interface type fixes & unit test improvements

This commit is contained in:
Hasan Manzak 2023-02-23 01:11:34 +03:00
parent b73f748dba
commit 7ec97810f7
No known key found for this signature in database
GPG Key ID: C1573806B673A138
17 changed files with 884 additions and 586 deletions

View File

@ -1,21 +1,76 @@
using System; using System;
using System.Linq; using System.Linq;
using System.Linq.Expressions; using System.Linq.Expressions;
using System.Reflection; using Sieve.Exceptions;
namespace Sieve.Extensions namespace Sieve.Extensions
{ {
public static partial class LinqExtensions public static partial class LinqExtensions
{ {
internal static Expression GeneratePropertyAccess
(
this Expression parameterExpression,
string propertyName
)
{
var propertyAccessor = parameterExpression;
try
{
propertyAccessor = Expression.PropertyOrField(propertyAccessor, propertyName);
}
catch (ArgumentException)
{
// propertyName is not a direct property of field of propertyAccessor expression's type.
// when propertyAccessor.Type is directly an interface, say typeof(ISomeEntity) and ISomeEntity is interfaced to IBaseEntity
// in which `propertyName` is defined in the first place.
// To solve this, search `propertyName` in all other implemented interfaces
var possibleInterfaceType = propertyAccessor.Type;
if (!possibleInterfaceType.IsInterface)
throw;
// get all implemented interface types
var implementedInterfaces = possibleInterfaceType.GetInterfaces();
try
{
// search propertyName in all interfaces
var interfacedExpression = implementedInterfaces
.Where
(
implementedInterface => implementedInterface
.GetProperties()
.Any(info => info.Name == propertyName)
)
.Select(implementedInterface => Expression.TypeAs(propertyAccessor, implementedInterface))
.SingleOrDefault();
if (interfacedExpression != null)
propertyAccessor = Expression.PropertyOrField(interfacedExpression, propertyName);
}
catch (InvalidOperationException ioe)
{
throw new SieveException
(
$"{propertyName} is repeated in interface hierarchy. Try renaming.",
ioe
);
}
}
return propertyAccessor;
}
public static IQueryable<TEntity> OrderByDynamic<TEntity>( public static IQueryable<TEntity> OrderByDynamic<TEntity>(
this IQueryable<TEntity> source, this IQueryable<TEntity> source,
string fullPropertyName, string fullPropertyName,
PropertyInfo propertyInfo,
bool desc, bool desc,
bool useThenBy, bool useThenBy,
bool disableNullableTypeExpression = false) bool disableNullableTypeExpression = false)
{ {
var lambda = GenerateLambdaWithSafeMemberAccess<TEntity>(fullPropertyName, propertyInfo, disableNullableTypeExpression); var lambda = GenerateLambdaWithSafeMemberAccess<TEntity>(fullPropertyName, disableNullableTypeExpression);
var command = desc var command = desc
? (useThenBy ? "ThenByDescending" : "OrderByDescending") ? (useThenBy ? "ThenByDescending" : "OrderByDescending")
@ -34,7 +89,6 @@ namespace Sieve.Extensions
private static Expression<Func<TEntity, object>> GenerateLambdaWithSafeMemberAccess<TEntity> private static Expression<Func<TEntity, object>> GenerateLambdaWithSafeMemberAccess<TEntity>
( (
string fullPropertyName, string fullPropertyName,
PropertyInfo propertyInfo,
bool disableNullableTypeExpression bool disableNullableTypeExpression
) )
{ {
@ -44,15 +98,7 @@ namespace Sieve.Extensions
foreach (var name in fullPropertyName.Split('.')) foreach (var name in fullPropertyName.Split('.'))
{ {
try propertyValue = propertyValue.GeneratePropertyAccess(name);
{
propertyValue = Expression.PropertyOrField(propertyValue, name);
}
catch (ArgumentException)
{
// name is not a direct property of field of propertyValue expression. construct a memberAccess then.
propertyValue = Expression.MakeMemberAccess(propertyValue, propertyInfo);
}
if (propertyValue.Type.IsNullable() && !disableNullableTypeExpression) if (propertyValue.Type.IsNullable() && !disableNullableTypeExpression)
{ {

View File

@ -289,7 +289,7 @@ namespace Sieve.Services
var names = fullPropertyName.Split('.'); var names = fullPropertyName.Split('.');
for (var i = 0; i < names.Length; i++) for (var i = 0; i < names.Length; i++)
{ {
propertyValue = Expression.PropertyOrField(propertyValue, names[i]); propertyValue = propertyValue.GeneratePropertyAccess(names[i]);
if (i != names.Length - 1 && propertyValue.Type.IsNullable()) if (i != names.Length - 1 && propertyValue.Type.IsNullable())
{ {
@ -368,7 +368,7 @@ namespace Sieve.Services
if (property != null) if (property != null)
{ {
result = result.OrderByDynamic(fullName, property, sortTerm.Descending, useThenBy, Options.Value.DisableNullableTypeExpressionForSorting); result = result.OrderByDynamic(fullName, sortTerm.Descending, useThenBy, Options.Value.DisableNullableTypeExpressionForSorting);
} }
else else
{ {

View File

@ -1,8 +1,9 @@
using System; using System;
using SieveUnitTests.Abstractions.Strategy;
namespace SieveUnitTests.Abstractions.Entity namespace SieveUnitTests.Abstractions.Entity
{ {
public interface IBaseEntity public interface IBaseEntity: ISupportSoftDelete
{ {
int Id { get; set; } int Id { get; set; }
DateTimeOffset DateCreated { get; set; } DateTimeOffset DateCreated { get; set; }

View File

@ -1,9 +1,10 @@
using Sieve.Attributes; using Sieve.Attributes;
using SieveUnitTests.Abstractions.Strategy;
using SieveUnitTests.Entities; using SieveUnitTests.Entities;
namespace SieveUnitTests.Abstractions.Entity namespace SieveUnitTests.Abstractions.Entity
{ {
public interface IPost: IBaseEntity public interface IPost: IBaseEntity, IAudit
{ {
[Sieve(CanFilter = true, CanSort = true)] [Sieve(CanFilter = true, CanSort = true)]
string Title { get; set; } string Title { get; set; }

View File

@ -4,8 +4,12 @@ namespace SieveUnitTests.Abstractions.Entity
{ {
public class SieveConfigurationForIPost : ISieveConfiguration public class SieveConfigurationForIPost : ISieveConfiguration
{ {
public void Configure(SievePropertyMapper mapper) public static void ConfigureStatic(SievePropertyMapper mapper)
{ {
mapper
.Property<IPost>(p => p.Id)
.CanSort();
mapper.Property<IPost>(p => p.ThisHasNoAttributeButIsAccessible) mapper.Property<IPost>(p => p.ThisHasNoAttributeButIsAccessible)
.CanSort() .CanSort()
.CanFilter() .CanFilter()
@ -32,6 +36,21 @@ namespace SieveUnitTests.Abstractions.Entity
.Property<IPost>(p => p.DateCreated) .Property<IPost>(p => p.DateCreated)
.CanSort() .CanSort()
.HasName("CreateDate"); .HasName("CreateDate");
mapper
.Property<IPost>(post => post.DeletedBy)
.CanSort()
.HasName("DeletedBy");
mapper
.Property<IPost>(post => post.UpdatedBy)
.CanFilter()
.HasName("UpdatedBy");
}
public void Configure(SievePropertyMapper mapper)
{
ConfigureStatic(mapper);
} }
} }
} }

View File

@ -0,0 +1,12 @@
using System;
namespace SieveUnitTests.Abstractions.Strategy
{
public interface IAudit
{
string CreatedBy { get; }
DateTime? CreatedAt { get; }
string UpdatedBy { get; }
DateTime? UpdatedAt { get; }
}
}

View File

@ -0,0 +1,10 @@
using System;
namespace SieveUnitTests.Abstractions.Strategy
{
public interface ISupportSoftDelete
{
string DeletedBy { get; }
DateTime? DeletedAt { get; }
}
}

View File

@ -10,5 +10,8 @@ namespace SieveUnitTests.Entities
[Sieve(CanFilter = true, CanSort = true)] [Sieve(CanFilter = true, CanSort = true)]
public DateTimeOffset DateCreated { get; set; } = DateTimeOffset.UtcNow; public DateTimeOffset DateCreated { get; set; } = DateTimeOffset.UtcNow;
public string DeletedBy { get; set; }
public DateTime? DeletedAt { get; set; }
} }
} }

View File

@ -30,5 +30,10 @@ namespace SieveUnitTests.Entities
public Comment TopComment { get; set; } public Comment TopComment { get; set; }
public Comment FeaturedComment { get; set; } public Comment FeaturedComment { get; set; }
public string CreatedBy { get; set; }
public DateTime? CreatedAt { get; set; }
public string UpdatedBy { get; set; }
public DateTime? UpdatedAt { get; set; }
} }
} }

View File

@ -4,8 +4,12 @@ namespace SieveUnitTests.Entities
{ {
public class SieveConfigurationForPost : ISieveConfiguration public class SieveConfigurationForPost : ISieveConfiguration
{ {
public void Configure(SievePropertyMapper mapper) public static void ConfigureStatic(SievePropertyMapper mapper)
{ {
mapper
.Property<Post>(p => p.Id)
.CanSort();
mapper.Property<Post>(p => p.ThisHasNoAttributeButIsAccessible) mapper.Property<Post>(p => p.ThisHasNoAttributeButIsAccessible)
.CanSort() .CanSort()
.CanFilter() .CanFilter()
@ -32,6 +36,21 @@ namespace SieveUnitTests.Entities
.Property<Post>(p => p.DateCreated) .Property<Post>(p => p.DateCreated)
.CanSort() .CanSort()
.HasName("CreateDate"); .HasName("CreateDate");
mapper
.Property<Post>(post => post.DeletedBy)
.CanSort()
.HasName("DeletedBy");
mapper
.Property<Post>(post => post.UpdatedBy)
.CanFilter()
.HasName("UpdatedBy");
}
public void Configure(SievePropertyMapper mapper)
{
ConfigureStatic(mapper);
} }
} }
} }

View File

@ -3,7 +3,6 @@ using System.Collections.Generic;
using System.Linq; using System.Linq;
using Sieve.Exceptions; using Sieve.Exceptions;
using Sieve.Models; using Sieve.Models;
using Sieve.Services;
using SieveUnitTests.Entities; using SieveUnitTests.Entities;
using SieveUnitTests.Services; using SieveUnitTests.Services;
using Xunit; using Xunit;
@ -11,28 +10,14 @@ using Xunit.Abstractions;
namespace SieveUnitTests namespace SieveUnitTests
{ {
public class General public class General: TestBase
{ {
private readonly ITestOutputHelper _testOutputHelper;
private readonly SieveProcessor _processor;
private readonly SieveProcessor _nullableProcessor;
private readonly IQueryable<Post> _posts; private readonly IQueryable<Post> _posts;
private readonly IQueryable<Comment> _comments; private readonly IQueryable<Comment> _comments;
public General(ITestOutputHelper testOutputHelper) public General(ITestOutputHelper testOutputHelper)
: base(testOutputHelper)
{ {
var nullableAccessor = new SieveOptionsAccessor();
nullableAccessor.Value.IgnoreNullsOnNotEqual = false;
_testOutputHelper = testOutputHelper;
_processor = new ApplicationSieveProcessor(new SieveOptionsAccessor(),
new SieveCustomSortMethods(),
new SieveCustomFilterMethods());
_nullableProcessor = new ApplicationSieveProcessor(nullableAccessor,
new SieveCustomSortMethods(),
new SieveCustomFilterMethods());
_posts = new List<Post> _posts = new List<Post>
{ {
new Post new Post
@ -77,6 +62,16 @@ namespace SieveUnitTests
new Post new Post
{ {
Id = 4, Id = 4,
Title = "E",
LikeCount = 5,
IsDraft = false,
CategoryId = null,
TopComment = new Comment { Id = 4, Text = "E1" },
UpdatedBy = "You"
},
new Post
{
Id = 5,
Title = "Yen", Title = "Yen",
LikeCount = 5, LikeCount = 5,
IsDraft = true, IsDraft = true,
@ -117,11 +112,14 @@ namespace SieveUnitTests
Filters = "Title@=*a" Filters = "Title@=*a"
}; };
var result = _processor.Apply(model, _posts); foreach (var sieveProcessor in GetProcessors())
{
var result = sieveProcessor.Apply(model, _posts);
Assert.Equal(0, result.First().Id); Assert.Equal(0, result.First().Id);
Assert.True(result.Count() == 1); Assert.True(result.Count() == 1);
} }
}
[Fact] [Fact]
public void NotEqualsCanBeCaseInsensitive() public void NotEqualsCanBeCaseInsensitive()
@ -131,10 +129,13 @@ namespace SieveUnitTests
Filters = "Title!=*a" Filters = "Title!=*a"
}; };
var result = _processor.Apply(model, _posts); foreach (var sieveProcessor in GetProcessors())
{
var result = sieveProcessor.Apply(model, _posts);
Assert.Equal(1, result.First().Id); Assert.Equal(1, result.First().Id);
Assert.True(result.Count() == 4); Assert.True(result.Count() == _posts.Count(post => !post.Title.Contains("a", StringComparison.OrdinalIgnoreCase)));
}
} }
[Fact] [Fact]
@ -145,15 +146,18 @@ namespace SieveUnitTests
Filters = "Title_-=n" Filters = "Title_-=n"
}; };
_testOutputHelper.WriteLine(model.GetFiltersParsed()[0].Values.ToString()); TestOutputHelper.WriteLine(model.GetFiltersParsed()[0].Values.ToString());
_testOutputHelper.WriteLine(model.GetFiltersParsed()[0].Operator); TestOutputHelper.WriteLine(model.GetFiltersParsed()[0].Operator);
_testOutputHelper.WriteLine(model.GetFiltersParsed()[0].OperatorParsed.ToString()); TestOutputHelper.WriteLine(model.GetFiltersParsed()[0].OperatorParsed.ToString());
var result = _processor.Apply(model, _posts); foreach (var sieveProcessor in GetProcessors())
{
var result = sieveProcessor.Apply(model, _posts);
Assert.Equal(4, result.First().Id); Assert.Equal(_posts.First(post => post.Title.EndsWith("n")).Id, result.First().Id);
Assert.True(result.Count() == 1); Assert.True(result.Count() == 1);
} }
}
[Fact] [Fact]
public void EndsWithCanBeCaseInsensitive() public void EndsWithCanBeCaseInsensitive()
@ -163,28 +167,31 @@ namespace SieveUnitTests
Filters = "Title_-=*N" Filters = "Title_-=*N"
}; };
_testOutputHelper.WriteLine(model.GetFiltersParsed()[0].Values.ToString()); TestOutputHelper.WriteLine(model.GetFiltersParsed()[0].Values.ToString());
_testOutputHelper.WriteLine(model.GetFiltersParsed()[0].Operator); TestOutputHelper.WriteLine(model.GetFiltersParsed()[0].Operator);
_testOutputHelper.WriteLine(model.GetFiltersParsed()[0].OperatorParsed.ToString()); TestOutputHelper.WriteLine(model.GetFiltersParsed()[0].OperatorParsed.ToString());
var result = _processor.Apply(model, _posts); foreach (var sieveProcessor in GetProcessors())
{
var result = sieveProcessor.Apply(model, _posts);
Assert.Equal(4, result.First().Id); Assert.Equal(_posts.First(post => post.Title.EndsWith("N", StringComparison.OrdinalIgnoreCase)).Id, result.First().Id);
Assert.True(result.Count() == 1); Assert.True(result.Count() == 1);
} }
}
[Fact] [Fact]
public void ContainsIsCaseSensitive() public void ContainsIsCaseSensitive()
{ {
var model = new SieveModel var model = new SieveModel { Filters = "Title@=a", };
{
Filters = "Title@=a",
};
var result = _processor.Apply(model, _posts); foreach (var sieveProcessor in GetProcessors())
{
var result = sieveProcessor.Apply(model, _posts);
Assert.True(!result.Any()); Assert.True(!result.Any());
} }
}
[Fact] [Fact]
public void NotContainsWorks() public void NotContainsWorks()
@ -194,65 +201,70 @@ namespace SieveUnitTests
Filters = "Title!@=D", Filters = "Title!@=D",
}; };
var result = _processor.Apply(model, _posts); foreach (var sieveProcessor in GetProcessors())
{
var result = sieveProcessor.Apply(model, _posts);
Assert.True(result.Count() == 4); Assert.True(result.Count() == _posts.Count(post => !post.Title.Contains("D")));
}
} }
[Fact] [Fact]
public void CanFilterBools() public void CanFilterBools()
{ {
var model = new SieveModel var model = new SieveModel { Filters = "IsDraft==false" };
foreach (var sieveProcessor in GetProcessors())
{ {
Filters = "IsDraft==false" var result = sieveProcessor.Apply(model, _posts);
};
var result = _processor.Apply(model, _posts); Assert.True(result.Count() == _posts.Count(post => !post.IsDraft));
}
Assert.True(result.Count() == 2);
} }
[Fact] [Fact]
public void CanSortBools() public void CanSortBools()
{ {
var model = new SieveModel var model = new SieveModel { Sorts = "-IsDraft" };
{
Sorts = "-IsDraft"
};
var result = _processor.Apply(model, _posts); foreach (var sieveProcessor in GetProcessors())
{
var result = sieveProcessor.Apply(model, _posts);
Assert.Equal(0, result.First().Id); Assert.Equal(0, result.First().Id);
} }
}
[Fact] [Fact]
public void CanFilterNullableInts() public void CanFilterNullableInts()
{ {
var model = new SieveModel var model = new SieveModel { Filters = "CategoryId==1" };
foreach (var sieveProcessor in GetProcessors())
{ {
Filters = "CategoryId==1" var result = sieveProcessor.Apply(model, _posts);
};
var result = _processor.Apply(model, _posts); Assert.True(result.Count() == _posts.Count(post => post.CategoryId == 1));
var nullableResult = _nullableProcessor.Apply(model, _posts); }
Assert.True(result.Count() == 2);
Assert.True(nullableResult.Count() == 2);
} }
[Fact] [Fact]
public void CanFilterNullableIntsWithNotEqual() public void CanFilterNullableIntsWithNotEqual()
{ {
var model = new SieveModel() var model = new SieveModel() { Filters = "CategoryId!=1" };
foreach (var sieveProcessor in GetProcessors())
{ {
Filters = "CategoryId!=1" var result = sieveProcessor.Apply(model, _posts);
};
var result = _processor.Apply(model, _posts); Assert.Equal
var nullableResult = _nullableProcessor.Apply(model, _posts); (
(sieveProcessor as ApplicationSieveProcessor)?.ExposedOptions.IgnoreNullsOnNotEqual ?? true
Assert.True(result.Count() == 2); ? _posts.Count(post => post.CategoryId != null && post.CategoryId != 1)
Assert.True(nullableResult.Count() == 3); : _posts.Count(post => post.CategoryId != 1),
result.Count()
);
}
} }
[Theory] [Theory]
@ -267,98 +279,101 @@ namespace SieveUnitTests
Filters = filter Filters = filter
}; };
var result = _processor.Apply(model, _comments); foreach (var sieveProcessor in GetProcessors())
{
var result = sieveProcessor.Apply(model, _comments);
Assert.True(result.Count() == 1); Assert.True(result.Count() == 1);
} }
}
[Fact] [Fact]
public void EqualsDoesntFailWithNonStringTypes() public void EqualsDoesntFailWithNonStringTypes()
{ {
var model = new SieveModel var model = new SieveModel { Filters = "LikeCount==50", };
TestOutputHelper.WriteLine(model.GetFiltersParsed()[0].Values.ToString());
TestOutputHelper.WriteLine(model.GetFiltersParsed()[0].Operator);
TestOutputHelper.WriteLine(model.GetFiltersParsed()[0].OperatorParsed.ToString());
foreach (var sieveProcessor in GetProcessors())
{ {
Filters = "LikeCount==50", var result = sieveProcessor.Apply(model, _posts);
};
_testOutputHelper.WriteLine(model.GetFiltersParsed()[0].Values.ToString());
_testOutputHelper.WriteLine(model.GetFiltersParsed()[0].Operator);
_testOutputHelper.WriteLine(model.GetFiltersParsed()[0].OperatorParsed.ToString());
var result = _processor.Apply(model, _posts);
Assert.Equal(1, result.First().Id); Assert.Equal(1, result.First().Id);
Assert.True(result.Count() == 1); Assert.True(result.Count() == 1);
} }
}
[Fact] [Fact]
public void CustomFiltersWork() public void CustomFiltersWork()
{ {
var model = new SieveModel var model = new SieveModel { Filters = "Isnew", };
{
Filters = "Isnew",
};
var result = _processor.Apply(model, _posts); foreach (var sieveProcessor in GetProcessors())
{
var result = sieveProcessor.Apply(model, _posts);
Assert.False(result.Any(p => p.Id == 0)); Assert.False(result.Any(p => p.Id == 0));
Assert.True(result.Count() == 4); Assert.True(result.Count() == _posts.Count(SieveCustomFilterMethods.IsNewFilterForPost));
}
} }
[Fact] [Fact]
public void CustomGenericFiltersWork() public void CustomGenericFiltersWork()
{ {
var model = new SieveModel var model = new SieveModel { Filters = "Latest", };
{
Filters = "Latest",
};
var result = _processor.Apply(model, _comments); foreach (var sieveProcessor in GetProcessors())
{
var result = sieveProcessor.Apply(model, _comments);
Assert.False(result.Any(p => p.Id == 0)); Assert.False(result.Any(p => p.Id == 0));
Assert.True(result.Count() == 2); Assert.True(result.Count() == 2);
} }
}
[Fact] [Fact]
public void CustomFiltersWithOperatorsWork() public void CustomFiltersWithOperatorsWork()
{ {
var model = new SieveModel var model = new SieveModel { Filters = "HasInTitle==A", };
{
Filters = "HasInTitle==A",
};
var result = _processor.Apply(model, _posts); foreach (var sieveProcessor in GetProcessors())
{
var result = sieveProcessor.Apply(model, _posts);
Assert.True(result.Any(p => p.Id == 0)); Assert.True(result.Any(p => p.Id == 0));
Assert.True(result.Count() == 1); Assert.True(result.Count() == 1);
} }
}
[Fact] [Fact]
public void CustomFiltersMixedWithUsualWork1() public void CustomFiltersMixedWithUsualWork1()
{ {
var model = new SieveModel var model = new SieveModel { Filters = "Isnew,CategoryId==2", };
{
Filters = "Isnew,CategoryId==2",
};
var result = _processor.Apply(model, _posts); foreach (var sieveProcessor in GetProcessors())
{
var result = sieveProcessor.Apply(model, _posts);
Assert.True(result.Any(p => p.Id == 3)); Assert.True(result.Any(p => p.Id == 3));
Assert.True(result.Count() == 1); Assert.True(result.Count() == 1);
} }
}
[Fact] [Fact]
public void CustomFiltersMixedWithUsualWork2() public void CustomFiltersMixedWithUsualWork2()
{ {
var model = new SieveModel var model = new SieveModel { Filters = "CategoryId==2,Isnew", };
{
Filters = "CategoryId==2,Isnew",
};
var result = _processor.Apply(model, _posts); foreach (var sieveProcessor in GetProcessors())
{
var result = sieveProcessor.Apply(model, _posts);
Assert.True(result.Any(p => p.Id == 3)); Assert.True(result.Any(p => p.Id == 3));
Assert.True(result.Count() == 1); Assert.True(result.Count() == 1);
} }
}
[Fact] [Fact]
public void CustomFiltersOnDifferentSourcesCanShareName() public void CustomFiltersOnDifferentSourcesCanShareName()
@ -368,79 +383,84 @@ namespace SieveUnitTests
Filters = "CategoryId==2,Isnew", Filters = "CategoryId==2,Isnew",
}; };
var postResult = _processor.Apply(postModel, _posts); foreach (var sieveProcessor in GetProcessors())
{
var postResult = sieveProcessor.Apply(postModel, _posts);
Assert.True(postResult.Any(p => p.Id == 3)); Assert.True(postResult.Any(p => p.Id == 3));
Assert.Equal(1, postResult.Count()); Assert.Equal(1, postResult.Count());
}
var commentModel = new SieveModel var commentModel = new SieveModel
{ {
Filters = "Isnew", Filters = "Isnew",
}; };
var commentResult = _processor.Apply(commentModel, _comments); foreach (var sieveProcessor in GetProcessors())
{
var commentResult = sieveProcessor.Apply(commentModel, _comments);
Assert.True(commentResult.Any(c => c.Id == 2)); Assert.True(commentResult.Any(c => c.Id == 2));
Assert.Equal(2, commentResult.Count()); Assert.Equal(2, commentResult.Count());
} }
}
[Fact] [Fact]
public void CustomSortsWork() public void CustomSortsWork()
{ {
var model = new SieveModel var model = new SieveModel { Sorts = "Popularity", };
{
Sorts = "Popularity",
};
var result = _processor.Apply(model, _posts); foreach (var sieveProcessor in GetProcessors())
{
var result = sieveProcessor.Apply(model, _posts);
Assert.False(result.First().Id == 0); Assert.False(result.First().Id == 0);
} }
}
[Fact] [Fact]
public void CustomGenericSortsWork() public void CustomGenericSortsWork()
{ {
var model = new SieveModel var model = new SieveModel { Sorts = "Oldest", };
{
Sorts = "Oldest",
};
var result = _processor.Apply(model, _posts); foreach (var sieveProcessor in GetProcessors())
{
var result = sieveProcessor.Apply(model, _posts);
Assert.True(result.Last().Id == 0); Assert.True(result.Last().Id == 0);
} }
}
[Fact] [Fact]
public void MethodNotFoundExceptionWork() public void MethodNotFoundExceptionWork()
{ {
var model = new SieveModel var model = new SieveModel { Filters = "does not exist", };
{
Filters = "does not exist",
};
Assert.Throws<SieveMethodNotFoundException>(() => _processor.Apply(model, _posts)); foreach (var sieveProcessor in GetProcessors())
{
Assert.Throws<SieveMethodNotFoundException>(() => sieveProcessor.Apply(model, _posts));
}
} }
[Fact] [Fact]
public void IncompatibleMethodExceptionsWork() public void IncompatibleMethodExceptionsWork()
{ {
var model = new SieveModel var model = new SieveModel { Filters = "TestComment", };
{
Filters = "TestComment",
};
Assert.Throws<SieveIncompatibleMethodException>(() => _processor.Apply(model, _posts)); foreach (var sieveProcessor in GetProcessors())
{
Assert.Throws<SieveIncompatibleMethodException>(() => sieveProcessor.Apply(model, _posts));
}
} }
[Fact] [Fact]
public void OrNameFilteringWorks() public void OrNameFilteringWorks()
{ {
var model = new SieveModel var model = new SieveModel { Filters = "(Title|LikeCount)==3", };
{
Filters = "(Title|LikeCount)==3",
};
var result = _processor.Apply(model, _posts); foreach (var sieveProcessor in GetProcessors())
{
var result = sieveProcessor.Apply(model, _posts);
var entry = result.FirstOrDefault(); var entry = result.FirstOrDefault();
var resultCount = result.Count(); var resultCount = result.Count();
@ -448,34 +468,34 @@ namespace SieveUnitTests
Assert.Equal(1, resultCount); Assert.Equal(1, resultCount);
Assert.Equal(3, entry.Id); Assert.Equal(3, entry.Id);
} }
}
[Theory] [Theory]
[InlineData("CategoryId==1,(CategoryId|LikeCount)==50")] [InlineData("CategoryId==1,(CategoryId|LikeCount)==50")]
[InlineData("(CategoryId|LikeCount)==50,CategoryId==1")] [InlineData("(CategoryId|LikeCount)==50,CategoryId==1")]
public void CombinedAndOrFilterIndependentOfOrder(string filter) public void CombinedAndOrFilterIndependentOfOrder(string filter)
{ {
var model = new SieveModel var model = new SieveModel { Filters = filter, };
{
Filters = filter,
};
var result = _processor.Apply(model, _posts); foreach (var sieveProcessor in GetProcessors())
{
var result = sieveProcessor.Apply(model, _posts);
var entry = result.FirstOrDefault(); var entry = result.FirstOrDefault();
var resultCount = result.Count(); var resultCount = result.Count();
Assert.NotNull(entry); Assert.NotNull(entry);
Assert.Equal(1, resultCount); Assert.Equal(1, resultCount);
} }
}
[Fact] [Fact]
public void CombinedAndOrWithSpaceFilteringWorks() public void CombinedAndOrWithSpaceFilteringWorks()
{ {
var model = new SieveModel var model = new SieveModel { Filters = "Title==D, (Title|LikeCount)==3", };
{
Filters = "Title==D, (Title|LikeCount)==3",
};
var result = _processor.Apply(model, _posts); foreach (var sieveProcessor in GetProcessors())
{
var result = sieveProcessor.Apply(model, _posts);
var entry = result.FirstOrDefault(); var entry = result.FirstOrDefault();
var resultCount = result.Count(); var resultCount = result.Count();
@ -483,67 +503,77 @@ namespace SieveUnitTests
Assert.Equal(1, resultCount); Assert.Equal(1, resultCount);
Assert.Equal(3, entry.Id); Assert.Equal(3, entry.Id);
} }
}
[Fact] [Fact]
public void OrValueFilteringWorks() public void OrValueFilteringWorks()
{ {
var model = new SieveModel var model = new SieveModel { Filters = "Title==C|D", };
{
Filters = "Title==C|D",
};
var result = _processor.Apply(model, _posts); foreach (var sieveProcessor in GetProcessors())
{
var result = sieveProcessor.Apply(model, _posts);
Assert.Equal(2, result.Count()); Assert.Equal(2, result.Count());
Assert.True(result.Any(p => p.Id == 2)); Assert.True(result.Any(p => p.Id == 2));
Assert.True(result.Any(p => p.Id == 3)); Assert.True(result.Any(p => p.Id == 3));
} }
}
[Fact] [Fact]
public void OrValueFilteringWorks2() public void OrValueFilteringWorks2()
{ {
var model = new SieveModel var model = new SieveModel { Filters = "Text@=(|)", };
{
Filters = "Text@=(|)",
};
var result = _processor.Apply(model, _comments); foreach (var sieveProcessor in GetProcessors())
{
var result = sieveProcessor.Apply(model, _comments);
Assert.Equal(1, result.Count()); Assert.Equal(1, result.Count());
Assert.Equal(2, result.FirstOrDefault()?.Id); Assert.Equal(2, result.FirstOrDefault()?.Id);
} }
}
[Fact] [Fact]
public void NestedFilteringWorks() public void NestedFilteringWorks()
{ {
var model = new SieveModel var model = new SieveModel { Filters = "TopComment.Text!@=A", };
{
Filters = "TopComment.Text!@=A",
};
var result = _processor.Apply(model, _posts); foreach (var sieveProcessor in GetProcessors())
Assert.Equal(4, result.Count()); {
var result = sieveProcessor.Apply(model, _posts);
Assert.Equal(_posts.Count(post => !post.TopComment.Text.Contains("A")), result.Count());
var posts = result.ToList(); var posts = result.ToList();
Assert.Contains("B", posts[0].TopComment.Text); Assert.Contains("B", posts[0].TopComment.Text);
Assert.Contains("C", posts[1].TopComment.Text); Assert.Contains("C", posts[1].TopComment.Text);
Assert.Contains("D", posts[2].TopComment.Text); Assert.Contains("D", posts[2].TopComment.Text);
Assert.Contains("Yen", posts[3].TopComment.Text); Assert.Contains("E1", posts[3].TopComment.Text);
Assert.Contains("Yen", posts[4].TopComment.Text);
}
} }
[Fact] [Fact]
public void NestedSortingWorks() public void NestedSortingWorks()
{ {
var model = new SieveModel var model = new SieveModel { Sorts = "TopComment.Id", };
{
Sorts = "TopComment.Id",
};
var result = _processor.Apply(model, _posts); foreach (var sieveProcessor in GetProcessors())
Assert.Equal(5, result.Count()); {
var posts = result.ToList(); var result = sieveProcessor.Apply(model, _posts);
Assert.Equal(0, posts[0].Id); Assert.Equal(_posts.Count(), result.Count());
Assert.Equal(3, posts[1].Id); var posts = result
Assert.Equal(2, posts[2].Id); .Select(post => post.Id)
Assert.Equal(1, posts[3].Id); .ToList();
Assert.Equal(4, posts[4].Id);
Assert.True
(
posts.SequenceEqual
(
_posts
.AsEnumerable()
.OrderBy(post => post.TopComment.Id)
.Select(post => post.Id)
)
);
}
} }
[Fact] [Fact]
@ -554,17 +584,23 @@ namespace SieveUnitTests
Filters = "(topc|featc)@=*2", Filters = "(topc|featc)@=*2",
}; };
var result = _processor.Apply(model, _posts); foreach (var sieveProcessor in GetProcessors())
{
var result = sieveProcessor.Apply(model, _posts);
Assert.Equal(4, result.Count()); Assert.Equal(4, result.Count());
}
model = new SieveModel model = new SieveModel
{ {
Filters = "(topc|featc)@=*B", Filters = "(topc|featc)@=*B",
}; };
result = _processor.Apply(model, _posts); foreach (var sieveProcessor in GetProcessors())
{
var result = sieveProcessor.Apply(model, _posts);
Assert.Equal(1, result.Count()); Assert.Equal(1, result.Count());
} }
}
[Fact] [Fact]
public void FilteringNullsWorks() public void FilteringNullsWorks()
@ -583,14 +619,14 @@ namespace SieveUnitTests
}, },
}.AsQueryable(); }.AsQueryable();
var model = new SieveModel var model = new SieveModel { Filters = "FeaturedComment.Text!@=Some value", };
{
Filters = "FeaturedComment.Text!@=Some value",
};
var result = _processor.Apply(model, posts); foreach (var sieveProcessor in GetProcessors())
{
var result = sieveProcessor.Apply(model, posts);
Assert.Equal(0, result.Count()); Assert.Equal(0, result.Count());
} }
}
[Fact] [Fact]
public void SortingNullsWorks() public void SortingNullsWorks()
@ -624,12 +660,15 @@ namespace SieveUnitTests
Sorts = "TopComment.Id", Sorts = "TopComment.Id",
}; };
var result = _processor.Apply(model, posts); foreach (var sieveProcessor in GetProcessors())
{
var result = sieveProcessor.Apply(model, posts);
Assert.Equal(2, result.Count()); Assert.Equal(2, result.Count());
var sortedPosts = result.ToList(); var sortedPosts = result.ToList();
Assert.Equal(2, sortedPosts[0].Id); Assert.Equal(2, sortedPosts[0].Id);
Assert.Equal(1, sortedPosts[1].Id); Assert.Equal(1, sortedPosts[1].Id);
} }
}
[Fact] [Fact]
public void FilteringOnNullWorks() public void FilteringOnNullWorks()
@ -663,11 +702,14 @@ namespace SieveUnitTests
Filters = "FeaturedComment.Text==null", Filters = "FeaturedComment.Text==null",
}; };
var result = _processor.Apply(model, posts); foreach (var sieveProcessor in GetProcessors())
{
var result = sieveProcessor.Apply(model, posts);
Assert.Equal(1, result.Count()); Assert.Equal(1, result.Count());
var filteredPosts = result.ToList(); var filteredPosts = result.ToList();
Assert.Equal(2, filteredPosts[0].Id); Assert.Equal(2, filteredPosts[0].Id);
} }
}
[Fact] [Fact]
public void BaseDefinedPropertyMappingSortingWorks_WithCustomName() public void BaseDefinedPropertyMappingSortingWorks_WithCustomName()
@ -677,16 +719,25 @@ namespace SieveUnitTests
Sorts = "-CreateDate" Sorts = "-CreateDate"
}; };
var result = _processor.Apply(model, _posts); foreach (var sieveProcessor in GetProcessors())
Assert.Equal(5, result.Count()); {
var result = sieveProcessor.Apply(model, _posts);
Assert.Equal(_posts.Count(), result.Count());
var posts = result.ToList(); var posts = result
Assert.Equal(4, posts[0].Id); .Select(post => post.Id)
Assert.Equal(3,posts[1].Id); .ToList();
Assert.Equal(2,posts[2].Id);
Assert.Equal(1,posts[3].Id);
Assert.Equal(0,posts[4].Id);
Assert.True
(
posts.SequenceEqual
(
_posts
.OrderByDescending(post => post.DateCreated)
.Select(post => post.Id)
)
);
}
} }
[Fact] [Fact]
@ -713,9 +764,12 @@ namespace SieveUnitTests
Filters = "Text==Here is\\, another comment" Filters = "Text==Here is\\, another comment"
}; };
var result = _processor.Apply(model, comments); foreach (var sieveProcessor in GetProcessors())
{
var result = sieveProcessor.Apply(model, comments);
Assert.Equal(1, result.Count()); Assert.Equal(1, result.Count());
} }
}
[Fact] [Fact]
public void OrEscapedPipeValueFilteringWorks() public void OrEscapedPipeValueFilteringWorks()
@ -747,9 +801,12 @@ namespace SieveUnitTests
Filters = @"Text==Here is \| a comment|Here is \| another comment|Here is \\\| another comment(1)", Filters = @"Text==Here is \| a comment|Here is \| another comment|Here is \\\| another comment(1)",
}; };
var result = _processor.Apply(model, comments); foreach (var sieveProcessor in GetProcessors())
{
var result = sieveProcessor.Apply(model, comments);
Assert.Equal(3, result.Count()); Assert.Equal(3, result.Count());
} }
}
[Theory] [Theory]
[InlineData("CategoryId==1,(CategoryId|LikeCount)==50")] [InlineData("CategoryId==1,(CategoryId|LikeCount)==50")]
@ -761,13 +818,16 @@ namespace SieveUnitTests
Filters = filter Filters = filter
}; };
var result = _processor.Apply(model, _posts); foreach (var sieveProcessor in GetProcessors())
{
var result = sieveProcessor.Apply(model, _posts);
var entry = result.FirstOrDefault(); var entry = result.FirstOrDefault();
var resultCount = result.Count(); var resultCount = result.Count();
Assert.NotNull(entry); Assert.NotNull(entry);
Assert.Equal(1, resultCount); Assert.Equal(1, resultCount);
} }
}
[Theory] [Theory]
[InlineData(@"Title@=\\")] [InlineData(@"Title@=\\")]
@ -792,13 +852,16 @@ namespace SieveUnitTests
Filters = filter Filters = filter
}; };
var result = _processor.Apply(model, posts); foreach (var sieveProcessor in GetProcessors())
{
var result = sieveProcessor.Apply(model, posts);
var entry = result.FirstOrDefault(); var entry = result.FirstOrDefault();
var resultCount = result.Count(); var resultCount = result.Count();
Assert.NotNull(entry); Assert.NotNull(entry);
Assert.Equal(1, resultCount); Assert.Equal(1, resultCount);
} }
}
[Theory] [Theory]
[InlineData(@"Title@=\== ")] [InlineData(@"Title@=\== ")]
@ -840,13 +903,15 @@ namespace SieveUnitTests
Filters = filter, Filters = filter,
}; };
var result = _processor.Apply(model, posts); foreach (var sieveProcessor in GetProcessors())
{
var result = sieveProcessor.Apply(model, posts);
var entry = result.FirstOrDefault(); var entry = result.FirstOrDefault();
var resultCount = result.Count(); var resultCount = result.Count();
Assert.NotNull(entry); Assert.NotNull(entry);
Assert.Equal(1, resultCount); Assert.Equal(1, resultCount);
} }
}
} }
} }

View File

@ -3,7 +3,6 @@ using System.Collections.Generic;
using System.Linq; using System.Linq;
using Sieve.Exceptions; using Sieve.Exceptions;
using Sieve.Models; using Sieve.Models;
using Sieve.Services;
using SieveUnitTests.Abstractions.Entity; using SieveUnitTests.Abstractions.Entity;
using SieveUnitTests.Entities; using SieveUnitTests.Entities;
using SieveUnitTests.Services; using SieveUnitTests.Services;
@ -12,28 +11,14 @@ using Xunit.Abstractions;
namespace SieveUnitTests namespace SieveUnitTests
{ {
public class GeneralWithInterfaces public class GeneralWithInterfaces: TestBase
{ {
private readonly ITestOutputHelper _testOutputHelper;
private readonly SieveProcessor _processor;
private readonly SieveProcessor _nullableProcessor;
private readonly IQueryable<IPost> _posts; private readonly IQueryable<IPost> _posts;
private readonly IQueryable<Comment> _comments; private readonly IQueryable<Comment> _comments;
public GeneralWithInterfaces(ITestOutputHelper testOutputHelper) public GeneralWithInterfaces(ITestOutputHelper testOutputHelper)
: base(testOutputHelper)
{ {
var nullableAccessor = new SieveOptionsAccessor();
nullableAccessor.Value.IgnoreNullsOnNotEqual = false;
_testOutputHelper = testOutputHelper;
_processor = new ApplicationSieveProcessor(new SieveOptionsAccessor(),
new SieveCustomSortMethods(),
new SieveCustomFilterMethods());
_nullableProcessor = new ApplicationSieveProcessor(nullableAccessor,
new SieveCustomSortMethods(),
new SieveCustomFilterMethods());
_posts = new List<IPost> _posts = new List<IPost>
{ {
new Post new Post
@ -44,7 +29,8 @@ namespace SieveUnitTests
IsDraft = true, IsDraft = true,
CategoryId = null, CategoryId = null,
TopComment = new Comment { Id = 0, Text = "A1" }, TopComment = new Comment { Id = 0, Text = "A1" },
FeaturedComment = new Comment { Id = 4, Text = "A2" } FeaturedComment = new Comment { Id = 4, Text = "A2" },
DeletedBy = "Me"
}, },
new Post new Post
{ {
@ -54,7 +40,9 @@ namespace SieveUnitTests
IsDraft = false, IsDraft = false,
CategoryId = 1, CategoryId = 1,
TopComment = new Comment { Id = 3, Text = "B1" }, TopComment = new Comment { Id = 3, Text = "B1" },
FeaturedComment = new Comment { Id = 5, Text = "B2" } FeaturedComment = new Comment { Id = 5, Text = "B2" },
DeletedBy = "You",
UpdatedBy = "Me"
}, },
new Post new Post
{ {
@ -63,7 +51,9 @@ namespace SieveUnitTests
LikeCount = 0, LikeCount = 0,
CategoryId = 1, CategoryId = 1,
TopComment = new Comment { Id = 2, Text = "C1" }, TopComment = new Comment { Id = 2, Text = "C1" },
FeaturedComment = new Comment { Id = 6, Text = "C2" } FeaturedComment = new Comment { Id = 6, Text = "C2" },
DeletedBy = "Not Me",
UpdatedBy = "Your highness"
}, },
new Post new Post
{ {
@ -73,8 +63,29 @@ namespace SieveUnitTests
IsDraft = true, IsDraft = true,
CategoryId = 2, CategoryId = 2,
TopComment = new Comment { Id = 1, Text = "D1" }, TopComment = new Comment { Id = 1, Text = "D1" },
FeaturedComment = new Comment { Id = 7, Text = "D2" } FeaturedComment = new Comment { Id = 7, Text = "D2" },
UpdatedBy = "Him"
}, },
new Post
{
Id = 4,
Title = "E",
LikeCount = 5,
IsDraft = false,
CategoryId = null,
TopComment = new Comment { Id = 4, Text = "E1" },
UpdatedBy = "You"
},
new Post
{
Id = 5,
Title = "Yen",
LikeCount = 5,
IsDraft = true,
CategoryId = 5,
TopComment = new Comment { Id = 4, Text = "Yen3" },
FeaturedComment = new Comment { Id = 8, Text = "Yen4" }
}
}.AsQueryable(); }.AsQueryable();
_comments = new List<Comment> _comments = new List<Comment>
@ -108,11 +119,14 @@ namespace SieveUnitTests
Filters = "Title@=*a" Filters = "Title@=*a"
}; };
var result = _processor.Apply(model, _posts); foreach (var sieveProcessor in GetProcessors())
{
var result = sieveProcessor.Apply(model, _posts);
Assert.Equal(0, result.First().Id); Assert.Equal(0, result.First().Id);
Assert.True(result.Count() == 1); Assert.True(result.Count() == 1);
} }
}
[Fact] [Fact]
public void NotEqualsCanBeCaseInsensitive() public void NotEqualsCanBeCaseInsensitive()
@ -122,24 +136,27 @@ namespace SieveUnitTests
Filters = "Title!=*a" Filters = "Title!=*a"
}; };
var result = _processor.Apply(model, _posts); foreach (var sieveProcessor in GetProcessors())
{
var result = sieveProcessor.Apply(model, _posts);
Assert.Equal(1, result.First().Id); Assert.Equal(1, result.First().Id);
Assert.True(result.Count() == 3); Assert.True(result.Count() == _posts.Count(post => !post.Title.Contains("a", StringComparison.OrdinalIgnoreCase)));
}
} }
[Fact] [Fact]
public void ContainsIsCaseSensitive() public void ContainsIsCaseSensitive()
{ {
var model = new SieveModel var model = new SieveModel { Filters = "Title@=a", };
{
Filters = "Title@=a",
};
var result = _processor.Apply(model, _posts); foreach (var sieveProcessor in GetProcessors())
{
var result = sieveProcessor.Apply(model, _posts);
Assert.True(!result.Any()); Assert.True(!result.Any());
} }
}
[Fact] [Fact]
public void NotContainsWorks() public void NotContainsWorks()
@ -149,154 +166,159 @@ namespace SieveUnitTests
Filters = "Title!@=D", Filters = "Title!@=D",
}; };
var result = _processor.Apply(model, _posts); foreach (var sieveProcessor in GetProcessors())
{
var result = sieveProcessor.Apply(model, _posts);
Assert.True(result.Count() == 3); Assert.True(result.Count() == _posts.Count(post => !post.Title.Contains("D")));
}
} }
[Fact] [Fact]
public void CanFilterBools() public void CanFilterBools()
{ {
var model = new SieveModel var model = new SieveModel { Filters = "IsDraft==false" };
foreach (var sieveProcessor in GetProcessors())
{ {
Filters = "IsDraft==false" var result = sieveProcessor.Apply(model, _posts);
};
var result = _processor.Apply(model, _posts); Assert.True(result.Count() == _posts.Count(post => !post.IsDraft));
}
Assert.True(result.Count() == 2);
} }
[Fact] [Fact]
public void CanSortBools() public void CanSortBools()
{ {
var model = new SieveModel var model = new SieveModel { Sorts = "-IsDraft" };
{
Sorts = "-IsDraft"
};
var result = _processor.Apply(model, _posts); foreach (var sieveProcessor in GetProcessors())
{
var result = sieveProcessor.Apply(model, _posts);
Assert.Equal(0, result.First().Id); Assert.Equal(0, result.First().Id);
} }
}
[Fact] [Fact]
public void CanFilterNullableInts() public void CanFilterNullableInts()
{ {
var model = new SieveModel var model = new SieveModel { Filters = "CategoryId==1" };
foreach (var sieveProcessor in GetProcessors())
{ {
Filters = "CategoryId==1" var result = sieveProcessor.Apply(model, _posts);
};
var result = _processor.Apply(model, _posts); Assert.True(result.Count() == _posts.Count(post => post.CategoryId == 1));
var nullableResult = _nullableProcessor.Apply(model, _posts); }
Assert.True(result.Count() == 2);
Assert.True(nullableResult.Count() == 2);
} }
[Fact] [Fact]
public void CanFilterNullableIntsWithNotEqual() public void CanFilterNullableIntsWithNotEqual()
{ {
var model = new SieveModel() var model = new SieveModel() { Filters = "CategoryId!=1" };
foreach (var sieveProcessor in GetProcessors())
{ {
Filters = "CategoryId!=1" var result = sieveProcessor.Apply(model, _posts);
};
var result = _processor.Apply(model, _posts); Assert.Equal
var nullableResult = _nullableProcessor.Apply(model, _posts); (
(sieveProcessor as ApplicationSieveProcessor)?.ExposedOptions.IgnoreNullsOnNotEqual ?? true
Assert.True(result.Count() == 1); ? _posts.Count(post => post.CategoryId != null && post.CategoryId != 1)
Assert.True(nullableResult.Count() == 2); : _posts.Count(post => post.CategoryId != 1),
result.Count()
);
}
} }
[Fact] [Fact]
public void EqualsDoesntFailWithNonStringTypes() public void EqualsDoesntFailWithNonStringTypes()
{ {
var model = new SieveModel var model = new SieveModel { Filters = "LikeCount==50", };
TestOutputHelper.WriteLine(model.GetFiltersParsed()[0].Values.ToString());
TestOutputHelper.WriteLine(model.GetFiltersParsed()[0].Operator);
TestOutputHelper.WriteLine(model.GetFiltersParsed()[0].OperatorParsed.ToString());
foreach (var sieveProcessor in GetProcessors())
{ {
Filters = "LikeCount==50", var result = sieveProcessor.Apply(model, _posts);
};
_testOutputHelper.WriteLine(model.GetFiltersParsed()[0].Values.ToString());
_testOutputHelper.WriteLine(model.GetFiltersParsed()[0].Operator);
_testOutputHelper.WriteLine(model.GetFiltersParsed()[0].OperatorParsed.ToString());
var result = _processor.Apply(model, _posts);
Assert.Equal(1, result.First().Id); Assert.Equal(1, result.First().Id);
Assert.True(result.Count() == 1); Assert.True(result.Count() == 1);
} }
}
[Fact] [Fact]
public void CustomFiltersWork() public void CustomFiltersWork()
{ {
var model = new SieveModel var model = new SieveModel { Filters = "Isnew", };
{
Filters = "Isnew",
};
var result = _processor.Apply(model, _posts); foreach (var sieveProcessor in GetProcessors())
{
var result = sieveProcessor.Apply(model, _posts);
Assert.False(result.Any(p => p.Id == 0)); Assert.False(result.Any(p => p.Id == 0));
Assert.True(result.Count() == 3); Assert.True(result.Count() == _posts.Count(SieveCustomFilterMethods.IsNewFilterForIPost));
}
} }
[Fact] [Fact]
public void CustomGenericFiltersWork() public void CustomGenericFiltersWork()
{ {
var model = new SieveModel var model = new SieveModel { Filters = "Latest", };
{
Filters = "Latest",
};
var result = _processor.Apply(model, _comments); foreach (var sieveProcessor in GetProcessors())
{
var result = sieveProcessor.Apply(model, _comments);
Assert.False(result.Any(p => p.Id == 0)); Assert.False(result.Any(p => p.Id == 0));
Assert.True(result.Count() == 2); Assert.True(result.Count() == 2);
} }
}
[Fact] [Fact]
public void CustomFiltersWithOperatorsWork() public void CustomFiltersWithOperatorsWork()
{ {
var model = new SieveModel var model = new SieveModel { Filters = "HasInTitle==A", };
{
Filters = "HasInTitle==A",
};
var result = _processor.Apply(model, _posts); foreach (var sieveProcessor in GetProcessors())
{
var result = sieveProcessor.Apply(model, _posts);
Assert.True(result.Any(p => p.Id == 0)); Assert.True(result.Any(p => p.Id == 0));
Assert.True(result.Count() == 1); Assert.True(result.Count() == 1);
} }
}
[Fact] [Fact]
public void CustomFiltersMixedWithUsualWork1() public void CustomFiltersMixedWithUsualWork1()
{ {
var model = new SieveModel var model = new SieveModel { Filters = "Isnew,CategoryId==2", };
{
Filters = "Isnew,CategoryId==2",
};
var result = _processor.Apply(model, _posts); foreach (var sieveProcessor in GetProcessors())
{
var result = sieveProcessor.Apply(model, _posts);
Assert.True(result.Any(p => p.Id == 3)); Assert.True(result.Any(p => p.Id == 3));
Assert.True(result.Count() == 1); Assert.True(result.Count() == 1);
} }
}
[Fact] [Fact]
public void CustomFiltersMixedWithUsualWork2() public void CustomFiltersMixedWithUsualWork2()
{ {
var model = new SieveModel var model = new SieveModel { Filters = "CategoryId==2,Isnew", };
{
Filters = "CategoryId==2,Isnew",
};
var result = _processor.Apply(model, _posts); foreach (var sieveProcessor in GetProcessors())
{
var result = sieveProcessor.Apply(model, _posts);
Assert.True(result.Any(p => p.Id == 3)); Assert.True(result.Any(p => p.Id == 3));
Assert.True(result.Count() == 1); Assert.True(result.Count() == 1);
} }
}
[Fact] [Fact]
public void CustomFiltersOnDifferentSourcesCanShareName() public void CustomFiltersOnDifferentSourcesCanShareName()
@ -306,79 +328,84 @@ namespace SieveUnitTests
Filters = "CategoryId==2,Isnew", Filters = "CategoryId==2,Isnew",
}; };
var postResult = _processor.Apply(postModel, _posts); foreach (var sieveProcessor in GetProcessors())
{
var postResult = sieveProcessor.Apply(postModel, _posts);
Assert.True(postResult.Any(p => p.Id == 3)); Assert.True(postResult.Any(p => p.Id == 3));
Assert.Equal(1, postResult.Count()); Assert.Equal(1, postResult.Count());
}
var commentModel = new SieveModel var commentModel = new SieveModel
{ {
Filters = "Isnew", Filters = "Isnew",
}; };
var commentResult = _processor.Apply(commentModel, _comments); foreach (var sieveProcessor in GetProcessors())
{
var commentResult = sieveProcessor.Apply(commentModel, _comments);
Assert.True(commentResult.Any(c => c.Id == 2)); Assert.True(commentResult.Any(c => c.Id == 2));
Assert.Equal(2, commentResult.Count()); Assert.Equal(2, commentResult.Count());
} }
}
[Fact] [Fact]
public void CustomSortsWork() public void CustomSortsWork()
{ {
var model = new SieveModel var model = new SieveModel { Sorts = "Popularity", };
{
Sorts = "Popularity",
};
var result = _processor.Apply(model, _posts); foreach (var sieveProcessor in GetProcessors())
{
var result = sieveProcessor.Apply(model, _posts);
Assert.False(result.First().Id == 0); Assert.False(result.First().Id == 0);
} }
}
[Fact] [Fact]
public void CustomGenericSortsWork() public void CustomGenericSortsWork()
{ {
var model = new SieveModel var model = new SieveModel { Sorts = "Oldest", };
{
Sorts = "Oldest",
};
var result = _processor.Apply(model, _posts); foreach (var sieveProcessor in GetProcessors())
{
var result = sieveProcessor.Apply(model, _posts);
Assert.True(result.Last().Id == 0); Assert.True(result.Last().Id == 0);
} }
}
[Fact] [Fact]
public void MethodNotFoundExceptionWork() public void MethodNotFoundExceptionWork()
{ {
var model = new SieveModel var model = new SieveModel { Filters = "does not exist", };
{
Filters = "does not exist",
};
Assert.Throws<SieveMethodNotFoundException>(() => _processor.Apply(model, _posts)); foreach (var sieveProcessor in GetProcessors())
{
Assert.Throws<SieveMethodNotFoundException>(() => sieveProcessor.Apply(model, _posts));
}
} }
[Fact] [Fact]
public void IncompatibleMethodExceptionsWork() public void IncompatibleMethodExceptionsWork()
{ {
var model = new SieveModel var model = new SieveModel { Filters = "TestComment", };
{
Filters = "TestComment",
};
Assert.Throws<SieveIncompatibleMethodException>(() => _processor.Apply(model, _posts)); foreach (var sieveProcessor in GetProcessors())
{
Assert.Throws<SieveIncompatibleMethodException>(() => sieveProcessor.Apply(model, _posts));
}
} }
[Fact] [Fact]
public void OrNameFilteringWorks() public void OrNameFilteringWorks()
{ {
var model = new SieveModel var model = new SieveModel { Filters = "(Title|LikeCount)==3", };
{
Filters = "(Title|LikeCount)==3",
};
var result = _processor.Apply(model, _posts); foreach (var sieveProcessor in GetProcessors())
{
var result = sieveProcessor.Apply(model, _posts);
var entry = result.FirstOrDefault(); var entry = result.FirstOrDefault();
var resultCount = result.Count(); var resultCount = result.Count();
@ -386,34 +413,34 @@ namespace SieveUnitTests
Assert.Equal(1, resultCount); Assert.Equal(1, resultCount);
Assert.Equal(3, entry.Id); Assert.Equal(3, entry.Id);
} }
}
[Theory] [Theory]
[InlineData("CategoryId==1,(CategoryId|LikeCount)==50")] [InlineData("CategoryId==1,(CategoryId|LikeCount)==50")]
[InlineData("(CategoryId|LikeCount)==50,CategoryId==1")] [InlineData("(CategoryId|LikeCount)==50,CategoryId==1")]
public void CombinedAndOrFilterIndependentOfOrder(string filter) public void CombinedAndOrFilterIndependentOfOrder(string filter)
{ {
var model = new SieveModel var model = new SieveModel { Filters = filter, };
{
Filters = filter,
};
var result = _processor.Apply(model, _posts); foreach (var sieveProcessor in GetProcessors())
{
var result = sieveProcessor.Apply(model, _posts);
var entry = result.FirstOrDefault(); var entry = result.FirstOrDefault();
var resultCount = result.Count(); var resultCount = result.Count();
Assert.NotNull(entry); Assert.NotNull(entry);
Assert.Equal(1, resultCount); Assert.Equal(1, resultCount);
} }
}
[Fact] [Fact]
public void CombinedAndOrWithSpaceFilteringWorks() public void CombinedAndOrWithSpaceFilteringWorks()
{ {
var model = new SieveModel var model = new SieveModel { Filters = "Title==D, (Title|LikeCount)==3", };
{
Filters = "Title==D, (Title|LikeCount)==3",
};
var result = _processor.Apply(model, _posts); foreach (var sieveProcessor in GetProcessors())
{
var result = sieveProcessor.Apply(model, _posts);
var entry = result.FirstOrDefault(); var entry = result.FirstOrDefault();
var resultCount = result.Count(); var resultCount = result.Count();
@ -421,65 +448,77 @@ namespace SieveUnitTests
Assert.Equal(1, resultCount); Assert.Equal(1, resultCount);
Assert.Equal(3, entry.Id); Assert.Equal(3, entry.Id);
} }
}
[Fact] [Fact]
public void OrValueFilteringWorks() public void OrValueFilteringWorks()
{ {
var model = new SieveModel var model = new SieveModel { Filters = "Title==C|D", };
{
Filters = "Title==C|D",
};
var result = _processor.Apply(model, _posts); foreach (var sieveProcessor in GetProcessors())
{
var result = sieveProcessor.Apply(model, _posts);
Assert.Equal(2, result.Count()); Assert.Equal(2, result.Count());
Assert.True(result.Any(p => p.Id == 2)); Assert.True(result.Any(p => p.Id == 2));
Assert.True(result.Any(p => p.Id == 3)); Assert.True(result.Any(p => p.Id == 3));
} }
}
[Fact] [Fact]
public void OrValueFilteringWorks2() public void OrValueFilteringWorks2()
{ {
var model = new SieveModel var model = new SieveModel { Filters = "Text@=(|)", };
{
Filters = "Text@=(|)",
};
var result = _processor.Apply(model, _comments); foreach (var sieveProcessor in GetProcessors())
{
var result = sieveProcessor.Apply(model, _comments);
Assert.Equal(1, result.Count()); Assert.Equal(1, result.Count());
Assert.Equal(2, result.FirstOrDefault()?.Id); Assert.Equal(2, result.FirstOrDefault()?.Id);
} }
}
[Fact] [Fact]
public void NestedFilteringWorks() public void NestedFilteringWorks()
{ {
var model = new SieveModel var model = new SieveModel { Filters = "TopComment.Text!@=A", };
{
Filters = "TopComment.Text!@=A",
};
var result = _processor.Apply(model, _posts); foreach (var sieveProcessor in GetProcessors())
Assert.Equal(3, result.Count()); {
var result = sieveProcessor.Apply(model, _posts);
Assert.Equal(_posts.Count(post => !post.TopComment.Text.Contains("A")), result.Count());
var posts = result.ToList(); var posts = result.ToList();
Assert.Contains("B", posts[0].TopComment.Text); Assert.Contains("B", posts[0].TopComment.Text);
Assert.Contains("C", posts[1].TopComment.Text); Assert.Contains("C", posts[1].TopComment.Text);
Assert.Contains("D", posts[2].TopComment.Text); Assert.Contains("D", posts[2].TopComment.Text);
Assert.Contains("E1", posts[3].TopComment.Text);
Assert.Contains("Yen", posts[4].TopComment.Text);
}
} }
[Fact] [Fact]
public void NestedSortingWorks() public void NestedSortingWorks()
{ {
var model = new SieveModel var model = new SieveModel { Sorts = "TopComment.Id", };
{
Sorts = "TopComment.Id",
};
var result = _processor.Apply(model, _posts); foreach (var sieveProcessor in GetProcessors())
Assert.Equal(4, result.Count()); {
var posts = result.ToList(); var result = sieveProcessor.Apply(model, _posts);
Assert.Equal(0, posts[0].Id); Assert.Equal(_posts.Count(), result.Count());
Assert.Equal(3, posts[1].Id); var posts = result
Assert.Equal(2, posts[2].Id); .Select(post => post.Id)
Assert.Equal(1, posts[3].Id); .ToList();
Assert.True
(
posts.SequenceEqual
(
_posts
.AsEnumerable()
.OrderBy(post => post.TopComment.Id)
.Select(post => post.Id)
)
);
}
} }
[Fact] [Fact]
@ -490,17 +529,23 @@ namespace SieveUnitTests
Filters = "(topc|featc)@=*2", Filters = "(topc|featc)@=*2",
}; };
var result = _processor.Apply(model, _posts); foreach (var sieveProcessor in GetProcessors())
{
var result = sieveProcessor.Apply(model, _posts);
Assert.Equal(4, result.Count()); Assert.Equal(4, result.Count());
}
model = new SieveModel model = new SieveModel
{ {
Filters = "(topc|featc)@=*B", Filters = "(topc|featc)@=*B",
}; };
result = _processor.Apply(model, _posts); foreach (var sieveProcessor in GetProcessors())
{
var result = sieveProcessor.Apply(model, _posts);
Assert.Equal(1, result.Count()); Assert.Equal(1, result.Count());
} }
}
[Fact] [Fact]
public void FilteringNullsWorks() public void FilteringNullsWorks()
@ -519,14 +564,14 @@ namespace SieveUnitTests
}, },
}.AsQueryable(); }.AsQueryable();
var model = new SieveModel var model = new SieveModel { Filters = "FeaturedComment.Text!@=Some value", };
{
Filters = "FeaturedComment.Text!@=Some value",
};
var result = _processor.Apply(model, posts); foreach (var sieveProcessor in GetProcessors())
{
var result = sieveProcessor.Apply(model, posts);
Assert.Equal(0, result.Count()); Assert.Equal(0, result.Count());
} }
}
[Fact] [Fact]
public void SortingNullsWorks() public void SortingNullsWorks()
@ -555,17 +600,17 @@ namespace SieveUnitTests
}, },
}.AsQueryable(); }.AsQueryable();
var model = new SieveModel var model = new SieveModel { Sorts = "TopComment.Id", };
{
Sorts = "TopComment.Id",
};
var result = _processor.Apply(model, posts); foreach (var sieveProcessor in GetProcessors())
{
var result = sieveProcessor.Apply(model, posts);
Assert.Equal(2, result.Count()); Assert.Equal(2, result.Count());
var sortedPosts = result.ToList(); var sortedPosts = result.ToList();
Assert.Equal(2, sortedPosts[0].Id); Assert.Equal(2, sortedPosts[0].Id);
Assert.Equal(1, sortedPosts[1].Id); Assert.Equal(1, sortedPosts[1].Id);
} }
}
[Fact] [Fact]
public void FilteringOnNullWorks() public void FilteringOnNullWorks()
@ -594,33 +639,94 @@ namespace SieveUnitTests
}, },
}.AsQueryable(); }.AsQueryable();
var model = new SieveModel var model = new SieveModel { Filters = "FeaturedComment.Text==null", };
{
Filters = "FeaturedComment.Text==null",
};
var result = _processor.Apply(model, posts); foreach (var sieveProcessor in GetProcessors())
{
var result = sieveProcessor.Apply(model, posts);
Assert.Equal(1, result.Count()); Assert.Equal(1, result.Count());
var filteredPosts = result.ToList(); var filteredPosts = result.ToList();
Assert.Equal(2, filteredPosts[0].Id); Assert.Equal(2, filteredPosts[0].Id);
} }
}
[Fact] [Fact]
public void BaseDefinedPropertyMappingSortingWorks_WithCustomName() public void BaseDefinedPropertyMappingSortingWorks_WithCustomName()
{ {
var model = new SieveModel var model = new SieveModel { Sorts = "-CreateDate" };
foreach (var sieveProcessor in GetProcessors())
{ {
Sorts = "-CreateDate" var result = sieveProcessor.Apply(model, _posts);
}; Assert.Equal(_posts.Count(), result.Count());
var result = _processor.Apply(model, _posts); var posts = result
Assert.Equal(4, result.Count()); .Select(post => post.Id)
.ToList();
var posts = result.ToList(); Assert.True
Assert.Equal(3,posts[0].Id); (
Assert.Equal(2,posts[1].Id); posts.SequenceEqual
Assert.Equal(1,posts[2].Id); (
Assert.Equal(0,posts[3].Id); _posts
.OrderByDescending(post => post.DateCreated)
.Select(post => post.Id)
)
);
}
}
[Theory]
[InlineData("DeletedBy")]
[InlineData("-DeletedBy")]
public void CanSortWithInterfaceProperties(string sort)
{
var model = new SieveModel { Sorts = sort };
foreach (var sieveProcessor in GetProcessors())
{
var result = sieveProcessor.Apply(model, _posts);
var entry = result.FirstOrDefault();
var resultCount = result.Count();
Assert.NotNull(entry);
Assert.Equal(_posts.Count(), resultCount);
}
}
[Theory]
[InlineData("UpdatedBy==Me", 1, 1, new [] {1})]
[InlineData("UpdatedBy==Me|You", 2, 2, null)]
[InlineData("UpdatedBy==You|Me", 2, 2, null)]
[InlineData("UpdatedBy!=Him", 5, 3, null)]
[InlineData("UpdatedBy_=*You", 2, 2, null)]
public void CanFilterWithInterfaceProperties(string filters, int recordCount, int nullIgnoredRecordCount, int[] filteredIds)
{
var model = new SieveModel { Filters = filters, Sorts = "Id" };
foreach (var sieveProcessor in GetProcessors())
{
var result = sieveProcessor.Apply(model, _posts);
var resultCount = result.Count();
Assert.Equal
(
(sieveProcessor as ApplicationSieveProcessor)?.ExposedOptions.IgnoreNullsOnNotEqual ?? true
? nullIgnoredRecordCount
: recordCount,
resultCount
);
if (filteredIds != null)
{
Assert.True
(
result
.Select(post => post.Id)
.SequenceEqual(filteredIds)
);
}
}
} }
} }
} }

View File

@ -16,62 +16,20 @@ namespace SieveUnitTests.Services
{ {
} }
public SieveOptions ExposedOptions => new SieveOptions()
{
IgnoreNullsOnNotEqual = Options.Value.IgnoreNullsOnNotEqual,
CaseSensitive = Options.Value.CaseSensitive,
DefaultPageSize = Options.Value.DefaultPageSize,
DisableNullableTypeExpressionForSorting = Options.Value.DisableNullableTypeExpressionForSorting,
MaxPageSize = Options.Value.MaxPageSize,
ThrowExceptions = Options.Value.ThrowExceptions,
};
protected override SievePropertyMapper MapProperties(SievePropertyMapper mapper) protected override SievePropertyMapper MapProperties(SievePropertyMapper mapper)
{ {
mapper.Property<Post>(p => p.ThisHasNoAttributeButIsAccessible) SieveConfigurationForPost.ConfigureStatic(mapper);
.CanSort() SieveConfigurationForIPost.ConfigureStatic(mapper);
.CanFilter()
.HasName("shortname");
mapper.Property<Post>(p => p.TopComment.Text)
.CanFilter();
mapper.Property<Post>(p => p.TopComment.Id)
.CanSort();
mapper.Property<Post>(p => p.OnlySortableViaFluentApi)
.CanSort();
mapper.Property<Post>(p => p.TopComment.Text)
.CanFilter()
.HasName("topc");
mapper.Property<Post>(p => p.FeaturedComment.Text)
.CanFilter()
.HasName("featc");
mapper
.Property<Post>(p => p.DateCreated)
.CanSort()
.HasName("CreateDate");
// interfaces
mapper.Property<IPost>(p => p.ThisHasNoAttributeButIsAccessible)
.CanSort()
.CanFilter()
.HasName("shortname");
mapper.Property<IPost>(p => p.TopComment.Text)
.CanFilter();
mapper.Property<IPost>(p => p.TopComment.Id)
.CanSort();
mapper.Property<IPost>(p => p.OnlySortableViaFluentApi)
.CanSort();
mapper.Property<IPost>(p => p.TopComment.Text)
.CanFilter()
.HasName("topc");
mapper.Property<IPost>(p => p.FeaturedComment.Text)
.CanFilter()
.HasName("featc");
mapper
.Property<IPost>(p => p.DateCreated)
.CanSort()
.HasName("CreateDate");
return mapper; return mapper;
} }

View File

@ -1,5 +1,6 @@
using System; using System;
using System.Linq; using System.Linq;
using System.Linq.Expressions;
using Sieve.Services; using Sieve.Services;
using SieveUnitTests.Abstractions.Entity; using SieveUnitTests.Abstractions.Entity;
using SieveUnitTests.Entities; using SieveUnitTests.Entities;
@ -8,9 +9,14 @@ namespace SieveUnitTests.Services
{ {
public class SieveCustomFilterMethods : ISieveCustomFilterMethods public class SieveCustomFilterMethods : ISieveCustomFilterMethods
{ {
internal static readonly Expression<Func<Post, bool>> IsNewFilterForPost = post => post.LikeCount < 100;
internal static readonly Expression<Func<IPost, bool>> IsNewFilterForIPost = post => post.LikeCount < 100;
internal static readonly Expression<Func<Comment, bool>> IsNewFilterForComment = comment => comment.DateCreated > DateTimeOffset.UtcNow.AddDays(-2);
internal static readonly Expression<Func<IComment, bool>> IsNewFilterForIComment = comment => comment.DateCreated > DateTimeOffset.UtcNow.AddDays(-2);
public IQueryable<Post> IsNew(IQueryable<Post> source, string op, string[] values) public IQueryable<Post> IsNew(IQueryable<Post> source, string op, string[] values)
{ {
var result = source.Where(p => p.LikeCount < 100); var result = source.Where(IsNewFilterForPost);
return result; return result;
} }
@ -24,7 +30,7 @@ namespace SieveUnitTests.Services
public IQueryable<Comment> IsNew(IQueryable<Comment> source, string op, string[] values) public IQueryable<Comment> IsNew(IQueryable<Comment> source, string op, string[] values)
{ {
var result = source.Where(c => c.DateCreated > DateTimeOffset.UtcNow.AddDays(-2)); var result = source.Where(IsNewFilterForComment);
return result; return result;
} }
@ -42,7 +48,7 @@ namespace SieveUnitTests.Services
public IQueryable<IPost> IsNew(IQueryable<IPost> source, string op, string[] values) public IQueryable<IPost> IsNew(IQueryable<IPost> source, string op, string[] values)
{ {
var result = source.Where(p => p.LikeCount < 100); var result = source.Where(IsNewFilterForIPost);
return result; return result;
} }
@ -56,7 +62,7 @@ namespace SieveUnitTests.Services
public IQueryable<IComment> IsNew(IQueryable<IComment> source, string op, string[] values) public IQueryable<IComment> IsNew(IQueryable<IComment> source, string op, string[] values)
{ {
var result = source.Where(c => c.DateCreated > DateTimeOffset.UtcNow.AddDays(-2)); var result = source.Where(IsNewFilterForIComment);
return result; return result;
} }

View File

@ -9,6 +9,7 @@
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="16.7.1" /> <PackageReference Include="Microsoft.NET.Test.Sdk" Version="16.7.1" />
<PackageReference Include="Microsoft.Extensions.Options" Version="2.0.0" /> <PackageReference Include="Microsoft.Extensions.Options" Version="2.0.0" />
<PackageReference Include="xunit" Version="2.4.1" /> <PackageReference Include="xunit" Version="2.4.1" />
<PackageReference Include="Xunit.Combinatorial" Version="1.5.25" />
<PackageReference Include="xunit.runner.visualstudio" Version="2.4.3"> <PackageReference Include="xunit.runner.visualstudio" Version="2.4.3">
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets> <IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
<PrivateAssets>all</PrivateAssets> <PrivateAssets>all</PrivateAssets>

View File

@ -0,0 +1,48 @@
using System.Collections.Generic;
using Sieve.Services;
using SieveUnitTests.Services;
using Xunit.Abstractions;
namespace SieveUnitTests
{
public abstract class TestBase
{
protected TestBase(ITestOutputHelper testOutputHelper)
{
TestOutputHelper = testOutputHelper;
}
protected ITestOutputHelper TestOutputHelper { get; }
/// <summary>
/// Processors with the same mappings but configured via a different method.
/// </summary>
/// <returns></returns>
public static IEnumerable<ISieveProcessor> GetProcessors()
{
// normal processor
yield return new ApplicationSieveProcessor(
new SieveOptionsAccessor(),
new SieveCustomSortMethods(),
new SieveCustomFilterMethods());
// nullable processor
yield return new ApplicationSieveProcessor(
new SieveOptionsAccessor() { Value = { IgnoreNullsOnNotEqual = false } },
new SieveCustomSortMethods(),
new SieveCustomFilterMethods());
// modular processor
yield return new ModularConfigurationSieveProcessor(
new SieveOptionsAccessor(),
new SieveCustomSortMethods(),
new SieveCustomFilterMethods());
// modular processor with scan
yield return new ModularConfigurationWithScanSieveProcessor(
new SieveOptionsAccessor(),
new SieveCustomSortMethods(),
new SieveCustomFilterMethods());
}
}
}

View File

@ -1,6 +1,4 @@
using System; using System.ComponentModel;
using System.ComponentModel;
using System.Linq;
using Nuke.Common.Tooling; using Nuke.Common.Tooling;
[TypeConverter(typeof(TypeConverter<Configuration>))] [TypeConverter(typeof(TypeConverter<Configuration>))]