Traffic Light
I want to make a Traffic Light that changes color.
preview
These are the tests I have at the end of the chapter
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 )
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 )
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 )
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 )
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 )
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 )
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 )
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 )
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
start the project
I open a terminal
I open
makePythonTdd.shI change the name of the project to
traffic_lightinmakePythonTdd.sh1#!/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 . --nowI run
makePythonTdd.shin the terminal to make thetraffic_lightproject./makePythonTdd.sh
I open
makePythonTdd.ps1I change the name of the project to
traffic_lightinmakePythonTdd.ps11uv 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 . --nowI run
makePythonTdd.ps1in the terminal to make thetraffic_lightproject.\makePythonTdd.ps1
the terminal is my friend, and shows AssertionError
======================== FAILURES ========================= ___________ TestTrafficLight.test_failure _________________ self = <tests.test_traffic_light.TestTrafficLight testMethod=test_failure> def test_failure(self): > self.assertFalse(True) E AssertionError: True is not false tests/test_traffic_light.py:7: AssertionError ================ short test summary info ================== FAILED tests/test_traffic_light.py::TestTrafficLight::test_failure - AssertionError: True is not false ==================== 1 failed in X.YZs ====================I hold ctrl (Windows/Linux) or option/command (MacOS) on the keyboard and use the mouse to click on
tests/test_traffic_light.py:7to open itI change assertFalse to assertTrue in
tests/test_traffic_light.py4class TestTrafficLight(unittest.TestCase): 5 6 def test_failure(self): 7 # self.assertFalse(True) 8 self.assertTrue(True) 9 10 11# Exceptions seenthe test passes.
I open a new terminal then change directory to
traffic_lightcd traffic_lightI add the new files and folder to git for tracking
git add .I add a git commit message
git commit -am 'setup project'
I want the Traffic Light to change color based on a timer. If the inputs are
what color is the light now?
is the timer done?
then I get this truth table
current light |
timer |
output |
|---|---|---|
GREEN |
NOT done |
GREEN |
GREEN |
done |
YELLOW |
YELLOW |
NOT done |
YELLOW |
YELLOW |
done |
RED |
RED |
NOT done |
RED |
RED |
done |
GREEN |
test_green_light_timer_not_done
RED: make it fail
I go back to the terminal where the tests are running
I change test_failure to test_green_light_timer_not_done, then add an assertion for if the light is GREEN AND the timer is NOT done
current light
timer
output
GREEN
NOT done
GREEN
4class TestTrafficLight(unittest.TestCase): 5 6 def test_green_light_timer_not_done(self): 7 self.assertEqual( 8 src.traffic_light.control( 9 timer_done=False, 10 current_light='GREEN', 11 ), 12 'GREEN' 13 ) 14 15 16# Exceptions seen 17# AssertionErrorthe terminal is my friend, and shows NameError
NameError: name 'src' is not definedbecause I do not have a definition for
srcin this file
GREEN: make it pass
I add NameError to the list of Exceptions seen
16# Exceptions seen 17# AssertionError 18# NameErrorI add an import statement at the top of the file
1import src.traffic_light 2import unittest 3 4 5class TestTrafficLight(unittest.TestCase):the terminal is my friend, and shows AttributeError
AttributeError: module 'src.traffic_light' has no attribute 'control'because
traffic_light/__init__.pyin thesrcfolder does not have anything namedcontrolin itI add AttributeError to the list of Exceptions seen
17# Exceptions seen 18# AssertionError 19# NameError 20# AttributeErrorI open
traffic_light/__init__.pyfrom thesrcfolderI delete all the text in the file then add a function to
src/traffic_light/__init__.py1def control(): 2 return Nonethe terminal is my friend, and shows TypeError
TypeError: control() got an unexpected keyword argument 'timer_done'I add TypeError to the list of Exceptions seen, in
tests/test_traffic_light.py17# Exceptions seen 18# AssertionError 19# NameError 20# AttributeError 21# TypeErrorI add
timer_doneto the function insrc/traffic_light/__init__.py1def control(timer_done): 2 return Nonethe terminal is my friend, and shows TypeError
TypeError: control() got an unexpected keyword argument 'current_light'I add
current_lightto the function signature1def control(timer_done, current_light): 2 return Nonethe terminal is my friend, and shows AssertionError
AssertionError: None != 'GREEN'I change the return statement to give the test what it expects
1def control(timer_done, current_light): 2 return 'GREEN'the test passes.
control(current_light='GREEN' , timer_done=False) -> 'GREEN'I add a git commit message in the other terminal
git commit -am 'add test_green_light_timer_not_done'
test_green_light_timer_done
RED: make it fail
I go back to the terminal where the tests are running
I add a test with an assertion for if the light is GREEN AND the timer is done, to
tests/test_traffic_light.pycurrent light
timer
output
GREEN
done
YELLOW
7 def test_green_light_timer_not_done(self): 8 self.assertEqual( 9 src.traffic_light.control( 10 timer_done=False, 11 current_light='GREEN', 12 ), 13 'GREEN' 14 ) 15 16 def test_green_light_timer_done(self): 17 self.assertEqual( 18 src.traffic_light.control( 19 timer_done=True, 20 current_light='GREEN', 21 ), 22 'YELLOW' 23 ) 24 25 26# Exceptions seenthe terminal is my friend, and shows AssertionError
AssertionError: 'GREEN' != 'YELLOW'
GREEN: make it pass
I add an if statement for this case, to
src/traffic_light/__init__.py1def control(timer_done, current_light): 2 if timer_done: 3 return 'YELLOW' 4 5 return 'GREEN'the test passes.
control(current_light='GREEN' , timer_done=False) -> 'GREEN' control(current_light='GREEN' , timer_done=True ) -> 'YELLOW'
REFACTOR: make it better
I add a global variable for
'GREEN'totests/test_traffic_light.py1import src.traffic_light 2import unittest 3 4 5GREEN = 'GREEN' 6 7 8class TestTrafficLight(unittest.TestCase): 9 10 def test_green_light_timer_not_done(self):I use the new variable for
'GREEN'in test_green_light_timer_not_done10 def test_green_light_timer_not_done(self): 11 self.assertEqual( 12 src.traffic_light.control( 13 timer_done=False, 14 # current_light='GREEN', 15 current_light=GREEN, 16 ), 17 # 'GREEN' 18 GREEN 19 ) 20 21 def test_green_light_timer_done(self):the test is still green.
I remove the commented lines from test_green_light_timer_not_done
10 def test_green_light_timer_not_done(self): 11 self.assertEqual( 12 src.traffic_light.control( 13 timer_done=False, 14 current_light=GREEN, 15 ), 16 GREEN 17 ) 18 19 def test_green_light_timer_done(self):I use the new variable for
'GREEN'in test_green_light_timer_done19 def test_green_light_timer_done(self): 20 self.assertEqual( 21 src.traffic_light.control( 22 timer_done=True, 23 # current_light='GREEN', 24 current_light=GREEN, 25 ), 26 'YELLOW' 27 ) 28 29 30# Exceptions seenstill green.
I remove the commented lines from test_green_light_timer_done
19 def test_green_light_timer_done(self): 20 self.assertEqual( 21 src.traffic_light.control( 22 timer_done=True, 23 current_light=GREEN, 24 ), 25 'YELLOW' 26 ) 27 28 29# Exceptions seenI add a git commit message in the other terminal
git commit -am 'add test_green_light_timer_done'
test_yellow_light_timer_not_done
RED: make it fail
I go back to the terminal where the tests are running.
I add a test with an assertion for if the Traffic Light is YELLOW AND the timer is NOT done, to
tests/test_traffic_light.pycurrent light
timer
output
YELLOW
NOT done
YELLOW
19 def test_green_light_timer_done(self): 20 self.assertEqual( 21 src.traffic_light.control( 22 timer_done=True, 23 current_light=GREEN, 24 ), 25 'YELLOW' 26 ) 27 28 def test_yellow_light_timer_not_done(self): 29 self.assertEqual( 30 src.traffic_light.control( 31 timer_done=False, 32 current_light='YELLOW', 33 ), 34 'YELLOW' 35 ) 36 37 38# Exceptions seenthe terminal is my friend, and shows AssertionError
AssertionError: 'GREEN' != 'YELLOW'
GREEN: make it pass
I add an if statement for if the current light is YELLOW to
src/traffic_light/__init__.py1def control(timer_done, current_light): 2 if timer_done: 3 return 'YELLOW' 4 5 if current_light == 'YELLOW': 6 return current_light 7 8 return 'GREEN'the test passes.
control(current_light='GREEN' , timer_done=False) -> 'GREEN' control(current_light='GREEN' , timer_done=True ) -> 'YELLOW' control(current_light='YELLOW', timer_done=False) -> 'YELLOW'
REFACTOR: make it better
I add a global variable for
'YELLOW'totests/test_traffic_light.py1import src.traffic_light 2import unittest 3 4 5GREEN, YELLOW = 'GREEN', 'YELLOW' 6 7 8class TestTrafficLight(unittest.TestCase):I use the new variable for
'YELLOW'in test_green_light_timer_done19 def test_green_light_timer_done(self): 20 self.assertEqual( 21 src.traffic_light.control( 22 timer_done=True, 23 current_light=GREEN, 24 ), 25 # 'YELLOW' 26 YELLOW 27 ) 28 29 def test_yellow_light_timer_not_done(self):the test is still green.
I remove the commented line from test_green_light_timer_done
19 def test_green_light_timer_done(self): 20 self.assertEqual( 21 src.traffic_light.control( 22 timer_done=True, 23 current_light=GREEN, 24 ), 25 YELLOW 26 ) 27 28 def test_yellow_light_timer_not_done(self):I use the new variable for
'YELLOW'in test_yellow_light_timer_not_done28 def test_yellow_light_timer_not_done(self): 29 self.assertEqual( 30 src.traffic_light.control( 31 timer_done=False, 32 # current_light='YELLOW', 33 current_light=YELLOW, 34 ), 35 # 'YELLOW' 36 YELLOW 37 ) 38 39 40# Exceptions seenstill green.
I remove the commented lines from test_yellow_light_timer_not_done
28 def test_yellow_light_timer_not_done(self): 29 self.assertEqual( 30 src.traffic_light.control( 31 timer_done=False, 32 current_light=YELLOW, 33 ), 34 YELLOW 35 ) 36 37 38# Exceptions seenI add a git commit message in the other terminal
git commit -am 'add test_yellow_light_timer_not_done'
test_yellow_light_timer_done
RED: make it fail
I go back to the terminal where the tests are running
I add a test with an assertion for if the light is YELLOW AND the timer is done, to
tests/test_traffic_light.pycurrent light
timer
output
YELLOW
done
RED
28 def test_yellow_light_timer_not_done(self): 29 self.assertEqual( 30 src.traffic_light.control( 31 timer_done=False, 32 current_light=YELLOW, 33 ), 34 YELLOW 35 ) 36 37 def test_yellow_light_timer_done(self): 38 self.assertEqual( 39 src.traffic_light.control( 40 timer_done=True, 41 current_light=YELLOW, 42 ), 43 'RED' 44 ) 45 46 47# Exceptions seenthe terminal is my friend, and shows AssertionError
AssertionError: 'YELLOW' != 'RED'
GREEN: make it pass
I add an if statement for if the timer is done AND the light is YELLOW, in
src/traffic_light/__init__.py1def control(timer_done, current_light): 2 if timer_done: 3 if current_light == 'YELLOW': 4 return 'RED' 5 return 'YELLOW' 6 7 if current_light == 'YELLOW': 8 return current_light 9 10 return 'GREEN'the test passes.
control(current_light='GREEN' , timer_done=False) -> 'GREEN' control(current_light='GREEN' , timer_done=True ) -> 'YELLOW' control(current_light='YELLOW', timer_done=False) -> 'YELLOW' control(current_light='YELLOW', timer_done=True ) -> 'RED'I add a git commit message in the other terminal
git commit -am 'add test_yellow_light_timer_done'
test_red_light_timer_not_done
RED: make it fail
I go back to the terminal where the tests are running
I add a test with an assertion for if the Traffic Light is RED AND the timer is NOT done, to
tests/test_traffic_light.pycurrent light
timer
output
RED
NOT done
RED
37 def test_yellow_light_timer_done(self): 38 self.assertEqual( 39 src.traffic_light.control( 40 timer_done=True, 41 current_light=YELLOW, 42 ), 43 'RED' 44 ) 45 46 def test_red_light_timer_not_done(self): 47 self.assertEqual( 48 src.traffic_light.control( 49 timer_done=False, 50 current_light='RED' 51 ), 52 'RED' 53 ) 54 55 56# Exceptions seenthe terminal is my friend, and shows AssertionError
AssertionError: 'GREEN' != 'RED'
GREEN: make it pass
I add an if statement to src/traffic_light/__init__.py
7 if current_light == 'YELLOW':
8 return current_light
9 if current_light == 'RED':
10 return current_light
11
12 return 'GREEN'
the test passes.
control(current_light='GREEN' , timer_done=False) -> 'GREEN'
control(current_light='GREEN' , timer_done=True ) -> 'YELLOW'
control(current_light='YELLOW', timer_done=False) -> 'YELLOW'
control(current_light='YELLOW', timer_done=True ) -> 'RED'
control(current_light='RED' , timer_done=False) -> 'RED'
REFACTOR: make it better
I add a global variable for
'RED'totests/test_traffic_light.py1import src.traffic_light 2import unittest 3 4 5GREEN, YELLOW, RED = 'GREEN', 'YELLOW', 'RED' 6 7 8class TestTrafficLight(unittest.TestCase):I use the variable for
'RED'in test_yellow_light_timer_done37 def test_yellow_light_timer_done(self): 38 self.assertEqual( 39 src.traffic_light.control( 40 timer_done=True, 41 current_light=YELLOW, 42 ), 43 # 'RED' 44 RED 45 ) 46 47 def test_red_light_timer_not_done(self):the test is still green.
I remove the commented line from test_yellow_light_timer_done
37 def test_yellow_light_timer_done(self): 38 self.assertEqual( 39 src.traffic_light.control( 40 timer_done=True, 41 current_light=YELLOW, 42 ), 43 RED 44 ) 45 46 def test_red_light_timer_not_done(self):I use the variable for
'RED'in test_red_light_timer_not_done46 def test_red_light_timer_not_done(self): 47 self.assertEqual( 48 src.traffic_light.control( 49 timer_done=False, 50 # current_light='RED' 51 current_light=RED, 52 ), 53 # 'RED' 54 RED 55 ) 56 57 58# Exceptions seenstill green.
I remove the commented line from test_red_light_timer_not_done
46 def test_red_light_timer_not_done(self): 47 self.assertEqual( 48 src.traffic_light.control( 49 timer_done=False, 50 current_light=RED, 51 ), 52 RED 53 ) 54 55 56# Exceptions seenI add a git commit message in the other terminal
git commit -am 'add test_red_light_timer_not_done'
test_red_light_timer_done
RED: make it fail
I go back to the terminal where the tests are running
I add a test with an assertion for if the light is GREEN AND the timer is done, to
tests/test_traffic_light.pycurrent light
timer
output
RED
done
GREEN
46 def test_red_light_timer_not_done(self): 47 self.assertEqual( 48 src.traffic_light.control( 49 timer_done=False, 50 current_light=RED, 51 ), 52 RED 53 ) 54 55 def test_red_light_timer_done(self): 56 self.assertEqual( 57 src.traffic_light.control( 58 timer_done=True, 59 current_light=RED, 60 ), 61 GREEN 62 ) 63 64 65# Exceptions seenthe terminal is my friend, and shows AssertionError
AssertionError: 'YELLOW' != 'GREEN'I add an if statement for if the timer is done AND the current light is RED in
src/traffic_light/__init__.py1def control(timer_done, current_light): 2 if timer_done: 3 if current_light == 'YELLOW': 4 return 'RED' 5 if current_light == 'RED': 6 return 'GREEN' 7 return 'YELLOW' 8 9 if current_light == 'YELLOW': 10 return current_light 11 if current_light == 'RED': 12 return current_light 13 14 return 'GREEN'the test passes.
control(current_light='GREEN' , timer_done=False) -> 'GREEN' control(current_light='GREEN' , timer_done=True ) -> 'YELLOW' control(current_light='YELLOW', timer_done=False) -> 'YELLOW' control(current_light='YELLOW', timer_done=True ) -> 'RED' control(current_light='RED' , timer_done=False) -> 'RED' control(current_light='RED' , timer_done=True ) -> 'GREEN'I add a git commit message in the other terminal
git commit -am 'add test_green_light_timer_not_done'
refactor if statements
When the control function is called it checks if the timer is done
If the timer is done, it checks the color of the current light
If the current light is YELLOW, it returns RED
If the current light is RED, it returns GREEN
If none of the above conditions are met, it returns YELLOW
If none of the above conditions are met, it checks the color of the current light
If the current light is YELLOW, it returns YELLOW
If the current light is RED, it returns RED
If none of the above conditions are met, it returns GREEN
I go back to the terminal where the tests are running
I add an if statement for if the timer is done AND the light is GREEN, to make it clearer
1def control(timer_done, current_light): 2 if timer_done: 3 if current_light == 'GREEN': 4 return 'YELLOW' 5 if current_light == 'YELLOW': 6 return 'RED' 7 if current_light == 'RED': 8 return 'GREEN' 9 # return 'YELLOW'the tests are still green.
I add an if statement for if the timer is NOT done to be clearer
1def control(timer_done, current_light): 2 if timer_done: 3 if current_light == 'GREEN': 4 return 'YELLOW' 5 if current_light == 'YELLOW': 6 return 'RED' 7 if current_light == 'RED': 8 return 'GREEN' 9 # return 'YELLOW' 10 if not timer_done: 11 if current_light == 'YELLOW': 12 return current_light 13 if current_light == 'RED': 14 return current_light 15 16 return 'GREEN'still green.
I add an if statement for if the timer is NOT done and the light is GREEN, to make it clearer
10 if not timer_done: 11 if current_light == 'GREEN': 12 return current_light 13 if current_light == 'YELLOW': 14 return current_light 15 if current_light == 'RED': 16 return current_light 17 18 # return 'GREEN'The
controlfunction returns the current light in every case where the timer is NOT doneI add a return statement to return the current light if the timer is NOT done
10 if not timer_done: 11 return current_light 12 if current_light == 'GREEN': 13 return current_light 14 if current_light == 'YELLOW': 15 return current_light 16 if current_light == 'RED': 17 return current_light 18 19 # return 'GREEN'green.
I remove the commented lines and the other if statements from the else block because they are no longer used
1def control(timer_done, current_light): 2 if timer_done: 3 if current_light == 'GREEN': 4 return 'YELLOW' 5 if current_light == 'YELLOW': 6 return 'RED' 7 if current_light == 'RED': 8 return 'GREEN' 9 if not timer_done: 10 return current_lightstill green.
I move the if statement for if the timer is NOT done to the top to make the function return a value quicker before it checks the lights
1def control(timer_done, current_light): 2 if not timer_done: 3 return current_light 4 if timer_done: 5 if current_light == 'GREEN': 6 return 'YELLOW' 7 if current_light == 'YELLOW': 8 return 'RED' 9 if current_light == 'RED': 10 return 'GREEN'I add variables for
'RED','YELLOW'and'GREEN'1def control(timer_done, current_light): 2 red, yellow, green = 'RED', 'YELLOW', 'GREEN' 3 if not timer_done:I use the new variables for
'RED','YELLOW'and'GREEN'1def control(timer_done, current_light): 2 red, yellow, green = 'RED', 'YELLOW', 'GREEN' 3 if not timer_done: 4 return current_light 5 if timer_done: 6 # if current_light == 'GREEN': 7 if current_light == green: 8 # return 'YELLOW' 9 return yellow 10 # if current_light == 'YELLOW': 11 if current_light == yellow: 12 # return 'RED' 13 return red 14 # if current_light == 'RED': 15 if current_light == red: 16 # return 'GREEN' 17 return greenstill green.
I remove the commented lines from the
controlfunction1def control(timer_done, current_light): 2 red, yellow, green = 'RED', 'YELLOW', 'GREEN' 3 if not timer_done: 4 return current_light 5 if timer_done: 6 if current_light == green: 7 return yellow 8 if current_light == yellow: 9 return red 10 if current_light == red: 11 return greenI add a git commit message in the other terminal
git commit -am 'refactor if statements'
When the control function is called it checks if the timer is NOT done
If the timer is NOT done it returns the value of
current_lightcontrol(current_light='GREEN', timer_done=False) -> 'GREEN' └── def control(timer_done, current_light): ├── red, yellow, green = 'RED', 'YELLOW', 'GREEN' └── if not timer_done: └── return current_light return 'GREEN' if timer_done: if current_light == green: return yellow if current_light == yellow: return red if current_light == red: return greencontrol(current_light='YELLOW', timer_done=False) -> 'YELLOW' └── def control(timer_done, current_light): ├── red, yellow, green = 'RED', 'YELLOW', 'GREEN' └── if not timer_done: └── return current_light return 'YELLOW' if timer_done: if current_light == green: return yellow if current_light == yellow: return red if current_light == red: return greencontrol(current_light='RED', timer_done=False) -> 'RED' └── def control(timer_done, current_light): ├── red, yellow, green = 'RED', 'YELLOW', 'GREEN' └── if not timer_done: └── return current_light return 'RED' if timer_done: if current_light == green: return yellow if current_light == yellow: return red if current_light == red: return greenIf the timer is done it checks the value of
current_lightIf the current light is GREEN it returns YELLOW
control(current_light='GREEN', timer_done=True ) -> 'YELLOW' └── def control(timer_done, current_light): ├── red, yellow, green = 'RED', 'YELLOW', 'GREEN' ├── if not timer_done: │ return current_light └── if timer_done: └── if current_light == green: └── return yellow if current_light == yellow: return red if current_light == red: return greenIf the current light is YELLOW it returns RED
control(current_light='YELLOW', timer_done=True ) -> 'RED' └── def control(timer_done, current_light): ├── red, yellow, green = 'RED', 'YELLOW', 'GREEN' ├── if not timer_done: │ return current_light └── if timer_done: ├── if current_light == green: │ return yellow └── if current_light == yellow: └── return red if current_light == red: return greenIf the current light is RED it returns GREEN
control(current_light='RED', timer_done=True ) -> 'GREEN' └── def control(timer_done, current_light): ├── red, yellow, green = 'RED', 'YELLOW', 'GREEN' ├── if not timer_done: │ return current_light └── if timer_done: ├── if current_light == green: │ return yellow ├── if current_light == yellow: │ return red └── if current_light == red: └── return green
If none of the above conditions are met it returns None because ….
def control(timer_done, current_light): ├── red, yellow, green = 'RED', 'YELLOW', 'GREEN' ├── if not timer_done: │ return current_light └── if timer_done: ├── if current_light == green: │ return yellow ├── if current_light == yellow: │ return red ├── if current_light == red: │ return green
The truth table for the Traffic Light is
current light |
timer |
output |
|---|---|---|
GREEN |
NOT done |
GREEN |
GREEN |
done |
YELLOW |
YELLOW |
NOT done |
YELLOW |
YELLOW |
done |
RED |
RED |
NOT done |
RED |
RED |
done |
GREEN |
This only shows one set of lights for traffic in one direction, which is not needed if the street has no cross traffic, it is not yet a real Traffic Light.
I want the control function to show what happens in front of me (parallel) and what happens for the traffic crossing the street if the light is RED for me, it has to consider traffic in both directions
what traffic phase is this (cross, parallel or both)?
what is the light for me (parallel)?
what is the light for them (cross)?
is the timer done?
The Traffic Light has to make sure that there is never a case where cars move through the intersection at the same time to avoid accidents. The following cases must never happen
parallel |
cross |
|---|---|
GREEN |
GREEN |
GREEN |
YELLOW |
YELLOW |
YELLOW |
YELLOW |
GREEN |
The outputs will be the lights for Parallel and Cross Traffic which gives me this truth table
current |
current |
next |
next |
|
|---|---|---|---|---|
parallel |
cross |
timer |
parallel |
cross |
GREEN |
RED |
NOT done |
GREEN |
RED |
GREEN |
RED |
done |
YELLOW |
RED |
YELLOW |
RED |
NOT done |
YELLOW |
RED |
YELLOW |
RED |
done |
safety RED |
safety RED |
RED |
RED |
NOT done |
safety RED |
safety RED |
RED |
RED |
done |
RED |
GREEN |
current |
current |
next |
next |
|
|---|---|---|---|---|
parallel |
cross |
timer |
parallel |
cross |
RED |
GREEN |
NOT done |
RED |
GREEN |
RED |
GREEN |
done |
RED |
YELLOW |
RED |
YELLOW |
NOT done |
RED |
YELLOW |
RED |
YELLOW |
done |
safety RED |
safety RED |
RED |
RED |
NOT done |
safety RED |
safety RED |
RED |
RED |
done |
GREEN |
RED |
Where parallel is the light in front of me, and cross is the light for traffic crossing the street. The all RED row (Safety State) makes sure that there are no cars moving through the intersection at the same time to avoid accidents
test_cross_red_parallel_red_timer_done
RED: make it fail
I go back to the terminal where the tests are running
I add a test with an assertion for if the current parallel light is RED AND the current cross light is RED AND the timer is done
current
current
next
next
parallel
cross
timer
parallel
cross
RED
RED
done
GREEN
RED
55 def test_red_light_timer_done(self): 56 self.assertEqual( 57 src.traffic_light.control( 58 timer_done=True, 59 current_light=RED, 60 ), 61 GREEN 62 ) 63 64 def test_cross_red_parallel_red_timer_done(self): 65 self.assertEqual( 66 src.traffic_light.control( 67 current_parallel=RED, 68 current_cross=RED, 69 timer_done=True, 70 ), 71 (GREEN, RED) 72 ) 73 74 75# Exceptions seenthe terminal is my friend, and shows TypeError
TypeError: control() got an unexpected keyword argument 'current_parallel'
GREEN: make it pass
I add
current_parallelto the function definition insrc/traffic_light/__init__.py1def control(timer_done, current_light, current_parallel):the terminal is my friend, and shows TypeError
FAILED ...test_cross_red_parallel_red_timer_done - TypeError: control() got an unexpected keyword argument 'current_cross' FAILED ...test_green_light_timer_done - TypeError: control() missing 1 required positional argument: 'current_parallel' FAILED ...test_green_light_timer_not_done - TypeError: control() missing 1 required positional argument: 'current_parallel' FAILED ...test_red_light_timer_done - ypeError: control() missing 1 required positional argument: 'current_parallel' FAILED ...test_red_light_timer_not_done - TypeError: control() missing 1 required positional argument: 'current_parallel' FAILED ...test_yellow_light_timer_done - TypeError: control() missing 1 required positional argument: 'current_parallel' FAILED ...test_yellow_light_timer_not_done - TypeError: control() missing 1 required positional argument: 'current_parallel'I add a default value for the
current_parallelparameter1def control( 2 timer_done, current_light, 3 current_parallel='RED', 4 ):the terminal is my friend, and shows TypeError
TypeError: control() got an unexpected keyword argument 'current_cross'I add
current_crossto the function definition1def control( 2 timer_done, current_light, 3 current_parallel='RED', current_cross='RED', 4 ):the terminal is my friend, and shows TypeError
TypeError: control() missing 1 required positional argument: 'current_light'I add a default value for
current_lightto the function signature1def control( 2 timer_done, current_light='RED, 3 current_parallel='RED', current_cross='RED', 4 ):the terminal is my friend, and shows AssertionError
AssertionError: 'GREEN' != ('GREEN', 'RED')I add an if statement to
if timer_done:for if the current parallel light is RED AND the current cross light is RED8 if timer_done: 9 if current_light == green: 10 return yellow 11 if current_light == yellow: 12 return red 13 if current_light == red: 14 return green 15 if current_parallel == red and current_cross == red: 16 return green, redthe terminal still shows AssertionError because the function returns RED if the timer is done AND
current_lightis RED and the default value forcurrent_lightin this assertion is RED.I change the default value for
current_lightto None1def control( 2 timer_done, current_light=None, 3 current_parallel='RED', current_cross='RED', 4 ):the test passes.
control( current_parallel='RED' , current_cross='RED', timer_done=True ) -> 'GREEN', 'RED'I add a git commit message in the other terminal
git commit -am 'add test_cross_red_parallel_red_timer_done'
test_cross_red_parallel_red_timer_not_done
RED: make it fail
I go back to the terminal where the tests are running
I add a test with an assertion for if the current parallel light is RED AND the current cross light is RED AND the timer is NOT done
current
current
next
next
parallel
cross
timer
parallel
cross
RED
RED
NOT done
safety RED
safety RED
55 def test_red_light_timer_done(self): 56 self.assertEqual( 57 src.traffic_light.control( 58 timer_done=True, 59 current_light=RED, 60 ), 61 GREEN 62 ) 63 64 def test_cross_red_parallel_red_timer_not_done(self): 65 self.assertEqual( 66 src.traffic_light.control( 67 current_parallel=RED, 68 current_cross=RED, 69 timer_done=False, 70 ), 71 (RED, RED) 72 ) 73 74 def test_cross_red_parallel_red_timer_done(self):the terminal is my friend, and shows AssertionError
AssertionError: None != ('RED', 'RED')
GREEN: make it pass
I add an if statement for if the current parallel light is RED AND the current cross light is RED to
if not timer_done:insrc/traffic_light/__init__.py6 if not timer_done: 7 if current_parallel == red and current_cross == red: 8 return red, red 9 return current_light 10 if timer_done:the terminal is my friend, and shows AssertionError
FAILED ...test_green_light_timer_not_done - AssertionError: ('RED', 'RED') != 'GREEN' FAILED ...test_red_light_timer_not_done - AssertionError: ('RED', 'RED') != 'RED' FAILED ...test_yellow_light_timer_not_done - AssertionError: ('RED', 'RED') != 'YELLOW'because those assertions use the default values for
current_parallelandcross_parallelI add an if statements for if the timer is NOT done and the
current_lightis grouped as True6 if not timer_done: 7 if current_light: 8 return current_light 9 if current_parallel == red and current_cross == red: 10 return red, red 11 # return current_light 12 if timer_done:the test passes.
control( current_parallel='RED' , current_cross='RED', timer_done=False ) -> 'RED', 'RED' control( current_parallel='RED' , current_cross='RED', timer_done=True ) -> 'GREEN', 'RED'I remove the commented line
6 if not timer_done: 7 if current_light: 8 return current_light 9 if current_parallel == red and current_cross == red: 10 return red, red 11 12 if timer_done:I add a git commit message in the other terminal
git commit -am 'add test_cross_red_parallel_red_timer_not_done'
test_cross_yellow_parallel_red_timer_done
RED: make it fail
I go back to the terminal where the tests are running
I add a test with an assertion for if the current parallel light is RED AND the current cross light is YELLOW AND the timer is done
current
current
next
next
parallel
cross
timer
parallel
cross
RED
YELLOW
done
RED
RED
55 def test_red_light_timer_done(self): 56 self.assertEqual( 57 src.traffic_light.control( 58 timer_done=True, 59 current_light=RED, 60 ), 61 GREEN 62 ) 63 64 def test_cross_yellow_parallel_red_timer_done(self): 65 self.assertEqual( 66 src.traffic_light.control( 67 current_parallel=RED, 68 current_cross=YELLOW, 69 timer_done=True, 70 ), 71 (RED, RED) 72 ) 73 74 def test_cross_red_parallel_red_timer_not_done(self):the terminal is my friend, and shows AssertionError
AssertionError: None != ('RED', 'RED')
GREEN: make it pass
I add an if statement for if the current parallel light is RED AND the current cross light is YELLOW to if timer_done: in src/traffic_light/__init__.py
12 if timer_done:
13 if current_light == green:
14 return yellow
15 if current_light == yellow:
16 return red
17 if current_light == red:
18 return green
19 if current_parallel == red and current_cross == yellow:
20 return red, red
21 if current_parallel == red and current_cross == red:
22 return green, red
the test passes.
control(
current_parallel='RED' , current_cross='YELLOW',
timer_done=True
) -> 'RED', 'RED'
control(
current_parallel='RED' , current_cross='RED',
timer_done=False
) -> 'RED', 'RED'
control(
current_parallel='RED' , current_cross='RED',
timer_done=True
) -> 'GREEN', 'RED'
REFACTOR: make it better
Two of the if statements in
if timer_done:are for if the current parallel light is RED. I change them to remove repetition ofif current_parallel == red12 if timer_done: 13 if current_light == green: 14 return yellow 15 if current_light == yellow: 16 return red 17 if current_light == red: 18 return green 19 # if current_parallel == red and current_cross == yellow: 20 # return red, red 21 # if current_parallel == red and current_cross == red: 22 # return green, red 23 if current_parallel == red: 24 if current_cross == yellow: 25 return red, red 26 if current_cross == red: 27 return green, redthe tests are still green.
I remove the commented lines
12 if timer_done: 13 if current_light == green: 14 return yellow 15 if current_light == yellow: 16 return red 17 if current_light == red: 18 return green 19 20 if current_parallel == red: 21 if current_cross == yellow: 22 return red, red 23 if current_cross == red: 24 return green, redI add a git commit message in the other terminal
git commit -am 'add test_cross_yellow_parallel_red_timer_done'
test_cross_yellow_parallel_red_timer_not_done
RED: make it fail
I go back to the terminal where the tests are running
I add a test with an assertion for if the current parallel light is RED AND the current cross light is YELLOW AND the timer is NOT done
current
current
next
next
parallel
cross
timer
parallel
cross
RED
YELLOW
NOT done
RED
YELLOW
55 def test_red_light_timer_done(self): 56 self.assertEqual( 57 src.traffic_light.control( 58 timer_done=True, 59 current_light=RED, 60 ), 61 GREEN 62 ) 63 64 def test_cross_yellow_parallel_red_timer_not_done(self): 65 self.assertEqual( 66 src.traffic_light.control( 67 current_parallel=RED, 68 current_cross=YELLOW, 69 timer_done=False, 70 ), 71 (RED, YELLOW) 72 ) 73 74 def test_cross_yellow_parallel_red_timer_done(self):the terminal is my friend, and shows AssertionError
AssertionError: None != ('RED', 'YELLOW')
GREEN: make it pass
I add an if statement for if the current parallel light is RED AND the current cross light is YELLOW to if not timer_done: in src/traffic_light/__init__.py
6 if not timer_done:
7 if current_light:
8 return current_light
9 if current_parallel == red and current_cross == yellow:
10 return red, yellow
11 if current_parallel == red and current_cross == red:
12 return red, red
13
14 if timer_done:
the test passes.
control(
current_parallel='RED' , current_cross='YELLOW',
timer_done=False
) -> 'RED', 'YELLOW'
control(
current_parallel='RED' , current_cross='YELLOW',
timer_done=True
) -> 'RED', 'RED'
control(
current_parallel='RED' , current_cross='RED',
timer_done=False
) -> 'RED', 'RED'
control(
current_parallel='RED' , current_cross='RED',
timer_done=True
) -> 'GREEN', 'RED'
REFACTOR: make it better
Two of the if statements in
if not timer_done:are also for if the current parallel light is RED. I change them to remove repetition ofif current_parallel == red6 if not timer_done: 7 if current_light: 8 return current_light 9 # if current_parallel == red and current_cross == yellow: 10 # return red, yellow 11 # if current_parallel == red and current_cross == red: 12 # return red, red 13 if current_parallel == red: 14 if current_cross == yellow: 15 return red, yellow 16 if current_cross == red: 17 return red, red 18 19 if timer_done:the tests are still green.
I remove the commented lines
6 if not timer_done: 7 if current_light: 8 return current_light 9 10 if current_parallel == red: 11 if current_cross == yellow: 12 return red, yellow 13 if current_cross == red: 14 return red, red 15 16 if timer_done:I add a git commit message in the other terminal
git commit -am 'add test_cross_yellow_parallel_red_timer_not_done'
test_cross_green_parallel_red_timer_done
RED: make it fail
I go back to the terminal where the tests are running
I add a test with an assertion for if the current parallel light is RED AND the current cross light is GREEN AND the timer is done
current
current
next
next
parallel
cross
timer
parallel
cross
RED
GREEN
done
RED
YELLOW
55 def test_red_light_timer_done(self): 56 self.assertEqual( 57 src.traffic_light.control( 58 timer_done=True, 59 current_light=RED, 60 ), 61 GREEN 62 ) 63 64 def test_cross_green_parallel_red_timer_done(self): 65 self.assertEqual( 66 src.traffic_light.control( 67 current_parallel=RED, 68 current_cross=GREEN, 69 timer_done=True, 70 ), 71 (RED, YELLOW) 72 ) 73 74 def test_cross_yellow_parallel_red_timer_not_done(self):the terminal is my friend, and shows AssertionError
AssertionError: None != ('RED', 'YELLOW')
GREEN: make it pass
I add an if statement for if the current parallel light is RED AND the current cross light is GREEN to if timer_done: in src/traffic_light/__init__.py
16 if timer_done:
17 if current_light == green:
18 return yellow
19 if current_light == yellow:
20 return red
21 if current_light == red:
22 return green
23
24 if current_parallel == red:
25 if current_cross == green:
26 return red, yellow
27 if current_cross == yellow:
28 return red, red
29 if current_cross == red:
30 return green, red
the test passes.
control(
current_parallel='RED' , current_cross='GREEN',
timer_done=True
) -> 'RED', 'YELLOW'
control(
current_parallel='RED' , current_cross='YELLOW',
timer_done=False
) -> 'RED', 'YELLOW'
control(
current_parallel='RED' , current_cross='YELLOW',
timer_done=True
) -> 'RED', 'RED'
control(
current_parallel='RED' , current_cross='RED',
timer_done=False
) -> 'RED', 'RED'
control(
current_parallel='RED' , current_cross='RED',
timer_done=True
) -> 'GREEN', 'RED'
test_cross_green_parallel_red_timer_not_done
RED: make it fail
I go back to the terminal where the tests are running
I add a test with an assertion for if the current parallel light is RED AND the current cross light is GREEN AND the timer is NOT done
current
current
next
next
parallel
cross
timer
parallel
cross
RED
GREEN
NOT done
RED
GREEN
55 def test_red_light_timer_done(self): 56 self.assertEqual( 57 src.traffic_light.control( 58 timer_done=True, 59 current_light=RED, 60 ), 61 GREEN 62 ) 63 64 def test_cross_green_parallel_red_timer_not_done(self): 65 self.assertEqual( 66 src.traffic_light.control( 67 current_parallel=RED, 68 current_cross=GREEN, 69 timer_done=False, 70 ), 71 (RED, GREEN) 72 ) 73 74 def test_cross_green_parallel_red_timer_done(self):the terminal is my friend, and shows AssertionError
AssertionError: None != ('RED', 'GREEN')
GREEN: make it pass
I add an if statement for if the current parallel light is RED AND the current cross light is GREEN to if not timer_done: in src/traffic_light/__init__.py
6 if not timer_done:
7 if current_light:
8 return current_light
9
10 if current_parallel == red:
11 if current_cross == green:
12 return red, green
13 if current_cross == yellow:
14 return red, yellow
15 if current_cross == red:
16 return red, red
17
18 if timer_done:
the test passes.
control(
current_parallel='RED' , current_cross='GREEN',
timer_done=False
) -> 'RED', 'GREEN'
control(
current_parallel='RED' , current_cross='GREEN',
timer_done=True
) -> 'RED', 'YELLOW'
control(
current_parallel='RED' , current_cross='YELLOW',
timer_done=False
) -> 'RED', 'YELLOW'
control(
current_parallel='RED' , current_cross='YELLOW',
timer_done=True
) -> 'RED', 'RED'
control(
current_parallel='RED' , current_cross='RED',
timer_done=False
) -> 'RED', 'RED'
control(
current_parallel='RED' , current_cross='RED',
timer_done=True
) -> 'GREEN', 'RED'
REFACTOR: make it better
The three if statements in
if not timer_done:for if the current parallel light is RED all return the current parallel light and the current cross light. I write one return statement for all of them6 if not timer_done: 7 if current_light: 8 return current_light 9 10 if current_parallel == red: 11 return current_parallel, current_cross 12 if current_cross == green: 13 return red, green 14 if current_cross == yellow: 15 return red, yellow 16 if current_cross == red: 17 return red, red 18 19 if timer_done:the tests are still green.
I remove the if statements for the other cases since they are no longer used
6 if not timer_done: 7 if current_light: 8 return current_light 9 10 if current_parallel == red: 11 return current_parallel, current_cross 12 13 if timer_done:still green.
I add a git commit message in the other terminal
git commit -am 'add test_cross_green_parallel_red_timer_not_done'
test_parallel_red_cross_red_timer_done
RED: make it fail
I go back to the terminal where the tests are running
I change the assertion in test_red_light_timer_done for if the current parallel light is RED AND the current cross light is RED AND the timer is done
current
current
next
next
parallel
cross
timer
parallel
cross
RED
RED
done
RED
GREEN
55 def test_red_light_timer_done(self): 56 self.assertEqual( 57 src.traffic_light.control( 58 current_parallel=RED, 59 current_cross=RED, 60 timer_done=True, 61 # current_light=RED, 62 ), 63 # GREEN 64 (RED, GREEN) 65 ) 66 67 def test_cross_green_parallel_red_timer_not_done(self):the terminal is my friend, and shows AssertionError
AssertionError: Tuples differ: ('GREEN', 'RED') != ('RED', 'GREEN')because the
controlfunction cannot tell the difference betweenif the current parallel light is RED AND the cross light is RED AND the timer is done which returns the next parallel light as GREEN and the next cross light as RED, and
if the current parallel light is RED AND the cross light is RED AND the timer is done which returns the next parallel light as RED and the next cross light as GREEN
the current lights are the same in both cases but the output is different
current
current
next
next
parallel
cross
timer
parallel
cross
RED
RED
done
GREEN
RED
RED
RED
done
RED
GREEN
I need a way for the function to know the difference. When I look at the overall table I see that the phases that come right before these two states are the safety state which is also the same for both
current
current
next
next
parallel
cross
timer
parallel
cross
RED
RED
NOT done
safety RED
safety RED
RED
RED
done
GREEN
RED
RED
RED
NOT done
safety RED
safety RED
RED
RED
done
RED
GREEN
The difference between them is in the phase before the safety phase
current
current
next
next
parallel
cross
timer
parallel
cross
YELLOW
RED
done
RED
RED
RED
RED
NOT done
safety RED
safety RED
RED
RED
done
GREEN
RED
current
current
next
next
parallel
cross
timer
parallel
cross
RED
YELLOW
done
RED
RED
RED
RED
NOT done
safety RED
safety RED
RED
RED
done
RED
GREEN
The
controlfunction needs to know that it is a sequence based on whether the parallel or cross traffic is in a RED stateif it is in the RED state for cross traffic AND the current parallel light is RED AND the cross light is RED AND the timer is done it should keep the parallel light RED and turn the next cross light GREEN
if it is in the RED state for parallel traffic AND the current parallel light is RED AND the cross light is RED AND the timer is done it should turn the next parallel light GREEN and keep the next cross light RED
GREEN: make it pass
I add
red_phaseto the callcontrolfunction in the assertion in test_red_light_timer_done55 def test_red_light_timer_done(self): 56 self.assertEqual( 57 src.traffic_light.control( 58 red_phase='cross', 59 current_parallel=RED, 60 current_cross=RED, 61 timer_done=True, 62 # current_light=RED, 63 ), 64 # GREEN 65 (RED, GREEN) 66 ) 67 68 def test_cross_green_parallel_red_timer_not_done(self):the terminal is my friend, and shows TypeError
TypeError: control() got an unexpected keyword argument 'red_phase'I add
red_phasewith a default value for the other tests, to the function definition insrc/traffic_light/__init__.py1def control( 2 timer_done, current_light=None, 3 current_parallel='RED', current_cross='RED', 4 red_phase='parallel', 5 ):the terminal still shows AssertionError
I add an if statement to
if timer_done:for if the Traffic Light is currently in the RED phase for cross traffic AND the current parallel light is RED AND the current cross light is RED14 if timer_done: 15 if current_light == green: 16 return yellow 17 if current_light == yellow: 18 return red 19 if current_light == red: 20 return green 21 22 if red_phase == 'cross': 23 if current_parallel == red and current_cross == red: 24 return red, green 25 26 if current_parallel == red:the test passes.
control( current_parallel='RED' , current_cross='RED', timer_done=True, red_phase='cross' ) -> 'RED', 'GREEN'
REFACTOR: make it better
I remove the commented lines from test_red_light_timer_done in
tests/test_traffic_light.py55 def test_red_light_timer_done(self): 56 self.assertEqual( 57 src.traffic_light.control( 58 red_phase='cross', 59 current_parallel=RED, 60 current_cross=RED, 61 timer_done=True, 62 ), 63 (RED, GREEN) 64 ) 65 66 def test_cross_green_parallel_red_timer_not_done(self):I change the name of the test from test_red_light_timer_done to test_parallel_red_cross_red_timer_done
46 def test_red_light_timer_not_done(self): 47 self.assertEqual( 48 src.traffic_light.control( 49 timer_done=False, 50 current_light=RED, 51 ), 52 RED 53 ) 54 55 def test_parallel_red_cross_red_timer_done(self): 56 self.assertEqual( 57 src.traffic_light.control( 58 red_phase='cross', 59 current_parallel=RED, 60 current_cross=RED, 61 timer_done=True, 62 ), 63 (RED, GREEN) 64 ) 65 66 def test_cross_green_parallel_red_timer_not_done(self):I add a git commit message in the other terminal
git commit -am 'add test_parallel_red_cross_red_timer_done'
test_parallel_red_cross_red_timer_not_done
RED: make it fail
I go back to the terminal where the tests are running
I add values for
current_parallel,current_crossandred_phaseto the assertion in test_red_light_timer_not_done for if'cross'traffic is in the RED phase AND the current parallel light is RED AND the current cross light is RED AND the timer is NOT donered
current
current
next
next
phase
parallel
cross
timer
parallel
cross
‘cross’
RED
RED
NOT done
safety RED
safety RED
46 def test_red_light_timer_not_done(self): 47 self.assertEqual( 48 src.traffic_light.control( 49 red_phase='cross', 50 current_parallel=RED, 51 current_cross=RED, 52 timer_done=False, 53 # current_light=RED, 54 ), 55 # RED 56 (RED, RED) 57 ) 58 59 def test_parallel_red_cross_red_timer_done(self):the test is still green.
control( current_parallel='RED' , current_cross='RED', timer_done=False, red_phase='cross' ) -> 'RED', 'RED' control( current_parallel='RED' , current_cross='RED', timer_done=True, red_phase='cross' ) -> 'RED', 'GREEN'
GREEN: make it pass
I remove the commented lines from test_red_light_timer_not_done
46 def test_red_light_timer_not_done(self): 47 self.assertEqual( 48 src.traffic_light.control( 49 red_phase='cross', 50 current_parallel=RED, 51 current_cross=RED, 52 timer_done=False, 53 ), 54 (RED, RED) 55 ) 56 57 def test_parallel_red_cross_red_timer_done(self):I change the name of the test from test_red_light_timer_not_done to test_parallel_red_cross_red_timer_not_done
37 def test_yellow_light_timer_done(self): 38 self.assertEqual( 39 src.traffic_light.control( 40 timer_done=True, 41 current_light=YELLOW, 42 ), 43 RED 44 ) 45 46 def test_parallel_red_cross_red_timer_not_done(self): 47 self.assertEqual( 48 src.traffic_light.control( 49 red_phase='cross', 50 current_parallel=RED, 51 current_cross=RED, 52 timer_done=False, 53 ), 54 (RED, RED) 55 ) 56 57 def test_parallel_red_cross_red_timer_done(self):I add a git commit message in the other terminal
git commit -am 'add test_parallel_red_cross_red_timer_not_done'
test_parallel_yellow_cross_red_timer_done
RED: make it fail
I go back to the terminal where the tests are running
I add values for
current_parallel,current_crossandred_phaseto the assertion in test_yellow_light_timer_done for if'cross'traffic is in the RED phase AND the current parallel light is YELLOW AND the current cross light is RED AND the timer is donered
current
current
next
next
phase
parallel
cross
timer
parallel
cross
‘cross’
YELLOW
RED
done
RED
RED
37 def test_yellow_light_timer_done(self): 38 self.assertEqual( 39 src.traffic_light.control( 40 red_phase='cross', 41 current_parallel=YELLOW, 42 current_cross=RED, 43 timer_done=True, 44 # current_light=YELLOW, 45 ), 46 # RED 47 (RED, RED) 48 ) 49 50 def test_parallel_red_cross_red_timer_not_done(self):the terminal is my friend, and shows AssertionError
AssertionError: None != ('RED', 'RED')
GREEN: make it pass
I add an if statement for if the current parallel light is YELLOW AND the current cross light is RED to if timer_done: in src/traffic_light/__init__.py
14 if timer_done:
15 if current_light == green:
16 return yellow
17 if current_light == yellow:
18 return red
19 if current_light == red:
20 return green
21
22 if red_phase == 'cross':
23 if current_parallel == red and current_cross == red:
24 return red, green
25
26 if current_parallel == yellow and current_cross == red:
27 return red, red
28
29 if current_parallel == red:
the test passes.
control(
current_parallel='YELLOW' , current_cross='RED',
timer_done=True, red_phase='cross'
) -> 'RED', 'RED'
control(
current_parallel='RED' , current_cross='RED',
timer_done=False, red_phase='cross'
) -> 'RED', 'RED'
control(
current_parallel='RED' , current_cross='RED',
timer_done=True, red_phase='cross'
) -> 'RED', 'GREEN'
REFACTOR: make it better
Two of the if statements in
if timer_done:are for if the current cross light is RED which is whencrosstraffic is in the RED phase. I change them to remove repetition ofif current_cross == red14 if timer_done: 15 if current_light == green: 16 return yellow 17 if current_light == yellow: 18 return red 19 if current_light == red: 20 return green 21 22 if red_phase == 'cross': 23 # if current_parallel == red and current_cross == red: 24 # return red, green 25 26 # if current_parallel == yellow and current_cross == red: 27 # return red, red 28 if current_parallel == yellow: 29 return red, red 30 if current_parallel == red: 31 return red, green 32 33 if current_parallel == red:the tests are still green.
I remove the commented lines
14 if timer_done: 15 if current_light == green: 16 return yellow 17 if current_light == yellow: 18 return red 19 if current_light == red: 20 return green 21 22 if red_phase == 'cross': 23 if current_parallel == yellow: 24 return red, red 25 if current_parallel == red: 26 return red, green 27 28 if current_parallel == red:I remove the commented lines from test_yellow_light_timer_done
37 def test_yellow_light_timer_done(self): 38 self.assertEqual( 39 src.traffic_light.control( 40 red_phase='cross', 41 current_parallel=YELLOW, 42 current_cross=RED, 43 timer_done=True, 44 ), 45 (RED, RED) 46 ) 47 48 def test_parallel_red_cross_red_timer_not_done(self):I change the name of the test from test_yellow_light_timer_done to test_parallel_yellow_cross_red_timer_done
28 def test_yellow_light_timer_not_done(self): 29 self.assertEqual( 30 src.traffic_light.control( 31 timer_done=False, 32 current_light=YELLOW, 33 ), 34 YELLOW 35 ) 36 37 def test_parallel_yellow_cross_red_timer_done(self): 38 self.assertEqual( 39 src.traffic_light.control( 40 red_phase='cross', 41 current_parallel=YELLOW, 42 current_cross=RED, 43 timer_done=True, 44 ), 45 (RED, RED) 46 ) 47 48 def test_parallel_red_cross_red_timer_not_done(self):I add a git commit message in the other terminal
git commit -am 'add test_parallel_yellow_cross_red_timer_done'
test_parallel_yellow_cross_red_timer_not_done
RED: make it fail
I go back to the terminal where the tests are running
I add values for
current_parallel,current_crossandred_phaseto the assertion in test_yellow_light_timer_not_done for if'cross'traffic is in the RED phase AND the current parallel light is YELLOW AND the current cross light is RED AND the timer is NOT donered
current
current
next
next
phase
parallel
cross
timer
parallel
cross
‘cross’
YELLOW
RED
NOT done
YELLOW
RED
28 def test_yellow_light_timer_not_done(self): 29 self.assertEqual( 30 src.traffic_light.control( 31 red_phase='cross', 32 current_parallel=YELLOW, 33 current_cross=RED, 34 timer_done=False, 35 # current_light=YELLOW, 36 ), 37 # YELLOW 38 (YELLOW, RED) 39 ) 40 41 def test_parallel_yellow_cross_red_timer_done(self):the terminal is my friend, and shows AssertionError
AssertionError: None != ('YELLOW', 'RED')
GREEN: make it pass
I add an if statement for if the current parallel light is YELLOW AND the current cross light is RED to if not timer_done: in src/traffic_light/__init__.py
7 if not timer_done:
8 if current_light:
9 return current_light
10
11 if current_parallel == yellow and current_cross == red:
12 return yellow, red
13 if current_parallel == red:
14 return current_parallel, current_cross
15
16 if timer_done:
the test passes.
control(
current_parallel='YELLOW' , current_cross='RED',
timer_done=False, red_phase='cross'
) -> 'YELLOW', 'RED'
control(
current_parallel='YELLOW' , current_cross='RED',
timer_done=True, red_phase='cross'
) -> 'RED', 'RED'
control(
current_parallel='RED' , current_cross='RED',
timer_done=False, red_phase='cross'
) -> 'RED', 'RED'
control(
current_parallel='RED' , current_cross='RED',
timer_done=True, red_phase='cross'
) -> 'RED', 'GREEN'
REFACTOR: make it better
I remove the commented lines from test_yellow_light_timer_not_done in
tests/test_traffic_light.py28 def test_yellow_light_timer_not_done(self): 29 self.assertEqual( 30 src.traffic_light.control( 31 red_phase='cross', 32 current_parallel=YELLOW, 33 current_cross=RED, 34 timer_done=False, 35 ), 36 (YELLOW, RED) 37 ) 38 39 def test_parallel_yellow_cross_red_timer_done(self):I change the name of the test from test_yellow_light_timer_not_done to test_parallel_yellow_cross_red_timer_not_done
19 def test_green_light_timer_done(self): 20 self.assertEqual( 21 src.traffic_light.control( 22 timer_done=True, 23 current_light=GREEN, 24 ), 25 YELLOW 26 ) 27 28 def test_parallel_yellow_cross_red_timer_not_done(self): 29 self.assertEqual( 30 src.traffic_light.control( 31 red_phase='cross', 32 current_parallel=YELLOW, 33 current_cross=RED, 34 timer_done=False, 35 ), 36 (YELLOW, RED) 37 ) 38 39 def test_parallel_yellow_cross_red_timer_done(self):I add a git commit message in the other terminal
git commit -am 'add test_parallel_yellow_cross_red_timer_not_done'
test_parallel_green_cross_red_timer_done
I go back to the terminal where the tests are running
I add values for
current_parallel,current_crossandred_phaseto the assertion in test_green_light_timer_done for if'cross'traffic is in the RED phase AND the current parallel light is GREEN AND the current cross light is RED AND the timer is donered
current
current
next
next
phase
parallel
cross
timer
parallel
cross
‘cross’
GREEN
RED
done
YELLOW
RED
19 def test_green_light_timer_done(self): 20 self.assertEqual( 21 src.traffic_light.control( 22 red_phase='cross', 23 current_parallel=GREEN, 24 current_cross=RED, 25 timer_done=True, 26 # current_light=GREEN, 27 ), 28 # YELLOW 29 (YELLOW, RED) 30 ) 31 32 def test_parallel_yellow_cross_red_timer_not_done(self):the test is still green.
control( current_parallel='GREEN' , current_cross='RED', timer_done=True, red_phase='cross' ) -> 'YELLOW', 'RED' control( current_parallel='YELLOW' , current_cross='RED', timer_done=False, red_phase='cross' ) -> 'YELLOW', 'RED' control( current_parallel='YELLOW' , current_cross='RED', timer_done=True, red_phase='cross' ) -> 'RED', 'RED' control( current_parallel='RED' , current_cross='RED', timer_done=False, red_phase='cross' ) -> 'RED', 'RED' control( current_parallel='RED' , current_cross='RED', timer_done=True, red_phase='cross' ) -> 'RED', 'GREEN'I remove the commented lines from test_green_light_timer_done
19 def test_green_light_timer_done(self): 20 self.assertEqual( 21 src.traffic_light.control( 22 red_phase='cross', 23 current_parallel=GREEN, 24 current_cross=RED, 25 timer_done=True, 26 ), 27 (YELLOW, RED) 28 ) 29 30 def test_parallel_yellow_cross_red_timer_not_done(self):I change the name of the test from test_green_light_timer_done to test_parallel_green_cross_red_timer_done
10 def test_green_light_timer_not_done(self): 11 self.assertEqual( 12 src.traffic_light.control( 13 timer_done=False, 14 current_light=GREEN, 15 ), 16 GREEN 17 ) 18 19 def test_parallel_green_cross_red_timer_done(self): 20 self.assertEqual( 21 src.traffic_light.control( 22 red_phase='cross', 23 current_parallel=GREEN, 24 current_cross=RED, 25 timer_done=True, 26 ), 27 (YELLOW, RED) 28 ) 29 30 def test_parallel_yellow_cross_red_timer_not_done(self):I add a git commit message in the other terminal
git commit -am 'add test_parallel_green_cross_red_timer_done'
test_parallel_green_cross_red_timer_not_done
RED: make it fail
I go back to the terminal where the tests are running
I add values for
current_parallel,current_crossandred_phaseto the assertion in test_green_light_timer_not_done for if'cross'traffic is in the RED phase AND the current parallel light is GREEN AND the current cross light is RED AND the timer is NOT donered
current
current
next
next
phase
parallel
cross
timer
parallel
cross
‘cross’
GREEN
RED
NOT done
GREEN
RED
10 def test_green_light_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 # current_light=GREEN, 18 ), 19 # GREEN 20 (GREEN, RED) 21 ) 22 23 def test_parallel_green_cross_red_timer_done(self):the terminal is my friend, and shows AssertionError
AssertionError: None != ('GREEN', 'RED')
GREEN: make it pass
I add an if statement for if the current parallel light is GREEN AND the current cross light is RED to if not timer_done: in src/traffic_light/__init__.py
7 if not timer_done:
8 if current_light:
9 return current_light
10
11 if current_parallel == green and current_cross == red:
12 return green, red
13 if current_parallel == yellow and current_cross == red:
14 return yellow, red
15 if current_parallel == red:
16 return current_parallel, current_cross
17
18 if timer_done:
the test passes.
control(
current_parallel='GREEN' , current_cross='RED',
timer_done=False, red_phase='cross'
) -> 'GREEN', 'RED'
control(
current_parallel='GREEN' , current_cross='RED',
timer_done=True, red_phase='cross'
) -> 'YELLOW', 'RED'
control(
current_parallel='YELLOW' , current_cross='RED',
timer_done=False, red_phase='cross'
) -> 'YELLOW', 'RED'
control(
current_parallel='YELLOW' , current_cross='RED',
timer_done=True, red_phase='cross'
) -> 'RED', 'RED'
control(
current_parallel='RED' , current_cross='RED',
timer_done=False, red_phase='cross'
) -> 'RED', 'RED'
control(
current_parallel='RED' , current_cross='RED',
timer_done=True, red_phase='cross'
) -> 'RED', 'GREEN'
REFACTOR: make it better
I remove the commented lines from test_green_light_timer_not_done
10 def test_green_light_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):I change the name of the test from test_green_light_timer_not_done to test_parallel_green_cross_red_timer_not_done
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 )I remove the if statements for the
current_lightparameter since they are no longer used, insrc/traffic_light/__init__.py7 if not timer_done: 8 if current_parallel == green and current_cross == red: 9 return green, red 10 if current_parallel == yellow and current_cross == red: 11 return yellow, red 12 if current_parallel == red: 13 return current_parallel, current_cross 14 15 if timer_done: 16 if red_phase == 'cross': 17 if current_parallel == green: 18 return yellow, red 19 if current_parallel == yellow: 20 return red, red 21 if current_parallel == red: 22 return red, green 23 if current_parallel == red: 24 if current_cross == green: 25 return red, yellow 26 if current_cross == yellow: 27 return red, red 28 if current_cross == red: 29 return green, redthe tests are still green.
I remove the
current_lightparameter from the parentheses of the function definition1def control( 2 timer_done, red_phase='parallel', 3 current_parallel='RED', current_cross='RED', 4 ): 5 red, yellow, green = 'RED', 'YELLOW', 'GREEN' 6 if not timer_done:The three if statements in
if not timer_done:all return the current parallel light and the current cross light. I write one return statement for all of them6 if not timer_done: 7 return current_parallel, current_cross 8 if current_parallel == green and current_cross == red: 9 return green, red 10 if current_parallel == yellow and current_cross == red: 11 return yellow, red 12 if current_parallel == red: 13 return current_parallel, current_cross 14 15 if timer_done:the tests are still green.
I change
if current_parallel == redtoif red_phase == 'parallel':for if the timer is done AND the current parallel light is RED since it is for whenparalleltraffic is in the RED phase15 if timer_done: 16 if red_phase == 'cross': 17 if current_parallel == green: 18 return yellow, red 19 if current_parallel == yellow: 20 return red, red 21 if current_parallel == red: 22 return red, green 23 # if current_parallel == red: 24 if red_phase == 'parallel': 25 if current_cross == green: 26 return red, yellow 27 if current_cross == yellow: 28 return red, red 29 if current_cross == red: 30 return green, redgreen.
I remove the if statements from
if not timer_done:and the commented line since they are no longer used1def control( 2 timer_done, red_phase='parallel', 3 current_parallel='RED', current_cross='RED', 4 ): 5 red, yellow, green = 'RED', 'YELLOW', 'GREEN' 6 7 if not timer_done: 8 return current_parallel, current_cross 9 10 if timer_done: 11 if red_phase == 'cross': 12 if current_parallel == green: 13 return yellow, red 14 if current_parallel == yellow: 15 return red, red 16 if current_parallel == red: 17 return red, green 18 if red_phase == 'parallel': 19 if current_cross == green: 20 return red, yellow 21 if current_cross == yellow: 22 return red, red 23 if current_cross == red: 24 return green, redI add a git commit message in the other terminal
git commit -am \ 'add test_parallel_green_cross_red_timer_not_done'
When the control function is called it checks if the timer is NOT done
If the timer is NOT done, it returns the values of
current_parallelandcurrent_cross, which means it does not change the parallel or cross lights, it keeps them the samecontrol( current_parallel='RED', current_cross='GREEN', timer_done=False, red_phase='parallel' ) -> 'RED', 'GREEN' └── def control( timer_done, red_phase='parallel', current_parallel='RED', current_cross='RED', ): ├── red, yellow, green = 'RED', 'YELLOW', 'GREEN' └── if not timer_done: └── return current_parallel, current_cross return 'RED' , 'GREEN' if timer_done:control( current_parallel='RED', current_cross='YELLOW', timer_done=False, red_phase='parallel' ) -> 'RED', 'YELLOW' └── def control( timer_done, red_phase='parallel', current_parallel='RED', current_cross='RED', ): ├── red, yellow, green = 'RED', 'YELLOW', 'GREEN' └── if not timer_done: └── return current_parallel, current_cross return 'RED' , 'YELLOW' if timer_done:control( current_parallel='RED', current_cross='RED', timer_done=False, red_phase='parallel' ) -> 'RED', 'RED' └── def control( timer_done, red_phase='parallel', current_parallel='RED', current_cross='RED', ): ├── red, yellow, green = 'RED', 'YELLOW', 'GREEN' └── if not timer_done: └── return current_parallel, current_cross return 'RED' , 'RED' if timer_done:control( current_parallel='GREEN', current_cross='RED', timer_done=False, red_phase='cross' ) -> 'GREEN', 'RED' └── def control( timer_done, red_phase='parallel', current_parallel='RED', current_cross='RED', ): ├── red, yellow, green = 'RED', 'YELLOW', 'GREEN' └── if not timer_done: └── return current_parallel, current_cross return 'GREEN' , 'RED' if timer_done:control( current_parallel='YELLOW', current_cross='RED', timer_done=False, red_phase='cross' ) -> 'YELLOW', 'RED' └── def control( timer_done, red_phase='parallel', current_parallel='RED', current_cross='RED', ): ├── red, yellow, green = 'RED', 'YELLOW', 'GREEN' └── if not timer_done: └── return current_parallel, current_cross return 'YELLOW' , 'RED' if timer_done:control( current_parallel='RED', current_cross='RED', timer_done=False, red_phase='cross' ) -> 'RED', 'RED' └── def control( timer_done, red_phase='parallel', current_parallel='RED', current_cross='RED', ): ├── red, yellow, green = 'RED', 'YELLOW', 'GREEN' └── if not timer_done: └── return current_parallel, current_cross return 'RED' , 'RED' if timer_done:If the timer is done, it checks if
crosstraffic is in the RED phaseIf
crosstraffic is in the RED phase, it checks the value ofcurrent_parallelIf the current parallel light is GREEN, it returns
YELLOW, RED, which means the next parallel light will be YELLOW and the cross light will remain RED because it is still in the RED phasecontrol( current_parallel='GREEN', current_cross='RED', timer_done=True, red_phase='cross' ) -> 'YELLOW', 'RED' └── def control( timer_done, red_phase='parallel', current_parallel='RED', current_cross='RED', ): ├── red, yellow, green = 'RED', 'YELLOW', 'GREEN' ├── if not timer_done: │ return current_parallel, current_cross └── if timer_done: └── if red_phase == 'cross': └── if current_parallel == green: └── return yellow, red if current_parallel == yellow: return red, red if current_parallel == red: return red, green if red_phase == 'parallel':If the current parallel light is YELLOW, it returns
RED, RED, which means there will be no traffic in the intersection, the parallel and cross lights will both be REDcontrol( current_parallel='YELLOW', current_cross='RED', timer_done=True, red_phase='cross' ) -> 'RED', 'RED' └── def control( timer_done, red_phase='parallel', current_parallel='RED', current_cross='RED', ): ├── red, yellow, green = 'RED', 'YELLOW', 'GREEN' ├── if not timer_done: │ return current_parallel, current_cross └── if timer_done: └── if red_phase == 'cross': ├── if current_parallel == green: │ return yellow, red └── if current_parallel == yellow: └── return red, red if current_parallel == red: return red, green if red_phase == 'parallel':If the current parallel light is RED, it returns
RED, GREEN, which means the parallel light will stay RED since it is now in the RED phase and the next cross light will be GREENcontrol( current_parallel='RED', current_cross='RED', timer_done=True, red_phase='cross' ) -> 'RED', 'GREEN' └── def control( timer_done, red_phase='parallel', current_parallel='RED', current_cross='RED', ): ├── red, yellow, green = 'RED', 'YELLOW', 'GREEN' ├── if not timer_done: │ return current_parallel, current_cross └── if timer_done: └── if red_phase == 'cross': ├── if current_parallel == green: │ return yellow, red ├── if current_parallel == yellow: │ return red, red └── if current_parallel == red: └── return red, green if red_phase == 'parallel':If
crosstraffic is not in the RED phase, it checks ifparalleltraffic is in the RED phase
If
paralleltraffic is in the RED phase, it checks the value ofcurrent_crossIf the current cross light is GREEN, it returns
RED, YELLOW, which means the parallel light will remain RED because it is still in the RED phase and the next cross light will be YELLOWcontrol( current_parallel='RED', current_cross='GREEN', timer_done=True, red_phase='parallel' ) -> 'RED', 'YELLOW' └── def control( timer_done, red_phase='parallel', current_parallel='RED', current_cross='RED', ): ├── red, yellow, green = 'RED', 'YELLOW', 'GREEN' ├── if not timer_done: │ return current_parallel, current_cross └── if timer_done: ├── if red_phase == 'cross': │ ... └── if red_phase == 'parallel': └── if current_cross == green: └── return red, yellow if current_cross == yellow: return red, red if current_cross == red: return green, redIf the current parallel light is YELLOW, it returns
RED, RED, which means there will be no traffic in the intersection, the parallel and cross lights will both be REDcontrol( current_parallel='RED', current_cross='YELLOW', timer_done=True, red_phase='parallel' ) -> 'RED', 'RED' └── def control( timer_done, red_phase='parallel', current_parallel='RED', current_cross='RED', ): ├── red, yellow, green = 'RED', 'YELLOW', 'GREEN' ├── if not timer_done: │ return current_parallel, current_cross └── if timer_done: ├── if red_phase == 'cross': │ ... └── if red_phase == 'parallel': ├── if current_cross == green: │ return red, yellow └── if current_cross == yellow: └── return red, red if current_cross == red: return green, redIf the current cross light is RED, it returns
GREEN, RED, which means the next parallel light will be GREEN and the cross light will stay RED since it is now in the RED phasecontrol( current_parallel='RED', current_cross='RED', timer_done=True, red_phase='parallel' ) -> 'GREEN', 'RED' └── def control( timer_done, red_phase='parallel', current_parallel='RED', current_cross='RED', ): ├── red, yellow, green = 'RED', 'YELLOW', 'GREEN' ├── if not timer_done: │ return current_parallel, current_cross └── if timer_done: ├── if red_phase == 'cross': │ ... └── if red_phase == 'parallel': ├── if current_cross == green: │ return red, yellow ├── if current_cross == yellow: │ return red, red └── if current_cross == red: └── return green, red
If none of the above conditions are met it returns None
└── def control( timer_done, red_phase='parallel', current_parallel='RED', current_cross='RED', ): ├── red, yellow, green = 'RED', 'YELLOW', 'GREEN' ├── if not timer_done: │ return current_parallel, current_cross └── if timer_done: ├── if red_phase == 'cross': │ ... ├── if red_phase == 'parallel': │ ...
test_failsafe
The Traffic Light has to make sure that there is never a case where cars move through the intersection at the same time to avoid accidents. The following cases must never happen
parallel |
cross |
|---|---|
GREEN |
GREEN |
GREEN |
YELLOW |
YELLOW |
YELLOW |
YELLOW |
GREEN |
It should be RED for both cross and parallel traffic for any of the above cases and for any cases that are outside the safe cases, for example a power failure.
RED: make it fail
I add a test for the safety state in
tests/test_traffic_light.py131 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 ) 141 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 153 154# Exceptions seenthe terminal is my friend, and shows AssertionError
AssertionError: Tuples differ: ('BAP', 'RED') != ('RED', 'RED')
GREEN: make it pass
I add an if statement for if current_parallel is NOT GREEN or YELLOW or RED, in src/traffic_light/__init__.py
5 red, yellow, green = 'RED', 'YELLOW', 'GREEN'
6
7 if not (
8 current_parallel == green
9 or current_parallel == yellow
10 or current_parallel == red
11 ):
12 return red, red
13
14 if not timer_done:
the test passes.
control(
current_parallel='BAP', current_cross='RED',
timer_done=False, red_phase='BOOM'
) -> 'RED', 'RED'
REFACTOR: make it better
I add an assertion for if
current_crossis NOT GREEN or YELLOW or RED to test_failsafe intests/test_traffic_light.py142 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='BAP', 156 current_cross='POW', 157 timer_done=False, 158 ), 159 (RED, RED) 160 ) 161 162 163# Exceptions seenthe terminal is my friend, and shows AssertionError
AssertionError: Tuples differ: ('RED', 'POW') != ('RED', 'RED')I add an if statement for if
current_crossis NOT GREEN or YELLOW or RED to test_failsafe insrc/traffic_light/__init__.py7 if not ( 8 current_parallel == green 9 or current_parallel == yellow 10 or current_parallel == red 11 ): 12 return red, red 13 14 if not ( 15 current_cross == green 16 or current_cross == yellow 17 or current_cross == red 18 ): 19 return red, red 20 21 if not timer_done:the test passes.
control( current_parallel='RED', current_cross='POW', timer_done=False, red_phase='BOOM' ) -> 'RED', 'RED' control( current_parallel='BAP', current_cross='RED', timer_done=False, red_phase='BOOM' ) -> 'RED', 'RED'I add an assertion to test_failsafe for if both lights are GREEN, in
tests/test_traffic_light.py152 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 ) 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 171 172# Exceptions seenthe terminal is my friend, and shows AssertionError
AssertionError: Tuples differ: ('GREEN', 'GREEN') != ('RED', 'RED')I add an if statement for if both lights are GREEN, in
src/traffic_light/__init__.py14 if not ( 15 current_cross == green 16 or current_cross == yellow 17 or current_cross == red 18 ): 19 return red, red 20 21 if current_parallel == current_cross == green: 22 return red, red 23 24 if not timer_done:the test passes.
control( current_parallel='RED', current_cross='POW', timer_done=False, red_phase='BOOM' ) -> 'RED', 'RED' control( current_parallel='BAP', current_cross='RED', timer_done=False, red_phase='BOOM' ) -> 'RED', 'RED' control( current_parallel='GREEN', current_cross='GREEN', timer_done=False, red_phase='BOOM' ) -> 'RED', 'RED'I add an assertion to test_failsafe for if the parallel lights are GREEN AND the cross lights are YELLOW, in
tests/test_traffic_light.py161 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 ) 179 180 181# Exceptions seenthe terminal is my friend, and shows AssertionError
AssertionError: Tuples differ: ('GREEN', 'YELLOW') != ('RED', 'RED')I add an if statement for if the parallel lights are GREEN AND the cross lights are YELLOW, in
src/traffic_light/__init__.py21 if current_parallel == current_cross == green: 22 return red, red 23 if current_parallel == green and current_cross == yellow: 24 return red, red 25 26 if not timer_done:the test passes.
control( current_parallel='RED', current_cross='POW', timer_done=False, red_phase='BOOM' ) -> 'RED', 'RED' control( current_parallel='BAP', current_cross='RED', timer_done=False, red_phase='BOOM' ) -> 'RED', 'RED' control( current_parallel='GREEN', current_cross='GREEN', timer_done=False, red_phase='BOOM' ) -> 'RED', 'RED' control( current_parallel='GREEN', current_cross='YELLOW', timer_done=False, red_phase='BOOM' ) -> 'RED', 'RED'I add an assertion to test_failsafe for if the parallel lights are YELLOW AND the cross lights are GREEN, in
tests/test_traffic_light.py170 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 ) 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 189 190# Exceptions seenthe terminal is my friend, and shows AssertionError
AssertionError: Tuples differ: ('YELLOW', 'GREEN') != ('RED', 'RED')I add an if statement for if the parallel lights are YELLOW AND the cross lights are GREEN, in
src/traffic_light/__init__.py21 if current_parallel == current_cross == green: 22 return red, red 23 if current_parallel == green and current_cross == yellow: 24 return red, red 25 if current_parallel == yellow and current_cross == green: 26 return red, red 27 28 if not timer_done:the test passes.
control( current_parallel='RED', current_cross='POW', timer_done=False, red_phase='BOOM' ) -> 'RED', 'RED' control( current_parallel='BAP', current_cross='RED', timer_done=False, red_phase='BOOM' ) -> 'RED', 'RED' control( current_parallel='GREEN', current_cross='GREEN', timer_done=False, red_phase='BOOM' ) -> 'RED', 'RED' control( current_parallel='GREEN', current_cross='YELLOW', timer_done=False, red_phase='BOOM' ) -> 'RED', 'RED' control( current_parallel='YELLOW', current_cross='GREEN', timer_done=False, red_phase='BOOM' ) -> 'RED', 'RED'I add an assertion to test_failsafe for if both lights are YELLOW, in
tests/test_traffic_light.py179 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 seenthe terminal is my friend, and shows AssertionError
AssertionError: Tuples differ: ('YELLOW', 'YELLOW') != ('RED', 'RED')I add an if statement for if both lights are YELLOW, in
src/traffic_light/__init__.py21 if current_parallel == current_cross == green: 22 return red, red 23 if current_parallel == green and current_cross == yellow: 24 return red, red 25 if current_parallel == yellow and current_cross == green: 26 return red, red 27 if current_parallel == current_cross == yellow: 28 return red, red 29 30 if not timer_done:the test passes.
control( current_parallel='RED', current_cross='POW', timer_done=False, red_phase='BOOM' ) -> 'RED', 'RED' control( current_parallel='BAP', current_cross='RED', timer_done=False, red_phase='BOOM' ) -> 'RED', 'RED' control( current_parallel='GREEN', current_cross='GREEN', timer_done=False, red_phase='BOOM' ) -> 'RED', 'RED' control( current_parallel='GREEN', current_cross='YELLOW', timer_done=False, red_phase='BOOM' ) -> 'RED', 'RED' control( current_parallel='YELLOW', current_cross='GREEN', timer_done=False, red_phase='BOOM' ) -> 'RED', 'RED' control( current_parallel='YELLOW', current_cross='YELLOW', timer_done=False, red_phase='BOOM' ) -> 'RED', 'RED'
I add an if statement for if the parallel lights and cross lights are the same AND are not equal to RED
21 # if current_parallel == current_cross == green: 22 if current_parallel == current_cross != red: 23 return red, red 24 if current_parallel == green and current_cross == yellow: 25 return red, red 26 if current_parallel == yellow and current_cross == green: 27 return red, red 28 # if current_parallel == current_cross == yellow: 29 # return red, red 30 31 if not timer_done:the tests are still green.
I remove the commented lines
14 if not ( 15 current_cross == green 16 or current_cross == yellow 17 or current_cross == red 18 ): 19 return red, red 20 21 if current_parallel == current_cross != red: 22 return red, red 23 if current_parallel == green and current_cross == yellow: 24 return red, red 25 if current_parallel == yellow and current_cross == green: 26 return red, red 27 28 if not timer_done:I add a return statement with the safety state as what the
controlfunction returns by default39 if red_phase == 'parallel': 40 if current_cross == green: 41 return red, yellow 42 if current_cross == yellow: 43 return red, red 44 if current_cross == red: 45 return green, red 46 47 return red, redstill green.
I remove
if current_cross == yellow:fromif red_phase == 'parallel':since it returns the safety state39 if red_phase == 'parallel': 40 if current_cross == green: 41 return red, yellow 42 if current_cross == red: 43 return green, red 44 45 return red, redgreen.
I remove
if current_parallel == yellow:fromif red_phase == 'cross':since it returns the safety state31 if timer_done: 32 if red_phase == 'cross': 33 if current_parallel == green: 34 return yellow, red 35 if current_parallel == red: 36 return red, green 37 if red_phase == 'parallel':still green.
I add a git commit message in the other terminal
git commit -am 'add test_failsafe'
extract is_not_safe function
I add a function to check for when both lights allow traffic at the same time
1def is_not_safe(parallel, cross): 2 red, yellow, green = 'RED', 'YELLOW', 'GREEN' 3 if parallel == cross != red: 4 return True 5 if parallel == green and cross == yellow: 6 return True 7 if parallel == yellow and cross == green: 8 return True 9 10 11def control( 12 timer_done, red_phase='parallel', 13 current_parallel='RED', current_cross='RED', 14 ): 15 red, yellow, green = 'RED', 'YELLOW', 'GREEN'I add a call to the is_not_safe function for the if statements that check if the lights allow traffic both ways
15 red, yellow, green = 'RED', 'YELLOW', 'GREEN' 16 17 if not ( 18 current_parallel == green 19 or current_parallel == yellow 20 or current_parallel == red 21 ): 22 return red, red 23 24 if not ( 25 current_cross == green 26 or current_cross == yellow 27 or current_cross == red 28 ): 29 return red, red 30 31 if is_not_safe(current_parallel, current_cross): 32 return red, red 33 if current_parallel == current_cross != red: 34 # if current_parallel == current_cross != red: 35 # return red, red 36 # if current_parallel == green and current_cross == yellow: 37 # return red, red 38 # if current_parallel == yellow and current_cross == green: 39 # return red, red 40 41 if not timer_done:the tests are still green.
I remove the other if statements for the if statements that check if the lights allow traffic both ways, because they are no longer needed.
31 if is_not_safe(current_parallel, current_cross): 32 return red, red 33 34 if not timer_done: 35 return current_parallel, current_crossI write a conditional expression for the if statements in the is_not_safe function
1def is_not_safe(parallel, cross): 2 red, yellow, green = 'RED', 'YELLOW', 'GREEN' 3 return ( 4 (parallel == cross != red) 5 or (parallel == green and cross == yellow) 6 or (parallel == yellow and cross == green) 7 ) 8 if parallel == cross != red: 9 return True 10 if parallel == green and cross == yellow: 11 return True 12 if parallel == yellow and cross == green: 13 return True 14 15 16 17def control( 18 timer_done, red_phase='parallel', 19 current_parallel='RED', current_cross='RED', 20 ):still green.
I remove the other if statements because they are no longer used
1def is_not_safe(parallel, cross): 2 red, yellow, green = 'RED', 'YELLOW', 'GREEN' 3 return ( 4 (parallel == cross != red) 5 or (parallel == green and cross == yellow) 6 or (parallel == yellow and cross == green) 7 ) 8 9 10 11def control( 12 timer_done, red_phase='parallel', 13 current_parallel='RED', current_cross='RED', 14 ):I add a git commit message in the other terminal
git commit -am 'extract is_not_safe function'
extract is_not_light function
I add a function to check if the value of a light is GREEN or YELLOW or RED
1def is_not_safe(parallel, cross): 2 red, yellow, green = 'RED', 'YELLOW', 'GREEN' 3 return ( 4 (parallel == cross != red) 5 or (parallel == green and cross == yellow) 6 or (parallel == yellow and cross == green) 7 ) 8 9 10def is_not_light(light): 11 red, yellow, green = 'RED', 'YELLOW', 'GREEN' 12 if not ( 13 light == green or light == yellow or light == red 14 ): 15 return True 16 17 18def control( 19 timer_done, red_phase='parallel', 20 current_parallel='RED', current_cross='RED', 21 ):I add a call to the is_not_light function for the if statements that check if
current_parallelis GREEN or YELLOW or RED18def control( 19 timer_done, red_phase='parallel', 20 current_parallel='RED', current_cross='RED', 21 ): 22 red, yellow, green = 'RED', 'YELLOW', 'GREEN' 23 24 if is_not_light(current_parallel): 25 return red, red 26 # if not ( 27 # current_parallel == green 28 # or current_parallel == yellow 29 # or current_parallel == red 30 # ): 31 # return red, redgreen.
I add a call to the is_not_light function for the if statements that check if
current_crossis GREEN or YELLOW or RED31 # return red, red 32 33 if is_not_light(current_cross): 34 return red, red 35 # if not ( 36 # current_cross == green 37 # or current_cross == yellow 38 # or current_cross == red 39 # ): 40 # return red, red 41 42 if is_not_safe(current_parallel, current_cross):green.
I remove the commented lines from the
controlfunction18def control( 19 timer_done, red_phase='parallel', 20 current_parallel='RED', current_cross='RED', 21 ): 22 red, yellow, green = 'RED', 'YELLOW', 'GREEN' 23 24 if is_not_light(current_parallel): 25 return red, red 26 if is_not_light(current_cross): 27 return red, red 28 if is_not_safe(current_parallel, current_cross): 29 return red, red 30 31 if not timer_done: 32 return current_parallel, current_cross 33 34 if timer_done: 35 if red_phase == 'cross': 36 if current_parallel == green: 37 return yellow, red 38 if current_parallel == red: 39 return red, green 40 if red_phase == 'parallel': 41 if current_cross == green: 42 return red, yellow 43 if current_cross == red: 44 return green, red 45 46 return red, redI add a conditional expression to the is_not_light function
10def is_not_light(light): 11 red, yellow, green = 'RED', 'YELLOW', 'GREEN' 12 return not ( 13 light == green or light == yellow or light == red 14 ) 15 if not ( 16 light == green or light == yellow or light == red 17 ): 18 return Truestill green.
I remove the if statement from the is_not_light function
10def is_not_light(light): 11 red, yellow, green = 'RED', 'YELLOW', 'GREEN' 12 return not ( 13 light == green or light == yellow or light == red 14 ) 15 16 17def control( 18 timer_done, red_phase='parallel', 19 current_parallel='RED', current_cross='RED', 20 ): 21 red, yellow, green = 'RED', 'YELLOW', 'GREEN'I add a git commit message in the other terminal
git commit -am 'extract is_not_light function'
extract triggers_failsafe function
I add a function for the three Functions which trigger the fail safe
10def is_not_light(light): 11 red, yellow, green = 'RED', 'YELLOW', 'GREEN' 12 return not ( 13 light == green or light == yellow or light == red 14 ) 15 16 17def triggers_failsafe(parallel, cross): 18 return ( 19 is_not_light(parallel) or is_not_light(cross) 20 or is_not_safe(parallel, cross) 21 ) 22 23 24def control( 25 timer_done, red_phase='parallel', 26 current_parallel='RED', current_cross='RED', 27 ):I add a call to the triggers_failsafe function from the
controlfunction24def control( 25 timer_done, red_phase='parallel', 26 current_parallel='RED', current_cross='RED', 27 ): 28 red, yellow, green = 'RED', 'YELLOW', 'GREEN' 29 30 if triggers_failsafe(current_parallel, current_cross): 31 return red, red 32 # if is_not_light(current_parallel): 33 # return red, red 34 # if is_not_light(current_cross): 35 # return red, red 36 # if is_not_safe(current_parallel, current_cross): 37 # return red, red 38 39 if not timer_done:the tests are still green.
I remove the commented lines from the
controlfunction24def control( 25 timer_done, red_phase='parallel', 26 current_parallel='RED', current_cross='RED', 27 ): 28 red, yellow, green = 'RED', 'YELLOW', 'GREEN' 29 30 if triggers_failsafe(current_parallel, current_cross): 31 return red, red 32 33 if not timer_done: 34 return current_parallel, current_crossI add a git commit message in the other terminal
git commit -am 'extract triggers_failsafe function'
extract global variables for lights
I add global variables for GREEN, YELLOW and RED
1GREEN, YELLOW, RED = 'GREEN', 'YELLOW', 'RED' 2 3 4def is_not_safe(parallel, cross):I use the variables for GREEN, YELLOW and RED in the is_not_safe function
4def is_not_safe(parallel, cross): 5 # red, yellow, green = 'RED', 'YELLOW', 'GREEN' 6 return ( 7 # (parallel == cross != red) 8 (parallel == cross != RED) 9 # or (parallel == green and cross == yellow) 10 or (parallel == GREEN and cross == YELLOW) 11 # or (parallel == yellow and cross == green) 12 or (parallel == YELLOW and cross == GREEN) 13 )still green.
I remove the commented lines from the is_not_safe function
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):I use the variables for GREEN, YELLOW and RED in the is_not_light function
12def is_not_light(light): 13 # red, yellow, green = 'RED', 'YELLOW', 'GREEN' 14 return not ( 15 # light == green or light == yellow or light == red 16 light == GREEN or light == YELLOW or light == RED 17 ) 18 19 20def triggers_failsafe(parallel, cross):green.
I remove the commented lines from the is_not_light function
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):I use the variables for GREEN, YELLOW and RED in the
controlfunction25def control( 26 timer_done, red_phase='parallel', 27 # current_parallel='RED', current_cross='RED', 28 current_parallel=RED, current_cross=RED, 29 ): 30 # red, yellow, green = 'RED', 'YELLOW', 'GREEN' 31 32 if triggers_failsafe(current_parallel, current_cross): 33 # return red, red 34 return RED, RED 35 36 if not timer_done: 37 return current_parallel, current_cross 38 39 if timer_done:39 if timer_done: 40 if red_phase == 'cross': 41 # if current_parallel == green: 42 if current_parallel == GREEN: 43 # return yellow, red 44 return YELLOW, RED 45 # if current_parallel == red: 46 if current_parallel == RED: 47 # return red, green 48 return RED, GREEN 49 if red_phase == 'parallel': 50 # if current_cross == green: 51 if current_cross == GREEN: 52 # return red, yellow 53 return RED, YELLOW 54 # if current_cross == red: 55 if current_cross == RED: 56 # return green, red 57 return GREEN, RED 58 59 # return red, red 60 return RED, REDstill green.
I remove the commented lines from the
controlfunction25def control( 26 timer_done, red_phase='parallel', 27 current_parallel=RED, current_cross=RED, 28 ): 29 if triggers_failsafe(current_parallel, current_cross): 30 return RED, RED 31 32 if not timer_done: 33 return current_parallel, current_cross 34 35 if timer_done: 36 if red_phase == 'cross': 37 if current_parallel == GREEN: 38 return YELLOW, RED 39 if current_parallel == RED: 40 return RED, GREEN 41 if red_phase == 'parallel': 42 if current_cross == GREEN: 43 return RED, YELLOW 44 if current_cross == RED: 45 return GREEN, RED 46 47 return RED, REDI add a git commit message in the other terminal
git commit -am 'extract global variables for lights'
extract next_light function
I add a function for when the timer is done and none of the fail safes are triggered
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 ):I add a call to the next_light function from
if timer_done:in thecontrolfunction39def 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 if red_phase == 'cross':the tests are still green.
I remove the other statements in the
controlfunction39def 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, REDI add a git commit message in the other terminal
git commit -am 'extract next_light function'
When the control function is called it calls the triggers_failsafe function to check if the values of current_parallel or current_cross trigger the failsafe. The triggers_failsafe function calls the is_not_light function or is_not_safe function to check the values of current_parallel and current_cross
If the failsafe is triggered, it turns the parallel and cross lights RED
control( current_parallel='RED', current_cross='POW', timer_done=False, red_phase='BOOM' ) -> 'RED', 'RED' └── def control( timer_done, red_phase='parallel', current_parallel=RED, current_cross=RED, ): └── if triggers_failsafe(current_parallel, current_cross): ├── def triggers_failsafe(parallel, cross): │ └── return ( │ │ is_not_light(parallel) │ └── or is_not_light(cross) │ or is_not_safe(parallel, cross) │ ) │ └── def is_not_light(light): │ └── return not ( │ light == GREEN or light == YELLOW │ or light == RED │ ) │ return True └── return RED, RED if not timer_done:control( current_parallel='BAP', current_cross='RED', timer_done=False, red_phase='BOOM' ) -> 'RED', 'RED' └── def control( timer_done, red_phase='parallel', current_parallel=RED, current_cross=RED, ): └── if triggers_failsafe(current_parallel, current_cross): ├── def triggers_failsafe(parallel, cross): │ └── return ( │ └── is_not_light(parallel) │ or is_not_light(cross) │ or is_not_safe(parallel, cross) │ ) │ └── def is_not_light(light): │ └── return not ( │ light == GREEN or light == YELLOW │ or light == RED │ ) │ return True └── return RED, RED if not timer_done:control( current_parallel='GREEN', current_cross='GREEN', timer_done=False, red_phase='BOOM' ) -> 'RED', 'RED' └── def control( timer_done, red_phase='parallel', current_parallel=RED, current_cross=RED, ): └── if triggers_failsafe(current_parallel, current_cross): ├── def triggers_failsafe(parallel, cross): │ └── return ( │ │ is_not_light(parallel) or is_not_light(cross) │ └── or is_not_safe(parallel, cross) │ ) │ └── def is_not_safe(parallel, cross): │ └── return ( │ └── (parallel == cross != RED) │ or (parallel == GREEN and cross == YELLOW) │ or (parallel == YELLOW and cross == GREEN) │ ) │ return True └── return RED, RED if not timer_done:control( current_parallel='GREEN', current_cross='YELLOW', timer_done=False, red_phase='BOOM' ) -> 'RED', 'RED' └── def control( timer_done, red_phase='parallel', current_parallel=RED, current_cross=RED, ): └── if triggers_failsafe(current_parallel, current_cross): ├── def triggers_failsafe(parallel, cross): │ └── return ( │ │ is_not_light(parallel) or is_not_light(cross) │ └── or is_not_safe(parallel, cross) │ ) │ └── def is_not_safe(parallel, cross): │ └── return ( │ │ (parallel == cross != RED) │ └── or (parallel == GREEN and cross == YELLOW) │ or (parallel == YELLOW and cross == GREEN) │ ) │ return True └── return RED, RED if not timer_done:control( current_parallel='YELLOW', current_cross='GREEN', timer_done=False, red_phase='BOOM' ) -> 'RED', 'RED' └── def control( timer_done, red_phase='parallel', current_parallel=RED, current_cross=RED, ): └── if triggers_failsafe(current_parallel, current_cross): ├── def triggers_failsafe(parallel, cross): │ └── return ( │ │ is_not_light(parallel) or is_not_light(cross) │ └── or is_not_safe(parallel, cross) │ ) │ └── def is_not_safe(parallel, cross): │ └── return ( │ │ (parallel == cross != RED) │ │ or (parallel == GREEN and cross == YELLOW) │ └── or (parallel == YELLOW and cross == GREEN) │ ) │ return True └── return RED, RED if not timer_done:control( current_parallel='YELLOW', current_cross='YELLOW', timer_done=False, red_phase='BOOM' ) -> 'RED', 'RED' └── def control( timer_done, red_phase='parallel', current_parallel=RED, current_cross=RED, ): └── if triggers_failsafe(current_parallel, current_cross): ├── def triggers_failsafe(parallel, cross): │ └── return ( │ │ is_not_light(parallel) or is_not_light(cross) │ └── or is_not_safe(parallel, cross) │ ) │ └── def is_not_safe(parallel, cross): │ └── return ( │ └── (parallel == cross != RED) │ or (parallel == GREEN and cross == YELLOW) │ or (parallel == YELLOW and cross == GREEN) │ ) │ return True └── return RED, RED if not timer_done:If the failsafe is NOT triggered, it checks if the timer is NOT done
If the timer is NOT done, it returns the values of
current_parallelandcurrent_cross, which means it does not change the parallel or cross lights, it keeps them the samecontrol( current_parallel='RED', current_cross='GREEN', timer_done=False, red_phase='parallel' ) -> 'RED', 'GREEN' └── def control( timer_done, red_phase='parallel', current_parallel=RED, current_cross=RED, ): ├── if triggers_failsafe(current_parallel, current_cross): │ return RED, RED └── if not timer_done: └── return current_parallel, current_cross return 'RED' , 'GREEN' if timer_done:control( current_parallel='RED', current_cross='YELLOW', timer_done=False, red_phase='parallel' ) -> 'RED', 'YELLOW' └── def control( timer_done, red_phase='parallel', current_parallel='RED', current_cross='RED', ): ├── if triggers_failsafe(current_parallel, current_cross): │ return RED, RED └── if not timer_done: └── return current_parallel, current_cross return 'RED' , 'YELLOW' if timer_done:control( current_parallel='RED', current_cross='RED', timer_done=False, red_phase='parallel' ) -> 'RED', 'RED' └── def control( timer_done, red_phase='parallel', current_parallel='RED', current_cross='RED', ): ├── if triggers_failsafe(current_parallel, current_cross): │ return RED, RED └── if not timer_done: └── return current_parallel, current_cross return 'RED' , 'RED' if timer_done:control( current_parallel='GREEN', current_cross='RED', timer_done=False, red_phase='cross' ) -> 'GREEN', 'RED' └── def control( timer_done, red_phase='parallel', current_parallel='RED', current_cross='RED', ): ├── if triggers_failsafe(current_parallel, current_cross): │ return RED, RED └── if not timer_done: └── return current_parallel, current_cross return 'GREEN' , 'RED' if timer_done:control( current_parallel='YELLOW', current_cross='RED', timer_done=False, red_phase='cross' ) -> 'YELLOW', 'RED' └── def control( timer_done, red_phase='parallel', current_parallel='RED', current_cross='RED', ): ├── if triggers_failsafe(current_parallel, current_cross): │ return RED, RED └── if not timer_done: └── return current_parallel, current_cross return 'YELLOW' , 'RED' if timer_done:control( current_parallel='RED', current_cross='RED', timer_done=False, red_phase='cross' ) -> 'RED', 'RED' └── def control( timer_done, red_phase='parallel', current_parallel='RED', current_cross='RED', ): ├── if triggers_failsafe(current_parallel, current_cross): │ return RED, RED └── if not timer_done: └── return current_parallel, current_cross return 'RED' , 'RED' if timer_done:If the timer is done, it calls the next_light function which checks if
crosstraffic is in the RED phaseIf
crosstraffic is in the RED phase, it checks the value ofcurrent_parallelIf the current parallel light is GREEN, it returns
YELLOW, RED, which means the next parallel light will be YELLOW and the cross light will remain RED because it is still in the RED phasecontrol( current_parallel='GREEN', current_cross='RED', timer_done=True, red_phase='cross' ) -> 'YELLOW', 'RED' └── def control( timer_done, red_phase='parallel', current_parallel='RED', current_cross='RED', ): ├── if triggers_failsafe(current_parallel, current_cross): │ return RED, RED ├── if not timer_done: │ return current_parallel, current_cross └── if timer_done: └── return next_light( red_phase, current_parallel, current_cross ) └── def next_light(red_phase, parallel, cross): └── if red_phase == 'cross': └── if parallel == GREEN: └── return YELLOW, RED if parallel == RED:If the current parallel light is RED, it returns
RED, GREEN, which means the parallel light will stay RED since it is now in the RED phase and the next cross light will be GREENcontrol( current_parallel='RED', current_cross='RED', timer_done=True, red_phase='cross' ) -> 'RED', 'GREEN' └── def control( timer_done, red_phase='parallel', current_parallel='RED', current_cross='RED', ): ├── if triggers_failsafe(current_parallel, current_cross): │ return RED, RED ├── if not timer_done: │ return current_parallel, current_cross └── if timer_done: └── return next_light( red_phase, current_parallel, current_cross ) └── def next_light(red_phase, parallel, cross): └── if red_phase == 'cross': ├── if parallel == GREEN: │ return YELLOW, RED └── if parallel == RED: └── return RED, GREEN if red_phase == 'parallel':If
crosstraffic is not in the RED phase, it checks ifparalleltraffic is in the RED phase
If
paralleltraffic is in the RED phase, it checks the value ofcurrent_crossIf the current cross light is GREEN, it returns
RED, YELLOW, which means the parallel light will remain RED because it is still in the RED phase and the next cross light will be YELLOWcontrol( current_parallel='RED', current_cross='GREEN', timer_done=True, red_phase='parallel' ) -> 'RED', 'YELLOW' └── def control( timer_done, red_phase='parallel', current_parallel='RED', current_cross='RED', ): ├── if triggers_failsafe(current_parallel, current_cross): │ return RED, RED ├── if not timer_done: │ return current_parallel, current_cross └── if timer_done: └── return next_light( red_phase, current_parallel, current_cross ) └── def next_light(red_phase, parallel, cross): ├── if red_phase == 'cross': │ ... └── if red_phase == 'parallel': └── if cross == GREEN: └── return RED, YELLOW if cross == RED:If the current cross light is RED, it returns
GREEN, RED, which means the next parallel light will be GREEN and the cross light will stay RED since it is now in the RED phasecontrol( current_parallel='RED', current_cross='RED', timer_done=True, red_phase='parallel' ) -> 'GREEN', 'RED' └── def control( timer_done, red_phase='parallel', current_parallel='RED', current_cross='RED', ): ├── if triggers_failsafe(current_parallel, current_cross): │ return RED, RED ├── if not timer_done: │ return current_parallel, current_cross └── if timer_done: └── return next_light( red_phase, current_parallel, current_cross ) └── def next_light(red_phase, parallel, cross): ├── if red_phase == 'cross': │ ... └── if red_phase == 'parallel': ├── if cross == GREEN: │ return RED, YELLOW └── if cross == RED: └── return GREEN, RED return RED, REDIf none of the above conditions are met, it returns
RED, RED, which means there will be no traffic in the intersection, the parallel and cross lights will both be REDcontrol( current_parallel='YELLOW', current_cross='RED', timer_done=True, red_phase='cross' ) -> 'RED', 'RED' └── def control( timer_done, red_phase='parallel', current_parallel='RED', current_cross='RED', ): ├── if triggers_failsafe(current_parallel, current_cross): │ return RED, RED ├── if not timer_done: │ return current_parallel, current_cross └── if timer_done: └── return next_light( red_phase, current_parallel, current_cross ) └── def next_light(red_phase, parallel, cross): └── if red_phase == 'cross': ├── if parallel == GREEN: │ return YELLOW, RED ┌───┴── if parallel == RED: │ return RED, GREEN │ if red_phase == 'parallel': │ if cross == GREEN: │ return RED, YELLOW │ if cross == RED: │ return GREEN, RED └── return RED, REDcontrol( current_parallel='RED', current_cross='YELLOW', timer_done=True, red_phase='parallel' ) -> 'RED', 'RED' └── def control( timer_done, red_phase='parallel', current_parallel='RED', current_cross='RED', ): ├── if triggers_failsafe(current_parallel, current_cross): │ return RED, RED ├── if not timer_done: │ return current_parallel, current_cross └── if timer_done: └── return next_light( red_phase, current_parallel, current_cross ) └── def next_light(red_phase, parallel, cross): ├── if red_phase == 'cross': │ if parallel == GREEN: │ return YELLOW, RED │ if parallel == RED: │ return RED, GREEN └── if red_phase == 'parallel': ├── if cross == GREEN: │ return RED, YELLOW ┌───┴── if cross == RED: │ return GREEN, RED └── return RED, RED
If none of the above conditions are met, it returns
RED, RED, which means there will be no traffic in the intersection, the parallel and cross lights will both be RED└── def control( timer_done, red_phase='parallel', current_parallel='RED', current_cross='RED', ): ├── if triggers_failsafe(current_parallel, current_cross): │ return RED, RED ├── if not timer_done: │ return current_parallel, current_cross ├── if timer_done: │ return next_light( │ red_phase, current_parallel, current_cross │ ) └── return RED, RED
close the project
review
I ran tests for a Traffic Light that changes lights based on what RED phase the traffic is in ('cross' or 'parallel') AND if a timer is done or NOT done
The outputs are the next lights for Parallel and Cross Traffic which gave me this truth table
red |
current |
current |
next |
next |
|
|---|---|---|---|---|---|
phase |
parallel |
cross |
timer |
parallel |
cross |
‘cross’ |
GREEN |
RED |
NOT done |
GREEN |
RED |
‘cross’ |
GREEN |
RED |
done |
YELLOW |
RED |
‘cross’ |
YELLOW |
RED |
NOT done |
YELLOW |
RED |
‘cross’ |
YELLOW |
RED |
done |
safety RED |
safety RED |
‘cross’ |
RED |
RED |
NOT done |
safety RED |
safety RED |
‘cross’ |
RED |
RED |
done |
RED |
GREEN |
red |
current |
current |
next |
next |
|
|---|---|---|---|---|---|
phase |
parallel |
cross |
timer |
parallel |
cross |
‘parallel’ |
RED |
GREEN |
NOT done |
RED |
GREEN |
‘parallel’ |
RED |
GREEN |
done |
RED |
YELLOW |
‘parallel’ |
RED |
YELLOW |
NOT done |
RED |
YELLOW |
‘parallel’ |
RED |
YELLOW |
done |
safety RED |
safety RED |
‘parallel’ |
RED |
RED |
NOT done |
safety RED |
safety RED |
‘parallel’ |
RED |
RED |
done |
GREEN |
RED |
It also makes sure that there is never a case where cars move through the intersection at the same time to avoid accidents.
What if the Traffic Light has a walk button and I push it? What if the Traffic Light changes based on if there is an emergency vehicle? What would the inputs be and what truth table do I get?
code from the chapter
what is next?
I know how to make a Python Test Driven Development environment manually.
I know how to make a Python Test Driven Development environment automatically
I changed the name of the project in a few places every time I ran makePythonTdd, that is too many steps. Would you like to see a better way to make a Python Test Driven Development environment automatically?
rate pumping python
If this has been a 7 star experience for you, please CLICK HERE to leave a 5 star review of pumping python. It helps other people get into the book too.