diff --git a/emmental/audio/stopwatch.py b/emmental/audio/stopwatch.py new file mode 100644 index 0000000..971779b --- /dev/null +++ b/emmental/audio/stopwatch.py @@ -0,0 +1,42 @@ +# Copyright 2024 (c) Anna Schumaker. +"""A custom StopWatch object for tracking play time.""" +import datetime +from gi.repository import GObject + + +class StopWatch(GObject.GObject): + """A StopWatch object.""" + + def __init__(self) -> None: + """Initialize the StopWatch.""" + super().__init__() + self._saved = None + self._started = None + + def elapsed_time(self) -> float: + """Get the elapsed time (in seconds).""" + total = datetime.timedelta() + if self._saved is not None: + total += self._saved + if self._started is not None: + total += datetime.datetime.now() - self._started + return total.total_seconds() + + def reset(self) -> None: + """Reset the StopWatch.""" + self._saved = None + self._started = None + + def start(self) -> None: + """Start the StopWatch.""" + self._started = datetime.datetime.now() + + def stop(self) -> None: + """Stop the StopWatch.""" + if self._started is not None: + delta = datetime.datetime.now() - self._started + if self._saved is None: + self._saved = delta + else: + self._saved += delta + self._started = None diff --git a/tests/audio/test_stopwatch.py b/tests/audio/test_stopwatch.py new file mode 100644 index 0000000..581ea11 --- /dev/null +++ b/tests/audio/test_stopwatch.py @@ -0,0 +1,87 @@ +# Copyright 2024 (c) Anna Schumaker. +"""Tests our StopWatch object.""" +import datetime +import emmental.audio.stopwatch +import unittest +from gi.repository import GObject + + +@unittest.mock.patch.object(emmental.audio.stopwatch, "datetime") +class TestStopwatch(unittest.TestCase): + """Our stopwatch test case.""" + + def setUp(self): + """Set up common variables.""" + self.now = datetime.datetime.now() + self.newdelta = datetime.timedelta + self.stopwatch = emmental.audio.stopwatch.StopWatch() + + def test_init(self, mock_datetime: unittest.mock.Mock): + """Test that the StopWatch was created properly.""" + self.assertIsInstance(self.stopwatch, GObject.GObject) + + def test_elapsed_time(self, mock_datetime: unittest.mock.Mock): + """Test the elapsed_time() function.""" + mock_datetime.timedelta = self.newdelta + self.assertEqual(self.stopwatch.elapsed_time(), 0.0) + + mock_datetime.datetime.now.return_value = self.now + self.stopwatch.start() + + soon = self.now + datetime.timedelta(seconds=12.345) + mock_datetime.datetime.now.return_value = soon + self.assertEqual(self.stopwatch.elapsed_time(), 12.345) + + self.stopwatch._saved = datetime.timedelta(seconds=2) + self.assertEqual(self.stopwatch.elapsed_time(), 14.345) + + self.stopwatch.stop() + self.assertEqual(self.stopwatch.elapsed_time(), 14.345) + + self.stopwatch.reset() + self.assertEqual(self.stopwatch.elapsed_time(), 0.0) + + def test_reset(self, mock_datetime: unittest.mock.Mock): + """Test resetting the StopWatch.""" + mock_datetime.datetime.now.return_value = self.now + self.stopwatch.start() + soon = self.now + datetime.timedelta(seconds=12.345) + mock_datetime.datetime.now.return_value = soon + self.stopwatch.stop() + + self.stopwatch.reset() + self.assertIsNone(self.stopwatch._saved) + self.assertIsNone(self.stopwatch._started) + + def test_start(self, mock_datetime: unittest.mock.Mock): + """Test starting the StopWatch.""" + self.assertIsNone(self.stopwatch._started) + + mock_datetime.datetime.now.return_value = self.now + self.stopwatch.start() + self.assertEqual(self.stopwatch._started, self.now) + + def test_stop(self, mock_datetime: unittest.mock.Mock): + """Test stopping the StopWatch.""" + self.assertIsNone(self.stopwatch._saved) + self.stopwatch.stop() + self.assertIsNone(self.stopwatch._saved) + + mock_datetime.datetime.now.return_value = self.now + self.stopwatch.start() + delta1 = datetime.timedelta(seconds=12.345) + mock_datetime.datetime.now.return_value = self.now + delta1 + self.stopwatch.stop() + self.assertEqual(self.stopwatch._saved, delta1) + self.assertIsNone(self.stopwatch._started) + + now = self.now + delta1 + datetime.timedelta(seconds=2) + mock_datetime.datetime.now.return_value = now + self.stopwatch.start() + delta2 = datetime.timedelta(seconds=3) + mock_datetime.datetime.now.return_value = now + delta2 + self.stopwatch.stop() + self.assertEqual(self.stopwatch._saved, delta1 + delta2) + + self.stopwatch.stop() + self.assertEqual(self.stopwatch._saved, delta1 + delta2)