"""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()