Traffic Light: tests and solutions


makePythonTdd TrafficLight

The code in makePythonTdd.sh from Traffic Light

 1#!/bin/bash
 2uv init traffic_light
 3cd traffic_light
 4mkdir tests
 5touch tests/__init__.py
 6
 7echo "import unittest
 8
 9
10class TestTrafficLight(unittest.TestCase):
11
12    def test_failure(self):
13        self.assertFalse(True)
14
15
16# Exceptions seen
17# AssertionError
18" > tests/test_traffic_light.py
19
20echo "pytest" > requirements.txt
21echo "pytest-watcher" >> requirements.txt
22uv add --requirement requirements.txt
23uv run pytest-watcher . --now

The code in makePythonTdd.ps1 from Traffic Light

 1uv init traffic_light
 2cd traffic_light
 3mkdir tests
 4New-Item tests/__init__.py
 5
 6"import unittest
 7
 8
 9class TestTrafficLight(unittest.TestCase):
10
11    def test_failure(self):
12        self.assertFalse(True)
13
14
15# Exceptions seen
16# AssertionError
17" | Out-File "tests/test_traffic_light.py" -Encoding UTF8
18
19"pytest" | Out-File requirements.txt -Encoding UTF8
20"pytest-watcher" >> requirements.txt
21uv add --requirement requirements.txt
22uv run pytest-watcher . --now

Traffic Light: tests

The code in traffic_light/tests/test_traffic_light.py from Traffic Light

traffic_light/tests/test_traffic_light.py
 1import src.traffic_light
 2import unittest
 3
 4
 5GREEN, YELLOW, RED = 'GREEN', 'YELLOW', 'RED'
 6
 7
 8class TestTrafficLight(unittest.TestCase):
 9
10    def test_parallel_green_cross_red_timer_not_done(self):
11        self.assertEqual(
12            src.traffic_light.control(
13                red_phase='cross',
14                current_parallel=GREEN,
15                current_cross=RED,
16                timer_done=False,
17            ),
18            (GREEN, RED)
19        )
20
21    def test_parallel_green_cross_red_timer_done(self):
22        self.assertEqual(
23            src.traffic_light.control(
24                red_phase='cross',
25                current_parallel=GREEN,
26                current_cross=RED,
27                timer_done=True,
28            ),
29            (YELLOW, RED)
30        )
traffic_light/tests/test_traffic_light.py
32    def test_parallel_yellow_cross_red_timer_not_done(self):
33        self.assertEqual(
34            src.traffic_light.control(
35                red_phase='cross',
36                current_parallel=YELLOW,
37                current_cross=RED,
38                timer_done=False,
39            ),
40            (YELLOW, RED)
41        )
42
43    def test_parallel_yellow_cross_red_timer_done(self):
44        self.assertEqual(
45            src.traffic_light.control(
46                red_phase='cross',
47                current_parallel=YELLOW,
48                current_cross=RED,
49                timer_done=True,
50            ),
51            (RED, RED)
52        )
traffic_light/tests/test_traffic_light.py
54    def test_parallel_red_cross_red_timer_not_done(self):
55        self.assertEqual(
56            src.traffic_light.control(
57                red_phase='cross',
58                current_parallel=RED,
59                current_cross=RED,
60                timer_done=False,
61            ),
62            (RED, RED)
63        )
64
65    def test_parallel_red_cross_red_timer_done(self):
66        self.assertEqual(
67            src.traffic_light.control(
68                red_phase='cross',
69                current_parallel=RED,
70                current_cross=RED,
71                timer_done=True,
72            ),
73            (RED, GREEN)
74        )
traffic_light/tests/test_traffic_light.py
76    def test_cross_green_parallel_red_timer_not_done(self):
77        self.assertEqual(
78            src.traffic_light.control(
79                red_phase='parallel',
80                current_parallel=RED,
81                current_cross=GREEN,
82                timer_done=False,
83            ),
84            (RED, GREEN)
85        )
86
87    def test_cross_green_parallel_red_timer_done(self):
88        self.assertEqual(
89            src.traffic_light.control(
90                red_phase='parallel',
91                current_parallel=RED,
92                current_cross=GREEN,
93                timer_done=True,
94            ),
95            (RED, YELLOW)
96        )
traffic_light/tests/test_traffic_light.py
 98    def test_cross_yellow_parallel_red_timer_not_done(self):
 99        self.assertEqual(
100            src.traffic_light.control(
101                red_phase='parallel',
102                current_parallel=RED,
103                current_cross=YELLOW,
104                timer_done=False,
105            ),
106            (RED, YELLOW)
107        )
108
109    def test_cross_yellow_parallel_red_timer_done(self):
110        self.assertEqual(
111            src.traffic_light.control(
112                red_phase='parallel',
113                current_parallel=RED,
114                current_cross=YELLOW,
115                timer_done=True,
116            ),
117            (RED, RED)
118        )
traffic_light/tests/test_traffic_light.py
120    def test_cross_red_parallel_red_timer_not_done(self):
121        self.assertEqual(
122            src.traffic_light.control(
123                red_phase='parallel',
124                current_parallel=RED,
125                current_cross=RED,
126                timer_done=False,
127            ),
128            (RED, RED)
129        )
130
131    def test_cross_red_parallel_red_timer_done(self):
132        self.assertEqual(
133            src.traffic_light.control(
134                red_phase='parallel',
135                current_parallel=RED,
136                current_cross=RED,
137                timer_done=True,
138            ),
139            (GREEN, RED)
140        )
traffic_light/tests/test_traffic_light.py
142    def test_failsafe(self):
143        self.assertEqual(
144            src.traffic_light.control(
145                red_phase='BOOM',
146                current_parallel='BAP',
147                current_cross=RED,
148                timer_done=False,
149            ),
150            (RED, RED)
151        )
152        self.assertEqual(
153            src.traffic_light.control(
154                red_phase='BOOM',
155                current_parallel=RED,
156                current_cross='POW',
157                timer_done=False,
158            ),
159            (RED, RED)
160        )
traffic_light/tests/test_traffic_light.py
161        self.assertEqual(
162            src.traffic_light.control(
163                red_phase='BOOM',
164                current_parallel=GREEN,
165                current_cross=GREEN,
166                timer_done=False,
167            ),
168            (RED, RED)
169        )
170        self.assertEqual(
171            src.traffic_light.control(
172                red_phase='BOOM',
173                current_parallel=GREEN,
174                current_cross=YELLOW,
175                timer_done=False,
176            ),
177            (RED, RED)
178        )
traffic_light/tests/test_traffic_light.py
179        self.assertEqual(
180            src.traffic_light.control(
181                red_phase='BOOM',
182                current_parallel=YELLOW,
183                current_cross=GREEN,
184                timer_done=False,
185            ),
186            (RED, RED)
187        )
188        self.assertEqual(
189            src.traffic_light.control(
190                red_phase='BOOM',
191                current_parallel=YELLOW,
192                current_cross=YELLOW,
193                timer_done=False,
194            ),
195            (RED, RED)
196        )
197
198
199# Exceptions seen
200# AssertionError
201# NameError
202# AttributeError
203# TypeError

Traffic Light: solution

The code in traffic_light/src/traffic_light/__init__.py from Traffic Light

traffic_light/src/traffic_light/__init__.py
 1RED, YELLOW, GREEN = 'RED', 'YELLOW', 'GREEN'
 2
 3
 4def is_not_safe(parallel, cross):
 5    return (
 6        (parallel == cross != RED)
 7        or (parallel == GREEN and cross == YELLOW)
 8        or (parallel == YELLOW and cross == GREEN)
 9    )
10
11
12def is_not_light(light):
13    return not (
14        light == GREEN or light == YELLOW or light == RED
15    )
16
17
18def triggers_failsafe(parallel, cross):
19    return (
20        is_not_light(parallel) or is_not_light(cross)
21        or is_not_safe(parallel, cross)
22    )
23
24
25def next_light(red_phase, parallel, cross):
26    if red_phase == 'cross':
27        if parallel == GREEN:
28            return YELLOW, RED
29        if parallel == RED:
30            return RED, GREEN
31    if red_phase == 'parallel':
32        if cross == GREEN:
33            return RED, YELLOW
34        if cross == RED:
35            return GREEN, RED
36    return RED, RED
37
38
39def control(
40        timer_done, red_phase='parallel',
41        current_parallel=RED, current_cross=RED,
42    ):
43    if triggers_failsafe(current_parallel, current_cross):
44        return RED, RED
45
46    if not timer_done:
47        return current_parallel, current_cross
48
49    if timer_done:
50        return next_light(
51            red_phase, current_parallel, current_cross
52        )
53
54    return RED, RED