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:
parent
c45ec1909e
commit
5dc7735ba7
|
@ -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"])
|
|
||||||
|
|
|
@ -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)
|
|
||||||
|
|
Loading…
Reference in New Issue