gtk: Add a CalendarView class for selecting xfstests runs by date
This combines a Calendar and RunidView to select runs on a given day. Signed-off-by: Anna Schumaker <anna@nowheycreamery.com>
This commit is contained in:
parent
bac99c9c54
commit
704eb08091
|
@ -3,6 +3,7 @@
|
|||
import datetime
|
||||
import unittest
|
||||
import xfstestsdb.gtk.sidebar
|
||||
from gi.repository import GLib
|
||||
from gi.repository import Gtk
|
||||
|
||||
|
||||
|
@ -84,3 +85,84 @@ class TestRunidView(unittest.TestCase):
|
|||
self.view._view.emit("activate", 0)
|
||||
self.assertTrue(self.view._selection[0].get_expanded())
|
||||
self.assertEqual(self.view.runid, 2)
|
||||
|
||||
|
||||
class TestCalendarView(unittest.TestCase):
|
||||
"""Test the CalendarView class."""
|
||||
|
||||
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(["new", "/dev/vda2"])
|
||||
self.xfstestsdb.run(["new", "/dev/vda3"])
|
||||
self.xfstestsdb.run(["new", "/dev/vda4"])
|
||||
|
||||
query = "UPDATE xfstests_runs SET timestamp=? WHERE runid=?"
|
||||
dtime = datetime.datetime.now().replace(year=2023, month=1)
|
||||
self.xfstestsdb.sql(query, dtime.replace(day=1), 1)
|
||||
self.xfstestsdb.sql(query, dtime.replace(day=8), 2)
|
||||
self.xfstestsdb.sql(query, dtime.replace(day=15), 3)
|
||||
|
||||
self.sidebar = xfstestsdb.gtk.sidebar.CalendarView(self.xfstestsdb.sql)
|
||||
|
||||
def test_init(self):
|
||||
"""Test that the calendar view was set up properly."""
|
||||
self.assertIsInstance(self.sidebar, Gtk.Box)
|
||||
self.assertEqual(self.sidebar.props.spacing, 6)
|
||||
self.assertEqual(self.sidebar.props.orientation,
|
||||
Gtk.Orientation.VERTICAL)
|
||||
self.assertEqual(self.sidebar.sql, self.xfstestsdb.sql)
|
||||
|
||||
def test_calendar(self):
|
||||
"""Test the calendar widget."""
|
||||
self.assertIsInstance(self.sidebar._calendar, Gtk.Calendar)
|
||||
self.assertEqual(self.sidebar.get_first_child(),
|
||||
self.sidebar._calendar)
|
||||
|
||||
today = datetime.date.today()
|
||||
self.assertTrue(self.sidebar._calendar.get_day_is_marked(today.day))
|
||||
|
||||
def test_view(self):
|
||||
"""Test the runid view widget."""
|
||||
self.assertIsInstance(self.sidebar._view,
|
||||
xfstestsdb.gtk.sidebar.RunidView)
|
||||
self.assertIsInstance(self.sidebar._view.model,
|
||||
xfstestsdb.gtk.tree.DateDeviceList)
|
||||
self.assertEqual(self.sidebar._calendar.get_next_sibling(),
|
||||
self.sidebar._view)
|
||||
|
||||
self.assertEqual(self.sidebar._view.model.date, datetime.date.today())
|
||||
|
||||
def test_marked_days(self):
|
||||
"""Test marking days in the calendar."""
|
||||
gl_date = GLib.DateTime.new_local(2023, 1, 10, 0, 0, 0)
|
||||
self.sidebar._calendar.select_day(gl_date)
|
||||
|
||||
for signal in ["next-month", "next-year", "prev-month", "prev-year"]:
|
||||
with self.subTest(signal=signal):
|
||||
with unittest.mock.patch.object(self.sidebar._calendar,
|
||||
"clear_marks") as mock_clear:
|
||||
with unittest.mock.patch.object(self.sidebar._calendar,
|
||||
"mark_day") as mock_mark:
|
||||
self.sidebar._calendar.emit(signal)
|
||||
mock_clear.assert_called()
|
||||
mock_mark.assert_has_calls([unittest.mock.call(1),
|
||||
unittest.mock.call(8),
|
||||
unittest.mock.call(15)])
|
||||
|
||||
def test_select_day(self):
|
||||
"""Test selecting a day in the calendar."""
|
||||
gl_now = GLib.DateTime.new_now_local()
|
||||
self.sidebar._calendar.select_day(gl_now.add_days(-1))
|
||||
|
||||
today = datetime.date.today()
|
||||
self.assertEqual(self.sidebar._view.model.date,
|
||||
today - datetime.timedelta(days=1))
|
||||
|
||||
def test_runid_property(self):
|
||||
"""Test the runid property."""
|
||||
self.assertEqual(self.sidebar.runid, 0)
|
||||
self.sidebar._view.runid = 42
|
||||
self.assertEqual(self.sidebar.runid, 42)
|
||||
|
|
|
@ -1,9 +1,11 @@
|
|||
# Copyright 2023 (c) Anna Schumaker.
|
||||
"""Our sidebar for selecting a specific xfstests run to view."""
|
||||
import datetime
|
||||
import typing
|
||||
from gi.repository import GObject
|
||||
from gi.repository import Gio
|
||||
from gi.repository import Gtk
|
||||
from .. import sqlite
|
||||
from . import row
|
||||
from . import tree
|
||||
|
||||
|
@ -44,3 +46,52 @@ class RunidView(Gtk.ScrolledWindow):
|
|||
param: GObject.ParamSpec) -> None:
|
||||
model = None if self.model is None else self.model.treemodel
|
||||
self._selection.props.model = model
|
||||
|
||||
|
||||
class CalendarView(Gtk.Box):
|
||||
"""Our calendar view for seleting an xfstests run by date."""
|
||||
|
||||
runid = GObject.Property(type=int)
|
||||
sql = GObject.Property(type=GObject.TYPE_PYOBJECT)
|
||||
|
||||
def __init__(self, sql: sqlite.Connection) -> None:
|
||||
"""Initialize a CalendarView instance."""
|
||||
super().__init__(sql=sql, spacing=6,
|
||||
orientation=Gtk.Orientation.VERTICAL)
|
||||
today = datetime.date.today()
|
||||
self._calendar = Gtk.Calendar()
|
||||
self._view = RunidView(model=tree.DateDeviceList(sql, today))
|
||||
|
||||
self._view.bind_property("runid", self, "runid")
|
||||
self._calendar.connect("day-selected", self.__day_selected)
|
||||
self._calendar.connect("next-month", self.__date_changed)
|
||||
self._calendar.connect("next-year", self.__date_changed)
|
||||
self._calendar.connect("prev-month", self.__date_changed)
|
||||
self._calendar.connect("prev-year", self.__date_changed)
|
||||
|
||||
self.__mark_days(today)
|
||||
|
||||
self.append(self._calendar)
|
||||
self.append(self._view)
|
||||
|
||||
def __day_selected(self, calendar: Gtk.Calendar) -> None:
|
||||
self.__select_day(datetime.date(*calendar.get_date().get_ymd()))
|
||||
|
||||
def __date_changed(self, calendar: Gtk.Calendar) -> None:
|
||||
date = datetime.date(*calendar.get_date().get_ymd())
|
||||
self.__mark_days(date)
|
||||
self.__select_day(date)
|
||||
|
||||
def __select_day(self, date: datetime.date) -> None:
|
||||
self._view.model = tree.DateDeviceList(self.sql, date)
|
||||
|
||||
def __mark_days(self, date: datetime.date) -> None:
|
||||
min = datetime.datetime.combine(date.replace(day=1), datetime.time())
|
||||
max = (min + datetime.timedelta(days=40)).replace(day=1)
|
||||
|
||||
self._calendar.clear_marks()
|
||||
for stamp in self.sql("""SELECT DISTINCT timestamp FROM tagged_runs
|
||||
WHERE timestamp >= ? AND timestamp < ?""",
|
||||
min, max).fetchall():
|
||||
ts = datetime.datetime.fromisoformat(stamp['timestamp'])
|
||||
self._calendar.mark_day(ts.day)
|
||||
|
|
Loading…
Reference in New Issue