generated from Grigo/AndroidTemplate
173 lines
5.5 KiB
Python
173 lines
5.5 KiB
Python
import core.elevation as elev
|
|
|
|
|
|
class _FakeResponse:
|
|
def __init__(self, payload):
|
|
self._payload = payload
|
|
|
|
def raise_for_status(self):
|
|
return None
|
|
|
|
def json(self):
|
|
return self._payload
|
|
|
|
|
|
class _FakeClient:
|
|
def __init__(self, **kwargs):
|
|
self.kwargs = kwargs
|
|
|
|
def __enter__(self):
|
|
return self
|
|
|
|
def __exit__(self, *args):
|
|
return False
|
|
|
|
def get(self, url, params=None):
|
|
return _FakeResponse({"elevation": [152.0]})
|
|
|
|
|
|
def test_probe_elevation_api_ok(monkeypatch):
|
|
monkeypatch.setattr(elev, "_probe_checked_at", 0.0)
|
|
monkeypatch.setattr(elev.httpx, "Client", _FakeClient)
|
|
|
|
status = elev.probe_elevation_api(force=True)
|
|
|
|
assert status["ok"] is True
|
|
assert status["error"] is None
|
|
|
|
|
|
def test_fetch_skips_when_unreachable(monkeypatch):
|
|
monkeypatch.setattr(
|
|
elev,
|
|
"probe_elevation_api",
|
|
lambda force=False: {"ok": False, "url": elev.ELEVATION_API_URL, "error": "down"},
|
|
)
|
|
|
|
vals = elev.fetch_elevations_batch([55.75], [37.62])
|
|
|
|
assert vals == [None]
|
|
|
|
|
|
def test_build_profile_reports_unreachable(monkeypatch):
|
|
monkeypatch.setattr(
|
|
elev,
|
|
"probe_elevation_api",
|
|
lambda force=False: {"ok": False, "url": elev.ELEVATION_API_URL, "error": "down"},
|
|
)
|
|
|
|
profile = elev.build_elevation_profile(
|
|
[{"lat": 55.75, "lon": 37.62}, {"lat": 55.76, "lon": 37.63}],
|
|
10,
|
|
)
|
|
|
|
assert profile["points"] == []
|
|
assert "unreachable" in profile["api_error"]
|
|
|
|
|
|
def test_resample_track_path_count_even_spacing():
|
|
pts = [{"lat": 55.0, "lon": 37.0}, {"lat": 55.01, "lon": 37.0}]
|
|
samples = elev.resample_track_path_count(pts, 50)
|
|
assert len(samples) == 50
|
|
assert samples[0]["dist_m"] == 0.0
|
|
assert samples[-1]["dist_m"] > samples[0]["dist_m"]
|
|
gaps = [samples[i]["dist_m"] - samples[i - 1]["dist_m"] for i in range(1, len(samples))]
|
|
assert max(gaps) - min(gaps) < 1.0
|
|
|
|
|
|
def test_build_profile_target_points(monkeypatch):
|
|
monkeypatch.setattr(elev, "_probe_checked_at", 0.0)
|
|
monkeypatch.setattr(elev, "probe_elevation_api", lambda force=False: {"ok": True, "error": None})
|
|
monkeypatch.setattr(
|
|
elev,
|
|
"fetch_elevations_batch",
|
|
lambda lats, lons: [100.0 + i for i in range(len(lats))],
|
|
)
|
|
|
|
profile = elev.build_elevation_profile(
|
|
[{"lat": 55.0, "lon": 37.0}, {"lat": 55.01, "lon": 37.0}],
|
|
target_points=120,
|
|
)
|
|
|
|
assert len(profile["points"]) == 120
|
|
assert profile["step_m"] > 0
|
|
|
|
|
|
def test_find_nearest_hill_unreachable(monkeypatch):
|
|
monkeypatch.setattr(
|
|
elev,
|
|
"probe_elevation_api",
|
|
lambda force=False: {"ok": False, "url": elev.ELEVATION_API_URL, "error": "down"},
|
|
)
|
|
result = elev.find_nearest_hill(55.75, 37.62)
|
|
assert result["ok"] is False
|
|
|
|
|
|
def test_find_nearest_hill_picks_nearest_peak(monkeypatch):
|
|
monkeypatch.setattr(elev, "_probe_checked_at", 0.0)
|
|
monkeypatch.setattr(elev, "probe_elevation_api", lambda force=False: {"ok": True, "error": None})
|
|
|
|
def fake_batch(lats, lons):
|
|
out = []
|
|
for la, lo in zip(lats, lons):
|
|
if abs(la - 55.75) < 1e-4 and abs(lo - 37.62) < 1e-4:
|
|
out.append(100.0)
|
|
elif la > 55.75:
|
|
out.append(130.0)
|
|
else:
|
|
out.append(95.0)
|
|
return out
|
|
|
|
monkeypatch.setattr(elev, "fetch_elevations_batch", fake_batch)
|
|
result = elev.find_nearest_hill(55.75, 37.62, radius_m=2000, step_m=300, min_prominence_m=8)
|
|
assert result["ok"] is True
|
|
assert result["hill"]["elevation_m"] >= 120.0
|
|
|
|
|
|
def test_build_elevation_grid_delta(monkeypatch):
|
|
monkeypatch.setattr(elev, "_probe_checked_at", 0.0)
|
|
monkeypatch.setattr(elev, "probe_elevation_api", lambda force=False: {"ok": True, "error": None})
|
|
|
|
def fake_batch(lats, lons):
|
|
return [100.0 + (la - 55.75) * 1000.0 for la, lo in zip(lats, lons)]
|
|
|
|
monkeypatch.setattr(elev, "fetch_elevation_m", lambda lat, lon: 100.0)
|
|
monkeypatch.setattr(elev, "fetch_elevations_batch", fake_batch)
|
|
|
|
result = elev.build_elevation_grid(55.75, 37.62, radius_m=100, step_m=10)
|
|
assert result["ok"] is True
|
|
assert result["step_m"] == 10
|
|
assert len(result["points"]) > 0
|
|
assert result["min_delta_m"] <= 0 <= result["max_delta_m"]
|
|
assert all("delta_m" in p for p in result["points"])
|
|
|
|
|
|
def test_build_elevation_grid_fine_step_small_radius(monkeypatch):
|
|
monkeypatch.setattr(elev, "_probe_checked_at", 0.0)
|
|
monkeypatch.setattr(elev, "probe_elevation_api", lambda force=False: {"ok": True, "error": None})
|
|
monkeypatch.setattr(elev, "fetch_elevation_m", lambda lat, lon: 120.0)
|
|
monkeypatch.setattr(
|
|
elev,
|
|
"fetch_elevations_batch",
|
|
lambda lats, lons: [120.0 + i * 0.1 for i in range(len(lats))],
|
|
)
|
|
|
|
result = elev.build_elevation_grid(55.75, 37.62, radius_m=50, step_m=1)
|
|
assert result["ok"] is True
|
|
assert result["step_m"] == 1
|
|
assert len(result["points"]) > 1000
|
|
|
|
|
|
def test_build_elevation_grid_limits_points(monkeypatch):
|
|
monkeypatch.setattr(elev, "_probe_checked_at", 0.0)
|
|
monkeypatch.setattr(elev, "probe_elevation_api", lambda force=False: {"ok": True, "error": None})
|
|
monkeypatch.setattr(elev, "fetch_elevation_m", lambda lat, lon: 50.0)
|
|
monkeypatch.setattr(
|
|
elev,
|
|
"fetch_elevations_batch",
|
|
lambda lats, lons: [50.0] * len(lats),
|
|
)
|
|
|
|
step = elev._resolve_grid_step(55.75, 37.62, 500.0, 5.0)
|
|
cells = elev._sample_circular_grid(55.75, 37.62, 500.0, step)
|
|
assert len(cells) <= elev._MAX_GRID_POINTS
|