"""Fixtures every test gets. All three are about not touching the machine the tests run on, or anyone else's. The cache: a lookup writes to ``~/.cache`` by default, and a test run that touches the real one leaves entries behind and reads back entries an earlier version wrote. Redirecting it per test makes each run start from nothing. The settings: locking a frequency out writes it into ``config.yaml``, and a test that reached the real one would silently change what the next real scan does. The constant is replaced in every module that holds a copy, so that forgetting to pass a directory somewhere cannot end in someone's own settings. The network: a licence lookup goes to a public database and returns a real person's name and address. No test has any business doing that. """ import pytest import bandsaunter.browse import bandsaunter.callsign import bandsaunter.cli import bandsaunter.config import bandsaunter.tui @pytest.fixture(autouse=True) def isolated_cache(tmp_path_factory, monkeypatch): monkeypatch.setenv("XDG_CACHE_HOME", str(tmp_path_factory.mktemp("cache"))) @pytest.fixture(autouse=True) def no_licence_lookups(monkeypatch): """No test may contact the licence database. One did, silently, and passed -- it was only visible because the assertion it failed printed a real operator's address. A test that wants answers stubs this itself; anything else fails loudly rather than going to the network and being slow, flaky and rude about it. """ def refuse(self, url, call): raise AssertionError(f"a test tried to look up {call} for real") monkeypatch.setattr(bandsaunter.callsign.CallsignBook, "_request", refuse) class NoNetwork(BaseException): """Raised when a test reaches for the network. Deliberately not an ``Exception``: the code that fetches map tiles and looks aircraft up treats any ordinary failure as "no map today" and carries on, which would turn this guard into a silent pass. """ @pytest.fixture(autouse=True) def no_aircraft_lookups(monkeypatch): """Nor may a test ask a register who an aircraft is.""" import bandsaunter.flights def refuse(self, url): raise NoNetwork(f"a test tried to fetch {url} for real") monkeypatch.setattr(bandsaunter.flights.FlightBook, "_request", refuse) @pytest.fixture(autouse=True) def no_map_tiles(monkeypatch): """Nor fetch map tiles from somebody's tile server. A test that wants a map builds its own tiles and passes them in; one that forgets fails here rather than drawing an evening's worth of requests at a volunteer-funded service. """ import bandsaunter.basemap def refuse(request, timeout=None): where = getattr(request, "full_url", request) raise NoNetwork(f"a test tried to fetch {where} for real") monkeypatch.setattr(bandsaunter.basemap.urllib.request, "urlopen", refuse) @pytest.fixture(autouse=True) def isolated_settings(tmp_path_factory, monkeypatch): where = tmp_path_factory.mktemp("config") for module in (bandsaunter.config, bandsaunter.browse, bandsaunter.cli, bandsaunter.tui): if hasattr(module, "DEFAULT_CONFIG_DIR"): monkeypatch.setattr(module, "DEFAULT_CONFIG_DIR", where) if hasattr(module, "DEFAULT_CONFIG_PATH"): monkeypatch.setattr(module, "DEFAULT_CONFIG_PATH", where / "config.yaml") monkeypatch.setenv("BANDSAUNTER_CONFIG_DIR", str(where)) return where