#include #include #include #include #include #include #include "service/tcpserver.h" #include "service/tcpclient.h" #include "service/server.h" #include "service/service.h" #include "items/item.h" #include "sensors/sensor.h" class TestTcp : public QObject { Q_OBJECT private slots: void initTestCase() { // Setup for all tests } void testTcpServerCreation() { TcpServer server; // Server should be created successfully QVERIFY(true); } void testTcpServerLaunch() { TcpServer server; // Launch server on any address, port 0 means dynamic port bool result = server.launch(QHostAddress::Any, 0); QVERIFY(result); // Server should be listening after launch QVERIFY(server.isListening()); } void testTcpServerLaunchSpecificPort() { TcpServer server; // Try to launch on a specific port bool result = server.launch(QHostAddress::LocalHost, 0); QVERIFY(result); // Server should be listening QVERIFY(server.isListening()); } void testTcpClientCreation() { TcpClient client; // Client should be created successfully QVERIFY(true); } void testTcpProtocolMessageFormat() { // Test the protocol message format: "MSG JSON LEN \n" QJsonObject json; json["MessageType"] = "TestMessage"; json["Data"] = QJsonArray(); QByteArray jsonData = QJsonDocument(json).toJson(); QString message = QString("MSG JSON LEN %1\n").arg(jsonData.size()) + QString::fromUtf8(jsonData); // Verify message format QVERIFY(message.startsWith("MSG JSON LEN ")); QVERIFY(message.contains("\n")); // Parse the message size QStringList parts = message.split("\n"); QVERIFY(parts.size() >= 1); QString sizeStr = parts[0].mid(13); // Skip "MSG JSON LEN " bool ok; quint64 size = sizeStr.toUInt(&ok); QVERIFY(ok); QVERIFY(size == jsonData.size()); } void testTcpProtocolParseCommand() { // Test parsing a command from the protocol QByteArray command = "MSG JSON LEN 123\n"; QVERIFY(command.startsWith("MSG JSON LEN ")); QByteArray sizeStr = command.mid(13); sizeStr.chop(1); // Remove newline bool ok; quint64 size = sizeStr.toLongLong(&ok); QVERIFY(ok); QVERIFY(size == 123); } void testTcpServerSendJson() { // Start server TcpServer server; bool serverResult = server.launch(QHostAddress::LocalHost, 0); QVERIFY(serverResult); // Connect a client to trigger client list QTcpSocket clientSocket; clientSocket.connectToHost(QHostAddress::LocalHost, server.getServerPort()); QVERIFY(clientSocket.waitForConnected(1000)); // Give server time to accept connection QTest::qWait(200); // Send JSON from server QJsonObject json; json["MessageType"] = "TestMessage"; json["Data"] = QJsonArray(); server.sendJson(json); // Give more time for data to be sent QTest::qWait(200); // Client should receive data (or at least the connection should work) // Note: This may fail due to timing in test environment QVERIFY(clientSocket.state() == QTcpSocket::ConnectedState); // Cleanup clientSocket.close(); } void testTcpServerProcessIncomingJson() { // Start server TcpServer server; bool serverResult = server.launch(QHostAddress::LocalHost, 0); QVERIFY(serverResult); // Connect client QTcpSocket clientSocket; clientSocket.connectToHost(QHostAddress::LocalHost, server.getServerPort()); QVERIFY(clientSocket.waitForConnected(1000)); // Give server time to accept connection QTest::qWait(100); // Send a message that the server can process QJsonObject json; json["MessageType"] = "GetItems"; json["Data"] = QJsonArray(); QByteArray jsonData = QJsonDocument(json).toJson(); QString message = QString("MSG JSON LEN %1\n").arg(jsonData.size()) + QString::fromUtf8(jsonData); clientSocket.write(message.toUtf8()); clientSocket.flush(); // Give server time to process QTest::qWait(100); // Cleanup clientSocket.close(); } void testTcpServerMultipleClients() { // Start server TcpServer server; bool serverResult = server.launch(QHostAddress::LocalHost, 0); QVERIFY(serverResult); // Connect multiple clients QTcpSocket client1; client1.connectToHost(QHostAddress::LocalHost, server.getServerPort()); QVERIFY(client1.waitForConnected(1000)); QTcpSocket client2; client2.connectToHost(QHostAddress::LocalHost, server.getServerPort()); QVERIFY(client2.waitForConnected(1000)); // Give server time to accept connections QTest::qWait(200); // Send message to all clients QJsonObject json; json["MessageType"] = "TestMessage"; json["Data"] = QJsonArray(); server.sendJson(json); // Give time for data to be sent QTest::qWait(200); // Both clients should be connected (timing may affect actual data receipt) QVERIFY(client1.state() == QTcpSocket::ConnectedState); QVERIFY(client2.state() == QTcpSocket::ConnectedState); // Cleanup client1.close(); client2.close(); } void testItemUpdateMessageFormat() { // Test creating an item update message format Item item(1, "test_item", 1); QJsonObject itemJson; item.store(itemJson); QJsonArray items; items.append(itemJson); // Manually create the message (since createMessage is protected) QJsonObject message; message["MessageType"] = "ItemUpdate"; message["Data"] = items; message["FullList"] = false; QVERIFY(message["MessageType"].toString() == "ItemUpdate"); QVERIFY(message["Data"].toArray().size() == 1); QVERIFY(message["FullList"].toBool() == false); } void testSensorUpdateMessageFormat() { // Test creating a sensor update message format Sensor sensor(Sensor::TYPE_TEMPERATURE, 1, 25.0, "temp_sensor"); QJsonObject sensorJson; sensor.store(sensorJson); QJsonArray sensors; sensors.append(sensorJson); // Manually create the message (since createMessage is protected) QJsonObject message; message["MessageType"] = "SensorUpdate"; message["Data"] = sensors; QVERIFY(message["MessageType"].toString() == "SensorUpdate"); QVERIFY(message["Data"].toArray().size() == 1); } void testTcpClientSocketState() { // Test that TcpClient creates a socket TcpClient client; // The client should have a valid socket (internal implementation detail) // We can verify the client was created successfully QVERIFY(true); } void testTcpServerClientConnection() { // Start server TcpServer server; bool serverResult = server.launch(QHostAddress::LocalHost, 0); QVERIFY(serverResult); // Connect a client QTcpSocket clientSocket; clientSocket.connectToHost(QHostAddress::LocalHost, server.getServerPort()); bool waitResult = clientSocket.waitForConnected(1000); QVERIFY(waitResult); // Verify connection state QVERIFY(clientSocket.state() == QTcpSocket::ConnectedState); // Cleanup clientSocket.close(); } void testTcpServerDisconnection() { // Start server TcpServer server; bool serverResult = server.launch(QHostAddress::LocalHost, 0); QVERIFY(serverResult); // Connect a client QTcpSocket* client = new QTcpSocket(); client->connectToHost(QHostAddress::LocalHost, server.getServerPort()); QVERIFY(client->waitForConnected(1000)); // Give server time to accept connection QTest::qWait(100); // Disconnect client client->disconnectFromHost(); QTest::qWait(100); // Cleanup delete client; } void testTcpProtocolLargeMessage() { // Test the protocol with a larger message QJsonObject json; json["MessageType"] = "TestMessage"; // Create a large data array QJsonArray data; for (int i = 0; i < 100; i++) { data.append(QJsonObject{{"id", i}, {"value", QString("item%1").arg(i)}}); } json["Data"] = data; QByteArray jsonData = QJsonDocument(json).toJson(); QString message = QString("MSG JSON LEN %1\n").arg(jsonData.size()) + QString::fromUtf8(jsonData); // Verify message format QVERIFY(message.startsWith("MSG JSON LEN ")); // Parse the message size QStringList parts = message.split("\n"); QString sizeStr = parts[0].mid(13); bool ok; quint64 size = sizeStr.toUInt(&ok); QVERIFY(ok); QVERIFY(size == jsonData.size()); } void testAddSensorMessageFormat() { // Test creating an AddSensor message format Sensor sensor(Sensor::TYPE_TEMPERATURE, 1, 25.0, "temp_sensor"); QJsonObject sensorJson; sensor.store(sensorJson); QJsonObject payload; payload["Topic"] = "home/temperature"; payload["Name"] = "Living Room"; // Manually create the message (since createMessage is protected) QJsonObject message; message["MessageType"] = "AddSensor"; message["Data"] = QJsonArray(); message["Sensor"] = sensorJson; message["Backend"] = static_cast(Sensor::BACKEND_MQTT); message["Payload"] = payload; QVERIFY(message["MessageType"].toString() == "AddSensor"); QVERIFY(message["Sensor"].toObject()["Name"].toString() == "temp_sensor"); QVERIFY(message["Backend"].toInt() == Sensor::BACKEND_MQTT); QVERIFY(message["Payload"].toObject()["Topic"].toString() == "home/temperature"); } void testSensorBackendTypeEnum() { // Test that the backend type enum values are correct QVERIFY(Sensor::BACKEND_MICROCONTROLLER == 0); QVERIFY(Sensor::BACKEND_MQTT == 1); QVERIFY(Sensor::BACKEND_SUN == 2); } void testServiceAddSensor() { // Test that Service::addSensor can be called without crashing // and creates proper JSON message format TcpServer server; bool result = server.launch(QHostAddress::LocalHost, 0); QVERIFY(result); // Create a sensor and payload Sensor sensor(Sensor::TYPE_TEMPERATURE, 1, 25.0, "temp_sensor"); QJsonObject payload; payload["Topic"] = "home/temperature"; payload["Name"] = "Living Room"; // Call addSensor - this should not crash // The actual sending to clients depends on network timing server.addSensor(sensor, Sensor::BACKEND_MQTT, payload); // Test passed if no crash occurred QVERIFY(true); } void testServiceProcessAddSensorMessage() { // Test processing an incoming AddSensor message // We test the JSON parsing directly without network QJsonObject sensorJson; sensorJson["SensorType"] = static_cast(Sensor::TYPE_TEMPERATURE); sensorJson["Id"] = 1; sensorJson["Field"] = 25.0; sensorJson["Name"] = "temp_sensor"; QJsonObject payload; payload["Topic"] = "home/temperature"; payload["Name"] = "Living Room"; QJsonObject message; message["MessageType"] = "AddSensor"; message["Data"] = QJsonArray(); message["Sensor"] = sensorJson; message["Backend"] = static_cast(Sensor::BACKEND_MQTT); message["Payload"] = payload; // Test that the message can be parsed correctly QJsonDocument doc(message); QVERIFY(doc.isObject()); QJsonObject parsed = doc.object(); QVERIFY(parsed["MessageType"].toString() == "AddSensor"); QVERIFY(parsed["Backend"].toInt() == Sensor::BACKEND_MQTT); QVERIFY(parsed["Payload"].toObject()["Topic"].toString() == "home/temperature"); QVERIFY(parsed["Sensor"].toObject()["Name"].toString() == "temp_sensor"); } void cleanupTestCase() { // Cleanup after all tests } }; QTEST_APPLESS_MAIN(TestTcp) #include "test_tcp.moc"