From 84dd2d068317998f6fb59400c534ef5be6b51b53 Mon Sep 17 00:00:00 2001 From: historia Date: Mon, 7 Sep 2026 06:47:47 -0400 Subject: slop rewrite --- lib/project/tests/test_config.py | 134 +++++++++++++++++++++++++++++++++++++++ 1 file changed, 134 insertions(+) create mode 100644 lib/project/tests/test_config.py (limited to 'lib/project/tests/test_config.py') diff --git a/lib/project/tests/test_config.py b/lib/project/tests/test_config.py new file mode 100644 index 0000000..8144fc8 --- /dev/null +++ b/lib/project/tests/test_config.py @@ -0,0 +1,134 @@ +from dataclasses import asdict, fields + +import pytest + +from voiceforge.cli import main, parser, settings_for +from voiceforge.config import PROFILES, RANGES, Settings, resolve, toml +from voiceforge.pipeline import filters + + +@pytest.mark.parametrize("profile", PROFILES) +def test_profiles_and_toml_round_trip(profile, tmp_path): + settings = resolve(profile=profile) + assert asdict(settings) == asdict(Settings()) | PROFILES[profile] | {"profile": profile} + path = tmp_path / "settings.toml" + path.write_text(toml(settings)) + assert resolve(path) == settings + + +def test_precedence_defaults_profile_file_flags_then_set(tmp_path): + path = tmp_path / "settings.toml" + path.write_text('profile = "narrator"\ncompressor_ratio = 2.2\nwarmth_db = 3\n') + args = parser().parse_args([ + "config", "--config", str(path), "--profile", "radio", + "--warmth-db", "4", "--set", "warmth_db=5", "--set", "warmth_db=6", + ]) + settings = settings_for(args) + assert settings.profile == "radio" + assert settings.compressor_attack_ms == 8 # Selected profile beats file profile. + assert settings.compressor_ratio == 2.2 # File values beat profile defaults. + assert settings.warmth_db == 6 # Last --set beats named flags. + assert settings.sample_rate == 48000 + + +@pytest.mark.parametrize("field", [f.name for f in fields(Settings) if type(getattr(Settings(), f.name)) is bool]) +def test_boolean_flags_preserve_unspecified_and_accept_both_forms(field): + assert getattr(parser().parse_args(["config"]), field) is None + for enabled in (True, False): + flag = "--" + ("" if enabled else "no-") + field.replace("_", "-") + extra = ["--limiter"] if field == "normalize" and enabled else [] + args = parser().parse_args(["config", "--profile", "cleanup-only", flag, *extra]) + assert getattr(settings_for(args), field) is enabled + + +def test_false_cli_toggle_overrides_true_file_value(tmp_path): + path = tmp_path / "settings.toml" + path.write_text("eq = true\n") + args = parser().parse_args(["config", "--config", str(path), "--no-eq"]) + assert settings_for(args).eq is False + + +def test_no_denoise_and_unquoted_set_strings(): + assert settings_for(parser().parse_args(["config", "--no-denoise"])).denoiser == "none" + args = parser().parse_args(["config", "--no-denoise", "--set", "denoiser=fft"]) + assert settings_for(args).denoiser == "fft" + + +@pytest.mark.parametrize("key", RANGES) +def test_numeric_ranges_are_inclusive_and_reject_outside(key): + low, high = RANGES[key] + for value in (low, high): + assert getattr(resolve(overrides={key: value}), key) == value + for value in (low - 0.01, high + 0.01): + with pytest.raises(ValueError, match=key): + resolve(overrides={key: value}) + + +@pytest.mark.parametrize("overrides,match", [ + ({"typo": True}, "Unknown setting"), + ({"highpass": 1}, "highpass must be bool"), + ({"sample_rate": 48000.0}, "sample_rate must be int"), + ({"target_lufs": True}, "finite number"), + ({"target_lufs": float("nan")}, "finite number"), + ({"target_lufs": float("inf")}, "finite number"), + ({"denoiser": "unknown"}, "denoiser must be one of"), + ({"device": "gpu"}, "device must be one of"), + ({"channel": "stereo"}, "channel must be one of"), + ({"hum_hz": 55}, "hum_hz must be one of"), + ({"sample_rate": 96000}, "sample_rate must be one of"), + ({"mp3_bitrate": 64}, "mp3_bitrate must be one of"), + ({"limiter": False}, "Normalization includes true-peak limiting"), +]) +def test_invalid_configuration(overrides, match): + with pytest.raises(ValueError, match=match): + resolve(overrides=overrides) + + +def test_unknown_profile_and_malformed_toml(tmp_path): + with pytest.raises(ValueError, match="Unknown profile"): + resolve(profile="missing") + path = tmp_path / "bad.toml" + path.write_text("normalize = [") + with pytest.raises(ValueError): + resolve(path) + + +def test_invalid_cli_configuration_fails_before_processing(monkeypatch, capsys): + def unexpected(*args, **kwargs): + pytest.fail("Invalid configuration must not reach processing or tool setup") + + monkeypatch.setattr("voiceforge.cli.process", unexpected) + monkeypatch.setattr("voiceforge.cli.ensure_ffmpeg", unexpected) + monkeypatch.setattr("sys.argv", ["voiceforge", "process", "missing.wav", "--target-lufs", "0"]) + with pytest.raises(SystemExit) as error: + main() + assert error.value.code == 1 + assert "target_lufs must be between" in capsys.readouterr().err + + +def test_set_requires_assignment(): + with pytest.raises(ValueError, match="KEY=VALUE"): + settings_for(parser().parse_args(["config", "--set", "normalize"])) + + +@pytest.mark.parametrize("profile", ["radio", "not-a-profile"]) +def test_set_profile_uses_normal_profile_resolution(profile): + args = parser().parse_args(["config", "--set", f"profile={profile}"]) + if profile not in PROFILES: + with pytest.raises(ValueError, match="Unknown profile"): + settings_for(args) + else: + assert settings_for(args) == resolve(profile=profile) + + +@pytest.mark.parametrize("toggle,prefix,count", [ + ("expansion", "agate=", 1), ("eq", "equalizer=", 3), + ("compression", "acompressor=", 1), ("deess", "deesser=", 1), + ("lowpass", "lowpass=", 1), +]) +def test_shaping_filter_toggles(bypass, toggle, prefix, count): + assert filters(bypass) == ["anull"] + setattr(bypass, toggle, True) + chain = filters(bypass) + assert len(chain) == count + assert all(item.startswith(prefix) for item in chain) -- cgit v1.2.3