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

361 test geometries with hypothesis #364

Merged
merged 16 commits into from
Oct 13, 2024
Merged
Show file tree
Hide file tree
Changes from 11 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
8 changes: 4 additions & 4 deletions .github/workflows/run-all-tests.yml
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
# run tests and lint with a variety of Python versions
---
name: Tests
on: [push, pull_request]

Check warning on line 5 in .github/workflows/run-all-tests.yml

View workflow job for this annotation

GitHub Actions / static-tests (3.12)

5:1 [truthy] truthy value should be one of [false, true]

Check warning on line 5 in .github/workflows/run-all-tests.yml

View workflow job for this annotation

GitHub Actions / static-tests (3.12)

5:1 [truthy] truthy value should be one of [false, true]

jobs:
cpython:
Expand Down Expand Up @@ -43,7 +43,7 @@
pip install -e ".[tests, lxml]"
- name: Test with pytest
run: |
pytest tests --cov=fastkml --cov=tests --cov-fail-under=88 --cov-report=xml
pytest tests --cov=fastkml --cov=tests --cov-fail-under=95 --cov-report=xml
- name: "Upload coverage to Codecov"
if: ${{ matrix.python-version==3.11 }}
uses: codecov/codecov-action@v4
Expand Down Expand Up @@ -127,6 +127,9 @@
needs: [cpython, static-tests, pypy, cpython-lxml, doctest-lxml]
name: Build and publish to PyPI and TestPyPI
runs-on: ubuntu-latest
environment: release
permissions:
id-token: write
steps:
- uses: actions/checkout@v4
- name: Set up Python
Expand All @@ -150,11 +153,8 @@
if: startsWith(github.ref, 'refs/tags')
uses: pypa/gh-action-pypi-publish@release/v1
with:
password: ${{ secrets.TEST_PYPI_API_TOKEN }}
repository_url: https://test.pypi.org/legacy/
- name: Publish distribution 📦 to PyPI for push to main
if: github.event_name == 'push' && github.ref == 'refs/heads/main'
uses: pypa/gh-action-pypi-publish@release/v1
with:
password: ${{ secrets.PYPI_API_TOKEN }}
...
4 changes: 2 additions & 2 deletions .pre-commit-config.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -40,7 +40,7 @@ repos:
rev: v3.17.0
hooks:
- id: pyupgrade
args: ["--py3-plus", "--py37-plus"]
args: ["--py3-plus", "--py38-plus"]
Copy link
Contributor

Choose a reason for hiding this comment

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

💡 Codebase verification

Inconsistent Python Version Specifications

The pyupgrade hook in .pre-commit-config.yaml has been updated to include --py38-plus, indicating a shift to Python 3.8+. However, no minimum Python version specification was found in other configuration files (e.g., pyproject.toml, CI workflows). Please ensure that all relevant configuration files specify Python 3.8+ to maintain consistency across the project.

🔗 Analysis chain

Upgrade of minimum supported Python version

The pyupgrade hook arguments have been updated from --py37-plus to --py38-plus, indicating an increase in the minimum supported Python version to 3.8. This change aligns with modern Python practices and likely takes advantage of features introduced in Python 3.8.

To ensure consistency across the project, let's verify the Python version specification in other configuration files:

🏁 Scripts executed

The following scripts were executed for the analysis:

Script:

#!/bin/bash
# Description: Check Python version specifications in project files

# Check pyproject.toml for Python version
echo "Checking pyproject.toml:"
rg 'python\s*=\s*"[^"]+"' pyproject.toml

# Check setup.py if it exists
if [ -f setup.py ]; then
    echo "Checking setup.py:"
    rg 'python_requires\s*=\s*' setup.py
fi

# Check any requirements files
echo "Checking requirements files:"
rg '^python' requirements*.txt

# Check CI configuration files
echo "Checking CI configuration files:"
rg 'python-version' .github/workflows/*.yml

Length of output: 2380


Script:

#!/bin/bash
# Description: Verify Python version specifications across project configuration files

echo "Verifying Python version specifications..."

# Function to check Python version in a file
check_python_version() {
    local file=$1
    if [ -f "$file" ]; then
        echo "Checking $file for Python version specification:"
        rg 'python\s*=\s*"3\.[8-9]+' "$file" || echo "No Python 3.8+ specification found in $file."
    else
        echo "$file does not exist."
    fi
}

# Check pyproject.toml
check_python_version "pyproject.toml"

# Check setup.py
check_python_version "setup.py"

# Check setup.cfg
check_python_version "setup.cfg"

# Check setup.ini
check_python_version "setup.ini"

# Check requirements files for Python version comments or environment markers
echo "Checking requirements files for Python version specifications:"
rg -H 'python_version\s*>=\s*3\.(8|9)' requirements/*.txt || echo "No Python 3.8+ specifications found in requirements files."

# Check CI configuration files for Python version
echo "Checking CI configuration files for Python version specifications:"
rg -H 'python-version\s*3\.(8|9)' .github/workflows/*.yml || echo "No Python 3.8+ specifications found in CI configuration files."

Length of output: 1727

- repo: https://github.com/psf/black
rev: 24.8.0
hooks:
Expand Down Expand Up @@ -77,7 +77,7 @@ repos:
rev: v1.11.2
hooks:
- id: mypy
additional_dependencies: [pygeoif>=1.4, arrow, pytest]
additional_dependencies: [pygeoif>=1.4, arrow, pytest, hypothesis]
- repo: https://github.com/adamchainz/blacken-docs
rev: "1.18.0"
hooks:
Expand Down
1 change: 1 addition & 0 deletions fastkml/features.py
Original file line number Diff line number Diff line change
Expand Up @@ -185,6 +185,7 @@ def __bool__(self) -> bool:
classes=(int,),
get_kwarg=attribute_int_kwarg,
set_element=int_attribute,
default=2,
),
)

Expand Down
75 changes: 52 additions & 23 deletions fastkml/geometry.py
Original file line number Diff line number Diff line change
Expand Up @@ -93,6 +93,8 @@

MsgMutualExclusive: Final = "Geometry and kml coordinates are mutually exclusive"

xml_attrs = {"ns", "name_spaces", "id", "target_id"}


def handle_invalid_geometry_error(
*,
Expand Down Expand Up @@ -159,13 +161,12 @@ def coordinates_subelement(

"""
if getattr(obj, attr_name, None):
p = precision if precision is not None else 6
coords = getattr(obj, attr_name)
if len(coords[0]) == 2: # noqa: PLR2004
tuples = (f"{c[0]:.{p}f},{c[1]:.{p}f}" for c in coords)
elif len(coords[0]) == 3: # noqa: PLR2004
tuples = (f"{c[0]:.{p}f},{c[1]:.{p}f},{c[2]:.{p}f}" for c in coords)
if precision is None:
Copy link
Contributor

Choose a reason for hiding this comment

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

In coordinates_subelement, consider adding a check for empty coords to avoid potential errors when accessing coords[0].

Copy link
Contributor

Choose a reason for hiding this comment

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

suggestion (performance): Move the dimension check to the beginning of the function

Consider moving the check for valid dimensions (len(coords[0]) not in (2, 3)) to the beginning of the function. This would prevent unnecessary string formatting for invalid input, improving efficiency.

        if len(coords[0]) not in (2, 3):
            raise ValueError("Coordinates must be 2D or 3D")
        if precision is None:

tuples = (",".join(str(c) for c in coord) for coord in coords)
else:
tuples = (",".join(f"{c:.{precision}f}" for c in coord) for coord in coords)
if len(coords[0]) not in (2, 3):
Copy link
Contributor

Choose a reason for hiding this comment

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

🛠️ Refactor suggestion

Optimize by Moving Dimension Check Before Processing Coordinates

Currently, the dimension check if len(coords[0]) not in (2, 3): occurs after the coordinate formatting. Moving this check before formatting prevents unnecessary computation when coordinates have invalid dimensions.

Apply this diff to improve performance:

+    if not coords:
+        raise KMLWriteError("No coordinates provided")
+    if len(coords[0]) not in (2, 3):
+        msg = f"Invalid dimensions in coordinates '{coords}'"
+        raise KMLWriteError(msg)
     if precision is None:
         tuples = (",".join(str(c) for c in coord) for coord in coords)
     else:
         tuples = (",".join(f"{c:.{precision}f}" for c in coord) for coord in coords)
-    if len(coords[0]) not in (2, 3):
-        msg = f"Invalid dimensions in coordinates '{coords}'"
-        raise KMLWriteError(msg)
     element.text = " ".join(tuples)
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
if precision is None:
tuples = (",".join(str(c) for c in coord) for coord in coords)
else:
tuples = (",".join(f"{c:.{precision}f}" for c in coord) for coord in coords)
if len(coords[0]) not in (2, 3):
if not coords:
raise KMLWriteError("No coordinates provided")
if len(coords[0]) not in (2, 3):
msg = f"Invalid dimensions in coordinates '{coords}'"
raise KMLWriteError(msg)
if precision is None:
tuples = (",".join(str(c) for c in coord) for coord in coords)
else:
tuples = (",".join(f"{c:.{precision}f}" for c in coord) for coord in coords)
element.text = " ".join(tuples)

⚠️ Potential issue

Add Check for Empty coords to Prevent IndexError

Accessing coords[0] without verifying if coords is non-empty can lead to an IndexError when coords is empty. To ensure robustness, add a check for empty coords before accessing the first element.

Apply this diff to fix the issue:

+    if not coords:
+        raise KMLWriteError("No coordinates provided")
     if precision is None:
         tuples = (",".join(str(c) for c in coord) for coord in coords)
     else:
         tuples = (",".join(f"{c:.{precision}f}" for c in coord) for coord in coords)
+    if len(coords[0]) not in (2, 3):
-    if len(coords[0]) not in (2, 3):
         msg = f"Invalid dimensions in coordinates '{coords}'"
         raise KMLWriteError(msg)
     element.text = " ".join(tuples)
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
if precision is None:
tuples = (",".join(str(c) for c in coord) for coord in coords)
else:
tuples = (",".join(f"{c:.{precision}f}" for c in coord) for coord in coords)
if len(coords[0]) not in (2, 3):
if not coords:
raise KMLWriteError("No coordinates provided")
if precision is None:
tuples = (",".join(str(c) for c in coord) for coord in coords)
else:
tuples = (",".join(f"{c:.{precision}f}" for c in coord) for coord in coords)
if len(coords[0]) not in (2, 3):
msg = f"Invalid dimensions in coordinates '{coords}'"
raise KMLWriteError(msg)
element.text = " ".join(tuples)

msg = f"Invalid dimensions in coordinates '{coords}'"
raise KMLWriteError(msg)
element.text = " ".join(tuples)
Expand Down Expand Up @@ -488,6 +489,21 @@ def __bool__(self) -> bool:
"""
return bool(self.geometry)

def __eq__(self, other: object) -> bool:
Copy link
Contributor

Choose a reason for hiding this comment

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

suggestion: Extract common equality check logic into a utility function

The eq methods for Point, LineString, and Polygon are very similar. Consider extracting this common logic into a utility function to reduce code duplication and improve maintainability.

def __eq__(self, other: object) -> bool:
    return isinstance(other, Point) and geometry_equality(self, other)

"""Check if the Point objects are equal."""
if isinstance(other, Point):
return all(
getattr(self, attr) == getattr(other, attr)
for attr in (
"extrude",
"altitude_mode",
"geometry",
*xml_attrs,
*self._get_splat(),
)
)
return super().__eq__(other)
Copy link
Contributor

Choose a reason for hiding this comment

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

⚠️ Potential issue

Increase test coverage for Point.__eq__ method

Static analysis indicates that line 505 (return super().__eq__(other)) is not covered by tests. Adding a unit test where other is not an instance of Point will ensure this branch is tested.

🧰 Tools
🪛 GitHub Check: codecov/patch

[warning] 505-505: fastkml/geometry.py#L505
Added line #L505 was not covered by tests


Comment on lines +492 to +506
Copy link
Contributor

Choose a reason for hiding this comment

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

⚠️ Potential issue

Note on Test Coverage for Point.__eq__ Method

The __eq__ method implementation in the Point class is comprehensive. However, static analysis indicates that line 505 (return super().__eq__(other)) is not covered by existing tests. Adding a unit test where other is not an instance of Point will ensure this branch is exercised, improving test coverage and reliability.

Would you like assistance in creating a unit test to cover this scenario?

🧰 Tools
🪛 GitHub Check: codecov/patch

[warning] 505-505: fastkml/geometry.py#L505
Added line #L505 was not covered by tests

@property
def geometry(self) -> Optional[geo.Point]:
"""
Expand Down Expand Up @@ -628,6 +644,21 @@ def __bool__(self) -> bool:
"""
return bool(self.geometry)

def __eq__(self, other: object) -> bool:
"""Check if the LineString objects is equal."""
if isinstance(other, LineString):
return all(
getattr(self, attr) == getattr(other, attr)
for attr in (
"extrude",
"tessellate",
"geometry",
*xml_attrs,
*self._get_splat(),
)
)
return super().__eq__(other)
Copy link
Contributor

Choose a reason for hiding this comment

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

⚠️ Potential issue

Increase test coverage for LineString.__eq__ method

Line 660 is not covered by tests. Please add a unit test where other is not an instance of LineString to cover this code path.

🧰 Tools
🪛 GitHub Check: codecov/patch

[warning] 660-660: fastkml/geometry.py#L660
Added line #L660 was not covered by tests


Comment on lines +647 to +661
Copy link
Contributor

Choose a reason for hiding this comment

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

⚠️ Potential issue

Note on Test Coverage for LineString.__eq__ Method

Similarly, in the LineString class, the else branch in the __eq__ method (line 660) is not covered by tests. Introducing a test case where other is not a LineString instance will enhance coverage.

Can I help in drafting a unit test for this case?

🧰 Tools
🪛 GitHub Check: codecov/patch

[warning] 660-660: fastkml/geometry.py#L660
Added line #L660 was not covered by tests

@property
def geometry(self) -> Optional[geo.LineString]:
"""
Expand Down Expand Up @@ -754,22 +785,6 @@ def __init__(
**kwargs,
)

def __repr__(self) -> str:
"""Create a string (c)representation for LinearRing."""
return (
f"{self.__class__.__module__}.{self.__class__.__name__}("
f"ns={self.ns!r}, "
f"name_spaces={self.name_spaces!r}, "
f"id={self.id!r}, "
f"target_id={self.target_id!r}, "
f"extrude={self.extrude!r}, "
f"tessellate={self.tessellate!r}, "
f"altitude_mode={self.altitude_mode}, "
f"geometry={self.geometry!r}, "
f"**{self._get_splat()!r},"
")"
)

@property
def geometry(self) -> Optional[geo.LinearRing]:
"""
Expand Down Expand Up @@ -1182,12 +1197,26 @@ def __repr__(self) -> str:
f"extrude={self.extrude!r}, "
f"tessellate={self.tessellate!r}, "
f"altitude_mode={self.altitude_mode}, "
f"outer_boundary={self.outer_boundary!r}, "
f"inner_boundaries={self.inner_boundaries!r}, "
f"geometry={self.geometry!r}, "
f"**{self._get_splat()!r},"
")"
)

def __eq__(self, other: object) -> bool:
"""Check if the Polygon objects are equal."""
if isinstance(other, Polygon):
return all(
getattr(self, attr) == getattr(other, attr)
for attr in (
"extrude",
"tessellate",
"geometry",
*xml_attrs,
*self._get_splat(),
)
)
return super().__eq__(other)
Copy link
Contributor

Choose a reason for hiding this comment

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

⚠️ Potential issue

Increase test coverage for Polygon.__eq__ method

Line 1218 lacks test coverage. Including a test case where other is not a Polygon instance will improve coverage and validate the method's behavior.

🧰 Tools
🪛 GitHub Check: codecov/patch

[warning] 1218-1218: fastkml/geometry.py#L1218
Added line #L1218 was not covered by tests


Comment on lines +1205 to +1219
Copy link
Contributor

Choose a reason for hiding this comment

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

⚠️ Potential issue

Note on Test Coverage for Polygon.__eq__ Method

The else branch in the __eq__ method of the Polygon class (line 1218) lacks test coverage according to static analysis. Including a unit test where other is not a Polygon instance will ensure comprehensive testing of this method.

Would you like me to assist in writing this unit test?

🧰 Tools
🪛 GitHub Check: codecov/patch

[warning] 1218-1218: fastkml/geometry.py#L1218
Added line #L1218 was not covered by tests


registry.register(
Polygon,
Expand Down
2 changes: 2 additions & 0 deletions pyproject.toml
Original file line number Diff line number Diff line change
Expand Up @@ -77,6 +77,7 @@ lxml = [
"lxml",
]
tests = [
"hypothesis",
"pytest",
"pytest-cov",
]
Expand Down Expand Up @@ -117,6 +118,7 @@ source = [
[tool.coverage.report]
exclude_also = [
"^\\s*\\.\\.\\.$",
"class \\w+\\(Protocol\\)\\:",
"except AssertionError:",
"except ImportError:",
"if TYPE_CHECKING:",
Expand Down
21 changes: 21 additions & 0 deletions tests/conftest.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
"""
Configure the tests.

Register the hypothesis 'exhaustive' profile to run 10 thousand examples.
Run this profile with ``pytest --hypothesis-profile=exhaustive``
"""

from hypothesis import HealthCheck
from hypothesis import settings

settings.register_profile(
"exhaustive",
max_examples=10_000,
suppress_health_check=[HealthCheck.too_slow],
)
settings.register_profile(
"coverage",
max_examples=10,
suppress_health_check=[HealthCheck.too_slow],
)
Comment on lines +16 to +20
Copy link
Contributor

Choose a reason for hiding this comment

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

🛠️ Refactor suggestion

Consider increasing max_examples for the "coverage" profile.

While the current setting of 10 examples is good for quick checks, it might not provide comprehensive coverage for more complex scenarios. Consider increasing this value to strike a balance between speed and thorough coverage.

You might want to try a value between 50 and 100, for example:

settings.register_profile(
    "coverage",
    max_examples=50,
    suppress_health_check=[HealthCheck.too_slow],
)

settings.register_profile("ci", suppress_health_check=[HealthCheck.too_slow])
Copy link
Contributor

Choose a reason for hiding this comment

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

🛠️ Refactor suggestion

Consider explicitly setting max_examples for the "ci" profile.

The "ci" profile currently doesn't specify a max_examples value, which means it will use Hypothesis's default. For consistency with other profiles and to ensure predictable behavior in CI environments, consider explicitly setting this value.

You might want to add a max_examples parameter:

settings.register_profile(
    "ci",
    max_examples=200,  # Adjust this value based on your CI requirements
    suppress_health_check=[HealthCheck.too_slow],
)

4 changes: 2 additions & 2 deletions tests/geometries/boundaries_test.py
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,7 @@ def test_outer_boundary(self) -> None:
)

assert outer_boundary.geometry == geo.LinearRing(coords)
assert outer_boundary.to_string(prettyprint=False).strip() == (
assert outer_boundary.to_string(prettyprint=False, precision=6).strip() == (
'<kml:outerBoundaryIs xmlns:kml="http://www.opengis.net/kml/2.2">'
"<kml:LinearRing><kml:coordinates>"
"1.000000,2.000000 2.000000,0.000000 0.000000,0.000000 1.000000,2.000000"
Expand Down Expand Up @@ -66,7 +66,7 @@ def test_inner_boundary(self) -> None:

assert inner_boundary.geometry == geo.LinearRing(coords)
assert bool(inner_boundary)
assert inner_boundary.to_string(prettyprint=False).strip() == (
assert inner_boundary.to_string(prettyprint=False, precision=6).strip() == (
'<kml:innerBoundaryIs xmlns:kml="http://www.opengis.net/kml/2.2">'
"<kml:LinearRing><kml:coordinates>"
"1.000000,2.000000 2.000000,0.000000 0.000000,0.000000 1.000000,2.000000"
Expand Down
2 changes: 1 addition & 1 deletion tests/geometries/coordinates_test.py
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,7 @@ def test_coordinates(self) -> None:

coordinates = Coordinates(coords=coords)

assert coordinates.to_string().strip() == (
assert coordinates.to_string(precision=6).strip() == (
'<kml:coordinates xmlns:kml="http://www.opengis.net/kml/2.2">'
"0.000000,0.000000 0.000000,1.000000 1.000000,1.000000 "
"1.000000,0.000000 0.000000,0.000000"
Expand Down
60 changes: 33 additions & 27 deletions tests/geometries/geometry_test.py
Original file line number Diff line number Diff line change
Expand Up @@ -495,7 +495,7 @@ def test_create_kml_geometry_point(self) -> None:
"coordinates": (0.0, 1.0),
}
assert "Point>" in g.to_string()
assert "coordinates>0.000000,1.000000</" in g.to_string()
assert "coordinates>0.000000,1.000000</" in g.to_string(precision=6)

def test_create_kml_geometry_linestring(self) -> None:
"""Test the create_kml_geometry function."""
Expand All @@ -509,7 +509,9 @@ def test_create_kml_geometry_linestring(self) -> None:
"coordinates": ((0.0, 0.0), (1.0, 1.0)),
}
assert "LineString>" in g.to_string()
assert "coordinates>0.000000,0.000000 1.000000,1.000000</" in g.to_string()
assert "coordinates>0.000000,0.000000 1.000000,1.000000</" in g.to_string(
precision=6,
)

def test_create_kml_geometry_linearring(self) -> None:
"""Test the create_kml_geometry function."""
Expand All @@ -526,7 +528,7 @@ def test_create_kml_geometry_linearring(self) -> None:
assert (
"coordinates>0.000000,0.000000 1.000000,1.000000 1.000000,0.000000 "
"0.000000,0.000000</"
) in g.to_string()
) in g.to_string(precision=6)

def test_create_kml_geometry_polygon(self) -> None:
"""Test the create_kml_geometry function."""
Expand All @@ -543,7 +545,7 @@ def test_create_kml_geometry_polygon(self) -> None:
assert (
"coordinates>0.000000,0.000000 1.000000,1.000000 1.000000,0.000000 "
"0.000000,0.000000</"
) in g.to_string()
) in g.to_string(precision=6)

def test_create_kml_geometry_multipoint(self) -> None:
"""Test the create_kml_geometry function."""
Expand All @@ -552,12 +554,13 @@ def test_create_kml_geometry_multipoint(self) -> None:
assert isinstance(g, MultiGeometry)
assert g.geometry
assert len(g.geometry) == 4
assert "MultiGeometry>" in g.to_string()
assert "Point>" in g.to_string()
assert "coordinates>0.000000,0.000000</" in g.to_string()
assert "coordinates>1.000000,1.000000</" in g.to_string()
assert "coordinates>1.000000,0.000000</" in g.to_string()
assert "coordinates>2.000000,2.000000</" in g.to_string()
xml = g.to_string(precision=6)
assert "MultiGeometry>" in xml
assert "Point>" in xml
assert "coordinates>0.000000,0.000000</" in xml
assert "coordinates>1.000000,1.000000</" in xml
assert "coordinates>1.000000,0.000000</" in xml
assert "coordinates>2.000000,2.000000</" in xml

def test_create_kml_geometry_multilinestring(self) -> None:
"""Test the create_kml_geometry function."""
Expand All @@ -568,10 +571,11 @@ def test_create_kml_geometry_multilinestring(self) -> None:
assert isinstance(g, MultiGeometry)
assert g.geometry
assert len(g.geometry) == 2
assert "MultiGeometry>" in g.to_string()
assert "LineString>" in g.to_string()
assert "coordinates>0.000000,0.000000 1.000000,1.000000</" in g.to_string()
assert "coordinates>0.000000,0.000000 1.000000,1.000000</" in g.to_string()
xml = g.to_string(precision=6)
assert "MultiGeometry>" in xml
assert "LineString>" in xml
assert "coordinates>0.000000,0.000000 1.000000,1.000000</" in xml
assert "coordinates>0.000000,0.000000 1.000000,1.000000</" in xml

def test_create_kml_geometry_multipolygon(self) -> None:
"""Test the create_kml_geometry function."""
Expand All @@ -590,20 +594,21 @@ def test_create_kml_geometry_multipolygon(self) -> None:
assert isinstance(g, MultiGeometry)
assert g.geometry
assert len(g.geometry) == 2
assert "MultiGeometry>" in g.to_string()
assert "Polygon>" in g.to_string()
xml = g.to_string(precision=6)
assert "MultiGeometry>" in xml
assert "Polygon>" in xml
assert (
"coordinates>0.000000,0.000000 0.000000,1.000000 1.000000,1.000000 "
"1.000000,0.000000 0.000000,0.000000</"
) in g.to_string()
) in xml
assert (
"coordinates>0.100000,0.100000 0.100000,0.200000 0.200000,0.200000 "
"0.200000,0.100000 0.100000,0.100000</"
) in g.to_string()
) in xml
assert (
"coordinates>0.000000,0.000000 0.000000,1.000000 1.000000,1.000000 "
"1.000000,0.000000 0.000000,0.000000</"
) in g.to_string()
) in xml

def test_create_kml_geometry_geometrycollection(self) -> None:
multipoint = geo.MultiPoint([(0, 0), (1, 1), (1, 2), (2, 2)])
Expand All @@ -625,14 +630,15 @@ def test_create_kml_geometry_geometrycollection(self) -> None:
assert isinstance(g, MultiGeometry)
assert g.geometry
assert len(g.geometry) == 7
assert "MultiGeometry>" in g.to_string()
assert "LineString>" in g.to_string()
assert "LinearRing>" in g.to_string()
assert "Polygon>" in g.to_string()
assert "outerBoundaryIs>" in g.to_string()
assert "innerBoundaryIs>" in g.to_string()
assert "Point>" in g.to_string()
assert "coordinates>0.000000,0.000000</" in g.to_string()
xml = g.to_string(precision=6)
assert "MultiGeometry>" in xml
assert "LineString>" in xml
assert "LinearRing>" in xml
assert "Polygon>" in xml
assert "outerBoundaryIs>" in xml
assert "innerBoundaryIs>" in xml
assert "Point>" in xml
assert "coordinates>0.000000,0.000000</" in xml
assert g.geometry == gc

def test_create_kml_geometry_geometrycollection_roundtrip(self) -> None:
Expand Down
3 changes: 2 additions & 1 deletion tests/geometries/linearring_test.py
Original file line number Diff line number Diff line change
Expand Up @@ -45,7 +45,8 @@ def test_to_string(self) -> None:
assert "LinearRing" in linear_ring.to_string()
assert (
"coordinates>0.000000,0.000000 0.000000,1.000000 1.000000,1.000000 "
"1.000000,0.000000 0.000000,0.000000</" in linear_ring.to_string()
"1.000000,0.000000 0.000000,0.000000</"
in linear_ring.to_string(precision=6)
)

def test_from_string(self) -> None:
Expand Down
2 changes: 1 addition & 1 deletion tests/geometries/linestring_test.py
Original file line number Diff line number Diff line change
Expand Up @@ -47,7 +47,7 @@ def test_to_string(self) -> None:
assert "LineString" in line_string.to_string()
assert (
"coordinates>1.000000,2.000000 2.000000,0.000000</"
in line_string.to_string()
in line_string.to_string(precision=6)
)

def test_from_string(self) -> None:
Expand Down
Loading
Loading