From db5755586dc4a2d659dd25a0b865d1b9a59c8117 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E7=84=A6=E9=BE=99=E8=A8=80?= Date: Mon, 27 Jul 2026 20:41:20 +0800 Subject: [PATCH] =?UTF-8?q?=E6=B5=8B=E8=AF=95=EF=BC=9A=E5=8A=A0=E5=BC=BA?= =?UTF-8?q?=E4=B8=80=E7=BA=A7=E8=8F=9C=E5=8D=95=E7=A8=B3=E5=AE=9A=E5=AD=97?= =?UTF-8?q?=E6=AE=B5=E5=A5=91=E7=BA=A6?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../module_business/test_sql_contract.py | 41 +++++++++++++++++-- 1 file changed, 38 insertions(+), 3 deletions(-) diff --git a/shierfeng-fastapi-backend/tests/module_business/test_sql_contract.py b/shierfeng-fastapi-backend/tests/module_business/test_sql_contract.py index bca6d2e..9503d6d 100644 --- a/shierfeng-fastapi-backend/tests/module_business/test_sql_contract.py +++ b/shierfeng-fastapi-backend/tests/module_business/test_sql_contract.py @@ -590,6 +590,14 @@ EXPECTED_TOP_LEVEL_MENU_POSITIONS = { 2: ('系统监控', 0, 5), 3: ('系统工具', 0, 6), } +EXPECTED_TOP_LEVEL_MENU_STABLE_FIELDS = { + 121: ('基础资料维护', 'businessMaster', None, '', '', '1', '0', 'M', '0', '0', '', '#'), + 122: ('业务管理', 'businessOperation', None, '', '', '1', '0', 'M', '0', '0', '', '#'), + 123: ('报表查询', 'businessReport', None, '', '', '1', '0', 'M', '0', '0', '', '#'), + 1: ('系统管理', 'system', None, '', '', '1', '0', 'M', '0', '0', '', 'system'), + 2: ('系统监控', 'monitor', None, '', '', '1', '0', 'M', '0', '0', '', 'monitor'), + 3: ('系统工具', 'tool', None, '', '', '1', '0', 'M', '0', '0', '', 'tool'), +} MENU_PROMOTION_IDS = set(EXPECTED_TOP_LEVEL_MENU_POSITIONS) BUSINESS_MENU_IDS = set(range(121, 124)) | set(range(502, 519)) | set(range(1065, 1109)) MYSQL_MENU_STABLE_COLUMNS = ( @@ -870,6 +878,15 @@ def _business_menu_rows(sql: str) -> dict[int, list]: return _menu_rows(sql, BUSINESS_MENU_IDS) +def _assert_top_level_menu_fields(test_case: unittest.TestCase, sql: str) -> None: + rows = _menu_rows(sql, MENU_PROMOTION_IDS) + actual_positions = {menu_id: (row[1], int(row[2]), int(row[3])) for menu_id, row in rows.items()} + test_case.assertEqual(EXPECTED_TOP_LEVEL_MENU_POSITIONS, actual_positions) + stable_indexes = (1, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14) + actual_stable_fields = {menu_id: tuple(row[index] for index in stable_indexes) for menu_id, row in rows.items()} + test_case.assertEqual(EXPECTED_TOP_LEVEL_MENU_STABLE_FIELDS, actual_stable_fields) + + def _assert_business_menu_fields( test_case: unittest.TestCase, sql: str, @@ -1002,9 +1019,27 @@ class SqlContractTest(unittest.TestCase): for filename in INITIALIZERS: with self.subTest(filename=filename): sql = (SQL_ROOT / filename).read_text(encoding='utf-8') - rows = _menu_rows(sql, MENU_PROMOTION_IDS) - actual = {menu_id: (row[1], int(row[2]), int(row[3])) for menu_id, row in rows.items()} - self.assertEqual(EXPECTED_TOP_LEVEL_MENU_POSITIONS, actual) + _assert_top_level_menu_fields(self, sql) + + def test_top_level_menu_contract_rejects_same_stable_field_drift_in_both_initializers(self) -> None: + mutations = ( + (1, '系统管理', 'system', 'driftSystemIcon'), + (121, '基础资料维护', '#', 'driftBusinessIcon'), + ) + for filename in INITIALIZERS: + sql = (SQL_ROOT / filename).read_text(encoding='utf-8') + for menu_id, menu_name, original_icon, drifted_icon in mutations: + with self.subTest(filename=filename, menu_id=menu_id): + mutated, replacements = re.subn( + rf"(\(?\s*'?{menu_id}'?\s*,\s*'{menu_name}'.*?,\s*)'{re.escape(original_icon)}'" + r"(\s*,\s*'admin')", + rf"\1'{drifted_icon}'\2", + sql, + count=1, + ) + self.assertEqual(1, replacements) + with self.assertRaises(AssertionError): + _assert_top_level_menu_fields(self, mutated) def test_business_permission_inventory_rejects_duplicate_permission(self) -> None: sql = (SQL_ROOT / INITIALIZERS[0]).read_text(encoding='utf-8')