* Tests: add test for all games multiworld and test for two player multiworld per game * make assertSteps behave like call_all * review improvements * fix stage calling and loc copying in accessibility * add docstrings * lttp is on the options api now * skip the all games multiworld for now. likely needs to be modified to test specific worlds * move skip to the class
		
			
				
	
	
		
			78 lines
		
	
	
		
			3.8 KiB
		
	
	
	
		
			Python
		
	
	
	
	
	
			
		
		
	
	
			78 lines
		
	
	
		
			3.8 KiB
		
	
	
	
		
			Python
		
	
	
	
	
	
import unittest
 | 
						|
from typing import List, Tuple
 | 
						|
from unittest import TestCase
 | 
						|
 | 
						|
from BaseClasses import CollectionState, Location, MultiWorld
 | 
						|
from Fill import distribute_items_restrictive
 | 
						|
from Options import Accessibility
 | 
						|
from worlds.AutoWorld import AutoWorldRegister, call_all, call_single
 | 
						|
from ..general import gen_steps, setup_multiworld
 | 
						|
 | 
						|
 | 
						|
class MultiworldTestBase(TestCase):
 | 
						|
    multiworld: MultiWorld
 | 
						|
 | 
						|
    # similar to the implementation in WorldTestBase.test_fill
 | 
						|
    # but for multiple players and doesn't allow minimal accessibility
 | 
						|
    def fulfills_accessibility(self) -> bool:
 | 
						|
        """
 | 
						|
        Checks that the multiworld satisfies locations accessibility requirements, failing if all locations are cleared
 | 
						|
        but not beatable, or some locations are unreachable.
 | 
						|
        """
 | 
						|
        locations = [loc for loc in self.multiworld.get_locations()]
 | 
						|
        state = CollectionState(self.multiworld)
 | 
						|
        while locations:
 | 
						|
            sphere: List[Location] = []
 | 
						|
            for n in range(len(locations) - 1, -1, -1):
 | 
						|
                if locations[n].can_reach(state):
 | 
						|
                    sphere.append(locations.pop(n))
 | 
						|
            self.assertTrue(sphere, f"Unreachable locations: {locations}")
 | 
						|
            if not sphere:
 | 
						|
                return False
 | 
						|
            for location in sphere:
 | 
						|
                if location.item:
 | 
						|
                    state.collect(location.item, True, location)
 | 
						|
        return self.multiworld.has_beaten_game(state, 1)
 | 
						|
 | 
						|
    def assertSteps(self, steps: Tuple[str, ...]) -> None:
 | 
						|
        """Calls each step individually, continuing if a step for a specific world step fails."""
 | 
						|
        world_types = {world.__class__ for world in self.multiworld.worlds.values()}
 | 
						|
        for step in steps:
 | 
						|
            for player, world in self.multiworld.worlds.items():
 | 
						|
                with self.subTest(game=world.game, step=step):
 | 
						|
                    call_single(self.multiworld, step, player)
 | 
						|
            for world_type in sorted(world_types, key=lambda world: world.__name__):
 | 
						|
                with self.subTest(game=world_type.game, step=f"stage_{step}"):
 | 
						|
                    stage_callable = getattr(world_type, f"stage_{step}", None)
 | 
						|
                    if stage_callable:
 | 
						|
                        stage_callable(self.multiworld)
 | 
						|
 | 
						|
 | 
						|
@unittest.skip("too slow for main")
 | 
						|
class TestAllGamesMultiworld(MultiworldTestBase):
 | 
						|
    def test_fills(self) -> None:
 | 
						|
        """Tests that a multiworld with one of every registered game world can generate."""
 | 
						|
        all_worlds = list(AutoWorldRegister.world_types.values())
 | 
						|
        self.multiworld = setup_multiworld(all_worlds, ())
 | 
						|
        for world in self.multiworld.worlds.values():
 | 
						|
            world.options.accessibility.value = Accessibility.option_locations
 | 
						|
        self.assertSteps(gen_steps)
 | 
						|
        with self.subTest("filling multiworld", seed=self.multiworld.seed):
 | 
						|
            distribute_items_restrictive(self.multiworld)
 | 
						|
            call_all(self.multiworld, "post_fill")
 | 
						|
            self.assertTrue(self.fulfills_accessibility(), "Collected all locations, but can't beat the game")
 | 
						|
 | 
						|
 | 
						|
class TestTwoPlayerMulti(MultiworldTestBase):
 | 
						|
    def test_two_player_single_game_fills(self) -> None:
 | 
						|
        """Tests that a multiworld of two players for each registered game world can generate."""
 | 
						|
        for world in AutoWorldRegister.world_types.values():
 | 
						|
            self.multiworld = setup_multiworld([world, world], ())
 | 
						|
            for world in self.multiworld.worlds.values():
 | 
						|
                world.options.accessibility.value = Accessibility.option_locations
 | 
						|
            self.assertSteps(gen_steps)
 | 
						|
        with self.subTest("filling multiworld", seed=self.multiworld.seed):
 | 
						|
            distribute_items_restrictive(self.multiworld)
 | 
						|
            call_all(self.multiworld, "post_fill")
 | 
						|
            self.assertTrue(self.fulfills_accessibility(), "Collected all locations, but can't beat the game")
 |