Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

test: initial commit adding hypothesis property testing library #186

Merged
merged 2 commits into from
Mar 20, 2024
Merged
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
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -24,3 +24,4 @@ venv/
__pycache__/
*.stderr*
docs/_*
.hypothesis/
6 changes: 3 additions & 3 deletions pygeoif/geometry.py
Original file line number Diff line number Diff line change
Expand Up @@ -117,7 +117,7 @@ def convex_hull(self) -> Optional[Union["Point", "LineString", "Polygon"]]:

Returns a representation of the smallest convex Polygon containing
all the points in the object unless the number of points in the object
is less than three.
is fewer than three.
For two points, the convex hull collapses to a LineString;
for 1, to a Point.
"""
Expand Down Expand Up @@ -271,7 +271,7 @@ def is_empty(self) -> bool:
"""
Return if this geometry is empty.

A Point is considered empty when it has less than 2 coordinates.
A Point is considered empty when it has fewer than 2 coordinates.
"""
return len(self._geoms) < 2 # noqa: PLR2004

Expand Down Expand Up @@ -382,7 +382,7 @@ def is_empty(self) -> bool:
"""
Return if this geometry is empty.

A Linestring is considered empty when it has less than 2 points.
A Linestring is considered empty when it has fewer than 2 points.
"""
return len(self._geoms) < 2 # noqa: PLR2004

Expand Down
1 change: 1 addition & 0 deletions pyproject.toml
Original file line number Diff line number Diff line change
Expand Up @@ -79,6 +79,7 @@ linting = [
"yamllint",
]
tests = [
"hypothesis",
"pytest",
"pytest-cov",
]
Expand Down
52 changes: 52 additions & 0 deletions tests/conftest.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,52 @@
"""Data-generating strategies for property-based testing."""
import hypothesis.strategies as st

# Incomplete list of allowed spatial reference systems to generate data
# - EPSG 4326
# - EPSG 3857
# ...?


# EPSG:4326 primitives
latitudes = st.floats(
min_value=-90.0,
max_value=90.0,
allow_nan=False,
allow_infinity=False,
)
longitudes = st.floats(
min_value=-180.0,
max_value=180.0,
allow_nan=False,
allow_infinity=False,
)
elevations = st.floats(allow_nan=False, allow_infinity=False)


# Point2D
@st.composite
def points_2d(draw, srs="EPSG:4326"):
if srs == "EPSG:4326":
return draw(st.tuples(latitudes, longitudes))
raise NotImplementedError
Comment on lines +29 to +31

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggestion: Wrap the validation logic inside a function for better reusability and readability.

Suggested change
if srs == "EPSG:4326":
return draw(st.tuples(latitudes, longitudes))
raise NotImplementedError
def validate_srs(srs, draw, strategy):
if srs == "EPSG:4326":
return draw(strategy)
raise NotImplementedError
validate_srs(srs, draw, st.tuples(latitudes, longitudes))



# Point3D
@st.composite
def points_3d(draw, srs="EPSG:4326"):
if srs == "EPSG:4326":
return draw(st.tuples(latitudes, longitudes, elevations))
raise NotImplementedError
Comment on lines +37 to +39

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggestion: The validation logic is repeated in multiple places. Consider creating a helper function to avoid repetition.

Suggested change
if srs == "EPSG:4326":
return draw(st.tuples(latitudes, longitudes, elevations))
raise NotImplementedError
validate_srs(srs, draw, st.tuples(latitudes, longitudes, elevations))



# PointType
@st.composite
def points(draw, srs="EPSG:4326"):
if srs == "EPSG:4326":
return draw(st.one_of(points_2d(), points_3d()))
raise NotImplementedError
Comment on lines +45 to +47

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggestion: The validation logic is repeated. Consider creating a helper function to avoid repetition.

Suggested change
if srs == "EPSG:4326":
return draw(st.one_of(points_2d(), points_3d()))
raise NotImplementedError
validate_srs(srs, draw, st.one_of(points_2d(), points_3d()))



# LineType

# Geometries
9 changes: 9 additions & 0 deletions tests/test_point.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,9 +3,11 @@
from unittest import mock

import pytest
from hypothesis import given

from pygeoif import geometry
from pygeoif.exceptions import DimensionError
from tests.conftest import points


def test_empty() -> None:
Expand Down Expand Up @@ -250,3 +252,10 @@ def test_hash_empty() -> None:
point = geometry.Point(None, None)

assert hash(point) == hash(())


@given(points("EPSG:4326"))
def test_repr_eval_hypothesis_epsg_4326(point) -> None:
point = geometry.Point(*point)

assert eval(repr(point), {}, {"Point": geometry.Point}) == point