from dataclasses import dataclass, field from hooked_containers import events as e from hooked_containers.mapping import HookedMapping @dataclass class HookTracker: added: list[e.AddItemEvent] = field(default_factory=list) set: list[e.SetItemEvent] = field(default_factory=list) removed: list[e.RemoveItemEvent] = field(default_factory=list) def hook(self, event: e.ChangeEvent): match event: case e.AddItemEvent(): self.added.append(event.item) case e.SetItemEvent(): self.set.append(event.item) case e.RemoveItemEvent(): self.removed.append(event.item) class TestHookedMapping: class TestConstruction: def test_empty(self): m = HookedMapping({}) assert m._data == {} assert dict(m) == {} def test_with_existing(self): existing = {"a": 1, "b": 2} og_id = id(existing) m = HookedMapping(existing) assert id(m._data) == og_id assert dict(m) == existing def test_nesting(self): existing = {"a": {"x": 1}, "b": {"y": 2}} m = HookedMapping(existing) assert dict(m) == existing assert dict(m["a"]) == {"x": 1} assert dict(m["b"]) == {"y": 2} class TestMappingOps: def test_setitem(self): tracker = HookTracker() m = HookedMapping({}, tracker.hook) m["a"] = 1 assert m._data == {"a": 1} assert tracker.added == [1] def test_nested_setitem(self): tracker = HookTracker() m = HookedMapping({"a": {}}, tracker.hook) m["a"]["x"] = 1 assert m._data == {"a": {"x": 1}} assert tracker.added == [1] def test_getitem(self): m = HookedMapping({"a": 1}) assert m["a"] == 1 def test_delitem(self): tracker = HookTracker() m = HookedMapping({"a": 1}, tracker.hook) del m["a"] assert not m["a"] assert tracker.removed == [1]