def test_load_from_disk_with_data( mock_read_persisted_options: MagicMock, mock_get_persisted_options_from_data: MagicMock, mock_set_field: MagicMock, fields_to_test: List[str], option: Options): # Setup persisted_options = { field_name: MagicMock() for field_name in fields_to_test } new_serializers = { field_name: MagicMock() for field_name in fields_to_test } mock_get_persisted_options_from_data.return_value = persisted_options # Run with patch.dict(randovania.interface_common.options._SERIALIZER_FOR_FIELD, new_serializers): option.load_from_disk() # Assert mock_read_persisted_options.assert_called_once_with(option) mock_get_persisted_options_from_data.assert_called_once_with( mock_read_persisted_options.return_value) for field_name, serializer in new_serializers.items(): serializer.decode.assert_called_once_with( persisted_options[field_name]) mock_set_field.assert_has_calls( call(option, field_name, new_serializers[field_name].decode.return_value) for field_name in fields_to_test)
def test_load_from_disk_first_failure(tmp_path, mocker): persisted_result = MagicMock() mocker.patch( "randovania.interface_common.persisted_options.find_config_files", autospec=True, return_value=[ "[1]", "[2]", ]) mock_get_persisted_options_from_data = mocker.patch( "randovania.interface_common.persisted_options.get_persisted_options_from_data", autospec=True, side_effect=[ migration_lib.UnsupportedVersion(), persisted_result, ]) option = Options(tmp_path) option.load_from_persisted = MagicMock() # Run result = option.load_from_disk(True) # Assert assert result option.load_from_persisted.assert_called_once_with(persisted_result, True) mock_get_persisted_options_from_data.assert_has_calls([ call([1]), call([2]), ])
def __init__(self, options: Options, patch_data: dict, word_hash: str, spoiler: bool, games: list[RandovaniaGame]): super().__init__(options, patch_data, word_hash, spoiler, games) self._base_output_name = f"Prime Randomizer - {word_hash}" per_game = options.options_for_game(self._game) assert isinstance(per_game, PrimePerGameOptions) # Input self.input_file_button.clicked.connect(self._on_input_file_button) # Output self.output_file_button.clicked.connect(self._on_output_file_button) # Output format self.setup_multi_format(per_game.output_format) # Echoes input self.echoes_file_button.clicked.connect(self._on_echoes_file_button) # Echoes ISO input if RandovaniaGame.METROID_PRIME_ECHOES in games: self._use_echoes_models = RandovaniaGame.METROID_PRIME_ECHOES in per_game.use_external_models self.echoes_models_check.setChecked(self._use_echoes_models) self._on_echoes_models_check() self.echoes_models_check.clicked.connect( self._on_echoes_models_check) echoes_options = options.options_for_game( RandovaniaGame.METROID_PRIME_ECHOES) assert isinstance(echoes_options, EchoesPerGameOptions) if echoes_options.input_path is not None: self.echoes_file_edit.setText(str(echoes_options.input_path)) else: self._use_echoes_models = False self.echoes_models_check.hide() self.echoes_file_edit.hide() self.echoes_file_label.hide() self.echoes_file_button.hide() if per_game.input_path is not None: self.input_file_edit.setText(str(per_game.input_path)) if per_game.output_directory is not None: output_path = per_game.output_directory.joinpath( self.default_output_name) self.output_file_edit.setText(str(output_path)) add_field_validation( accept_button=self.accept_button, fields={ self.input_file_edit: lambda: is_file_validator(self.input_file), self.output_file_edit: lambda: output_file_validator(self.output_file), self.echoes_file_edit: lambda: self._use_echoes_models and is_file_validator( self.echoes_file), })
def test_save_options(skip_qtbot, tmp_path, is_prime_multi): options = Options(tmp_path) games = [RandovaniaGame.METROID_PRIME] if is_prime_multi: games.append(RandovaniaGame.METROID_PRIME_ECHOES) window = PrimeGameExportDialog(options, {}, "MyHash", True, games) window.output_file_edit.setText("somewhere/game.iso") if is_prime_multi: skip_qtbot.mouseClick(window.echoes_models_check, QtCore.Qt.LeftButton) window.echoes_file_edit.setText("somewhere/echoes.iso") # Run window.save_options() # Assert assert options.options_for_game( RandovaniaGame.METROID_PRIME).output_directory == Path("somewhere") if is_prime_multi: assert options.options_for_game( RandovaniaGame.METROID_PRIME).use_external_models == { RandovaniaGame.METROID_PRIME_ECHOES } assert options.options_for_game( RandovaniaGame.METROID_PRIME_ECHOES).input_path == Path( "somewhere/echoes.iso")
def test_load_from_disk_no_data( mock_read_persisted_options: MagicMock, mock_get_persisted_options_from_data: MagicMock, option: Options): # Run option.load_from_disk() # Assert mock_read_persisted_options.assert_called_once_with(option) mock_get_persisted_options_from_data.assert_not_called()
def test_load_from_disk_missing_json(ignore_decode_errors: bool, tmpdir): # Setup option = Options(Path(tmpdir)) tmpdir.join("config.json").write_text("", "utf-8") if ignore_decode_errors: result = option.load_from_disk(ignore_decode_errors) assert result != ignore_decode_errors else: with pytest.raises(DecodeFailedException): option.load_from_disk(ignore_decode_errors)
def test_save_options(skip_qtbot, tmp_path): options = Options(tmp_path) window = SuperMetroidGameExportDialog(options, {}, "MyHash", True, []) window.output_file_edit.setText("somewhere/game.smc") # Run window.save_options() # Assert assert options.options_for_game( RandovaniaGame.SUPER_METROID).output_directory == Path("somewhere")
def test_save_options(skip_qtbot, tmp_path): options = Options(tmp_path) window = CSGameExportDialog(options, {}, "MyHash", True, []) window.output_file_edit.setText("somewhere/foo") # Run window.save_options() # Assert assert options.options_for_game( RandovaniaGame.CAVE_STORY).output_directory == Path("somewhere/foo")
def test_load_from_disk_no_data(tmp_path, mocker): # Setup mock_get_persisted_options_from_data: MagicMock = mocker.patch( "randovania.interface_common.persisted_options.get_persisted_options_from_data", autospec=True) option = Options(tmp_path) # Run option.load_from_disk() # Assert mock_get_persisted_options_from_data.assert_not_called()
def __init__(self, options: Options, patch_data: dict, word_hash: str, spoiler: bool, games: list[RandovaniaGame]): super().__init__(options, patch_data, word_hash, spoiler, games) self.default_output_name = f"Echoes Randomizer - {word_hash}" self._prompt_input_file = check_extracted_game(self.input_file_edit, self.input_file_button, self._contents_file_path) per_game = options.options_for_game(self._game) assert isinstance(per_game, EchoesPerGameOptions) # Input self.input_file_button.clicked.connect(self._on_input_file_button) # Output self.output_file_button.clicked.connect(self._on_output_file_button) # Prime input self.prime_file_button.clicked.connect(self._on_prime_file_button) if RandovaniaGame.METROID_PRIME in games: self._use_prime_models = RandovaniaGame.METROID_PRIME in per_game.use_external_models self.prime_models_check.setChecked(self._use_prime_models) self._on_prime_models_check() self.prime_models_check.clicked.connect(self._on_prime_models_check) prime_options = options.options_for_game(RandovaniaGame.METROID_PRIME) assert isinstance(prime_options, PrimePerGameOptions) if prime_options.input_path is not None: self.prime_file_edit.setText(str(prime_options.input_path)) else: self._use_prime_models = False self.prime_models_check.hide() self.prime_file_edit.hide() self.prime_file_label.hide() self.prime_file_button.hide() if self._prompt_input_file and per_game.input_path is not None: self.input_file_edit.setText(str(per_game.input_path)) if per_game.output_directory is not None: output_path = per_game.output_directory.joinpath(f"{self.default_output_name}.iso") self.output_file_edit.setText(str(output_path)) add_field_validation( accept_button=self.accept_button, fields={ self.input_file_edit: lambda: echoes_input_validator(self.input_file, self._prompt_input_file, self.input_file_edit), self.output_file_edit: lambda: output_file_validator(self.output_file), self.prime_file_edit: lambda: self._use_prime_models and is_file_validator(self.prime_file), } )
def test_set_options_for_game_with_wrong_type(option: Options): # Run with pytest.raises(ValueError) as exception: option.set_options_for_game(RandovaniaGame.METROID_PRIME, EchoesPerGameOptions( cosmetic_patches=RandovaniaGame.METROID_PRIME_ECHOES.data.layout.cosmetic_patches.default(), )) # Assert assert str(exception.value) == ( "Expected <class 'randovania.games.prime1.exporter.options.PrimePerGameOptions'>, " "got <class 'randovania.games.prime2.exporter.options.EchoesPerGameOptions'>" )
def test_edit_layout_quantity(option: Options, initial_layout_configuration_params: dict): # Setup option._layout_configuration = LayoutConfiguration.from_params(**initial_layout_configuration_params) option._nested_autosave_level = 1 pickup = next(option._layout_configuration.pickup_quantities.pickups()) # Run initial_layout_configuration_params["pickup_quantities"] = {pickup.name: 12} option.set_quantity_for_pickup(pickup, 12) # Assert assert option.layout_configuration == LayoutConfiguration.from_params(**initial_layout_configuration_params)
def test_single_save_with_nested_context_manager(mock_save_to_disk: MagicMock, option: Options): # Setup option._dark_mode = False # Run with option: option.dark_mode = True with option: pass # Assert mock_save_to_disk.assert_called_once_with(option)
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"] = new_trick_level setattr(option, "layout_configuration_trick_level", new_trick_level) # Assert assert option.layout_configuration == LayoutConfiguration.from_params(**initial_layout_configuration_params)
def test_save_options(skip_qtbot, tmp_path): options = Options(tmp_path) window = DreadGameExportDialog(options, {}, "MyHash", True, []) window.atmosphere_radio.setChecked(True) # Run window.save_options() # Assert game_options = options.options_for_game(RandovaniaGame.METROID_DREAD) assert isinstance(game_options, DreadPerGameOptions) assert game_options.target_platform == DreadModPlatform.ATMOSPHERE
def test_single_save_with_nested_context_manager(mock_save_to_disk: MagicMock, option: Options): # Setup option._output_directory = Path("start") # Run with option: option.output_directory = Path("end") with option: pass # Assert mock_save_to_disk.assert_called_once_with(option)
def test_mark_alert_as_displayed(tmp_path): opt = Options(tmp_path) all_alerts = (InfoAlert.FAQ, InfoAlert.MULTIWORLD_FAQ) for alert in all_alerts: assert not opt.is_alert_displayed(alert) opt.mark_alert_as_displayed(alert) assert opt.is_alert_displayed(alert) assert opt.displayed_alerts == set(all_alerts) new_opt = Options(tmp_path) new_opt.load_from_disk() assert new_opt.displayed_alerts == set(all_alerts)
def test_save_with_context_manager(mock_save_to_disk: MagicMock, option: Options): # Setup settings_changed = MagicMock() option._dark_mode = False option.on_options_changed = settings_changed # Run with option: option.dark_mode = True # Assert mock_save_to_disk.assert_called_once_with(option) settings_changed.assert_called_once_with()
def test_save_with_context_manager(mock_save_to_disk: MagicMock, option: Options): # Setup settings_changed = MagicMock() option._output_directory = Path("start") option.on_options_changed = settings_changed # Run with option: option.output_directory = Path("end") # Assert mock_save_to_disk.assert_called_once_with(option) settings_changed.assert_called_once_with()
def test_changing_field_without_context_manager_should_error(option: Options): # Run with pytest.raises(AssertionError) as exception: option.dark_mode = True # Assert assert str(exception.value) == "Attempting to edit an Options, but it wasn't made editable"
def test_changing_field_without_context_manager_should_error(option: Options): # Run with pytest.raises(AssertionError) as exception: option.output_directory = Path("start") # Assert assert str(exception.value) == "Attempting to edit an Options, but it wasn't made editable"
def test_delete_files_location( tmpdir, games_path_exist: bool, backup_path_exist: bool, ): # Setup data_dir = Path(str(tmpdir.join("user_data_dir"))) options = Options(data_dir) game_files = tmpdir.join("user_data_dir", "extracted_game") if games_path_exist: game_files.ensure_dir() game_files.join("random.txt").write_text("yay", "utf-8") backup_files = tmpdir.join("user_data_dir", "backup") if backup_path_exist: backup_files.ensure_dir() backup_files.join("random.txt").write_text("yay", "utf-8") # Run simplified_patcher.delete_files_location(options) # Assert assert not game_files.exists() assert not backup_files.exists()
def _load_options(): logger.info("Loading up user preferences code...") from randovania.interface_common.options import Options from randovania.gui.lib import startup_tools, theme logger.info("Restoring saved user preferences...") options = Options.with_default_data_dir() if not startup_tools.load_options_from_disk(options): raise SystemExit(1) logger.info("Creating user preferences folder") import dulwich.repo import dulwich.errors try: dulwich.repo.Repo(options.user_dir) except dulwich.errors.NotGitRepository: options.user_dir.mkdir(parents=True, exist_ok=True) dulwich.repo.Repo.init(options.user_dir) theme.set_dark_theme(options.dark_mode) from randovania.layout.preset_migration import VersionedPreset for old_preset in options.data_dir.joinpath("presets").glob( "*.randovania_preset"): old_preset.rename( old_preset.with_name( f"{old_preset.stem}.{VersionedPreset.file_extension()}")) logger.info("Loaded user preferences") return options
def __init__(self, options: Options, patch_data: dict, word_hash: str, spoiler: bool, games: list[RandovaniaGame]): super().__init__(options, patch_data, word_hash, spoiler, games) self._base_output_name = f"SM Randomizer - {word_hash}" per_game = options.options_for_game(self._game) assert isinstance(per_game, SuperMetroidPerGameOptions) # Input self.input_file_button.clicked.connect(self._on_input_file_button) # Output self.output_file_button.clicked.connect(self._on_output_file_button) # Output format self.setup_multi_format(per_game.output_format) if per_game.input_path is not None: self.input_file_edit.setText(str(per_game.input_path)) if per_game.output_directory is not None: output_path = per_game.output_directory.joinpath( self.default_output_name) self.output_file_edit.setText(str(output_path)) add_field_validation( accept_button=self.accept_button, fields={ self.input_file_edit: lambda: not self.input_file.is_file(), self.output_file_edit: lambda: output_file_validator(self.output_file), })
def show_main_window(app: QApplication, args): options = Options.with_default_data_dir() options.load_from_disk() from randovania.gui.main_window import MainWindow main_window = MainWindow(options, getattr(args, "preview", False)) app.main_window = main_window main_window.show()
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_serialize_fields(option: Options): # Setup # Run result = option._serialize_fields() # Assert assert result == {"version": 6, "options": {}}
def show_tracker(app: QApplication, args): from randovania.gui.tracker_window import TrackerWindow options = Options.with_default_data_dir() options.load_from_disk() app.tracker = TrackerWindow(options.layout_configuration) app.tracker.show()
def test_load_from_disk_invalid_json(ignore_decode_errors: bool, tmpdir): # Setup option = Options(Path(tmpdir)) tmpdir.join("config.json").write_text( json.dumps( randovania.interface_common.persisted_options. serialized_data_for_options( {"cosmetic_patches": { "pickup_model_style": "invalid-value" }})), "utf-8") if ignore_decode_errors: result = option.load_from_disk(ignore_decode_errors) assert result != ignore_decode_errors else: with pytest.raises(DecodeFailedException): option.load_from_disk(ignore_decode_errors)
def _default_online_interactions(skip_qtbot, preset_manager) -> OnlineInteractions: main_window = MagicMock() parent = QtWidgets.QWidget() skip_qtbot.add_widget(parent) return OnlineInteractions(parent, preset_manager, MagicMock(), main_window, Options(MagicMock()))