mirror of https://github.com/sean-m/McRule.git
262 lines
10 KiB
C#
262 lines
10 KiB
C#
using Newtonsoft.Json.Linq;
|
|
using System.Linq;
|
|
using System.Linq.Expressions;
|
|
using System.Reflection;
|
|
using System.Reflection.Metadata;
|
|
|
|
using static McRule.Tests.TestPolicies;
|
|
|
|
namespace McRule.Tests {
|
|
public class Filtering {
|
|
|
|
People[] peoples = new[] {
|
|
new People("Sean", "Confused", 35, true, new[] {"muggle"}),
|
|
new People("Sean", "Actor", 90, false, new[] {"muggle", "metallurgist"}),
|
|
new People("Bean", "Runt", 20, false, new[] {"muggle", "giant"}),
|
|
new People("Robin", "Comedian", 63, false, new[] {"muggle", "hilarious"}),
|
|
new People("Tim", "Enchantor", 999, false, new[] {"magical", "grumpy"}),
|
|
new People("Ragnar", "Viking", 25, true, new[] {"muggle", "grumpy"}),
|
|
new People("Lars", "Viking", 30, false, new[] {"muggle", "grumpy"}),
|
|
new People("Ferris", "Student", 17, true, new[] {"muggle"}),
|
|
new People("Greta", null, 20, true, null),
|
|
};
|
|
|
|
public class People
|
|
{
|
|
public string name { get; set; }
|
|
public string kind { get; set; }
|
|
public int? number { get; set; }
|
|
public bool stillWithUs { get; set; }
|
|
public string[] tags { get; set; }
|
|
public People? relatedTo { get; set; }
|
|
|
|
public People(string name, string kind, int? number, bool stillWithUs, string[] tags = null)
|
|
{
|
|
this.name = name;
|
|
this.kind = kind;
|
|
this.number = number;
|
|
this.stillWithUs = stillWithUs;
|
|
this.tags = tags;
|
|
}
|
|
|
|
public override bool Equals(object obj)
|
|
{
|
|
return obj is People other &&
|
|
name == other.name &&
|
|
kind == other.kind &&
|
|
number == other.number &&
|
|
stillWithUs == other.stillWithUs &&
|
|
System.Linq.Enumerable.SequenceEqual(tags, other.tags);
|
|
}
|
|
}
|
|
|
|
|
|
[SetUp]
|
|
public void Setup() { }
|
|
|
|
[Test]
|
|
public void MatchNullLiteral() {
|
|
var filter = matchNullLiteral.GetPredicateExpression<People>()?.Compile();
|
|
var folks = peoples.Where(filter);
|
|
|
|
Assert.IsTrue(folks.All(x => x.kind == null));
|
|
|
|
// Test using EF generator
|
|
var efGenerator = PredicateExpressionPolicyExtensions.GetEfExpressionGenerator();
|
|
var efFilter = matchNullLiteral.GeneratePredicateExpression<People>(efGenerator)?.Compile();
|
|
|
|
folks = peoples.Where(efFilter);
|
|
|
|
Assert.IsTrue(folks.All(x => x.kind == null));
|
|
}
|
|
|
|
[Test]
|
|
public void MatchNullByString() {
|
|
var expression = matchNullByString.GetPredicateExpression<People>();
|
|
var filter = expression?.Compile();
|
|
var folks = peoples.Where(filter);
|
|
|
|
Assert.Zero(folks.Count(), "A string value of null \"null\" should not evaluate to a null literal so should yield no results here.");
|
|
|
|
// Test using EF generator
|
|
var efGenerator = PredicateExpressionPolicyExtensions.GetEfExpressionGenerator();
|
|
var efFilter = matchNullByString.GeneratePredicateExpression<People>(efGenerator)?.Compile();
|
|
|
|
folks = peoples.Where(efFilter);
|
|
|
|
Assert.Zero(folks.Count(), "A string value of null \"null\" should not evaluate to a null literal so should yield no results here.");
|
|
}
|
|
|
|
[Test]
|
|
public void NegativeStringMatch() {
|
|
var filter = notSean.GetPredicateExpression<People>()?.Compile();
|
|
var folks = peoples.Where(filter);
|
|
|
|
Assert.Null(folks.FirstOrDefault(x => x.name == "Sean"));
|
|
}
|
|
|
|
[Test]
|
|
public void EndsWith() {
|
|
// Filter should match on people who's name ends in 'ean',
|
|
// and case insensitive ends with 'EAN'.
|
|
var filter = eans.GetPredicateExpression<People>()?.Compile();
|
|
var folks = peoples.Where(filter);
|
|
|
|
Assert.NotNull(folks);
|
|
Assert.IsTrue(folks.All(x => x.name.EndsWith("ean")));
|
|
}
|
|
|
|
[Test]
|
|
public void CombineTwoExpressionsIntoCollection() {
|
|
// Combine two different filters with an And
|
|
var filter = new ExpressionRuleCollection() {
|
|
Rules = new[] {
|
|
youngens, vikings
|
|
},
|
|
RuleOperator = RuleOperator.And
|
|
}?.GetPredicateExpression<People>()?.Compile();
|
|
|
|
var folks = peoples.Where(filter);
|
|
|
|
// Match should be exclusive enough to only include Ragnar
|
|
Assert.NotNull(folks);
|
|
Assert.IsTrue(folks.Count() == 1);
|
|
Assert.IsTrue(folks.FirstOrDefault()?.name == "Ragnar");
|
|
|
|
// Process both expressions separately to verify they
|
|
// have different results.
|
|
filter = youngens.GetPredicateExpression<People>()?.Compile();
|
|
folks = peoples.Where(filter);
|
|
Assert.IsTrue(folks.Count() > 1);
|
|
|
|
filter = vikings.GetPredicateExpression<People>()?.Compile();
|
|
folks = peoples.Where(filter);
|
|
Assert.IsTrue(folks.Count() > 1);
|
|
|
|
// Original compound filter with an Or predicate
|
|
filter = new ExpressionRuleCollection() {
|
|
Rules = new[] {
|
|
youngens, vikings
|
|
},
|
|
RuleOperator = RuleOperator.Or
|
|
}?.GetPredicateExpression<People>()?.Compile();
|
|
|
|
folks = peoples.Where(filter);
|
|
Assert.IsTrue(folks.Count() > 1);
|
|
// Should include Vikings by kind and Student by number
|
|
Assert.NotNull(folks.Where(x => x.kind == "Viking"));
|
|
Assert.NotNull(folks.Where(x => x.kind == "Student"));
|
|
}
|
|
|
|
[Test]
|
|
public void YoungPeople() {
|
|
var filter = youngens.GetPredicateExpression<People>()?.Compile();
|
|
var folks = peoples.Where(filter);
|
|
|
|
Assert.NotNull(folks);
|
|
Assert.IsTrue(folks.All(x => x.number >= 17 && x.number < 30));
|
|
}
|
|
|
|
[Test]
|
|
public void FilterListOfObjectsByMemberCollectionContents()
|
|
{
|
|
var generator = new PolicyToExpressionGenerator();
|
|
var generatedFilter = muggles.GeneratePredicateExpression<People>(generator);
|
|
var filteredFolks = peoples.Where(generatedFilter.Compile());
|
|
|
|
var efGenerator = new PolicyToEFExpressionGenerator();
|
|
var efGeneratedFilter = muggles.GeneratePredicateExpression<People>(efGenerator);
|
|
var efFilteredFolks = peoples.Where(efGeneratedFilter.Compile());
|
|
|
|
|
|
var filter = muggles.GetPredicateExpression<People>()?.Compile();
|
|
var folks = peoples.Where(filter);
|
|
|
|
Assert.NotNull(folks);
|
|
Assert.IsTrue(folks.All(x => x.tags.Contains("muggle")));
|
|
Assert.IsTrue(folks.All(x => filteredFolks.Contains(x)));
|
|
Assert.IsTrue(folks.All(x => efFilteredFolks.Contains(x)));
|
|
}
|
|
|
|
[Test]
|
|
public void BoolConditional() {
|
|
var filter = notQuiteDead.GetPredicateExpression<People>()?.Compile();
|
|
var folks = peoples.Where(filter);
|
|
|
|
Assert.NotNull(folks);
|
|
Assert.IsTrue(folks.Count() > 0);
|
|
}
|
|
|
|
[Test]
|
|
public void FilterWhenNoMatchingTypesThrows() {
|
|
// Shouldn't have any filters in the policy for string objects.
|
|
Assert.Throws<ExpressionGeneratorException>(() => { notQuiteDead.GetPredicateExpression<string>(); });
|
|
}
|
|
|
|
[Test]
|
|
public void TestPolicyWithOrConditional() {
|
|
var filter = deadOrViking.GetPredicateExpression<People>()?.Compile();
|
|
var folks = peoples.Where(filter);
|
|
|
|
Assert.NotNull(folks);
|
|
Assert.NotNull(folks.Where(x => x.kind == "Viking" && x.stillWithUs == false));
|
|
Assert.NotNull(folks.Where(x => x.kind == "Viking" && x.stillWithUs == true));
|
|
|
|
// Should be either a viking or dead, not neither.
|
|
Assert.Null(folks.FirstOrDefault(x => x.kind != "Viking" && x.stillWithUs == true));
|
|
}
|
|
|
|
[Test]
|
|
public void TestBooleanMatches() {
|
|
var filter = notQuiteDead.GetPredicateExpression<People>()?.Compile();
|
|
var folks = peoples.Where(filter);
|
|
|
|
Assert.IsTrue(folks.All(x => x.stillWithUs == true));
|
|
}
|
|
|
|
[Test]
|
|
public void PolicyEFExpressionShouldNotEmitComparisonTypeStringMatches() {
|
|
var filter = eans.GetPredicateExpression<People>();
|
|
|
|
var efGenerator = PredicateExpressionPolicyExtensions.GetEfExpressionGenerator();
|
|
var efFilter = eans.GeneratePredicateExpression<People>(efGenerator);
|
|
|
|
Assert.NotNull(filter);
|
|
Assert.AreNotEqual(efFilter.ToString(), filter.ToString());
|
|
Assert.IsTrue(filter.ToString().Contains("CurrentCulture"));
|
|
Assert.IsFalse(efFilter.ToString().Contains("CurrentCulture"), "EF safe string comparision contains a CurrentCulture directive, wrong generator used for AddStringPropertyExpression.");
|
|
}
|
|
|
|
[Test]
|
|
public void BaseThrowsOnPoorlyImplementedGenerator()
|
|
{
|
|
var failedGenerator = new FailedExpressionGeneratorBase();
|
|
Assert.Throws<NotImplementedException>(() => { _ = eans.GeneratePredicateExpression<People>(failedGenerator); });
|
|
}
|
|
|
|
|
|
[Test]
|
|
public void SelectPropertyOfMemberObject() {
|
|
var filter = vikings.GetPredicateExpression<People>()?.Compile();
|
|
|
|
// This should be the two Vikings: Lars then Ragnar, in that order
|
|
var folks = peoples.Where(filter).OrderBy(x => x.name);
|
|
|
|
// We specify that Lars is related to Ragnar
|
|
folks.First().relatedTo = folks.Skip(1).First();
|
|
|
|
var testMembersProperty = ("People", "relatedTo.name", "Ragnar").ToFilterRule().GetPredicateExpression<People>().Compile();
|
|
|
|
Assert.NotNull(folks);
|
|
Assert.True(testMembersProperty(folks.First()));
|
|
}
|
|
}
|
|
|
|
internal class FailedExpressionGeneratorBase : ExpressionGeneratorBase
|
|
{
|
|
public FailedExpressionGeneratorBase()
|
|
{
|
|
}
|
|
}
|
|
}
|