diff --git a/tests/gtk/test_row.py b/tests/gtk/test_row.py index 139e279..9572568 100644 --- a/tests/gtk/test_row.py +++ b/tests/gtk/test_row.py @@ -6,6 +6,64 @@ from gi.repository import Gtk from gi.repository import Adw +class TestFactory(unittest.TestCase): + """Tests our base Gtk.Factory to make Gtk.Inscriptions.""" + + def setUp(self): + """Set up common variables.""" + self.xunitrow = xfstestsdb.gtk.model.XunitRow("xunit/row") + self.listitem = Gtk.ListItem() + self.listitem.get_item = unittest.mock.Mock(return_value=self.xunitrow) + + self.factory = xfstestsdb.gtk.row.Factory() + + def test_init(self): + """Test that the Factory was initialized correctly.""" + self.assertIsInstance(self.factory, Gtk.SignalListItemFactory) + + def test_setup(self): + """Test that the factory implements the 'setup' signal.""" + with unittest.mock.patch.object(self.factory, + "do_setup") as mock_setup: + self.factory.emit("setup", self.listitem) + self.assertIsInstance(self.listitem.get_child(), Gtk.Inscription) + self.assertEqual(self.listitem.get_child().props.xalign, 0.5) + self.assertEqual(self.listitem.get_child().props.nat_chars, 10) + self.assertTrue(self.listitem.get_child().has_css_class("numeric")) + mock_setup.assert_called_with(self.listitem.get_child()) + + def test_bind(self): + """Test that the factory implements the 'bind' signal.""" + with unittest.mock.patch.object(self.factory, "do_bind") as mock_bind: + self.factory.emit("setup", self.listitem) + self.factory.emit("bind", self.listitem) + mock_bind.assert_called_with(self.xunitrow, + self.listitem.get_child()) + + def test_unbind(self): + """Test that the factory implements the 'unbind' signal.""" + with unittest.mock.patch.object(self.factory, + "do_unbind") as mock_unbind: + self.factory.emit("setup", self.listitem) + self.factory.emit("bind", self.listitem) + self.listitem.get_child().set_text("text") + + self.factory.emit("unbind", self.listitem) + self.assertIsNone(self.listitem.get_child().get_text()) + mock_unbind.assert_called_with(self.xunitrow, + self.listitem.get_child()) + + def test_teardown(self): + """Test that the factory implements the 'teardown' signal.""" + with unittest.mock.patch.object(self.factory, + "do_teardown") as mock_teardown: + self.factory.emit("setup", self.listitem) + child = self.listitem.get_child() + self.factory.emit("teardown", self.listitem) + self.assertIsNone(self.listitem.get_child()) + mock_teardown.assert_called_with(child) + + class TestLabelFactory(unittest.TestCase): """Tests our Gtk.Factory to make Gtk.Labels.""" @@ -15,12 +73,12 @@ class TestLabelFactory(unittest.TestCase): self.listitem = Gtk.ListItem() self.listitem.get_item = unittest.mock.Mock(return_value=self.testcase) - self.factory = xfstestsdb.gtk.row.LabelFactory("name") + self.factory = xfstestsdb.gtk.row.LabelFactory(property="name") self.group = xfstestsdb.gtk.row.LabelFactory.group def test_init(self): """Test that the factory was initialized correctly.""" - self.assertIsInstance(self.factory, Gtk.SignalListItemFactory) + self.assertIsInstance(self.factory, xfstestsdb.gtk.row.Factory) self.assertEqual(self.factory.property, "name") def test_size_group(self): @@ -33,8 +91,6 @@ class TestLabelFactory(unittest.TestCase): def test_setup(self): """Test that the factory implements the 'setup' signal.""" self.factory.emit("setup", self.listitem) - self.assertIsInstance(self.listitem.get_child(), Gtk.Label) - self.assertTrue(self.listitem.get_child().has_css_class("numeric")) self.assertIn(self.listitem.get_child(), self.group.get_widgets()) def test_bind(self): @@ -50,14 +106,13 @@ class TestLabelFactory(unittest.TestCase): self.factory.emit("setup", self.listitem) self.factory.emit("bind", self.listitem) self.factory.emit("unbind", self.listitem) - self.assertEqual(self.listitem.get_child().get_text(), "") + self.assertIsNone(self.listitem.get_child().get_text()) def test_teardown(self): """Test that the factory implements the 'teardown' signal.""" self.factory.emit("setup", self.listitem) child = self.listitem.get_child() self.factory.emit("teardown", self.listitem) - self.assertIsNone(self.listitem.get_child()) self.assertNotIn(child, self.group.get_widgets()) def test_styles(self): @@ -99,16 +154,9 @@ class TestResultFactory(unittest.TestCase): def test_init(self): """Test that the factory was initialized correctly.""" - self.assertIsInstance(self.factory, Gtk.SignalListItemFactory) + self.assertIsInstance(self.factory, xfstestsdb.gtk.row.Factory) self.assertEqual(self.factory.xunit, "xunit-1") - def test_setup(self): - """Test that the factory implements the 'setup' signal.""" - self.factory.emit("setup", self.listitem) - self.assertIsInstance(self.listitem.get_child(), Gtk.Label) - self.assertTrue(self.listitem.get_child().has_css_class("numeric")) - self.assertEqual(self.parent.get_child(), self.listitem.get_child()) - def test_bind_passed(self): """Test binding to a passing test.""" self.testcase.add_xunit("xunit-1", "passed", 3, "", None, None) @@ -119,7 +167,6 @@ class TestResultFactory(unittest.TestCase): self.assertTrue(self.parent.has_css_class("passed")) self.factory.emit("unbind", self.listitem) - self.assertEqual(self.listitem.get_child().get_text(), "") self.assertFalse(self.parent.has_css_class("passed")) def test_bind_skipped(self): @@ -134,7 +181,6 @@ class TestResultFactory(unittest.TestCase): self.assertTrue(self.parent.has_css_class("skipped")) self.factory.emit("unbind", self.listitem) - self.assertEqual(self.listitem.get_child().get_text(), "") self.assertFalse(self.parent.has_css_class("skipped")) def test_bind_failed(self): @@ -149,23 +195,16 @@ class TestResultFactory(unittest.TestCase): self.assertTrue(self.parent.has_css_class("failure")) self.factory.emit("unbind", self.listitem) - self.assertEqual(self.listitem.get_child().get_text(), "") self.assertFalse(self.parent.has_css_class("failure")) def test_bind_missing(self): """Test binding to a missing test.""" self.factory.emit("setup", self.listitem) self.factory.emit("bind", self.listitem) - self.assertEqual(self.listitem.get_child().get_text(), "") + self.assertIsNone(self.listitem.get_child().get_text()) self.factory.emit("unbind", self.listitem) - def test_teardown(self): - """Test that the factory implements the 'teardown' signal.""" - self.factory.emit("setup", self.listitem) - self.factory.emit("teardown", self.listitem) - self.assertIsNone(self.listitem.get_child()) - class TestSummaryFactory(unittest.TestCase): """Tests our Gtk.Factory to show Xfstests results summaries.""" @@ -180,15 +219,9 @@ class TestSummaryFactory(unittest.TestCase): def test_init(self): """Test that the factory was initialized correctly.""" - self.assertIsInstance(self.factory, Gtk.SignalListItemFactory) + self.assertIsInstance(self.factory, xfstestsdb.gtk.row.Factory) self.assertEqual(self.factory.xunit, "xunit-1") - def test_setup(self): - """Test that the factory implements the 'setup' signal.""" - self.factory.emit("setup", self.listitem) - self.assertIsInstance(self.listitem.get_child(), Gtk.Label) - self.assertTrue(self.listitem.get_child().has_css_class("numeric")) - def test_bind_passed(self): """Test binding to the passed tests summary.""" self.summary.add_xunit("xunit-1", 1, "testcase") @@ -198,7 +231,6 @@ class TestSummaryFactory(unittest.TestCase): self.assertTrue(self.listitem.get_child().has_css_class("success")) self.factory.emit("unbind", self.listitem) - self.assertEqual(self.listitem.get_child().get_text(), "") self.assertFalse(self.listitem.get_child().has_css_class("success")) def test_bind_failed(self): @@ -211,7 +243,6 @@ class TestSummaryFactory(unittest.TestCase): self.assertTrue(self.listitem.get_child().has_css_class("error")) self.factory.emit("unbind", self.listitem) - self.assertEqual(self.listitem.get_child().get_text(), "") self.assertFalse(self.listitem.get_child().has_css_class("error")) def test_bind_skipped(self): @@ -224,7 +255,6 @@ class TestSummaryFactory(unittest.TestCase): self.assertTrue(self.listitem.get_child().has_css_class("warning")) self.factory.emit("unbind", self.listitem) - self.assertEqual(self.listitem.get_child().get_text(), "") self.assertFalse(self.listitem.get_child().has_css_class("warning")) def test_bind_time(self): @@ -237,11 +267,4 @@ class TestSummaryFactory(unittest.TestCase): self.assertTrue(self.listitem.get_child().has_css_class("accent")) self.factory.emit("unbind", self.listitem) - self.assertEqual(self.listitem.get_child().get_text(), "") self.assertFalse(self.listitem.get_child().has_css_class("accent")) - - def test_teardown(self): - """Test that the factory implements the 'teardown' signal.""" - self.factory.emit("setup", self.listitem) - self.factory.emit("teardown", self.listitem) - self.assertIsNone(self.listitem.get_child()) diff --git a/xfstestsdb/gtk/row.py b/xfstestsdb/gtk/row.py index 3b4b8a4..4fe5e91 100644 --- a/xfstestsdb/gtk/row.py +++ b/xfstestsdb/gtk/row.py @@ -3,13 +3,58 @@ import typing from gi.repository import GObject from gi.repository import Gtk +from . import model STYLES = {"passed": "success", "failed": "error", "skipped": "warning", "time": "accent"} -class LabelFactory(Gtk.SignalListItemFactory): +class Factory(Gtk.SignalListItemFactory): + """Create Gtk.Inscriptions for each Gtk.ListItem.""" + + def __init__(self, *args, **kwargs): + """Initialize our InscriptionFactory.""" + super().__init__(*args, **kwargs) + self.connect("setup", self.__setup) + self.connect("bind", self.__bind) + self.connect("unbind", self.__unbind) + self.connect("teardown", self.__teardown) + + def __setup(self, factory: typing.Self, listitem: Gtk.ListItem) -> None: + """Set up a ListItem child widget.""" + child = Gtk.Inscription(xalign=0.5, nat_chars=10) + child.add_css_class("numeric") + self.do_setup(child) + listitem.set_child(child) + + def __bind(self, factory: typing.Self, listitem: Gtk.ListItem) -> None: + """Bind a ListItem to the child widget.""" + self.do_bind(listitem.get_item(), listitem.get_child()) + + def __unbind(self, factory: typing.Self, listitem: Gtk.ListItem) -> None: + """Unbind a ListItem from the child widget.""" + self.do_unbind(listitem.get_item(), listitem.get_child()) + listitem.get_child().set_text(None) + + def __teardown(self, factory: typing.Self, listitem: Gtk.ListItem) -> None: + self.do_teardown(listitem.get_child()) + listitem.set_child(None) + + def do_setup(self, child: Gtk.Inscription) -> None: + """Extra factory-specific setup for the child widget.""" + + def do_bind(self, row: model.XunitRow, child: Gtk.Inscription) -> None: + """Extra factory-specific binding work for the child widget.""" + + def do_unbind(self, row: model.XunitRow, child: Gtk.Inscription) -> None: + """Extra factory-specific unbinding work for the child widget.""" + + def do_teardown(self, child: Gtk.Inscription) -> None: + """Extra factory-specific teardown for the child widget.""" + + +class LabelFactory(Factory): """Create Gtk.Labels for each testcase.""" property = GObject.Property(type=str) @@ -18,42 +63,30 @@ class LabelFactory(Gtk.SignalListItemFactory): def __init__(self, property: str): """Initialize our InscriptionFactory.""" super().__init__(property=property) - self.connect("setup", self.do_setup) - self.connect("bind", self.do_bind) - self.connect("unbind", self.do_unbind) - self.connect("teardown", self.do_teardown) - def do_setup(self, factory: typing.Self, listitem: Gtk.ListItem) -> None: + def do_setup(self, child: Gtk.Inscription) -> None: """Set up a ListItem child widget.""" - child = Gtk.Label() - child.add_css_class("numeric") - listitem.set_child(child) LabelFactory.group.add_widget(child) - def do_bind(self, factory: typing.Self, listitem: Gtk.ListItem) -> None: + def do_bind(self, row: model.XunitRow, child: Gtk.Inscription) -> None: """Bind a ListItem to the child widget.""" - text = listitem.get_item().get_property(self.property) - child = listitem.get_child() + text = row.get_property(self.property) if style := STYLES.get(text): child.add_css_class(style) child.set_text(text) - def do_unbind(self, factory: typing.Self, listitem: Gtk.ListItem) -> None: + def do_unbind(self, row: model.XunitRow, child: Gtk.Inscription) -> None: """Unbind a ListItem from the child widget.""" - child = listitem.get_child() for style in STYLES.values(): child.remove_css_class(style) - child.set_text("") - def do_teardown(self, factory: typing.Self, - listitem: Gtk.ListItem) -> None: + def do_teardown(self, child: Gtk.Inscription) -> None: """Clean up a ListItem child widget.""" - if (child := listitem.get_child()) is not None: + if child is not None: LabelFactory.group.remove_widget(child) - listitem.set_child(None) -class ResultFactory(Gtk.SignalListItemFactory): +class ResultFactory(Factory): """Factory for making test result widgets.""" xunit = GObject.Property(type=str) @@ -61,43 +94,26 @@ class ResultFactory(Gtk.SignalListItemFactory): def __init__(self, xunit: str): """Initialize our ResultFactory.""" super().__init__(xunit=xunit) - self.connect("setup", self.do_setup) - self.connect("bind", self.do_bind) - self.connect("unbind", self.do_unbind) - self.connect("teardown", self.do_teardown) - def do_setup(self, factory: typing.Self, listitem: Gtk.ListItem) -> None: - """Set up a ListItem child widget.""" - listitem.set_child(Gtk.Label()) - listitem.get_child().add_css_class("numeric") - - def do_bind(self, factory: typing.Self, listitem: Gtk.ListItem) -> None: + def do_bind(self, row: model.TestCase, child: Gtk.Inscription) -> None: """Bind a ListItem to the child widget.""" - if (result := listitem.get_item()[self.xunit]) is None: + if (result := row[self.xunit]) is None: return if (text := result.status) == "passed": text = f"{result.time} seconds" - child = listitem.get_child() child.set_text(text) child.set_tooltip_text(result.message.lstrip(" -")) child.get_parent().add_css_class(result.status) - def do_unbind(self, factory: typing.Self, listitem: Gtk.ListItem) -> None: + def do_unbind(self, row: model.TestCase, child: Gtk.Inscription) -> None: """Unbind a ListItem from the child widget.""" - if (result := listitem.get_item()[self.xunit]) is not None: - child = listitem.get_child() - child.set_text("") + if (result := row[self.xunit]) is not None: child.get_parent().remove_css_class(result.status) - def do_teardown(self, factory: typing.Self, - listitem: Gtk.ListItem) -> None: - """Clean up a ListItem child widget.""" - listitem.set_child(None) - -class SummaryFactory(Gtk.SignalListItemFactory): +class SummaryFactory(Factory): """Factory for making test summary widgets.""" xunit = GObject.Property(type=str) @@ -105,31 +121,13 @@ class SummaryFactory(Gtk.SignalListItemFactory): def __init__(self, xunit: str): """Initialize our ResultFactory.""" super().__init__(xunit=xunit) - self.connect("setup", self.do_setup) - self.connect("bind", self.do_bind) - self.connect("unbind", self.do_unbind) - self.connect("teardown", self.do_teardown) - def do_setup(self, factory: typing.Self, listitem: Gtk.ListItem) -> None: - """Set up a ListItem child widget.""" - listitem.set_child(Gtk.Label()) - listitem.get_child().add_css_class("numeric") - - def do_bind(self, factory: typing.Self, listitem: Gtk.ListItem) -> None: + def do_bind(self, row: model.Summary, child: Gtk.Inscription) -> None: """Bind a ListItem to the child widget.""" - summary = listitem.get_item() - result = summary[self.xunit] - child = listitem.get_child() + result = row[self.xunit] child.set_text(str(result)) - child.add_css_class(STYLES[summary.name]) + child.add_css_class(STYLES[row.name]) - def do_unbind(self, factory: typing.Self, listitem: Gtk.ListItem) -> None: + def do_unbind(self, row: model.TestCase, child: Gtk.Inscription) -> None: """Unbind a ListItem from the child widget.""" - child = listitem.get_child() - child.set_text("") - child.remove_css_class(STYLES[listitem.get_item().name]) - - def do_teardown(self, factory: typing.Self, - listitem: Gtk.ListItem) -> None: - """Clean up a ListItem child widget.""" - listitem.set_child(None) + child.remove_css_class(STYLES[row.name])