blob: 70620d5596da2ffa217c696f4166ee8c7de3502c [file] [log] [blame]
Serhiy Storchakadec45b42016-06-04 23:27:14 +03001import unittest
2from test import test_support as support
3
4turtle = support.import_module('turtle')
5Vec2D = turtle.Vec2D
6
7test_config = """\
8width = 0.75
9height = 0.8
10canvwidth = 500
11canvheight = 200
12leftright = 100
13topbottom = 100
14mode = world
15colormode = 255
16delay = 100
17undobuffersize = 10000
18shape = circle
19pencolor = red
20fillcolor = blue
21resizemode = auto
22visible = None
23language = english
24exampleturtle = turtle
25examplescreen = screen
26title = Python Turtle Graphics
27using_IDLE = ''
28"""
29
30test_config_two = """\
31# Comments!
32# Testing comments!
33pencolor = red
34fillcolor = blue
35visible = False
36language = english
37# Some more
38# comments
39using_IDLE = False
40"""
41
42invalid_test_config = """
43pencolor = red
44fillcolor: blue
45visible = False
46"""
47
48
49class TurtleConfigTest(unittest.TestCase):
50
51 def get_cfg_file(self, cfg_str):
52 self.addCleanup(support.unlink, support.TESTFN)
53 with open(support.TESTFN, 'w') as f:
54 f.write(cfg_str)
55 return support.TESTFN
56
57 def test_config_dict(self):
58
59 cfg_name = self.get_cfg_file(test_config)
60 parsed_cfg = turtle.config_dict(cfg_name)
61
62 expected = {
63 'width' : 0.75,
64 'height' : 0.8,
65 'canvwidth' : 500,
66 'canvheight': 200,
67 'leftright': 100,
68 'topbottom': 100,
69 'mode': 'world',
70 'colormode': 255,
71 'delay': 100,
72 'undobuffersize': 10000,
73 'shape': 'circle',
74 'pencolor' : 'red',
75 'fillcolor' : 'blue',
76 'resizemode' : 'auto',
77 'visible' : None,
78 'language': 'english',
79 'exampleturtle': 'turtle',
80 'examplescreen': 'screen',
81 'title': 'Python Turtle Graphics',
82 'using_IDLE': '',
83 }
84
85 self.assertEqual(parsed_cfg, expected)
86
87 def test_partial_config_dict_with_commments(self):
88
89 cfg_name = self.get_cfg_file(test_config_two)
90 parsed_cfg = turtle.config_dict(cfg_name)
91
92 expected = {
93 'pencolor': 'red',
94 'fillcolor': 'blue',
95 'visible': False,
96 'language': 'english',
97 'using_IDLE': False,
98 }
99
100 self.assertEqual(parsed_cfg, expected)
101
102 def test_config_dict_invalid(self):
103
104 cfg_name = self.get_cfg_file(invalid_test_config)
105
106 with support.captured_stdout() as stdout:
107 parsed_cfg = turtle.config_dict(cfg_name)
108
109 err_msg = stdout.getvalue()
110
111 self.assertIn('Bad line in config-file ', err_msg)
112 self.assertIn('fillcolor: blue', err_msg)
113
114 self.assertEqual(parsed_cfg, {
115 'pencolor': 'red',
116 'visible': False,
117 })
118
119
120class VectorComparisonMixin:
121
122 def assertVectorsAlmostEqual(self, vec1, vec2):
123 if len(vec1) != len(vec2):
124 self.fail("Tuples are not of equal size")
125 for idx, (i, j) in enumerate(zip(vec1, vec2)):
126 self.assertAlmostEqual(
127 i, j, msg='values at index {} do not match'.format(idx))
128
129
130class TestVec2D(VectorComparisonMixin, unittest.TestCase):
131
132 def _assert_arithmetic_cases(self, test_cases, lambda_operator):
133 for test_case in test_cases:
134 ((first, second), expected) = test_case
135
136 op1 = Vec2D(*first)
137 op2 = Vec2D(*second)
138
139 result = lambda_operator(op1, op2)
140
141 expected = Vec2D(*expected)
142
143 self.assertVectorsAlmostEqual(result, expected)
144
145 def test_vector_addition(self):
146
147 test_cases = [
148 (((0, 0), (1, 1)), (1.0, 1.0)),
149 (((-1, 0), (2, 2)), (1, 2)),
150 (((1.5, 0), (1, 1)), (2.5, 1)),
151 ]
152
153 self._assert_arithmetic_cases(test_cases, lambda x, y: x + y)
154
155 def test_vector_subtraction(self):
156
157 test_cases = [
158 (((0, 0), (1, 1)), (-1, -1)),
159 (((10.625, 0.125), (10, 0)), (0.625, 0.125)),
160 ]
161
162 self._assert_arithmetic_cases(test_cases, lambda x, y: x - y)
163
164 def test_vector_multiply(self):
165
166 vec1 = Vec2D(10, 10)
167 vec2 = Vec2D(0.5, 3)
168 answer = vec1 * vec2
169 expected = 35
170 self.assertAlmostEqual(answer, expected)
171
172 vec = Vec2D(0.5, 3)
173 answer = vec * 10
174 expected = Vec2D(5, 30)
175 self.assertVectorsAlmostEqual(answer, expected)
176
177 def test_vector_negative(self):
178 vec = Vec2D(10, -10)
179 expected = (-10, 10)
180 self.assertVectorsAlmostEqual(-vec, expected)
181
182 def test_distance(self):
183 vec = Vec2D(6, 8)
184 expected = 10
185 self.assertEqual(abs(vec), expected)
186
187 vec = Vec2D(0, 0)
188 expected = 0
189 self.assertEqual(abs(vec), expected)
190
191 vec = Vec2D(2.5, 6)
192 expected = 6.5
193 self.assertEqual(abs(vec), expected)
194
195 def test_rotate(self):
196
197 cases = [
198 (((0, 0), 0), (0, 0)),
199 (((0, 1), 90), (-1, 0)),
200 (((0, 1), -90), (1, 0)),
201 (((1, 0), 180), (-1, 0)),
202 (((1, 0), 360), (1, 0)),
203 ]
204
205 for case in cases:
206 (vec, rot), expected = case
207 vec = Vec2D(*vec)
208 got = vec.rotate(rot)
209 self.assertVectorsAlmostEqual(got, expected)
210
211
212class TestTNavigator(VectorComparisonMixin, unittest.TestCase):
213
214 def setUp(self):
215 self.nav = turtle.TNavigator()
216
217 def test_goto(self):
218 self.nav.goto(100, -100)
219 self.assertAlmostEqual(self.nav.xcor(), 100)
220 self.assertAlmostEqual(self.nav.ycor(), -100)
221
222 def test_pos(self):
223 self.assertEqual(self.nav.pos(), self.nav._position)
224 self.nav.goto(100, -100)
225 self.assertEqual(self.nav.pos(), self.nav._position)
226
227 def test_left(self):
228 self.assertEqual(self.nav._orient, (1.0, 0))
229 self.nav.left(90)
230 self.assertVectorsAlmostEqual(self.nav._orient, (0.0, 1.0))
231
232 def test_right(self):
233 self.assertEqual(self.nav._orient, (1.0, 0))
234 self.nav.right(90)
235 self.assertVectorsAlmostEqual(self.nav._orient, (0, -1.0))
236
237 def test_reset(self):
238 self.nav.goto(100, -100)
239 self.assertAlmostEqual(self.nav.xcor(), 100)
240 self.assertAlmostEqual(self.nav.ycor(), -100)
241 self.nav.reset()
242 self.assertAlmostEqual(self.nav.xcor(), 0)
243 self.assertAlmostEqual(self.nav.ycor(), 0)
244
245 def test_forward(self):
246 self.nav.forward(150)
247 expected = Vec2D(150, 0)
248 self.assertVectorsAlmostEqual(self.nav.position(), expected)
249
250 self.nav.reset()
251 self.nav.left(90)
252 self.nav.forward(150)
253 expected = Vec2D(0, 150)
254 self.assertVectorsAlmostEqual(self.nav.position(), expected)
255
256 self.assertRaises(TypeError, self.nav.forward, 'skldjfldsk')
257
258 def test_backwards(self):
259 self.nav.back(200)
260 expected = Vec2D(-200, 0)
261 self.assertVectorsAlmostEqual(self.nav.position(), expected)
262
263 self.nav.reset()
264 self.nav.right(90)
265 self.nav.back(200)
266 expected = Vec2D(0, 200)
267 self.assertVectorsAlmostEqual(self.nav.position(), expected)
268
269 def test_distance(self):
270 self.nav.forward(100)
271 expected = 100
272 self.assertAlmostEqual(self.nav.distance(Vec2D(0,0)), expected)
273
274 def test_radians_and_degrees(self):
275 self.nav.left(90)
276 self.assertAlmostEqual(self.nav.heading(), 90)
277 self.nav.radians()
278 self.assertAlmostEqual(self.nav.heading(), 1.57079633)
279 self.nav.degrees()
280 self.assertAlmostEqual(self.nav.heading(), 90)
281
282 def test_towards(self):
283
284 coordinates = [
285 # coordinates, expected
286 ((100, 0), 0.0),
287 ((100, 100), 45.0),
288 ((0, 100), 90.0),
289 ((-100, 100), 135.0),
290 ((-100, 0), 180.0),
291 ((-100, -100), 225.0),
292 ((0, -100), 270.0),
293 ((100, -100), 315.0),
294 ]
295
296 for (x, y), expected in coordinates:
297 self.assertEqual(self.nav.towards(x, y), expected)
298 self.assertEqual(self.nav.towards((x, y)), expected)
299 self.assertEqual(self.nav.towards(Vec2D(x, y)), expected)
300
301 def test_heading(self):
302
303 self.nav.left(90)
304 self.assertAlmostEqual(self.nav.heading(), 90)
305 self.nav.left(45)
306 self.assertAlmostEqual(self.nav.heading(), 135)
307 self.nav.right(1.6)
308 self.assertAlmostEqual(self.nav.heading(), 133.4)
309 self.assertRaises(TypeError, self.nav.right, 'sdkfjdsf')
310 self.nav.reset()
311
312 rotations = [10, 20, 170, 300]
313 result = sum(rotations) % 360
314 for num in rotations:
315 self.nav.left(num)
316 self.assertEqual(self.nav.heading(), result)
317 self.nav.reset()
318
319 result = (360-sum(rotations)) % 360
320 for num in rotations:
321 self.nav.right(num)
322 self.assertEqual(self.nav.heading(), result)
323 self.nav.reset()
324
325 rotations = [10, 20, -170, 300, -210, 34.3, -50.2, -10, -29.98, 500]
326 sum_so_far = 0
327 for num in rotations:
328 if num < 0:
329 self.nav.right(abs(num))
330 else:
331 self.nav.left(num)
332 sum_so_far += num
333 self.assertAlmostEqual(self.nav.heading(), sum_so_far % 360)
334
335 def test_setheading(self):
336 self.nav.setheading(102.32)
337 self.assertAlmostEqual(self.nav.heading(), 102.32)
338 self.nav.setheading(-123.23)
339 self.assertAlmostEqual(self.nav.heading(), (-123.23) % 360)
340 self.nav.setheading(-1000.34)
341 self.assertAlmostEqual(self.nav.heading(), (-1000.34) % 360)
342 self.nav.setheading(300000)
343 self.assertAlmostEqual(self.nav.heading(), 300000%360)
344
345 def test_positions(self):
346 self.nav.forward(100)
347 self.nav.left(90)
348 self.nav.forward(-200)
349 self.assertVectorsAlmostEqual(self.nav.pos(), (100.0, -200.0))
350
351 def test_setx_and_sety(self):
352 self.nav.setx(-1023.2334)
353 self.nav.sety(193323.234)
354 self.assertVectorsAlmostEqual(self.nav.pos(), (-1023.2334, 193323.234))
355
356 def test_home(self):
357 self.nav.left(30)
358 self.nav.forward(-100000)
359 self.nav.home()
360 self.assertVectorsAlmostEqual(self.nav.pos(), (0,0))
361 self.assertAlmostEqual(self.nav.heading(), 0)
362
363 def test_distance_method(self):
364 self.assertAlmostEqual(self.nav.distance(30, 40), 50)
365 vec = Vec2D(0.22, .001)
366 self.assertAlmostEqual(self.nav.distance(vec), 0.22000227271553355)
367 another_turtle = turtle.TNavigator()
368 another_turtle.left(90)
369 another_turtle.forward(10000)
370 self.assertAlmostEqual(self.nav.distance(another_turtle), 10000)
371
372
373class TestTPen(unittest.TestCase):
374
375 def test_pendown_and_penup(self):
376
377 tpen = turtle.TPen()
378
379 self.assertTrue(tpen.isdown())
380 tpen.penup()
381 self.assertFalse(tpen.isdown())
382 tpen.pendown()
383 self.assertTrue(tpen.isdown())
384
385 def test_showturtle_hideturtle_and_isvisible(self):
386
387 tpen = turtle.TPen()
388
389 self.assertTrue(tpen.isvisible())
390 tpen.hideturtle()
391 self.assertFalse(tpen.isvisible())
392 tpen.showturtle()
393 self.assertTrue(tpen.isvisible())
394
395
396def test_main():
397 support.run_unittest(TurtleConfigTest, TestVec2D, TestTNavigator, TestTPen)
398
399if __name__ == '__main__':
400 test_main()