|
12 | 12 | E_F = "Expected False, "
|
13 | 13 |
|
14 | 14 |
|
| 15 | +def float_range(a, b, step): |
| 16 | + result = [] |
| 17 | + current_value = a |
| 18 | + while current_value < b: |
| 19 | + result.append(current_value) |
| 20 | + current_value += step |
| 21 | + return result |
| 22 | + |
| 23 | + |
15 | 24 | class CircleTypeTest(unittest.TestCase):
|
16 | 25 | def testConstruction_invalid_type(self):
|
17 | 26 | """Checks whether passing wrong types to the constructor
|
@@ -1186,6 +1195,185 @@ def test_collidepolygon_no_invalidation(self):
|
1186 | 1195 | self.assertEqual(poly.centerx, poly_copy.centerx)
|
1187 | 1196 | self.assertEqual(poly.centery, poly_copy.centery)
|
1188 | 1197 |
|
| 1198 | + def test_meth_rotate_ip_invalid_argnum(self): |
| 1199 | + """Ensures that the rotate_ip method correctly deals with invalid numbers of arguments.""" |
| 1200 | + c = Circle(0, 0, 1) |
| 1201 | + |
| 1202 | + with self.assertRaises(TypeError): |
| 1203 | + c.rotate_ip() |
| 1204 | + |
| 1205 | + invalid_args = [ |
| 1206 | + (1, (2, 2), 2), |
| 1207 | + (1, (2, 2), 2, 2), |
| 1208 | + (1, (2, 2), 2, 2, 2), |
| 1209 | + (1, (2, 2), 2, 2, 2, 2), |
| 1210 | + (1, (2, 2), 2, 2, 2, 2, 2), |
| 1211 | + (1, (2, 2), 2, 2, 2, 2, 2, 2), |
| 1212 | + ] |
| 1213 | + |
| 1214 | + for args in invalid_args: |
| 1215 | + with self.assertRaises(TypeError): |
| 1216 | + c.rotate_ip(*args) |
| 1217 | + |
| 1218 | + def test_meth_rotate_ip_invalid_argtype(self): |
| 1219 | + """Ensures that the rotate_ip method correctly deals with invalid argument types.""" |
| 1220 | + c = Circle(0, 0, 1) |
| 1221 | + |
| 1222 | + invalid_args = [ |
| 1223 | + ("a",), # angle str |
| 1224 | + (None,), # angle str |
| 1225 | + ((1, 2)), # angle tuple |
| 1226 | + ([1, 2]), # angle list |
| 1227 | + (1, "a"), # origin str |
| 1228 | + (1, None), # origin None |
| 1229 | + (1, True), # origin True |
| 1230 | + (1, False), # origin False |
| 1231 | + (1, (1, 2, 3)), # origin tuple |
| 1232 | + (1, [1, 2, 3]), # origin list |
| 1233 | + (1, (1, "a")), # origin str |
| 1234 | + (1, ("a", 1)), # origin str |
| 1235 | + (1, (1, None)), # origin None |
| 1236 | + (1, (None, 1)), # origin None |
| 1237 | + (1, (1, (1, 2))), # origin tuple |
| 1238 | + (1, (1, [1, 2])), # origin list |
| 1239 | + ] |
| 1240 | + |
| 1241 | + for value in invalid_args: |
| 1242 | + with self.assertRaises(TypeError): |
| 1243 | + c.rotate_ip(*value) |
| 1244 | + |
| 1245 | + def test_meth_rotate_ip_return(self): |
| 1246 | + """Ensures that the rotate_ip method always returns None.""" |
| 1247 | + c = Circle(0, 0, 1) |
| 1248 | + |
| 1249 | + for angle in float_range(-360, 360, 1): |
| 1250 | + self.assertIsNone(c.rotate_ip(angle)) |
| 1251 | + self.assertIsInstance(c.rotate_ip(angle), type(None)) |
| 1252 | + |
| 1253 | + def test_meth_rotate_invalid_argnum(self): |
| 1254 | + """Ensures that the rotate method correctly deals with invalid numbers of arguments.""" |
| 1255 | + c = Circle(0, 0, 1) |
| 1256 | + |
| 1257 | + with self.assertRaises(TypeError): |
| 1258 | + c.rotate() |
| 1259 | + |
| 1260 | + invalid_args = [ |
| 1261 | + (1, (2, 2), 2), |
| 1262 | + (1, (2, 2), 2, 2), |
| 1263 | + (1, (2, 2), 2, 2, 2), |
| 1264 | + (1, (2, 2), 2, 2, 2, 2), |
| 1265 | + (1, (2, 2), 2, 2, 2, 2, 2), |
| 1266 | + (1, (2, 2), 2, 2, 2, 2, 2, 2), |
| 1267 | + ] |
| 1268 | + |
| 1269 | + for args in invalid_args: |
| 1270 | + with self.assertRaises(TypeError): |
| 1271 | + c.rotate(*args) |
| 1272 | + |
| 1273 | + def test_meth_rotate_invalid_argtype(self): |
| 1274 | + """Ensures that the rotate method correctly deals with invalid argument types.""" |
| 1275 | + c = Circle(0, 0, 1) |
| 1276 | + |
| 1277 | + invalid_args = [ |
| 1278 | + ("a",), # angle str |
| 1279 | + (None,), # angle str |
| 1280 | + ((1, 2)), # angle tuple |
| 1281 | + ([1, 2]), # angle list |
| 1282 | + (1, "a"), # origin str |
| 1283 | + (1, None), # origin None |
| 1284 | + (1, True), # origin True |
| 1285 | + (1, False), # origin False |
| 1286 | + (1, (1, 2, 3)), # origin tuple |
| 1287 | + (1, [1, 2, 3]), # origin list |
| 1288 | + (1, (1, "a")), # origin str |
| 1289 | + (1, ("a", 1)), # origin str |
| 1290 | + (1, (1, None)), # origin None |
| 1291 | + (1, (None, 1)), # origin None |
| 1292 | + (1, (1, (1, 2))), # origin tuple |
| 1293 | + (1, (1, [1, 2])), # origin list |
| 1294 | + ] |
| 1295 | + |
| 1296 | + for value in invalid_args: |
| 1297 | + with self.assertRaises(TypeError): |
| 1298 | + c.rotate(*value) |
| 1299 | + |
| 1300 | + def test_meth_rotate_return(self): |
| 1301 | + """Ensures that the rotate method always returns a Line.""" |
| 1302 | + c = Circle(0, 0, 1) |
| 1303 | + |
| 1304 | + class CircleSubclass(Circle): |
| 1305 | + pass |
| 1306 | + |
| 1307 | + cs = CircleSubclass(0, 0, 1) |
| 1308 | + |
| 1309 | + for angle in float_range(-360, 360, 1): |
| 1310 | + self.assertIsInstance(c.rotate(angle), Circle) |
| 1311 | + self.assertIsInstance(cs.rotate(angle), CircleSubclass) |
| 1312 | + |
| 1313 | + def test_meth_rotate(self): |
| 1314 | + """Ensures the Circle.rotate() method rotates the Circle correctly.""" |
| 1315 | + |
| 1316 | + def rotate_circle(circle: Circle, angle, center): |
| 1317 | + def rotate_point(x, y, rang, cx, cy): |
| 1318 | + x -= cx |
| 1319 | + y -= cy |
| 1320 | + x_new = x * math.cos(rang) - y * math.sin(rang) |
| 1321 | + y_new = x * math.sin(rang) + y * math.cos(rang) |
| 1322 | + return x_new + cx, y_new + cy |
| 1323 | + |
| 1324 | + angle = math.radians(angle) |
| 1325 | + cx, cy = center if center is not None else circle.center |
| 1326 | + x, y = rotate_point(circle.x, circle.y, angle, cx, cy) |
| 1327 | + return Circle(x, y, circle.r) |
| 1328 | + |
| 1329 | + def assert_approx_equal(circle1, circle2, eps=1e-12): |
| 1330 | + self.assertAlmostEqual(circle1.x, circle2.x, delta=eps) |
| 1331 | + self.assertAlmostEqual(circle1.y, circle2.y, delta=eps) |
| 1332 | + self.assertAlmostEqual(circle1.r, circle2.r, delta=eps) |
| 1333 | + |
| 1334 | + c = Circle(0, 0, 1) |
| 1335 | + angles = float_range(-360, 360, 0.5) |
| 1336 | + centers = [(a, b) for a in range(-10, 10) for b in range(-10, 10)] |
| 1337 | + for angle in angles: |
| 1338 | + assert_approx_equal(c.rotate(angle), rotate_circle(c, angle, None)) |
| 1339 | + for center in centers: |
| 1340 | + assert_approx_equal( |
| 1341 | + c.rotate(angle, center), rotate_circle(c, angle, center) |
| 1342 | + ) |
| 1343 | + |
| 1344 | + def test_meth_rotate_ip(self): |
| 1345 | + """Ensures the Circle.rotate_ip() method rotates the Circle correctly.""" |
| 1346 | + |
| 1347 | + def rotate_circle(circle: Circle, angle, center): |
| 1348 | + def rotate_point(x, y, rang, cx, cy): |
| 1349 | + x -= cx |
| 1350 | + y -= cy |
| 1351 | + x_new = x * math.cos(rang) - y * math.sin(rang) |
| 1352 | + y_new = x * math.sin(rang) + y * math.cos(rang) |
| 1353 | + return x_new + cx, y_new + cy |
| 1354 | + |
| 1355 | + angle = math.radians(angle) |
| 1356 | + cx, cy = center if center is not None else circle.center |
| 1357 | + x, y = rotate_point(circle.x, circle.y, angle, cx, cy) |
| 1358 | + circle.x = x |
| 1359 | + circle.y = y |
| 1360 | + return circle |
| 1361 | + |
| 1362 | + def assert_approx_equal(circle1, circle2, eps=1e-12): |
| 1363 | + self.assertAlmostEqual(circle1.x, circle2.x, delta=eps) |
| 1364 | + self.assertAlmostEqual(circle1.y, circle2.y, delta=eps) |
| 1365 | + self.assertAlmostEqual(circle1.r, circle2.r, delta=eps) |
| 1366 | + |
| 1367 | + c = Circle(0, 0, 1) |
| 1368 | + angles = float_range(-360, 360, 0.5) |
| 1369 | + centers = [(a, b) for a in range(-10, 10) for b in range(-10, 10)] |
| 1370 | + for angle in angles: |
| 1371 | + c.rotate_ip(angle) |
| 1372 | + assert_approx_equal(c, rotate_circle(c, angle, None)) |
| 1373 | + for center in centers: |
| 1374 | + c.rotate_ip(angle, center) |
| 1375 | + assert_approx_equal(c, rotate_circle(c, angle, center)) |
| 1376 | + |
1189 | 1377 |
|
1190 | 1378 | if __name__ == "__main__":
|
1191 | 1379 | unittest.main()
|
0 commit comments