diff --git a/shierfeng-fastapi-backend/module_business/domain/pallet_state_machine.py b/shierfeng-fastapi-backend/module_business/domain/pallet_state_machine.py index 6b08a3f..d8e8e52 100644 --- a/shierfeng-fastapi-backend/module_business/domain/pallet_state_machine.py +++ b/shierfeng-fastapi-backend/module_business/domain/pallet_state_machine.py @@ -32,7 +32,8 @@ class PalletStateMachine: current: PalletFlowState, target: PalletFlowState, ) -> None: + if not isinstance(current, PalletFlowState) or not isinstance(target, PalletFlowState): + raise TypeError('current 和 target 必须是 PalletFlowState') + if (current, target) not in cls._ALLOWED_TRANSITIONS: - raise InvalidPalletTransition( - f'不允许的托盘状态迁移:{current.value} -> {target.value}' - ) + raise InvalidPalletTransition(f'不允许的托盘状态迁移:{current.value} -> {target.value}') diff --git a/shierfeng-fastapi-backend/tests/module_business/test_state_machine.py b/shierfeng-fastapi-backend/tests/module_business/test_state_machine.py index 9fb125b..3bebc13 100644 --- a/shierfeng-fastapi-backend/tests/module_business/test_state_machine.py +++ b/shierfeng-fastapi-backend/tests/module_business/test_state_machine.py @@ -39,6 +39,22 @@ class PalletStateMachineTest(unittest.TestCase): PalletFlowState.FILLED_IN_WAREHOUSE, ) + def test_raw_string_states_are_rejected(self) -> None: + with self.assertRaisesRegex(TypeError, 'PalletFlowState'): + PalletStateMachine.ensure_transition( + 'UNSTOCKED', + 'EMPTY_IN_WAREHOUSE', + ) + + def test_mixed_state_types_are_rejected(self) -> None: + mixed_states = ( + ('UNSTOCKED', PalletFlowState.EMPTY_IN_WAREHOUSE), + (PalletFlowState.UNSTOCKED, 'EMPTY_IN_WAREHOUSE'), + ) + for current, target in mixed_states: + with self.subTest(current=current, target=target), self.assertRaisesRegex(TypeError, 'PalletFlowState'): + PalletStateMachine.ensure_transition(current, target) + def test_confirmed_flow_is_the_only_allowed_transition_set(self) -> None: actual_allowed = set() for current in PalletFlowState: @@ -54,6 +70,18 @@ class PalletStateMachineTest(unittest.TestCase): class PalletEnumTest(unittest.TestCase): def test_supporting_enum_values_match_domain_contract(self) -> None: + self.assertEqual( + [ + 'UNSTOCKED', + 'EMPTY_IN_WAREHOUSE', + 'FILLED_IN_WAREHOUSE', + 'AT_SITE_UNUSED', + 'AT_SITE_PARTIAL', + 'AT_SITE_EMPTY', + 'RETURNING', + ], + [item.value for item in PalletFlowState], + ) self.assertEqual(['DRAFT', 'CONFIRMED'], [item.value for item in DocumentStatus]) self.assertEqual( ['REQUESTED', 'CONFIRMED'],