gtk: Add a ListModel for holding the XfstestsRuns attached to a device

I will add to this to create a TreeModel to display individual runs
associated with each device in the sidebar.

Signed-off-by: Anna Schumaker <anna@nowheycreamery.com>
This commit is contained in:
Anna Schumaker 2023-11-02 14:59:27 -04:00
parent bf668fc936
commit 70274c448c
2 changed files with 194 additions and 0 deletions

120
tests/gtk/test_tree.py Normal file
View File

@ -0,0 +1,120 @@
# Copyright 2023 (c) Anna Schumaker.
"""Tests our xfstests run selector tree."""
import datetime
import unittest
import xfstestsdb.gtk.tree
from gi.repository import GObject
from gi.repository import Gio
class TestXfstestsRun(unittest.TestCase):
"""Test case for our XfstestsRun GObject."""
def setUp(self):
"""Set up common variables."""
self.now = datetime.datetime.now()
self.run = xfstestsdb.gtk.tree.XfstestsRun(1, self.now)
def test_run(self):
"""Test the XfsetstsRun object."""
self.assertIsInstance(self.run, GObject.GObject)
self.assertEqual(self.run.runid, 1)
self.assertEqual(self.run.timestamp, self.now)
def test_gt(self):
"""Test the XfstestsRun Greater-Than operator."""
soon = self.now + datetime.timedelta(seconds=5)
run2 = xfstestsdb.gtk.tree.XfstestsRun(2, soon)
run3 = xfstestsdb.gtk.tree.XfstestsRun(3, soon)
self.assertTrue(run2 > self.run)
self.assertFalse(self.run > run2)
self.assertFalse(self.run > self.run)
self.assertTrue(run3 > run2)
self.assertFalse(run2 > run3)
def test_lt(self):
"""Test the XfstestsRun Less-Than operator."""
soon = self.now + datetime.timedelta(seconds=5)
run2 = xfstestsdb.gtk.tree.XfstestsRun(2, soon)
run3 = xfstestsdb.gtk.tree.XfstestsRun(3, soon)
self.assertTrue(self.run < run2)
self.assertFalse(run2 < self.run)
self.assertFalse(self.run < self.run)
self.assertTrue(run2 < run3)
self.assertFalse(run3 < run2)
def test_str(self):
"""Test converting an XfstestsRun to a string."""
self.assertEqual(self.run.ftime, "%T")
self.assertEqual(str(self.run), f"#1: {self.now.strftime('%T')}")
self.run.ftime = "%c"
self.assertEqual(str(self.run), f"#1: {self.now.strftime('%c')}")
class TestDeviceRunModel(unittest.TestCase):
"""Test case for our DeviceRow GObject."""
def setUp(self):
"""Set up common variables."""
self.device = xfstestsdb.gtk.tree.DeviceRunsList(name="/dev/vda1")
def test_init(self):
"""Test creating a DeviceRow instance."""
self.assertIsInstance(self.device, GObject.GObject)
self.assertIsInstance(self.device, Gio.ListModel)
self.assertEqual(self.device.name, "/dev/vda1")
self.assertEqual(str(self.device), "/dev/vda1")
def test_lt(self):
"""Test comparing DeviceRow instances."""
dev_a = xfstestsdb.gtk.tree.DeviceRunsList(name="a")
dev_b = xfstestsdb.gtk.tree.DeviceRunsList(name="b")
self.assertTrue(dev_a < dev_b)
self.assertFalse(dev_b < dev_a)
self.assertFalse(dev_a < dev_a)
def test_get_item_type(self):
"""Test the get_item_type() function."""
self.assertEqual(self.device.get_item_type(),
xfstestsdb.gtk.tree.XfstestsRun.__gtype__)
def test_get_n_items(self):
"""Test the get_n_items() function."""
self.assertEqual(self.device.get_n_items(), 0)
self.assertEqual(self.device.n_items, 0)
self.device.add_run(1, datetime.datetime.now())
self.assertEqual(self.device.get_n_items(), 1)
self.assertEqual(self.device.n_items, 1)
def test_get_item(self):
"""Test the get_item() function."""
now = datetime.datetime.now()
then = now - datetime.timedelta(seconds=42)
self.device.add_run(1, now)
self.assertIsInstance(self.device[0], xfstestsdb.gtk.tree.XfstestsRun)
self.assertEqual(self.device[0].runid, 1)
self.assertEqual(self.device[0].timestamp, now)
self.device.add_run(2, then, "%c")
self.assertEqual(self.device[0].runid, 2)
self.assertEqual(self.device[0].ftime, "%c")
self.assertEqual(self.device[1].runid, 1)
def test_get_earliest_run(self):
"""Test the get_earliest_run() function."""
self.assertIsNone(self.device.get_earliest_run())
now = datetime.datetime.now()
self.device.add_run(1, now)
self.assertEqual(self.device.get_earliest_run().runid, 1)
then = now - datetime.timedelta(seconds=42)
self.device.add_run(2, then)
self.assertEqual(self.device.get_earliest_run().runid, 2)

74
xfstestsdb/gtk/tree.py Normal file
View File

@ -0,0 +1,74 @@
# Copyright 2023 (c) Anna Schumaker.
"""Our tree model for selecting an xfstests run to view."""
import bisect
import datetime
import typing
from gi.repository import GObject
from gi.repository import Gio
class XfstestsRun(GObject.GObject):
"""A single XfstessRun."""
timestamp = GObject.Property(type=GObject.TYPE_PYOBJECT)
runid = GObject.Property(type=int)
ftime = GObject.Property(type=str)
def __init__(self, runid: int, timestamp: datetime.datetime,
ftime: str = "%T") -> None:
"""Initialize an XfstestsRun instance."""
super().__init__(timestamp=timestamp, runid=runid, ftime=ftime)
def __gt__(self, rhs: typing.Self) -> bool:
"""Compare the timestamps an runids of two XfstestRun objects."""
return (self.timestamp, self.runid) > (rhs.timestamp, rhs.runid)
def __lt__(self, rhs: typing.Self) -> bool:
"""Compare the timestamps and runids of two XfstestsRun objects."""
return (self.timestamp, self.runid) < (rhs.timestamp, rhs.runid)
def __str__(self) -> str:
"""Get a string representation of this run."""
return f"#{self.runid}: {self.timestamp.strftime(self.ftime)}"
class DeviceRunsList(GObject.GObject, Gio.ListModel):
"""Contains a single test device with multiple runs."""
name = GObject.Property(type=str)
n_items = GObject.Property(type=int)
def __init__(self, name: str) -> None:
"""Initialize our DeviceRunsList."""
super().__init__(name=name)
self.__runs = []
def __lt__(self, rhs: typing.Self) -> bool:
"""Compare two DeviceRunsList objects."""
return self.name < rhs.name
def __str__(self) -> str:
"""Get the name of this device."""
return self.name
def do_get_item_type(self) -> GObject.GType:
"""Get the type of objects in the list."""
return XfstestsRun.__gtype__
def do_get_n_items(self) -> int:
"""Get the number of runs added to this device."""
return self.n_items
def do_get_item(self, n: int) -> XfstestsRun:
"""Get the run at the nth position."""
return self.__runs[n]
def add_run(self, runid: int, timestamp: datetime.datetime,
ftime: str = "%T") -> None:
"""Add a run to the Device's list."""
bisect.insort(self.__runs, XfstestsRun(runid, timestamp, ftime))
self.n_items = len(self.__runs)
def get_earliest_run(self) -> XfstestsRun | None:
"""Get the earliest XfstestsRun that we know about."""
return self.__runs[0] if self.n_items > 0 else None