""" 标准库匹配规则单元测试 通过 conftest.py 加载生产代码 standard_service.py(绕过 package __init__.py 重依赖) """ import sys import os import pytest # 使用 conftest.py 中的共享 fixtures 和工厂函数 from conftest import ( StandardRepository, StandardMatcher, MatchResultCode, create_matcher, DEFAULT_MOCK_DATA, ) class TestStandardRepository: """测试数据仓库""" def test_load_data(self, repository): """测试数据加载""" assert len(repository.get_all_records()) == 8 def test_find_by_number_exact(self, repository): """测试精确匹配标准号""" result = repository.find_by_number_exact("TB 10002-2017") assert result is not None assert result.standard_name == "铁路桥涵设计规范" def test_find_by_name_exact(self, repository): """测试精确匹配名称""" result = repository.find_by_name_exact("铁路桥涵设计规范") assert result is not None assert result.standard_number == "TB 10002-2017" def test_find_current_by_name(self, repository): """测试查询现行标准(使用规范化名称)""" # 生产代码的 find_current_by_normalized_name 使用归一化名称 # 注意:归一化保留了中文顿号"、" normalized = repository._normalize_for_matching("起重机 钢丝绳 保养、维护、检验和报废") results = repository.find_current_by_normalized_name(normalized) assert len(results) == 1 assert results[0].standard_number == "GB/T 5972-2023" class TestStandardMatcher: """测试匹配器(基于生产代码的归一化匹配逻辑)""" def test_case1_ok(self, matcher): """情况1: 状态正常""" result = matcher.match(1, "铁路桥涵设计规范", "TB 10002-2017") assert result.status_code == MatchResultCode.OK.value assert result.final_result == "无问题" def test_case2_substituted(self, matcher): """情况2: 被替代""" result = matcher.match(1, "起重机 钢丝绳 保养、维护、检验和报废", "GB/T 5972-2016") assert result.status_code == MatchResultCode.SUBSTITUTED.value assert result.substitute_number == "(GB/T 5972-2023)" assert "已废止" in result.final_result def test_case3_abolished(self, matcher): """情况3: 废止无替代""" result = matcher.match(1, "缆索起重机", "GB/T 28756-2012") assert result.status_code == MatchResultCode.ABOLISHED.value assert "无现行状态" in result.final_result def test_case4_mismatch(self, matcher): """情况4: 不匹配""" result = matcher.match(1, "公路水运危险性较大工程专项施工方案编制审查规程", "JT/T 1495-2023") assert result.status_code == MatchResultCode.MISMATCH.value assert result.substitute_number == "(JT/T 1495-2024)" def test_case5_not_found(self, matcher): """情况5: 不存在""" result = matcher.match(1, "不存在的标准", "GB/T 99999-9999") assert result.status_code == MatchResultCode.NOT_FOUND.value def test_empty_name_returns_none(self, matcher): """空名称应返回 None(生产代码跳过审查逻辑)""" result = matcher.match(1, "", "TB 10002-2017") assert result is None def test_raw_fields_preserved(self, matcher): """验证原始输入字段正确保存""" result = matcher.match(1, "《铁路桥涵设计规范》", "(TB 10002-2017)") assert result is not None assert result.raw_name == "《铁路桥涵设计规范》" assert result.raw_number == "(TB 10002-2017)" assert result.normalized_name == "铁路桥涵设计规范" assert result.normalized_number == "TB100022017" assert result.status_code == MatchResultCode.OK.value class TestStandardMatchingBatch: """测试批量检查(模拟 StandardMatchingService.check_standards 逻辑)""" def test_check_standards_batch(self, matcher): """测试批量检查""" standards = [ {"standard_name": "铁路桥涵设计规范", "standard_number": "TB 10002-2017"}, {"standard_name": "缆索起重机", "standard_number": "GB/T 28756-2012"}, {"standard_name": "不存在的标准", "standard_number": "GB/T 99999-9999"}, ] from conftest import check_standards_via_matcher results = check_standards_via_matcher(matcher, standards) assert len(results) == 3 assert results[0].status_code == MatchResultCode.OK.value assert results[1].status_code == MatchResultCode.ABOLISHED.value assert results[2].status_code == MatchResultCode.NOT_FOUND.value def test_batch_filters_none(self, matcher): """空名称应被过滤(生产代码行为)""" standards = [ {"standard_name": "铁路桥涵设计规范", "standard_number": "TB 10002-2017"}, {"standard_name": "", "standard_number": "TB 10002-2017"}, # 空名称 ] from conftest import check_standards_via_matcher results = check_standards_via_matcher(matcher, standards) assert len(results) == 1 assert results[0].status_code == MatchResultCode.OK.value class TestDocumentExamples: """测试文档中列出的7个示例""" def test_example_1_railway_bridge(self, matcher): """(1)《铁路桥涵设计规范》(TB 10002-2017) - 正常""" result = matcher.match(1, "铁路桥涵设计规范", "TB 10002-2017") assert result.status_code == MatchResultCode.OK.value def test_example_2_seismic_design(self, matcher): """(2)《铁路工程抗震设计规范》(GB 50111-2006) - 正常""" result = matcher.match(1, "铁路工程抗震设计规范", "GB 50111-2006") assert result.status_code == MatchResultCode.OK.value def test_example_3_concrete(self, matcher): """(3)《铁路混凝土工程施工质量验收标准》(TB 10424-2018) - 正常""" result = matcher.match(1, "铁路混凝土工程施工质量验收标准", "TB 10424-2018") assert result.status_code == MatchResultCode.OK.value def test_example_4_highway_mismatch(self, matcher): """(4)年份不匹配 - 应为2024""" result = matcher.match(1, "公路水运危险性较大工程专项施工方案编制审查规程", "JT/T 1495-2023") assert result.status_code == MatchResultCode.MISMATCH.value assert result.substitute_number == "(JT/T 1495-2024)" def test_example_5_crane_wire_substituted(self, matcher): """(5)被替代 GB/T 5972-2016 -> GB/T 5972-2023""" result = matcher.match(1, "起重机 钢丝绳 保养、维护、检验和报废", "GB/T 5972-2016") assert result.status_code == MatchResultCode.SUBSTITUTED.value assert result.substitute_number == "(GB/T 5972-2023)" def test_example_6_cable_crane_abolished(self, matcher): """(6)废止无替代""" result = matcher.match(1, "缆索起重机", "GB/T 28756-2012") assert result.status_code == MatchResultCode.ABOLISHED.value def test_example_7_safety_device_abolished(self, matcher): """(7)废止无替代""" result = matcher.match(1, "电力高处作业防坠器", "DL/T 1147-2009") assert result.status_code == MatchResultCode.ABOLISHED.value if __name__ == "__main__": pytest.main([__file__, "-v"])