#include #include "actors/actor.h" #include "actors/timeractor.h" #include "actors/sensoractor.h" #include "actors/scriptactor.h" #include "sensors/sensor.h" class TestActor : public QObject { Q_OBJECT private slots: void initTestCase() { // Setup for all tests } void testActorCreation() { Actor actor; // Actor should be active by default QVERIFY(actor.isActive()); // Actor should not be exhausted by default QVERIFY(!actor.isExausted()); } void testActorActivation() { Actor actor; // Test makeActive/makeInactive actor.makeActive(); QVERIFY(actor.isActive()); actor.makeInactive(); QVERIFY(!actor.isActive()); } void testActorSetActive() { Actor actor; // Test setActive actor.setActive(1); QVERIFY(actor.isActive()); actor.setActive(0); QVERIFY(!actor.isActive()); } void testActorTriggerValue() { Actor actor; // Default trigger value should be 0 QVERIFY(actor.getTriggerValue() == 0); // Set trigger value actor.setTriggerValue(1); QVERIFY(actor.getTriggerValue() == 1); actor.setTriggerValue(255); QVERIFY(actor.getTriggerValue() == 255); } void testActorActionName() { Actor actor; // Default trigger value is 0, so action name should be "off" QVERIFY(actor.actionName() == "off"); // Set trigger value to 1 actor.setTriggerValue(1); QVERIFY(actor.actionName() == "on"); // Set trigger value to something else actor.setTriggerValue(5); QVERIFY(actor.actionName() == "value to 5"); } void testActorJsonSerialization() { Actor actor; actor.setTriggerValue(1); actor.makeInactive(); QJsonObject json; actor.store(json); // Verify JSON contents QVERIFY(json.contains("Active")); QVERIFY(json.contains("Exausted")); QVERIFY(json.contains("TriggerValue")); QVERIFY(json["Active"].toBool() == false); QVERIFY(json["Exausted"].toBool() == false); QVERIFY(json["TriggerValue"].toInt() == 1); } void testActorJsonDeserialization() { QJsonObject json; json["Active"] = false; json["Exausted"] = true; json["TriggerValue"] = 5; Actor actor; actor.load(json); QVERIFY(actor.isActive() == false); QVERIFY(actor.isExausted() == true); QVERIFY(actor.getTriggerValue() == 5); } void testActorCreateActor() { // Test creating different actor types std::shared_ptr alarmActor = Actor::createActor("Alarm"); QVERIFY(alarmActor != nullptr); std::shared_ptr sensorActor = Actor::createActor("Sensor"); QVERIFY(sensorActor != nullptr); std::shared_ptr timerActor = Actor::createActor("Timer"); QVERIFY(timerActor != nullptr); std::shared_ptr regulatorActor = Actor::createActor("Regulator"); QVERIFY(regulatorActor != nullptr); std::shared_ptr polynomalActor = Actor::createActor("Polynomal"); QVERIFY(polynomalActor != nullptr); std::shared_ptr scriptActor = Actor::createActor("Script"); QVERIFY(scriptActor != nullptr); std::shared_ptr genericActor = Actor::createActor("Actor"); QVERIFY(genericActor != nullptr); // Test unknown type returns nullptr std::shared_ptr unknownActor = Actor::createActor("UnknownType"); QVERIFY(unknownActor == nullptr); } void testActorLoadActor() { QJsonObject json; json["Type"] = "Timer"; json["Active"] = true; json["Exausted"] = false; json["TriggerValue"] = 1; json["Timeout"] = 5000; std::shared_ptr actor = Actor::loadActor(json); QVERIFY(actor != nullptr); // Verify the actor was loaded with correct values QVERIFY(actor->isActive()); QVERIFY(!actor->isExausted()); QVERIFY(actor->getTriggerValue() == 1); } void testTimerActorCreation() { TimerActor actor(60); // Default timeout should be 60 seconds QVERIFY(actor.getTimeout() == 60); } void testTimerActorSetTimeout() { TimerActor actor(60); actor.setTimeout(120); QVERIFY(actor.getTimeout() == 120); actor.setTimeout(5); QVERIFY(actor.getTimeout() == 5); } void testTimerActorJsonSerialization() { TimerActor actor(120); QJsonObject json; actor.store(json); // Verify JSON contents QVERIFY(json.contains("Type")); QVERIFY(json.contains("Timeout")); QVERIFY(json["Type"].toString() == "Timer"); QVERIFY(json["Timeout"].toInt() == 120000); // Converted to milliseconds } void testTimerActorJsonDeserialization() { QJsonObject json; json["Type"] = "Timer"; json["Timeout"] = 30000; // 30 seconds in milliseconds json["Active"] = true; json["Exausted"] = false; json["TriggerValue"] = 1; TimerActor actor; actor.load(json, false); // Timeout should be 30 seconds QVERIFY(actor.getTimeout() == 30); } void testTimerActorGetName() { TimerActor actor(60); QString name = actor.getName(); QVERIFY(name.contains("60")); } void testSensorActorCreation() { Sensor sensor(Sensor::TYPE_TEMPERATURE, 1, 25.0, "temp_sensor"); SensorActor actor(sensor); // Verify sensor was set correctly QVERIFY(actor.getSensor().type == Sensor::TYPE_TEMPERATURE); QVERIFY(actor.getSensor().id == 1); } void testSensorActorDefaultCreation() { SensorActor actor; // Default sensor should be dummy QVERIFY(actor.getSensor().type == Sensor::TYPE_DUMMY); } void testSensorActorSetSensor() { SensorActor actor; Sensor newSensor(Sensor::TYPE_HUMIDITY, 2, 60.0, "humidity_sensor"); actor.setSensor(newSensor); QVERIFY(actor.getSensor().type == Sensor::TYPE_HUMIDITY); QVERIFY(actor.getSensor().id == 2); } void testSensorActorSetThreshold() { SensorActor actor; actor.setThreshold(25.0); QVERIFY(actor.getThreshold() == 25.0); } void testSensorActorSetSlope() { SensorActor actor; actor.setSloap(SensorActor::SLOPE_UP); QVERIFY(actor.getSloap() == SensorActor::SLOPE_UP); actor.setSloap(SensorActor::SLOPE_DOWN); QVERIFY(actor.getSloap() == SensorActor::SLOPE_DOWN); actor.setSloap(SensorActor::SLOPE_BOTH); QVERIFY(actor.getSloap() == SensorActor::SLOPE_BOTH); } void testSensorActorJsonSerialization() { Sensor sensor(Sensor::TYPE_TEMPERATURE, 1, 25.0, "temp_sensor"); SensorActor actor(sensor); actor.setThreshold(30.0); actor.setSloap(SensorActor::SLOPE_UP); QJsonObject json; actor.store(json); // Verify JSON contents QVERIFY(json.contains("Type")); QVERIFY(json.contains("Threshold")); QVERIFY(json.contains("Sloap")); QVERIFY(json.contains("SensorType")); QVERIFY(json["Type"].toString() == "Sensor"); QVERIFY(json["Threshold"].toDouble() == 30.0); QVERIFY(json["Sloap"].toInt() == SensorActor::SLOPE_UP); } void testSensorActorJsonDeserialization() { QJsonObject json; json["Type"] = "Sensor"; json["Threshold"] = 25.5; json["Sloap"] = SensorActor::SLOPE_DOWN; json["SensorType"] = Sensor::TYPE_HUMIDITY; json["SensorId"] = 3; json["SensorField"] = 65.0; json["SensorName"] = "humidity"; json["Active"] = true; json["Exausted"] = false; json["TriggerValue"] = 1; SensorActor actor; actor.load(json, false); QVERIFY(actor.getThreshold() == 25.5); QVERIFY(actor.getSloap() == SensorActor::SLOPE_DOWN); } void testSensorActorGetName() { Sensor sensor(Sensor::TYPE_TEMPERATURE, 1, 25.0, "temp_sensor"); SensorActor actor(sensor); actor.setThreshold(30.0); QString name = actor.getName(); QVERIFY(name.contains("temp_sensor")); QVERIFY(name.contains("30")); } // ScriptActor tests void testScriptActorCreation() { ScriptActor actor; // Should start with empty sensors QVERIFY(actor.getSensors().isEmpty()); // Should not watch parent item by default QVERIFY(!actor.getWatchParentItem()); // Script path and code should be empty QVERIFY(actor.getScriptPath().isEmpty()); QVERIFY(actor.getScriptCode().isEmpty()); } void testScriptActorSensors() { ScriptActor actor; // Add sensors Sensor sensor1(Sensor::TYPE_TEMPERATURE, 1, 25.0, "temp1"); Sensor sensor2(Sensor::TYPE_HUMIDITY, 2, 60.0, "humidity"); actor.addSensor(sensor1); actor.addSensor(sensor2); QVERIFY(actor.getSensors().size() == 2); // Adding duplicate (same type+id) should not add again Sensor sensor1Duplicate(Sensor::TYPE_TEMPERATURE, 1, 30.0, "temp1_dup"); actor.addSensor(sensor1Duplicate); QVERIFY(actor.getSensors().size() == 2); // Remove sensor actor.removeSensor(sensor1); QVERIFY(actor.getSensors().size() == 1); QVERIFY(actor.getSensors()[0].type == Sensor::TYPE_HUMIDITY); // Clear sensors actor.clearSensors(); QVERIFY(actor.getSensors().isEmpty()); } void testScriptActorSensorMatching() { ScriptActor actor; // Add a temperature sensor with id 5 Sensor watchedSensor(Sensor::TYPE_TEMPERATURE, 5, 20.0, "watched_temp"); actor.addSensor(watchedSensor); // A different temperature sensor (id 10) should NOT match Sensor otherTempSensor(Sensor::TYPE_TEMPERATURE, 10, 25.0, "other_temp"); QVERIFY(!(otherTempSensor.type == watchedSensor.type && otherTempSensor.id == watchedSensor.id)); // A humidity sensor with same id (5) should NOT match Sensor sameIdHumidity(Sensor::TYPE_HUMIDITY, 5, 50.0, "humidity_same_id"); QVERIFY(!(sameIdHumidity.type == watchedSensor.type && sameIdHumidity.id == watchedSensor.id)); } void testScriptActorWatchParentItem() { ScriptActor actor; QVERIFY(!actor.getWatchParentItem()); actor.setWatchParentItem(true); QVERIFY(actor.getWatchParentItem()); actor.setWatchParentItem(false); QVERIFY(!actor.getWatchParentItem()); } void testScriptActorScriptPath() { ScriptActor actor; QVERIFY(actor.getScriptPath().isEmpty()); actor.setScriptPath("/path/to/script.py"); QVERIFY(actor.getScriptPath() == "/path/to/script.py"); } void testScriptActorScriptCode() { ScriptActor actor; QVERIFY(actor.getScriptCode().isEmpty()); actor.setScriptCode("return 42"); QVERIFY(actor.getScriptCode() == "return 42"); } void testScriptActorJsonSerialization() { ScriptActor actor; actor.setWatchParentItem(true); actor.setScriptPath("/path/to/script.py"); actor.setScriptCode("return 1"); Sensor sensor1(Sensor::TYPE_TEMPERATURE, 1, 25.0, "temp1"); Sensor sensor2(Sensor::TYPE_HUMIDITY, 2, 60.0, "humidity"); actor.addSensor(sensor1); actor.addSensor(sensor2); QJsonObject json; actor.store(json); // Verify JSON contents QVERIFY(json["Type"].toString() == "Script"); QVERIFY(json["WatchParentItem"].toBool() == true); QVERIFY(json["ScriptPath"].toString() == "/path/to/script.py"); QVERIFY(json["ScriptCode"].toString() == "return 1"); QVERIFY(json.contains("Sensors")); QJsonArray sensorsArray = json["Sensors"].toArray(); QVERIFY(sensorsArray.size() == 2); // Check first sensor QVERIFY(sensorsArray[0].toObject()["Type"].toInt() == Sensor::TYPE_TEMPERATURE); QVERIFY(sensorsArray[0].toObject()["Id"].toInteger() == 1); } void testScriptActorJsonDeserialization() { QJsonObject json; json["Type"] = "Script"; json["WatchParentItem"] = true; json["ScriptPath"] = "/custom/script.py"; json["ScriptCode"] = "return 99"; json["Active"] = true; json["Exausted"] = false; json["TriggerValue"] = 5; QJsonArray sensorsArray; QJsonObject sensor1; sensor1["Type"] = Sensor::TYPE_TEMPERATURE; sensor1["Id"] = 10; sensor1["Name"] = "loaded_temp"; sensorsArray.append(sensor1); json["Sensors"] = sensorsArray; ScriptActor actor; actor.load(json, false); QVERIFY(actor.getWatchParentItem() == true); QVERIFY(actor.getScriptPath() == "/custom/script.py"); QVERIFY(actor.getScriptCode() == "return 99"); QVERIFY(actor.getTriggerValue() == 5); QVERIFY(actor.isActive() == true); QVERIFY(actor.getSensors().size() == 1); QVERIFY(actor.getSensors()[0].type == Sensor::TYPE_TEMPERATURE); QVERIFY(actor.getSensors()[0].id == 10); QVERIFY(actor.getSensors()[0].name == "loaded_temp"); } void testScriptActorLoadActor() { QJsonObject json; json["Type"] = "Script"; json["WatchParentItem"] = false; json["ScriptCode"] = "return 42"; json["Active"] = true; json["Exausted"] = false; json["TriggerValue"] = 1; std::shared_ptr actor = Actor::loadActor(json); QVERIFY(actor != nullptr); // Verify the actor was loaded with correct values QVERIFY(actor->isActive()); QVERIFY(!actor->isExausted()); QVERIFY(actor->getTriggerValue() == 1); } void testScriptActorGetName() { ScriptActor actor; // Without sensors, name should just be "Script" QString name = actor.getName(); QVERIFY(name == "Script"); // With sensors Sensor sensor1(Sensor::TYPE_TEMPERATURE, 1, 25.0, "temp_sensor"); actor.addSensor(sensor1); name = actor.getName(); QVERIFY(name.contains("Script")); QVERIFY(name.contains("temp_sensor")); // With parent item watching actor.setWatchParentItem(true); name = actor.getName(); QVERIFY(name.contains("parent item")); } void testScriptActorTriggerSync() { ScriptActor actor; actor.setTriggerValue(5); // triggerSync should not crash // It emits sigItemUpdate which will be handled by parent item actor.triggerSync(); // Verify trigger value is unchanged QVERIFY(actor.getTriggerValue() == 5); } void testScriptActorRunScript() { ScriptActor actor; actor.setTriggerValue(0); // Set a simple script that returns 42 actor.setScriptCode("return 42"); // Run the script QVariant result = actor.runScriptNow(); // Verify the result is 42 QVERIFY(result.isValid()); QVERIFY(result.toInt() == 42); // Note: performValueAction emits sigItemUpdate but doesn't update triggerValue // triggerValue is set manually and used for manual activation } void testScriptActorRunScriptWithDicts() { ScriptActor actor; actor.setTriggerValue(0); // Set a script that uses the available dicts actor.setScriptCode("return len(items) + len(sensors)"); // Run the script - should not crash QVariant result = actor.runScriptNow(); // Result should be valid (number of items + sensors) QVERIFY(result.isValid()); } void testScriptActorRunScriptMultipleTimes() { ScriptActor actor; actor.setTriggerValue(0); // Set a script that increments actor.setScriptCode("return 1"); // Run multiple times - should not crash for(int i = 0; i < 3; i++) { QVariant result = actor.runScriptNow(); QVERIFY(result.isValid()); QVERIFY(result.toInt() == 1); } } void cleanupTestCase() { // Cleanup after all tests } }; QTEST_APPLESS_MAIN(TestActor) #include "test_actor.moc"