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