If there is invalid / empty data in the Trash Guide JSON data, filter those out after they are loaded.pull/108/head
parent
bf61ab0fac
commit
1129f178a8
@ -0,0 +1,79 @@
|
||||
using FluentAssertions;
|
||||
using NUnit.Framework;
|
||||
using TestLibrary.AutoFixture;
|
||||
using TrashLib.Sonarr.ReleaseProfile;
|
||||
using TrashLib.Sonarr.ReleaseProfile.Filters;
|
||||
|
||||
namespace TrashLib.Tests.Sonarr.ReleaseProfile.Filters;
|
||||
|
||||
[TestFixture]
|
||||
[Parallelizable(ParallelScope.All)]
|
||||
public class ReleaseProfileDataValidationFiltererTest
|
||||
{
|
||||
[Test, AutoMockData]
|
||||
public void Valid_data_is_not_filtered_out(ReleaseProfileDataValidationFilterer sut)
|
||||
{
|
||||
var data = new[]
|
||||
{
|
||||
new ReleaseProfileData
|
||||
{
|
||||
TrashId = "trash_id",
|
||||
Name = "name",
|
||||
Required = new[] {new TermData {Term = "term1"}},
|
||||
Ignored = new[] {new TermData {Term = "term2"}},
|
||||
Preferred = new[] {new PreferredTermData {Terms = new[] {new TermData {Term = "term3"}}}}
|
||||
}
|
||||
};
|
||||
|
||||
var result = sut.FilterProfiles(data);
|
||||
|
||||
result.Should().BeEquivalentTo(data);
|
||||
}
|
||||
|
||||
[Test, AutoMockData]
|
||||
public void Invalid_terms_are_filtered_out(ReleaseProfileDataValidationFilterer sut)
|
||||
{
|
||||
var data = new[]
|
||||
{
|
||||
new ReleaseProfileData
|
||||
{
|
||||
TrashId = "trash_id",
|
||||
Name = "name",
|
||||
Required = new[] {new TermData {Term = ""}},
|
||||
Ignored = new[] {new TermData {Term = "term2"}},
|
||||
Preferred = new[] {new PreferredTermData {Terms = new[] {new TermData {Term = "term3"}}}}
|
||||
}
|
||||
};
|
||||
|
||||
var result = sut.FilterProfiles(data);
|
||||
|
||||
result.Should().ContainSingle().Which.Should().BeEquivalentTo(new ReleaseProfileData
|
||||
{
|
||||
TrashId = "trash_id",
|
||||
Name = "name",
|
||||
Required = Array.Empty<TermData>(),
|
||||
Ignored = new[] {new TermData {Term = "term2"}},
|
||||
Preferred = new[] {new PreferredTermData {Terms = new[] {new TermData {Term = "term3"}}}}
|
||||
});
|
||||
}
|
||||
|
||||
[Test, AutoMockData]
|
||||
public void Whole_release_profile_filtered_out_if_all_terms_invalid(ReleaseProfileDataValidationFilterer sut)
|
||||
{
|
||||
var data = new[]
|
||||
{
|
||||
new ReleaseProfileData
|
||||
{
|
||||
TrashId = "trash_id",
|
||||
Name = "name",
|
||||
Required = new[] {new TermData {Term = ""}},
|
||||
Ignored = new[] {new TermData {Term = ""}},
|
||||
Preferred = new[] {new PreferredTermData {Terms = new[] {new TermData {Term = ""}}}}
|
||||
}
|
||||
};
|
||||
|
||||
var result = sut.FilterProfiles(data);
|
||||
|
||||
result.Should().BeEmpty();
|
||||
}
|
||||
}
|
@ -1,69 +1,58 @@
|
||||
using System.Collections.ObjectModel;
|
||||
using Common.FluentValidation;
|
||||
using FluentValidation.Results;
|
||||
using Serilog;
|
||||
using TrashLib.Sonarr.Config;
|
||||
|
||||
namespace TrashLib.Sonarr.ReleaseProfile;
|
||||
namespace TrashLib.Sonarr.ReleaseProfile.Filters;
|
||||
|
||||
public class ReleaseProfileDataFilterer
|
||||
{
|
||||
private readonly ILogger _log;
|
||||
private readonly ReleaseProfileDataValidationFilterer _validator;
|
||||
|
||||
public ReleaseProfileDataFilterer(ILogger log)
|
||||
{
|
||||
_log = log;
|
||||
}
|
||||
|
||||
private void LogInvalidTerm(List<ValidationFailure> failures, string filterDescription)
|
||||
{
|
||||
_log.Debug("Validation failed on term data ({Filter}): {Failures}", filterDescription, failures);
|
||||
_validator = new ReleaseProfileDataValidationFilterer(log);
|
||||
}
|
||||
|
||||
public ReadOnlyCollection<TermData> ExcludeTerms(IEnumerable<TermData> terms,
|
||||
IEnumerable<string> excludeFilter)
|
||||
{
|
||||
return terms
|
||||
.Where(x => !excludeFilter.Contains(x.TrashId, StringComparer.InvariantCultureIgnoreCase))
|
||||
.IsValid(new TermDataValidator(), (e, x) => LogInvalidTerm(e, $"Exclude: {x}"))
|
||||
.ToList().AsReadOnly();
|
||||
var result = terms.Where(x => !excludeFilter.Contains(x.TrashId, StringComparer.InvariantCultureIgnoreCase));
|
||||
return _validator.FilterTerms(result).ToList().AsReadOnly();
|
||||
}
|
||||
|
||||
public ReadOnlyCollection<PreferredTermData> ExcludeTerms(IEnumerable<PreferredTermData> terms,
|
||||
IReadOnlyCollection<string> excludeFilter)
|
||||
{
|
||||
return terms
|
||||
var result = terms
|
||||
.Select(x => new PreferredTermData
|
||||
{
|
||||
Score = x.Score,
|
||||
Terms = ExcludeTerms(x.Terms, excludeFilter)
|
||||
})
|
||||
.IsValid(new PreferredTermDataValidator(), (e, x) => LogInvalidTerm(e, $"Exclude Preferred: {x}"))
|
||||
.ToList()
|
||||
.AsReadOnly();
|
||||
});
|
||||
|
||||
return _validator.FilterTerms(result).ToList().AsReadOnly();
|
||||
}
|
||||
|
||||
public ReadOnlyCollection<TermData> IncludeTerms(IEnumerable<TermData> terms,
|
||||
IEnumerable<string> includeFilter)
|
||||
{
|
||||
return terms
|
||||
.Where(x => includeFilter.Contains(x.TrashId, StringComparer.InvariantCultureIgnoreCase))
|
||||
.IsValid(new TermDataValidator(), (e, x) => LogInvalidTerm(e, $"Include: {x}"))
|
||||
.ToList().AsReadOnly();
|
||||
var result = terms.Where(x => includeFilter.Contains(x.TrashId, StringComparer.InvariantCultureIgnoreCase));
|
||||
return _validator.FilterTerms(result).ToList().AsReadOnly();
|
||||
}
|
||||
|
||||
public ReadOnlyCollection<PreferredTermData> IncludeTerms(IEnumerable<PreferredTermData> terms,
|
||||
IReadOnlyCollection<string> includeFilter)
|
||||
{
|
||||
return terms
|
||||
var result = terms
|
||||
.Select(x => new PreferredTermData
|
||||
{
|
||||
Score = x.Score,
|
||||
Terms = IncludeTerms(x.Terms, includeFilter)
|
||||
})
|
||||
.IsValid(new PreferredTermDataValidator(), (e, x) => LogInvalidTerm(e, $"Include Preferred {x}"))
|
||||
.ToList()
|
||||
.AsReadOnly();
|
||||
});
|
||||
|
||||
return _validator.FilterTerms(result).ToList().AsReadOnly();
|
||||
}
|
||||
|
||||
public ReleaseProfileData? FilterProfile(ReleaseProfileData selectedProfile,
|
@ -0,0 +1,51 @@
|
||||
using Common.FluentValidation;
|
||||
using FluentValidation.Results;
|
||||
using Serilog;
|
||||
|
||||
namespace TrashLib.Sonarr.ReleaseProfile.Filters;
|
||||
|
||||
public class ReleaseProfileDataValidationFilterer
|
||||
{
|
||||
private readonly ILogger _log;
|
||||
|
||||
public ReleaseProfileDataValidationFilterer(ILogger log)
|
||||
{
|
||||
_log = log;
|
||||
}
|
||||
|
||||
private void LogInvalidTerm(List<ValidationFailure> failures, string filterDescription)
|
||||
{
|
||||
_log.Debug("Validation failed on term data ({Filter}): {Failures}", filterDescription, failures);
|
||||
}
|
||||
|
||||
public IEnumerable<TermData> FilterTerms(IEnumerable<TermData> terms)
|
||||
{
|
||||
return terms.IsValid(new TermDataValidator(), (e, x) => LogInvalidTerm(e, x.ToString()));
|
||||
}
|
||||
|
||||
public IEnumerable<PreferredTermData> FilterTerms(IEnumerable<PreferredTermData> terms)
|
||||
{
|
||||
return terms.IsValid(new PreferredTermDataValidator(), (e, x) => LogInvalidTerm(e, x.ToString()));
|
||||
}
|
||||
|
||||
private ReleaseProfileData FilterProfile(ReleaseProfileData profile)
|
||||
{
|
||||
return profile with
|
||||
{
|
||||
Required = FilterTerms(profile.Required).ToList(),
|
||||
Ignored = FilterTerms(profile.Ignored).ToList(),
|
||||
Preferred = FilterTerms(profile.Preferred).ToList()
|
||||
};
|
||||
}
|
||||
|
||||
public IEnumerable<ReleaseProfileData> FilterProfiles(IEnumerable<ReleaseProfileData> data)
|
||||
{
|
||||
return data
|
||||
.Select(FilterProfile)
|
||||
.IsValid(new ReleaseProfileDataValidator(), (e, x) =>
|
||||
{
|
||||
_log.Warning("Excluding invalid release profile: {Profile}", x.ToString());
|
||||
_log.Debug("Release profile excluded for these reasons: {Reasons}", e);
|
||||
});
|
||||
}
|
||||
}
|
Loading…
Reference in new issue