gtk: Create an XunitList base class

The XunitList implements the Gio.ListModel interface, and builds in some
virtual functions to query and fill out the rows in the list in a
standard way. I also update the TestCaseList and SummaryList to both
inherit from this class.

Signed-off-by: Anna Schumaker <anna@nowheycreamery.com>
This commit is contained in:
Anna Schumaker 2023-08-15 13:56:27 -04:00
parent c45ec1909e
commit 5dc7735ba7
2 changed files with 112 additions and 103 deletions

View File

@ -58,6 +58,49 @@ class TestXunitRow(unittest.TestCase):
self.assertEqual(xunit.name, "xunit-2") self.assertEqual(xunit.name, "xunit-2")
class TestXunitList(unittest.TestCase):
"""Test case for our base XunitList object."""
def setUp(self):
"""Set up common variables."""
self.xfstestsdb = xfstestsdb.Command()
with unittest.mock.patch("sys.stdout"):
self.xfstestsdb.run(["new", "/dev/vda1"])
self.xfstestsdb.run(["xunit", "read", "--name", "xunit-1",
"1", str(tests.xunit.XUNIT_1)])
self.xfstestsdb.run(["xunit", "read", "--name", "xunit-2",
"1", str(tests.xunit.XUNIT_1)])
self.xulist = xfstestsdb.gtk.model.XunitList(self.xfstestsdb.sql, 1)
def test_init(self):
"""Test that the XunitList was set up properly."""
self.assertIsInstance(self.xulist, GObject.GObject)
self.assertIsInstance(self.xulist, Gio.ListModel)
self.assertEqual(self.xulist.runid, 1)
def test_get_item_type(self):
"""Test the get_item_type() function."""
self.assertEqual(self.xulist.get_item_type(),
xfstestsdb.gtk.model.XunitRow.__gtype__)
def test_get_n_items(self):
"""Test the get_n_items() function."""
self.assertEqual(self.xulist.get_n_items(), 0)
self.assertEqual(self.xulist.n_items, 0)
self.xulist.n_items = 2
self.assertEqual(self.xulist.get_n_items(), 2)
def test_get_item(self):
"""Test the get_item() function."""
self.assertIsNone(self.xulist.get_item(0))
def test_get_xunits(self):
"""Test the get_xunits() function."""
self.assertListEqual(self.xulist.get_xunits(), ["xunit-1", "xunit-2"])
class TestTestResult(unittest.TestCase): class TestTestResult(unittest.TestCase):
"""Tests a single TestCase Xunit instance.""" """Tests a single TestCase Xunit instance."""
@ -133,18 +176,8 @@ class TestCaseList(unittest.TestCase):
def test_init(self): def test_init(self):
"""Test that the TestCaseList was set up properly.""" """Test that the TestCaseList was set up properly."""
self.assertIsInstance(self.tclist, GObject.GObject) self.assertIsInstance(self.tclist, xfstestsdb.gtk.model.XunitList)
self.assertIsInstance(self.tclist, Gio.ListModel)
self.assertEqual(self.tclist.runid, 1) self.assertEqual(self.tclist.runid, 1)
def test_get_item_type(self):
"""Test the get_item_type() function."""
self.assertEqual(self.tclist.get_item_type(),
xfstestsdb.gtk.model.TestCase.__gtype__)
def test_get_n_items(self):
"""Test the get_n_items() function."""
self.assertEqual(self.tclist.get_n_items(), 10)
self.assertEqual(self.tclist.n_items, 10) self.assertEqual(self.tclist.n_items, 10)
def test_get_item(self): def test_get_item(self):
@ -163,10 +196,6 @@ class TestCaseList(unittest.TestCase):
self.assertIsNone(self.tclist.get_item(10)) self.assertIsNone(self.tclist.get_item(10))
def test_get_xunits(self):
"""Test the get_xunits() function."""
self.assertListEqual(self.tclist.get_xunits(), ["xunit-1", "xunit-2"])
class TestCaseFilter(unittest.TestCase): class TestCaseFilter(unittest.TestCase):
"""Tests our Gtk.Filter customized for filtering TestCases.""" """Tests our Gtk.Filter customized for filtering TestCases."""
@ -314,18 +343,8 @@ class TestSummaryList(unittest.TestCase):
def test_init(self): def test_init(self):
"""Test that the SummaryList was set up properly.""" """Test that the SummaryList was set up properly."""
self.assertIsInstance(self.summary, GObject.GObject) self.assertIsInstance(self.summary, xfstestsdb.gtk.model.XunitList)
self.assertIsInstance(self.summary, Gio.ListModel)
self.assertEqual(self.summary.runid, 1) self.assertEqual(self.summary.runid, 1)
def test_get_item_type(self):
"""Test the get_item_type() function."""
self.assertEqual(self.summary.get_item_type(),
xfstestsdb.gtk.model.Summary.__gtype__)
def test_get_n_items(self):
"""Test the get_n_items() function."""
self.assertEqual(self.summary.get_n_items(), 4)
self.assertEqual(self.summary.n_items, 4) self.assertEqual(self.summary.n_items, 4)
def test_get_item(self): def test_get_item(self):
@ -342,7 +361,3 @@ class TestSummaryList(unittest.TestCase):
case "skipped": expected = {"3 testcases"} case "skipped": expected = {"3 testcases"}
case "time": expected = {"43 seconds"} case "time": expected = {"43 seconds"}
self.assertSetEqual(summary.get_results(), expected) self.assertSetEqual(summary.get_results(), expected)
def test_get_xunits(self):
"""Test the get_xunits() function."""
self.assertListEqual(self.summary.get_xunits(), ["xunit-1", "xunit-2"])

View File

@ -1,5 +1,6 @@
# Copyright 2023 (c) Anna Schumaker. # Copyright 2023 (c) Anna Schumaker.
"""Our Testcase Gio.ListModel.""" """Our Testcase Gio.ListModel."""
import sqlite3
import typing import typing
from gi.repository import GObject from gi.repository import GObject
from gi.repository import Gio from gi.repository import Gio
@ -48,6 +49,50 @@ class XunitRow(GObject.GObject):
return {str(xunit) for xunit in self.__xunits.values()} return {str(xunit) for xunit in self.__xunits.values()}
class XunitList(GObject.GObject, Gio.ListModel):
"""A list of XunitRows for a specific Xfstests Run."""
runid = GObject.Property(type=int)
n_items = GObject.Property(type=int)
def __init__(self, sql: sqlite.Connection, runid: int) -> None:
"""Initialize an XunitList."""
super().__init__(runid=runid)
self.__xunits = set()
rows = {}
for row in self.do_query(sql).fetchall():
self.do_parse(rows, row)
self.__xunits.add(row["xunit"])
self.__items = sorted(rows.values())
self.n_items = len(self.__items)
def do_get_item_type(self) -> GObject.GType:
"""Get the type of the objects in the list."""
return XunitRow.__gtype__
def do_get_n_items(self) -> int:
"""Get the number of items in the list."""
return self.n_items
def do_get_item(self, n: int) -> XunitRow | None:
"""Get a specific item on the list."""
return self.__items[n] if n < self.n_items else None
def do_parse(self, rows: dict[XunitRow], row: sqlite3.Row) -> None:
"""Parse a sqlite3.Row and add it to the rows dict."""
def do_query(self, sql: sqlite.Connection) -> sqlite3.Cursor:
"""Query the database."""
return sql("SELECT name AS xunit FROM xunits WHERE runid=?",
self.runid)
def get_xunits(self) -> list[str]:
"""Get a list of xunits attached to this xfstests run."""
return sorted(self.__xunits)
class TestResult(XunitCell): class TestResult(XunitCell):
"""The results for a single TestCase with a specific Xunit.""" """The results for a single TestCase with a specific Xunit."""
@ -75,46 +120,20 @@ class TestCase(XunitRow):
stderr=("" if stderr is None else stderr)) stderr=("" if stderr is None else stderr))
class TestCaseList(GObject.GObject, Gio.ListModel): class TestCaseList(XunitList):
"""A list of TestCases for a specific Xfstests Run.""" """A list of TestCases for a specific Xfstests Run."""
runid = GObject.Property(type=int) def do_query(self, sql: sqlite.Connection) -> sqlite3.Cursor:
n_items = GObject.Property(type=int) """Query the database for testcase results."""
return sql("""SELECT testcase, xunit, status, time,
message, stdout, stderr
FROM testcases_view WHERE runid=?""", self.runid)
def __init__(self, sql: sqlite.Connection, runid: int) -> None: def do_parse(self, rows: dict[TestCase], row: sqlite3.Cursor) -> None:
"""Initialize a TestCaseList.""" """Parse the data in the row and add it to the rows dict."""
super().__init__(runid=runid) testcase = rows.setdefault(row["testcase"], TestCase(row["testcase"]))
self.__xunits = set() testcase.add_xunit(row["xunit"], row["status"], row["time"],
row["message"], row["stdout"], row["stderr"])
cases = {}
cur = sql("""SELECT testcase, xunit, status,
time, message, stdout, stderr
FROM testcases_view WHERE runid=?""", runid)
for row in cur.fetchall():
testcase = cases.setdefault(row["testcase"],
TestCase(row["testcase"]))
testcase.add_xunit(row["xunit"], row["status"], row["time"],
row["message"], row["stdout"], row["stderr"])
self.__xunits.add(row["xunit"])
self.__items = sorted(cases.values())
self.n_items = len(self.__items)
def do_get_item_type(self) -> GObject.GType:
"""Get the type of the objects in the list."""
return TestCase.__gtype__
def do_get_n_items(self) -> int:
"""Get the number of items in the list."""
return self.n_items
def do_get_item(self, n: int) -> TestCase | None:
"""Get a specific item on the list."""
return self.__items[n] if n < self.n_items else None
def get_xunits(self) -> list[str]:
"""Get a list of xunits attached to this xfstests run."""
return sorted(self.__xunits)
class TestCaseFilter(Gtk.Filter): class TestCaseFilter(Gtk.Filter):
@ -183,42 +202,17 @@ class Summary(XunitRow):
return SummaryValue(name=name, value=value, unit=unit) return SummaryValue(name=name, value=value, unit=unit)
class SummaryList(GObject.GObject, Gio.ListModel): class SummaryList(XunitList):
"""A list summarizing the results of a specific Xfstests Run.""" """A list summarizing the results of a specific Xfstests Run."""
runid = GObject.Property(type=int) def do_query(self, sql: sqlite.Connection) -> sqlite3.Cursor:
n_items = GObject.Property(type=int) """Query the database for xunit summaries."""
return sql("""SELECT name AS xunit, passed, failed, skipped, time
FROM xunits_view WHERE runid=?""", self.runid)
def __init__(self, sql: sqlite.Connection, runid: int) -> None: def do_parse(self, rows: dict[Summary], row: sqlite3.Row) -> None:
"""Initialize a SummaryList.""" """Parse the data in the row and add it to the rows dict."""
super().__init__(runid=runid) for field in ["passed", "failed", "skipped", "time"]:
self.__xunits = set() summary = rows.setdefault(field, Summary(field))
summary.add_xunit(row["xunit"], row[field],
results = {} "second" if field == "time" else "testcase")
cur = sql("""SELECT name AS xunit, passed, failed, skipped, time
FROM xunits_view WHERE runid=?""", runid)
for row in cur.fetchall():
for field in ["passed", "failed", "skipped", "time"]:
summary = results.setdefault(field, Summary(field))
summary.add_xunit(row["xunit"], row[field],
"second" if field == "time" else "testcase")
self.__xunits.add(row["xunit"])
self.__items = sorted(results.values())
self.n_items = len(self.__items)
def do_get_item_type(self) -> GObject.GType:
"""Get the type of the objects in the list."""
return Summary.__gtype__
def do_get_n_items(self) -> int:
"""Get the number of items in the list."""
return self.n_items
def do_get_item(self, n: int) -> Summary | None:
"""Get a specific item on the list."""
return self.__items[n] if n < self.n_items else None
def get_xunits(self) -> list[str]:
"""Get a list of xunits attached to this xfstests run."""
return sorted(self.__xunits)