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
3 changes: 3 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -256,3 +256,6 @@ Thumbs.db
.idea/

# End of https://www.toptal.com/developers/gitignore/api/intellij,python

# Claude Code settings
.claude/*
698 changes: 698 additions & 0 deletions poetry.lock

Large diffs are not rendered by default.

82 changes: 82 additions & 0 deletions pyproject.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,82 @@
[tool.poetry]
name = "geospatial-tile-processor"
version = "0.1.0"
description = "A tool for processing geospatial vector tiles and extracting GeoJSON features"
authors = ["Author <author@example.com>"]
readme = "Readme.md"
packages = [{include = "*.py", from = "."}]

[tool.poetry.dependencies]
python = "^3.8"
certifi = "2020.12.5"
chardet = "4.0.0"
future = "0.18.2"
idna = "2.10"
mapbox-vector-tile = "1.2.0"
protobuf = "3.15.7"
pyclipper = "^1.3.0"
requests = "^2.31.0"
Shapely = "^2.0.0"
six = "1.15.0"
urllib3 = "1.26.4"

[tool.poetry.group.test.dependencies]
pytest = "^7.4.0"
pytest-cov = "^4.1.0"
pytest-mock = "^3.11.1"


[tool.pytest.ini_options]
testpaths = ["tests"]
python_files = ["test_*.py", "*_test.py"]
python_classes = ["Test*"]
python_functions = ["test_*"]
addopts = [
"-v",
"--strict-markers",
"--strict-config",
"--cov=.",
"--cov-report=html:htmlcov",
"--cov-report=xml:coverage.xml",
"--cov-report=term-missing",
"--cov-fail-under=80"
]
markers = [
"unit: marks tests as unit tests (fast, isolated)",
"integration: marks tests as integration tests (slower, with dependencies)",
"slow: marks tests as slow (deselect with '-m \"not slow\"')"
]

[tool.coverage.run]
source = ["."]
omit = [
"tests/*",
"*/tests/*",
"test_*.py",
"*_test.py",
".venv/*",
"venv/*",
"*/venv/*",
"*/.venv/*"
]

[tool.coverage.report]
exclude_lines = [
"pragma: no cover",
"def __repr__",
"if self.debug:",
"if settings.DEBUG",
"raise AssertionError",
"raise NotImplementedError",
"if 0:",
"if __name__ == .__main__.:"
]
show_missing = true
precision = 2

[tool.coverage.html]
directory = "htmlcov"

[build-system]
requires = ["poetry-core"]
build-backend = "poetry.core.masonry.api"
Empty file added tests/__init__.py
Empty file.
145 changes: 145 additions & 0 deletions tests/conftest.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,145 @@
import pytest
import tempfile
import shutil
import os
from unittest.mock import Mock, patch
import json


@pytest.fixture
def temp_dir():
"""Create a temporary directory that gets cleaned up after the test."""
temp_path = tempfile.mkdtemp()
yield temp_path
shutil.rmtree(temp_path, ignore_errors=True)


@pytest.fixture
def sample_geojson_feature():
"""Sample GeoJSON feature for testing."""
return {
"type": "Feature",
"id": 1,
"geometry": {
"type": "Point",
"coordinates": [100.0, 0.5]
},
"properties": {
"name": "Sample Point"
}
}


@pytest.fixture
def sample_polygon_feature():
"""Sample polygon GeoJSON feature for testing."""
return {
"type": "Feature",
"id": 2,
"geometry": {
"type": "Polygon",
"coordinates": [[[100.0, 0.0], [101.0, 0.0], [101.0, 1.0], [100.0, 1.0], [100.0, 0.0]]]
},
"properties": {
"area": "sample"
}
}


@pytest.fixture
def sample_vector_tile_data():
"""Sample vector tile data structure for testing."""
return {
"Gebaeudeflaeche": {
"features": [
{
"geometry": {
"type": "Point",
"coordinates": [2048, 2048]
},
"properties": {"name": "test"},
"id": 1
}
]
}
}


@pytest.fixture
def mock_tile_coordinates():
"""Mock tile coordinates for testing."""
return {
"x": 17602,
"y": 11333,
"zoom": 15
}


@pytest.fixture
def mock_requests_response():
"""Mock requests response object."""
mock_response = Mock()
mock_response.content = b'mock vector tile content'
mock_response.status_code = 200
return mock_response


@pytest.fixture
def create_test_file():
"""Factory fixture to create test files with specific content."""
created_files = []

def _create_file(filepath, content):
os.makedirs(os.path.dirname(filepath), exist_ok=True)
with open(filepath, 'w') as f:
if isinstance(content, dict):
json.dump(content, f)
else:
f.write(content)
created_files.append(filepath)
return filepath

yield _create_file

# Cleanup
for filepath in created_files:
try:
os.remove(filepath)
except (OSError, FileNotFoundError):
pass


@pytest.fixture
def mock_environment_variables():
"""Mock environment variables for testing."""
with patch.dict(os.environ, {
'TEST_VAR': 'test_value',
'DEBUG': 'False'
}, clear=False):
yield


@pytest.fixture(scope="session")
def test_constants():
"""Test constants that can be reused across tests."""
return {
'MVT_EXTENT': 4096,
'DEFAULT_ZOOM': 15,
'SAMPLE_LAT': 47.23,
'SAMPLE_LON': 5.53
}


@pytest.fixture
def captured_stdout(capsys):
"""Convenience fixture to capture stdout easily."""
def _capture():
return capsys.readouterr()
return _capture


@pytest.fixture(autouse=True)
def reset_global_state():
"""Automatically reset any global state before each test."""
yield
# Add any global state cleanup here if needed
Empty file added tests/integration/__init__.py
Empty file.
65 changes: 65 additions & 0 deletions tests/test_setup_validation.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,65 @@
import pytest
import sys
import os

# Add the project root to the Python path for imports
sys.path.insert(0, os.path.dirname(os.path.dirname(os.path.abspath(__file__))))

import parser
import scraper


class TestSetupValidation:
"""Validation tests to ensure the testing infrastructure is working correctly."""

def test_imports_work(self):
"""Test that we can import the main modules."""
assert parser is not None
assert scraper is not None

def test_parser_functions_exist(self):
"""Test that expected functions exist in parser module."""
assert hasattr(parser, 'num2deg')
assert hasattr(parser, 'listdirs')
assert hasattr(parser, 'vectorToCoords')

def test_scraper_functions_exist(self):
"""Test that expected functions exist in scraper module."""
assert hasattr(scraper, 'deg2num')
assert hasattr(scraper, 'save_result')

@pytest.mark.unit
def test_num2deg_function(self):
"""Test the num2deg function with known values."""
lat, lon = parser.num2deg(0, 0, 0)
assert lat == pytest.approx(85.0511, abs=0.01)
assert lon == pytest.approx(-180.0, abs=0.01)

@pytest.mark.unit
def test_deg2num_function(self):
"""Test the deg2num function with known values."""
x, y = scraper.deg2num(0, 0, 1)
assert x == 1
assert y == 1

def test_fixtures_available(self, temp_dir, sample_geojson_feature):
"""Test that our custom fixtures are working."""
assert os.path.exists(temp_dir)
assert sample_geojson_feature['type'] == 'Feature'

@pytest.mark.slow
def test_slow_marker_works(self):
"""Test that the slow marker is working (this test should be skipped with -m 'not slow')."""
import time
time.sleep(0.1) # Simulate a slow test
assert True

def test_coverage_config(self):
"""Test that coverage configuration is accessible."""
# This test mainly ensures pytest-cov is installed and working
assert True

def test_mock_functionality(self, mock_requests_response):
"""Test that pytest-mock fixtures are working."""
assert mock_requests_response.status_code == 200
assert mock_requests_response.content == b'mock vector tile content'
Empty file added tests/unit/__init__.py
Empty file.