|
1 | 1 | from unittest.mock import MagicMock |
| 2 | +import pytest |
2 | 3 |
|
3 | 4 | from app.modules.orders import service, repository, models |
| 5 | +from app.modules.orders.service import OrderStateMachine, InvalidOrderTransition |
4 | 6 |
|
5 | 7 |
|
6 | 8 | def _make_mock_repo(order=None): |
@@ -91,3 +93,74 @@ def test_delete_order_not_found(): |
91 | 93 | assert False, "Should have raised ValueError" |
92 | 94 | except ValueError as e: |
93 | 95 | assert str(e) == "Order not found" |
| 96 | + |
| 97 | + |
| 98 | +# ── FSM Unit Tests ────────────────────────────────────────────────────────── |
| 99 | + |
| 100 | +VALID_TRANSITIONS = [ |
| 101 | + (models.OrderStatus.RECEIVED, models.OrderStatus.PROCESSING), |
| 102 | + (models.OrderStatus.RECEIVED, models.OrderStatus.CANCELLED), |
| 103 | + (models.OrderStatus.PROCESSING, models.OrderStatus.FULFILLED), |
| 104 | + (models.OrderStatus.PROCESSING, models.OrderStatus.CANCELLED), |
| 105 | + (models.OrderStatus.FULFILLED, models.OrderStatus.SHIPPED), |
| 106 | + (models.OrderStatus.FULFILLED, models.OrderStatus.CANCELLED), |
| 107 | + (models.OrderStatus.SHIPPED, models.OrderStatus.DELIVERED), |
| 108 | +] |
| 109 | + |
| 110 | +INVALID_TRANSITIONS = [ |
| 111 | + (models.OrderStatus.RECEIVED, models.OrderStatus.FULFILLED), |
| 112 | + (models.OrderStatus.RECEIVED, models.OrderStatus.SHIPPED), |
| 113 | + (models.OrderStatus.RECEIVED, models.OrderStatus.DELIVERED), |
| 114 | + (models.OrderStatus.PROCESSING, models.OrderStatus.SHIPPED), |
| 115 | + (models.OrderStatus.PROCESSING, models.OrderStatus.DELIVERED), |
| 116 | + (models.OrderStatus.FULFILLED, models.OrderStatus.DELIVERED), |
| 117 | + (models.OrderStatus.FULFILLED, models.OrderStatus.RECEIVED), |
| 118 | + (models.OrderStatus.SHIPPED, models.OrderStatus.PROCESSING), |
| 119 | + (models.OrderStatus.SHIPPED, models.OrderStatus.CANCELLED), |
| 120 | + (models.OrderStatus.DELIVERED, models.OrderStatus.PROCESSING), |
| 121 | + (models.OrderStatus.DELIVERED, models.OrderStatus.DELIVERED), |
| 122 | + (models.OrderStatus.CANCELLED, models.OrderStatus.PROCESSING), |
| 123 | + (models.OrderStatus.CANCELLED, models.OrderStatus.CANCELLED), |
| 124 | +] |
| 125 | + |
| 126 | + |
| 127 | +@pytest.mark.parametrize("current, target", VALID_TRANSITIONS) |
| 128 | +def test_fsm_valid_transitions(current, target): |
| 129 | + OrderStateMachine.validate_transition(current, target) |
| 130 | + |
| 131 | + |
| 132 | +@pytest.mark.parametrize("current, target", INVALID_TRANSITIONS) |
| 133 | +def test_fsm_invalid_transitions(current, target): |
| 134 | + with pytest.raises(InvalidOrderTransition): |
| 135 | + OrderStateMachine.validate_transition(current, target) |
| 136 | + |
| 137 | + |
| 138 | +def test_fsm_unknown_current_status(): |
| 139 | + with pytest.raises(InvalidOrderTransition): |
| 140 | + OrderStateMachine.validate_transition("unknown", models.OrderStatus.PROCESSING) |
| 141 | + |
| 142 | + |
| 143 | +def test_fsm_unknown_target_status(): |
| 144 | + with pytest.raises(InvalidOrderTransition): |
| 145 | + OrderStateMachine.validate_transition(models.OrderStatus.RECEIVED, "unknown") |
| 146 | + |
| 147 | + |
| 148 | +# ── Service Layer FSM Integration Tests ───────────────────────────────────── |
| 149 | + |
| 150 | + |
| 151 | +def test_update_order_invalid_status_transition(): |
| 152 | + order = _make_order() |
| 153 | + repo = _make_mock_repo(order=order) |
| 154 | + with pytest.raises(InvalidOrderTransition): |
| 155 | + service.update_order(repo, 1, status="delivered") |
| 156 | + repo._db.commit.assert_not_called() |
| 157 | + repo._db.refresh.assert_not_called() |
| 158 | + |
| 159 | + |
| 160 | +def test_update_order_valid_status_transition(): |
| 161 | + order = _make_order() |
| 162 | + repo = _make_mock_repo(order=order) |
| 163 | + result = service.update_order(repo, 1, status="processing") |
| 164 | + assert result.status == "processing" |
| 165 | + repo._db.commit.assert_called_once() |
| 166 | + repo._db.refresh.assert_called_once_with(order) |
0 commit comments