fix: Allow quality group names to duplicate quality names.

Fixes #200
json-serializing-nullable-fields-issue
Robert Dailey 10 months ago
parent e6924c10e4
commit d6fc96f247

@ -16,6 +16,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
### Fixed ### Fixed
- Better error message to console when no configuration files are found. - Better error message to console when no configuration files are found.
- Allow quality group names to duplicate quality names (#200).
## [5.2.0] - 2023-08-06 ## [5.2.0] - 2023-08-06

@ -110,12 +110,6 @@ public class QualityProfileConfigYamlValidator : AbstractValidator<QualityProfil
.When(x => x is {Qualities.Count: > 0}); .When(x => x is {Qualities.Count: > 0});
RuleFor(x => x.Qualities) RuleFor(x => x.Qualities)
.Must((o, x) => !x!
.Where(y => y.Qualities is not null)
.SelectMany(y => y.Qualities!)
.Contains(o.Upgrade!.UntilQuality, StringComparer.InvariantCultureIgnoreCase))
.WithMessage(o =>
$"For profile {o.Name}, 'until_quality' must not refer to qualities contained within groups")
.Must((o, x) => !x! .Must((o, x) => !x!
.Where(y => y is {Enabled: false, Name: not null}) .Where(y => y is {Enabled: false, Name: not null})
.Select(y => y.Name!) .Select(y => y.Name!)
@ -135,20 +129,36 @@ public class QualityProfileConfigYamlValidator : AbstractValidator<QualityProfil
IReadOnlyCollection<QualityProfileQualityConfigYaml> qualities, IReadOnlyCollection<QualityProfileQualityConfigYaml> qualities,
ValidationContext<QualityProfileConfigYaml> context) ValidationContext<QualityProfileConfigYaml> context)
{ {
var dupes = qualities // Check for quality duplicates between non-groups and groups
var qualityDupes = qualities
.Where(x => x.Qualities is null)
.Select(x => x.Name) .Select(x => x.Name)
.Concat(qualities.Where(x => x.Qualities is not null).SelectMany(x => x.Qualities!)) .Concat(qualities.Where(x => x.Qualities is not null).SelectMany(x => x.Qualities!))
.NotNull()
.GroupBy(x => x) .GroupBy(x => x)
.Select(x => x.Skip(1).FirstOrDefault()) .Select(x => x.Skip(1).FirstOrDefault())
.NotNull(); .NotNull();
foreach (var dupe in dupes) foreach (var dupe in qualityDupes)
{ {
var x = context.InstanceToValidate; var x = context.InstanceToValidate;
context.AddFailure( context.AddFailure(
$"For profile {x.Name}, 'qualities' contains duplicates for quality '{dupe}'"); $"For profile {x.Name}, 'qualities' contains duplicates for quality '{dupe}'");
} }
// Check for quality duplicates between non-groups and groups
var groupDupes = qualities
.Where(x => x.Qualities is not null)
.Select(x => x.Name)
.GroupBy(x => x)
.Select(x => x.Skip(1).FirstOrDefault())
.NotNull();
foreach (var dupe in groupDupes)
{
var x = context.InstanceToValidate;
context.AddFailure(
$"For profile {x.Name}, 'qualities' contains duplicates for quality group '{dupe}'");
}
} }
} }

@ -83,36 +83,6 @@ public class ConfigYamlDataObjectsValidationTest
$"which is '{data.Upgrade!.UntilQuality}'"); $"which is '{data.Upgrade!.UntilQuality}'");
} }
[Test]
public void Quality_profile_cutoff_must_not_reference_child_qualities()
{
var data = new QualityProfileConfigYaml
{
Name = "My QP",
Upgrade = new QualityProfileFormatUpgradeYaml
{
Allowed = true,
UntilQuality = "Child Quality"
},
Qualities = new[]
{
new QualityProfileQualityConfigYaml
{
Name = "Parent Group",
Qualities = new[] {"Child 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}, 'until_quality' must not refer to qualities contained within groups");
}
[Test] [Test]
public void Quality_profile_qualities_must_have_no_duplicates() public void Quality_profile_qualities_must_have_no_duplicates()
{ {
@ -125,13 +95,21 @@ public class ConfigYamlDataObjectsValidationTest
new QualityProfileQualityConfigYaml {Name = "Dupe Quality"}, 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 2"},
new QualityProfileQualityConfigYaml {Name = "Dupe Quality 2"},
new QualityProfileQualityConfigYaml {Name = "Dupe Quality 3"}, new QualityProfileQualityConfigYaml {Name = "Dupe Quality 3"},
new QualityProfileQualityConfigYaml {Name = "Dupe Quality 4"},
new QualityProfileQualityConfigYaml new QualityProfileQualityConfigYaml
{ {
Name = "Dupe Quality 3", Name = "Dupe Quality 2",
Qualities = new[] {"Dupe Quality 4"} Qualities = new[] {"Dupe Quality 3"}
},
new QualityProfileQualityConfigYaml
{
Name = "Dupe Quality 4",
Qualities = new[] {"Dupe Quality 5"}
},
new QualityProfileQualityConfigYaml
{
Name = "Dupe Quality 4",
Qualities = new[] {"Dupe Quality 5"}
} }
} }
}; };
@ -143,9 +121,9 @@ public class ConfigYamlDataObjectsValidationTest
result.Errors.Select(x => x.ErrorMessage).Should().BeEquivalentTo( 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'",
$"For profile {data.Name}, 'qualities' contains duplicates for quality 'Dupe Quality 2'",
$"For profile {data.Name}, 'qualities' contains duplicates for quality 'Dupe Quality 3'", $"For profile {data.Name}, 'qualities' contains duplicates for quality 'Dupe Quality 3'",
$"For profile {data.Name}, 'qualities' contains duplicates for quality 'Dupe Quality 4'"); $"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] [Test]

Loading…
Cancel
Save