Added MethodCallExpression support (#53)

* MemberAccessExpression / UnaryExpression / MethodCallExpression support as long as it evaluatues to a boolean value.
pull/55/head
David 2020-09-21 11:21:31 +01:00 committed by GitHub
parent 6b66162e56
commit 845e92c6e1
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
6 changed files with 168 additions and 36 deletions

View File

@ -24,13 +24,16 @@ namespace RulesEngine.ExpressionBuilders
{
_reSettings = reSettings;
}
internal override Expression<Func<RuleInput, RuleResultTree>> BuildExpressionForRule(Rule rule, IEnumerable<ParameterExpression> typeParamExpressions, ParameterExpression ruleInputExp)
{
try
{
var config = new ParsingConfig { CustomTypeProvider = new CustomTypeProvider(_reSettings.CustomTypes) };
var e = DynamicExpressionParser.ParseLambda(config, typeParamExpressions.ToArray(), null, rule.Expression);
var body = (BinaryExpression)e.Body;
var body = e.Body is BinaryExpression binaryExpression
? binaryExpression
: Expression.MakeBinary(ExpressionType.And, e.Body, Expression.Constant(true));
return Helpers.ToResultTreeExpression(rule, null, body, typeParamExpressions, ruleInputExp);
}
catch (Exception ex)
@ -52,6 +55,5 @@ namespace RulesEngine.ExpressionBuilders
var e = DynamicExpressionParser.ParseLambda(config, typeParamExpressions.ToArray(), null, param.Expression);
return e.Body;
}
}
}

View File

@ -124,7 +124,6 @@ namespace RulesEngine.UnitTest
});
}
[Theory]
[InlineData("rules1.json")]
public void ExecuteRule_InvalidWorkFlow_ThrowsException(string ruleFileName)
@ -149,7 +148,6 @@ namespace RulesEngine.UnitTest
Assert.Throws<ArgumentException>(() => re.ExecuteRule("inputWorkflow", input1, input2, input3));
}
[Theory]
[InlineData("rules1.json")]
public void ClearWorkflow_RemovesAllWorkflow(string ruleFileName)
@ -165,7 +163,6 @@ namespace RulesEngine.UnitTest
Assert.Throws<ArgumentException>(() => re.ExecuteRule("inputWorkflowReference", input1, input2, input3));
}
[Theory]
[InlineData("rules1.json")]
[InlineData("rules2.json")]
@ -190,7 +187,6 @@ namespace RulesEngine.UnitTest
Assert.Contains(result, c => c.IsSuccess);
}
[Theory]
[InlineData("rules4.json")]
public void RulesEngine_Execute_Rule_For_Nested_Rule_Params_Returns_Success(string ruleFileName)
@ -255,6 +251,61 @@ namespace RulesEngine.UnitTest
Assert.All(result, c => Assert.Equal(expectedResult, c.IsSuccess));
}
[Theory]
[InlineData("rules6.json")]
public void ExecuteRule_RuleWithMethodExpression_ReturnsSucess(string ruleFileName)
{
var re = GetRulesEngine(ruleFileName);
Func<bool> func = () => true;
dynamic input1 = new ExpandoObject();
input1.Property1 = "hello";
input1.Boolean = false;
input1.Method = func;
var utils = new TestInstanceUtils();
List<RuleResultTree> result = re.ExecuteRule("inputWorkflow", new RuleParameter("input1", input1));
Assert.NotNull(result);
Assert.IsType<List<RuleResultTree>>(result);
Assert.All(result, c => Assert.True(c.IsSuccess));
}
[Theory]
[InlineData("rules7.json")]
public void ExecuteRule_RuleWithUnaryExpression_ReturnsSucess(string ruleFileName)
{
var re = GetRulesEngine(ruleFileName);
dynamic input1 = new ExpandoObject();
input1.Boolean = false;
var utils = new TestInstanceUtils();
List<RuleResultTree> result = re.ExecuteRule("inputWorkflow", new RuleParameter("input1", input1));
Assert.NotNull(result);
Assert.IsType<List<RuleResultTree>>(result);
Assert.All(result, c => Assert.True(c.IsSuccess));
}
[Theory]
[InlineData("rules8.json")]
public void ExecuteRule_RuleWithMemberAccessExpression_ReturnsSucess(string ruleFileName)
{
var re = GetRulesEngine(ruleFileName);
dynamic input1 = new ExpandoObject();
input1.Boolean = false;
var utils = new TestInstanceUtils();
List<RuleResultTree> result = re.ExecuteRule("inputWorkflow", new RuleParameter("input1", input1));
Assert.NotNull(result);
Assert.IsType<List<RuleResultTree>>(result);
Assert.All(result, c => Assert.False(c.IsSuccess));
}
private RulesEngine CreateRulesEngine(WorkflowRules workflow)
{
var json = JsonConvert.SerializeObject(workflow);
@ -277,7 +328,6 @@ namespace RulesEngine.UnitTest
return new RulesEngine(new string[] { data, injectWorkflowStr }, mockLogger.Object);
}
private dynamic GetInput1()
{
var converter = new ExpandoObjectConverter();
@ -334,14 +384,14 @@ namespace RulesEngine.UnitTest
}
[ExcludeFromCodeCoverage]
private class TestInstanceUtils{
public bool CheckExists(string str){
private class TestInstanceUtils
{
public bool CheckExists(string str)
{
if (str != null && str.Length > 0)
return true;
return false;
}
}
}
}
}

View File

@ -33,6 +33,15 @@
<None Update="TestData\rules2.json">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</None>
<None Update="TestData\rules8.json">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</None>
<None Update="TestData\rules7.json">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</None>
<None Update="TestData\rules6.json">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</None>
<None Update="TestData\rules5.json">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</None>

View File

@ -0,0 +1,29 @@
{
"WorkflowName": "inputWorkflow",
"Rules": [
{
"RuleName": "GiveDiscount10",
"SuccessEvent": "10",
"ErrorMessage": "One or more adjust rules failed.",
"ErrorType": "Error",
"RuleExpressionType": "LambdaExpression",
"Expression": "input1.Property1.Contains(\"hell\")"
},
{
"RuleName": "GiveDiscount20",
"SuccessEvent": "20",
"ErrorMessage": "One or more adjust rules failed.",
"ErrorType": "Error",
"RuleExpressionType": "LambdaExpression",
"Expression": "input1.Property1.Contains(\"hell\") && !input1.Boolean"
},
{
"RuleName": "GiveDiscount30",
"SuccessEvent": "30",
"ErrorMessage": "One or more adjust rules failed.",
"ErrorType": "Error",
"RuleExpressionType": "LambdaExpression",
"Expression": "input1.Method.Invoke()"
}
]
}

View File

@ -0,0 +1,21 @@
{
"WorkflowName": "inputWorkflow",
"Rules": [
{
"RuleName": "GiveDiscount10",
"SuccessEvent": "10",
"ErrorMessage": "One or more adjust rules failed.",
"ErrorType": "Error",
"RuleExpressionType": "LambdaExpression",
"Expression": "!input1.Boolean"
},
{
"RuleName": "GiveDiscount20",
"SuccessEvent": "20",
"ErrorMessage": "One or more adjust rules failed.",
"ErrorType": "Error",
"RuleExpressionType": "LambdaExpression",
"Expression": "!input1.Boolean && true"
}
]
}

View File

@ -0,0 +1,21 @@
{
"WorkflowName": "inputWorkflow",
"Rules": [
{
"RuleName": "GiveDiscount10",
"SuccessEvent": "10",
"ErrorMessage": "One or more adjust rules failed.",
"ErrorType": "Error",
"RuleExpressionType": "LambdaExpression",
"Expression": "input1.Boolean"
},
{
"RuleName": "GiveDiscount20",
"SuccessEvent": "20",
"ErrorMessage": "One or more adjust rules failed.",
"ErrorType": "Error",
"RuleExpressionType": "LambdaExpression",
"Expression": "input1.Boolean && true || (input1.Boolean)"
}
]
}