#include "infrastructure/runtime_settings_loader.h" #include "support/test_support.h" #include #include #include #include #include namespace { using TestSupport::require; void writeUtf8(const QString &path, const QByteArray &contents) { QFile file(path); require(file.open(QIODevice::WriteOnly), "runtime settings file must open"); require(file.write(contents) == contents.size(), "runtime settings file must be written completely"); } bool containsMessage( const RuntimeSettingsLoadResult &result, const std::string &fragment) { return std::any_of( result.messages.cbegin(), result.messages.cend(), [&fragment](const std::string &message) { return message.find(fragment) != std::string::npos; }); } void testMissingFileCreatesOnlyPlcDefaults() { QTemporaryDir directory; require(directory.isValid(), "runtime settings directory must be valid"); const QString path = directory.filePath("config/runtime.ini"); const RuntimeSettingsLoadResult result = RuntimeSettingsLoader::load(path); require(QFile::exists(path) && !result.warningRequired, "missing runtime settings must be created without warning"); QFile file(path); require(file.open(QIODevice::ReadOnly), "created runtime settings must be readable"); const QByteArray contents = file.readAll(); require(contents.contains("[PlcDefaults]\n") && contents.contains("PortName=COM3\n") && !contents.contains("[ProjectLimits]") && !contents.contains("[HmiDefaults]") && !contents.contains("[Config]"), "runtime settings must contain only PLC defaults"); } void testRuntimeSettingsLoadsSerialFields() { QTemporaryDir directory; require(directory.isValid(), "runtime settings directory must be valid"); const QString path = directory.filePath("runtime.ini"); writeUtf8( path, QByteArrayLiteral( "[PlcDefaults]\n" "PortName=COM7\n" "ServerAddress=2\n" "BaudRate=19200\n" "DataBits=7\n" "Parity=3\n" "StopBits=2\n")); const RuntimeSettingsLoadResult result = RuntimeSettingsLoader::load(path); require(!result.warningRequired && result.plcDefaults.portName == "COM7" && result.plcDefaults.serverAddress == 2 && result.plcDefaults.baudRate == 19200 && result.plcDefaults.dataBits == 7 && result.plcDefaults.parity == 3 && result.plcDefaults.stopBits == 2, "runtime settings must load all six serial fields"); } void testRuntimeSettingsRejectsInvalidFileAsOneUnit() { QTemporaryDir directory; require(directory.isValid(), "runtime settings directory must be valid"); const QString path = directory.filePath("invalid.ini"); writeUtf8( path, QByteArrayLiteral( "[PlcDefaults]\n" "PortName=COM7\n" "ServerAddress=2\n" "BaudRate=19200\n" "DataBits=8\n" "Parity=2\n" "StopBits=1\n" "[PlcDefaults]\n" "PortName=COM8\n")); const RuntimeSettingsLoadResult result = RuntimeSettingsLoader::load(path); require(result.warningRequired && result.plcDefaults.portName == "COM3" && containsMessage(result, "重复"), "duplicate runtime settings must fall back to code defaults"); } void testRuntimeSettingsWritesMinimalFile() { QTemporaryDir directory; require(directory.isValid(), "runtime settings directory must be valid"); const QString path = directory.filePath("config/runtime.ini"); PlcSerialConfiguration configuration; configuration.portName = "COM9"; configuration.serverAddress = 9; configuration.baudRate = 38400; configuration.dataBits = 8; configuration.parity = 0; configuration.stopBits = 1; std::string error; require(RuntimeSettingsLoader::write(path, configuration, &error), "runtime settings must write successfully"); const RuntimeSettingsLoadResult loaded = RuntimeSettingsLoader::load(path); require(!loaded.warningRequired && loaded.plcDefaults.portName == "COM9" && loaded.plcDefaults.serverAddress == 9 && loaded.plcDefaults.baudRate == 38400 && loaded.plcDefaults.parity == 0, "written runtime settings must round trip"); } } // namespace int main(int argc, char *argv[]) { QCoreApplication application(argc, argv); return TestSupport::runTestSuite("runtime settings tests", { {"testMissingFileCreatesOnlyPlcDefaults", testMissingFileCreatesOnlyPlcDefaults}, {"testRuntimeSettingsLoadsSerialFields", testRuntimeSettingsLoadsSerialFields}, {"testRuntimeSettingsRejectsInvalidFileAsOneUnit", testRuntimeSettingsRejectsInvalidFileAsOneUnit}, {"testRuntimeSettingsWritesMinimalFile", testRuntimeSettingsWritesMinimalFile}, }); }