|
- #include "domain/virtual_register_repository.h"
- #include "services/alarm_service.h"
- #include "services/hmi_editor_service.h"
- #include "services/hmi_navigation_service.h"
- #include "services/hmi_runtime_service.h"
- #include "services/logic_editor_service.h"
- #include "services/offline_simulation_service.h"
- #include "services/project_service.h"
- #include "services/register_monitor_service.h"
- #include "services/runtime_mode_service.h"
- #include "support/test_support.h"
- #include "ui/hmi_editor_widget.h"
- #include "ui/logic_editor_widget.h"
- #include "ui/runtime_monitor_widget.h"
- #include "ui/runtime_panel_controller.h"
-
- #include <QApplication>
- #include <QCoreApplication>
- #include <QEventLoop>
- #include <QLabel>
- #include <QWidget>
-
- #include <iostream>
- #include <stdexcept>
- #include <string>
-
- namespace {
-
- using TestProjectStorage = TestSupport::InMemoryProjectStorage;
- using TestSupport::require;
-
- ControlLogic makeAlwaysOnLogic()
- {
- ControlLogic logic;
- logic.id = "queued-trace-logic";
- logic.name = "Queued trace logic";
-
- LadderRung rung;
- rung.id = "always-on-rung";
- rung.name = "Always on";
- rung.condition = ConditionExpression::fromWire("always-on-wire", 10);
-
- LogicNode output;
- output.id = "always-on-output";
- output.config = CoilNodeConfig{
- RegisterAddress{RegisterArea::M, 1}, CoilMode::Normal};
- rung.output = output;
- logic.rungs.push_back(rung);
- return logic;
- }
-
- void testQueuedOfflineTraceIsIgnoredAfterReturningToEditing()
- {
- TestProjectStorage storage;
- ProjectService project_service(storage);
- VirtualRegisterRepository virtual_repository;
- OfflineSimulationService simulation_service(virtual_repository);
- OnlineLogicMonitorService online_monitor_service(virtual_repository);
- RuntimeModeService runtime_mode_service(
- project_service, simulation_service, online_monitor_service);
- HmiEditorService hmi_editor_service(project_service);
- HmiRuntimeService hmi_runtime_service(virtual_repository);
- LogicEditorService logic_editor_service(project_service);
- HmiNavigationService hmi_navigation_service(project_service);
- AlarmService alarm_service(project_service, virtual_repository);
- RegisterMonitorService register_monitor_service(virtual_repository);
-
- const ControlLogic logic = makeAlwaysOnLogic();
- project_service.editProject().controlLogics.push_back(logic);
-
- QWidget parent;
- HmiEditorWidget hmi_editor_widget(
- hmi_editor_service, hmi_runtime_service, alarm_service, &parent);
- LogicEditorWidget logic_editor_widget(logic_editor_service, &parent);
- QLabel executor_status_label(&parent);
- std::string current_logic_id = logic.id;
- logic_editor_widget.setLogicId(current_logic_id);
-
- RuntimePanelController controller(
- parent,
- runtime_mode_service,
- project_service,
- hmi_editor_service,
- hmi_runtime_service,
- logic_editor_service,
- hmi_navigation_service,
- alarm_service,
- register_monitor_service,
- hmi_editor_widget,
- logic_editor_widget,
- executor_status_label,
- [¤t_logic_id] { return current_logic_id; },
- [¤t_logic_id](const std::string &logic_id)
- {
- current_logic_id = logic_id;
- },
- [](const std::string &) {},
- [](const QString &, int) {},
- [](const QString &) {},
- [] {});
- controller.configure();
-
- require(runtime_mode_service.enterOfflineRunning().succeeded,
- "offline simulation must start for queued trace regression");
- controller.enterRuntime(
- {}, logic.id, runtime_mode_service.mode(),
- runtime_mode_service.plcConnectionState());
- QLabel *logic_label = controller.runtimeMonitorWidget()
- ->findChild<QLabel *>(QStringLiteral("logicLabel"));
- QLabel *notice_label = controller.runtimeMonitorWidget()
- ->findChild<QLabel *>(QStringLiteral("logicNoticeLabel"));
- require(logic_label != nullptr && notice_label != nullptr,
- "runtime monitor must expose its local trace labels");
- require(logic_label->text() == QStringLiteral("梯形图运行状态")
- && !notice_label->isVisible(),
- "offline runtime must keep the normal ladder trace heading");
- controller.runtimeMonitorWidget()->setMode(
- ApplicationMode::OnlineRunning, PlcConnectionState::Connected);
- require(logic_label->text() == QStringLiteral("本地推算轨迹")
- && notice_label->isVisible()
- && notice_label->text().contains(QStringLiteral("不写入 PLC 程序或 M/D"))
- && notice_label->text().contains(QStringLiteral("HMI 和自由监控仍可写 PLC")),
- "online runtime must explain the read-only local trace boundary");
- controller.runtimeMonitorWidget()->setMode(
- ApplicationMode::OfflineRunning, PlcConnectionState::Disconnected);
- require(simulation_service.executeOnce().succeeded,
- "offline simulation must produce a trace before editing");
- require(simulation_service.traceSnapshot()
- .forLogic(logic.id).rungValues.at("always-on-rung"),
- "the queued trace must contain an energized rung");
-
- require(runtime_mode_service.enterEditing().succeeded,
- "offline simulation must return to editing before queued delivery");
- controller.leaveRuntime(
- runtime_mode_service.mode(), runtime_mode_service.plcConnectionState());
- logic_editor_widget.clearRuntimeTrace();
- require(!logic_editor_widget.runtimeTraceEnabled(),
- "editing transition must initially clear the runtime trace");
-
- QCoreApplication::processEvents(QEventLoop::AllEvents);
- require(!logic_editor_widget.runtimeTraceEnabled(),
- "a queued offline scan must not restore the trace after returning to editing");
- }
-
- } // namespace
-
- int main(int argc, char *argv[])
- {
- qputenv("QT_QPA_PLATFORM", QByteArrayLiteral("offscreen"));
- QApplication application(argc, argv);
- try
- {
- testQueuedOfflineTraceIsIgnoredAfterReturningToEditing();
- }
- catch (const std::exception &error)
- {
- std::cerr << "runtime panel controller tests failed: "
- << error.what() << '\n';
- return 1;
- }
-
- std::cout << "runtime panel controller tests passed\n";
- return 0;
- }
|