Coverage for tests/test_turtlesc.py: 100%
914 statements
« prev ^ index » next coverage.py v7.7.0, created at 2025-04-01 13:58 -0400
« prev ^ index » next coverage.py v7.7.0, created at 2025-04-01 13:58 -0400
1import pytest
2from turtle import *
3from turtlesc import *
4from random import *
6seed(42) # Keep at 42 for reproducible tests (dependent on which tests are run and in what order, anyway)
7tracer(10000, 0)
9def test_basic_sc_calls():
10 # Blanks are no-ops and fine:
11 assert sc('') == 0
12 assert sc('', '') == 0
13 assert sc(' ') == 0
14 assert sc(' ', ' ') == 0
15 assert sc('f 1, ') == 1
16 assert sc('f -1, ', '\n', ' ') == 1
18 # Invalid commands raise exceptions:
19 with pytest.raises(TurtleShortcutException):
20 sc('invalid')
21 with pytest.raises(TurtleShortcutException):
22 sc('f')
23 with pytest.raises(TurtleShortcutException):
24 sc('f 1 2')
25 with pytest.raises(TurtleShortcutException):
26 sc('f invalid')
28 assert sc('f 1, f -1') == 2
30def test_in_radians_mode():
31 radians()
32 assert in_radians_mode()
33 degrees()
34 assert not in_radians_mode()
37def test_in_degrees_mode():
38 degrees()
39 assert in_degrees_mode()
40 radians()
41 assert not in_degrees_mode()
42 degrees() # These tests always use degrees mode.
45def test_forward():
46 turtle.reset()
48 for name in ('f', 'forward', 'F', 'FORWARD', 'fOrWaRd'):
49 with pytest.raises(TurtleShortcutException):
50 sc(f'{name}') # Missing argument
51 with pytest.raises(TurtleShortcutException):
52 sc(f'{name} 1 2') # Too many arguments
53 with pytest.raises(TurtleShortcutException):
54 sc(f'{name} invalid') # Invalid argument
56 assert sc(f'{name} 1') == 1
57 assert pos() == (1, 0)
58 assert sc(f'{name} -1') == 1
59 assert pos() == (0, 0)
60 assert sc(f'{name} 0') == 1
61 assert pos() == (0, 0)
62 assert sc(f'{name} 0.5') == 1
63 assert pos() == (0.5, 0)
64 assert sc(f'{name} -0.5') == 1
65 assert pos() == (0, 0)
68def test_backward():
69 turtle.reset()
71 for name in ('b', 'backward', 'B', 'BACKWARD', 'bAcKwArD'):
72 with pytest.raises(TurtleShortcutException):
73 sc(f'{name}') # Missing argument
74 with pytest.raises(TurtleShortcutException):
75 sc(f'{name} 1 2') # Too many arguments
76 with pytest.raises(TurtleShortcutException):
77 sc(f'{name} invalid') # Invalid argument
79 assert sc(f'{name} 1') == 1
80 assert pos() == (-1, 0)
81 assert sc(f'{name} -1') == 1
82 assert pos() == (0, 0)
83 assert sc(f'{name} 0') == 1
84 assert pos() == (0, 0)
85 assert sc(f'{name} 0.5') == 1
86 assert pos() == (-0.5, 0)
87 assert sc(f'{name} -0.5') == 1
88 assert pos() == (0, 0)
91def test_right():
92 turtle.reset()
94 for name in ('r', 'right', 'R', 'RIGHT', 'rIgHt'):
95 with pytest.raises(TurtleShortcutException):
96 sc(f'{name}') # Missing argument
97 with pytest.raises(TurtleShortcutException):
98 sc(f'{name} 1 2') # Too many arguments
99 with pytest.raises(TurtleShortcutException):
100 sc(f'{name} invalid') # Invalid argument
102 assert sc(f'{name} 1') == 1
103 assert heading() == 359
104 assert sc(f'{name} -1') == 1
105 assert heading() == 0
106 assert sc(f'{name} 0') == 1
107 assert heading() == 0
108 assert sc(f'{name} 0.5') == 1
109 assert heading() == 359.5
110 assert sc(f'{name} -0.5') == 1
111 assert heading() == 0
114def test_left():
115 turtle.reset()
117 for name in ('l', 'left', 'L', 'LEFT', 'lEfT'):
118 with pytest.raises(TurtleShortcutException):
119 sc(f'{name}') # Missing argument
120 with pytest.raises(TurtleShortcutException):
121 sc(f'{name} 1 2') # Too many arguments
122 with pytest.raises(TurtleShortcutException):
123 sc(f'{name} invalid') # Invalid argument
125 assert sc(f'{name} 1') == 1
126 assert heading() == 1
127 assert sc(f'{name} -1') == 1
128 assert heading() == 0
129 assert sc(f'{name} 0') == 1
130 assert heading() == 0
131 assert sc(f'{name} 0.5') == 1
132 assert heading() == 0.5
133 assert sc(f'{name} -0.5') == 1
134 assert heading() == 0
137def test_setheading():
138 for name in ('sh', 'setheading', 'SH', 'SETHEADING', 'sEtHeAdInG'):
139 with pytest.raises(TurtleShortcutException):
140 sc(f'{name}') # Missing argument
141 with pytest.raises(TurtleShortcutException):
142 sc(f'{name} 1 2') # Too many arguments
143 with pytest.raises(TurtleShortcutException):
144 sc(f'{name} invalid') # Invalid argument
146 assert sc(f'{name} 1') == 1
147 assert heading() == 1
148 assert sc(f'{name} 0') == 1
149 assert heading() == 0
150 assert sc(f'{name} 360') == 1
151 assert heading() == 0
152 assert sc(f'{name} 720') == 1
153 assert heading() == 0
154 assert sc(f'{name} -360') == 1
155 assert heading() == 0
158def test_home():
159 for name in ('h', 'home', 'H', 'HOME', 'hOmE'):
160 with pytest.raises(TurtleShortcutException):
161 sc(f'{name} 1') # Too many arguments
163 assert sc(f'{name}') == 1
164 assert pos() == (0, 0)
165 assert heading() == 0
168def test_clear():
169 for name in ('c', 'clear', 'C', 'CLEAR', 'cLeAr'):
170 with pytest.raises(TurtleShortcutException):
171 sc(f'{name} 1') # Too many arguments
173 assert sc(f'{name}') == 1
176def test_goto():
177 for name in ('g', 'goto', 'G', 'GOTO', 'gOtO'):
178 with pytest.raises(TurtleShortcutException):
179 sc(f'{name}') # Missing argument
180 with pytest.raises(TurtleShortcutException):
181 sc(f'{name} 1') # Missing second argument
182 with pytest.raises(TurtleShortcutException):
183 sc(f'{name} 1 2 3') # Too many arguments
184 with pytest.raises(TurtleShortcutException):
185 sc(f'{name} 1 invalid')
186 with pytest.raises(TurtleShortcutException):
187 sc(f'{name} invalid 2')
189 assert sc(f'{name} 1 2') == 1
190 assert pos() == (1, 2)
191 assert sc(f'{name} -3 -4') == 1
192 assert pos() == (-3, -4)
193 assert sc(f'{name} 0 0') == 1
194 assert pos() == (0, 0)
195 assert sc(f'{name} 0.5 0.5') == 1
196 assert pos() == (0.5, 0.5)
197 assert sc(f'{name} -0.5 -0.5') == 1
198 assert pos() == (-0.5, -0.5)
201def test_tele():
202 for name in ('tele', 'TELE', 'tElE', 'teleport', 'TELEPORT', 'tElEpOrT'):
203 with pytest.raises(TurtleShortcutException):
204 sc(f'{name}') # Missing argument
205 with pytest.raises(TurtleShortcutException):
206 sc(f'{name} 1') # Missing second argument
207 with pytest.raises(TurtleShortcutException):
208 sc(f'{name} 1 2 3') # Too many arguments
209 with pytest.raises(TurtleShortcutException):
210 sc(f'{name} 1 invalid')
211 with pytest.raises(TurtleShortcutException):
212 sc(f'{name} invalid 2')
214 assert sc(f'{name} 1 2') == 1
215 assert pos() == (1, 2)
216 assert sc(f'{name} -3 -4') == 1
217 assert pos() == (-3, -4)
218 assert sc(f'{name} 0 0') == 1
219 assert pos() == (0, 0)
220 assert sc(f'{name} 0.5 0.5') == 1
221 assert pos() == (0.5, 0.5)
222 assert sc(f'{name} -0.5 -0.5') == 1
223 assert pos() == (-0.5, -0.5)
226def test_setx():
227 for name in ('x', 'setx', 'X', 'SETX', 'sEtX'):
228 reset()
230 with pytest.raises(TurtleShortcutException):
231 sc(f'{name}') # Missing argument
232 with pytest.raises(TurtleShortcutException):
233 sc(f'{name} 1 2') # Too many arguments
234 with pytest.raises(TurtleShortcutException):
235 sc(f'{name} invalid') # Invalid argument
237 assert sc(f'{name} 1') == 1
238 assert pos() == (1, 0)
239 assert sc(f'{name} -2') == 1
240 assert pos() == (-2, 0)
241 assert sc(f'{name} 0.5') == 1
242 assert pos() == (0.5, 0)
243 assert sc(f'{name} -0.5') == 1
244 assert pos() == (-0.5, 0)
246 sety(10)
247 assert sc(f'{name} 1') == 1
248 assert pos() == (1, 10)
251def test_sety():
252 for name in ('y', 'sety', 'Y', 'SETY', 'sEtY'):
253 reset()
255 with pytest.raises(TurtleShortcutException):
256 sc(f'{name}') # Missing argument
257 with pytest.raises(TurtleShortcutException):
258 sc(f'{name} 1 2') # Too many arguments
259 with pytest.raises(TurtleShortcutException):
260 sc(f'{name} invalid') # Invalid argument
262 assert sc(f'{name} 1') == 1
263 assert pos() == (0, 1)
264 assert sc(f'{name} -2') == 1
265 assert pos() == (0, -2)
266 assert sc(f'{name} 0.5') == 1
267 assert pos() == (0, 0.5)
268 assert sc(f'{name} -0.5') == 1
269 assert pos() == (0, -0.5)
271 setx(10)
272 assert sc(f'{name} 1') == 1
273 assert pos() == (10, 1)
277def test_pendown():
278 for name in ('pd', 'pendown', 'PD', 'PENDOWN', 'pEnDoWn'):
279 with pytest.raises(TurtleShortcutException):
280 sc(f'{name} 1') # Too many arguments
282 penup()
283 assert sc(f'{name}') == 1
284 assert isdown()
287def test_penup():
288 for name in ('pu', 'penup', 'PU', 'PENUP', 'pEnUp'):
289 with pytest.raises(TurtleShortcutException):
290 sc(f'{name} 1') # Too many arguments
292 pendown()
293 assert sc(f'{name}') == 1
294 assert not isdown()
297def test_pensize():
298 for name in ('ps', 'pensize', 'PS', 'PENSIZE', 'pEnSiZe'):
299 with pytest.raises(TurtleShortcutException):
300 sc(f'{name}') # Missing argument
301 with pytest.raises(TurtleShortcutException):
302 sc(f'{name} 1 2') # Too many arguments
303 with pytest.raises(TurtleShortcutException):
304 sc(f'{name} invalid') # Invalid argument
306 assert sc(f'{name} 10') == 1
307 assert pensize() == 10
309 assert sc(f'{name} 1.5') == 1
310 assert pensize() == 1.5
312 pensize(1)
315def test_stamp():
316 for name in ('st', 'stamp', 'ST', 'STAMP', 'sTaMp'):
317 reset()
319 with pytest.raises(TurtleShortcutException):
320 sc(f'{name} 1') # Too many arguments
322 assert sc(f'{name}') == 1
325def test_pencolor_fillcolor_bgcolor():
326 for name in ('pc', 'pencolor', 'PC', 'PENCOLOR', 'pEnCoLoR', 'fc', 'fillcolor', 'FC', 'FILLCOLOR', 'fIlLcOlOr', 'bc', 'bgcolor', 'BC', 'BGCOLOR', 'bGcOlOr'):
327 function_to_test = None
328 if name.lower().startswith('p'):
329 function_to_test = pencolor
330 elif name.lower().startswith('f'):
331 function_to_test = fillcolor
332 elif name.lower().startswith('b'):
333 function_to_test = bgcolor
335 with pytest.raises(TurtleShortcutException):
336 sc(f'{name}') # Missing argument
338 with pytest.raises(TurtleShortcutException):
339 sc(f'{name} 1 2') # Too many arguments
341 with pytest.raises(TurtleShortcutException):
342 sc(f'{name} FF0000') # Missing the leading # for hex colors
344 with pytest.raises(TurtleShortcutException):
345 sc(f'{name} invalid 0 0') # Invalid argument
346 with pytest.raises(TurtleShortcutException):
347 sc(f'{name} 0 invalid 0') # Invalid argument
348 with pytest.raises(TurtleShortcutException):
349 sc(f'{name} 0 0 invalid') # Invalid argument
352 colormode(1.0) # Set to 1.0 for testing
354 function_to_test('black') # Reset to black
355 assert sc(f'{name} red') == 1
356 assert function_to_test() == 'red'
358 function_to_test('black') # Reset to black
359 assert sc(f'{name} red') == 1
360 assert function_to_test() == 'red'
362 function_to_test('black') # Reset to black
363 assert sc(f'{name} 1 0 0') == 1
364 assert function_to_test() == (1.0, 0.0, 0.0)
366 function_to_test('black') # Reset to black
367 assert sc(f'{name} 1.0 0.0 0.0') == 1
368 assert function_to_test() == (1.0, 0.0, 0.0)
370 with pytest.raises(TurtleShortcutException):
371 sc(f'{name} 255 0 0')
373 colormode(1.0)
374 assert function_to_test() != (0, 255, 0) # Make sure it's not returning a 255 mode value.
376 for color_mode_setting in (255, 1.0):
377 colormode(color_mode_setting)
378 for color_name in 'black blue brown orange gray grey green purple violet pink yellow white red magenta cyan'.split():
379 assert sc(f'{name} {color_name}') == 1 # Set the color
380 assert function_to_test() == color_name # Test that the color was set
382 colormode(255)
383 assert sc(f'{name} #FF0000') == 1
384 assert function_to_test() == (255, 0, 0.0)
386 colormode(1)
387 assert sc(f'{name} #FF0000') == 1
388 assert function_to_test() == (1, 0, 0.0)
390 with pytest.raises(TurtleShortcutException):
391 sc(f'{name} xxyyzz') # Invalid color name
395def test_circle():
396 for name in ('cir', 'circle', 'CIR', 'CIRCLE', 'cIrClE'):
397 reset()
399 with pytest.raises(TurtleShortcutException):
400 sc(f'{name}') # Missing argument
401 with pytest.raises(TurtleShortcutException):
402 sc(f'{name} 1 2') # Too many arguments
403 with pytest.raises(TurtleShortcutException):
404 sc(f'{name} invalid') # Invalid argument
406 # The (int(pos()[0]), int(pos()[1])) stuff is because Vec2D objects
407 # returned from pos() consider (-0.00, -0.00) as not equal to (0, 0).
409 assert sc(f'{name} 1') == 1
410 assert (int(pos()[0]), int(pos()[1])) == (0, 0)
412 assert sc(f'{name} 10') == 1
413 assert (int(pos()[0]), int(pos()[1])) == (0, 0)
415 assert sc(f'{name} 10.5') == 1
416 assert (int(pos()[0]), int(pos()[1])) == (0, 0)
418 assert sc(f'{name} -1') == 1
419 assert (int(pos()[0]), int(pos()[1])) == (0, 0)
421 assert sc(f'{name} -10') == 1
422 assert (int(pos()[0]), int(pos()[1])) == (0, 0)
424 assert sc(f'{name} -10.5') == 1
425 assert (int(pos()[0]), int(pos()[1])) == (0, 0)
427 assert sc(f'{name} 0') == 1
428 assert (int(pos()[0]), int(pos()[1])) == (0, 0)
431def test_undo():
432 for name in ('undo', 'UNDO', 'uNdO'):
433 reset()
435 with pytest.raises(TurtleShortcutException):
436 sc(f'{name} 1') # Too many arguments
438 assert sc(f'{name}') == 1
441def test_begin_fill_end():
442 for name in ('bf', 'begin_fill', 'BF', 'BEGIN_FILL', 'bEgIn_FiLl'):
443 with pytest.raises(TurtleShortcutException):
444 sc(f'{name} 1') # Too many arguments
446 assert sc(f'{name}') == 1
447 end_fill()
450def test_end_fill():
451 for name in ('ef', 'end_fill', 'EF', 'END_FILL', 'eNd_FiLl'):
452 with pytest.raises(TurtleShortcutException):
453 sc(f'{name} 1') # Too many arguments
455 begin_fill()
456 assert sc(f'{name}') == 1
459def test_reset():
460 for name in ('reset', 'RESET', 'rEsEt'):
461 with pytest.raises(TurtleShortcutException):
462 sc(f'{name} 1') # Too many arguments
464 assert sc(f'{name}') == 1
467def test_sleep_sc():
468 for name in ('sleep', 'SLEEP', 'sLeEp'):
469 with pytest.raises(TurtleShortcutException):
470 sc(f'{name}')
475def test_move_turn():
476 # Test the move and turn commands:
478 # Test home/h:
479 goto(1, 0)
480 assert sc('h') == 1
481 assert (int(pos()[0]), int(pos()[1])) == (0, 0)
483 goto(1, 0)
484 assert sc('home') == 1
485 assert (int(pos()[0]), int(pos()[1])) == (0, 0)
487 with pytest.raises(TurtleShortcutException):
488 sc('h 1')
490 # Test f/b forward/backward l/r left/right:
491 assert sc('f 1') == 1
492 assert (int(pos()[0]), int(pos()[1])) == (1, 0)
494 assert sc('forward 1') == 1
495 assert (int(pos()[0]), int(pos()[1])) == (2, 0)
497 assert sc('b 1') == 1
498 assert (int(pos()[0]), int(pos()[1])) == (1, 0)
500 assert sc('backward 1') == 1
501 assert (int(pos()[0]), int(pos()[1])) == (0, 0)
503 assert sc('l 90') == 1
504 assert heading() == 90
506 assert sc('left 90') == 1
507 assert heading() == 180
509 assert sc('r 90') == 1
510 assert heading() == 90
512 assert sc('right 90') == 1
513 assert heading() == 0
515 assert sc('sh 42') == 1
516 assert heading() == 42
517 assert sc('sh 0') == 1
518 assert heading() == 0
520 assert sc('f -1') == 1
521 assert (int(pos()[0]), int(pos()[1])) == (-1, 0)
523 assert sc('b -1') == 1
524 assert (int(pos()[0]), int(pos()[1])) == (0, 0)
526 assert sc('l -90') == 1
527 assert heading() == 270
529 assert sc('r -90') == 1
530 assert heading() == 0
532 assert sc('r 0') == 1
533 assert heading() == 0
535 assert sc('r 360') == 1
536 assert heading() == 0
538 assert sc('r 720') == 1
539 assert heading() == 0
541 assert sc('r -360') == 1
542 assert heading() == 0
544 assert sc('r -720') == 1
545 assert heading() == 0
547 assert sc('l 0') == 1
548 assert heading() == 0
550 assert sc('l 360') == 1
551 assert heading() == 0
553 assert sc('l 720') == 1
554 assert heading() == 0
556 assert sc('l -360') == 1
557 assert heading() == 0
559 assert sc('l -720') == 1
560 assert heading() == 0
562 assert sc('c') == 1
563 assert sc('clear') == 1
565 # Test g and goto:
566 assert sc('g 10 20') == 1
567 assert (int(pos()[0]), int(pos()[1])) == (10, 20)
569 assert sc('goto -30 -40') == 1
570 assert (int(pos()[0]), int(pos()[1])) == (-30, -40)
572 with pytest.raises(TurtleShortcutException):
573 sc('goto 10')
575 with pytest.raises(TurtleShortcutException):
576 sc('goto 10 invalid')
578 with pytest.raises(TurtleShortcutException):
579 sc('goto invalid 20')
581 with pytest.raises(TurtleShortcutException):
582 sc('goto invalid invalid')
584 with pytest.raises(TurtleShortcutException):
585 sc('g')
587 assert sc('x 100') == 1
588 assert (int(pos()[0]), int(pos()[1])) == (100, -40)
590 assert sc('y 200') == 1
591 assert (int(pos()[0]), int(pos()[1])) == (100, 200)
593 assert sc('setx 300') == 1
594 assert (int(pos()[0]), int(pos()[1])) == (300, 200)
596 assert sc('sety 400') == 1
597 assert (int(pos()[0]), int(pos()[1])) == (300, 400)
599 with pytest.raises(TurtleShortcutException):
600 sc('setx invalid')
602 with pytest.raises(TurtleShortcutException):
603 sc('sety invalid')
605 with pytest.raises(TurtleShortcutException):
606 sc('x invalid')
608 with pytest.raises(TurtleShortcutException):
609 sc('y invalid')
611def test_cardinal_directions_nsew():
612 # Test calling a function while in radians mode:
613 reset()
614 radians()
615 assert sc(f'n 100') == 1
616 assert (int(pos()[0]), int(pos()[1])) == (0, 100)
617 degrees()
619 for n, s, e, w, nw, ne, sw, se in ('n s e w nw ne sw se'.split(),
620 'north south east west northwest northeast southwest southeast'.split(),
621 'N S E W NW NE SW SE'.split(),
622 'NORTH SOUTH EAST WEST NORTHWEST NORTHEAST SOUTHWEST SOUTHEAST'.split()):
623 reset()
624 assert sc(f'{n} 100') == 1
625 assert (int(pos()[0]), int(pos()[1])) == (0, 100)
626 assert sc(f'{n} -100') == 1
627 assert (int(pos()[0]), int(pos()[1])) == (0, 0)
629 reset()
630 assert sc(f'{s} 100') == 1
631 assert (int(pos()[0]), int(pos()[1])) == (0, -100)
632 assert sc(f'{s} -100') == 1
633 assert (int(pos()[0]), int(pos()[1])) == (0, 0)
635 reset()
636 assert sc(f'{e} 100') == 1
637 assert (int(pos()[0]), int(pos()[1])) == (100, 0)
638 assert sc(f'{e} -100') == 1
639 assert (int(pos()[0]), int(pos()[1])) == (0, 0)
641 reset()
642 assert sc(f'{w} 100') == 1
643 assert (int(pos()[0]), int(pos()[1])) == (-100, 0)
644 assert sc(f'{w} -100') == 1
645 assert (int(pos()[0]), int(pos()[1])) == (0, 0)
647 reset()
648 assert sc(f'{nw} 100') == 1
649 assert (int(pos()[0]), int(pos()[1])) == (-70, 70)
650 assert sc(f'{nw} -100') == 1
651 assert (int(pos()[0]), int(pos()[1])) == (0, 0)
653 reset()
654 assert sc(f'{ne} 100') == 1
655 assert (int(pos()[0]), int(pos()[1])) == (70, 70)
656 assert sc(f'{ne} -100') == 1
657 assert (int(pos()[0]), int(pos()[1])) == (0, 0)
659 reset()
660 assert sc(f'{sw} 100') == 1
661 assert (int(pos()[0]), int(pos()[1])) == (-70, -70)
662 assert sc(f'{sw} -100') == 1
663 assert (int(pos()[0]), int(pos()[1])) == (0, 0)
665 reset()
666 assert sc(f'{se} 100') == 1
667 assert (int(pos()[0]), int(pos()[1])) == (70, -70)
668 assert sc(f'{se} -100') == 1
669 assert (int(pos()[0]), int(pos()[1])) == (0, 0)
672def test_sleep():
673 with pytest.raises(TurtleShortcutException):
674 sc('sleep') # Missing argument
675 with pytest.raises(TurtleShortcutException):
676 sc('sleep 1 2') # Too many arguments
677 with pytest.raises(TurtleShortcutException):
678 sc('sleep invalid') # Invalid argument
680 assert sc('sleep 1') == 1
681 assert sc('sleep 0.1') == 1
683def test_tracer_update():
684 orig_tracer = tracer()
685 orig_delay = delay()
687 for name in ('t', 'T', 'tracer', 'TRACER', 'tRaCeR'):
688 with pytest.raises(TurtleShortcutException):
689 sc('{name}') # Missing argument
690 with pytest.raises(TurtleShortcutException):
691 sc('{name} 1 2 3') # Too many arguments
692 with pytest.raises(TurtleShortcutException):
693 sc('{name} invalid 0')
694 with pytest.raises(TurtleShortcutException):
695 sc('{name} 0 invalid')
697 assert sc(f'{name} 123 1') == 1
698 assert tracer() == 123
699 assert delay() == 1
701 for name in ('u', 'U', 'update', 'UPDATE', 'uPdAtE'):
702 with pytest.raises(TurtleShortcutException):
703 sc('{name} 1') # Too many arguments
705 assert sc(f'{name}') == 1
707 tracer(orig_tracer, orig_delay)
710def test_show_hide():
711 for name in ('show', 'SHOW', 'sHoW'):
712 with pytest.raises(TurtleShortcutException):
713 sc(f'{name} 1') # Too many arguments
715 assert sc(f'{name}') == 1
716 assert isvisible()
718 for name in ('hide', 'HIDE', 'hIdE'):
719 with pytest.raises(TurtleShortcutException):
720 sc(f'{name} 1') # Too many arguments
722 assert sc(f'{name}') == 1
723 assert not isvisible()
726def test_dot():
727 for name in ('dot', 'DOT', 'dOt'):
728 with pytest.raises(TurtleShortcutException):
729 sc(f'{name}') # Missing argument
730 with pytest.raises(TurtleShortcutException):
731 sc(f'{name} 1 2') # Too many arguments
732 with pytest.raises(TurtleShortcutException):
733 sc(f'{name} invalid') # Invalid argument
734 with pytest.raises(TurtleShortcutException):
735 sc(f'{name} -1') # Invalid argument
738 assert sc(f'{name} 1') == 1
739 assert sc(f'{name} 10') == 1
740 assert sc(f'{name} 10.5') == 1
741 assert sc(f'{name} 0') == 1
744def test_clearstamp():
745 for name in ('cs', 'clearstamp', 'CS', 'CLEARSTAMP', 'cLeArStAmP'):
746 with pytest.raises(TurtleShortcutException):
747 sc(f'{name} 1 2') # Too many arguments
748 with pytest.raises(TurtleShortcutException):
749 sc(f'{name}') # Missing argument
750 with pytest.raises(TurtleShortcutException):
751 sc(f'{name} invalid') # Invalid argument
753 stamp_id = stamp()
754 assert sc(f'{name} {stamp_id}') == 1
757def test_clearstamps():
758 for name in ('css', 'clearstamps', 'CSS', 'CLEARSTAMPS', 'cLeArStAmPs'):
759 with pytest.raises(TurtleShortcutException):
760 sc(f'{name} 1 2') # Too many arguments
761 with pytest.raises(TurtleShortcutException):
762 sc(f'{name} invalid') # Invalid argument
764 assert sc(f'{name} 0') == 1
765 assert sc(f'{name} 2') == 1
766 assert sc(f'{name} -2') == 1
767 assert sc(f'{name}') == 1
769def test_speed():
770 for name in ('speed', 'SPEED', 'sPeEd'):
771 with pytest.raises(TurtleShortcutException):
772 sc(f'{name}') # Missing argument
773 with pytest.raises(TurtleShortcutException):
774 sc(f'{name} 1 2') # Too many arguments
775 with pytest.raises(TurtleShortcutException):
776 sc(f'{name} invalid') # Invalid argument
778 # Test numeric settings 0 to 10:
779 for speed_setting in tuple(range(11)):
780 assert sc(f'{name} {speed_setting}') == 1
781 assert speed() == speed_setting
782 # Test string settings:
783 for speed_setting, numeric_equivalent in {'fastest': 0, 'fast': 10, 'normal': 6, 'slow': 3, 'slowest': 1, 'FASTEST': 0, 'FAST': 10, 'NORMAL': 6, 'SLOW': 3, 'SLOWEST': 1}.items():
784 assert sc(f'{name} {speed_setting}') == 1
785 assert speed() == numeric_equivalent
787 tracer(10000, 0) # Restore the original tracer settings for other tests.
790def test_scs():
791 assert scs('f 100') == 'forward(100)'
792 assert scs('b 100') == 'backward(100)'
793 assert scs('l 90') == 'left(90)'
794 assert scs('r 90') == 'right(90)'
795 assert scs('g 100 200') == 'goto(100, 200)'
796 assert scs('sh 90') == 'setheading(90)'
797 assert scs('pu') == 'penup()'
798 assert scs('pd') == 'pendown()'
799 assert scs('ps 10') == 'pensize(10)'
800 assert scs('bf') == 'begin_fill()'
801 assert scs('ef') == 'end_fill()'
802 assert scs('reset') == 'reset()'
803 assert scs('sleep 1') == 'sleep(1)'
804 assert scs('t 100 0') == 'tracer(100, 0)'
805 assert scs('u') == 'update()'
806 assert scs('show') == 'showturtle()'
807 assert scs('hide') == 'hideturtle()'
808 assert scs('dot 10') == 'dot(10)'
809 assert scs('cs 1') == 'clearstamp(1)'
810 assert scs('css') == 'clearstamps()'
811 assert scs('css 1') == 'clearstamps(1)'
812 assert scs('st') == 'stamp()'
813 assert scs('speed 1') == 'speed(1)'
814 assert scs('home') == 'home()'
815 assert scs('x 100') == 'setx(100)'
816 assert scs('y 100') == 'sety(100)'
817 assert scs('setx 100') == 'setx(100)'
818 assert scs('sety 100') == 'sety(100)'
819 assert scs('c') == 'clear()'
820 assert scs('undo') == 'undo()'
821 assert scs('cir 100') == 'circle(100)'
822 assert scs('g 100 200') == 'goto(100, 200)'
823 assert scs('tele 100 200') == 'teleport(100, 200)'
825 assert scs('pc red') == "pencolor('red')"
826 assert scs('fc red') == "fillcolor('red')"
827 assert scs('bc red') == "bgcolor('red')"
829 colormode(255)
830 assert scs('pc red') == "pencolor('red')"
831 assert scs('pc 255 0 0') == 'pencolor((255, 0, 0))'
832 assert scs('fc 255 0 0') == 'fillcolor((255, 0, 0))'
833 assert scs('bc 255 0 0') == 'bgcolor((255, 0, 0))'
835 colormode(1.0)
836 assert scs('pc red') == "pencolor('red')"
837 with pytest.raises(TurtleShortcutException):
838 scs('pc 255 0 0')
839 with pytest.raises(TurtleShortcutException):
840 scs('fc 255 0 0')
841 with pytest.raises(TurtleShortcutException):
842 scs('bc 255 0 0')
844 assert scs('pc 1.0 0.0 0.0') == 'pencolor((1.0, 0.0, 0.0))'
845 assert scs('fc 1.0 0.0 0.0') == 'fillcolor((1.0, 0.0, 0.0))'
846 assert scs('bc 1.0 0.0 0.0') == 'bgcolor((1.0, 0.0, 0.0))'
848 degrees()
849 assert scs('n 100') == 'setheading(90)\nforward(100)'
850 assert scs('s 100') == 'setheading(270)\nforward(100)'
851 assert scs('e 100') == 'setheading(0)\nforward(100)'
852 assert scs('w 100') == 'setheading(180)\nforward(100)'
853 assert scs('nw 100') == 'setheading(135)\nforward(100)'
854 assert scs('ne 100') == 'setheading(45)\nforward(100)'
855 assert scs('sw 100') == 'setheading(225)\nforward(100)'
856 assert scs('se 100') == 'setheading(315)\nforward(100)'
857 assert scs('north 100') == 'setheading(90)\nforward(100)'
858 assert scs('south 100') == 'setheading(270)\nforward(100)'
859 assert scs('east 100') == 'setheading(0)\nforward(100)'
860 assert scs('west 100') == 'setheading(180)\nforward(100)'
861 assert scs('northwest 100') == 'setheading(135)\nforward(100)'
862 assert scs('northeast 100') == 'setheading(45)\nforward(100)'
863 assert scs('southwest 100') == 'setheading(225)\nforward(100)'
864 assert scs('southeast 100') == 'setheading(315)\nforward(100)'
865 assert scs('N 100') == 'setheading(90)\nforward(100)'
866 assert scs('S 100') == 'setheading(270)\nforward(100)'
867 assert scs('E 100') == 'setheading(0)\nforward(100)'
868 assert scs('W 100') == 'setheading(180)\nforward(100)'
869 assert scs('NW 100') == 'setheading(135)\nforward(100)'
870 assert scs('NE 100') == 'setheading(45)\nforward(100)'
871 assert scs('SW 100') == 'setheading(225)\nforward(100)'
872 assert scs('SE 100') == 'setheading(315)\nforward(100)'
873 assert scs('NORTH 100') == 'setheading(90)\nforward(100)'
874 assert scs('SOUTH 100') == 'setheading(270)\nforward(100)'
875 assert scs('EAST 100') == 'setheading(0)\nforward(100)'
876 assert scs('WEST 100') == 'setheading(180)\nforward(100)'
877 assert scs('NORTHWEST 100') == 'setheading(135)\nforward(100)'
878 assert scs('NORTHEAST 100') == 'setheading(45)\nforward(100)'
879 assert scs('SOUTHWEST 100') == 'setheading(225)\nforward(100)'
880 assert scs('SOUTHEAST 100') == 'setheading(315)\nforward(100)'
881 assert scs('n 100, f 100') == 'setheading(90)\nforward(100)\nforward(100)'
882 assert scs('n 100, f 100, f 100') == 'setheading(90)\nforward(100)\nforward(100)\nforward(100)'
884 radians()
885 assert scs('n 100') == 'degrees()\nsetheading(90)\nforward(100)\nradians()'
886 assert scs('s 100') == 'degrees()\nsetheading(270)\nforward(100)\nradians()'
887 assert scs('e 100') == 'degrees()\nsetheading(0)\nforward(100)\nradians()'
888 assert scs('w 100') == 'degrees()\nsetheading(180)\nforward(100)\nradians()'
889 assert scs('nw 100') == 'degrees()\nsetheading(135)\nforward(100)\nradians()'
890 assert scs('ne 100') == 'degrees()\nsetheading(45)\nforward(100)\nradians()'
891 assert scs('sw 100') == 'degrees()\nsetheading(225)\nforward(100)\nradians()'
892 assert scs('se 100') == 'degrees()\nsetheading(315)\nforward(100)\nradians()'
894 degrees()
897def test_psc(capsys):
898 psc('f 100')
899 assert capsys.readouterr().out == 'forward(100)\n'
900 psc('b 100')
901 assert capsys.readouterr().out == 'backward(100)\n'
902 psc('l 90')
903 assert capsys.readouterr().out == 'left(90)\n'
904 psc('r 90')
905 assert capsys.readouterr().out == 'right(90)\n'
906 psc('g 100 200')
907 assert capsys.readouterr().out == 'goto(100, 200)\n'
908 psc('sh 90')
909 assert capsys.readouterr().out == 'setheading(90)\n'
910 psc('pu')
911 assert capsys.readouterr().out == 'penup()\n'
912 psc('pd')
913 assert capsys.readouterr().out == 'pendown()\n'
914 psc('ps 10')
915 assert capsys.readouterr().out == 'pensize(10)\n'
916 psc('bf')
917 assert capsys.readouterr().out == 'begin_fill()\n'
918 psc('ef')
919 assert capsys.readouterr().out == 'end_fill()\n'
920 psc('reset')
921 assert capsys.readouterr().out == 'reset()\n'
922 psc('sleep 1')
923 assert capsys.readouterr().out == 'sleep(1)\n'
924 psc('t 100 0')
925 assert capsys.readouterr().out == 'tracer(100, 0)\n'
926 psc('u')
927 assert capsys.readouterr().out == 'update()\n'
928 psc('show')
929 assert capsys.readouterr().out == 'showturtle()\n'
930 psc('hide')
931 assert capsys.readouterr().out == 'hideturtle()\n'
932 psc('dot 10')
933 assert capsys.readouterr().out == 'dot(10)\n'
934 psc('cs 1')
935 assert capsys.readouterr().out == 'clearstamp(1)\n'
936 psc('css')
937 assert capsys.readouterr().out == 'clearstamps()\n'
938 psc('css 1')
939 assert capsys.readouterr().out == 'clearstamps(1)\n'
940 psc('st')
941 assert capsys.readouterr().out == 'stamp()\n'
942 psc('speed 1')
943 assert capsys.readouterr().out == 'speed(1)\n'
944 psc('home')
945 assert capsys.readouterr().out == 'home()\n'
946 psc('x 100')
947 assert capsys.readouterr().out == 'setx(100)\n'
948 psc('y 100')
949 assert capsys.readouterr().out == 'sety(100)\n'
950 psc('setx 100')
951 assert capsys.readouterr().out == 'setx(100)\n'
952 psc('sety 100')
953 assert capsys.readouterr().out == 'sety(100)\n'
954 psc('c')
955 assert capsys.readouterr().out == 'clear()\n'
956 psc('undo')
957 assert capsys.readouterr().out == 'undo()\n'
958 psc('cir 100')
959 assert capsys.readouterr().out == 'circle(100)\n'
960 psc('g 100 200')
961 assert capsys.readouterr().out == 'goto(100, 200)\n'
962 psc('tele 100 200')
963 assert capsys.readouterr().out == 'teleport(100, 200)\n'
965 psc('pc red')
966 assert capsys.readouterr().out == "pencolor('red')\n"
967 psc('fc red')
968 assert capsys.readouterr().out == "fillcolor('red')\n"
969 psc('bc red')
970 assert capsys.readouterr().out == "bgcolor('red')\n"
972 colormode(255)
973 psc('pc red')
974 assert capsys.readouterr().out == "pencolor('red')\n"
975 psc('pc 255 0 0')
976 assert capsys.readouterr().out == 'pencolor((255, 0, 0))\n'
977 psc('fc 255 0 0')
978 assert capsys.readouterr().out == 'fillcolor((255, 0, 0))\n'
979 psc('bc 255 0 0')
980 assert capsys.readouterr().out == 'bgcolor((255, 0, 0))\n'
982 colormode(1.0)
983 psc('pc red')
984 assert capsys.readouterr().out == "pencolor('red')\n"
985 with pytest.raises(TurtleShortcutException):
986 psc('pc 255 0 0')
987 with pytest.raises(TurtleShortcutException):
988 psc('fc 255 0 0')
989 with pytest.raises(TurtleShortcutException):
990 psc('bc 255 0 0')
992 psc('pc 1.0 0.0 0.0')
993 assert capsys.readouterr().out == 'pencolor((1.0, 0.0, 0.0))\n'
994 psc('fc 1.0 0.0 0.0')
995 assert capsys.readouterr().out == 'fillcolor((1.0, 0.0, 0.0))\n'
996 psc('bc 1.0 0.0 0.0')
997 assert capsys.readouterr().out == 'bgcolor((1.0, 0.0, 0.0))\n'
999 degrees()
1000 psc('n 100')
1001 assert capsys.readouterr().out == 'setheading(90)\nforward(100)\n'
1002 psc('s 100')
1003 assert capsys.readouterr().out == 'setheading(270)\nforward(100)\n'
1004 psc('e 100')
1005 assert capsys.readouterr().out == 'setheading(0)\nforward(100)\n'
1006 psc('w 100')
1007 assert capsys.readouterr().out == 'setheading(180)\nforward(100)\n'
1008 psc('nw 100')
1009 assert capsys.readouterr().out == 'setheading(135)\nforward(100)\n'
1010 psc('ne 100')
1011 assert capsys.readouterr().out == 'setheading(45)\nforward(100)\n'
1012 psc('sw 100')
1013 assert capsys.readouterr().out == 'setheading(225)\nforward(100)\n'
1014 psc('se 100')
1015 assert capsys.readouterr().out == 'setheading(315)\nforward(100)\n'
1016 psc('north 100')
1017 assert capsys.readouterr().out == 'setheading(90)\nforward(100)\n'
1018 psc('south 100')
1019 assert capsys.readouterr().out == 'setheading(270)\nforward(100)\n'
1020 psc('east 100')
1021 assert capsys.readouterr().out == 'setheading(0)\nforward(100)\n'
1022 psc('west 100')
1023 assert capsys.readouterr().out == 'setheading(180)\nforward(100)\n'
1024 psc('northwest 100')
1025 assert capsys.readouterr().out == 'setheading(135)\nforward(100)\n'
1026 psc('northeast 100')
1027 assert capsys.readouterr().out == 'setheading(45)\nforward(100)\n'
1028 psc('southwest 100')
1029 assert capsys.readouterr().out == 'setheading(225)\nforward(100)\n'
1030 psc('southeast 100')
1031 assert capsys.readouterr().out == 'setheading(315)\nforward(100)\n'
1032 psc('N 100')
1033 assert capsys.readouterr().out == 'setheading(90)\nforward(100)\n'
1034 psc('S 100')
1035 assert capsys.readouterr().out == 'setheading(270)\nforward(100)\n'
1036 psc('E 100')
1037 assert capsys.readouterr().out == 'setheading(0)\nforward(100)\n'
1038 psc('W 100')
1039 assert capsys.readouterr().out == 'setheading(180)\nforward(100)\n'
1040 psc('NW 100')
1041 assert capsys.readouterr().out == 'setheading(135)\nforward(100)\n'
1042 psc('NE 100')
1043 assert capsys.readouterr().out == 'setheading(45)\nforward(100)\n'
1044 psc('SW 100')
1045 assert capsys.readouterr().out == 'setheading(225)\nforward(100)\n'
1046 psc('SE 100')
1047 assert capsys.readouterr().out == 'setheading(315)\nforward(100)\n'
1048 psc('NORTH 100')
1049 assert capsys.readouterr().out == 'setheading(90)\nforward(100)\n'
1050 psc('SOUTH 100')
1051 assert capsys.readouterr().out == 'setheading(270)\nforward(100)\n'
1052 psc('EAST 100')
1053 assert capsys.readouterr().out == 'setheading(0)\nforward(100)\n'
1054 psc('WEST 100')
1055 assert capsys.readouterr().out == 'setheading(180)\nforward(100)\n'
1056 psc('NORTHWEST 100')
1057 assert capsys.readouterr().out == 'setheading(135)\nforward(100)\n'
1058 psc('NORTHEAST 100')
1059 assert capsys.readouterr().out == 'setheading(45)\nforward(100)\n'
1060 psc('SOUTHWEST 100')
1061 assert capsys.readouterr().out == 'setheading(225)\nforward(100)\n'
1062 psc('SOUTHEAST 100')
1063 assert capsys.readouterr().out == 'setheading(315)\nforward(100)\n'
1064 psc('n 100, f 100')
1065 assert capsys.readouterr().out == 'setheading(90)\nforward(100)\nforward(100)\n'
1066 psc('n 100, f 100, f 100')
1067 assert capsys.readouterr().out == 'setheading(90)\nforward(100)\nforward(100)\nforward(100)\n'
1069 radians()
1070 psc('n 100')
1071 assert capsys.readouterr().out == 'degrees()\nsetheading(90)\nforward(100)\nradians()\n'
1072 psc('s 100')
1073 assert capsys.readouterr().out == 'degrees()\nsetheading(270)\nforward(100)\nradians()\n'
1074 psc('e 100')
1075 assert capsys.readouterr().out == 'degrees()\nsetheading(0)\nforward(100)\nradians()\n'
1076 psc('w 100')
1077 assert capsys.readouterr().out == 'degrees()\nsetheading(180)\nforward(100)\nradians()\n'
1078 psc('nw 100')
1079 assert capsys.readouterr().out == 'degrees()\nsetheading(135)\nforward(100)\nradians()\n'
1080 psc('ne 100')
1081 assert capsys.readouterr().out == 'degrees()\nsetheading(45)\nforward(100)\nradians()\n'
1082 psc('sw 100')
1083 assert capsys.readouterr().out == 'degrees()\nsetheading(225)\nforward(100)\nradians()\n'
1084 psc('se 100')
1085 assert capsys.readouterr().out == 'degrees()\nsetheading(315)\nforward(100)\nradians()\n'
1087 degrees()
1090def test_skip(capsys):
1091 turtle.home()
1092 assert sc('f 100', skip=True) == 0
1093 assert turtle.pos() == (0, 0)
1094 assert sc('f 100', skip=True, _return_turtle_code=True) == ()
1097def test_comment():
1098 assert sc('# ignore 123 abc') == 0
1099 assert sc('f 100, # ignore this') == 1
1100 assert sc('f 100, # ignore this, b 100') == 2
1101 assert sc('f 100, # ignore this, b 100, # ignore this') == 2
1102 assert sc('f 100, # ignore this, b 100, # ignore this, f 100') == 3
1105def test_recording():
1106 begin_recording()
1107 assert RECORDED_SHORTCUTS == []
1108 assert sc('f 100, l 90, f 100, l 90, # foobar, f 100') == 5
1109 assert end_recording() == ['f 100', ' l 90', ' f 100', ' l 90', ' # foobar', ' f 100']
1110 begin_recording()
1111 assert RECORDED_SHORTCUTS == []
1115# EXAMPLE PROGRAMS:
1117def test_colorful_squares():
1118 colormode(1.0)
1119 sc('t 1000 0, ps 4')
1121 for i in range(100): # Draw 100 squares.
1122 # Move to a random place:
1123 sc(f'pu,g {randint(-400, 200)} {randint(-400, 200)},pd,fc {random()} {random()} {random()}, pc {random()} {random()} {random()}')
1124 line_length = randint(20, 200)
1126 # Draw the filled-in square:
1127 sc('bf')
1128 for j in range(4):
1129 sc(f'f {line_length}, l 90')
1130 sc('ef')
1132 sc('u,reset')
1135def test_draw_circles():
1136 sc('t 1000 0, ps 1')
1138 # Draw circle in the top half of the window:
1139 sc('sh 0') # Face right.
1140 for i in range(20):
1141 sc(f'cir {i * 10}')
1143 # Draw circles in the bottom half of the window:
1144 sc('sh 180') # Face left.
1145 for i in range(20):
1146 sc(f'cir {i * 10}')
1147 sc('u,reset')
1150def test_curve_path_filled():
1151 sc('t 1000 0, ps 1')
1152 colormode(1.0)
1153 for i in range(50):
1154 sc(f'fc {random()} {random()} {random()}')
1156 # Set a random heading and draw several short lines with changing direction:
1157 sc(f'sh {randint(0, 360)}, bf')
1159 for j in range(randint(200, 600)):
1160 sc(f'f 1,l {randint(-4, 4)}')
1161 sc(f'h, ef')
1162 sc('u,reset')
1165if __name__ == '__main__':
1166 pytest.main()