综合平台编程器项目的远程存储
Вы не можете выбрать более 25 тем Темы должны начинаться с буквы или цифры, могут содержать дефисы(-) и должны содержать не более 35 символов.
 
 
 
 

142 строки
5.4 KiB

  1. #include "domain/project_storage.h"
  2. #include "domain/register_repository.h"
  3. #include "services/hmi_editor_service.h"
  4. #include "services/hmi_runtime_service.h"
  5. #include "services/project_service.h"
  6. #include <exception>
  7. #include <iostream>
  8. #include <stdexcept>
  9. #include <string>
  10. namespace {
  11. class TestProjectStorage final : public ProjectStorage
  12. {
  13. public:
  14. // 编辑服务测试只关注内存模型变更,不依赖真实文件系统
  15. ProjectSaveResult save(const Project &, const std::string &) override
  16. {
  17. return {true, ProjectStorageError::None, {}};
  18. }
  19. ProjectLoadResult load(const std::string &) override
  20. {
  21. return {false, {}, ProjectStorageError::FileReadFailed, {}};
  22. }
  23. };
  24. void require(bool condition, const std::string &message)
  25. {
  26. if (!condition)
  27. {
  28. throw std::runtime_error(message);
  29. }
  30. }
  31. void testControlEditing()
  32. {
  33. // 覆盖控件创建、移动、绑定校验、重命名冲突和删除流程
  34. TestProjectStorage storage;
  35. ProjectService project_service(storage);
  36. HmiEditorService service(project_service);
  37. const HmiEditorResult page_result = service.ensureDefaultPage();
  38. require(page_result.succeeded, "default HMI page creation must succeed");
  39. const std::string page_id = page_result.id;
  40. const HmiEditorResult button = service.addControl(page_id, HmiControlType::Button);
  41. const HmiEditorResult indicator = service.addControl(page_id, HmiControlType::Indicator);
  42. const HmiEditorResult display = service.addControl(
  43. page_id, HmiControlType::NumericDisplay);
  44. const HmiEditorResult input = service.addControl(page_id, HmiControlType::NumericInput);
  45. require(button.succeeded && indicator.succeeded && display.succeeded && input.succeeded,
  46. "four basic HMI controls must be added");
  47. const HmiPage *page = service.findPage(page_id);
  48. require(page != nullptr && page->controls.size() == 4,
  49. "all added controls must be kept in the page model");
  50. require(service.moveControl(page_id, button.id, {120, 80, 120, 40}).succeeded,
  51. "a valid control move must succeed");
  52. require(!service.moveControl(page_id, button.id, {790, 460, 120, 40}).succeeded,
  53. "a move outside the page must be rejected");
  54. HmiControl updated = *service.findControl(page_id, button.id);
  55. updated.binding = RegisterAddress{RegisterArea::D, 0};
  56. require(!service.updateControl(page_id, button.id, updated).succeeded,
  57. "buttons must reject D address bindings during editing");
  58. updated.binding = RegisterAddress{RegisterArea::M, 7};
  59. updated.text = "启动";
  60. require(service.updateControl(page_id, button.id, updated).succeeded,
  61. "a button M binding and edited text must be accepted");
  62. HmiControl duplicate = *service.findControl(page_id, indicator.id);
  63. duplicate.id = button.id;
  64. require(service.updateControl(page_id, indicator.id, duplicate).error
  65. == HmiEditorError::DuplicateId,
  66. "duplicate control ids must be rejected");
  67. require(service.removeControl(page_id, indicator.id).succeeded,
  68. "deleting a selected control must succeed");
  69. require(service.findControl(page_id, indicator.id) == nullptr,
  70. "deleted controls must not remain in the model");
  71. }
  72. void testRuntimeUsesRegisterRepository()
  73. {
  74. // 运行服务只能经由仓库接口读写 M/D,不依赖具体离线实现
  75. VirtualRegisterRepository repository;
  76. HmiRuntimeService runtime_service(repository);
  77. HmiControl button;
  78. button.id = "start";
  79. button.type = HmiControlType::Button;
  80. button.binding = RegisterAddress{RegisterArea::M, 12};
  81. require(runtime_service.toggleButton(button).succeeded,
  82. "button runtime writes must be accepted by the repository");
  83. require(repository.readBit(*button.binding).value,
  84. "button runtime writes must reach the M repository value");
  85. HmiControl indicator;
  86. indicator.id = "running";
  87. indicator.type = HmiControlType::Indicator;
  88. indicator.binding = RegisterAddress{RegisterArea::M, 12};
  89. const HmiRuntimeReadResult indicator_value = runtime_service.readControl(indicator);
  90. require(indicator_value.succeeded && indicator_value.bit_value,
  91. "indicators must read M values through the repository");
  92. HmiControl numeric_input;
  93. numeric_input.id = "target";
  94. numeric_input.type = HmiControlType::NumericInput;
  95. numeric_input.binding = RegisterAddress{RegisterArea::D, 9};
  96. require(runtime_service.writeNumericInput(numeric_input, -18).succeeded,
  97. "numeric input runtime writes must be accepted by the repository");
  98. HmiControl numeric_display;
  99. numeric_display.id = "actual";
  100. numeric_display.type = HmiControlType::NumericDisplay;
  101. numeric_display.binding = RegisterAddress{RegisterArea::D, 9};
  102. const HmiRuntimeReadResult numeric_value = runtime_service.readControl(numeric_display);
  103. require(numeric_value.succeeded && numeric_value.word_value == -18,
  104. "numeric display must read D values through the repository");
  105. }
  106. } // namespace
  107. int main()
  108. {
  109. try
  110. {
  111. // 编辑和运行场景分别验证服务层两条独立职责
  112. testControlEditing();
  113. testRuntimeUsesRegisterRepository();
  114. }
  115. catch (const std::exception &error)
  116. {
  117. std::cerr << "HMI editor service tests failed: " << error.what() << '\n';
  118. return 1;
  119. }
  120. std::cout << "HMI editor service tests passed\n";
  121. return 0;
  122. }