using FluentValidation.TestHelper; using Recyclarr.Config.Parsing; namespace Recyclarr.Tests.Config.Parsing; [TestFixture] public class ConfigYamlDataObjectsValidationTest { [Test] public void Quality_profile_format_upgrade_allowed_required() { var data = new QualityProfileConfigYaml { Name = "My QP", Upgrade = new QualityProfileFormatUpgradeYaml(), }; var validator = new QualityProfileFormatUpgradeYamlValidator(data); var result = validator.TestValidate(data.Upgrade); result .ShouldHaveValidationErrorFor(x => x.Allowed) .WithErrorMessage( $"For profile {data.Name}, 'allowed' under 'upgrade' is required. " + $"If you don't want Recyclarr to manage upgrades, delete the whole 'upgrade' block." ); } [Test] public void Quality_profile_format_upgrade_until_quality_required() { var data = new QualityProfileConfigYaml { Name = "My QP", Upgrade = new QualityProfileFormatUpgradeYaml { Allowed = true }, Qualities = new List(), }; var validator = new QualityProfileFormatUpgradeYamlValidator(data); var result = validator.TestValidate(data.Upgrade); result .ShouldHaveValidationErrorFor(x => x.UntilQuality) .WithErrorMessage( $"For profile {data.Name}, 'until_quality' is required when 'allowed' is set to 'true' and " + $"an explicit 'qualities' list is provided." ); } [Test] public void Quality_profile_name_required() { var data = new QualityProfileConfigYaml(); var validator = new QualityProfileConfigYamlValidator(); var result = validator.TestValidate(data); result.ShouldHaveValidationErrorFor(x => x.Name); } [Test] public void Quality_profile_qualities_must_have_cutoff_quality() { var data = new QualityProfileConfigYaml { Name = "My QP", Upgrade = new QualityProfileFormatUpgradeYaml { Allowed = true, UntilQuality = "Test Quality", }, Qualities = [new QualityProfileQualityConfigYaml { Name = "Another Quality" }], }; var validator = new QualityProfileConfigYamlValidator(); var result = validator.TestValidate(data); result.ShouldHaveValidationErrorFor(x => x.Qualities); result .Errors.Select(x => x.ErrorMessage) .Should() .BeEquivalentTo( $"For profile {data.Name}, 'qualities' must contain the quality mentioned in 'until_quality', " + $"which is '{data.Upgrade!.UntilQuality}'" ); } [Test] public void Quality_profile_qualities_must_have_no_duplicates() { var data = new QualityProfileConfigYaml { Name = "My QP", Qualities = [ new QualityProfileQualityConfigYaml { Name = "Dupe Quality" }, new QualityProfileQualityConfigYaml { Name = "Dupe Quality" }, new QualityProfileQualityConfigYaml { Name = "Dupe Quality" }, new QualityProfileQualityConfigYaml { Name = "Dupe Quality 2" }, new QualityProfileQualityConfigYaml { Name = "Dupe Quality 3" }, new QualityProfileQualityConfigYaml { Name = "Dupe Quality 2", Qualities = ["Dupe Quality 3"], }, new QualityProfileQualityConfigYaml { Name = "Dupe Quality 4", Qualities = ["Dupe Quality 5"], }, new QualityProfileQualityConfigYaml { Name = "Dupe Quality 4", Qualities = ["Dupe Quality 5"], }, ], }; var validator = new QualityProfileConfigYamlValidator(); var result = validator.TestValidate(data); result.ShouldHaveValidationErrorFor(x => x.Qualities); result .Errors.Select(x => x.ErrorMessage) .Should() .BeEquivalentTo( $"For profile {data.Name}, 'qualities' contains duplicates for quality 'Dupe Quality'", $"For profile {data.Name}, 'qualities' contains duplicates for quality 'Dupe Quality 3'", $"For profile {data.Name}, 'qualities' contains duplicates for quality group 'Dupe Quality 4'", $"For profile {data.Name}, 'qualities' contains duplicates for quality 'Dupe Quality 5'" ); } [Test] public void Quality_profile_qualities_must_have_at_least_one_enabled() { var data = new QualityProfileConfigYaml { Name = "My QP", Qualities = [ new QualityProfileQualityConfigYaml { Name = "Quality 1", Enabled = false }, new QualityProfileQualityConfigYaml { Name = "Quality 2", Enabled = false }, ], }; var validator = new QualityProfileConfigYamlValidator(); var result = validator.TestValidate(data); result.ShouldHaveValidationErrorFor(x => x.Qualities); result .Errors.Select(x => x.ErrorMessage) .Should() .BeEquivalentTo( $"For profile {data.Name}, at least one explicitly listed quality under 'qualities' must be enabled." ); } [Test] public void Quality_profile_cutoff_quality_should_not_refer_to_disabled_qualities() { var data = new QualityProfileConfigYaml { Name = "My QP", Upgrade = new QualityProfileFormatUpgradeYaml { Allowed = true, UntilQuality = "Disabled Quality", }, Qualities = [ new QualityProfileQualityConfigYaml { Name = "Enabled Quality" }, new QualityProfileQualityConfigYaml { Name = "Disabled Quality", Enabled = false }, ], }; var validator = new QualityProfileConfigYamlValidator(); var result = validator.TestValidate(data); result.ShouldHaveValidationErrorFor(x => x.Qualities); result .Errors.Select(x => x.ErrorMessage) .Should() .BeEquivalentTo( $"For profile {data.Name}, 'until_quality' must not refer to explicitly disabled qualities" ); } [Test] public void Empty_qualities_in_groups_not_allowed() { var data = new QualityProfileConfigYaml { Name = "Profile", Qualities = [ new QualityProfileQualityConfigYaml { Name = "Group", Qualities = Array.Empty(), }, ], }; var validator = new QualityProfileConfigYamlValidator(); var result = validator.TestValidate(data); result.ShouldHaveValidationErrorFor(x => x.Qualities); result .Errors.Select(x => x.ErrorMessage) .Should() .BeEquivalentTo( $"For profile {data.Name}, 'qualities' contains 1 groups with less than 2 qualities" ); } [Test] public void Only_one_quality_in_groups_not_allowed() { var data = new QualityProfileConfigYaml { Name = "Profile", Qualities = [ new QualityProfileQualityConfigYaml { Name = "Group", Qualities = ["One Quality"] }, ], }; var validator = new QualityProfileConfigYamlValidator(); var result = validator.TestValidate(data); result.ShouldHaveValidationErrorFor(x => x.Qualities); result .Errors.Select(x => x.ErrorMessage) .Should() .BeEquivalentTo( $"For profile {data.Name}, 'qualities' contains 1 groups with less than 2 qualities" ); } [Test] public void Two_qualities_in_group_passes_validation() { var data = new QualityProfileConfigYaml { Name = "Profile", Qualities = [ new QualityProfileQualityConfigYaml { Name = "Group", Qualities = ["One Quality", "Two Quality"], }, ], }; var validator = new QualityProfileConfigYamlValidator(); var result = validator.TestValidate(data); result.ShouldNotHaveAnyValidationErrors(); } }