"""Block selection: what the enforcer may and may not kill.""" from __future__ import annotations import unittest from datetime import datetime, timedelta, timezone from webrestrict.blocker import select_victims, self_protection from webrestrict.config import DeviceConfig NOW = datetime(2026, 10, 14, 20, 0, tzinfo=timezone.utc) def config(**overrides) -> DeviceConfig: base = dict( locked=True, until=(NOW + timedelta(minutes=30)).isoformat(), block=["notepad.exe", "steam.exe"], allow=["Spotify.exe"], ) base.update(overrides) return DeviceConfig(**base) PROCESSES = [ (100, "notepad.exe"), (101, "Notepad.EXE"), (200, "steam.exe"), (300, "Spotify.exe"), (400, "explorer.exe"), (500, "python.exe"), ] class SelectVictimsTests(unittest.TestCase): def test_blocks_every_matching_process(self): victims = select_victims(PROCESSES, config()) self.assertEqual([(v.pid, v.matched) for v in victims], [(100, "notepad"), (101, "notepad"), (200, "steam")]) def test_allowlist_wins(self): victims = select_victims(PROCESSES, config(allow=["spotify"])) self.assertNotIn(300, [v.pid for v in victims]) def test_nothing_is_blocked_when_unlocked(self): self.assertEqual(select_victims(PROCESSES, config(locked=False)), []) def test_nothing_is_blocked_when_the_blocklist_is_empty(self): self.assertEqual(select_victims(PROCESSES, config(block=[])), []) def test_nothing_is_blocked_after_until(self): expired = config(until=(NOW - timedelta(minutes=1)).isoformat()) self.assertEqual(select_victims(PROCESSES, expired, now=NOW), []) def test_protected_names_are_never_victims(self): victims = select_victims(PROCESSES, config(block=["explorer.exe"]), protected_names=["explorer.exe"]) self.assertEqual(victims, []) def test_protected_pids_are_never_victims(self): victims = select_victims(PROCESSES, config(block=["python.exe"]), protected_pids=[500]) self.assertEqual(victims, []) def test_duplicate_pids_are_reported_once(self): victims = select_victims([(100, "notepad.exe"), (100, "notepad.exe")], config()) self.assertEqual(len(victims), 1) def test_bad_rows_are_ignored(self): victims = select_victims([("x", "notepad.exe"), (0, ""), (None, None)], config()) self.assertEqual(victims, []) class SelfProtectionTests(unittest.TestCase): def test_includes_the_process_and_its_parents(self): pids, names = self_protection(10, ["python.exe", "pythonw.exe"], [5, 3, 1]) self.assertEqual(pids, {10, 5, 3, 1}) self.assertEqual(names, {"python.exe", "pythonw.exe"}) if __name__ == "__main__": unittest.main()