import importlib.util import csv import io from pathlib import Path import sys import types import unittest from unittest.mock import patch MODULE_PATH = Path(__file__).resolve().parents[1] / "core" / "identification_config.py" SPEC = importlib.util.spec_from_file_location( "identification_config_under_test", MODULE_PATH ) IDENTIFICATION_CONFIG = importlib.util.module_from_spec(SPEC) SPEC.loader.exec_module(IDENTIFICATION_CONFIG) validate_identification_config = IDENTIFICATION_CONFIG.validate_identification_config parse_identification_config_csv = IDENTIFICATION_CONFIG.parse_identification_config_csv download_identification_config = IDENTIFICATION_CONFIG.download_identification_config VALID_CONFIG = { "q_in_val": 50.0, "dt": 0.1, "n_order": 6, "t_c": 2.5, "levels": [10, 20, 30, 40, 50, 60, 70, 80], "dead_area": 240.0, "xa_full": 1000.0, "V_val": 5.0, "repeat": 2, } def config_csv(config): output = io.StringIO(newline="") writer = csv.writer(output) writer.writerow(("parameter", "value")) for key in ( "q_in_val", "dt", "n_order", "t_c", "levels", "dead_area", "xa_full", "V_val", "repeat"): value = config[key] if key == "levels": value = ",".join(str(item) for item in value) writer.writerow((key, value)) return output.getvalue() class IdentificationConfigTests(unittest.TestCase): def test_accepts_and_normalizes_valid_config(self): result = validate_identification_config(VALID_CONFIG) self.assertEqual(result["repeat"], 2) self.assertEqual(result["levels"], [ 10.0, 20.0, 30.0, 40.0, 50.0, 60.0, 70.0, 80.0 ]) def test_rejects_missing_field(self): config = dict(VALID_CONFIG) config.pop("repeat") with self.assertRaisesRegex(ValueError, "缺少"): validate_identification_config(config) def test_parses_parameter_value_csv(self): result = parse_identification_config_csv(config_csv(VALID_CONFIG)) self.assertEqual(result, VALID_CONFIG) def test_rejects_non_power_of_two_levels(self): config = dict(VALID_CONFIG, levels=[10, 20, 30]) with self.assertRaisesRegex(ValueError, "2 的整数次幂"): validate_identification_config(config) def test_rejects_symbol_period_shorter_than_sample_period(self): config = dict(VALID_CONFIG, dt=0.1, t_c=0.05) with self.assertRaisesRegex(ValueError, "t_c 必须大于等于 dt"): validate_identification_config(config) def test_rejects_travel_scan_above_xa_full(self): config = dict(VALID_CONFIG, xa_full=999.0) with self.assertRaisesRegex(ValueError, "1000"): validate_identification_config(config) def test_rejects_dead_area_at_or_above_xa_full(self): config = dict(VALID_CONFIG, dead_area=1000.0) with self.assertRaisesRegex(ValueError, "dead_area"): validate_identification_config(config) def test_download_requests_customer_config_and_validates_it(self): calls = [] class FakeResponse: def __init__(self, body=None, text=None): self.body = body self.text = text def raise_for_status(self): return None def json(self): return self.body requests_module = types.ModuleType("requests") requests_module.RequestException = Exception def post(url, json, timeout): calls.append(("post", url, json, timeout)) return FakeResponse({"success": True, "url": "https://temp/config"}) def get(url, timeout): calls.append(("get", url, timeout)) return FakeResponse(text=config_csv(VALID_CONFIG)) requests_module.post = post requests_module.get = get api_module = types.ModuleType("api") api_module.data_record_url = "https://cloud/data_record" api_module.the_folder = "客户A" with patch.dict(sys.modules, { "requests": requests_module, "api": api_module, }): result = download_identification_config(timeout=7) self.assertEqual(result["repeat"], 2) self.assertEqual(calls[0], ( "post", "https://cloud/data_record", {"type": "getIdentificationConfig", "deviceId": "客户A"}, 7, )) self.assertEqual(calls[1], ("get", "https://temp/config", 7)) def test_download_reports_cloud_rejection(self): class FakeResponse: def raise_for_status(self): return None def json(self): return {"success": False, "errMsg": "配置不存在"} requests_module = types.ModuleType("requests") requests_module.RequestException = Exception requests_module.post = lambda *args, **kwargs: FakeResponse() api_module = types.ModuleType("api") api_module.data_record_url = "https://cloud/data_record" api_module.the_folder = "客户A" with patch.dict(sys.modules, { "requests": requests_module, "api": api_module, }): with self.assertRaisesRegex(ValueError, "配置不存在"): download_identification_config() if __name__ == "__main__": unittest.main()