综合平台编程器项目的远程存储
Você não pode selecionar mais de 25 tópicos Os tópicos devem começar com uma letra ou um número, podem incluir traços ('-') e podem ter até 35 caracteres.
 
 
 
 

139 linhas
4.7 KiB

  1. #include "domain/project_storage.h"
  2. #include "domain/register_repository.h"
  3. #include "services/alarm_editor_service.h"
  4. #include "services/alarm_service.h"
  5. #include "services/project_service.h"
  6. #include <algorithm>
  7. #include <exception>
  8. #include <iostream>
  9. #include <stdexcept>
  10. #include <string>
  11. namespace {
  12. class TestProjectStorage final : public ProjectStorage
  13. {
  14. public:
  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. const AlarmRecord *findRecord(
  32. const AlarmService &service, const std::string &definition_id)
  33. {
  34. const auto &records = service.records();
  35. const auto record = std::find_if(
  36. records.cbegin(), records.cend(),
  37. [&definition_id](const AlarmRecord &candidate)
  38. {
  39. return candidate.definitionId == definition_id;
  40. });
  41. return record == records.cend() ? nullptr : &*record;
  42. }
  43. void testAlarmDefinitionsAndRuntimeLifecycle()
  44. {
  45. TestProjectStorage storage;
  46. ProjectService project_service(storage);
  47. AlarmEditorService editor_service(project_service);
  48. VirtualRegisterRepository repository;
  49. AlarmService alarm_service(project_service, repository);
  50. AlarmDefinition m_alarm;
  51. m_alarm.address = RegisterAddress{RegisterArea::M, 0};
  52. m_alarm.condition = AlarmCondition::MOn;
  53. m_alarm.message = "Emergency stop";
  54. const AlarmEditorResult m_result = editor_service.addDefinition(m_alarm);
  55. AlarmDefinition high_alarm;
  56. high_alarm.address = RegisterAddress{RegisterArea::D, 0};
  57. high_alarm.condition = AlarmCondition::DHigh;
  58. high_alarm.threshold = 80;
  59. high_alarm.message = "Temperature high";
  60. const AlarmEditorResult high_result = editor_service.addDefinition(high_alarm);
  61. AlarmDefinition low_alarm;
  62. low_alarm.address = RegisterAddress{RegisterArea::D, 1};
  63. low_alarm.condition = AlarmCondition::DLow;
  64. low_alarm.threshold = 10;
  65. low_alarm.message = "Pressure low";
  66. const AlarmEditorResult low_result = editor_service.addDefinition(low_alarm);
  67. require(m_result.succeeded && high_result.succeeded && low_result.succeeded,
  68. "M, D high and D low alarm definitions must be accepted");
  69. AlarmDefinition invalid = high_alarm;
  70. invalid.address = RegisterAddress{RegisterArea::M, 2};
  71. require(editor_service.addDefinition(invalid).error
  72. == AlarmEditorError::InvalidDefinition,
  73. "D alarm conditions must reject M addresses");
  74. repository.writeWord(RegisterAddress{RegisterArea::D, 1}, 20);
  75. alarm_service.refresh();
  76. require(alarm_service.records().empty(),
  77. "inactive alarm conditions must not create records");
  78. repository.writeBit(RegisterAddress{RegisterArea::M, 0}, true);
  79. repository.writeWord(RegisterAddress{RegisterArea::D, 0}, 80);
  80. repository.writeWord(RegisterAddress{RegisterArea::D, 1}, 10);
  81. alarm_service.refresh();
  82. require(findRecord(alarm_service, m_result.id) != nullptr
  83. && findRecord(alarm_service, high_result.id) != nullptr
  84. && findRecord(alarm_service, low_result.id) != nullptr,
  85. "all three alarm conditions must create active records");
  86. require(alarm_service.acknowledge(m_result.id)
  87. && findRecord(alarm_service, m_result.id)->acknowledged,
  88. "an active alarm must be locally acknowledged");
  89. repository.writeBit(RegisterAddress{RegisterArea::M, 0}, false);
  90. repository.writeWord(RegisterAddress{RegisterArea::D, 0}, 79);
  91. repository.writeWord(RegisterAddress{RegisterArea::D, 1}, 11);
  92. alarm_service.refresh();
  93. require(alarm_service.records().empty(),
  94. "cleared conditions must immediately remove active alarms");
  95. repository.writeBit(RegisterAddress{RegisterArea::M, 0}, true);
  96. alarm_service.refresh();
  97. require(findRecord(alarm_service, m_result.id) != nullptr
  98. && alarm_service.records().size() == 1
  99. && !alarm_service.records().front().acknowledged,
  100. "a repeated alarm must create a new unacknowledged occurrence");
  101. alarm_service.reset();
  102. require(alarm_service.records().empty(),
  103. "leaving runtime must clear session alarm records");
  104. }
  105. } // namespace
  106. int main()
  107. {
  108. try
  109. {
  110. testAlarmDefinitionsAndRuntimeLifecycle();
  111. }
  112. catch (const std::exception &error)
  113. {
  114. std::cerr << "alarm service tests failed: " << error.what() << '\n';
  115. return 1;
  116. }
  117. std::cout << "alarm service tests passed\n";
  118. return 0;
  119. }