def test_decode(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 = "gAAAfReLCAAC4wAAAOaANg==" expected = Permalink( seed_number=1000, spoiler=True, patcher_configuration=PatcherConfiguration( menu_mod=True, warp_to_start=False, ), layout_configuration=LayoutConfiguration.from_params( trick_level_configuration=TrickLevelConfiguration( LayoutTrickLevel.HARD), elevators=LayoutElevators.RANDOMIZED, ), ) # Uncomment this line to quickly get the new encoded permalink # assert expected.as_str == "" # print(expected.as_str) # Run link = Permalink.from_str(encoded) # Assert assert link == expected
def test_round_trip_generated_patches(echoes_game_data): # Setup configuration = LayoutConfiguration.from_params( trick_level_configuration=TrickLevelConfiguration( global_level=LayoutTrickLevel.MINIMAL_RESTRICTIONS, specific_levels={}, )) patches = generator._create_randomized_patches( permalink=Permalink( seed_number=1000, spoiler=True, patcher_configuration=PatcherConfiguration.default(), layout_configuration=configuration, ), game=data_reader.decode_data(echoes_game_data), status_update=lambda x: None, ) # Run encoded = game_patches_serializer.serialize(patches, echoes_game_data) decoded = game_patches_serializer.decode(encoded, configuration) # Assert assert patches == decoded
def test_round_trip_generated_patches(echoes_game_data, default_preset): # Setup preset = dataclasses.replace( default_preset, base_preset_name=default_preset.name, configuration=dataclasses.replace( default_preset.configuration, trick_level=TrickLevelConfiguration( minimal_logic=True, specific_levels={}, game=RandovaniaGame.PRIME2, ) ) ) all_patches = generator._async_create_description( permalink=Permalink( seed_number=1000, spoiler=True, presets={0: preset}, ), status_update=lambda x: None, attempts=0, ).all_patches # Run encoded = game_patches_serializer.serialize(all_patches, {0: echoes_game_data}) decoded = game_patches_serializer.decode(encoded, {0: preset.configuration}) # Assert assert all_patches == decoded
def test_round_trip_generated_patches(echoes_game_data, preset_manager): # Setup preset = dataclasses.replace( preset_manager.default_preset, layout_configuration=dataclasses.replace( preset_manager.default_preset.layout_configuration, trick_level_configuration=TrickLevelConfiguration( global_level=LayoutTrickLevel.MINIMAL_RESTRICTIONS, specific_levels={}, ))) all_patches = generator._async_create_description( permalink=Permalink( seed_number=1000, spoiler=True, presets={0: preset}, ), status_update=lambda x: None, ).all_patches # Run encoded = game_patches_serializer.serialize(all_patches, {0: echoes_game_data}) decoded = game_patches_serializer.decode(encoded, {0: preset.layout_configuration}) # Assert assert all_patches == decoded
def test_round_trip_generated_patches(echoes_game_data, preset_manager): # Setup preset = dataclasses.replace( preset_manager.default_preset, layout_configuration=dataclasses.replace( preset_manager.default_preset.layout_configuration, trick_level_configuration=TrickLevelConfiguration( global_level=LayoutTrickLevel.MINIMAL_RESTRICTIONS, specific_levels={}, ) ) ) patches = generator._create_randomized_patches( permalink=Permalink( seed_number=1000, spoiler=True, preset=preset, ), game=data_reader.decode_data(echoes_game_data), status_update=lambda x: None, ) # Run encoded = game_patches_serializer.serialize(patches, echoes_game_data) decoded = game_patches_serializer.decode(encoded, preset.layout_configuration) # Assert assert patches == decoded
def test_reach_size_from_start(echoes_game_description, default_layout_configuration, minimal_logic, nodes, safe_nodes): # Setup specific_levels = { trick.short_name: LayoutTrickLevel.HYPERMODE for trick in echoes_game_description.resource_database.trick } layout_configuration = dataclasses.replace( default_layout_configuration, trick_level_configuration=TrickLevelConfiguration( minimal_logic=minimal_logic, specific_levels=specific_levels if not minimal_logic else {}), ) player_pool = generator.create_player_pool(Random(15000), layout_configuration, 0) game, state = logic_bootstrap(layout_configuration, player_pool.game, player_pool.patches) # Run reach = GeneratorReach.reach_from_state(game, state) # Assert assert len(list(reach.nodes)) >= nodes assert len(list(reach.safe_nodes)) >= safe_nodes
def test_edit_layout_trick_level(editor: PresetEditor, initial_layout_configuration_params: dict, default_layout_configuration, new_trick_level: LayoutTrickLevel): # Setup editor._layout_configuration = dataclasses.replace(default_layout_configuration, **initial_layout_configuration_params) editor._nested_autosave_level = 1 # Run initial_layout_configuration_params["trick_level_configuration"] = TrickLevelConfiguration(new_trick_level) editor.set_layout_configuration_field("trick_level_configuration", TrickLevelConfiguration(new_trick_level)) # Assert assert editor.layout_configuration == dataclasses.replace(default_layout_configuration, **initial_layout_configuration_params)
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 test_edit_layout_trick_level(option: Options, initial_layout_configuration_params: dict, new_trick_level: LayoutTrickLevel): # Setup option._layout_configuration = LayoutConfiguration.from_params( **initial_layout_configuration_params) option._nested_autosave_level = 1 # Run initial_layout_configuration_params[ "trick_level_configuration"] = TrickLevelConfiguration(new_trick_level) option.set_layout_configuration_field( "trick_level_configuration", TrickLevelConfiguration(new_trick_level)) # Assert assert option.layout_configuration == LayoutConfiguration.from_params( **initial_layout_configuration_params)
def test_set_level_for_trick_remove(echoes_resource_database): trick = echoes_resource_database.trick[0] config = TrickLevelConfiguration(False, {}, RandovaniaGame.PRIME2) assert config.level_for_trick(trick) == LayoutTrickLevel.DISABLED config = config.set_level_for_trick(trick, LayoutTrickLevel.ADVANCED) assert config.level_for_trick(trick) == LayoutTrickLevel.ADVANCED config = config.set_level_for_trick(trick, LayoutTrickLevel.DISABLED) assert config.level_for_trick(trick) == LayoutTrickLevel.DISABLED
def test_decode(configuration_with_data): # Setup data, expected = configuration_with_data # Run decoder = BitPackDecoder(data) result = TrickLevelConfiguration.bit_pack_unpack(decoder, { "reference": TrickLevelConfiguration(False, {}, RandovaniaGame.PRIME2), }) # Assert assert result == expected
def _create_open_map_tracker_actions(self): base_layout = self.preset_manager.default_preset.layout_configuration for trick_level in LayoutTrickLevel: if trick_level != LayoutTrickLevel.MINIMAL_RESTRICTIONS: action = QtWidgets.QAction(self) action.setText(trick_level.long_name) self.menu_map_tracker.addAction(action) configuration = dataclasses.replace( base_layout, trick_level_configuration=TrickLevelConfiguration(trick_level, {}) ) action.triggered.connect(partial(self.open_map_tracker, configuration))
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 test_reach_size_from_start(echoes_game_description): # Setup configuration = LayoutConfiguration.from_params( trick_level_configuration=TrickLevelConfiguration( LayoutTrickLevel.HYPERMODE), ) patches = GamePatches.with_game(echoes_game_description) patches = patches.assign_gate_assignment( base_patches_factory.gate_assignment_for_configuration( configuration, echoes_game_description.resource_database, Random(15000))) game, state = logic_bootstrap(configuration, echoes_game_description, patches) # Run reach = GeneratorReach.reach_from_state(game, state) # Assert assert len(list(reach.nodes)) == 26 assert len(list(reach.safe_nodes)) == 4
def test_reach_size_from_start(echoes_game_description, default_layout_configuration): # Setup layout_configuration = dataclasses.replace( default_layout_configuration, trick_level_configuration=TrickLevelConfiguration( LayoutTrickLevel.HYPERMODE), ) player_pool = generator.create_player_pool(Random(15000), layout_configuration, 0) game, state = logic_bootstrap(layout_configuration, player_pool.game, player_pool.patches) # Run reach = GeneratorReach.reach_from_state(game, state) # Assert assert len(list(reach.nodes)) == 44 assert len(list(reach.safe_nodes)) == 5
def test_reach_size_from_start(echoes_game_description, default_layout_configuration): # Setup configuration = dataclasses.replace( default_layout_configuration, trick_level_configuration=TrickLevelConfiguration( LayoutTrickLevel.HYPERMODE), ) patches = echoes_game_description.create_game_patches() patches = patches.assign_gate_assignment( base_patches_factory.gate_assignment_for_configuration( configuration, echoes_game_description.resource_database, Random(15000))) game, state = logic_bootstrap(configuration, echoes_game_description, patches) # Run reach = GeneratorReach.reach_from_state(game, state) # Assert assert len(list(reach.nodes)) == 25 assert len(list(reach.safe_nodes)) == 4
def test_encode_no_tricks_are_removed(): from_json = TrickLevelConfiguration.from_json( { "minimal_logic": False, "specific_levels": { "Dash": "disabled" } }, game=RandovaniaGame.PRIME2) encoded = bitpacking._pack_encode_results([ (value_argument, value_format) for value_argument, value_format in from_json.bit_pack_encode({}) ]) assert encoded == b'\x00\x00\x00\x00' decoder = BitPackDecoder(encoded) decoded = TrickLevelConfiguration.bit_pack_unpack(decoder, { "reference": TrickLevelConfiguration(False, {}, RandovaniaGame.PRIME2), }) assert decoded.specific_levels == {}
with pytest.raises(ValueError): Permalink.from_str(invalid) @pytest.mark.parametrize("spoiler", [False, True]) @pytest.mark.parametrize("patcher", [ {}, { "menu_mod": True, "warp_to_start": False, }, ]) @pytest.mark.parametrize("layout", [ {}, { "trick_level_configuration": TrickLevelConfiguration(LayoutTrickLevel.VETERAN), "sky_temple_keys": LayoutSkyTempleKeyMode.ALL_GUARDIANS, "elevators": LayoutElevators.TWO_WAY_RANDOMIZED, }, ]) def test_round_trip(spoiler: bool, patcher: dict, layout: dict, preset_manager): # Setup preset = Preset( name="{} Custom".format(preset_manager.default_preset.name), description="A customized preset.", base_preset_name=preset_manager.default_preset.name, patcher_configuration=dataclasses.replace(preset_manager.default_preset.patcher_configuration, **patcher), layout_configuration=dataclasses.replace(preset_manager.default_preset.layout_configuration, **layout),
Permalink.from_str(invalid) @pytest.mark.parametrize("spoiler", [False, True]) @pytest.mark.parametrize("patcher", [ {}, { "menu_mod": True, "warp_to_start": False, }, ]) @pytest.mark.parametrize("layout", [ {}, { "trick_level_configuration": TrickLevelConfiguration(LayoutTrickLevel.EXPERT), "sky_temple_keys": LayoutSkyTempleKeyMode.ALL_GUARDIANS, "elevators": LayoutElevators.TWO_WAY_RANDOMIZED, }, ]) def test_round_trip(spoiler: bool, patcher: dict, layout: dict, default_preset): # Setup preset = Preset( name="{} Custom".format(default_preset.name), description="A customized preset.", base_preset_name=default_preset.name, patcher_configuration=dataclasses.replace( default_preset.patcher_configuration, **patcher),
with pytest.raises(ValueError): Permalink.from_str(invalid) @pytest.mark.parametrize("spoiler", [False, True]) @pytest.mark.parametrize("patcher", [ {}, { "menu_mod": True, "warp_to_start": False, }, ]) @pytest.mark.parametrize("layout", [ {}, { "trick_level_configuration": TrickLevelConfiguration(specific_levels={"ScanPost": LayoutTrickLevel.EXPERT}), "sky_temple_keys": LayoutSkyTempleKeyMode.ALL_GUARDIANS, "elevators": LayoutElevators.TWO_WAY_RANDOMIZED, }, ]) def test_round_trip(spoiler: bool, patcher: dict, layout: dict, default_preset): # Setup preset = Preset( name="{} Custom".format(default_preset.name), description="A customized preset.", base_preset_name=default_preset.name, patcher_configuration=dataclasses.replace(default_preset.patcher_configuration, **patcher), layout_configuration=dataclasses.replace(default_preset.layout_configuration, **layout),
with pytest.raises(ValueError): Permalink.from_str(invalid) @pytest.mark.parametrize("spoiler", [False, True]) @pytest.mark.parametrize("patcher", [ PatcherConfiguration.default(), PatcherConfiguration( menu_mod=True, warp_to_start=False, ), ]) @pytest.mark.parametrize("layout", [ LayoutConfiguration.default(), LayoutConfiguration.from_params( trick_level_configuration=TrickLevelConfiguration( LayoutTrickLevel.HARD), sky_temple_keys=LayoutSkyTempleKeyMode.ALL_GUARDIANS, elevators=LayoutElevators.RANDOMIZED, ), ]) 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
result = option._serialize_fields() # Assert assert result == { "version": randovania.interface_common.persisted_options. _CURRENT_OPTIONS_FILE_VERSION, "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:
def test_pretty_description_tricks_echoes(levels, expected): config = TrickLevelConfiguration(False, levels, RandovaniaGame.PRIME2) assert config.pretty_description == expected
def test_pretty_description_minimal_logic(): config = TrickLevelConfiguration(True, {}, RandovaniaGame.PRIME2) assert config.pretty_description == "Minimal Logic"
_test_descriptions = [ _create_test_layout_description( configuration=LayoutConfiguration.default(), pickup_mapping=[ 37, 2, 2, 68, 100, 38, 102, 109, 8, 17, 4, 69, 88, 13, 44, 2, 4, 2, 74, 2, 27, 23, 2, 46, 43, 15, 2, 2, 50, 4, 24, 2, 2, 2, 2, 57, 2, 2, 2, 4, 4, 115, 2, 53, 7, 2, 2, 59, 75, 8, 2, 52, 8, 2, 19, 112, 2, 8, 17, 92, 2, 2, 79, 106, 2, 4, 2, 17, 4, 2, 2, 2, 2, 117, 2, 2, 2, 17, 2, 8, 82, 8, 2, 4, 114, 118, 2, 91, 8, 4, 4, 11, 2, 2, 4, 1, 2, 0, 4, 8, 2, 116, 2, 4, 2, 2, 86, 2, 2, 39, 2, 21, 2, 2, 45, 2, 4, 76, 83 ], ), _create_test_layout_description( configuration=LayoutConfiguration.from_params( trick_level_configuration=TrickLevelConfiguration( LayoutTrickLevel.HYPERMODE), ), pickup_mapping=[ 91, 45, 17, 24, 4, 2, 23, 59, 2, 0, 2, 68, 8, 38, 2, 2, 2, 7, 4, 115, 37, 2, 86, 2, 76, 2, 4, 2, 117, 112, 17, 2, 2, 2, 13, 39, 88, 82, 102, 50, 57, 2, 52, 116, 2, 4, 2, 8, 118, 2, 2, 2, 1, 2, 2, 53, 74, 2, 2, 114, 4, 2, 4, 8, 2, 8, 2, 2, 19, 2, 43, 2, 2, 2, 2, 2, 2, 8, 4, 2, 2, 2, 4, 109, 2, 4, 2, 4, 11, 8, 69, 92, 2, 4, 106, 17, 17, 21, 75, 79, 2, 2, 2, 100, 2, 15, 83, 8, 4, 2, 2, 46, 24, 2, 4, 44, 8, 4, 2 ], ), _create_test_layout_description( configuration=LayoutConfiguration.from_params( trick_level_configuration=TrickLevelConfiguration( LayoutTrickLevel.MINIMAL_RESTRICTIONS), sky_temple_keys=LayoutSkyTempleKeyMode.ALL_BOSSES,
from randovania.interface_common.options import Options, DecodeFailedException from randovania.interface_common.preset_editor import PresetEditor from randovania.layout.layout_configuration import LayoutConfiguration, LayoutElevators, \ LayoutSkyTempleKeyMode from randovania.layout.starting_location import StartingLocation from randovania.layout.trick_level import LayoutTrickLevel, TrickLevelConfiguration @pytest.fixture(name="editor") def _editor() -> PresetEditor: return PresetEditor(MagicMock()) _sample_layout_configurations = [ { "trick_level_configuration": TrickLevelConfiguration(trick_level), "sky_temple_keys": LayoutSkyTempleKeyMode.default(), "elevators": LayoutElevators.TWO_WAY_RANDOMIZED, } 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 test_edit_layout_trick_level(editor: PresetEditor,