From b6f523e6226ff23f0e4c405940d981490ba9661f Mon Sep 17 00:00:00 2001 From: Anna Schumaker Date: Thu, 27 Jan 2022 16:39:07 -0500 Subject: [PATCH] report-xfstests.py: Add filtering support for tests - Flip a switch to hide tests that were completely skipped - Flip a switch to hide tests that were completely passed - Type to do a regex search of test names Signed-off-by: Anna Schumaker --- report-xfstests.py | 123 ++++++++++++++++++++++++++++++++++++++++++--- 1 file changed, 117 insertions(+), 6 deletions(-) diff --git a/report-xfstests.py b/report-xfstests.py index d938f59..04c7fcc 100755 --- a/report-xfstests.py +++ b/report-xfstests.py @@ -4,6 +4,7 @@ gi.require_version("Gtk", "4.0") import bisect import pathlib +import re import sys import xdg.BaseDirectory import xml.etree.ElementTree @@ -135,6 +136,15 @@ class TestCase(GObject.GObject): def __lt__(self, rhs): return self.name < rhs.name + def passed(self): + return False not in [ len(elm) == 0 for elm in self.tests.values() ] + + def failed(self): + return 3 in [ len(elm) for elm in self.tests.values() ] + + def skipped(self): + return False not in [ len(elm) == 1 for elm in self.tests.values() ] + class TestResultsModel(GObject.GObject, Gio.ListModel): def __init__(self): @@ -169,6 +179,58 @@ class TestResultsModel(GObject.GObject, Gio.ListModel): self.emit("items-changed", 0, rm, len(self.tests)) +class TestResultsFilter(Gtk.Filter): + def __init__(self): + Gtk.Filter.__init__(self) + self.show_passing = True + self.show_skipped = True + self.regex = re.compile("") + + def set_regex(self, text): + change = Gtk.FilterChange.DIFFERENT + if text in self.regex.pattern: + change = Gtk.FilterChange.LESS_STRICT + elif self.regex.pattern in text: + change = Gtk.FilterChange.MORE_STRICT + + self.regex = re.compile(text, re.I) + self.changed(change) + + def set_show_passing(self, val): + self.show_passing = val + self.set_show_changed(self.show_passing) + + def set_show_skipped(self, val): + self.show_skipped = val + self.set_show_changed(self.show_skipped) + + def set_show_changed(self, newval): + match newval: + case True: self.changed(Gtk.FilterChange.LESS_STRICT) + case False: self.changed(Gtk.FilterChange.MORE_STRICT) + + def do_match(self, item): + if not self.show_passing and item.passed(): + return False + if not self.show_skipped and item.skipped(): + return False + if not self.show_passing and not self.show_skipped and not item.failed(): + return False + return self.regex.search(item.name) != None + + +class FilterPopover(Gtk.Popover): + def __init__(self, parent): + Gtk.Popover.__init__(self) + self.set_child(Gtk.Label()) + self.set_autohide(False) + self.set_parent(parent) + + def popup(self, text): + self.get_child().set_text(text) + super().popup() + + class TestResultsFactory(Gtk.SignalListItemFactory): def __init__(self, column): Gtk.SignalListItemFactory.__init__(self) @@ -202,12 +264,22 @@ class TestWindow(Gtk.ScrolledWindow): Gtk.ScrolledWindow.__init__(self, vexpand=True, hexpand=True, hscrollbar_policy=Gtk.PolicyType.NEVER) self.results = TestResultsModel() - self.selection = Gtk.NoSelection.new(self.results) + self.filter = Gtk.FilterListModel.new(self.results, TestResultsFilter()) + self.selection = Gtk.NoSelection.new(self.filter) self.view = Gtk.ColumnView.new(self.selection) self.set_child(self.view) if len(sys.argv) > 1: self.set_tests(pathlib.Path(sys.argv[1])) + def set_show_passing(self, show): + self.filter.get_filter().set_show_passing(show) + + def set_show_skipped(self, show): + self.filter.get_filter().set_show_skipped(show) + + def set_filter_regex(self, text): + self.filter.get_filter().set_regex(text) + def set_tests(self, path): for column in [ c for c in self.view.get_columns() ]: self.view.remove_column(column) @@ -222,16 +294,40 @@ class Window(Gtk.Window): Gtk.Window.__init__(self, title="Xfstests Results") self.calendar = Calendar() self.servers = ServerWindow() + self.passing = Gtk.Switch(halign=Gtk.Align.CENTER, active=True) + self.lpass = Gtk.Label.new("Show Passing Tests") + self.skipped = Gtk.Switch(halign=Gtk.Align.CENTER, active=True) + self.lskip = Gtk.Label.new("Show Skipped Tests") + self.search = Gtk.SearchEntry(placeholder_text="Type To Filter Tests") + self.popover = FilterPopover(parent=self.search) self.xfstests = TestWindow() - self.grid = Gtk.Grid() - self.grid.attach(self.calendar, 0, 0, 1, 1) - self.grid.attach(self.servers, 0, 1, 1, 1) - self.grid.attach(self.xfstests, 1, 0, 1, 2) + + self.left = Gtk.Grid(row_spacing=5) + self.left.attach(self.calendar, 0, 0, 2, 1) + self.left.attach(self.servers, 0, 1, 2, 1) + self.left.attach(self.passing, 0, 2, 1, 1) + self.left.attach(self.lpass, 1, 2, 1, 1) + self.left.attach(self.skipped, 0, 3, 1, 1) + self.left.attach(self.lskip, 1, 3, 1, 1) + + self.right = Gtk.Box.new(Gtk.Orientation.VERTICAL, 5) + self.right.append(self.search) + self.right.append(self.xfstests) + + self.child = Gtk.Box.new(Gtk.Orientation.HORIZONTAL, 5) + self.child.append(self.left) + self.child.append(self.right) + + self.lskip.set_xalign(0) + self.lpass.set_xalign(0) self.set_default_size(1000, 600) - self.set_child(self.grid) + self.set_child(self.child) self.calendar.connect("day-selected", self.date_changed) self.servers.connect("test-changed", self.test_changed) + self.passing.connect("notify::active", self.show_passing) + self.skipped.connect("notify::active", self.show_skipped) + self.search.connect("search-changed", self.search_changed) self.date_changed(self.calendar) def date_changed(self, calendar): @@ -240,6 +336,21 @@ class Window(Gtk.Window): def test_changed(self, window, file): self.xfstests.set_tests(pathlib.Path(file.get_path())) + def show_passing(self, passing, param): + self.xfstests.set_show_passing(passing.get_active()) + + def show_skipped(self, skipped, param): + self.xfstests.set_show_skipped(skipped.get_active()) + + def search_changed(self, search): + try: + self.xfstests.set_filter_regex(search.get_text()) + self.search.remove_css_class("warning") + self.popover.popdown() + except re.error as e: + self.search.add_css_class("warning") + self.popover.popup(str(e)) + class Application(Gtk.Application): def __init__(self, *args, **kwargs):