From 103b270662e971137763a2e5c0c44c5e2fa9ed38 Mon Sep 17 00:00:00 2001 From: Hans Ekkehard Plesser Date: Thu, 23 Nov 2023 14:11:36 +0100 Subject: [PATCH] Improve test for dictionary subsets --- testsuite/pytests/test_helper_functions.py | 70 +++++++++---------- .../pytests/test_sp/test_synaptic_elements.py | 13 ++-- .../test_sp/test_update_synaptic_elements.py | 18 ++--- testsuite/pytests/utilities/testutil.py | 17 +++++ 4 files changed, 63 insertions(+), 55 deletions(-) diff --git a/testsuite/pytests/test_helper_functions.py b/testsuite/pytests/test_helper_functions.py index 6ab61144ba..5a27b5ae19 100644 --- a/testsuite/pytests/test_helper_functions.py +++ b/testsuite/pytests/test_helper_functions.py @@ -19,39 +19,39 @@ # You should have received a copy of the GNU General Public License # along with NEST. If not, see . -import unittest - import nest - - -class TestHelperFunctions(unittest.TestCase): - def test_get_verbosity(self): - verbosity = nest.get_verbosity() - self.assertTrue(isinstance(verbosity, int)) - - def test_set_verbosity(self): - levels = [ - ("M_ALL", 0), - ("M_DEBUG", 5), - ("M_STATUS", 7), - ("M_INFO", 10), - ("M_DEPRECATED", 18), - ("M_WARNING", 20), - ("M_ERROR", 30), - ("M_FATAL", 40), - ("M_QUIET", 100), - ] - for level, code in levels: - nest.set_verbosity(level) - verbosity = nest.get_verbosity() - self.assertEqual(verbosity, code) - - -def suite(): - suite = unittest.makeSuite(TestHelperFunctions, "test") - return suite - - -if __name__ == "__main__": - runner = unittest.TextTestRunner(verbosity=2) - runner.run(suite()) +import pytest +import testutil + + +@pytest.mark.parametrize( + "level, value", + [ + ("M_ALL", 0), + ("M_DEBUG", 5), + ("M_STATUS", 7), + ("M_INFO", 10), + ("M_DEPRECATED", 18), + ("M_WARNING", 20), + ("M_ERROR", 30), + ("M_FATAL", 40), + ("M_QUIET", 100), + ], +) +def test_set_verbosity(level, value): + nest.set_verbosity(level) + assert nest.get_verbosity() == value + + +@pytest.mark.parametrize( + "a, b, expected", + [ + ({}, {}, True), + ({}, {"a": 5}, True), + ({"a": 5}, {"a": 5}, True), + ({"a": 7}, {"a": 5}, False), + ({"a": 5, "b": 3}, {"a": 5}, False), + ], +) +def test_dict_is_subset(a, b, expected): + assert testutil.dict_is_subset_of(a, b) == expected diff --git a/testsuite/pytests/test_sp/test_synaptic_elements.py b/testsuite/pytests/test_sp/test_synaptic_elements.py index 05f81deaf1..b2dd91d223 100644 --- a/testsuite/pytests/test_sp/test_synaptic_elements.py +++ b/testsuite/pytests/test_sp/test_synaptic_elements.py @@ -22,6 +22,7 @@ import unittest import nest +from testutil import dict_is_subset_of __author__ = "naveau" @@ -37,7 +38,7 @@ def test_set_status(self): nest.SetStatus(neuron, {"synaptic_elements": synaptic_element_dict}) neuron_synaptic_elements = nest.GetStatus(neuron, "synaptic_elements")[0] self.assertIn("SE", neuron_synaptic_elements) - self.assertEqual(neuron_synaptic_elements["SE"], synaptic_element_dict["SE"] | neuron_synaptic_elements["SE"]) + self.assertTrue(dict_is_subset_of(synaptic_element_dict["SE"], neuron_synaptic_elements["SE"])) def test_set_status_overwrite(self): synaptic_element_dict1 = {"SE1": {"z": 15.0, "growth_curve": "linear"}} @@ -50,9 +51,7 @@ def test_set_status_overwrite(self): neuron_synaptic_elements = nest.GetStatus(neuron, "synaptic_elements")[0] self.assertNotIn("SE1", neuron_synaptic_elements) self.assertIn("SE2", neuron_synaptic_elements) - self.assertEqual( - neuron_synaptic_elements["SE2"], synaptic_element_dict2["SE2"] | neuron_synaptic_elements["SE2"] - ) + self.assertTrue(dict_is_subset_of(synaptic_element_dict2["SE2"], neuron_synaptic_elements["SE2"])) def test_set_defaults(self): synaptic_element_dict = {"SE": {"z": 15.0, "growth_curve": "linear"}} @@ -61,7 +60,7 @@ def test_set_defaults(self): neuron = nest.Create("iaf_psc_alpha", 1) neuron_synaptic_elements = nest.GetStatus(neuron, "synaptic_elements")[0] self.assertIn("SE", neuron_synaptic_elements) - self.assertEqual(neuron_synaptic_elements["SE"], synaptic_element_dict["SE"] | neuron_synaptic_elements["SE"]) + self.assertTrue(dict_is_subset_of(synaptic_element_dict["SE"], neuron_synaptic_elements["SE"])) def test_set_defaults_overwrite(self): synaptic_element_dict1 = {"SE1": {"z": 15.0, "growth_curve": "linear"}} @@ -74,9 +73,7 @@ def test_set_defaults_overwrite(self): neuron_synaptic_elements = nest.GetStatus(neuron, "synaptic_elements")[0] self.assertNotIn("SE1", neuron_synaptic_elements) self.assertIn("SE2", neuron_synaptic_elements) - self.assertEqual( - neuron_synaptic_elements["SE2"], synaptic_element_dict2["SE2"] | neuron_synaptic_elements["SE2"] - ) + self.assertTrue(dict_is_subset_of(synaptic_element_dict2["SE2"], neuron_synaptic_elements["SE2"])) def suite(): diff --git a/testsuite/pytests/test_sp/test_update_synaptic_elements.py b/testsuite/pytests/test_sp/test_update_synaptic_elements.py index 7cdab28179..b74c807a10 100644 --- a/testsuite/pytests/test_sp/test_update_synaptic_elements.py +++ b/testsuite/pytests/test_sp/test_update_synaptic_elements.py @@ -22,6 +22,7 @@ import unittest import nest +from testutil import dict_is_subset_of class TestUpdateSynapticElements(unittest.TestCase): @@ -55,12 +56,8 @@ def test_update_synaptic_elements(self): self.assertIn("Den_ex", neuron_synaptic_elements) self.assertIn("Axon", neuron_synaptic_elements) - self.assertEqual( - neuron_synaptic_elements["Axon"], structural_p_elements["Axon"] | neuron_synaptic_elements["Axon"] - ) - self.assertEqual( - neuron_synaptic_elements["Den_ex"], structural_p_elements["Den_ex"] | neuron_synaptic_elements["Den_ex"] - ) + self.assertTrue(structural_p_elements["Axon"], neuron_synaptic_elements["Axon"]) + self.assertTrue(structural_p_elements["Den_ex"], neuron_synaptic_elements["Den_ex"]) # Update Axon elements nest.SetStatus(neuron, "synaptic_elements_param", elements_to_update) @@ -69,13 +66,10 @@ def test_update_synaptic_elements(self): self.assertIn("Axon", neuron_synaptic_elements) # Should have been updated - self.assertEqual( - neuron_synaptic_elements["Axon"], elements_to_update["Axon"] | neuron_synaptic_elements["Axon"] - ) + self.assertTrue(elements_to_update["Axon"], neuron_synaptic_elements["Axon"]) + # Should be unchanged - self.assertEqual( - neuron_synaptic_elements["Den_ex"], structural_p_elements["Den_ex"] | neuron_synaptic_elements["Den_ex"] - ) + self.assertTrue(structural_p_elements["Den_ex"], neuron_synaptic_elements["Den_ex"]) def suite(): diff --git a/testsuite/pytests/utilities/testutil.py b/testsuite/pytests/utilities/testutil.py index 9169c50c93..54a9e0dcdc 100644 --- a/testsuite/pytests/utilities/testutil.py +++ b/testsuite/pytests/utilities/testutil.py @@ -30,6 +30,23 @@ def parameter_fixture(name, default_factory=lambda: None): return pytest.fixture(autouse=True, name=name)(lambda request: getattr(request, "param", default_factory())) +def dict_is_subset_of(small, big): + """ + Return true if dict `small` is subset of dict `big`. + + `small` must contain all keys in `big` with the same values. + """ + + # See + # https://stackoverflow.com/questions/20050913/python-unittests-assertdictcontainssubset-recommended-alternative + # https://peps.python.org/pep-0584/ + # + # Note: | is **not** a symmetric operator for dicts. `small` must be the second operand to | as it determines + # the value of joint keys in the merged dictionary. + + return big == big | small + + def isin_approx(A, B, tol=1e-06): A = np.asarray(A) B = np.asarray(B)