From 8af7908cd00127af8ac6918fc8135c2c84c41027 Mon Sep 17 00:00:00 2001 From: alwaysintreble Date: Wed, 15 Feb 2023 15:46:10 -0600 Subject: [PATCH] Tests: datapackage and more multiworld renaming (#1454) * Tests: add a test that created items and locations exist in the datapackage * move FF validation to `assert_generate` and remove test exclusion * test created location addresses are correct * make the assertion proper and more verbose * make item count test ~~a bit faster~~ a lot nicer * 120 blaze it * name test multiworld setup better and fix another over 120 line in FFR --- test/general/TestImplemented.py | 10 +++++----- test/general/TestItems.py | 22 +++++++++++++--------- test/general/TestLocations.py | 17 +++++++++++++---- test/general/TestReachability.py | 10 +++++----- test/general/__init__.py | 2 +- worlds/ff1/__init__.py | 18 ++++++++++-------- 6 files changed, 47 insertions(+), 32 deletions(-) diff --git a/test/general/TestImplemented.py b/test/general/TestImplemented.py index 490e3b85..b504470b 100644 --- a/test/general/TestImplemented.py +++ b/test/general/TestImplemented.py @@ -1,24 +1,24 @@ import unittest from worlds.AutoWorld import AutoWorldRegister -from . import setup_default_world +from . import setup_solo_multiworld class TestImplemented(unittest.TestCase): def testCompletionCondition(self): """Ensure a completion condition is set that has requirements.""" for game_name, world_type in AutoWorldRegister.world_types.items(): - if not world_type.hidden and game_name not in {"ArchipIDLE", "Final Fantasy", "Sudoku"}: + if not world_type.hidden and game_name not in {"ArchipIDLE", "Sudoku"}: with self.subTest(game_name): - multiworld = setup_default_world(world_type) + multiworld = setup_solo_multiworld(world_type) self.assertFalse(multiworld.completion_condition[1](multiworld.state)) def testEntranceParents(self): """Tests that the parents of created Entrances match the exiting Region.""" for game_name, world_type in AutoWorldRegister.world_types.items(): - if not world_type.hidden and game_name not in {"Final Fantasy"}: + if not world_type.hidden: with self.subTest(game_name): - multiworld = setup_default_world(world_type) + multiworld = setup_solo_multiworld(world_type) for region in multiworld.regions: for exit in region.exits: self.assertEqual(exit.parent_region, region) diff --git a/test/general/TestItems.py b/test/general/TestItems.py index c962d572..95eb8d28 100644 --- a/test/general/TestItems.py +++ b/test/general/TestItems.py @@ -1,6 +1,6 @@ import unittest from worlds.AutoWorld import AutoWorldRegister -from . import setup_default_world +from . import setup_solo_multiworld class TestBase(unittest.TestCase): @@ -43,14 +43,18 @@ class TestBase(unittest.TestCase): def testItemCountGreaterEqualLocations(self): for game_name, world_type in AutoWorldRegister.world_types.items(): - - if game_name in {"Final Fantasy"}: - continue with self.subTest("Game", game=game_name): - world = setup_default_world(world_type) - location_count = sum(0 if location.event or location.item else 1 for location in world.get_locations()) + multiworld = setup_solo_multiworld(world_type) self.assertGreaterEqual( - len(world.itempool), - location_count, - f"{game_name} Item count MUST meet or exceede the number of locations", + len(multiworld.itempool), + len(multiworld.get_unfilled_locations()), + f"{game_name} Item count MUST meet or exceed the number of locations", ) + + def testItemsInDatapackage(self): + """Test that any created items in the itempool are in the datapackage""" + for game_name, world_type in AutoWorldRegister.world_types.items(): + with self.subTest("Game", game=game_name): + multiworld = setup_solo_multiworld(world_type) + for item in multiworld.itempool: + self.assertIn(item.name, world_type.item_name_to_id) diff --git a/test/general/TestLocations.py b/test/general/TestLocations.py index f08939bc..5dbb1d55 100644 --- a/test/general/TestLocations.py +++ b/test/general/TestLocations.py @@ -1,16 +1,25 @@ import unittest from collections import Counter from worlds.AutoWorld import AutoWorldRegister -from . import setup_default_world +from . import setup_solo_multiworld class TestBase(unittest.TestCase): def testCreateDuplicateLocations(self): + """Tests that no two Locations share a name.""" for game_name, world_type in AutoWorldRegister.world_types.items(): - if game_name in {"Final Fantasy"}: - continue - multiworld = setup_default_world(world_type) + multiworld = setup_solo_multiworld(world_type) locations = Counter(multiworld.get_locations()) if locations: self.assertLessEqual(locations.most_common(1)[0][1], 1, f"{world_type.game} has duplicate of location {locations.most_common(1)}") + + def testLocationsInDatapackage(self): + """Tests that created locations not filled before fill starts exist in the datapackage.""" + for game_name, world_type in AutoWorldRegister.world_types.items(): + with self.subTest("Game", game_name=game_name): + multiworld = setup_solo_multiworld(world_type) + locations = multiworld.get_unfilled_locations() # do unfilled locations to avoid Events + for location in locations: + self.assertIn(location.name, world_type.location_name_to_id) + self.assertEqual(location.address, world_type.location_name_to_id[location.name]) diff --git a/test/general/TestReachability.py b/test/general/TestReachability.py index b70ed236..10525a37 100644 --- a/test/general/TestReachability.py +++ b/test/general/TestReachability.py @@ -3,7 +3,7 @@ import unittest from BaseClasses import CollectionState from worlds.AutoWorld import AutoWorldRegister -from . import setup_default_world +from . import setup_solo_multiworld class TestBase(unittest.TestCase): @@ -12,9 +12,9 @@ class TestBase(unittest.TestCase): def testAllStateCanReachEverything(self): for game_name, world_type in AutoWorldRegister.world_types.items(): # Final Fantasy logic is controlled by finalfantasyrandomizer.com - if game_name not in {"Ori and the Blind Forest", "Final Fantasy"}: # TODO: fix Ori Logic + if game_name not in {"Ori and the Blind Forest"}: # TODO: fix Ori Logic with self.subTest("Game", game=game_name): - world = setup_default_world(world_type) + world = setup_solo_multiworld(world_type) excluded = world.exclude_locations[1].value state = world.get_all_state(False) for location in world.get_locations(): @@ -28,9 +28,9 @@ class TestBase(unittest.TestCase): def testEmptyStateCanReachSomething(self): for game_name, world_type in AutoWorldRegister.world_types.items(): # Final Fantasy logic is controlled by finalfantasyrandomizer.com - if game_name not in {"Archipelago", "Final Fantasy", "Sudoku"}: + if game_name not in {"Archipelago", "Sudoku"}: with self.subTest("Game", game=game_name): - world = setup_default_world(world_type) + world = setup_solo_multiworld(world_type) state = CollectionState(world) locations = set() for location in world.get_locations(): diff --git a/test/general/__init__.py b/test/general/__init__.py index 247b135c..970c4ef9 100644 --- a/test/general/__init__.py +++ b/test/general/__init__.py @@ -6,7 +6,7 @@ from worlds.AutoWorld import call_all gen_steps = ["generate_early", "create_regions", "create_items", "set_rules", "generate_basic", "pre_fill"] -def setup_default_world(world_type) -> MultiWorld: +def setup_solo_multiworld(world_type) -> MultiWorld: multiworld = MultiWorld(1) multiworld.game[1] = world_type.game multiworld.player_name = {1: "Tester"} diff --git a/worlds/ff1/__init__.py b/worlds/ff1/__init__.py index 824fa1d3..51dd4b2a 100644 --- a/worlds/ff1/__init__.py +++ b/worlds/ff1/__init__.py @@ -45,8 +45,14 @@ class FF1World(World): self.locked_items = [] self.locked_locations = [] - def generate_early(self): - return + @classmethod + def stage_assert_generate(cls, multiworld: MultiWorld) -> None: + # Fail generation if there are no items in the pool + for player in multiworld.get_game_players(cls.game): + options = get_options(multiworld, 'items', player) + assert options,\ + f"FFR settings submitted with no key items ({multiworld.get_player_name(player)}). Please ensure you " \ + f"generated the settings using finalfantasyrandomizer.com AND enabled the AP flag" def create_regions(self): locations = get_options(self.multiworld, 'locations', self.player) @@ -65,8 +71,8 @@ class FF1World(World): terminated_event.access_rule = goal_rule_and_shards if "MARK" in items.keys(): # Fail generation for Noverworld and provide link to old FFR website - raise Exception("FFR Noverworld seeds must be generated on an older version of FFR. Please ensure you generated the settings using " - "4-4-0.finalfantasyrandomizer.com") + raise Exception("FFR Noverworld seeds must be generated on an older version of FFR. Please ensure you " + "generated the settings using 4-4-0.finalfantasyrandomizer.com") menu_region.locations.append(terminated_event) self.multiworld.regions += [menu_region] @@ -85,10 +91,6 @@ class FF1World(World): if possible_early_items: progression_item = self.multiworld.random.choice(possible_early_items) self._place_locked_item_in_sphere0(progression_item) - else: - # Fail generation if there are no items in the pool - raise Exception("FFR settings submitted with no key items. Please ensure you generated the settings using " - "finalfantasyrandomizer.com AND enabled the AP flag") items = [self.create_item(name) for name, data in items.items() for x in range(data['count']) if name not in self.locked_items]