From 14634af83c912e3225ee820c6edbb53bc83ffd31 Mon Sep 17 00:00:00 2001 From: Jakob Ketterl Date: Tue, 24 Mar 2020 20:36:26 +0100 Subject: [PATCH] add layer add / remove events + tests --- owrx/property/__init__.py | 33 +++++++++++-- test/property/test_property_stack.py | 71 ++++++++++++++++++++++++++++ 2 files changed, 100 insertions(+), 4 deletions(-) diff --git a/owrx/property/__init__.py b/owrx/property/__init__.py index 486b9fe..5db390a 100644 --- a/owrx/property/__init__.py +++ b/owrx/property/__init__.py @@ -40,6 +40,10 @@ class PropertyManager(ABC): def __dict__(self): pass + @abstractmethod + def keys(self): + pass + def collect(self, *props): return PropertyFilter(self, *props) @@ -95,6 +99,9 @@ class PropertyLayer(PropertyManager): def __dict__(self): return {k: v for k, v in self.properties.items()} + def keys(self): + return self.properties.keys() + class PropertyFilter(PropertyManager): def __init__(self, pm: PropertyManager, *props: str): @@ -126,6 +133,9 @@ class PropertyFilter(PropertyManager): def __dict__(self): return {k: v for k, v in self.pm.__dict__().items() if k in self.props} + def keys(self): + return [k for k in self.pm.keys() if k in self.props] + class PropertyStack(PropertyManager): def __init__(self): @@ -136,6 +146,10 @@ class PropertyStack(PropertyManager): """ highest priority = 0 """ + for key in pm.keys(): + if key not in self or self[key] != pm[key]: + self._fireCallbacks(key, pm[key]) + self.layers.append({"priority": priority, "props": pm}) def eventClosure(name, value): @@ -152,6 +166,12 @@ class PropertyStack(PropertyManager): for layer in self.layers: if layer["props"] == pm: self.layers.remove(layer) + for key in pm.keys(): + if key in self: + if self[key] != pm[key]: + self._fireCallbacks(key, self[key]) + else: + self._fireCallbacks(key, None) def _getTopLayer(self, item): layers = [la["props"] for la in sorted(self.layers, key=lambda l: l["priority"])] @@ -159,7 +179,8 @@ class PropertyStack(PropertyManager): if item in m: return m # return top layer by default - return layers[0] + if layers: + return layers[0] def __getitem__(self, item): layer = self._getTopLayer(item) @@ -171,8 +192,12 @@ class PropertyStack(PropertyManager): def __contains__(self, item): layer = self._getTopLayer(item) - return layer.__contains__(item) + if layer: + return layer.__contains__(item) + return False def __dict__(self): - keys = [key for l in self.layers for key in l["props"].__dict__().keys()] - return {k: self.__getitem__(k) for k in keys} + return {k: self.__getitem__(k) for k in self.keys()} + + def keys(self): + return set([key for l in self.layers for key in l["props"].keys()]) diff --git a/test/property/test_property_stack.py b/test/property/test_property_stack.py index ff83635..b2658ef 100644 --- a/test/property/test_property_stack.py +++ b/test/property/test_property_stack.py @@ -65,3 +65,74 @@ class PropertyStackTest(TestCase): mock.method.assert_not_called() high_layer["testkey"] = "modified high value" mock.method.assert_called_once_with("testkey", "modified high value") + + def testPropertyEventOnLayerAdd(self): + low_layer = PropertyLayer() + low_layer["testkey"] = "low value" + stack = PropertyStack() + stack.addLayer(1, low_layer) + mock = Mock() + stack.wireProperty("testkey", mock.method) + mock.reset_mock() + high_layer = PropertyLayer() + high_layer["testkey"] = "high value" + stack.addLayer(0, high_layer) + mock.method.assert_called_once_with("high value") + + def testNoEventOnExistingValue(self): + low_layer = PropertyLayer() + low_layer["testkey"] = "same value" + stack = PropertyStack() + stack.addLayer(1, low_layer) + mock = Mock() + stack.wireProperty("testkey", mock.method) + mock.reset_mock() + high_layer = PropertyLayer() + high_layer["testkey"] = "same value" + stack.addLayer(0, high_layer) + mock.method.assert_not_called() + + def testEventOnLayerWithNewProperty(self): + low_layer = PropertyLayer() + low_layer["existingkey"] = "existing value" + stack = PropertyStack() + stack.addLayer(1, low_layer) + mock = Mock() + stack.wireProperty("newkey", mock.method) + high_layer = PropertyLayer() + high_layer["newkey"] = "new value" + stack.addLayer(0, high_layer) + mock.method.assert_called_once_with("new value") + + def testEventOnLayerRemoval(self): + low_layer = PropertyLayer() + high_layer = PropertyLayer() + stack = PropertyStack() + stack.addLayer(1, low_layer) + stack.addLayer(0, high_layer) + low_layer["testkey"] = "low value" + high_layer["testkey"] = "high value" + + mock = Mock() + stack.wireProperty("testkey", mock.method) + mock.method.assert_called_once_with("high value") + mock.reset_mock() + stack.removeLayer(high_layer) + mock.method.assert_called_once_with("low value") + + def testNoneOnKeyRemoval(self): + low_layer = PropertyLayer() + high_layer = PropertyLayer() + stack = PropertyStack() + stack.addLayer(1, low_layer) + stack.addLayer(0, high_layer) + low_layer["testkey"] = "low value" + high_layer["testkey"] = "high value" + high_layer["unique key"] = "unique value" + + mock = Mock() + stack.wireProperty("unique key", mock.method) + mock.method.assert_called_once_with("unique value") + mock.reset_mock() + stack.removeLayer(high_layer) + mock.method.assert_called_once_with(None)