Example #1
0
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)
Example #2
0
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]),
    ])
Example #3
0
    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),
            })
Example #4
0
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")
Example #5
0
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()
Example #6
0
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")
Example #9
0
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),
            }
        )
Example #11
0
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'>"
    )
Example #12
0
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)
Example #13
0
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)
Example #14
0
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
Example #16
0
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)
Example #17
0
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)
Example #18
0
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()
Example #19
0
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()
Example #20
0
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"
Example #21
0
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()
Example #23
0
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
Example #24
0
    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),
            })
Example #25
0
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()
Example #26
0
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)
Example #27
0
def test_serialize_fields(option: Options):
    # Setup

    # Run
    result = option._serialize_fields()

    # Assert
    assert result == {"version": 6, "options": {}}
Example #28
0
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()
Example #29
0
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)
Example #30
0
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()))