diff --git a/evennia/contrib/tests.py b/evennia/contrib/tests.py index c94f850390..c576de29fd 100644 --- a/evennia/contrib/tests.py +++ b/evennia/contrib/tests.py @@ -222,6 +222,8 @@ class ForceUTCDatetime(datetime.datetime): @patch('evennia.contrib.extended_room.datetime.datetime', ForceUTCDatetime) +# mock gametime to return April 9, 2064, at 21:06 (spring evening) +@patch('evennia.utils.gametime.gametime', new=Mock(return_value=2975000766)) class TestExtendedRoom(CommandTest): room_typeclass = extended_room.ExtendedRoom DETAIL_DESC = "A test detail." @@ -236,8 +238,6 @@ class TestExtendedRoom(CommandTest): self.room1.db.details = {'testdetail': self.DETAIL_DESC} self.room1.db.spring_desc = self.SPRING_DESC self.room1.db.desc = self.OLD_DESC - # mock gametime to return April 9, 2064, at 21:06 (spring evening) - gametime.gametime = Mock(return_value=2975000766) def test_return_appearance(self): # get the appearance of a non-extended room for contrast purposes @@ -607,11 +607,8 @@ def _testcallback(): pass +@patch('evennia.utils.gametime.gametime', new=Mock(return_value=2975000898.46)) class TestCustomGameTime(EvenniaTest): - def setUp(self): - super().setUp() - gametime.gametime = Mock(return_value=2975000898.46) # does not seem to work - def tearDown(self): if hasattr(self, "timescript"): self.timescript.stop() diff --git a/evennia/utils/gametime.py b/evennia/utils/gametime.py index c3cc0ac416..f964c4b053 100644 --- a/evennia/utils/gametime.py +++ b/evennia/utils/gametime.py @@ -189,12 +189,13 @@ def real_seconds_until(sec=None, min=None, hour=None, if projected <= current: # We increase one unit of time depending on parameters - days_in_month = monthrange(s_year, s_month)[1] - days_in_year = sum(monthrange(s_year, m + 1)[1] for m in range(12)) if month is not None: - projected += timedelta(days=days_in_year) + projected = projected.replace(year=s_year+1) elif day is not None: - projected += timedelta(days=days_in_month) + try: + projected = projected.replace(month=s_month+1) + except ValueError: + projected = projected.replace(month=1) elif hour is not None: projected += timedelta(days=1) elif min is not None: diff --git a/evennia/utils/tests/test_gametime.py b/evennia/utils/tests/test_gametime.py new file mode 100644 index 0000000000..7b11f4b043 --- /dev/null +++ b/evennia/utils/tests/test_gametime.py @@ -0,0 +1,98 @@ +""" +Unit tests for the utilities of the evennia.utils.gametime module. +""" + +import time +import unittest +from unittest.mock import Mock + +from django.conf import settings +from django.test import TestCase + +from evennia.utils import gametime + + +class TestGametime(TestCase): + def setUp(self) -> None: + self.time = time.time + self._SERVER_EPOCH = gametime._SERVER_EPOCH + time.time = Mock(return_value=1555595378.0) + gametime._SERVER_EPOCH = None + gametime.SERVER_RUNTIME = 600.0 + gametime.SERVER_START_TIME = time.time() - 300 + gametime.SERVER_RUNTIME_LAST_UPDATED = time.time() - 30 + gametime.TIMEFACTOR = 5.0 + self.timescripts = [] + + def tearDown(self) -> None: + time.time = self.time + gametime._SERVER_EPOCH = self._SERVER_EPOCH + gametime.SERVER_RUNTIME_LAST_UPDATED = 0.0 + gametime.SERVER_RUNTIME = 0.0 + gametime.SERVER_START_TIME = 0.0 + gametime.TIMEFACTOR = settings.TIME_FACTOR + for script in self.timescripts: + script.stop() + + def test_runtime(self): + self.assertAlmostEqual(gametime.runtime(), 630.0) + + def test_server_epoch(self): + self.assertAlmostEqual(gametime.server_epoch(), time.time() - 630.0) + + def test_uptime(self): + self.assertAlmostEqual(gametime.uptime(), 300.0) + + def test_game_epoch_no_setting(self): + self.assertAlmostEqual(gametime.game_epoch(), gametime.server_epoch()) + + def test_game_epoch_setting(self): + with self.settings(TIME_GAME_EPOCH=0): + self.assertEqual(gametime.game_epoch(), 0) + + def test_gametime_simple(self): + self.assertAlmostEqual(gametime.gametime(), 630.0 * 5) + + def test_gametime_absolute(self): + self.assertAlmostEqual(gametime.gametime(absolute=True), 1555597898.0) + + def test_gametime_downtimes(self): + gametime.IGNORE_DOWNTIMES = True + self.assertAlmostEqual(gametime.gametime(), 630 * 5.0) + gametime.IGNORE_DOWNTIMES = False + + def test_real_seconds_until(self): + # using the gametime value above, we are working from the following + # datetime: datetime.datetime(2019, 4, 18, 14, 31, 38, 245449) + self.assertAlmostEqual(gametime.real_seconds_until(sec=48), 2) + self.assertAlmostEqual(gametime.real_seconds_until(min=32), 12) + self.assertAlmostEqual(gametime.real_seconds_until(hour=15), 720) + self.assertAlmostEqual(gametime.real_seconds_until(day=19), 17280) + self.assertAlmostEqual(gametime.real_seconds_until(month=5), 518400) + self.assertAlmostEqual(gametime.real_seconds_until(year=2020), 6324480) + + def test_real_seconds_until_behind(self): + self.assertAlmostEqual(gametime.real_seconds_until(sec=28), 10) + self.assertAlmostEqual(gametime.real_seconds_until(min=30), 708) + self.assertAlmostEqual(gametime.real_seconds_until(hour=13), 16560) + self.assertAlmostEqual(gametime.real_seconds_until(day=17), 501120) + self.assertAlmostEqual(gametime.real_seconds_until(month=1), 4752000) + + def test_real_seconds_until_leap_year(self): + self.assertAlmostEqual(gametime.real_seconds_until(month=3), 5788800) + + def test_schedule(self): + callback = Mock() + script = gametime.schedule(callback, day=19) + self.timescripts.append(script) + self.assertIsInstance(script, gametime.TimeScript) + self.assertAlmostEqual(script.interval, 17280) + self.assertEqual(script.repeats, 1) + + def test_repeat_schedule(self): + callback = Mock() + script = gametime.schedule(callback, repeat=True, min=32) + self.timescripts.append(script) + self.assertIsInstance(script, gametime.TimeScript) + self.assertAlmostEqual(script.interval, 12) + self.assertEqual(script.repeats, -1)