gtk: Create a MessagesView

The MessagesView combines two MessageViews into a split-pane card. This
lets us display stdout and stderr side-by-side to the user so they can
see what is going on. I also add a 'back' button that the user can click
to signal that they are done reviewing the output.

Signed-off-by: Anna Schumaker <anna@nowheycreamery.com>
This commit is contained in:
Anna Schumaker 2023-08-30 16:57:38 -04:00
parent 5fb9bd6221
commit ea2913429c
2 changed files with 125 additions and 0 deletions

View File

@ -4,6 +4,7 @@ import unittest
import tests.xunit
import xfstestsdb.gtk.view
from gi.repository import Gtk
from gi.repository import Adw
class TestXunitView(unittest.TestCase):
@ -352,6 +353,85 @@ class TestMessageView(unittest.TestCase):
self.assertEqual(self.view.text, "\n".join(diff))
class MessagesView(unittest.TestCase):
"""Test the MessagesView."""
def setUp(self):
"""Set up common variables."""
self.view = xfstestsdb.gtk.view.MessagesView()
def test_init(self):
"""Check that the MessagesView was set up correctly."""
self.assertIsInstance(self.view, Gtk.Box)
self.assertIsInstance(self.view.get_first_child(), Gtk.CenterBox)
self.assertIsInstance(self.view.get_last_child(), Gtk.Paned)
self.assertTrue(self.view.get_first_child().has_css_class("toolbar"))
self.assertTrue(self.view.has_css_class("card"))
self.assertEqual(self.view.props.orientation, Gtk.Orientation.VERTICAL)
self.assertEqual(self.view.props.margin_start, 24)
self.assertEqual(self.view.props.margin_end, 24)
self.assertEqual(self.view.props.margin_top, 24)
self.assertEqual(self.view.props.margin_bottom, 24)
def test_back_button(self):
"""Check that the back button was set up correctly."""
self.assertIsInstance(self.view._back, Gtk.Button)
self.assertIsInstance(self.view._back.props.child, Adw.ButtonContent)
self.assertEqual(self.view.get_first_child().props.start_widget,
self.view._back)
self.assertEqual(self.view._back.props.child.props.icon_name,
"go-previous-symbolic")
self.assertEqual(self.view._back.props.child.props.label, "back")
self.assertTrue(self.view._back.has_css_class("suggested-action"))
self.assertTrue(self.view._back.has_css_class("pill"))
go_back = unittest.mock.Mock()
self.view.connect("go-back", go_back)
self.view._back.emit("clicked")
go_back.assert_called()
def test_title(self):
"""Check that the view title was set up correctly."""
self.assertIsInstance(self.view._title, Adw.WindowTitle)
self.assertEqual(self.view.get_first_child().props.center_widget,
self.view._title)
self.assertEqual(self.view.testcase, "")
self.view.testcase = "test/case"
self.assertEqual(self.view._title.props.title, "test/case")
self.assertEqual(self.view.xunit, "")
self.view.xunit = "xunit-1"
self.assertEqual(self.view._title.props.subtitle, "xunit-1")
def test_stdout(self):
"""Check that the stdout window was set up properly."""
self.assertIsInstance(self.view._stdout,
xfstestsdb.gtk.view.MessageView)
self.assertEqual(self.view.get_last_child().props.start_child,
self.view._stdout)
self.assertEqual(self.view._stdout.title, "stdout")
self.assertEqual(self.view.stdout, "")
self.view.stdout = "stdout text"
self.assertEqual(self.view._stdout.text, "stdout text")
def test_stderr(self):
"""Check that the stderr window was set up properly."""
self.assertIsInstance(self.view._stderr,
xfstestsdb.gtk.view.MessageView)
self.assertEqual(self.view.get_last_child().props.end_child,
self.view._stderr)
self.assertEqual(self.view._stderr.title, "stderr")
self.assertEqual(self.view.stderr, "")
self.view.stderr = "stderr text"
self.assertEqual(self.view._stderr.text, "stderr text")
class TestSummaryView(unittest.TestCase):
"""Tests the SummaryView."""

View File

@ -4,6 +4,7 @@ import re
from gi.repository import GObject
from gi.repository import Gio
from gi.repository import Gtk
from gi.repository import Adw
from .model import PropertyList
from .model import PropertyFilter
from .model import TestCaseList
@ -231,6 +232,50 @@ class MessageView(Gtk.Box):
buffer.set_text(new_text)
class MessagesView(Gtk.Box):
"""A view for displaying stdout and stderr messages."""
testcase = GObject.Property(type=str)
xunit = GObject.Property(type=str)
stdout = GObject.Property(type=str)
stderr = GObject.Property(type=str)
def __init__(self):
"""Initialize a MessagesView."""
icon = "go-previous-symbolic"
super().__init__(orientation=Gtk.Orientation.VERTICAL, margin_top=24,
margin_start=24, margin_end=24, margin_bottom=24)
self._back = Gtk.Button(child=Adw.ButtonContent(icon_name=icon,
label="back"))
self._title = Adw.WindowTitle()
self._stdout = MessageView("stdout")
self._stderr = MessageView("stderr")
self.bind_property("testcase", self._title, "title")
self.bind_property("xunit", self._title, "subtitle")
self.bind_property("stdout", self._stdout, "text")
self.bind_property("stderr", self._stderr, "text")
self._back.connect("clicked", self.__back_clicked)
self.append(Gtk.CenterBox(start_widget=self._back,
center_widget=self._title))
self.append(Gtk.Paned(start_child=self._stdout,
end_child=self._stderr, vexpand=True))
self.get_first_child().add_css_class("toolbar")
self._back.add_css_class("suggested-action")
self._back.add_css_class("pill")
self.add_css_class("card")
def __back_clicked(self, button: Gtk.Button) -> None:
self.emit("go-back")
@GObject.Signal
def go_back(self) -> None:
"""Signal that the user wants to go back."""
class SummaryView(XunitView):
"""Displays our SummaryList model to the user."""