From a18e724e0b871ac685634543de0f8dbdef55ff8b Mon Sep 17 00:00:00 2001 From: Chason Chaffin Date: Fri, 19 Apr 2019 00:30:53 +0900 Subject: [PATCH 1/5] Adding tests for gametime module --- evennia/utils/tests/test_gametime.py | 78 ++++++++++++++++++++++++++++ 1 file changed, 78 insertions(+) create mode 100644 evennia/utils/tests/test_gametime.py diff --git a/evennia/utils/tests/test_gametime.py b/evennia/utils/tests/test_gametime.py new file mode 100644 index 0000000000..a2c005f174 --- /dev/null +++ b/evennia/utils/tests/test_gametime.py @@ -0,0 +1,78 @@ +""" +Unit tests for the utilities of the evennia.utils.gametime module. +""" + +import time +from unittest.mock import Mock + +from django.test import TestCase + +from evennia.utils import gametime + +time.time = Mock(return_value=1555595378.0) + + +class TestGametime(TestCase): + def setUp(self): + gametime.SERVER_RUNTIME = 600.0 + gametime.SERVER_START_TIME = time.time() - 300 + gametime.SERVER_RUNTIME_LAST_UPDATED = time.time() - 30 + gametime.TIMEFACTOR = 5.0 + + 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=3), 5771520) + + def test_schedule(self): + callback = Mock() + script = gametime.schedule(callback, day=19) + 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.assertIsInstance(script, gametime.TimeScript) + self.assertAlmostEqual(script.interval, 12) + self.assertEqual(script.repeats, -1) From 73f82d0ad1d3b502b21e1629ad1745b054d12098 Mon Sep 17 00:00:00 2001 From: Chason Chaffin Date: Fri, 19 Apr 2019 10:40:19 +0900 Subject: [PATCH 2/5] Fixing tests for new gametime tests It appears that some mocks setup for gametime in the contrib library were causing issues with the gametime tests. I've switched those mocks to be patches instead so they are cleared out when the test finishes. --- evennia/contrib/tests.py | 9 +++------ evennia/utils/tests/test_gametime.py | 11 ++++++++++- 2 files changed, 13 insertions(+), 7 deletions(-) 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/tests/test_gametime.py b/evennia/utils/tests/test_gametime.py index a2c005f174..032513c7ea 100644 --- a/evennia/utils/tests/test_gametime.py +++ b/evennia/utils/tests/test_gametime.py @@ -5,6 +5,7 @@ Unit tests for the utilities of the evennia.utils.gametime module. import time from unittest.mock import Mock +from django.conf import settings from django.test import TestCase from evennia.utils import gametime @@ -13,12 +14,18 @@ time.time = Mock(return_value=1555595378.0) class TestGametime(TestCase): - def setUp(self): + def setUp(self) -> 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 + def tearDown(self) -> None: + gametime.SERVER_RUNTIME_LAST_UPDATED = 0.0 + gametime.SERVER_RUNTIME = 0.0 + gametime.SERVER_START_TIME = 0.0 + gametime.TIMEFACTOR = settings.TIME_FACTOR + def test_runtime(self): self.assertAlmostEqual(gametime.runtime(), 630.0) @@ -69,6 +76,7 @@ class TestGametime(TestCase): self.assertIsInstance(script, gametime.TimeScript) self.assertAlmostEqual(script.interval, 17280) self.assertEqual(script.repeats, 1) + script.stop() def test_repeat_schedule(self): callback = Mock() @@ -76,3 +84,4 @@ class TestGametime(TestCase): self.assertIsInstance(script, gametime.TimeScript) self.assertAlmostEqual(script.interval, 12) self.assertEqual(script.repeats, -1) + script.stop() From 552146db5c37cdae534e0fb0ab7884b6b782e3e8 Mon Sep 17 00:00:00 2001 From: Chason Chaffin Date: Fri, 19 Apr 2019 11:32:49 +0900 Subject: [PATCH 3/5] More fixes on gametime tests Looks like I *was* causing the previous issues by mocking time.time --- evennia/utils/tests/test_gametime.py | 15 +++++++++++---- 1 file changed, 11 insertions(+), 4 deletions(-) diff --git a/evennia/utils/tests/test_gametime.py b/evennia/utils/tests/test_gametime.py index 032513c7ea..fff07b9399 100644 --- a/evennia/utils/tests/test_gametime.py +++ b/evennia/utils/tests/test_gametime.py @@ -10,21 +10,28 @@ from django.test import TestCase from evennia.utils import gametime -time.time = Mock(return_value=1555595378.0) - 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) @@ -73,15 +80,15 @@ class TestGametime(TestCase): 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) - script.stop() 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) - script.stop() From 7ebd6a9f0efe1badc2f15d5f5b83d6e91db817cb Mon Sep 17 00:00:00 2001 From: Chason Chaffin Date: Fri, 19 Apr 2019 12:49:27 +0900 Subject: [PATCH 4/5] testing for bug found in gametime module I've found a bug in the gametime module where if your date is the year before a leap year, and the real_seconds_until function has to adjust the date (from using an earlier month) over that leap year, the calculation is off a day since the current function uses the length of the current year to determine how far to skip ahead I've changed the current test to *not* test for this bug in the mainline test (before it was passing because I was using the output from the current function to determine correctness) and to add a separate test that is marked as an expected failure for now. I am working on a fix but it is outside the scope of this PR. --- evennia/utils/tests/test_gametime.py | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/evennia/utils/tests/test_gametime.py b/evennia/utils/tests/test_gametime.py index fff07b9399..cc2a759c18 100644 --- a/evennia/utils/tests/test_gametime.py +++ b/evennia/utils/tests/test_gametime.py @@ -3,6 +3,7 @@ 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 @@ -75,7 +76,11 @@ class TestGametime(TestCase): 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=3), 5771520) + self.assertAlmostEqual(gametime.real_seconds_until(month=1), 4752000) + + @unittest.expectedFailure + def test_real_seconds_until_leap_year(self): + self.assertAlmostEqual(gametime.real_seconds_until(month=3), 5788800) def test_schedule(self): callback = Mock() From 8fc7815189ed324779a8844d690499ccc6558114 Mon Sep 17 00:00:00 2001 From: Chason Chaffin Date: Fri, 19 Apr 2019 16:19:15 +0900 Subject: [PATCH 5/5] Fixing bug in gametime module Previously, gametime used the length of the current year and current month to calculate the future date in the real_seconds_until function. This caused a small bug when passing over a leap day from a year without a leap day. This change uses the datetime module to just increment the year or month, sidestepping the issue. --- evennia/utils/gametime.py | 9 +++++---- evennia/utils/tests/test_gametime.py | 1 - 2 files changed, 5 insertions(+), 5 deletions(-) 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 index cc2a759c18..7b11f4b043 100644 --- a/evennia/utils/tests/test_gametime.py +++ b/evennia/utils/tests/test_gametime.py @@ -78,7 +78,6 @@ class TestGametime(TestCase): self.assertAlmostEqual(gametime.real_seconds_until(day=17), 501120) self.assertAlmostEqual(gametime.real_seconds_until(month=1), 4752000) - @unittest.expectedFailure def test_real_seconds_until_leap_year(self): self.assertAlmostEqual(gametime.real_seconds_until(month=3), 5788800)