from __future__ import annotations import json from pathlib import Path from boltclam import realtime from boltclam.realtime import browser_download_roots, snapshot from boltclam.winlock import copy_for_scan def test_snapshot_finds_final_files_and_skips_partials(tmp_path): root = tmp_path / "Downloads" root.mkdir() (root / "old.exe").write_bytes(b"abc") (root / "new.crdownload").write_bytes(b"partial") (root / ".hidden").write_bytes(b"hidden") sub = root / "Sub" sub.mkdir() (sub / "inside.zip").write_bytes(b"zip") found = snapshot([root]) names = {Path(value[2]).name for value in found.values()} assert names == {"old.exe", "inside.zip"} def test_chromium_download_preference_is_watched(tmp_path, monkeypatch): local = tmp_path / "Local" roaming = tmp_path / "Roaming" monkeypatch.setenv("LOCALAPPDATA", str(local)) monkeypatch.setenv("APPDATA", str(roaming)) download = tmp_path / "Custom Downloads" download.mkdir() profile = local / "Google" / "Chrome" / "User Data" / "Default" profile.mkdir(parents=True) (profile / "Preferences").write_text(json.dumps({ "download": {"default_directory": str(download)}}), encoding="utf-8") monkeypatch.setattr(realtime.paths, "browser_download_roots", lambda: []) roots = browser_download_roots() assert download.resolve() in [path.resolve() for path in roots] def test_firefox_download_preference_is_watched(tmp_path, monkeypatch): local = tmp_path / "Local" roaming = tmp_path / "Roaming" monkeypatch.setenv("LOCALAPPDATA", str(local)) monkeypatch.setenv("APPDATA", str(roaming)) download = tmp_path / "Firefox Downloads" download.mkdir() profile = roaming / "Mozilla" / "Firefox" / "Profiles" / "abc.default" profile.mkdir(parents=True) escaped = str(download).replace("\\", "\\\\") (profile / "prefs.js").write_text( f'user_pref("browser.download.dir", "{escaped}");\n', encoding="utf-8") monkeypatch.setattr(realtime.paths, "browser_download_roots", lambda: []) roots = browser_download_roots() assert download.resolve() in [path.resolve() for path in roots] def test_watcher_stops_cleanly_instead_of_raising(monkeypatch, qapp): messages: list[str] = [] watcher = realtime.DownloadWatcher(interval=0.1) watcher.watch_status.connect(messages.append) monkeypatch.setattr(realtime, "browser_download_roots", lambda extra: (_ for _ in ()).throw( RuntimeError("simulated watcher failure"))) watcher.start() assert watcher.wait(3000) qapp.processEvents() assert not watcher.isRunning() assert "stopped" in " ".join(messages).lower() def test_copy_for_scan_preserves_bytes(tmp_path): source = tmp_path / "download.exe" source.write_bytes(b"sample bytes") destination = tmp_path / "copy.bin" locker, exclusive = copy_for_scan(source, destination, attempts=1, delay=0) try: assert destination.read_bytes() == b"sample bytes" assert isinstance(exclusive, bool) finally: locker.close()