Tests: test that the game is beatable for WorldTestBases (#1495)

* Tests: test that the game is beatable for WorldTestBases

* update docstring

* don't test the bases with default options for real this time

* invert the property so worlds can use it easier

* setup check should be or

* test class needs to always be constructed

* skip default tests before multiworld setup

* check if the calling method is in the base's __dict__

* shorter property and functional setup skipping

* shorter property and functional setup skipping
This commit is contained in:
alwaysintreble 2023-03-02 17:30:40 -06:00 committed by GitHub
parent 805f33c39e
commit 21fb16291d
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
1 changed files with 20 additions and 9 deletions

View File

@ -112,7 +112,11 @@ class WorldTestBase(unittest.TestCase):
self.world_setup()
def world_setup(self, seed: typing.Optional[int] = None) -> None:
if type(self) is WorldTestBase:
if type(self) is WorldTestBase or \
(hasattr(WorldTestBase, self._testMethodName)
and not self.run_default_tests and
getattr(self, self._testMethodName).__code__ is
getattr(WorldTestBase, self._testMethodName, None).__code__):
return # setUp gets called for tests defined in the base class. We skip world_setup here.
if not hasattr(self, "game"):
raise NotImplementedError("didn't define game name")
@ -208,16 +212,20 @@ class WorldTestBase(unittest.TestCase):
# following tests are automatically run
@property
def skip_default_tests(self) -> bool:
def run_default_tests(self) -> bool:
"""Not possible or identical to the base test that's always being run already"""
constructed = hasattr(self, "game") and hasattr(self, "multiworld")
return not constructed or (not self.options
and self.setUp is WorldTestBase.setUp
and self.world_setup is WorldTestBase.world_setup)
return (self.options
or self.setUp.__code__ is not WorldTestBase.setUp.__code__
or self.world_setup.__code__ is not WorldTestBase.world_setup.__code__)
@property
def constructed(self) -> bool:
"""A multiworld has been constructed by this point"""
return hasattr(self, "game") and hasattr(self, "multiworld")
def testAllStateCanReachEverything(self):
"""Ensure all state can reach everything with the defined options"""
if self.skip_default_tests:
"""Ensure all state can reach everything and complete the game with the defined options"""
if not (self.run_default_tests and self.constructed):
return
with self.subTest("Game", game=self.game):
excluded = self.multiworld.exclude_locations[1].value
@ -226,10 +234,13 @@ class WorldTestBase(unittest.TestCase):
if location.name not in excluded:
with self.subTest("Location should be reached", location=location):
self.assertTrue(location.can_reach(state), f"{location.name} unreachable")
with self.subTest("Beatable"):
self.multiworld.state = state
self.assertBeatable(True)
def testEmptyStateCanReachSomething(self):
"""Ensure empty state can reach at least one location with the defined options"""
if self.skip_default_tests:
if not (self.run_default_tests and self.constructed):
return
with self.subTest("Game", game=self.game):
state = CollectionState(self.multiworld)