import json
import pytest
import maplibre_tiles as mlt
POINT = {"type": "Point", "coordinates": [1, 2]}
LINE = {"type": "LineString", "coordinates": [[0, 0], [5, 5]]}
def _fc(features):
return {"type": "FeatureCollection", "features": features}
def _feature(geometry, **members):
return {"type": "Feature", "geometry": geometry, **members}
def test_point_feature_collection_roundtrips():
blob = mlt.encode_geojson(_fc([_feature(POINT)]), "roads", extent=4096)
assert isinstance(blob, bytes)
layers = mlt.decode_mlt(blob)
assert len(layers) == 1
layer = layers[0]
assert layer.name == "roads"
assert layer.extent == 4096
assert len(layer.features) == 1
assert layer.features[0].geometry_type == "Point"
fc = json.loads(mlt.decode_mlt_to_geojson(blob))
assert fc["features"][0]["geometry"] == POINT
def test_extent_defaults_to_4096():
blob = mlt.encode_geojson(_fc([_feature(POINT)]), "roads")
assert mlt.decode_mlt(blob)[0].extent == 4096
def test_scalar_properties_roundtrip():
blob = mlt.encode_geojson(
_fc(
[
_feature(
POINT,
properties={
"name": "main",
"lanes": 3,
"oneway": True,
"width": 3.5,
},
)
]
),
"roads",
)
props = mlt.decode_mlt(blob)[0].features[0].properties
assert props["name"] == "main"
assert props["lanes"] == 3
assert props["oneway"] is True
assert props["width"] == 3.5
def test_feature_id_roundtrips():
blob = mlt.encode_geojson(
_fc(
[
_feature(POINT, id=42),
_feature({"type": "Point", "coordinates": [3, 4]}),
]
),
"roads",
)
feats = mlt.decode_mlt(blob)[0].features
assert feats[0].id == 42
assert feats[1].id is None
@pytest.mark.parametrize(
"geometry",
[
{"type": "Point", "coordinates": [2048, 1024]},
{"type": "MultiPoint", "coordinates": [[1, 1], [2, 2]]},
{"type": "LineString", "coordinates": [[0, 0], [10, 0], [10, 10]]},
{
"type": "MultiLineString",
"coordinates": [[[0, 0], [1, 1]], [[2, 2], [3, 3]]],
},
{
"type": "Polygon",
"coordinates": [
[[0, 0], [10, 0], [10, 10], [0, 10], [0, 0]],
[[2, 2], [4, 2], [4, 4], [2, 4], [2, 2]],
],
},
{
"type": "MultiPolygon",
"coordinates": [
[[[0, 0], [5, 0], [5, 5], [0, 5], [0, 0]]],
[[[6, 6], [8, 6], [8, 8], [6, 8], [6, 6]]],
],
},
],
ids=lambda g: g["type"],
)
def test_geometry_kinds_roundtrip(geometry):
blob = mlt.encode_geojson(_fc([_feature(geometry)]), "l")
fc = json.loads(mlt.decode_mlt_to_geojson(blob))
assert fc["features"][0]["geometry"] == geometry
def test_multi_layer_tile_via_concatenation():
roads = mlt.encode_geojson(
_fc([_feature(POINT, id=1)]),
"roads",
)
water = mlt.encode_geojson(
_fc([_feature(LINE, id=2)]),
"water",
)
tile = b"".join([roads, water])
layers = mlt.decode_mlt(tile)
assert [layer.name for layer in layers] == ["roads", "water"]
assert mlt.list_layers(tile) == ["roads", "water"]
@pytest.mark.parametrize(
"feature",
[
_feature(POINT, properties={"tags": {"a": 1}}),
_feature(POINT, properties={"tags": [1, 2]}),
_feature(POINT, id="way/1"),
_feature(POINT, id=-1),
_feature(POINT, id=3.5),
_feature(None),
_feature({"type": "LineString", "coordinates": []}),
_feature({"type": "Point", "coordinates": [1.2, 3.4]}),
_feature({"type": "Point", "coordinates": [1, 2, 3]}),
{"geometry": POINT}, ],
ids=[
"nested_dict_prop",
"nested_list_prop",
"string_id",
"negative_id",
"float_id",
"null_geometry",
"empty_geometry",
"fractional_coord",
"three_d_coord",
"not_a_feature",
],
)
def test_strict_feature_errors(feature):
with pytest.raises(ValueError):
mlt.encode_geojson(_fc([feature]), "r")
def test_non_feature_collection_input_errors():
with pytest.raises(ValueError):
mlt.encode_geojson(_feature(POINT), "r")
def test_empty_layer_errors():
with pytest.raises(ValueError):
mlt.encode_geojson(_fc([]), "r")
POLYGON = {
"type": "Polygon",
"coordinates": [[[0, 0], [10, 0], [10, 10], [0, 10], [0, 0]]],
}
def test_tessellate_polygon_returns_bytes():
blob = mlt.encode_geojson(_fc([_feature(POLYGON)]), "l", tessellate=True)
assert isinstance(blob, bytes)
@pytest.mark.parametrize("sort", ["auto", "morton", "hilbert", "id", "none"])
def test_sort_modes_return_bytes(sort):
blob = mlt.encode_geojson(_fc([_feature(POLYGON, id=1)]), "l", sort=sort)
assert isinstance(blob, bytes)
def test_invalid_sort_errors():
with pytest.raises(ValueError):
mlt.encode_geojson(_fc([_feature(POINT)]), "l", sort="bogus")
@pytest.mark.parametrize("shared_dict", [True, False])
def test_shared_dict_returns_bytes(shared_dict):
blob = mlt.encode_geojson(
_fc([_feature(POINT, properties={"name": "main"})]),
"l",
shared_dict=shared_dict,
)
assert isinstance(blob, bytes)
@pytest.mark.parametrize("flag", ["fsst", "fastpfor"])
@pytest.mark.parametrize("value", [True, False])
def test_compression_toggles_return_bytes(flag, value):
blob = mlt.encode_geojson(
_fc([_feature(POINT, properties={"name": "main", "lanes": 3})]),
"l",
**{flag: value},
)
assert isinstance(blob, bytes)