step 8: harden docs and prepare rebuilt beta
This commit is contained in:
@@ -7,6 +7,8 @@ from dpg_map.cache import (
|
||||
DiskCacheConfig,
|
||||
DiskCacheMetadata,
|
||||
MemoryCacheConfig,
|
||||
clear_disk_cache_path,
|
||||
disk_cache_size_bytes,
|
||||
plan_disk_prune,
|
||||
tile_cache_path,
|
||||
write_disk_metadata,
|
||||
@@ -66,3 +68,23 @@ def test_disk_cache_prune_ordering(tmp_path: Path) -> None:
|
||||
planned = plan_disk_prune(tmp_path, 5, protected_paths={protected})
|
||||
|
||||
assert planned == [first, second]
|
||||
|
||||
|
||||
def test_provider_scoped_disk_cache_clear(tmp_path: Path) -> None:
|
||||
osm = tile_cache_path(tmp_path, "osm", 1, 1, 1)
|
||||
custom = tile_cache_path(tmp_path, "custom", 1, 1, 1)
|
||||
for path in (osm, custom):
|
||||
path.parent.mkdir(parents=True, exist_ok=True)
|
||||
path.write_bytes(b"abcde")
|
||||
write_disk_metadata(
|
||||
path.with_suffix(".json"),
|
||||
DiskCacheMetadata(url=str(path), last_accessed_at=1.0, size_bytes=5),
|
||||
)
|
||||
|
||||
assert disk_cache_size_bytes(tmp_path, provider="osm") == 5
|
||||
|
||||
clear_disk_cache_path(tmp_path, provider="osm")
|
||||
|
||||
assert not osm.exists()
|
||||
assert custom.exists()
|
||||
assert disk_cache_size_bytes(tmp_path) == 5
|
||||
|
||||
140
tests/test_hardening.py
Normal file
140
tests/test_hardening.py
Normal file
@@ -0,0 +1,140 @@
|
||||
from __future__ import annotations
|
||||
|
||||
from math import nan
|
||||
|
||||
import pytest
|
||||
|
||||
import dpg_map as dpgm
|
||||
from dpg_map.commands import CommandKind
|
||||
from dpg_map.exceptions import (
|
||||
CoordinateError,
|
||||
MapNotFoundError,
|
||||
OverlayNotFoundError,
|
||||
ProviderNotFoundError,
|
||||
)
|
||||
from dpg_map.overlays import TrajectoryOverlay
|
||||
from dpg_map.providers import TileProvider
|
||||
from dpg_map.renderer import drain_renderer_commands
|
||||
from dpg_map.state import DirtyFlags, InteractionState, create_map_state, get_map_state
|
||||
from dpg_map.tiles import TileID, TileResult, TileStatus
|
||||
|
||||
|
||||
def test_public_callables_have_docstrings() -> None:
|
||||
for name in dpgm.__all__:
|
||||
value = getattr(dpgm, name)
|
||||
if callable(value):
|
||||
assert value.__doc__, name
|
||||
|
||||
|
||||
def test_unknown_map_raises_public_error() -> None:
|
||||
with pytest.raises(MapNotFoundError):
|
||||
dpgm.get_center(map_tag="missing-map")
|
||||
|
||||
|
||||
def test_unknown_overlay_raises_public_error() -> None:
|
||||
create_map_state(tag="missing-overlay")
|
||||
|
||||
with pytest.raises(OverlayNotFoundError):
|
||||
dpgm.update_marker("vehicle", lat=47.0, lon=2.0, map_tag="missing-overlay")
|
||||
|
||||
|
||||
def test_unknown_provider_raises_public_error() -> None:
|
||||
create_map_state(tag="missing-provider")
|
||||
|
||||
with pytest.raises(ProviderNotFoundError):
|
||||
dpgm.set_provider("missing-provider-name", map_tag="missing-provider")
|
||||
|
||||
|
||||
def test_invalid_coordinates_raise_public_error() -> None:
|
||||
create_map_state(tag="invalid-coordinates")
|
||||
|
||||
with pytest.raises(CoordinateError):
|
||||
dpgm.add_marker("bad-lat", lat=91.0, lon=2.0, map_tag="invalid-coordinates")
|
||||
with pytest.raises(CoordinateError):
|
||||
dpgm.set_center(nan, 2.0, map_tag="invalid-coordinates")
|
||||
|
||||
|
||||
def test_mismatched_polyline_lat_lon_lengths_raise_public_error() -> None:
|
||||
create_map_state(tag="mismatched-polyline")
|
||||
|
||||
with pytest.raises(CoordinateError):
|
||||
dpgm.add_polyline("line", lats=[47.0, 47.1], lons=[2.0], map_tag="mismatched-polyline")
|
||||
|
||||
|
||||
def test_empty_trajectory_is_valid_for_live_updates() -> None:
|
||||
create_map_state(tag="empty-trajectory")
|
||||
|
||||
dpgm.add_trajectory("track", points=[], map_tag="empty-trajectory")
|
||||
|
||||
state = get_map_state("empty-trajectory")
|
||||
overlay = state.overlays["track"]
|
||||
assert isinstance(overlay, TrajectoryOverlay)
|
||||
assert overlay.points == ()
|
||||
|
||||
|
||||
def test_clear_deleted_overlay_raises_public_error() -> None:
|
||||
create_map_state(tag="deleted-overlay")
|
||||
dpgm.add_marker("vehicle", lat=47.0, lon=2.0, map_tag="deleted-overlay")
|
||||
|
||||
dpgm.delete_overlay("vehicle", map_tag="deleted-overlay")
|
||||
|
||||
with pytest.raises(OverlayNotFoundError):
|
||||
dpgm.delete_overlay("vehicle", map_tag="deleted-overlay")
|
||||
|
||||
|
||||
def test_provider_switch_ignores_tiles_that_finish_after_switch() -> None:
|
||||
provider = TileProvider(
|
||||
name="hardening-switch-provider",
|
||||
url_template="https://tiles.example.test/{z}/{x}/{y}.png",
|
||||
min_zoom=0,
|
||||
max_zoom=4,
|
||||
)
|
||||
dpgm.register_provider(provider)
|
||||
try:
|
||||
state = create_map_state(tag="provider-switch-loading", zoom=3)
|
||||
old_tile = TileID("osm", 3, 1, 2)
|
||||
with state.tile_manager._lock:
|
||||
state.tile_manager._loading.add(old_tile)
|
||||
|
||||
dpgm.set_provider("hardening-switch-provider", map_tag="provider-switch-loading")
|
||||
state.tile_manager._result_queue.put(
|
||||
TileResult(
|
||||
old_tile,
|
||||
generation=0,
|
||||
status=TileStatus.READY,
|
||||
width=1,
|
||||
height=1,
|
||||
pixels=(1.0, 1.0, 1.0, 1.0),
|
||||
source="network",
|
||||
)
|
||||
)
|
||||
|
||||
commands = drain_renderer_commands(state)
|
||||
accepted = state.tile_manager.drain_results(
|
||||
generation=state.generation,
|
||||
provider_name=state.provider.name,
|
||||
)
|
||||
|
||||
assert [command.kind for command in commands] == [CommandKind.SET_PROVIDER]
|
||||
assert accepted == []
|
||||
assert state.tile_manager.snapshot().stale_results == 1
|
||||
assert state.tile_manager.get_ready_tile(old_tile) is None
|
||||
finally:
|
||||
dpgm.unregister_provider("hardening-switch-provider")
|
||||
|
||||
|
||||
def test_overlay_update_preserves_active_drag_model_state() -> None:
|
||||
create_map_state(tag="update-while-dragging", center=(47.0, 2.0), zoom=9)
|
||||
dpgm.add_marker("vehicle", lat=47.0, lon=2.0, map_tag="update-while-dragging")
|
||||
state = get_map_state("update-while-dragging")
|
||||
state.command_queue.drain()
|
||||
state.dirty = DirtyFlags.NONE
|
||||
state.interaction = InteractionState(active_drag=True, last_mouse_position=(20.0, 30.0))
|
||||
|
||||
dpgm.update_marker("vehicle", lat=47.1, lon=2.1, map_tag="update-while-dragging")
|
||||
|
||||
assert state.interaction.active_drag is True
|
||||
assert state.interaction.last_mouse_position == (20.0, 30.0)
|
||||
assert state.center == (47.0, 2.0)
|
||||
assert state.zoom == 9
|
||||
assert state.dirty == DirtyFlags.OVERLAYS
|
||||
@@ -66,6 +66,17 @@ def test_layer_state_tracks_visibility_and_overlay_membership() -> None:
|
||||
assert "vehicle" not in state.overlays
|
||||
|
||||
|
||||
def test_add_layer_can_update_visibility_and_z_index() -> None:
|
||||
create_map_state(tag="layer-order")
|
||||
|
||||
dpgm.add_layer("fleet", z_index=25, show=False, map_tag="layer-order")
|
||||
dpgm.add_layer("fleet", z_index=30, show=True, map_tag="layer-order")
|
||||
|
||||
state = get_map_state("layer-order")
|
||||
assert state.layers["fleet"].show is True
|
||||
assert state.layers["fleet"].z_index == 30
|
||||
|
||||
|
||||
def test_threaded_marker_updates_coalesce_without_touching_view_or_drag_state() -> None:
|
||||
create_map_state(tag="threaded-marker", center=(47.0, 2.0), zoom=9)
|
||||
dpgm.add_marker("vehicle", lat=47.0, lon=2.0, map_tag="threaded-marker")
|
||||
|
||||
@@ -6,6 +6,7 @@ def test_package_exports_required_public_api() -> None:
|
||||
|
||||
expected = {
|
||||
"configure",
|
||||
"CacheStats",
|
||||
"TileProvider",
|
||||
"register_provider",
|
||||
"unregister_provider",
|
||||
|
||||
@@ -4,8 +4,10 @@ from typing import Any
|
||||
|
||||
import dpg_map as dpgm
|
||||
from dpg_map.commands import CommandKind, MapCommand
|
||||
from dpg_map.providers import TileProvider
|
||||
from dpg_map.renderer import MapRenderer, drain_renderer_commands
|
||||
from dpg_map.state import DirtyFlags, create_map_state
|
||||
from dpg_map.tiles import TileID, TileResult, TileStatus
|
||||
|
||||
|
||||
class FakeDpg:
|
||||
@@ -115,3 +117,60 @@ def test_overlay_update_drain_sets_only_overlay_dirty() -> None:
|
||||
drain_renderer_commands(state)
|
||||
|
||||
assert state.dirty == DirtyFlags.OVERLAYS
|
||||
|
||||
|
||||
def test_provider_switch_keeps_overlays_and_invalidates_tiles() -> None:
|
||||
provider = TileProvider(
|
||||
name="renderer-switch-provider",
|
||||
url_template="https://tiles.example.test/{z}/{x}/{y}.png",
|
||||
min_zoom=3,
|
||||
max_zoom=4,
|
||||
attribution="Example",
|
||||
)
|
||||
dpgm.register_provider(provider)
|
||||
try:
|
||||
state = create_map_state(tag="provider-switch", center=(47.0, 2.0), zoom=8)
|
||||
dpgm.add_marker("vehicle", lat=47.0, lon=2.0, map_tag="provider-switch")
|
||||
state.command_queue.drain()
|
||||
state.dirty = DirtyFlags.NONE
|
||||
tile_id = TileID("osm", 3, 1, 2)
|
||||
state.tile_manager._result_queue.put(
|
||||
TileResult(
|
||||
tile_id,
|
||||
generation=state.generation,
|
||||
status=TileStatus.READY,
|
||||
width=1,
|
||||
height=1,
|
||||
pixels=(1.0, 1.0, 1.0, 1.0),
|
||||
source="disk",
|
||||
)
|
||||
)
|
||||
state.tile_manager.drain_results(generation=state.generation, provider_name="osm")
|
||||
state.tile_manager.set_texture_tag(tile_id, "old-texture")
|
||||
|
||||
dpgm.set_provider("renderer-switch-provider", map_tag="provider-switch")
|
||||
drain_renderer_commands(state)
|
||||
|
||||
assert "vehicle" in state.overlays
|
||||
assert state.center == (47.0, 2.0)
|
||||
assert state.zoom == 4
|
||||
assert state.generation == 1
|
||||
assert state.provider.name == "renderer-switch-provider"
|
||||
assert state.dirty & DirtyFlags.PROVIDER
|
||||
assert state.dirty & DirtyFlags.TILES
|
||||
assert state.dirty & DirtyFlags.OVERLAYS
|
||||
assert state.tile_manager.get_ready_tile(tile_id) is None
|
||||
assert state.tile_manager.take_texture_deletions() == ["old-texture"]
|
||||
finally:
|
||||
dpgm.unregister_provider("renderer-switch-provider")
|
||||
|
||||
|
||||
def test_map_scoped_clear_disk_cache_command_keeps_dearpygui_out_of_caller_thread() -> None:
|
||||
state = create_map_state(tag="clear-disk-command")
|
||||
state.dirty = DirtyFlags.NONE
|
||||
|
||||
dpgm.clear_disk_cache(map_tag="clear-disk-command")
|
||||
|
||||
commands = state.command_queue.drain()
|
||||
assert [command.kind for command in commands] == [CommandKind.CLEAR_DISK_CACHE]
|
||||
assert state.dirty == DirtyFlags.TILES
|
||||
|
||||
Reference in New Issue
Block a user