|
1 | 1 | """Unit tests for locations helper module.""" |
2 | | - |
| 2 | +import math |
3 | 3 | import unittest |
4 | 4 | from unittest.mock import MagicMock |
5 | 5 |
|
|
16 | 16 | select_highest_level_polygon, |
17 | 17 | select_lowest_level_polygon, |
18 | 18 | get_country_code_from_polygons, |
| 19 | + round_geojson_coords, |
| 20 | + round_coords, |
19 | 21 | ) |
20 | 22 | from unittest.mock import patch |
21 | 23 |
|
@@ -455,3 +457,154 @@ def test_get_country_code_from_polygons_all_none_admin_levels_returns_one_with_c |
455 | 457 | ] |
456 | 458 | result = get_country_code_from_polygons(polys) |
457 | 459 | self.assertIn(result, {"US", "CA"}) |
| 460 | + |
| 461 | + def _coords_equal(self, a, b, abs_tol=1e-5): |
| 462 | + if isinstance(a, (list, tuple)) and isinstance(b, (list, tuple)): |
| 463 | + if len(a) != len(b): |
| 464 | + return False |
| 465 | + return all(self._coords_equal(x, y, abs_tol=abs_tol) for x, y in zip(a, b)) |
| 466 | + elif isinstance(a, (list, tuple)) or isinstance(b, (list, tuple)): |
| 467 | + return False |
| 468 | + else: |
| 469 | + return math.isclose(a, b, abs_tol=abs_tol) |
| 470 | + |
| 471 | + def test_round_point(self): |
| 472 | + geom = {"type": "Point", "coordinates": [1.1234567, 2.9876543]} |
| 473 | + rounded = round_geojson_coords(geom, precision=5) |
| 474 | + assert self._coords_equal(rounded["coordinates"], [1.12346, 2.98765]) |
| 475 | + |
| 476 | + def test_round_linestring(self): |
| 477 | + geom = { |
| 478 | + "type": "LineString", |
| 479 | + "coordinates": [[1.1234567, 2.9876543], [3.1111111, 4.9999999]], |
| 480 | + } |
| 481 | + rounded = round_geojson_coords(geom, precision=5) |
| 482 | + assert self._coords_equal( |
| 483 | + rounded["coordinates"], [[1.12346, 2.98765], [3.11111, 5.0]] |
| 484 | + ) |
| 485 | + |
| 486 | + def test_round_polygon(self): |
| 487 | + geom = { |
| 488 | + "type": "Polygon", |
| 489 | + "coordinates": [ |
| 490 | + [[1.1234567, 2.9876543], [3.1111111, 4.9999999], [1.1234567, 2.9876543]] |
| 491 | + ], |
| 492 | + } |
| 493 | + rounded = round_geojson_coords(geom, precision=5) |
| 494 | + assert self._coords_equal( |
| 495 | + rounded["coordinates"], |
| 496 | + [[[1.12346, 2.98765], [3.11111, 5.0], [1.12346, 2.98765]]], |
| 497 | + ) |
| 498 | + |
| 499 | + def test_round_multipoint(self): |
| 500 | + geom = { |
| 501 | + "type": "MultiPoint", |
| 502 | + "coordinates": [[1.1234567, 2.9876543], [3.1111111, 4.9999999]], |
| 503 | + } |
| 504 | + rounded = round_geojson_coords(geom, precision=5) |
| 505 | + assert self._coords_equal( |
| 506 | + rounded["coordinates"], [[1.12346, 2.98765], [3.11111, 5.0]] |
| 507 | + ) |
| 508 | + |
| 509 | + def test_round_multilinestring(self): |
| 510 | + geom = { |
| 511 | + "type": "MultiLineString", |
| 512 | + "coordinates": [ |
| 513 | + [[1.1234567, 2.9876543], [3.1111111, 4.9999999]], |
| 514 | + [[5.5555555, 6.6666666], [7.7777777, 8.8888888]], |
| 515 | + ], |
| 516 | + } |
| 517 | + rounded = round_geojson_coords(geom, precision=5) |
| 518 | + assert self._coords_equal( |
| 519 | + rounded["coordinates"], |
| 520 | + [ |
| 521 | + [[1.12346, 2.98765], [3.11111, 5.0]], |
| 522 | + [[5.55556, 6.66667], [7.77778, 8.88889]], |
| 523 | + ], |
| 524 | + ) |
| 525 | + |
| 526 | + def test_round_multipolygon(self): |
| 527 | + geom = { |
| 528 | + "type": "MultiPolygon", |
| 529 | + "coordinates": [ |
| 530 | + [ |
| 531 | + [ |
| 532 | + [1.1234567, 2.9876543], |
| 533 | + [3.1111111, 4.9999999], |
| 534 | + [1.1234567, 2.9876543], |
| 535 | + ] |
| 536 | + ], |
| 537 | + [ |
| 538 | + [ |
| 539 | + [5.5555555, 6.6666666], |
| 540 | + [7.7777777, 8.8888888], |
| 541 | + [5.5555555, 6.6666666], |
| 542 | + ] |
| 543 | + ], |
| 544 | + ], |
| 545 | + } |
| 546 | + rounded = round_geojson_coords(geom, precision=5) |
| 547 | + assert self._coords_equal( |
| 548 | + rounded["coordinates"], |
| 549 | + [ |
| 550 | + [[[1.12346, 2.98765], [3.11111, 5.0], [1.12346, 2.98765]]], |
| 551 | + [[[5.55556, 6.66667], [7.77778, 8.88889], [5.55556, 6.66667]]], |
| 552 | + ], |
| 553 | + ) |
| 554 | + |
| 555 | + def test_round_geometrycollection(self): |
| 556 | + geom = { |
| 557 | + "type": "GeometryCollection", |
| 558 | + "geometries": [ |
| 559 | + {"type": "Point", "coordinates": [1.1234567, 2.9876543]}, |
| 560 | + { |
| 561 | + "type": "LineString", |
| 562 | + "coordinates": [[3.1111111, 4.9999999], [5.5555555, 6.6666666]], |
| 563 | + }, |
| 564 | + ], |
| 565 | + } |
| 566 | + rounded = round_geojson_coords(geom, precision=5) |
| 567 | + assert self._coords_equal( |
| 568 | + rounded["geometries"][0]["coordinates"], [1.12346, 2.98765] |
| 569 | + ) |
| 570 | + assert self._coords_equal( |
| 571 | + rounded["geometries"][1]["coordinates"], |
| 572 | + [[3.11111, 5.0], [5.55556, 6.66667]], |
| 573 | + ) |
| 574 | + |
| 575 | + def test_empty_coords(self): |
| 576 | + geom = {"type": "Point", "coordinates": []} |
| 577 | + rounded = round_geojson_coords(geom, precision=5) |
| 578 | + assert rounded["coordinates"] == [] |
| 579 | + |
| 580 | + def test_non_list_coords(self): |
| 581 | + geom = {"type": "Point", "coordinates": 1.1234567} |
| 582 | + rounded = round_geojson_coords(geom, precision=5) |
| 583 | + assert rounded["coordinates"] == 1.1234567 |
| 584 | + |
| 585 | + def test_round_coords_single_float(self): |
| 586 | + assert ( |
| 587 | + round_coords(1.1234567, 5) == 1.1234567 |
| 588 | + ) # Non-list input returns unchanged |
| 589 | + |
| 590 | + def test_round_coords_list_of_floats(self): |
| 591 | + assert round_coords([1.1234567, 2.9876543], 5) == [1.12346, 2.98765] |
| 592 | + |
| 593 | + def test_round_coords_tuple_of_floats(self): |
| 594 | + assert round_coords((1.1234567, 2.9876543), 5) == [1.12346, 2.98765] |
| 595 | + |
| 596 | + def test_round_coords_nested_lists(self): |
| 597 | + coords = [[[1.1234567, 2.9876543], [3.1111111, 4.9999999]]] |
| 598 | + expected = [[[1.12346, 2.98765], [3.11111, 5.0]]] |
| 599 | + assert round_coords(coords, 5) == expected |
| 600 | + |
| 601 | + def test_round_coords_empty_list(self): |
| 602 | + assert round_coords([], 5) == [] |
| 603 | + |
| 604 | + def test_round_coords_non_numeric(self): |
| 605 | + assert round_coords("not_a_number", 5) == "not_a_number" |
| 606 | + |
| 607 | + def test_round_coords_mixed_types(self): |
| 608 | + coords = [1.1234567, "foo", 2.9876543] |
| 609 | + expected = [1.12346, "foo", 2.98765] |
| 610 | + assert round_coords(coords, 5) == expected |
0 commit comments