Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
36 changes: 36 additions & 0 deletions python/sedonadb/python/sedonadb/testing.py
Original file line number Diff line number Diff line change
Expand Up @@ -63,6 +63,31 @@ def _env_no_skip():
return env_no_skip in ("true", "1")


def _normalize_geometry_wkt_columns(rows, geometry_indexes):
"""Canonicalize WKT only for geometry-typed tuple values."""
import shapely

geometry_indexes = set(geometry_indexes)
normalized_rows = []

for row in rows:
normalized_row = list(row)

for i in geometry_indexes:
value = normalized_row[i]
if not isinstance(value, str):
continue

try:
normalized_row[i] = shapely.to_wkt(shapely.from_wkt(value))
except (ValueError, TypeError, shapely.errors.GEOSException):
pass

normalized_rows.append(tuple(normalized_row))

return normalized_rows


class DBEngine:
"""Engine-agnostic catalog and SQL engine

Expand Down Expand Up @@ -288,7 +313,18 @@ def assert_result(self, result, expected, **kwargs) -> "DBEngine":
result_pandas = self.result_to_pandas(result)
pandas.testing.assert_frame_equal(result_pandas, expected, **kwargs)
elif isinstance(expected, list):
result_table = self.result_to_table(result)
geometry_indexes = {
i
for i, col in enumerate(result_table.columns)
if _type_is_geoarrow(col.type)
}
result_tuples = self.result_to_tuples(result, **kwargs)
if geometry_indexes:
result_tuples = _normalize_geometry_wkt_columns(
result_tuples, geometry_indexes
)
expected = _normalize_geometry_wkt_columns(expected, geometry_indexes)
if result_tuples != expected:
raise AssertionError(
f"Expected:\n {expected}\nGot:\n {result_tuples}"
Expand Down
22 changes: 7 additions & 15 deletions python/sedonadb/tests/functions/test_functions.py
Original file line number Diff line number Diff line change
Expand Up @@ -1221,11 +1221,11 @@ def test_st_unaryunion_zm(eng, geom, expected):
elif is_postgis and ("M(" in expected or "M (" in expected):
pytest.skip("PostGIS doesn't support M dimensions")
else:
# Test for exact string equality
# Remove all spaces from both the actual and expected results to ignore formatting differences
# Compare the geometry result directly so the shared test harness can
# normalize WKT formatting for geometry-typed outputs only.
eng.assert_query_result(
f"SELECT replace(ST_AsText(ST_UnaryUnion({geom_or_null(geom)})), ' ', '')",
expected.replace(" ", ""),
f"SELECT ST_UnaryUnion({geom_or_null(geom)})",
expected,
)


Expand Down Expand Up @@ -2309,7 +2309,7 @@ def test_st_length(eng, geom, expected):
("geom", "expected"),
[
(None, None),
("POINT EMPTY", "POINT EMPTY"),
("POINT EMPTY", "POINT (nan nan)"),
("LINESTRING EMPTY", "LINESTRING EMPTY"),
("POLYGON EMPTY", "POLYGON EMPTY"),
("MULTIPOINT EMPTY", "MULTIPOINT EMPTY"),
Expand Down Expand Up @@ -2371,20 +2371,12 @@ def test_st_normalize(eng, geom, expected):
expected = "POLYGON Z ((0 0 5, 0 1 5, 1 1 5, 1 0 5, 0 0 5))"

if isinstance(eng, PostGIS) and expected is not None:
# Normalize expected WKT to PostGIS's compact ST_AsText formatting.
expected = expected.replace(", ", ",")
expected = expected.replace(" (", "(")
# Normalize expected WKT to PostGIS's formatting.
expected = expected.replace(r"ZM(", r"ZM (")
expected = expected.replace(r"M(", r"M (")
expected = expected.replace(r"Z(", r"Z (")

if isinstance(eng, SedonaDB) and expected is not None:
expected = expected.replace(", ", ",")
expected = expected.replace(" (", "(")

eng.assert_query_result(
f"SELECT ST_AsText(ST_Normalize({geom_or_null(geom)}))", expected
)
eng.assert_query_result(f"SELECT ST_Normalize({geom_or_null(geom)})", expected)


@pytest.mark.parametrize("eng", [SedonaDB, PostGIS])
Expand Down
15 changes: 15 additions & 0 deletions python/sedonadb/tests/test_testing.py
Original file line number Diff line number Diff line change
Expand Up @@ -129,6 +129,21 @@ def test_assert_result_spatial(eng):
)


@pytest.mark.parametrize("eng", [SedonaDB, PostGIS, DuckDB])
def test_assert_result_wkt_normalizes_geometry_only(eng):
with eng.create_or_skip() as eng:
eng.assert_query_result(
"SELECT ST_GeomFromText('POLYGON Z ((0 0 5, 0 1 5, 1 1 5, 1 0 5, 0 0 5))') as geom",
"POLYGON Z ((0 0 5,0 1 5,1 1 5,1 0 5,0 0 5))",
)

with pytest.raises(AssertionError):
eng.assert_query_result(
"SELECT 'POLYGON Z ((0 0 5, 0 1 5, 1 1 5, 1 0 5, 0 0 5))' as geom",
"POLYGON Z ((0 0 5,0 1 5,1 1 5,1 0 5,0 0 5))",
)


@pytest.mark.parametrize("eng", [SedonaDB, PostGIS, DuckDB])
def test_table_arrow_no_crs(eng):
with eng.create_or_skip() as eng:
Expand Down