93 lines
3.2 KiB
Python
93 lines
3.2 KiB
Python
"""Unit tests for the geometry and parsing helpers of end_finder."""
|
|
|
|
import unittest
|
|
|
|
from end_finder import angle_between, intersect_lines, parse_point
|
|
|
|
|
|
class ParsePointTest(unittest.TestCase):
|
|
"""Parsing of user input: valid formats accepted, invalid ones rejected."""
|
|
|
|
def test_valid_space_separated(self):
|
|
self.assertEqual(parse_point("100 200"), (100.0, 200.0))
|
|
|
|
def test_valid_comma_separated(self):
|
|
self.assertEqual(parse_point("100,200"), (100.0, 200.0))
|
|
|
|
def test_valid_decimals_and_mixed_separators(self):
|
|
self.assertEqual(parse_point(" 100.5 , -200.25 "), (100.5, -200.25))
|
|
|
|
def test_invalid_single_number(self):
|
|
with self.assertRaises(ValueError):
|
|
parse_point("100")
|
|
|
|
def test_invalid_too_many_numbers(self):
|
|
with self.assertRaises(ValueError):
|
|
parse_point("100 200 300")
|
|
|
|
def test_invalid_non_numeric(self):
|
|
with self.assertRaises(ValueError):
|
|
parse_point("abc def")
|
|
|
|
def test_invalid_empty_input(self):
|
|
with self.assertRaises(ValueError):
|
|
parse_point("")
|
|
|
|
|
|
class AngleBetweenTest(unittest.TestCase):
|
|
"""Consistency of the angle between two throw lines."""
|
|
|
|
def test_perpendicular_lines(self):
|
|
angle = angle_between((0, 0), (1, 0), (0, 0), (0, 1))
|
|
self.assertAlmostEqual(angle, 90.0)
|
|
|
|
def test_parallel_lines(self):
|
|
angle = angle_between((0, 0), (1, 0), (5, 5), (10, 5))
|
|
self.assertAlmostEqual(angle, 0.0)
|
|
|
|
def test_parallel_lines_opposite_directions(self):
|
|
# Collinear lines whose direction vectors point in opposite
|
|
# directions (both throws towards the same stronghold) are still
|
|
# parallel: the angle between the lines must be 0, not 180.
|
|
angle = angle_between((-100, 0), (100, 0), (100, 0), (-100, 0))
|
|
self.assertAlmostEqual(angle, 0.0)
|
|
|
|
def test_small_angle(self):
|
|
angle = angle_between((0, 0), (100, 1), (0, 0), (100, -1))
|
|
self.assertAlmostEqual(angle, 1.145, places=2)
|
|
|
|
|
|
class IntersectLinesTest(unittest.TestCase):
|
|
"""Intersection of two throw lines: nominal, degenerate and invalid."""
|
|
|
|
def test_nominal_exact_intersection(self):
|
|
x, z = intersect_lines((0, 0), (1, 1), (1, 0), (0, 1))
|
|
self.assertAlmostEqual(x, 0.5)
|
|
self.assertAlmostEqual(z, 0.5)
|
|
|
|
def test_nominal_decimals(self):
|
|
# Intersection of x = 0.5z and x = 10 - 0.5z is (5, 10).
|
|
x, z = intersect_lines((0, 0), (1, 2), (10, 0), (0, 20))
|
|
self.assertAlmostEqual(x, 5.0)
|
|
self.assertAlmostEqual(z, 10.0)
|
|
|
|
def test_vertical_lines(self):
|
|
# Vertical line x = 1 crossing the line through (5, 0) and (10, 10).
|
|
x, z = intersect_lines((1, 0), (1, 10), (5, 0), (10, 10))
|
|
self.assertAlmostEqual(x, 1.0)
|
|
self.assertAlmostEqual(z, -8.0)
|
|
|
|
def test_exactly_parallel_raises(self):
|
|
with self.assertRaises(ValueError):
|
|
intersect_lines((0, 0), (1, 0), (0, 5), (1, 5))
|
|
|
|
def test_zero_direction_vector_raises(self):
|
|
with self.assertRaises(ValueError):
|
|
intersect_lines((1, 1), (1, 1), (0, 0), (1, 0))
|
|
with self.assertRaises(ValueError):
|
|
intersect_lines((0, 0), (1, 0), (2, 2), (2, 2))
|
|
|
|
|
|
if __name__ == "__main__":
|
|
unittest.main()
|