diff --git a/tests/gtk/test_tree.py b/tests/gtk/test_tree.py index 4aa2cb0..09a4536 100644 --- a/tests/gtk/test_tree.py +++ b/tests/gtk/test_tree.py @@ -193,3 +193,77 @@ class TestDateDeviceList(unittest.TestCase): with self.assertRaises(IndexError): self.assertIsNone(tree[5]) + + +class TestTagDeviceList(unittest.TestCase): + """Test case for our TagDeviceList GObject.""" + + def setUp(self): + """Set up common variables.""" + self.tag = xfstestsdb.gtk.tree.TagDeviceList(name="mytag") + + def test_init(self): + """Test creating a TagDeviceList instance.""" + self.assertIsInstance(self.tag, GObject.GObject) + self.assertIsInstance(self.tag, Gio.ListModel) + self.assertEqual(self.tag.name, "mytag") + self.assertEqual(str(self.tag), "mytag") + + def test_lt(self): + """Test comparing TagDeviceList instances.""" + tag_a = xfstestsdb.gtk.tree.TagDeviceList(name="a") + tag_b = xfstestsdb.gtk.tree.TagDeviceList(name="b") + + now = datetime.datetime.now() + then = now - datetime.timedelta(seconds=42) + tag_a.add_run(1, "/dev/vda1", now) + tag_b.add_run(2, "/dev/vda2", then) + + self.assertTrue(tag_a < tag_b) + self.assertFalse(tag_b < tag_a) + self.assertFalse(tag_a < tag_a) + + tag_a.add_run(2, "/dev/vda2", then) + self.assertTrue(tag_b < tag_a) + + def test_get_item_type(self): + """Test the get_item_type() function.""" + self.assertEqual(self.tag.get_item_type(), + xfstestsdb.gtk.tree.DeviceRunsList.__gtype__) + + def test_get_n_items(self): + """Test the get_n_items() function.""" + self.assertEqual(self.tag.get_n_items(), 0) + self.assertEqual(self.tag.n_items, 0) + + self.tag.add_run(1, "/dev/vda1", datetime.datetime.now()) + self.assertEqual(self.tag.get_n_items(), 1) + self.assertEqual(self.tag.n_items, 1) + + def test_get_item(self): + """Test the get_item() function.""" + now = datetime.datetime.now() + then = now - datetime.timedelta(seconds=42) + + self.tag.add_run(1, "/dev/vda2", now) + self.assertIsInstance(self.tag[0], xfstestsdb.gtk.tree.DeviceRunsList) + self.assertEqual(self.tag[0].name, "/dev/vda2") + self.assertEqual(self.tag[0][0].runid, 1) + self.assertEqual(self.tag[0][0].timestamp, now) + self.assertEqual(self.tag[0][0].ftime, "%c") + + self.tag.add_run(2, "/dev/vda1", then) + self.assertEqual(self.tag[0].name, "/dev/vda1") + self.assertEqual(self.tag[1].name, "/dev/vda2") + + def test_get_earliest_run(self): + """Test the get_earliest_run() function.""" + self.assertIsNone(self.tag.get_earliest_run()) + + now = datetime.datetime.now() + self.tag.add_run(1, "/dev/vda1", now) + self.assertEqual(self.tag.get_earliest_run().runid, 1) + + then = now - datetime.timedelta(seconds=42) + self.tag.add_run(2, "/dev/vda2", then) + self.assertEqual(self.tag.get_earliest_run().runid, 2) diff --git a/xfstestsdb/gtk/tree.py b/xfstestsdb/gtk/tree.py index 07f3e7e..6c537f9 100644 --- a/xfstestsdb/gtk/tree.py +++ b/xfstestsdb/gtk/tree.py @@ -126,3 +126,57 @@ class DateDeviceList(GObject.GObject, Gio.ListModel): min = datetime.datetime.combine(date, datetime.time()) max = min + datetime.timedelta(days=1) return (min, max) + + +class TagDeviceList(GObject.GObject, Gio.ListModel): + """Contains a single tag with multiple devices and runs.""" + + name = GObject.Property(type=str) + n_items = GObject.Property(type=int) + + def __init__(self, name: str) -> None: + """Initialize our TagDeviceList.""" + super().__init__(name=name) + self.__devices = [] + + def __lt__(self, rhs: typing.Self) -> bool: + """Compare two TagDeviceList objects.""" + lhs_run = self.get_earliest_run() + rhs_run = rhs.get_earliest_run() + if lhs_run.runid == rhs_run.runid: + return self.name > rhs.name + return lhs_run > rhs_run + + def __str__(self) -> str: + """Get the name of this tag.""" + return self.name + + def do_get_item_type(self) -> GObject.GType: + """Get the type of objects in the list.""" + return DeviceRunsList.__gtype__ + + def do_get_n_items(self) -> int: + """Get the number of devices added to this tag.""" + return self.n_items + + def do_get_item(self, n: int) -> DeviceRunsList: + """Get the device at the nth position.""" + return self.__devices[n] + + def add_run(self, runid: int, device: str, + timestamp: datetime.datetime) -> None: + """Add a run to the Tag's list.""" + pos = bisect.bisect_left(self.__devices, device, key=str) + if pos < len(self.__devices) and self.__devices[pos].name == device: + dev = self.__devices[pos] + else: + dev = DeviceRunsList(device) + self.__devices.insert(pos, dev) + + dev.add_run(runid, timestamp, "%c") + self.n_items = len(self.__devices) + + def get_earliest_run(self) -> XfstestsRun | None: + """Get the earliest run added to the tag.""" + runs = [d.get_earliest_run() for d in self.__devices] + return min(runs, default=None)