Tests: world test base class (#1116)
* world test base class * game not instance property * I would have guessed that this only collected 1. * game property * move SoE tests into worlds * don't force auto world setup
This commit is contained in:
		
							parent
							
								
									49ae79e5ce
								
							
						
					
					
						commit
						f12b73f487
					
				|  | @ -128,7 +128,7 @@ ipython_config.py | |||
| 
 | ||||
| # Environments | ||||
| .env | ||||
| .venv | ||||
| .venv* | ||||
| env/ | ||||
| venv/ | ||||
| ENV/ | ||||
|  |  | |||
|  | @ -1,4 +1,5 @@ | |||
| from __future__ import annotations | ||||
| from argparse import Namespace | ||||
| 
 | ||||
| import copy | ||||
| from enum import unique, IntEnum, IntFlag | ||||
|  | @ -54,6 +55,7 @@ class MultiWorld(): | |||
|     indirect_connections: Dict[Region, Set[Entrance]] | ||||
|     exclude_locations: Dict[int, Options.ExcludeLocations] | ||||
| 
 | ||||
|     game: Dict[int, str] | ||||
| 
 | ||||
|     class AttributeProxy(): | ||||
|         def __init__(self, rule): | ||||
|  | @ -200,7 +202,7 @@ class MultiWorld(): | |||
|         self.slot_seeds = {player: random.Random(self.random.getrandbits(64)) for player in | ||||
|                            range(1, self.players + 1)} | ||||
| 
 | ||||
|     def set_options(self, args): | ||||
|     def set_options(self, args: Namespace) -> None: | ||||
|         for option_key in Options.common_options: | ||||
|             setattr(self, option_key, getattr(args, option_key, {})) | ||||
|         for option_key in Options.per_game_common_options: | ||||
|  |  | |||
|  | @ -78,6 +78,9 @@ class AssembleOptions(abc.ABCMeta): | |||
| 
 | ||||
|         return super(AssembleOptions, mcs).__new__(mcs, name, bases, attrs) | ||||
| 
 | ||||
|     @abc.abstractclassmethod | ||||
|     def from_any(cls, value: typing.Any) -> "Option[typing.Any]": ... | ||||
| 
 | ||||
| 
 | ||||
| T = typing.TypeVar('T') | ||||
| 
 | ||||
|  |  | |||
|  | @ -0,0 +1,5 @@ | |||
| from test.worlds.test_base import WorldTestBase | ||||
| 
 | ||||
| 
 | ||||
| class SoETestBase(WorldTestBase): | ||||
|     game = "Secret of Evermore" | ||||
|  | @ -7,54 +7,66 @@ from worlds import AutoWorld | |||
| from worlds.AutoWorld import call_all | ||||
| 
 | ||||
| 
 | ||||
| class SoETestBase(unittest.TestCase): | ||||
| class WorldTestBase(unittest.TestCase): | ||||
|     options: typing.Dict[str, typing.Any] = {} | ||||
|     world: MultiWorld | ||||
|     game = "Secret of Evermore" | ||||
| 
 | ||||
|     def setUp(self): | ||||
|     game: typing.ClassVar[str]  # define game name in subclass, example "Secret of Evermore" | ||||
|     auto_construct: typing.ClassVar[bool] = True | ||||
|     """ automatically set up a world for each test in this class """ | ||||
| 
 | ||||
|     def setUp(self) -> None: | ||||
|         if self.auto_construct: | ||||
|             self.world_setup() | ||||
| 
 | ||||
|     def world_setup(self) -> None: | ||||
|         if not hasattr(self, "game"): | ||||
|             raise NotImplementedError("didn't define game name") | ||||
|         self.world = MultiWorld(1) | ||||
|         self.world.game[1] = self.game | ||||
|         self.world.player_name = {1: "Tester"} | ||||
|         self.world.set_seed() | ||||
|         args = Namespace() | ||||
|         for name, option in AutoWorld.AutoWorldRegister.world_types[self.game].option_definitions.items(): | ||||
|             setattr(args, name, {1: option.from_any(self.options.get(name, option.default))}) | ||||
|             setattr(args, name, { | ||||
|                 1: option.from_any(self.options.get(name, getattr(option, "default"))) | ||||
|             }) | ||||
|         self.world.set_options(args) | ||||
|         self.world.set_default_common_options() | ||||
|         for step in gen_steps: | ||||
|             call_all(self.world, step) | ||||
| 
 | ||||
|     def collect_all_but(self, item_names: typing.Union[str, typing.Iterable[str]]): | ||||
|     def collect_all_but(self, item_names: typing.Union[str, typing.Iterable[str]]) -> None: | ||||
|         if isinstance(item_names, str): | ||||
|             item_names = (item_names,) | ||||
|         for item in self.world.get_items(): | ||||
|             if item.name not in item_names: | ||||
|                 self.world.state.collect(item) | ||||
| 
 | ||||
|     def get_item_by_name(self, item_name: str): | ||||
|     def get_item_by_name(self, item_name: str) -> Item: | ||||
|         for item in self.world.get_items(): | ||||
|             if item.name == item_name: | ||||
|                 return item | ||||
|         raise ValueError("No such item") | ||||
| 
 | ||||
|     def get_items_by_name(self, item_names: typing.Union[str, typing.Iterable[str]]): | ||||
|     def get_items_by_name(self, item_names: typing.Union[str, typing.Iterable[str]]) -> typing.List[Item]: | ||||
|         if isinstance(item_names, str): | ||||
|             item_names = (item_names,) | ||||
|         return [item for item in self.world.itempool if item.name in item_names] | ||||
| 
 | ||||
|     def collect_by_name(self, item_names: typing.Union[str, typing.Iterable[str]]): | ||||
|     def collect_by_name(self, item_names: typing.Union[str, typing.Iterable[str]]) -> typing.List[Item]: | ||||
|         """ collect all of the items in the item pool that have the given names """ | ||||
|         items = self.get_items_by_name(item_names) | ||||
|         self.collect(items) | ||||
|         return items | ||||
| 
 | ||||
|     def collect(self, items: typing.Union[Item, typing.Iterable[Item]]): | ||||
|     def collect(self, items: typing.Union[Item, typing.Iterable[Item]]) -> None: | ||||
|         if isinstance(items, Item): | ||||
|             items = (items,) | ||||
|         for item in items: | ||||
|             self.world.state.collect(item) | ||||
| 
 | ||||
|     def remove(self, items: typing.Union[Item, typing.Iterable[Item]]): | ||||
|     def remove(self, items: typing.Union[Item, typing.Iterable[Item]]) -> None: | ||||
|         if isinstance(items, Item): | ||||
|             items = (items,) | ||||
|         for item in items: | ||||
|  | @ -62,13 +74,15 @@ class SoETestBase(unittest.TestCase): | |||
|                 self.world.state.events.remove(item.location) | ||||
|             self.world.state.remove(item) | ||||
| 
 | ||||
|     def can_reach_location(self, location): | ||||
|     def can_reach_location(self, location: str) -> bool: | ||||
|         return self.world.state.can_reach(location, "Location", 1) | ||||
| 
 | ||||
|     def count(self, item_name): | ||||
|     def count(self, item_name: str) -> int: | ||||
|         return self.world.state.count(item_name, 1) | ||||
| 
 | ||||
|     def assertAccessDependency(self, locations, possible_items): | ||||
|     def assertAccessDependency(self, | ||||
|                                locations: typing.List[str], | ||||
|                                possible_items: typing.Iterable[typing.Iterable[str]]) -> None: | ||||
|         all_items = [item_name for item_names in possible_items for item_name in item_names] | ||||
| 
 | ||||
|         self.collect_all_but(all_items) | ||||
		Loading…
	
		Reference in New Issue