public void EnsureValid_GivenOptionsWithInvalidDefaultForDataType_ThrowsInvalidRulesEngineOptionsExceptionClaimingInvalidDefault(DataTypes dataType, object defaultValue) { // Arrange RulesEngineOptions rulesEngineOptions = RulesEngineOptions.NewWithDefaults(); rulesEngineOptions.DataTypeDefaults[dataType] = defaultValue; InvalidRulesEngineOptionsException actual = Assert.Throws <InvalidRulesEngineOptionsException>(() => { // Act RulesEngineOptionsValidator.EnsureValid(rulesEngineOptions); }); actual.Message.Should().Be($"Specified invalid default value for data type {dataType}: {defaultValue ?? "null"}."); }
public void GetDeferredEvalFor_GivenStringConditionNodeWithNoConditionSuppliedAndRulesEngineConfiguredToUseDataTypeDefaultWhenMissing_ReturnsFuncThatEvalsFalse() { // Arrange StringConditionNode <ConditionType> conditionNode = new StringConditionNode <ConditionType>(ConditionType.IsoCurrency, Operators.Equal, "EUR"); Mock <IOperatorEvalStrategy> mockOperatorEvalStrategy = new Mock <IOperatorEvalStrategy>(); mockOperatorEvalStrategy.Setup(x => x.Eval(It.IsAny <string>(), It.IsAny <string>())) .Returns(false); Mock <IOperatorEvalStrategyFactory> mockOperatorEvalStrategyFactory = new Mock <IOperatorEvalStrategyFactory>(); mockOperatorEvalStrategyFactory.Setup(x => x.GetOperatorEvalStrategy(It.IsAny <Operators>())) .Returns(mockOperatorEvalStrategy.Object); IEnumerable <Condition <ConditionType> > conditions = new Condition <ConditionType>[] { new Condition <ConditionType> { Type = ConditionType.IsoCountryCode, Value = "PT" } }; MatchModes matchMode = MatchModes.Exact; RulesEngineOptions rulesEngineOptions = RulesEngineOptions.NewWithDefaults(); rulesEngineOptions.MissingConditionBehavior = MissingConditionBehaviors.UseDataTypeDefault; DeferredEval sut = new DeferredEval(mockOperatorEvalStrategyFactory.Object, rulesEngineOptions); // Act Func <IEnumerable <Condition <ConditionType> >, bool> actual = sut.GetDeferredEvalFor(conditionNode, matchMode); bool actualEvalResult = actual.Invoke(conditions); // Assert actualEvalResult.Should().BeFalse(); mockOperatorEvalStrategyFactory.Verify(x => x.GetOperatorEvalStrategy(It.IsAny <Operators>()), Times.Once()); mockOperatorEvalStrategy.Verify(x => x.Eval(It.IsAny <string>(), It.IsAny <string>()), Times.Once()); }
public void GetDeferredEvalFor_GivenUnknownConditionNodeType_ThrowsNotSupportedException() { // Arrange Mock <IValueConditionNode <ConditionType> > mockValueConditionNode = new Mock <IValueConditionNode <ConditionType> >(); Mock <IOperatorEvalStrategyFactory> mockOperatorEvalStrategyFactory = new Mock <IOperatorEvalStrategyFactory>(); MatchModes matchMode = MatchModes.Exact; RulesEngineOptions rulesEngineOptions = RulesEngineOptions.NewWithDefaults(); DeferredEval sut = new DeferredEval(mockOperatorEvalStrategyFactory.Object, rulesEngineOptions); // Act NotSupportedException notSupportedException = Assert.Throws <NotSupportedException>(() => sut.GetDeferredEvalFor(mockValueConditionNode.Object, matchMode)); // Assert notSupportedException.Should().NotBeNull(); notSupportedException.Message.Should().Be($"Unsupported value condition node: '{mockValueConditionNode.Object.GetType().Name}'."); }
public void GetDeferredEvalFor_GivenDecimalConditionNode_ReturnsFuncToEvalConditionsCollection() { // Arrange DecimalConditionNode <ConditionType> conditionNode = new DecimalConditionNode <ConditionType>(ConditionType.PluviosityRate, Operators.GreaterThan, 50); Mock <IOperatorEvalStrategy> mockOperatorEvalStrategy = new Mock <IOperatorEvalStrategy>(); mockOperatorEvalStrategy.Setup(x => x.Eval(It.IsAny <decimal>(), It.IsAny <decimal>())) .Returns(true); Mock <IOperatorEvalStrategyFactory> mockOperatorEvalStrategyFactory = new Mock <IOperatorEvalStrategyFactory>(); mockOperatorEvalStrategyFactory.Setup(x => x.GetOperatorEvalStrategy(It.IsAny <Operators>())) .Returns(mockOperatorEvalStrategy.Object); IEnumerable <Condition <ConditionType> > conditions = new Condition <ConditionType>[] { new Condition <ConditionType> { Type = ConditionType.PluviosityRate, Value = 78 } }; MatchModes matchMode = MatchModes.Exact; RulesEngineOptions rulesEngineOptions = RulesEngineOptions.NewWithDefaults(); DeferredEval sut = new DeferredEval(mockOperatorEvalStrategyFactory.Object, rulesEngineOptions); // Act Func <IEnumerable <Condition <ConditionType> >, bool> actual = sut.GetDeferredEvalFor(conditionNode, matchMode); bool actualEvalResult = actual.Invoke(conditions); // Assert actualEvalResult.Should().BeTrue(); mockOperatorEvalStrategyFactory.Verify(x => x.GetOperatorEvalStrategy(It.IsAny <Operators>()), Times.Once()); mockOperatorEvalStrategy.Verify(x => x.Eval(It.IsAny <decimal>(), It.IsAny <decimal>()), Times.Once()); }
public async Task MatchOneAsync_GivenContentTypeDateAndConditions_FetchesRulesForDayFailsEvalsAndReturnsNull() { // Arrange DateTime matchDateTime = new DateTime(2018, 07, 01, 18, 19, 30); ContentType contentType = ContentType.Type1; IEnumerable <Condition <ConditionType> > conditions = new[] { new Condition <ConditionType> { Type = ConditionType.IsoCountryCode, Value = "BRZ" }, new Condition <ConditionType> { Type = ConditionType.IsoCurrency, Value = "USD" } }; IEnumerable <Rule <ContentType, ConditionType> > rules = new[] { new Rule <ContentType, ConditionType> { ContentContainer = new ContentContainer <ContentType>(contentType, (t) => new object()), DateBegin = new DateTime(2018, 01, 01), DateEnd = new DateTime(2019, 01, 01), Name = "Expected rule", Priority = 3, RootCondition = new StringConditionNode <ConditionType>(ConditionType.IsoCountryCode, Operators.Equal, "USA") }, new Rule <ContentType, ConditionType> { ContentContainer = new ContentContainer <ContentType>(contentType, (t) => new object()), DateBegin = new DateTime(2010, 01, 01), DateEnd = new DateTime(2021, 01, 01), Name = "Expected rule", Priority = 200, RootCondition = new StringConditionNode <ConditionType>(ConditionType.IsoCountryCode, Operators.Equal, "USA") } }; EvaluationOptions evaluationOptions = new EvaluationOptions { MatchMode = MatchModes.Exact }; Mock <IRulesDataSource <ContentType, ConditionType> > mockRulesDataSource = SetupMockForRulesDataSource(rules); Mock <IConditionsEvalEngine <ConditionType> > mockConditionsEvalEngine = SetupMockForConditionsEvalEngine(false, evaluationOptions); RulesEngineOptions rulesEngineOptions = RulesEngineOptions.NewWithDefaults(); RulesEngine <ContentType, ConditionType> sut = new RulesEngine <ContentType, ConditionType>(mockConditionsEvalEngine.Object, mockRulesDataSource.Object, rulesEngineOptions); // Act Rule <ContentType, ConditionType> actual = await sut.MatchOneAsync(contentType, matchDateTime, conditions); // Assert actual.Should().BeNull(); mockRulesDataSource.Verify(x => x.GetRulesAsync(It.IsAny <ContentType>(), It.IsAny <DateTime>(), It.IsAny <DateTime>()), Times.Once()); mockConditionsEvalEngine.Verify(x => x.Eval( It.IsAny <IConditionNode <ConditionType> >(), It.IsAny <IEnumerable <Condition <ConditionType> > >(), It.Is <EvaluationOptions>(eo => eo == evaluationOptions)), Times.AtLeastOnce()); }
public async Task MatchManyAsync_GivenContentTypeDateAndConditions_FetchesRulesForDayEvalsAndReturnsAllMatches() { // Arrange DateTime matchDateTime = new DateTime(2018, 07, 01, 18, 19, 30); ContentType contentType = ContentType.Type1; IEnumerable <Condition <ConditionType> > conditions = new[] { new Condition <ConditionType> { Type = ConditionType.IsoCountryCode, Value = "USA" }, new Condition <ConditionType> { Type = ConditionType.IsoCurrency, Value = "USD" } }; Rule <ContentType, ConditionType> expected1 = new Rule <ContentType, ConditionType> { ContentContainer = new ContentContainer <ContentType>(contentType, (t) => new object()), DateBegin = new DateTime(2018, 01, 01), DateEnd = new DateTime(2019, 01, 01), Name = "Expected rule 1", Priority = 3, RootCondition = new StringConditionNode <ConditionType>(ConditionType.IsoCountryCode, Operators.Equal, "USA") }; Rule <ContentType, ConditionType> expected2 = new Rule <ContentType, ConditionType> { ContentContainer = new ContentContainer <ContentType>(contentType, (t) => new object()), DateBegin = new DateTime(2010, 01, 01), DateEnd = new DateTime(2021, 01, 01), Name = "Expected rule 2", Priority = 200, RootCondition = new StringConditionNode <ConditionType>(ConditionType.IsoCountryCode, Operators.Equal, "USA") }; Rule <ContentType, ConditionType> notExpected = new Rule <ContentType, ConditionType> { ContentContainer = new ContentContainer <ContentType>(contentType, (t) => new object()), DateBegin = new DateTime(2018, 01, 01), DateEnd = new DateTime(2019, 01, 01), Name = "Not expected rule", Priority = 1, // Topmost rule, should be the one that wins if options are set to topmost wins. RootCondition = new StringConditionNode <ConditionType>(ConditionType.IsoCountryCode, Operators.Equal, "CHE") }; IEnumerable <Rule <ContentType, ConditionType> > rules = new[] { expected1, expected2, notExpected }; EvaluationOptions evaluationOptions = new EvaluationOptions { MatchMode = MatchModes.Exact }; Mock <IRulesDataSource <ContentType, ConditionType> > mockRulesDataSource = SetupMockForRulesDataSource(rules); Mock <IConditionsEvalEngine <ConditionType> > mockConditionsEvalEngine = SetupMockForConditionsEvalEngine((rootConditionNode, inputConditions, evalOptions) => { switch (rootConditionNode) { case StringConditionNode <ConditionType> stringConditionNode: return(stringConditionNode.Operand == "USA"); default: return(false); } }, evaluationOptions); RulesEngineOptions rulesEngineOptions = RulesEngineOptions.NewWithDefaults(); RulesEngine <ContentType, ConditionType> sut = new RulesEngine <ContentType, ConditionType>(mockConditionsEvalEngine.Object, mockRulesDataSource.Object, rulesEngineOptions); // Act IEnumerable <Rule <ContentType, ConditionType> > actual = await sut.MatchManyAsync(contentType, matchDateTime, conditions); // Assert actual.Should().Contain(expected1) .And.Contain(expected2) .And.NotContain(notExpected); mockRulesDataSource.Verify(x => x.GetRulesAsync(It.IsAny <ContentType>(), It.IsAny <DateTime>(), It.IsAny <DateTime>()), Times.Once()); mockConditionsEvalEngine.Verify(x => x.Eval( It.IsAny <IConditionNode <ConditionType> >(), It.IsAny <IEnumerable <Condition <ConditionType> > >(), It.Is <EvaluationOptions>(eo => eo == evaluationOptions)), Times.AtLeastOnce()); }
public ConfiguredRulesEngineBuilder(IRulesDataSource <TContentType, TConditionType> rulesDataSource) { this.rulesDataSource = rulesDataSource; this.rulesEngineOptions = RulesEngineOptions.NewWithDefaults(); }