private ISpecification <IEnumerable <Condition <TConditionType> > > BuildSpecification(IConditionNode <TConditionType> conditionNode, MatchModes matchMode) { return(conditionNode switch { IValueConditionNode <TConditionType> valueConditionNode => this.BuildSpecificationForValueNode(valueConditionNode, matchMode), ComposedConditionNode <TConditionType> composedConditionNode => this.BuildSpecificationForComposedNode(composedConditionNode, matchMode), _ => throw new NotSupportedException($"Unsupported condition node: '{conditionNode.GetType().Name}'."), });
public void Eval_GivenComposedConditionNodeWithAndOperatorAndUnknownConditionNodeWithSearchMode_ThrowsNotSupportedException() { // Arrange StubConditionNode <ConditionType> condition1 = new StubConditionNode <ConditionType>(); StringConditionNode <ConditionType> condition2 = new StringConditionNode <ConditionType>(ConditionType.IsoCurrency, Operators.NotEqual, "SGD"); ComposedConditionNode <ConditionType> composedConditionNode = new ComposedConditionNode <ConditionType>( LogicalOperators.Or, new IConditionNode <ConditionType>[] { condition1, condition2 }); IEnumerable <Condition <ConditionType> > conditions = new[] { new Condition <ConditionType> { Type = ConditionType.IsoCurrency, Value = "SGD" }, new Condition <ConditionType> { Type = ConditionType.IsoCountryCode, Value = "PT" } }; EvaluationOptions evaluationOptions = new EvaluationOptions { MatchMode = MatchModes.Search, ExcludeRulesWithoutSearchConditions = true }; Mock <IDeferredEval> mockDeferredEval = new Mock <IDeferredEval>(); mockDeferredEval.SetupSequence(x => x.GetDeferredEvalFor(It.IsAny <IValueConditionNode <ConditionType> >(), It.Is <MatchModes>(mm => mm == MatchModes.Exact))) .Returns(() => { return((c) => false); }) .Returns(() => { return((c) => true); }) .Throws(new NotImplementedException("Shouldn't have gotten any more deferred evals.")); ConditionsEvalEngine <ConditionType> sut = new ConditionsEvalEngine <ConditionType>(mockDeferredEval.Object); // Act NotSupportedException notSupportedException = Assert.Throws <NotSupportedException>(() => sut.Eval(composedConditionNode, conditions, evaluationOptions)); // Assert notSupportedException.Should().NotBeNull(); notSupportedException.Message.Should().Be("Unsupported condition node: 'StubConditionNode`1'."); mockDeferredEval.Verify(x => x.GetDeferredEvalFor(It.IsAny <IValueConditionNode <ConditionType> >(), It.Is <MatchModes>(mm => mm == MatchModes.Exact)), Times.Exactly(0)); }
public void Eval_GivenComposedConditionNodeWithAndOperatorAndMissingConditionWithSearchMode_EvalsAndReturnsResult() { // Arrange BooleanConditionNode <ConditionType> condition1 = new BooleanConditionNode <ConditionType>(ConditionType.IsVip, Operators.Equal, true); StringConditionNode <ConditionType> condition2 = new StringConditionNode <ConditionType>(ConditionType.IsoCurrency, Operators.NotEqual, "SGD"); ComposedConditionNode <ConditionType> composedConditionNode = new ComposedConditionNode <ConditionType>( LogicalOperators.Or, new IConditionNode <ConditionType>[] { condition1, condition2 }); IEnumerable <Condition <ConditionType> > conditions = new[] { new Condition <ConditionType> { Type = ConditionType.IsoCurrency, Value = "SGD" }, new Condition <ConditionType> { Type = ConditionType.IsoCountryCode, Value = "PT" } }; EvaluationOptions evaluationOptions = new EvaluationOptions { MatchMode = MatchModes.Search, ExcludeRulesWithoutSearchConditions = true }; Mock <IDeferredEval> mockDeferredEval = new Mock <IDeferredEval>(); mockDeferredEval.SetupSequence(x => x.GetDeferredEvalFor(It.IsAny <IValueConditionNode <ConditionType> >(), It.Is <MatchModes>(mm => mm == MatchModes.Exact))) .Returns(() => { return((c) => false); }) .Returns(() => { return((c) => true); }) .Throws(new NotImplementedException("Shouldn't have gotten any more deferred evals.")); ConditionsEvalEngine <ConditionType> sut = new ConditionsEvalEngine <ConditionType>(mockDeferredEval.Object); // Act bool actual = sut.Eval(composedConditionNode, conditions, evaluationOptions); // Assert actual.Should().BeFalse(); mockDeferredEval.Verify(x => x.GetDeferredEvalFor(It.IsAny <IValueConditionNode <ConditionType> >(), It.Is <MatchModes>(mm => mm == MatchModes.Exact)), Times.Exactly(0)); }
public void ComposedConditionNode_Init_GivenSetupWithChildConditionsAndLogicalOperator_ReturnsSettedValues() { // Arrange LogicalOperators expectedLogicalOperator = LogicalOperators.Eval; IEnumerable <IConditionNode <ConditionType> > expectedChildConditionNodes = new IConditionNode <ConditionType>[] { new Mock <IConditionNode <ConditionType> >().Object, new Mock <IConditionNode <ConditionType> >().Object }; ComposedConditionNode <ConditionType> sut = new ComposedConditionNode <ConditionType>(expectedLogicalOperator, expectedChildConditionNodes); // Act LogicalOperators actualLogicalOperator = sut.LogicalOperator; IEnumerable <IConditionNode <ConditionType> > actualChildConditionNodes = sut.ChildConditionNodes; // Assert actualLogicalOperator.Should().Be(expectedLogicalOperator); actualChildConditionNodes.Should().NotBeNull().And.BeSameAs(expectedChildConditionNodes); }
public void Eval_GivenComposedConditionNodeWithEvalOperator_ThrowsNotSupportedException() { // Arrange BooleanConditionNode <ConditionType> condition1 = new BooleanConditionNode <ConditionType>(ConditionType.IsVip, Operators.Equal, true); StringConditionNode <ConditionType> condition2 = new StringConditionNode <ConditionType>(ConditionType.IsoCurrency, Operators.NotEqual, "SGD"); ComposedConditionNode <ConditionType> composedConditionNode = new ComposedConditionNode <ConditionType>( LogicalOperators.Eval, new IConditionNode <ConditionType>[] { condition1, condition2 }); IEnumerable <Condition <ConditionType> > conditions = new[] { new Condition <ConditionType> { Type = ConditionType.IsoCurrency, Value = "SGD" }, new Condition <ConditionType> { Type = ConditionType.IsVip, Value = true } }; EvaluationOptions evaluationOptions = new EvaluationOptions { MatchMode = MatchModes.Exact }; Mock <IDeferredEval> mockDeferredEval = new Mock <IDeferredEval>(); ConditionsEvalEngine <ConditionType> sut = new ConditionsEvalEngine <ConditionType>(mockDeferredEval.Object); // Act NotSupportedException notSupportedException = Assert.Throws <NotSupportedException>(() => sut.Eval(composedConditionNode, conditions, evaluationOptions)); // Assert notSupportedException.Should().NotBeNull(); notSupportedException.Message.Should().Be("Unsupported logical operator: 'Eval'."); mockDeferredEval.Verify(x => x.GetDeferredEvalFor(It.IsAny <IValueConditionNode <ConditionType> >(), It.Is <MatchModes>(mm => mm == MatchModes.Exact)), Times.Never()); }
public void CreateRule_GivenRuleDataModelWithComposedNodeAndChildNodesOfEachDataType_ReturnsRuleInstance() { // Arrange dynamic content = new ExpandoObject(); content.Prop1 = 123; content.Prop2 = "Sample string"; content.Prop3 = 500.34m; ValueConditionNodeDataModel integerConditionNodeDataModel = new ValueConditionNodeDataModel { ConditionType = "SampleIntegerCondition", DataType = DataTypes.Integer, LogicalOperator = LogicalOperators.Eval, Operand = 20, Operator = Operators.GreaterThan }; ValueConditionNodeDataModel stringConditionNodeDataModel = new ValueConditionNodeDataModel { ConditionType = "SampleStringCondition", DataType = DataTypes.String, LogicalOperator = LogicalOperators.Eval, Operand = "TEST", Operator = Operators.Equal }; ValueConditionNodeDataModel decimalConditionNodeDataModel = new ValueConditionNodeDataModel { ConditionType = "SampleDecimalCondition", DataType = DataTypes.Decimal, LogicalOperator = LogicalOperators.Eval, Operand = 50.3m, Operator = Operators.LesserThanOrEqual }; ValueConditionNodeDataModel booleanConditionNodeDataModel = new ValueConditionNodeDataModel { ConditionType = "SampleBooleanCondition", DataType = DataTypes.Boolean, LogicalOperator = LogicalOperators.Eval, Operand = true, Operator = Operators.NotEqual }; RuleDataModel ruleDataModel = new RuleDataModel { Content = content, ContentType = "ContentTypeSample", DateBegin = new System.DateTime(2020, 1, 1), DateEnd = null, Id = ObjectId.GenerateNewId(), Name = "My rule used for testing purposes", Priority = 1, RootCondition = new ComposedConditionNodeDataModel { LogicalOperator = LogicalOperators.And, ChildConditionNodes = new ConditionNodeDataModel[] { integerConditionNodeDataModel, stringConditionNodeDataModel, decimalConditionNodeDataModel, booleanConditionNodeDataModel } } }; IContentSerializationProvider <ContentType> contentSerializationProvider = Mock.Of <IContentSerializationProvider <ContentType> >(); RuleFactory <ContentType, ConditionType> ruleFactory = new RuleFactory <ContentType, ConditionType>(contentSerializationProvider); // Act Rule <ContentType, ConditionType> rule = ruleFactory.CreateRule(ruleDataModel); // Assert rule.Should().NotBeNull(); rule.ContentContainer.Should().NotBeNull() .And.BeOfType <SerializedContentContainer <ContentType> >(); rule.DateBegin.Should().Be(ruleDataModel.DateBegin); rule.DateEnd.Should().BeNull(); rule.Name.Should().Be(ruleDataModel.Name); rule.Priority.Should().Be(ruleDataModel.Priority); rule.RootCondition.Should().BeOfType <ComposedConditionNode <ConditionType> >(); ComposedConditionNode <ConditionType> composedConditionNode = rule.RootCondition.As <ComposedConditionNode <ConditionType> >(); composedConditionNode.LogicalOperator.Should().Be(LogicalOperators.And); composedConditionNode.ChildConditionNodes.Should().HaveCount(4); IEnumerable <IntegerConditionNode <ConditionType> > integerConditionNodes = composedConditionNode.ChildConditionNodes.OfType <IntegerConditionNode <ConditionType> >(); integerConditionNodes.Should().HaveCount(1); IntegerConditionNode <ConditionType> integerConditionNode = integerConditionNodes.First(); integerConditionNode.Should().NotBeNull(); integerConditionNode.ConditionType.Should().Match <ConditionType>(x => x == Enum.Parse <ConditionType>(integerConditionNodeDataModel.ConditionType)); integerConditionNode.DataType.Should().Be(integerConditionNodeDataModel.DataType); integerConditionNode.LogicalOperator.Should().Be(integerConditionNodeDataModel.LogicalOperator); integerConditionNode.Operand.Should().Match(x => object.Equals(x, integerConditionNodeDataModel.Operand)); integerConditionNode.Operator.Should().Be(integerConditionNodeDataModel.Operator); IEnumerable <StringConditionNode <ConditionType> > stringConditionNodes = composedConditionNode.ChildConditionNodes.OfType <StringConditionNode <ConditionType> >(); stringConditionNodes.Should().HaveCount(1); StringConditionNode <ConditionType> stringConditionNode = stringConditionNodes.First(); stringConditionNode.Should().NotBeNull(); stringConditionNode.ConditionType.Should().Match <ConditionType>(x => x == Enum.Parse <ConditionType>(stringConditionNodeDataModel.ConditionType)); stringConditionNode.DataType.Should().Be(stringConditionNodeDataModel.DataType); stringConditionNode.LogicalOperator.Should().Be(stringConditionNodeDataModel.LogicalOperator); stringConditionNode.Operand.Should().Match(x => object.Equals(x, stringConditionNodeDataModel.Operand)); stringConditionNode.Operator.Should().Be(stringConditionNodeDataModel.Operator); IEnumerable <DecimalConditionNode <ConditionType> > decimalConditionNodes = composedConditionNode.ChildConditionNodes.OfType <DecimalConditionNode <ConditionType> >(); decimalConditionNodes.Should().HaveCount(1); DecimalConditionNode <ConditionType> decimalConditionNode = decimalConditionNodes.First(); decimalConditionNode.Should().NotBeNull(); decimalConditionNode.ConditionType.Should().Match <ConditionType>(x => x == Enum.Parse <ConditionType>(decimalConditionNodeDataModel.ConditionType)); decimalConditionNode.DataType.Should().Be(decimalConditionNodeDataModel.DataType); decimalConditionNode.LogicalOperator.Should().Be(decimalConditionNodeDataModel.LogicalOperator); decimalConditionNode.Operand.Should().Match(x => object.Equals(x, decimalConditionNodeDataModel.Operand)); decimalConditionNode.Operator.Should().Be(decimalConditionNodeDataModel.Operator); IEnumerable <BooleanConditionNode <ConditionType> > booleanConditionNodes = composedConditionNode.ChildConditionNodes.OfType <BooleanConditionNode <ConditionType> >(); booleanConditionNodes.Should().HaveCount(1); BooleanConditionNode <ConditionType> booleanConditionNode = booleanConditionNodes.First(); booleanConditionNode.Should().NotBeNull(); booleanConditionNode.ConditionType.Should().Match <ConditionType>(x => x == Enum.Parse <ConditionType>(booleanConditionNodeDataModel.ConditionType)); booleanConditionNode.DataType.Should().Be(booleanConditionNodeDataModel.DataType); booleanConditionNode.LogicalOperator.Should().Be(booleanConditionNodeDataModel.LogicalOperator); booleanConditionNode.Operand.Should().Be(Convert.ToBoolean(booleanConditionNodeDataModel.Operand)); booleanConditionNode.Operator.Should().Be(booleanConditionNodeDataModel.Operator); }