public void CombinationFilterNode_Equality_IsNotAffectedByGenericType() { IFilterNode <CharFilter> combination1 = new CombinationFilterNode <CharFilter>(new[] { new CharFilterSubClass('A'), new CharFilterSubClass('B') }); // Note combination2 is constructed using a more specific generic type than combination1. IFilterNode <CharFilter> combination2 = new CombinationFilterNode <CharFilterSubClass>(new[] { new CharFilterSubClass('A'), new CharFilterSubClass('B') }); Assert.Equal(combination1, combination2); Assert.Equal(combination2, combination1); }
public void CombinationFilter_OrOperator_GetPredicate_FiltersToExpectedResults() { var filter1 = new NumericRangeFilter(5, 10); var filter2 = new NumericRangeFilter(8, 15); var filter = new CombinationFilterNode <NumericRangeFilter>(new[] { filter1, filter2 }, CombinationOperator.Any); var values = new[] { 1, 3, 5, 9, 11 }; var expectedFilteredValues = new[] { 5, 9, 11 }; var filterPredicate = filter.GetPredicate <NumericRangeFilter, int>(); var filteredValues = values.Where(filterPredicate); Assert.Equal(expectedFilteredValues, filteredValues); }
public void Collapse_ShouldRemoveDuplicates() { var filter = new CharFilter('A'); var leafFilterNode = filter.ToLeafFilterNode(); var combinationFilterNode = new CombinationFilterNode <CharFilter>(new[] { leafFilterNode, leafFilterNode }); var collapsedFilterNode = combinationFilterNode.Collapse(); var expectedFilterNode = filter.ToLeafFilterNode(); Assert.Equal(expectedFilterNode, collapsedFilterNode); // Also check IsEquivalentTo works, which internally uses Collapse. Assert.True(leafFilterNode.IsEquivalentTo(combinationFilterNode)); Assert.True(combinationFilterNode.IsEquivalentTo(leafFilterNode)); }
public void CombinationFilterNodeWithOperatorAll_ShouldPrecedeCombinationFilterNodeWithOperatorAny() { var allCombination = new CombinationFilterNode <CharFilter>(new[] { new CharFilter('B'), new CharFilter('C') }, CombinationOperator.All); var anyCombination = new CombinationFilterNode <CharFilter>(new[] { new CharFilter('B'), new CharFilter('C') }, CombinationOperator.Any); var sut = FilterNodeComparer <CharFilter> .Default; var result = sut.Compare(allCombination, anyCombination); Assert.Equal(-1, result); var oppositeResult = sut.Compare(anyCombination, allCombination); Assert.Equal(1, oppositeResult); }
public void InvertedFilterNode_ShouldPrecedeCombinationFilterNode() { var invertedFilterNode = new InvertedFilterNode <CharFilter>(new CharFilter('A')); var combinationFilterNode = new CombinationFilterNode <CharFilter>(new[] { new CharFilter('B'), new CharFilter('C') }); var sut = FilterNodeComparer <CharFilter> .Default; var result = sut.Compare(invertedFilterNode, combinationFilterNode); Assert.Equal(-1, result); var oppositeResult = sut.Compare(combinationFilterNode, invertedFilterNode); Assert.Equal(1, oppositeResult); }
public void CombinationFilterNodeComparison_ShouldUseLexicographicalListComparison() { var combination1 = new CombinationFilterNode <CharFilter>(new[] { new CharFilter('A'), new CharFilter('C') }); var combination2 = new CombinationFilterNode <CharFilter>(new[] { new CharFilter('A'), new CharFilter('B') }); var sut = FilterNodeComparer <CharFilter> .Default; var result = sut.Compare(combination1, combination2); Assert.Equal(1, result); var oppositeResult = sut.Compare(combination2, combination1); Assert.Equal(-1, oppositeResult); }
public void ComplexFilter_IsMatch_FiltersToExpectedResults() { var filter5To10 = new NumericRangeFilter(5, 10); var filter8To15 = new NumericRangeFilter(8, 15); var filter5To10Or8To15 = new CombinationFilterNode <NumericRangeFilter>(new[] { filter5To10, filter8To15 }, CombinationOperator.Any); var filter9To12 = new NumericRangeFilter(9, 12); var filter = new CombinationFilterNode <NumericRangeFilter>(new IFilterNode <NumericRangeFilter>[] { filter5To10Or8To15, filter9To12.ToLeafFilterNode() }, CombinationOperator.All); var values = new[] { 1, 3, 5, 9, 11 }; var expectedFilteredValues = new[] { 9, 11 }; var filteredValues = values.Where(filter.IsMatch); Assert.Equal(expectedFilteredValues, filteredValues); }
public void Collapse_ShouldFlattenNestedCombinations_WhenInnerOperatorMatchesOuter(CombinationOperator outerCombinationOperator, CombinationOperator alternateInnerCombinationOperator) { var filterA = new CharFilter('A'); var filterB = new CharFilter('B'); var filterC = new CharFilter('C'); var filterD = new CharFilter('D'); var filterE = new CharFilter('E'); var filterF = new CharFilter('F'); var filterG = new CharFilter('G'); var filterH = new CharFilter('H'); var innerCombinationFilterToFlatten = new CombinationFilterNode <CharFilter>(new [] { filterA, filterB }, outerCombinationOperator); var innerCombinationFilterToRetain1 = new CombinationFilterNode <CharFilter>(new [] { filterC, filterD }, alternateInnerCombinationOperator); var innerCombinationFilterToRetain2 = new CombinationFilterNode <CharFilter>(new[] { filterE, filterF }, alternateInnerCombinationOperator); // When outer operator == All and other == Any, this is equivalent to // (A AND B) AND (C OR D) AND (E OR F) AND G AND H // Which can be collapsed to: A AND B AND G AND H AND (C OR D) AND (E OR F) // When outer operator == Any and other == All, this is equivalent to // (A OR B) OR (C AND D) OR (E AND F) OR G OR H // Which can be collapsed to: A OR B OR G OR H OR (C AND D) OR (E AND F) var outerCombinationFilter = new CombinationFilterNode <CharFilter>(new IFilterNode <CharFilter>[] { innerCombinationFilterToFlatten, innerCombinationFilterToRetain1, innerCombinationFilterToRetain2, filterG.ToLeafFilterNode(), filterH.ToLeafFilterNode() }, outerCombinationOperator); var collapsedFilter = outerCombinationFilter.Collapse(); var expectedCollapsedFilter = new CombinationFilterNode <CharFilter>(new IFilterNode <CharFilter>[] { filterA.ToLeafFilterNode(), filterB.ToLeafFilterNode(), innerCombinationFilterToRetain1, innerCombinationFilterToRetain2, filterG.ToLeafFilterNode(), filterH.ToLeafFilterNode(), }, outerCombinationOperator); Assert.Equal(expectedCollapsedFilter, collapsedFilter); // Also check IsEquivalentTo works, which internally uses Collapse. Assert.True(collapsedFilter.IsEquivalentTo(outerCombinationFilter)); Assert.True(outerCombinationFilter.IsEquivalentTo(collapsedFilter)); }
public void Aggregate_ReturnsExpectedResult_WhenComputingLengthOfLongestInterval() { var filter5To10 = new NumericRangeFilter(5, 10); var filter8To15 = new NumericRangeFilter(8, 15); var filter5To10Or8To15 = new CombinationFilterNode <NumericRangeFilter>(new[] { filter5To10, filter8To15 }, CombinationOperator.Any); var filter9To12 = new NumericRangeFilter(9, 12); var filter = new CombinationFilterNode <NumericRangeFilter>(new IFilterNode <NumericRangeFilter>[] { filter5To10Or8To15, filter9To12.ToLeafFilterNode() }, CombinationOperator.All); // Reduce the filter to get the length of the longest interval var result = filter.Aggregate <double>( (lengths, _) => lengths.Max(), length => double.PositiveInfinity, leafFilterNode => leafFilterNode.Filter.UpperBound - leafFilterNode.Filter.LowerBound); // Max is 15 - 8 Assert.Equal(7, result); }
public void Bind_ReturnsCorrectStructureAndValues() { var filter5To10 = new NumericRangeFilter(5, 10); var filter8To15 = new NumericRangeFilter(8, 15); var filter5To10Or8To15 = new[] { filter5To10, filter8To15 }.Combine(CombinationOperator.Any); var filter9To12 = new NumericRangeFilter(9, 12); var filter = new[] { filter5To10Or8To15, filter9To12.ToLeafFilterNode() }.Combine(CombinationOperator.All); var result = filter.Bind <NumericRangeFilter>( f => { if (ReferenceEquals(f, filter5To10)) { return(new CombinationFilterNode <NumericRangeFilter>(new [] { filter5To10, filter8To15 }, CombinationOperator.Any)); } if (ReferenceEquals(f, filter8To15)) { return(FilterNode <NumericRangeFilter> .False); } if (ReferenceEquals(f, filter9To12)) { return(new InvertedFilterNode <NumericRangeFilter>(f)); } return(f.ToLeafFilterNode()); }); var expectedFilter = new CombinationFilterNode <NumericRangeFilter>( new IFilterNode <NumericRangeFilter>[] { new CombinationFilterNode <NumericRangeFilter>( new IFilterNode <NumericRangeFilter>[] { filter5To10Or8To15, FilterNode <NumericRangeFilter> .False }, CombinationOperator.Any), new InvertedFilterNode <NumericRangeFilter>(filter9To12), }, CombinationOperator.All); Assert.Equal(expectedFilter, result); }
public void Collapse_ShouldAbsorbRedundantNestedCombinations(CombinationOperator outerCombinationOperator, CombinationOperator alternateInnerCombinationOperator) { var filterA = new CharFilter('A'); var filterB = new CharFilter('B'); var filterC = new CharFilter('C'); var filterD = new CharFilter('D'); var filterE = new CharFilter('E'); var filterF = new CharFilter('F'); var filterG = new CharFilter('G'); var filterH = new CharFilter('H'); var innerCombinationFilterToFlatten = new CombinationFilterNode <CharFilter>(new[] { filterA, filterB }, outerCombinationOperator); var innerCombinationFilterToRetain = new CombinationFilterNode <CharFilter>(new[] { filterC, filterD }, alternateInnerCombinationOperator); var innerCombinationFilterToAbsorb = new CombinationFilterNode <CharFilter>(new[] { filterA, filterE }, alternateInnerCombinationOperator); var outerCombinationFilter = new CombinationFilterNode <CharFilter>(new IFilterNode <CharFilter>[] { innerCombinationFilterToFlatten, innerCombinationFilterToRetain, innerCombinationFilterToAbsorb, filterG.ToLeafFilterNode(), filterH.ToLeafFilterNode() }, outerCombinationOperator); var collapsedFilter = outerCombinationFilter.Collapse(); var expectedCollapsedFilter = new CombinationFilterNode <CharFilter>(new IFilterNode <CharFilter>[] { filterA.ToLeafFilterNode(), filterB.ToLeafFilterNode(), innerCombinationFilterToRetain, filterG.ToLeafFilterNode(), filterH.ToLeafFilterNode(), }, outerCombinationOperator); Assert.Equal(expectedCollapsedFilter, collapsedFilter); // Also check IsEquivalentTo works, which internally uses Collapse. Assert.True(collapsedFilter.IsEquivalentTo(outerCombinationFilter)); Assert.True(outerCombinationFilter.IsEquivalentTo(collapsedFilter)); }
public void GetPartial_Example() { // All the numbers from -5 to 10, EXCEPT numbers from 2 to 6 var filter = new CombinationFilterNode <NumericRangeFilter>(new IFilterNode <NumericRangeFilter>[] { new LeafFilterNode <NumericRangeFilter>(new NumericRangeFilter(-5, 10)), new InvertedFilterNode <NumericRangeFilter>(new NumericRangeFilter(2, 6)), }, CombinationOperator.All); // Exclude filters with negative values var partialFilter = filter.GetPartial(f => f.LowerBound >= 0); var positiveValues = new[] { 1, 3, 5, 7, 12 }; var prefilteredValues = positiveValues.Where(partialFilter.GetPredicate <NumericRangeFilter, int>()).ToList(); Assert.Equal(new[] { 1, 7, 12 }, prefilteredValues); var additionalValues = new[] { -7, -4, 11 }; var combinedValues = prefilteredValues.Concat(additionalValues); var finalValues = combinedValues.Where(filter.GetPredicate <NumericRangeFilter, int>()); Assert.Equal(new[] { 1, 7, -4 }, finalValues); }
public void Map_ReturnsCorrectStructureAndValues() { var filter5To10 = new NumericRangeFilter(5, 10); var filter8To15 = new NumericRangeFilter(8, 15); var filter5To10Or8To15 = new CombinationFilterNode <NumericRangeFilter>(new[] { filter5To10, filter8To15 }, CombinationOperator.Any); var filter9To12 = new NumericRangeFilter(9, 12); var filter = new CombinationFilterNode <NumericRangeFilter>(new IFilterNode <NumericRangeFilter>[] { filter5To10Or8To15, filter9To12.ToLeafFilterNode() }, CombinationOperator.All); var result = filter.Map( f => { var newLowerBound = f.LowerBound + 1; var newUpperBound = f.UpperBound - 1; return(new NumericRangeFilter(newLowerBound, newUpperBound)); }); var filter6To9 = new NumericRangeFilter(6, 9); var filter9To14 = new NumericRangeFilter(9, 14); var filter6To9Or9To14 = new CombinationFilterNode <NumericRangeFilter>(new[] { filter6To9, filter9To14 }, CombinationOperator.Any); var filter10To11 = new NumericRangeFilter(10, 11); var expectedFilter = new CombinationFilterNode <NumericRangeFilter>(new IFilterNode <NumericRangeFilter>[] { filter6To9Or9To14, filter10To11.ToLeafFilterNode() }, CombinationOperator.All); Assert.Equal(expectedFilter, result); }