#include "domain/project_storage.h" #include "domain/register_repository.h" #include "services/hmi_editor_service.h" #include "services/hmi_runtime_service.h" #include "services/project_service.h" #include #include #include #include namespace { class TestProjectStorage final : public ProjectStorage { public: // 编辑服务测试只关注内存模型变更,不依赖真实文件系统 ProjectSaveResult save(const Project &, const std::string &) override { return {true, ProjectStorageError::None, {}}; } ProjectLoadResult load(const std::string &) override { return {false, {}, ProjectStorageError::FileReadFailed, {}}; } }; void require(bool condition, const std::string &message) { if (!condition) { throw std::runtime_error(message); } } void testControlEditing() { // 覆盖控件创建、移动、绑定校验、重命名冲突和删除流程 TestProjectStorage storage; ProjectService project_service(storage); HmiEditorService service(project_service); const HmiEditorResult page_result = service.ensureDefaultPage(); require(page_result.succeeded, "default HMI page creation must succeed"); const std::string page_id = page_result.id; const HmiEditorResult button = service.addControl(page_id, HmiControlType::Button); const HmiEditorResult indicator = service.addControl(page_id, HmiControlType::Indicator); const HmiEditorResult display = service.addControl( page_id, HmiControlType::NumericDisplay); const HmiEditorResult input = service.addControl(page_id, HmiControlType::NumericInput); require(button.succeeded && indicator.succeeded && display.succeeded && input.succeeded, "four basic HMI controls must be added"); const HmiPage *page = service.findPage(page_id); require(page != nullptr && page->controls.size() == 4, "all added controls must be kept in the page model"); require(service.moveControl(page_id, button.id, {120, 80, 120, 40}).succeeded, "a valid control move must succeed"); require(!service.moveControl(page_id, button.id, {790, 460, 120, 40}).succeeded, "a move outside the page must be rejected"); HmiControl updated = *service.findControl(page_id, button.id); updated.binding = RegisterAddress{RegisterArea::D, 0}; require(!service.updateControl(page_id, button.id, updated).succeeded, "buttons must reject D address bindings during editing"); updated.binding = RegisterAddress{RegisterArea::M, 7}; updated.text = "启动"; require(service.updateControl(page_id, button.id, updated).succeeded, "a button M binding and edited text must be accepted"); HmiControl duplicate = *service.findControl(page_id, indicator.id); duplicate.id = button.id; require(service.updateControl(page_id, indicator.id, duplicate).error == HmiEditorError::DuplicateId, "duplicate control ids must be rejected"); require(service.removeControl(page_id, indicator.id).succeeded, "deleting a selected control must succeed"); require(service.findControl(page_id, indicator.id) == nullptr, "deleted controls must not remain in the model"); } void testRuntimeUsesRegisterRepository() { // 运行服务只能经由仓库接口读写 M/D,不依赖具体离线实现 VirtualRegisterRepository repository; HmiRuntimeService runtime_service(repository); HmiControl button; button.id = "start"; button.type = HmiControlType::Button; button.binding = RegisterAddress{RegisterArea::M, 12}; require(runtime_service.toggleButton(button).succeeded, "button runtime writes must be accepted by the repository"); require(repository.readBit(*button.binding).value, "button runtime writes must reach the M repository value"); HmiControl indicator; indicator.id = "running"; indicator.type = HmiControlType::Indicator; indicator.binding = RegisterAddress{RegisterArea::M, 12}; const HmiRuntimeReadResult indicator_value = runtime_service.readControl(indicator); require(indicator_value.succeeded && indicator_value.bit_value, "indicators must read M values through the repository"); HmiControl numeric_input; numeric_input.id = "target"; numeric_input.type = HmiControlType::NumericInput; numeric_input.binding = RegisterAddress{RegisterArea::D, 9}; require(runtime_service.writeNumericInput(numeric_input, -18).succeeded, "numeric input runtime writes must be accepted by the repository"); HmiControl numeric_display; numeric_display.id = "actual"; numeric_display.type = HmiControlType::NumericDisplay; numeric_display.binding = RegisterAddress{RegisterArea::D, 9}; const HmiRuntimeReadResult numeric_value = runtime_service.readControl(numeric_display); require(numeric_value.succeeded && numeric_value.word_value == -18, "numeric display must read D values through the repository"); } } // namespace int main() { try { // 编辑和运行场景分别验证服务层两条独立职责 testControlEditing(); testRuntimeUsesRegisterRepository(); } catch (const std::exception &error) { std::cerr << "HMI editor service tests failed: " << error.what() << '\n'; return 1; } std::cout << "HMI editor service tests passed\n"; return 0; }