Farfetch / rules-framework

A generic framework that allows defining and evaluating rules for complex business scenarios.
MIT License
41 stars 8 forks source link

[Bug Report]: Operators.In and Operators.NotIn with not working properly when trying to match the rule setting the condition value as null #130

Closed isabelneto closed 1 year ago

isabelneto commented 1 year ago

Prerequisites

Description

When creating a rule using the Operators.In or Operators.NotIn we are getting one exception when trying to match the rule with that condition set to null (or, nonexistent, in the case where the condition type is string, since it's default is null). The problem seems to be in Rules.Framework, when trying to cast.

Steps to reproduce

  1. Create a rule like the following:
    this.Add(
    this.Add(
        RuleBuilder
            .NewRule<RuleContentType, ConditionType>()
            .WithName("Some Rule")
            .WithContent(
                RuleContentType.SomeContentType,
                  "SomeText"
            )
            .WithCondition(x => x
                .AsValued(ConditionType.SomeConditionType).OfDataType<string>()
                .WithComparisonOperator(Operators.In)
                .SetOperand(new[] { "11111", "22222", "33333", "44444", "55555" })
                .Build()
            )
            .WithDateBegin(DateTime.Parse("2022-01-01"))
            .Build(),
        RuleAddPriorityOption.ByPriorityNumber(1)
    );
  2. Create a test case where SomeConditionType is null

Expected behavior

It shouldn't match the rule but no errors should occour.

Actual behavior

It is throwing an exception: System.ArgumentException: Parameter value or contained value is not convertible to String. (Parameter 'leftOperand')

System.ArgumentException
Parameter value or contained value is not convertible to String. (Parameter 'leftOperand')
   at Rules.Framework.Evaluation.ValueEvaluation.Dispatchers.ConditionEvalDispatcherBase.ConvertToDataType(Object operand, String paramName, DataTypeConfiguration dataTypeConfiguration)
   at Rules.Framework.Evaluation.ValueEvaluation.Dispatchers.OneToManyConditionEvalDispatcher.EvalDispatch(DataTypes dataType, Object leftOperand, Operators operator, Object rightOperand)
   at Rules.Framework.Evaluation.ValueEvaluation.DeferredEval.Eval[TConditionType](IDictionary`2 conditions, IValueConditionNode`1 valueConditionNode, Object rightOperand, MatchModes matchMode)
   at Rules.Framework.Evaluation.ValueEvaluation.DeferredEval.Eval[TConditionType](IDictionary`2 conditions, ValueConditionNode`1 valueConditionNode, MatchModes matchMode)
   at Rules.Framework.Evaluation.ValueEvaluation.DeferredEval.<>c__DisplayClass3_0`1.<GetDeferredEvalFor>b__4(IDictionary`2 conditions)
   at Rules.Framework.Evaluation.Specification.FuncSpecification`1.IsSatisfiedBy(T input)
   at Rules.Framework.Evaluation.ConditionsEvalEngine`1.Eval(IConditionNode`1 conditionNode, IDictionary`2 conditions, EvaluationOptions evaluationOptions)
   at Rules.Framework.RulesEngine`2.<>c__DisplayClass18_0.<MatchAsync>b__2(Rule`2 r)
   at System.Linq.Enumerable.WhereEnumerableIterator`1.ToList()
   at System.Linq.Enumerable.ToList[TSource](IEnumerable`1 source)
   at Rules.Framework.RulesEngine`2.MatchAsync(TContentType contentType, DateTime matchDateBegin, DateTime matchDateEnd, IEnumerable`1 conditions, EvaluationOptions evaluationOptions)
   at Rules.Framework.RulesEngine`2.MatchOneAsync(TContentType contentType, DateTime matchDateTime, IEnumerable`1 conditions)
   at Farfetch.Finance.OrderTransactions.Data.RulesEngine.Tests.Engine.ContentTypeBaseTests.MatchOneAsync(DateTime expectedMatchDate, Condition`1[] expectedConditions) in C:\ave\_git\order-transactions-service\src\Data.RulesEngine.Tests\Engine\ContentTypeBaseTests.cs:line 44
   at Farfetch.Finance.OrderTransactions.Data.RulesEngine.Tests.Rules.RulesTestHelper.TestRuleAsync[TRuleContent](String ruleName, DateTime expectedMatchDate, Nullable`1 expectedEndDate, Condition`1[] expectedConditions, TRuleContent expectedValue) in C:\ave\_git\order-transactions-service\src\Data.RulesEngine.Tests\Rules\RulesTestHelper.cs:line 25
   at Farfetch.Finance.OrderTransactions.Data.RulesEngine.Tests.Rules.Transactions.PromoCodeX10NetRulesTests.GetRulesSpecifications_PromoCodeX10Net_WithConditionsRule(String ruleName, DateTime expectedMatchDate, Condition`1[] expectedConditions, RuleResultContent expectedValue) in C:\ave\_git\order-transactions-service\src\Data.RulesEngine.Tests\Rules\Transactions\PromoCodeX10NetRulesTests.cs:line 343
   at Xunit.Sdk.TestInvoker`1.<>c__DisplayClass48_1.<<InvokeTestMethodAsync>b__1>d.MoveNext() in C:\Dev\xunit\xunit\src\xunit.execution\Sdk\Frameworks\Runners\TestInvoker.cs:line 264
--- End of stack trace from previous location ---
   at Xunit.Sdk.ExecutionTimer.AggregateAsync(Func`1 asyncAction) in C:\Dev\xunit\xunit\src\xunit.execution\Sdk\Frameworks\ExecutionTimer.cs:line 48
   at Xunit.Sdk.ExceptionAggregator.RunAsync(Func`1 code) in C:\Dev\xunit\xunit\src\xunit.core\Sdk\ExceptionAggregator.cs:line 90

System.InvalidCastException
Object must implement IConvertible.
   at System.Convert.ChangeType(Object value, Type conversionType, IFormatProvider provider)
   at Rules.Framework.Evaluation.ValueEvaluation.Dispatchers.ConditionEvalDispatcherBase.ConvertToDataType(Object operand, String paramName, DataTypeConfiguration dataTypeConfiguration)

Rules Framework version

v1.7.7