def test_decode(location_with_data): # Setup data, expected = location_with_data # Run decoder = BitPackDecoder(data) result = StartingLocation.bit_pack_unpack(decoder, { "reference": StartingLocation.with_elements([], RandovaniaGame.PRIME2) }) # Assert assert result == expected
def test_distribute_command_logic(mock_generate_list: MagicMock, ): # Setup args = MagicMock() args.trick_level = LayoutTrickLevel.HARD.value args.major_items_mode = False args.sky_temple_keys = LayoutSkyTempleKeyMode.ALL_BOSSES.value args.skip_item_loss = True args.seed = 15000 args.output_file = "asdfasdf/qwerqwerqwer/zxcvzxcv.json" # Run echoes.distribute_command_logic(args) # Assert mock_generate_list.assert_called_once_with(permalink=Permalink( seed_number=args.seed, spoiler=True, patcher_configuration=PatcherConfiguration.default(), layout_configuration=LayoutConfiguration.from_params( trick_level=LayoutTrickLevel.HARD, sky_temple_keys=LayoutSkyTempleKeyMode.ALL_BOSSES, elevators=LayoutRandomizedFlag.VANILLA, pickup_quantities={}, starting_location=StartingLocation.default(), starting_resources=StartingResources.from_non_custom_configuration( StartingResourcesConfiguration.VANILLA_ITEM_LOSS_DISABLED), ), ), status_update=ANY) save_file_mock: MagicMock = mock_generate_list.return_value.save_to_file save_file_mock.assert_called_once_with(Path(args.output_file))
def test_create_permalink_logic(mock_print: MagicMock, ): # Setup args = MagicMock() args.trick_level = LayoutTrickLevel.HARD.value args.major_items_mode = False args.sky_temple_keys = LayoutSkyTempleKeyMode.ALL_BOSSES.value args.skip_item_loss = True args.seed = 15000 args.menu_mod = False args.warp_to_start = False # Run randovania.cli.commands.create_permalink.create_permalink_logic(args) # Assert permalink = Permalink( seed_number=args.seed, spoiler=True, patcher_configuration=PatcherConfiguration( menu_mod=args.menu_mod, warp_to_start=args.warp_to_start, ), layout_configuration=LayoutConfiguration.from_params( trick_level_configuration=TrickLevelConfiguration( LayoutTrickLevel.HARD), sky_temple_keys=LayoutSkyTempleKeyMode.ALL_BOSSES, elevators=LayoutElevators.VANILLA, starting_location=StartingLocation.default(), ), ) # Assert mock_print.assert_called_once_with(permalink)
def _update_starting_location(self): if self._has_valid_starting_location(): with self._options as options: options.set_layout_configuration_field( "starting_location", StartingLocation(self.startingarea_combo.currentData(), self.current_starting_area_location))
def from_json_dict(cls, json_dict: dict) -> "LayoutConfiguration": return LayoutConfiguration( trick_level_configuration=TrickLevelConfiguration.from_json( json_dict["trick_level"]), damage_strictness=LayoutDamageStrictness( json_dict["damage_strictness"]), sky_temple_keys=LayoutSkyTempleKeyMode( json_dict["sky_temple_keys"]), elevators=LayoutElevators(json_dict["elevators"]), starting_location=StartingLocation.from_json( json_dict["starting_location"]), available_locations=AvailableLocationsConfiguration.from_json( json_dict["available_locations"]), major_items_configuration=MajorItemsConfiguration.from_json( json_dict["major_items_configuration"], default_prime2_item_database(), ), ammo_configuration=AmmoConfiguration.from_json( json_dict["ammo_configuration"], default_prime2_item_database(), ), translator_configuration=TranslatorConfiguration.from_json( json_dict["translator_configuration"]), hints=HintConfiguration.from_json(json_dict["hints"]), beam_configuration=BeamConfiguration.from_json( json_dict["beam_configuration"]), skip_final_bosses=json_dict["skip_final_bosses"], energy_per_tank=json_dict["energy_per_tank"], split_beam_ammo=json_dict["split_beam_ammo"], )
def test_invalid_constructor_location_should_be_missing(): with pytest.raises(ValueError) as err: StartingLocation(StartingLocationConfiguration.SHIP, AreaLocation(0, 0)) assert str(err.value) == "custom_location set to world 0/area 0, " \ "but configuration is StartingLocationConfiguration.SHIP instead of CUSTOM"
def default(cls) -> "LayoutConfiguration": return cls.from_params( trick_level=LayoutTrickLevel.NO_TRICKS, sky_temple_keys=LayoutSkyTempleKeyMode.FULLY_RANDOM, elevators=LayoutRandomizedFlag.VANILLA, pickup_quantities={}, starting_location=StartingLocation.default(), starting_resources=StartingResources.default(), )
def get_layout_configuration_from_args(args) -> LayoutConfiguration: return LayoutConfiguration.from_params( trick_level=LayoutTrickLevel(args.trick_level), sky_temple_keys=LayoutSkyTempleKeyMode(args.sky_temple_keys), elevators=LayoutRandomizedFlag.VANILLA, pickup_quantities={}, starting_location=StartingLocation.default(), starting_resources=StartingResources.from_item_loss( not args.skip_item_loss), )
def _starting_location_on_select_save_station(self): world_list = self.game_description.world_list save_stations = [world_list.node_to_area_location(node) for node in world_list.all_nodes if node.name == "Save Station"] with self._editor as editor: editor.set_layout_configuration_field( "starting_location", StartingLocation.with_elements(save_stations) )
def test_decode(location_with_data): # Setup data, expected = location_with_data # Run decoder = BitPackDecoder(data) result = StartingLocation.bit_pack_unpack(decoder, {}) # Assert assert result == expected
def from_json_dict(cls, json_dict: dict) -> "LayoutConfiguration": return cls.from_params( trick_level=LayoutTrickLevel(json_dict["trick_level"]), sky_temple_keys=LayoutSkyTempleKeyMode( json_dict["sky_temple_keys"]), elevators=LayoutRandomizedFlag(json_dict["elevators"]), pickup_quantities=json_dict["pickup_quantities"], starting_location=StartingLocation.from_json( json_dict["starting_location"]), starting_resources=StartingResources.from_json( json_dict["starting_resources"]), )
def _location_with_data(request, mocker, echoes_game_description): world_list = echoes_game_description.world_list areas = list( itertools.islice( (AreaLocation(world.world_asset_id, area.area_asset_id) for world in world_list.worlds for area in world.areas if area.valid_starting_location), 15)) mocker.patch("randovania.layout.starting_location._areas_list", return_value=list(sorted(areas))) return request.param["encoded"], StartingLocation.from_json( request.param["json"])
def test_create_patches( mock_random: MagicMock, mock_calculate_item_pool: MagicMock, mock_create_base_patches: MagicMock, mock_retcon_playthrough_filler: MagicMock, mock_indices_for_unassigned_pickups: MagicMock, ): # Setup seed_number: int = 91319 game = default_prime2_game_description() status_update: Union[MagicMock, Callable[[str], None]] = MagicMock() configuration = LayoutConfiguration.from_params( trick_level=LayoutTrickLevel.NO_TRICKS, sky_temple_keys=LayoutSkyTempleKeyMode.FULLY_RANDOM, elevators=LayoutRandomizedFlag.VANILLA, pickup_quantities={}, starting_location=StartingLocation.default(), starting_resources=StartingResources.from_item_loss(False), ) permalink = Permalink( seed_number=seed_number, spoiler=True, patcher_configuration=PatcherConfiguration.default(), layout_configuration=configuration, ) mock_calculate_item_pool.return_value = list( sorted(game.pickup_database.original_pickup_mapping.values())) mock_create_base_patches.return_value.starting_location = game.starting_location mock_create_base_patches.return_value.custom_initial_items = None filler_patches = mock_retcon_playthrough_filler.return_value # Run result = generator._create_patches(permalink, game, status_update) # Assert mock_random.assert_called_once_with(permalink.as_str) mock_calculate_item_pool.assert_called_once_with(permalink, game) mock_create_base_patches.assert_called_once_with(mock_random.return_value, game, permalink, ANY) mock_retcon_playthrough_filler.assert_called_once_with( ANY, ANY, ANY, mock_random.return_value, status_update) mock_indices_for_unassigned_pickups.assert_called_once_with( mock_random.return_value, game, filler_patches.pickup_assignment, ANY) filler_patches.assign_new_pickups.assert_called_once_with( mock_indices_for_unassigned_pickups.return_value) assert result == filler_patches.assign_new_pickups.return_value
def get_layout_configuration_from_args(args) -> LayoutConfiguration: try: sky_temple_keys = int(args.sky_temple_keys) except ValueError: sky_temple_keys = args.sky_temple_keys # TODO: support for item loss return LayoutConfiguration.from_params( trick_level_configuration=TrickLevelConfiguration( LayoutTrickLevel(args.trick_level)), sky_temple_keys=LayoutSkyTempleKeyMode(sky_temple_keys), elevators=LayoutElevators.VANILLA, starting_location=StartingLocation.default(), )
def from_json_dict(cls, json_dict: dict) -> "LayoutConfiguration": return cls.from_params( trick_level_configuration=TrickLevelConfiguration.from_json(json_dict["trick_level"]), sky_temple_keys=LayoutSkyTempleKeyMode(json_dict["sky_temple_keys"]), elevators=LayoutElevators(json_dict["elevators"]), starting_location=StartingLocation.from_json(json_dict["starting_location"]), randomization_mode=RandomizationMode(json_dict["randomization_mode"]), major_items_configuration=MajorItemsConfiguration.from_json( json_dict["major_items_configuration"], default_prime2_item_database(), ), ammo_configuration=AmmoConfiguration.from_json( json_dict["ammo_configuration"], default_prime2_item_database(), ), translator_configuration=TranslatorConfiguration.from_json(json_dict["translator_configuration"]), hints=HintConfiguration.from_json(json_dict["hints"]), split_beam_ammo=json_dict["split_beam_ammo"], )
def _test_data(): data = default_data.decode_default_prime2() game = data_reader.decode_data(data, False) configuration = LayoutConfiguration.from_params( trick_level=LayoutTrickLevel.NO_TRICKS, sky_temple_keys=LayoutSkyTempleKeyMode.FULLY_RANDOM, elevators=LayoutRandomizedFlag.VANILLA, pickup_quantities={}, starting_location=StartingLocation.default(), starting_resources=StartingResources.default(), ) permalink = Permalink( seed_number=15000, spoiler=True, patcher_configuration=PatcherConfiguration.default(), layout_configuration=configuration, ) logic, state = logic_bootstrap(configuration, game, GamePatches.with_game(game)) return logic, state, permalink
def test_generate_seed_with_invalid_quantity_configuration(): # Setup status_update = MagicMock() configuration = LayoutConfiguration.from_params( trick_level=LayoutTrickLevel.NO_TRICKS, sky_temple_keys=LayoutSkyTempleKeyMode.FULLY_RANDOM, elevators=LayoutRandomizedFlag.VANILLA, pickup_quantities={"Light Suit": 5}, starting_location=StartingLocation.default(), starting_resources=StartingResources.default(), ) permalink = Permalink( seed_number=50, spoiler=True, patcher_configuration=PatcherConfiguration.default(), layout_configuration=configuration, ) # Run with pytest.raises(randovania.resolver.exceptions.GenerationFailure): generator.generate_list(permalink, status_update=status_update)
def test_decode_v1(mock_dictionary_byte_hash: MagicMock): mock_dictionary_byte_hash.return_value = 120 # We're mocking the database hash to avoid breaking tests every single time we change the database # This test should break whenever we change how permalinks are created # When this happens, we must bump the permalink version and change the tests encoded = "IAAAfReNPArRHMClxLYgIID3" expected = Permalink( seed_number=1000, spoiler=True, patcher_configuration=PatcherConfiguration( disable_hud_popup=True, menu_mod=True, speed_up_credits=False, ), layout_configuration=LayoutConfiguration.from_params( trick_level=LayoutTrickLevel.HARD, sky_temple_keys=LayoutSkyTempleKeyMode.FULLY_RANDOM, elevators=LayoutRandomizedFlag.RANDOMIZED, pickup_quantities={ "Missile Expansion": 10, "Light Suit": 9, }, starting_location=StartingLocation.default(), starting_resources=StartingResources.default(), ), ) # Uncomment this line to quickly get the new encoded permalink # assert expected.as_str == "" # Run link = Permalink.from_str(encoded) # Assert assert link == expected
PatcherConfiguration( menu_mod=True, warp_to_start=False, ), ]) @pytest.mark.parametrize("layout", [ LayoutConfiguration.default(), LayoutConfiguration.from_params( trick_level=LayoutTrickLevel.HARD, sky_temple_keys=LayoutSkyTempleKeyMode.FULLY_RANDOM, elevators=LayoutRandomizedFlag.RANDOMIZED, pickup_quantities={ "Missile Expansion": 10, "Light Suit": 9, }, starting_location=StartingLocation.default(), starting_resources=StartingResources.default(), ), ]) def test_round_trip(spoiler: bool, patcher: PatcherConfiguration, layout: LayoutConfiguration): # Setup link = Permalink( seed_number=1000, spoiler=spoiler, patcher_configuration=patcher, layout_configuration=layout, ) # Run after = Permalink.from_str(link.as_str)
result = option._serialize_fields() # Assert assert result == { "version": 4, "options": {} } _sample_layout_configurations = [ { "trick_level": trick_level, "sky_temple_keys": LayoutSkyTempleKeyMode.FULLY_RANDOM, "elevators": LayoutRandomizedFlag.RANDOMIZED, "pickup_quantities": {}, "starting_location": StartingLocation.default(), "starting_resources": StartingResources.from_item_loss(item_loss), } for trick_level in [LayoutTrickLevel.NO_TRICKS, LayoutTrickLevel.HARD, LayoutTrickLevel.MINIMAL_RESTRICTIONS] for item_loss in (False, True) ] @pytest.fixture(params=_sample_layout_configurations, name="initial_layout_configuration_params") def _initial_layout_configuration_params(request) -> dict: return request.param @pytest.mark.parametrize("new_trick_level", [LayoutTrickLevel.NO_TRICKS, LayoutTrickLevel.TRIVIAL, LayoutTrickLevel.HYPERMODE]) def test_edit_layout_trick_level(option: Options,
def test_invalid_constructor_missing_location(): with pytest.raises(ValueError) as err: StartingLocation(StartingLocationConfiguration.CUSTOM, None) assert str( err.value) == "Configuration is CUSTOM, but not custom_location set"
def test_round_trip_json_all_custom_location(custom_starting_location): # Run round_trip = StartingLocation.from_json(custom_starting_location.as_json) # Assert assert custom_starting_location == round_trip
def test_round_trip_json_simple(simple_starting_location): # Run round_trip = StartingLocation.from_json(simple_starting_location.as_json) # Assert assert simple_starting_location == round_trip
def test_default(): value = StartingLocation.default() # Assert assert value.configuration == StartingLocationConfiguration.SHIP
def _custom_starting_location(): return StartingLocation(StartingLocationConfiguration.CUSTOM, AreaLocation(2252328306, 3417147547))
def _simple_starting_location(request): yield StartingLocation(request.param, None)
"options": { "last_changelog_displayed": str(update_checker.strict_current_version()), } } _sample_layout_configurations = [{ "trick_level_configuration": TrickLevelConfiguration(trick_level), "sky_temple_keys": LayoutSkyTempleKeyMode.default(), "elevators": LayoutElevators.RANDOMIZED, "starting_location": StartingLocation.default(), } for trick_level in [ LayoutTrickLevel.NO_TRICKS, LayoutTrickLevel.HARD, LayoutTrickLevel.MINIMAL_RESTRICTIONS ]] @pytest.fixture(params=_sample_layout_configurations, name="initial_layout_configuration_params") def _initial_layout_configuration_params(request) -> dict: return request.param @pytest.mark.parametrize("new_trick_level", [ LayoutTrickLevel.NO_TRICKS, LayoutTrickLevel.TRIVIAL, LayoutTrickLevel.HYPERMODE
def _location_with_data(request): return request.param["encoded"], StartingLocation.from_json( request.param["json"])
def test_apply_layout(mock_run_with_args: MagicMock, mock_base_args: MagicMock, mock_ensure_no_menu_mod: MagicMock, mock_create_pak_backups: MagicMock, mock_calculate_indices: MagicMock, mock_add_menu_mod_to_files: MagicMock, mock_create_progress_update_from_successive_messages: MagicMock, mock_save_to_file: MagicMock, seed_number: int, item_loss: bool, elevators: bool, warp_to_start: bool, include_menu_mod: bool, speed_up_credits: bool, ): # Setup hud_memo_popup_removal: bool = MagicMock() cosmetic_patches = CosmeticPatches(disable_hud_popup=hud_memo_popup_removal, speed_up_credits=speed_up_credits, ) description = LayoutDescription( version=randovania.VERSION, permalink=Permalink( seed_number=seed_number, spoiler=False, patcher_configuration=PatcherConfiguration( menu_mod=include_menu_mod, warp_to_start=warp_to_start, ), layout_configuration=LayoutConfiguration.from_params( trick_level=MagicMock(), sky_temple_keys=MagicMock(), elevators=LayoutRandomizedFlag.RANDOMIZED if elevators else LayoutRandomizedFlag.VANILLA, pickup_quantities={}, starting_location=StartingLocation.default(), starting_resources=StartingResources.from_item_loss(item_loss), ) ), patches=None, solver_path=(), ) game_root = MagicMock(spec=Path()) backup_files_path = MagicMock() progress_update = MagicMock() status_update = mock_create_progress_update_from_successive_messages.return_value mock_calculate_indices.return_value = [10, 25, 1, 2, 5, 1] mock_base_args.return_value = [] expected_args = [ "-s", str(seed_number), "-p", "10,25,1,2,5,1" ] if not item_loss: expected_args.append("-i") if elevators: expected_args.append("-v") if speed_up_credits: expected_args.append("-c") if warp_to_start: expected_args.append("-t") # Run claris_randomizer.apply_layout(description, cosmetic_patches, backup_files_path, progress_update, game_root) # Assert mock_base_args.assert_called_once_with(game_root, hud_memo_popup_removal=hud_memo_popup_removal) mock_create_progress_update_from_successive_messages.assert_called_once_with( progress_update, 400 if include_menu_mod else 100 ) mock_ensure_no_menu_mod.assert_called_once_with(game_root, backup_files_path, status_update) mock_create_pak_backups.assert_called_once_with(game_root, backup_files_path, status_update) mock_calculate_indices.assert_called_once_with(description) game_root.joinpath.assert_called_once_with("files", "randovania.json") mock_save_to_file.assert_called_once_with(description, game_root.joinpath.return_value) mock_run_with_args.assert_called_once_with(expected_args, "Randomized!", status_update) if include_menu_mod: mock_add_menu_mod_to_files.assert_called_once_with(game_root, status_update) else: mock_add_menu_mod_to_files.assert_not_called()
def _starting_location_on_select_ship(self): with self._editor as editor: editor.set_layout_configuration_field( "starting_location", StartingLocation.with_elements( [self.game_description.starting_location]))