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

143 рядки
5.5 KiB

  1. #include "domain/project_storage.h"
  2. #include "services/logic_editor_service.h"
  3. #include "services/project_service.h"
  4. #include <iostream>
  5. #include <stdexcept>
  6. namespace {
  7. class TestProjectStorage final : public ProjectStorage
  8. {
  9. public:
  10. ProjectSaveResult save(const Project &, const std::string &) override
  11. {
  12. return {true, ProjectStorageError::None, {}};
  13. }
  14. ProjectLoadResult load(const std::string &) override
  15. {
  16. return {false, {}, ProjectStorageError::FileReadFailed, {}};
  17. }
  18. };
  19. void require(bool condition, const std::string &message)
  20. {
  21. if (!condition)
  22. {
  23. throw std::runtime_error(message);
  24. }
  25. }
  26. ContactNodeConfig contact(int address)
  27. {
  28. return {RegisterAddress{RegisterArea::M, address}, ContactMode::NormallyOpen};
  29. }
  30. void testStructuredEditingAndNormalization()
  31. {
  32. TestProjectStorage storage;
  33. ProjectService project_service(storage);
  34. LogicEditorService service(project_service);
  35. const std::string logic_id = service.ensureDefaultLogic().id;
  36. const std::string rung_id = service.firstRungId(logic_id);
  37. const LogicEditorResult first = service.appendCondition(logic_id, rung_id, contact(0));
  38. const LogicEditorResult second = service.appendCondition(logic_id, rung_id, contact(1));
  39. require(first.succeeded && second.succeeded, "series append must succeed");
  40. const LadderRung *rung = service.findRung(logic_id, rung_id);
  41. require(rung->condition->kind == ConditionExpressionKind::Series
  42. && rung->condition->children.size() == 2U,
  43. "two appended nodes must form a series expression");
  44. const std::string second_expression_id = second.id;
  45. const LogicEditorResult parallel = service.addParallelCondition(
  46. logic_id, rung_id, second_expression_id, contact(2));
  47. require(parallel.succeeded, "parallel insertion must succeed");
  48. rung = service.findRung(logic_id, rung_id);
  49. const ConditionExpression *parallel_expression = service.findExpression(
  50. logic_id, rung_id, rung->condition->children.at(1).id);
  51. require(parallel_expression != nullptr
  52. && parallel_expression->kind == ConditionExpressionKind::Parallel,
  53. "selected node must become a parallel expression");
  54. const LogicEditorResult nested_series = service.insertCondition(
  55. logic_id,
  56. rung_id,
  57. parallel.id,
  58. SeriesInsertPosition::After,
  59. contact(3));
  60. require(nested_series.succeeded, "a parallel branch must accept a series node");
  61. rung = service.findRung(logic_id, rung_id);
  62. require(rung->condition->kind == ConditionExpressionKind::Series,
  63. "root must remain a series expression");
  64. const ConditionExpression &nested_parallel_expression = rung->condition->children.at(1);
  65. require(nested_parallel_expression.kind == ConditionExpressionKind::Parallel
  66. && nested_parallel_expression.children.at(1).kind
  67. == ConditionExpressionKind::Series,
  68. "editor must express A AND (B OR (C AND D))");
  69. require(service.removeNode(logic_id, nested_series.id).succeeded,
  70. "nested series node deletion must succeed");
  71. rung = service.findRung(logic_id, rung_id);
  72. require(rung->condition->children.at(1).kind == ConditionExpressionKind::Parallel
  73. && rung->condition->children.at(1).children.at(1).kind
  74. == ConditionExpressionKind::Node,
  75. "single-child series container must collapse after deletion");
  76. require(service.removeNode(logic_id, parallel.id).succeeded,
  77. "parallel leaf deletion must succeed");
  78. rung = service.findRung(logic_id, rung_id);
  79. require(rung->condition->kind == ConditionExpressionKind::Series
  80. && rung->condition->children.size() == 2U,
  81. "single-child parallel container must collapse after deletion");
  82. require(service.setOutput(
  83. logic_id,
  84. rung_id,
  85. CoilNodeConfig{RegisterAddress{RegisterArea::M, 10}, CoilMode::Normal})
  86. .succeeded,
  87. "output coil must be set");
  88. require(service.findLogic(logic_id)->validate(),
  89. "structured editing result must remain a valid draft");
  90. }
  91. void testBranchLevelParallelInsertion()
  92. {
  93. TestProjectStorage storage;
  94. ProjectService project_service(storage);
  95. LogicEditorService service(project_service);
  96. const std::string logic_id = service.ensureDefaultLogic().id;
  97. const std::string rung_id = service.firstRungId(logic_id);
  98. service.appendCondition(logic_id, rung_id, contact(0));
  99. service.appendCondition(logic_id, rung_id, contact(1));
  100. const std::string series_id = service.findRung(logic_id, rung_id)->condition->id;
  101. const LogicEditorResult branch = service.addParallelCondition(
  102. logic_id, rung_id, series_id, contact(2));
  103. require(branch.succeeded, "a whole series branch must accept a parallel condition");
  104. const ConditionExpression &root = *service.findRung(logic_id, rung_id)->condition;
  105. require(root.kind == ConditionExpressionKind::Parallel
  106. && root.children.front().kind == ConditionExpressionKind::Series,
  107. "branch-level insertion must express (A AND B) OR C");
  108. }
  109. } // namespace
  110. int main()
  111. {
  112. try
  113. {
  114. testStructuredEditingAndNormalization();
  115. testBranchLevelParallelInsertion();
  116. }
  117. catch (const std::exception &error)
  118. {
  119. std::cerr << "logic editor service tests failed: " << error.what() << '\n';
  120. return 1;
  121. }
  122. std::cout << "logic editor service tests passed\n";
  123. return 0;
  124. }