diff --git a/test/TestBase.py b/test/TestBase.py index fb8031a9..a2c9bc28 100644 --- a/test/TestBase.py +++ b/test/TestBase.py @@ -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)