综合平台编程器项目的远程存储
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 

168 regels
5.5 KiB

  1. #include "services/runtime_mode_service.h"
  2. #include "services/offline_simulation_service.h"
  3. #include "services/project_service.h"
  4. #include "domain/active_register_repository.h"
  5. #include "domain/project_storage.h"
  6. #include "domain/register_repository.h"
  7. #include <functional>
  8. #include <iostream>
  9. #include <stdexcept>
  10. #include <string>
  11. #include <utility>
  12. namespace {
  13. class TestProjectStorage final : public ProjectStorage
  14. {
  15. public:
  16. ProjectSaveResult save(const Project &, const std::string &) override
  17. {
  18. return {true, ProjectStorageError::None, {}};
  19. }
  20. ProjectLoadResult load(const std::string &) override
  21. {
  22. return {false, {}, ProjectStorageError::FileReadFailed, {}};
  23. }
  24. };
  25. class ReadyPlcGateway final : public PlcCommunicationGateway
  26. {
  27. public:
  28. PlcCommunicationResult connectDevice(const PlcSerialConfiguration &) override
  29. {
  30. connection_state = PlcConnectionState::Connected;
  31. if (state_changed)
  32. {
  33. state_changed();
  34. }
  35. return {true, {}};
  36. }
  37. void disconnectDevice() override
  38. {
  39. connection_state = PlcConnectionState::Disconnected;
  40. initial_read = false;
  41. }
  42. void setPollAddresses(const std::vector<RegisterAddress> &) override {}
  43. PlcConnectionState state() const override { return connection_state; }
  44. bool initialReadCompleted() const override { return initial_read; }
  45. PlcCommunicationError lastErrorType() const override
  46. {
  47. return PlcCommunicationError::None;
  48. }
  49. const std::string &lastError() const override { return last_error; }
  50. void setCallbacks(
  51. std::function<void()> state_callback,
  52. std::function<void(bool)> initial_callback,
  53. std::function<void()> cache_callback,
  54. std::function<void(const std::string &)> error_callback) override
  55. {
  56. state_changed = std::move(state_callback);
  57. initial_read_changed = std::move(initial_callback);
  58. cache_updated = std::move(cache_callback);
  59. error_reported = std::move(error_callback);
  60. }
  61. void completeInitialRead()
  62. {
  63. initial_read = true;
  64. if (initial_read_changed)
  65. {
  66. initial_read_changed(true);
  67. }
  68. }
  69. private:
  70. PlcConnectionState connection_state = PlcConnectionState::Disconnected;
  71. bool initial_read = false;
  72. std::string last_error;
  73. std::function<void()> state_changed;
  74. std::function<void(bool)> initial_read_changed;
  75. std::function<void()> cache_updated;
  76. std::function<void(const std::string &)> error_reported;
  77. };
  78. void require(bool condition, const std::string &message)
  79. {
  80. if (!condition)
  81. {
  82. throw std::runtime_error(message);
  83. }
  84. }
  85. void testModeTransitions()
  86. {
  87. // 验证服务将 PLC 首读状态与领域模式切换规则正确组合
  88. TestProjectStorage storage;
  89. ProjectService project_service(storage);
  90. VirtualRegisterRepository virtual_repository;
  91. VirtualRegisterRepository plc_repository;
  92. ActiveRegisterRepository active_repository(virtual_repository);
  93. OfflineSimulationService simulation_service(virtual_repository);
  94. ReadyPlcGateway gateway;
  95. RuntimeModeService service(project_service, simulation_service);
  96. service.configurePlc(
  97. gateway, active_repository, virtual_repository, plc_repository);
  98. require(service.mode() == ApplicationMode::Editing,
  99. "service must start in editing mode");
  100. require(service.policy().allowsProjectEditing,
  101. "editing mode must allow project editing");
  102. require(service.enterOfflineRunning().succeeded,
  103. "editing mode must enter offline running");
  104. require(service.simulationState() == SimulationState::Running,
  105. "offline mode must start the software executor");
  106. require(service.policy().usesVirtualRegisters,
  107. "offline running must use virtual registers");
  108. require(service.enterOnlineRunning().error
  109. == ModeTransitionError::MustReturnToEditing,
  110. "running modes must not switch directly");
  111. require(service.enterEditing().succeeded,
  112. "offline running must return to editing");
  113. require(service.simulationState() == SimulationState::Stopped,
  114. "returning to editing must stop the software executor first");
  115. require(service.enterOnlineRunning().error
  116. == ModeTransitionError::InitialPlcReadRequired,
  117. "online running must require an initial PLC read");
  118. require(service.connectPlc(
  119. {"COM9", 1, 9600, 8, 2, 1, 1000, 2, 200}).succeeded,
  120. "PLC connection must be established before its initial read can complete");
  121. gateway.completeInitialRead();
  122. require(service.initialPlcReadCompleted(),
  123. "service must retain the initial PLC read state");
  124. require(service.enterOnlineRunning().succeeded,
  125. "online running must start after an initial PLC read");
  126. require(service.simulationState() == SimulationState::Stopped,
  127. "online running must never start the software executor");
  128. require(service.policy().usesPlcRegisters,
  129. "online running must use PLC registers");
  130. require(!service.policy().runsLogicExecutor,
  131. "online running must keep the software executor stopped");
  132. }
  133. } // namespace
  134. int main()
  135. {
  136. try
  137. {
  138. // 运行模式只有这一组状态机边界测试
  139. testModeTransitions();
  140. }
  141. catch (const std::exception &error)
  142. {
  143. std::cerr << "runtime mode service tests failed: " << error.what() << '\n';
  144. return 1;
  145. }
  146. std::cout << "runtime mode service tests passed\n";
  147. return 0;
  148. }