* fixed namespace issue (#82)
* fixed namespace issue * added editorconfig * cleaned up files based on editorconfigpull/93/head v3.0.1
parent
2886bca157
commit
9c8b9d484e
|
@ -0,0 +1,134 @@
|
|||
# Rules in this file were initially inferred by Visual Studio IntelliCode from the C:\Users\abcy\source\repos\RulesEngine codebase based on best match to current usage at 22-12-2020
|
||||
# You can modify the rules from these initially generated values to suit your own policies
|
||||
# You can learn more about editorconfig here: https://docs.microsoft.com/en-us/visualstudio/ide/editorconfig-code-style-settings-reference
|
||||
[*.cs]
|
||||
|
||||
|
||||
#Core editorconfig formatting - indentation
|
||||
|
||||
#use soft tabs (spaces) for indentation
|
||||
indent_style = space
|
||||
|
||||
#Formatting - indentation options
|
||||
|
||||
#indent switch case contents.
|
||||
csharp_indent_case_contents = true
|
||||
#indent switch labels
|
||||
csharp_indent_switch_labels = true
|
||||
|
||||
#Formatting - new line options
|
||||
|
||||
#place catch statements on a new line
|
||||
csharp_new_line_before_catch = true
|
||||
#place else statements on a new line
|
||||
csharp_new_line_before_else = true
|
||||
#require members of anonymous types to be on separate lines
|
||||
csharp_new_line_before_members_in_anonymous_types = true
|
||||
#require members of object intializers to be on separate lines
|
||||
csharp_new_line_before_members_in_object_initializers = true
|
||||
#require braces to be on a new line for methods, control_blocks, and types (also known as "Allman" style)
|
||||
csharp_new_line_before_open_brace = methods, control_blocks, types
|
||||
|
||||
#Formatting - organize using options
|
||||
|
||||
#do not place System.* using directives before other using directives
|
||||
dotnet_sort_system_directives_first = false
|
||||
|
||||
#Formatting - spacing options
|
||||
|
||||
#require NO space between a cast and the value
|
||||
csharp_space_after_cast = false
|
||||
#require a space before the colon for bases or interfaces in a type declaration
|
||||
csharp_space_after_colon_in_inheritance_clause = true
|
||||
#require a space after a keyword in a control flow statement such as a for loop
|
||||
csharp_space_after_keywords_in_control_flow_statements = true
|
||||
#require a space before the colon for bases or interfaces in a type declaration
|
||||
csharp_space_before_colon_in_inheritance_clause = true
|
||||
#remove space within empty argument list parentheses
|
||||
csharp_space_between_method_call_empty_parameter_list_parentheses = false
|
||||
#remove space between method call name and opening parenthesis
|
||||
csharp_space_between_method_call_name_and_opening_parenthesis = false
|
||||
#do not place space characters after the opening parenthesis and before the closing parenthesis of a method call
|
||||
csharp_space_between_method_call_parameter_list_parentheses = false
|
||||
#remove space within empty parameter list parentheses for a method declaration
|
||||
csharp_space_between_method_declaration_empty_parameter_list_parentheses = false
|
||||
#place a space character after the opening parenthesis and before the closing parenthesis of a method declaration parameter list.
|
||||
csharp_space_between_method_declaration_parameter_list_parentheses = false
|
||||
|
||||
#Formatting - wrapping options
|
||||
|
||||
#leave code block on single line
|
||||
csharp_preserve_single_line_blocks = true
|
||||
#leave statements and member declarations on the same line
|
||||
csharp_preserve_single_line_statements = true
|
||||
|
||||
#Style - Code block preferences
|
||||
|
||||
#prefer curly braces even for one line of code
|
||||
csharp_prefer_braces = true:suggestion
|
||||
|
||||
#Style - expression bodied member options
|
||||
|
||||
#prefer block bodies for constructors
|
||||
csharp_style_expression_bodied_constructors = false:suggestion
|
||||
#prefer block bodies for methods
|
||||
csharp_style_expression_bodied_methods = false:suggestion
|
||||
|
||||
#Style - expression level options
|
||||
|
||||
#prefer out variables to be declared inline in the argument list of a method call when possible
|
||||
csharp_style_inlined_variable_declaration = true:suggestion
|
||||
#prefer the language keyword for member access expressions, instead of the type name, for types that have a keyword to represent them
|
||||
dotnet_style_predefined_type_for_member_access = true:suggestion
|
||||
|
||||
#Style - Expression-level preferences
|
||||
|
||||
#prefer objects to be initialized using object initializers when possible
|
||||
dotnet_style_object_initializer = true:suggestion
|
||||
#prefer inferred anonymous type member names
|
||||
dotnet_style_prefer_inferred_anonymous_type_member_names = false:suggestion
|
||||
|
||||
#Style - implicit and explicit types
|
||||
|
||||
#prefer var over explicit type in all cases, unless overridden by another code style rule
|
||||
csharp_style_var_elsewhere = true:suggestion
|
||||
#prefer var is used to declare variables with built-in system types such as int
|
||||
csharp_style_var_for_built_in_types = true:suggestion
|
||||
#prefer var when the type is already mentioned on the right-hand side of a declaration expression
|
||||
csharp_style_var_when_type_is_apparent = true:suggestion
|
||||
|
||||
#Style - language keyword and framework type options
|
||||
|
||||
#prefer the language keyword for local variables, method parameters, and class members, instead of the type name, for types that have a keyword to represent them
|
||||
dotnet_style_predefined_type_for_locals_parameters_members = true:suggestion
|
||||
|
||||
#Style - Miscellaneous preferences
|
||||
|
||||
#prefer anonymous functions over local functions
|
||||
csharp_style_pattern_local_over_anonymous_function = false:suggestion
|
||||
|
||||
#Style - modifier options
|
||||
|
||||
#prefer accessibility modifiers to be declared except for public interface members. This will currently not differ from always and will act as future proofing for if C# adds default interface methods.
|
||||
dotnet_style_require_accessibility_modifiers = for_non_interface_members:suggestion
|
||||
|
||||
#Style - Modifier preferences
|
||||
|
||||
#when this rule is set to a list of modifiers, prefer the specified ordering.
|
||||
csharp_preferred_modifier_order = public,private,internal,readonly,static,async,override,sealed:suggestion
|
||||
|
||||
#Style - qualification options
|
||||
|
||||
#prefer fields not to be prefaced with this. or Me. in Visual Basic
|
||||
dotnet_style_qualification_for_field = false:suggestion
|
||||
#prefer methods not to be prefaced with this. or Me. in Visual Basic
|
||||
dotnet_style_qualification_for_method = false:suggestion
|
||||
#prefer properties not to be prefaced with this. or Me. in Visual Basic
|
||||
dotnet_style_qualification_for_property = false:suggestion
|
||||
|
||||
|
||||
#file header
|
||||
[*.{cs,vb}]
|
||||
file_header_template = Copyright (c) Microsoft Corporation.\nLicensed under the MIT License.
|
||||
file_header_template_style = prepend:error
|
||||
file_header_template_style = replace:suggestion
|
|
@ -2,9 +2,9 @@ name: "Code scanning"
|
|||
|
||||
on:
|
||||
push:
|
||||
branches: [ master ]
|
||||
branches: [ main ]
|
||||
pull_request:
|
||||
branches: [ master ]
|
||||
branches: [ main ]
|
||||
schedule:
|
||||
- cron: '0 18 * * 1'
|
||||
|
||||
|
|
|
@ -2,9 +2,9 @@ name: build
|
|||
|
||||
on:
|
||||
push:
|
||||
branches: [ master ]
|
||||
branches: [ main ]
|
||||
pull_request:
|
||||
branches: [ master, develop ]
|
||||
branches: [ main, develop ]
|
||||
|
||||
jobs:
|
||||
build:
|
||||
|
|
|
@ -1,6 +1,11 @@
|
|||
# CHANGELOG
|
||||
|
||||
All notable changes to this project will be documented in this file.
|
||||
|
||||
## [3.0.1]
|
||||
- Moved ActionResult and ActionRuleResult under RulesEngine.Models namespace
|
||||
|
||||
|
||||
## [3.0.0]
|
||||
### Major Enhancements
|
||||
- Added support for Actions. More details on [actions wiki](https://github.com/microsoft/RulesEngine/wiki/Actions)
|
||||
|
|
|
@ -14,6 +14,7 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "DemoApp", "demo\DemoApp\Dem
|
|||
EndProject
|
||||
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Solution Items", "Solution Items", "{019DF693-8442-45B4-88C3-55CB7AFCB42E}"
|
||||
ProjectSection(SolutionItems) = preProject
|
||||
.editorconfig = .editorconfig
|
||||
CHANGELOG.md = CHANGELOG.md
|
||||
global.json = global.json
|
||||
README.md = README.md
|
||||
|
|
|
@ -1,4 +1,7 @@
|
|||
using BenchmarkDotNet.Attributes;
|
||||
// Copyright (c) Microsoft Corporation.
|
||||
// Licensed under the MIT License.
|
||||
|
||||
using BenchmarkDotNet.Attributes;
|
||||
using BenchmarkDotNet.Running;
|
||||
using Newtonsoft.Json;
|
||||
using RulesEngine.Models;
|
||||
|
@ -14,7 +17,8 @@ namespace RulesEngineBenchmark
|
|||
private readonly RulesEngine.RulesEngine rulesEngine;
|
||||
private readonly object ruleInput;
|
||||
private readonly List<WorkflowRules> workflows;
|
||||
class ListItem
|
||||
|
||||
private class ListItem
|
||||
{
|
||||
public int Id { get; set; }
|
||||
public string Value { get; set; }
|
||||
|
@ -25,21 +29,21 @@ namespace RulesEngineBenchmark
|
|||
{
|
||||
var files = Directory.GetFiles(Directory.GetCurrentDirectory(), "NestedInputDemo.json", SearchOption.AllDirectories);
|
||||
if (files == null || files.Length == 0)
|
||||
{
|
||||
throw new Exception("Rules not found.");
|
||||
}
|
||||
|
||||
var fileData = File.ReadAllText(files[0]);
|
||||
workflows = JsonConvert.DeserializeObject<List<WorkflowRules>>(fileData);
|
||||
|
||||
rulesEngine = new RulesEngine.RulesEngine(workflows.ToArray(), null,new ReSettings {
|
||||
|
||||
rulesEngine = new RulesEngine.RulesEngine(workflows.ToArray(), null, new ReSettings {
|
||||
EnableFormattedErrorMessage = false,
|
||||
EnableLocalParams = false
|
||||
});
|
||||
|
||||
ruleInput = new
|
||||
{
|
||||
ruleInput = new {
|
||||
SimpleProp = "simpleProp",
|
||||
NestedProp = new
|
||||
{
|
||||
NestedProp = new {
|
||||
SimpleProp = "nestedSimpleProp",
|
||||
ListProp = new List<ListItem>
|
||||
{
|
||||
|
@ -67,15 +71,15 @@ namespace RulesEngineBenchmark
|
|||
{
|
||||
foreach (var workflow in workflows)
|
||||
{
|
||||
List<RuleResultTree> resultList = rulesEngine.ExecuteAllRulesAsync(workflow.WorkflowName, ruleInput).Result;
|
||||
_ = rulesEngine.ExecuteAllRulesAsync(workflow.WorkflowName, ruleInput).Result;
|
||||
}
|
||||
}
|
||||
}
|
||||
class Program
|
||||
public class Program
|
||||
{
|
||||
static void Main(string[] args)
|
||||
public static void Main(string[] args)
|
||||
{
|
||||
var summary = BenchmarkRunner.Run<REBenchmark>();
|
||||
_ = BenchmarkRunner.Run<REBenchmark>();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,4 +1,7 @@
|
|||
using Newtonsoft.Json;
|
||||
// Copyright (c) Microsoft Corporation.
|
||||
// Licensed under the MIT License.
|
||||
|
||||
using Newtonsoft.Json;
|
||||
using Newtonsoft.Json.Converters;
|
||||
using RulesEngine.Models;
|
||||
using System;
|
||||
|
@ -44,13 +47,11 @@ namespace DemoApp
|
|||
|
||||
List<RuleResultTree> resultList = bre.ExecuteAllRulesAsync("Discount", inputs).Result;
|
||||
|
||||
resultList.OnSuccess((eventName) =>
|
||||
{
|
||||
resultList.OnSuccess((eventName) => {
|
||||
discountOffered = $"Discount offered is {eventName} % over MRP.";
|
||||
});
|
||||
|
||||
resultList.OnFail(() =>
|
||||
{
|
||||
resultList.OnFail(() => {
|
||||
discountOffered = "The user is not eligible for any discount.";
|
||||
});
|
||||
|
||||
|
|
|
@ -1,14 +1,17 @@
|
|||
using Newtonsoft.Json;
|
||||
// Copyright (c) Microsoft Corporation.
|
||||
// Licensed under the MIT License.
|
||||
|
||||
using Newtonsoft.Json;
|
||||
using RulesEngine.Extensions;
|
||||
using RulesEngine.Models;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Dynamic;
|
||||
using System.IO;
|
||||
|
||||
namespace DemoApp
|
||||
{
|
||||
class ListItem {
|
||||
internal class ListItem
|
||||
{
|
||||
public int Id { get; set; }
|
||||
public string Value { get; set; }
|
||||
}
|
||||
|
@ -18,10 +21,9 @@ namespace DemoApp
|
|||
public void Run()
|
||||
{
|
||||
Console.WriteLine($"Running {nameof(NestedInputDemo)}....");
|
||||
var nestedInput = new {
|
||||
var nestedInput = new {
|
||||
SimpleProp = "simpleProp",
|
||||
NestedProp = new
|
||||
{
|
||||
NestedProp = new {
|
||||
SimpleProp = "nestedSimpleProp",
|
||||
ListProp = new List<ListItem>
|
||||
{
|
||||
|
@ -37,29 +39,29 @@ namespace DemoApp
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
};
|
||||
|
||||
var files = Directory.GetFiles(Directory.GetCurrentDirectory(), "NestedInputDemo.json", SearchOption.AllDirectories);
|
||||
if (files == null || files.Length == 0)
|
||||
{
|
||||
throw new Exception("Rules not found.");
|
||||
}
|
||||
|
||||
var fileData = File.ReadAllText(files[0]);
|
||||
var workflowRules = JsonConvert.DeserializeObject<List<WorkflowRules>>(fileData);
|
||||
|
||||
var bre = new RulesEngine.RulesEngine(workflowRules.ToArray(),null);
|
||||
foreach(var workflow in workflowRules)
|
||||
var bre = new RulesEngine.RulesEngine(workflowRules.ToArray(), null);
|
||||
foreach (var workflow in workflowRules)
|
||||
{
|
||||
List<RuleResultTree> resultList = bre.ExecuteAllRulesAsync(workflow.WorkflowName, nestedInput).Result;
|
||||
var resultList = bre.ExecuteAllRulesAsync(workflow.WorkflowName, nestedInput).Result;
|
||||
|
||||
resultList.OnSuccess((eventName) =>
|
||||
{
|
||||
resultList.OnSuccess((eventName) => {
|
||||
Console.WriteLine($"{workflow.WorkflowName} evaluation resulted in succees - {eventName}");
|
||||
}).OnFail(() =>
|
||||
{
|
||||
}).OnFail(() => {
|
||||
Console.WriteLine($"{workflow.WorkflowName} evaluation resulted in failure");
|
||||
});
|
||||
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
|
|
@ -3,9 +3,9 @@
|
|||
|
||||
namespace DemoApp
|
||||
{
|
||||
static class Program
|
||||
public static class Program
|
||||
{
|
||||
static void Main(string[] args)
|
||||
public static void Main(string[] args)
|
||||
{
|
||||
new BasicDemo().Run();
|
||||
new NestedInputDemo().Run();
|
||||
|
|
|
@ -1,25 +1,30 @@
|
|||
using System;
|
||||
// Copyright (c) Microsoft Corporation.
|
||||
// Licensed under the MIT License.
|
||||
|
||||
using RulesEngine.Models;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Threading.Tasks;
|
||||
using RulesEngine.Models;
|
||||
|
||||
namespace RulesEngine.Actions
|
||||
{
|
||||
public abstract class ActionBase
|
||||
{
|
||||
internal virtual async ValueTask<ActionRuleResult> ExecuteAndReturnResultAsync(ActionContext context, RuleParameter[] ruleParameters,bool includeRuleResults=false){
|
||||
ActionRuleResult result = new ActionRuleResult();
|
||||
internal async virtual ValueTask<ActionRuleResult> ExecuteAndReturnResultAsync(ActionContext context, RuleParameter[] ruleParameters, bool includeRuleResults = false)
|
||||
{
|
||||
var result = new ActionRuleResult();
|
||||
try
|
||||
{
|
||||
result.Output = await Run(context, ruleParameters);
|
||||
}
|
||||
catch(Exception ex)
|
||||
catch (Exception ex)
|
||||
{
|
||||
result.Exception = new Exception($"Exception while executing {this.GetType().Name}: {ex.Message}",ex);
|
||||
result.Exception = new Exception($"Exception while executing {GetType().Name}: {ex.Message}", ex);
|
||||
}
|
||||
finally
|
||||
{
|
||||
if(includeRuleResults){
|
||||
if (includeRuleResults)
|
||||
{
|
||||
result.Results = new List<RuleResultTree>()
|
||||
{
|
||||
context.GetParentRuleResult()
|
||||
|
|
|
@ -1,4 +1,7 @@
|
|||
using Newtonsoft.Json;
|
||||
// Copyright (c) Microsoft Corporation.
|
||||
// Licensed under the MIT License.
|
||||
|
||||
using Newtonsoft.Json;
|
||||
using RulesEngine.Models;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
|
@ -22,7 +25,8 @@ namespace RulesEngine.Actions
|
|||
_parentResult = parentResult;
|
||||
}
|
||||
|
||||
public RuleResultTree GetParentRuleResult(){
|
||||
public RuleResultTree GetParentRuleResult()
|
||||
{
|
||||
return _parentResult;
|
||||
}
|
||||
public T GetContext<T>(string name)
|
||||
|
|
|
@ -1,4 +1,7 @@
|
|||
using System;
|
||||
// Copyright (c) Microsoft Corporation.
|
||||
// Licensed under the MIT License.
|
||||
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
|
||||
namespace RulesEngine.Actions
|
||||
|
@ -12,9 +15,10 @@ namespace RulesEngine.Actions
|
|||
_actionRegistry = new Dictionary<string, Func<ActionBase>>(StringComparer.OrdinalIgnoreCase);
|
||||
|
||||
}
|
||||
internal ActionFactory(IDictionary<string,Func<ActionBase>> actionRegistry): this()
|
||||
internal ActionFactory(IDictionary<string, Func<ActionBase>> actionRegistry) : this()
|
||||
{
|
||||
foreach(var kv in actionRegistry){
|
||||
foreach (var kv in actionRegistry)
|
||||
{
|
||||
_actionRegistry.Add(kv.Key, kv.Value);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,7 +1,9 @@
|
|||
// Copyright (c) Microsoft Corporation.
|
||||
// Licensed under the MIT License.
|
||||
|
||||
using RulesEngine.Models;
|
||||
using System.Collections.Generic;
|
||||
using System.Threading.Tasks;
|
||||
using RulesEngine.ExpressionBuilders;
|
||||
using RulesEngine.Models;
|
||||
|
||||
namespace RulesEngine.Actions
|
||||
{
|
||||
|
@ -14,11 +16,13 @@ namespace RulesEngine.Actions
|
|||
_ruleEngine = ruleEngine;
|
||||
}
|
||||
|
||||
internal override async ValueTask<ActionRuleResult> ExecuteAndReturnResultAsync(ActionContext context, RuleParameter[] ruleParameters, bool includeRuleResults=false){
|
||||
var innerResult = await base.ExecuteAndReturnResultAsync(context,ruleParameters,includeRuleResults);
|
||||
internal async override ValueTask<ActionRuleResult> ExecuteAndReturnResultAsync(ActionContext context, RuleParameter[] ruleParameters, bool includeRuleResults = false)
|
||||
{
|
||||
var innerResult = await base.ExecuteAndReturnResultAsync(context, ruleParameters, includeRuleResults);
|
||||
var output = innerResult.Output as ActionRuleResult;
|
||||
List<RuleResultTree> resultList = null;
|
||||
if(includeRuleResults){
|
||||
if (includeRuleResults)
|
||||
{
|
||||
resultList = new List<RuleResultTree>(output.Results);
|
||||
resultList.AddRange(innerResult.Results);
|
||||
}
|
||||
|
@ -29,11 +33,11 @@ namespace RulesEngine.Actions
|
|||
};
|
||||
}
|
||||
|
||||
public override async ValueTask<object> Run(ActionContext context, RuleParameter[] ruleParameters)
|
||||
public async override ValueTask<object> Run(ActionContext context, RuleParameter[] ruleParameters)
|
||||
{
|
||||
var workflowName = context.GetContext<string>("workflowName");
|
||||
var ruleName = context.GetContext<string>("ruleName");
|
||||
var ruleResult = await _ruleEngine.ExecuteActionWorkflowAsync(workflowName,ruleName,ruleParameters);
|
||||
var ruleResult = await _ruleEngine.ExecuteActionWorkflowAsync(workflowName, ruleName, ruleParameters);
|
||||
return ruleResult;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,7 +1,9 @@
|
|||
using System.Collections.Generic;
|
||||
using System.Threading.Tasks;
|
||||
// Copyright (c) Microsoft Corporation.
|
||||
// Licensed under the MIT License.
|
||||
|
||||
using RulesEngine.ExpressionBuilders;
|
||||
using RulesEngine.Models;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace RulesEngine.Actions
|
||||
{
|
||||
|
|
|
@ -1,6 +1,5 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Text;
|
||||
// Copyright (c) Microsoft Corporation.
|
||||
// Licensed under the MIT License.
|
||||
|
||||
namespace RulesEngine.Enums
|
||||
{
|
||||
|
|
|
@ -29,16 +29,16 @@ namespace RulesEngine.ExpressionBuilders
|
|||
bool func(object[] paramList) => ruleDelegate(paramList);
|
||||
return Helpers.ToResultTree(rule, null, func);
|
||||
}
|
||||
catch (Exception ex)
|
||||
catch (Exception ex)
|
||||
{
|
||||
ex.Data.Add(nameof(rule.RuleName), rule.RuleName);
|
||||
ex.Data.Add(nameof(rule.Expression), rule.Expression);
|
||||
|
||||
|
||||
if (!_reSettings.EnableExceptionAsErrorMessage) throw;
|
||||
bool func(object[] param) => false;
|
||||
var exceptionMessage = $"Exception while parsing expression `{rule?.Expression}` - {ex.Message}";
|
||||
return Helpers.ToResultTree(rule, null, func, exceptionMessage);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -2,9 +2,6 @@
|
|||
// Licensed under the MIT License.
|
||||
|
||||
using RulesEngine.Models;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq.Expressions;
|
||||
|
||||
namespace RulesEngine.ExpressionBuilders
|
||||
{
|
||||
|
|
|
@ -1,11 +1,14 @@
|
|||
using Microsoft.Extensions.Caching.Memory;
|
||||
// Copyright (c) Microsoft Corporation.
|
||||
// Licensed under the MIT License.
|
||||
|
||||
using FastExpressionCompiler;
|
||||
using Microsoft.Extensions.Caching.Memory;
|
||||
using RulesEngine.Models;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Linq.Dynamic.Core;
|
||||
using System.Linq.Expressions;
|
||||
using FastExpressionCompiler;
|
||||
|
||||
namespace RulesEngine.ExpressionBuilders
|
||||
{
|
||||
|
@ -17,34 +20,35 @@ namespace RulesEngine.ExpressionBuilders
|
|||
public RuleExpressionParser(ReSettings reSettings)
|
||||
{
|
||||
_reSettings = reSettings;
|
||||
_memoryCache = new MemoryCache(new MemoryCacheOptions{
|
||||
_memoryCache = new MemoryCache(new MemoryCacheOptions {
|
||||
SizeLimit = 1000
|
||||
});
|
||||
}
|
||||
|
||||
public Func<object[],T> Compile<T>(string expression, RuleParameter[] ruleParams)
|
||||
public Func<object[], T> Compile<T>(string expression, RuleParameter[] ruleParams)
|
||||
{
|
||||
var cacheKey = GetCacheKey(expression,ruleParams,typeof(T));
|
||||
return _memoryCache.GetOrCreate(cacheKey,(entry) => {
|
||||
var cacheKey = GetCacheKey(expression, ruleParams, typeof(T));
|
||||
return _memoryCache.GetOrCreate(cacheKey, (entry) => {
|
||||
entry.SetSize(1);
|
||||
var config = new ParsingConfig { CustomTypeProvider = new CustomTypeProvider(_reSettings.CustomTypes) };
|
||||
var typeParamExpressions = GetParameterExpression(ruleParams).ToArray();
|
||||
var e = DynamicExpressionParser.ParseLambda(config, true, typeParamExpressions.ToArray(), typeof(T), expression);
|
||||
var wrappedExpression = WrapExpression<T>(e,typeParamExpressions);
|
||||
return wrappedExpression.CompileFast<Func<object[],T>>();
|
||||
var wrappedExpression = WrapExpression<T>(e, typeParamExpressions);
|
||||
return wrappedExpression.CompileFast<Func<object[], T>>();
|
||||
});
|
||||
|
||||
|
||||
}
|
||||
|
||||
private Expression<Func<object[],T>> WrapExpression<T>(LambdaExpression expression, ParameterExpression[] parameters){
|
||||
var argExp = Expression.Parameter(typeof(object[]),"args");
|
||||
IEnumerable<Expression> paramExps = parameters.Select((c, i) => {
|
||||
private Expression<Func<object[], T>> WrapExpression<T>(LambdaExpression expression, ParameterExpression[] parameters)
|
||||
{
|
||||
var argExp = Expression.Parameter(typeof(object[]), "args");
|
||||
var paramExps = parameters.Select((c, i) => {
|
||||
var arg = Expression.ArrayAccess(argExp, Expression.Constant(i));
|
||||
return (Expression)Expression.Assign(c, Expression.Convert(arg, c.Type));
|
||||
});
|
||||
var blockExpSteps = paramExps.Concat(new List<Expression> { expression.Body });
|
||||
var blockExp = Expression.Block(parameters, blockExpSteps);
|
||||
return Expression.Lambda<Func<object[],T>>(blockExp, argExp);
|
||||
return Expression.Lambda<Func<object[], T>>(blockExp, argExp);
|
||||
}
|
||||
|
||||
|
||||
|
@ -77,9 +81,10 @@ namespace RulesEngine.ExpressionBuilders
|
|||
}
|
||||
}
|
||||
|
||||
private string GetCacheKey(string expression, RuleParameter[] ruleParameters,Type returnType){
|
||||
var paramKey = string.Join("|",ruleParameters.Select(c => c.Type.ToString()));
|
||||
var returnTypeKey = returnType?.ToString() ?? "null";
|
||||
private string GetCacheKey(string expression, RuleParameter[] ruleParameters, Type returnType)
|
||||
{
|
||||
var paramKey = string.Join("|", ruleParameters.Select(c => c.Type.ToString()));
|
||||
var returnTypeKey = returnType?.ToString() ?? "null";
|
||||
var combined = $"Expression:{expression}-Params:{paramKey}-ReturnType:{returnTypeKey}";
|
||||
return combined;
|
||||
}
|
||||
|
|
|
@ -5,7 +5,6 @@ using RulesEngine.Models;
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Linq.Expressions;
|
||||
|
||||
namespace RulesEngine.HelperFunctions
|
||||
{
|
||||
|
@ -14,12 +13,11 @@ namespace RulesEngine.HelperFunctions
|
|||
/// </summary>
|
||||
internal static class Helpers
|
||||
{
|
||||
internal static RuleFunc<RuleResultTree> ToResultTree(Rule rule, IEnumerable<RuleResultTree> childRuleResults, Func<object[],bool> isSuccessFunc, string exceptionMessage = "")
|
||||
internal static RuleFunc<RuleResultTree> ToResultTree(Rule rule, IEnumerable<RuleResultTree> childRuleResults, Func<object[], bool> isSuccessFunc, string exceptionMessage = "")
|
||||
{
|
||||
return (inputs) => new RuleResultTree
|
||||
{
|
||||
return (inputs) => new RuleResultTree {
|
||||
Rule = rule,
|
||||
Inputs = inputs.ToDictionary(c => c.Name,c => c.Value),
|
||||
Inputs = inputs.ToDictionary(c => c.Name, c => c.Value),
|
||||
IsSuccess = isSuccessFunc(inputs.Select(c => c.Value).ToArray()),
|
||||
ChildResults = childRuleResults,
|
||||
ExceptionMessage = exceptionMessage
|
||||
|
|
|
@ -14,7 +14,7 @@ namespace RulesEngine.HelperFunctions
|
|||
{
|
||||
public static object GetTypedObject(dynamic input)
|
||||
{
|
||||
if(input is ExpandoObject)
|
||||
if (input is ExpandoObject)
|
||||
{
|
||||
Type type = CreateAbstractClassType(input);
|
||||
return CreateObject(type, input);
|
||||
|
@ -28,11 +28,11 @@ namespace RulesEngine.HelperFunctions
|
|||
{
|
||||
List<DynamicProperty> props = new List<DynamicProperty>();
|
||||
|
||||
if(input == null)
|
||||
if (input == null)
|
||||
{
|
||||
return typeof(object);
|
||||
}
|
||||
if(!(input is ExpandoObject))
|
||||
if (!(input is ExpandoObject))
|
||||
{
|
||||
return input.GetType();
|
||||
}
|
||||
|
@ -51,7 +51,7 @@ namespace RulesEngine.HelperFunctions
|
|||
var internalType = CreateAbstractClassType(((IList)expando.Value)[0]);
|
||||
value = new List<object>().Cast(internalType).ToList(internalType).GetType();
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
else
|
||||
{
|
||||
|
@ -86,7 +86,7 @@ namespace RulesEngine.HelperFunctions
|
|||
}
|
||||
else if (expando.Value is IList)
|
||||
{
|
||||
var internalType = type.GetProperty(expando.Key).PropertyType.GenericTypeArguments.FirstOrDefault()??typeof(object);
|
||||
var internalType = type.GetProperty(expando.Key).PropertyType.GenericTypeArguments.FirstOrDefault() ?? typeof(object);
|
||||
var temp = (IList)expando.Value;
|
||||
var newList = new List<object>();
|
||||
for (int i = 0; i < temp.Count; i++)
|
||||
|
@ -123,5 +123,5 @@ namespace RulesEngine.HelperFunctions
|
|||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
}
|
||||
|
|
|
@ -8,7 +8,7 @@ using System.Threading.Tasks;
|
|||
namespace RulesEngine.Interfaces
|
||||
{
|
||||
public interface IRulesEngine
|
||||
{
|
||||
{
|
||||
/// <summary>
|
||||
/// This will execute all the rules of the specified workflow
|
||||
/// </summary>
|
||||
|
|
|
@ -1,9 +1,12 @@
|
|||
using System;
|
||||
// Copyright (c) Microsoft Corporation.
|
||||
// Licensed under the MIT License.
|
||||
|
||||
using System.Collections.Generic;
|
||||
using System.Text;
|
||||
using System.Diagnostics.CodeAnalysis;
|
||||
|
||||
namespace RulesEngine.Models
|
||||
{
|
||||
[ExcludeFromCodeCoverage]
|
||||
public class ActionInfo
|
||||
{
|
||||
public string Name { get; set; }
|
||||
|
|
|
@ -1,6 +1,15 @@
|
|||
using System;
|
||||
// Copyright (c) Microsoft Corporation.
|
||||
// Licensed under the MIT License.
|
||||
|
||||
public class ActionResult{
|
||||
public object Output {get; set;}
|
||||
public Exception Exception { get; set; }
|
||||
}
|
||||
using System;
|
||||
using System.Diagnostics.CodeAnalysis;
|
||||
|
||||
namespace RulesEngine.Models
|
||||
{
|
||||
[ExcludeFromCodeCoverage]
|
||||
public class ActionResult
|
||||
{
|
||||
public object Output { get; set; }
|
||||
public Exception Exception { get; set; }
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,7 +1,14 @@
|
|||
// Copyright (c) Microsoft Corporation.
|
||||
// Licensed under the MIT License.
|
||||
|
||||
using System.Collections.Generic;
|
||||
using RulesEngine.Models;
|
||||
using System.Diagnostics.CodeAnalysis;
|
||||
|
||||
|
||||
public class ActionRuleResult : ActionResult{
|
||||
public List<RuleResultTree> Results {get; set;}
|
||||
}
|
||||
namespace RulesEngine.Models
|
||||
{
|
||||
[ExcludeFromCodeCoverage]
|
||||
public class ActionRuleResult : ActionResult
|
||||
{
|
||||
public List<RuleResultTree> Results { get; set; }
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,7 +1,8 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
// Copyright (c) Microsoft Corporation.
|
||||
// Licensed under the MIT License.
|
||||
|
||||
using System;
|
||||
using System.Diagnostics.CodeAnalysis;
|
||||
using System.Text;
|
||||
|
||||
namespace RulesEngine.Models
|
||||
{
|
||||
|
@ -13,10 +14,10 @@ namespace RulesEngine.Models
|
|||
{
|
||||
internal string Name { get; set; }
|
||||
internal Type ReturnType { get; set; }
|
||||
internal Func<object[],object> Value { get; set; }
|
||||
internal Func<object[], object> Value { get; set; }
|
||||
internal RuleParameter AsRuleParameter()
|
||||
{
|
||||
return new RuleParameter(Name,ReturnType);
|
||||
return new RuleParameter(Name, ReturnType);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,4 +1,7 @@
|
|||
using Newtonsoft.Json;
|
||||
// Copyright (c) Microsoft Corporation.
|
||||
// Licensed under the MIT License.
|
||||
|
||||
using Newtonsoft.Json;
|
||||
using System.Diagnostics.CodeAnalysis;
|
||||
|
||||
namespace RulesEngine.Models
|
||||
|
|
|
@ -14,7 +14,7 @@ namespace RulesEngine.Models
|
|||
public Type[] CustomTypes { get; set; }
|
||||
public Dictionary<string, Func<ActionBase>> CustomActions { get; set; }
|
||||
public bool EnableExceptionAsErrorMessage { get; set; } = true;
|
||||
public bool EnableFormattedErrorMessage {get; set; } = true;
|
||||
public bool EnableLocalParams {get;set;} = true;
|
||||
public bool EnableFormattedErrorMessage { get; set; } = true;
|
||||
public bool EnableLocalParams { get; set; } = true;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -6,7 +6,6 @@ using Newtonsoft.Json.Converters;
|
|||
using RulesEngine.Enums;
|
||||
using System.Collections.Generic;
|
||||
using System.Diagnostics.CodeAnalysis;
|
||||
using System.Linq;
|
||||
|
||||
namespace RulesEngine.Models
|
||||
{
|
||||
|
|
|
@ -1,23 +1,24 @@
|
|||
// Copyright (c) Microsoft Corporation.
|
||||
// Licensed under the MIT License.
|
||||
|
||||
using RulesEngine.HelperFunctions;
|
||||
using System;
|
||||
using System.Diagnostics.CodeAnalysis;
|
||||
using RulesEngine.HelperFunctions;
|
||||
|
||||
namespace RulesEngine.Models
|
||||
{
|
||||
[ExcludeFromCodeCoverage]
|
||||
public class RuleParameter
|
||||
{
|
||||
public RuleParameter(string name,object value)
|
||||
public RuleParameter(string name, object value)
|
||||
{
|
||||
Value = Utils.GetTypedObject(value);
|
||||
Type = Value.GetType();
|
||||
Name = name;
|
||||
}
|
||||
|
||||
internal RuleParameter(string name,Type type){
|
||||
internal RuleParameter(string name, Type type)
|
||||
{
|
||||
Name = name;
|
||||
Type = type;
|
||||
}
|
||||
|
|
|
@ -40,9 +40,9 @@ namespace RulesEngine.Models
|
|||
/// <summary>
|
||||
/// Gets or sets the input object
|
||||
/// </summary>
|
||||
public Dictionary<string,object> Inputs { get; set; }
|
||||
public Dictionary<string, object> Inputs { get; set; }
|
||||
|
||||
public ActionResult ActionResult {get; set;}
|
||||
public ActionResult ActionResult { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets the exception message in case an error is thrown during rules calculation.
|
||||
|
|
|
@ -1,9 +1,11 @@
|
|||
using RulesEngine.Models;
|
||||
// Copyright (c) Microsoft Corporation.
|
||||
// Licensed under the MIT License.
|
||||
|
||||
using RulesEngine.ExpressionBuilders;
|
||||
using RulesEngine.Models;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using RulesEngine.ExpressionBuilders;
|
||||
using RulesEngine.HelperFunctions;
|
||||
|
||||
namespace RulesEngine
|
||||
{
|
||||
|
@ -32,8 +34,8 @@ namespace RulesEngine
|
|||
/// </returns>
|
||||
public IEnumerable<CompiledParam> CompileParamsExpression(Rule rule, IEnumerable<RuleParameter> ruleParams)
|
||||
{
|
||||
|
||||
if(rule.LocalParams == null) return null;
|
||||
|
||||
if (rule.LocalParams == null) return null;
|
||||
|
||||
var compiledParameters = new List<CompiledParam>();
|
||||
var evaluatedParameters = new List<RuleParameter>();
|
||||
|
@ -54,7 +56,7 @@ namespace RulesEngine
|
|||
/// <param name="compiledParam">The compiled parameter.</param>
|
||||
/// <param name="ruleParams">The rule parameters.</param>
|
||||
/// <returns>RuleParameter.</returns>
|
||||
public RuleParameter EvaluateCompiledParam(string paramName, Func<object[],object> compiledParam, IEnumerable<RuleParameter> inputs)
|
||||
public RuleParameter EvaluateCompiledParam(string paramName, Func<object[], object> compiledParam, IEnumerable<RuleParameter> inputs)
|
||||
{
|
||||
var result = compiledParam(inputs.Select(c => c.Value).ToArray());
|
||||
return new RuleParameter(paramName, result);
|
||||
|
@ -68,7 +70,7 @@ namespace RulesEngine
|
|||
/// <param name="typeParameterExpressions">The type parameter expressions.</param>
|
||||
/// <param name="ruleInputExp">The rule input exp.</param>
|
||||
/// <returns></returns>
|
||||
private Func<object[],object> GetDelegateForRuleParam(LocalParam param, RuleParameter[] ruleParameters)
|
||||
private Func<object[], object> GetDelegateForRuleParam(LocalParam param, RuleParameter[] ruleParameters)
|
||||
{
|
||||
return _ruleExpressionParser.Compile<object>(param.Expression, ruleParameters);
|
||||
}
|
||||
|
|
|
@ -38,18 +38,8 @@ namespace RulesEngine
|
|||
/// <exception cref="ArgumentNullException">expressionBuilderFactory</exception>
|
||||
internal RuleCompiler(RuleExpressionBuilderFactory expressionBuilderFactory, ILogger logger)
|
||||
{
|
||||
if (expressionBuilderFactory == null)
|
||||
{
|
||||
throw new ArgumentNullException($"{nameof(expressionBuilderFactory)} can't be null.");
|
||||
}
|
||||
|
||||
if (logger == null)
|
||||
{
|
||||
throw new ArgumentNullException($"{nameof(logger)} can't be null.");
|
||||
}
|
||||
|
||||
_logger = logger;
|
||||
_expressionBuilderFactory = expressionBuilderFactory;
|
||||
_logger = logger ?? throw new ArgumentNullException($"{nameof(logger)} can't be null.");
|
||||
_expressionBuilderFactory = expressionBuilderFactory ?? throw new ArgumentNullException($"{nameof(expressionBuilderFactory)} can't be null.");
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
|
@ -60,15 +50,15 @@ namespace RulesEngine
|
|||
/// <param name="input"></param>
|
||||
/// <param name="ruleParam"></param>
|
||||
/// <returns>Compiled func delegate</returns>
|
||||
internal RuleFunc<RuleResultTree> CompileRule(Rule rule,params RuleParameter[] ruleParams)
|
||||
internal RuleFunc<RuleResultTree> CompileRule(Rule rule, params RuleParameter[] ruleParams)
|
||||
{
|
||||
try
|
||||
{
|
||||
if(rule == null)
|
||||
if (rule == null)
|
||||
{
|
||||
throw new ArgumentNullException(nameof(rule));
|
||||
}
|
||||
RuleFunc<RuleResultTree> ruleExpression = GetDelegateForRule(rule,ruleParams);
|
||||
var ruleExpression = GetDelegateForRule(rule, ruleParams);
|
||||
return ruleExpression;
|
||||
}
|
||||
catch (Exception ex)
|
||||
|
@ -78,7 +68,7 @@ namespace RulesEngine
|
|||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// Gets the expression for rule.
|
||||
|
@ -89,9 +79,7 @@ namespace RulesEngine
|
|||
/// <returns></returns>
|
||||
private RuleFunc<RuleResultTree> GetDelegateForRule(Rule rule, RuleParameter[] ruleParams)
|
||||
{
|
||||
ExpressionType nestedOperator;
|
||||
|
||||
if (Enum.TryParse(rule.Operator, out nestedOperator) && nestedOperators.Contains(nestedOperator) &&
|
||||
if (Enum.TryParse(rule.Operator, out ExpressionType nestedOperator) && nestedOperators.Contains(nestedOperator) &&
|
||||
rule.Rules != null && rule.Rules.Any())
|
||||
{
|
||||
return BuildNestedRuleFunc(rule, nestedOperator, ruleParams);
|
||||
|
@ -142,13 +130,12 @@ namespace RulesEngine
|
|||
ruleFuncList.Add(GetDelegateForRule(r, ruleParams));
|
||||
}
|
||||
|
||||
return (paramArray) =>
|
||||
{
|
||||
var resultList = ruleFuncList.Select(fn => fn(paramArray));
|
||||
Func<object[],bool> isSuccess = (p) => ApplyOperation(resultList, operation);
|
||||
RuleFunc<RuleResultTree> result = Helpers.ToResultTree(parentRule, resultList,isSuccess);
|
||||
return result(paramArray);
|
||||
};
|
||||
return (paramArray) => {
|
||||
var resultList = ruleFuncList.Select(fn => fn(paramArray));
|
||||
Func<object[], bool> isSuccess = (p) => ApplyOperation(resultList, operation);
|
||||
var result = Helpers.ToResultTree(parentRule, resultList, isSuccess);
|
||||
return result(paramArray);
|
||||
};
|
||||
}
|
||||
|
||||
|
||||
|
|
|
@ -13,7 +13,7 @@ namespace RulesEngine
|
|||
internal class RulesCache
|
||||
{
|
||||
/// <summary>The compile rules</summary>
|
||||
private ConcurrentDictionary<string, IDictionary<string,RuleFunc<RuleResultTree>>> _compileRules = new ConcurrentDictionary<string, IDictionary<string,RuleFunc<RuleResultTree>>>();
|
||||
private ConcurrentDictionary<string, IDictionary<string, RuleFunc<RuleResultTree>>> _compileRules = new ConcurrentDictionary<string, IDictionary<string, RuleFunc<RuleResultTree>>>();
|
||||
|
||||
/// <summary>The workflow rules</summary>
|
||||
private ConcurrentDictionary<string, WorkflowRules> _workflowRules = new ConcurrentDictionary<string, WorkflowRules>();
|
||||
|
@ -47,7 +47,7 @@ namespace RulesEngine
|
|||
/// <summary>Adds the or update compiled rule.</summary>
|
||||
/// <param name="compiledRuleKey">The compiled rule key.</param>
|
||||
/// <param name="compiledRule">The compiled rule.</param>
|
||||
public void AddOrUpdateCompiledRule(string compiledRuleKey, IDictionary<string,RuleFunc<RuleResultTree>> compiledRule)
|
||||
public void AddOrUpdateCompiledRule(string compiledRuleKey, IDictionary<string, RuleFunc<RuleResultTree>> compiledRule)
|
||||
{
|
||||
_compileRules.AddOrUpdate(compiledRuleKey, compiledRule, (k, v) => compiledRule);
|
||||
}
|
||||
|
@ -100,7 +100,7 @@ namespace RulesEngine
|
|||
return workflowRules;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
/// <summary>Gets the compiled rules.</summary>
|
||||
/// <param name="compiledRulesKey">The compiled rules key.</param>
|
||||
|
@ -119,7 +119,7 @@ namespace RulesEngine
|
|||
var compiledKeysToRemove = _compileRules.Keys.Where(key => key.StartsWith(workflowName));
|
||||
foreach (var key in compiledKeysToRemove)
|
||||
{
|
||||
_compileRules.TryRemove(key, out IDictionary<string,RuleFunc<RuleResultTree>> val);
|
||||
_compileRules.TryRemove(key, out IDictionary<string, RuleFunc<RuleResultTree>> val);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,7 +1,6 @@
|
|||
// Copyright (c) Microsoft Corporation.
|
||||
// Licensed under the MIT License.
|
||||
|
||||
using System.Threading.Tasks;
|
||||
using FluentValidation;
|
||||
using Microsoft.Extensions.Caching.Memory;
|
||||
using Microsoft.Extensions.Logging;
|
||||
|
@ -11,6 +10,7 @@ using Newtonsoft.Json.Linq;
|
|||
using RulesEngine.Actions;
|
||||
using RulesEngine.Enums;
|
||||
using RulesEngine.Exceptions;
|
||||
using RulesEngine.ExpressionBuilders;
|
||||
using RulesEngine.Interfaces;
|
||||
using RulesEngine.Models;
|
||||
using RulesEngine.Validators;
|
||||
|
@ -18,7 +18,7 @@ using System;
|
|||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text.RegularExpressions;
|
||||
using RulesEngine.ExpressionBuilders;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace RulesEngine
|
||||
{
|
||||
|
@ -58,15 +58,16 @@ namespace RulesEngine
|
|||
_reSettings = reSettings ?? new ReSettings();
|
||||
_ruleExpressionParser = new RuleExpressionParser(_reSettings);
|
||||
_ruleParamCompiler = new ParamCompiler(_reSettings, _ruleExpressionParser);
|
||||
_ruleCompiler = new RuleCompiler(new RuleExpressionBuilderFactory(_reSettings, _ruleExpressionParser),_logger);
|
||||
_ruleCompiler = new RuleCompiler(new RuleExpressionBuilderFactory(_reSettings, _ruleExpressionParser), _logger);
|
||||
_actionFactory = new ActionFactory(GetActionRegistry(_reSettings));
|
||||
}
|
||||
|
||||
private IDictionary<string,Func<ActionBase>> GetActionRegistry(ReSettings reSettings)
|
||||
private IDictionary<string, Func<ActionBase>> GetActionRegistry(ReSettings reSettings)
|
||||
{
|
||||
var actionDictionary = GetDefaultActionRegistry();
|
||||
var customActions = reSettings.CustomActions ?? new Dictionary<string, Func<ActionBase>>();
|
||||
foreach(var customAction in customActions){
|
||||
foreach (var customAction in customActions)
|
||||
{
|
||||
actionDictionary.Add(customAction);
|
||||
}
|
||||
return actionDictionary;
|
||||
|
@ -88,7 +89,7 @@ namespace RulesEngine
|
|||
|
||||
var ruleParams = new List<RuleParameter>();
|
||||
|
||||
for (int i = 0; i < inputs.Length; i++)
|
||||
for (var i = 0; i < inputs.Length; i++)
|
||||
{
|
||||
var input = inputs[i];
|
||||
ruleParams.Add(new RuleParameter($"input{i + 1}", input));
|
||||
|
@ -105,10 +106,11 @@ namespace RulesEngine
|
|||
/// <returns>List of rule results</returns>
|
||||
public async ValueTask<List<RuleResultTree>> ExecuteAllRulesAsync(string workflowName, params RuleParameter[] ruleParams)
|
||||
{
|
||||
var ruleResultList = ValidateWorkflowAndExecuteRule(workflowName, ruleParams);
|
||||
foreach(var ruleResult in ruleResultList){
|
||||
var actionResult = await ExecuteActionForRuleResult(ruleResult,false);
|
||||
ruleResult.ActionResult = new ActionResult{
|
||||
var ruleResultList = ValidateWorkflowAndExecuteRule(workflowName, ruleParams);
|
||||
foreach (var ruleResult in ruleResultList)
|
||||
{
|
||||
var actionResult = await ExecuteActionForRuleResult(ruleResult, false);
|
||||
ruleResult.ActionResult = new ActionResult {
|
||||
Output = actionResult.Output,
|
||||
Exception = actionResult.Exception
|
||||
};
|
||||
|
@ -121,27 +123,26 @@ namespace RulesEngine
|
|||
{
|
||||
var compiledRule = CompileRule(workflowName, ruleName, ruleParameters);
|
||||
var resultTree = compiledRule(ruleParameters);
|
||||
return await ExecuteActionForRuleResult(resultTree,true);
|
||||
return await ExecuteActionForRuleResult(resultTree, true);
|
||||
}
|
||||
|
||||
private async ValueTask<ActionRuleResult> ExecuteActionForRuleResult(RuleResultTree resultTree, bool includeRuleResults=false)
|
||||
private async ValueTask<ActionRuleResult> ExecuteActionForRuleResult(RuleResultTree resultTree, bool includeRuleResults = false)
|
||||
{
|
||||
ActionTriggerType triggerType = resultTree?.IsSuccess == true ? ActionTriggerType.onSuccess : ActionTriggerType.onFailure;
|
||||
var triggerType = resultTree?.IsSuccess == true ? ActionTriggerType.onSuccess : ActionTriggerType.onFailure;
|
||||
|
||||
if (resultTree?.Rule?.Actions != null && resultTree.Rule.Actions.ContainsKey(triggerType))
|
||||
{
|
||||
var actionInfo = resultTree.Rule.Actions[triggerType];
|
||||
var action = _actionFactory.Get(actionInfo.Name);
|
||||
var ruleParameters = resultTree.Inputs.Select(kv => new RuleParameter(kv.Key,kv.Value)).ToArray();
|
||||
return await action.ExecuteAndReturnResultAsync(new ActionContext(actionInfo.Context, resultTree), ruleParameters,includeRuleResults);
|
||||
var ruleParameters = resultTree.Inputs.Select(kv => new RuleParameter(kv.Key, kv.Value)).ToArray();
|
||||
return await action.ExecuteAndReturnResultAsync(new ActionContext(actionInfo.Context, resultTree), ruleParameters, includeRuleResults);
|
||||
}
|
||||
else
|
||||
{
|
||||
//If there is no action,return output as null and return the result for rule
|
||||
return new ActionRuleResult
|
||||
{
|
||||
return new ActionRuleResult {
|
||||
Output = null,
|
||||
Results = includeRuleResults ? new List<RuleResultTree>() { resultTree }: null
|
||||
Results = includeRuleResults ? new List<RuleResultTree>() { resultTree } : null
|
||||
};
|
||||
}
|
||||
}
|
||||
|
@ -226,20 +227,22 @@ namespace RulesEngine
|
|||
/// </returns>
|
||||
private bool RegisterRule(string workflowName, params RuleParameter[] ruleParams)
|
||||
{
|
||||
string compileRulesKey = GetCompiledRulesKey(workflowName,ruleParams);
|
||||
var compileRulesKey = GetCompiledRulesKey(workflowName, ruleParams);
|
||||
if (_rulesCache.ContainsCompiledRules(compileRulesKey))
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
var workflowRules = _rulesCache.GetWorkFlowRules(workflowName);
|
||||
if (workflowRules != null)
|
||||
{
|
||||
var dictFunc = new Dictionary<string,RuleFunc<RuleResultTree>>();
|
||||
var dictFunc = new Dictionary<string, RuleFunc<RuleResultTree>>();
|
||||
foreach (var rule in workflowRules.Rules)
|
||||
{
|
||||
dictFunc.Add(rule.RuleName,CompileRule(workflowName, ruleParams, rule));
|
||||
dictFunc.Add(rule.RuleName, CompileRule(workflowName, ruleParams, rule));
|
||||
}
|
||||
|
||||
_rulesCache.AddOrUpdateCompiledRule(compileRulesKey,dictFunc);
|
||||
_rulesCache.AddOrUpdateCompiledRule(compileRulesKey, dictFunc);
|
||||
_logger.LogTrace($"Rules has been compiled for the {workflowName} workflow and added to dictionary");
|
||||
return true;
|
||||
}
|
||||
|
@ -250,30 +253,32 @@ namespace RulesEngine
|
|||
}
|
||||
|
||||
|
||||
private RuleFunc<RuleResultTree> CompileRule(string workflowName,string ruleName,RuleParameter[] ruleParameters){
|
||||
private RuleFunc<RuleResultTree> CompileRule(string workflowName, string ruleName, RuleParameter[] ruleParameters)
|
||||
{
|
||||
var rules = _rulesCache.GetRules(workflowName);
|
||||
var currentRule = rules?.SingleOrDefault(c => c.RuleName == ruleName);
|
||||
if(currentRule == null){
|
||||
if (currentRule == null)
|
||||
{
|
||||
throw new ArgumentException($"Workflow `{workflowName}` does not contain any rule named `{ruleName}`");
|
||||
}
|
||||
return CompileRule(workflowName,ruleParameters,currentRule);
|
||||
return CompileRule(workflowName, ruleParameters, currentRule);
|
||||
}
|
||||
|
||||
private RuleFunc<RuleResultTree> CompileRule(string workflowName, RuleParameter[] ruleParams, Rule rule)
|
||||
{
|
||||
if(!_reSettings.EnableLocalParams){
|
||||
return _ruleCompiler.CompileRule(rule,ruleParams);
|
||||
if (!_reSettings.EnableLocalParams)
|
||||
{
|
||||
return _ruleCompiler.CompileRule(rule, ruleParams);
|
||||
}
|
||||
var compiledParamsKey = GetCompiledParamsCacheKey(workflowName, rule.RuleName, ruleParams);
|
||||
IEnumerable<CompiledParam> compiledParamList = _compiledParamsCache.GetOrCreate(compiledParamsKey, (entry) => _ruleParamCompiler.CompileParamsExpression(rule, ruleParams));
|
||||
var compiledParamList = _compiledParamsCache.GetOrCreate(compiledParamsKey, (entry) => _ruleParamCompiler.CompileParamsExpression(rule, ruleParams));
|
||||
var compiledRuleParameters = compiledParamList?.Select(c => c.AsRuleParameter()) ?? new List<RuleParameter>();
|
||||
var updatedRuleParams = ruleParams?.Concat(compiledRuleParameters);
|
||||
var compiledRule = _ruleCompiler.CompileRule(rule, updatedRuleParams?.ToArray());
|
||||
|
||||
RuleFunc<RuleResultTree> updatedRule = (RuleParameter[] paramList) =>
|
||||
{
|
||||
RuleFunc<RuleResultTree> updatedRule = (RuleParameter[] paramList) => {
|
||||
var inputs = paramList.AsEnumerable();
|
||||
IEnumerable<CompiledParam> localParams = compiledParamList ?? new List<CompiledParam>();
|
||||
var localParams = compiledParamList ?? new List<CompiledParam>();
|
||||
var evaluatedParamList = new List<RuleParameter>();
|
||||
foreach (var localParam in localParams)
|
||||
{
|
||||
|
@ -288,7 +293,7 @@ namespace RulesEngine
|
|||
return updatedRule;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// This will execute the compiled rules
|
||||
|
@ -300,8 +305,8 @@ namespace RulesEngine
|
|||
{
|
||||
_logger.LogTrace($"Compiled rules found for {workflowName} workflow and executed");
|
||||
|
||||
List<RuleResultTree> result = new List<RuleResultTree>();
|
||||
string compiledRulesCacheKey = GetCompiledRulesKey(workflowName,ruleParameters);
|
||||
var result = new List<RuleResultTree>();
|
||||
var compiledRulesCacheKey = GetCompiledRulesKey(workflowName, ruleParameters);
|
||||
foreach (var compiledRule in _rulesCache.GetCompiledRules(compiledRulesCacheKey)?.Values)
|
||||
{
|
||||
var resultTree = compiledRule(ruleParameters);
|
||||
|
@ -311,20 +316,21 @@ namespace RulesEngine
|
|||
FormatErrorMessages(result);
|
||||
return result;
|
||||
}
|
||||
|
||||
|
||||
private string GetCompiledRulesKey(string workflowName, RuleParameter[] ruleParams)
|
||||
{
|
||||
var key = $"{workflowName}-" + String.Join("-", ruleParams.Select(c => c.Type.Name));
|
||||
var key = $"{workflowName}-" + string.Join("-", ruleParams.Select(c => c.Type.Name));
|
||||
return key;
|
||||
}
|
||||
|
||||
private string GetCompiledParamsCacheKey(string workflowName,string ruleName,RuleParameter[] ruleParams)
|
||||
private string GetCompiledParamsCacheKey(string workflowName, string ruleName, RuleParameter[] ruleParams)
|
||||
{
|
||||
var key = $"compiledparams-{workflowName}-{ruleName}" + String.Join("-", ruleParams.Select(c => c.Type.Name));
|
||||
return key;
|
||||
var key = $"compiledparams-{workflowName}-{ruleName}" + string.Join("-", ruleParams.Select(c => c.Type.Name));
|
||||
return key;
|
||||
}
|
||||
|
||||
private IDictionary<string,Func<ActionBase>> GetDefaultActionRegistry(){
|
||||
private IDictionary<string, Func<ActionBase>> GetDefaultActionRegistry()
|
||||
{
|
||||
return new Dictionary<string, Func<ActionBase>>{
|
||||
{"OutputExpression",() => new OutputExpressionAction(_ruleExpressionParser) },
|
||||
{"EvaluateRule", () => new EvaluateRuleAction(this) }
|
||||
|
@ -338,11 +344,13 @@ namespace RulesEngine
|
|||
/// <returns>Updated error message.</returns>
|
||||
private IEnumerable<RuleResultTree> FormatErrorMessages(IEnumerable<RuleResultTree> ruleResultList)
|
||||
{
|
||||
if(_reSettings.EnableFormattedErrorMessage){
|
||||
if (_reSettings.EnableFormattedErrorMessage)
|
||||
{
|
||||
foreach (var ruleResult in ruleResultList?.Where(r => !r.IsSuccess))
|
||||
{
|
||||
var errorMessage = ruleResult?.Rule?.ErrorMessage;
|
||||
if(errorMessage != null){
|
||||
if (errorMessage != null)
|
||||
{
|
||||
var errorParameters = Regex.Matches(errorMessage, ParamParseRegex);
|
||||
|
||||
var inputs = ruleResult.Inputs;
|
||||
|
@ -366,7 +374,7 @@ namespace RulesEngine
|
|||
}
|
||||
ruleResult.ExceptionMessage = errorMessage;
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
}
|
||||
return ruleResultList;
|
||||
|
@ -381,9 +389,9 @@ namespace RulesEngine
|
|||
/// <param name="typeName">Name of the type.</param>
|
||||
/// <param name="propertyName">Name of the property.</param>
|
||||
/// <returns>Updated error message.</returns>
|
||||
private static string UpdateErrorMessage(string errorMessage, IDictionary<string,object> inputs, string property, string typeName, string propertyName)
|
||||
private static string UpdateErrorMessage(string errorMessage, IDictionary<string, object> inputs, string property, string typeName, string propertyName)
|
||||
{
|
||||
var arrParams = inputs?.Select(c => new {Name = c.Key, c.Value });
|
||||
var arrParams = inputs?.Select(c => new { Name = c.Key, c.Value });
|
||||
var model = arrParams?.Where(a => string.Equals(a.Name, typeName))?.FirstOrDefault();
|
||||
if (model != null)
|
||||
{
|
||||
|
|
|
@ -2,7 +2,7 @@
|
|||
|
||||
<PropertyGroup>
|
||||
<TargetFramework>netstandard2.0</TargetFramework>
|
||||
<Version>3.0.0</Version>
|
||||
<Version>3.0.1</Version>
|
||||
<Copyright>Copyright (c) Microsoft Corporation.</Copyright>
|
||||
<PackageLicenseFile>LICENSE</PackageLicenseFile>
|
||||
<PackageProjectUrl>https://github.com/microsoft/RulesEngine</PackageProjectUrl>
|
||||
|
|
|
@ -1,13 +1,13 @@
|
|||
// Copyright (c) Microsoft Corporation.
|
||||
// Licensed under the MIT License.
|
||||
|
||||
using FluentValidation;
|
||||
using RulesEngine.HelperFunctions;
|
||||
using RulesEngine.Models;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Linq.Expressions;
|
||||
using FluentValidation;
|
||||
using RulesEngine.HelperFunctions;
|
||||
using RulesEngine.Models;
|
||||
|
||||
namespace RulesEngine.Validators
|
||||
{
|
||||
|
@ -19,15 +19,13 @@ namespace RulesEngine.Validators
|
|||
RuleFor(c => c.RuleName).NotEmpty().WithMessage(Constants.RULE_NAME_NULL_ERRMSG);
|
||||
|
||||
//Nested expression check
|
||||
When(c => c.RuleExpressionType == null,() =>
|
||||
{
|
||||
When(c => c.RuleExpressionType == null, () => {
|
||||
RuleFor(c => c.Operator)
|
||||
.NotNull().WithMessage(Constants.OPERATOR_NULL_ERRMSG)
|
||||
.Must(op => _nestedOperators.Any(x => x.ToString().Equals(op, StringComparison.OrdinalIgnoreCase)))
|
||||
.WithMessage(Constants.OPERATOR_INCORRECT_ERRMSG);
|
||||
|
||||
When(c => c.Rules?.Any() != true, () =>
|
||||
{
|
||||
When(c => c.Rules?.Any() != true, () => {
|
||||
RuleFor(c => c.WorkflowRulesToInject).NotEmpty().WithMessage(Constants.INJECT_WORKFLOW_RULES_ERRMSG);
|
||||
})
|
||||
.Otherwise(() => {
|
||||
|
@ -39,8 +37,7 @@ namespace RulesEngine.Validators
|
|||
|
||||
private void RegisterExpressionTypeRules()
|
||||
{
|
||||
When(c => c.RuleExpressionType == RuleExpressionType.LambdaExpression, () =>
|
||||
{
|
||||
When(c => c.RuleExpressionType == RuleExpressionType.LambdaExpression, () => {
|
||||
RuleFor(c => c.Expression).NotEmpty().WithMessage(Constants.LAMBDA_EXPRESSION_EXPRESSION_NULL_ERRMSG);
|
||||
RuleFor(c => c.Operator).Null().WithMessage(Constants.LAMBDA_EXPRESSION_OPERATOR_ERRMSG);
|
||||
RuleFor(c => c.Rules).Null().WithMessage(Constants.LAMBDA_EXPRESSION_RULES_ERRMSG);
|
||||
|
@ -52,7 +49,8 @@ namespace RulesEngine.Validators
|
|||
if (rules?.Any() != true) return false;
|
||||
var validator = new RuleValidator();
|
||||
var isValid = true;
|
||||
foreach(var rule in rules){
|
||||
foreach (var rule in rules)
|
||||
{
|
||||
isValid &= validator.Validate(rule).IsValid;
|
||||
if (!isValid) break;
|
||||
}
|
||||
|
|
|
@ -1,10 +1,10 @@
|
|||
// Copyright (c) Microsoft Corporation.
|
||||
// Licensed under the MIT License.
|
||||
|
||||
using System.Linq;
|
||||
using FluentValidation;
|
||||
using RulesEngine.HelperFunctions;
|
||||
using RulesEngine.Models;
|
||||
using System.Linq;
|
||||
|
||||
namespace RulesEngine.Validators
|
||||
{
|
||||
|
@ -13,8 +13,7 @@ namespace RulesEngine.Validators
|
|||
public WorkflowRulesValidator()
|
||||
{
|
||||
RuleFor(c => c.WorkflowName).NotEmpty().WithMessage(Constants.WORKFLOW_NAME_NULL_ERRMSG);
|
||||
When(c => c.Rules?.Any() != true, () =>
|
||||
{
|
||||
When(c => c.Rules?.Any() != true, () => {
|
||||
RuleFor(c => c.WorkflowRulesToInject).NotEmpty().WithMessage(Constants.INJECT_WORKFLOW_RULES_ERRMSG);
|
||||
}).Otherwise(() => {
|
||||
var ruleValidator = new RuleValidator();
|
||||
|
|
|
@ -1,5 +1,7 @@
|
|||
// Copyright (c) Microsoft Corporation.
|
||||
// Licensed under the MIT License.
|
||||
|
||||
using AutoFixture;
|
||||
using Moq;
|
||||
using RulesEngine.Actions;
|
||||
using RulesEngine.Models;
|
||||
using System;
|
||||
|
|
|
@ -1,23 +1,28 @@
|
|||
// Copyright (c) Microsoft Corporation.
|
||||
// Licensed under the MIT License.
|
||||
|
||||
using RulesEngine.Enums;
|
||||
using RulesEngine.Models;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Diagnostics.CodeAnalysis;
|
||||
using System.Linq;
|
||||
using System.Threading.Tasks;
|
||||
using RulesEngine.Enums;
|
||||
using RulesEngine.Models;
|
||||
using Xunit;
|
||||
|
||||
namespace RulesEngine.UnitTest{
|
||||
namespace RulesEngine.UnitTest
|
||||
{
|
||||
|
||||
[ExcludeFromCodeCoverage]
|
||||
public class RulesEngineWithActionsTests{
|
||||
public class RulesEngineWithActionsTests
|
||||
{
|
||||
|
||||
[Fact]
|
||||
public async Task WhenExpressionIsSuccess_OutputExpressionAction_ReturnsExpressionEvaluation(){
|
||||
public async Task WhenExpressionIsSuccess_OutputExpressionAction_ReturnsExpressionEvaluation()
|
||||
{
|
||||
var engine = new RulesEngine(GetWorkflowWithActions());
|
||||
var result = await engine.ExecuteActionWorkflowAsync("ActionWorkflow", "ExpressionOutputRuleTest", new RuleParameter[0]);
|
||||
Assert.NotNull(result);
|
||||
Assert.Equal(2*2,result.Output);
|
||||
Assert.Equal(2 * 2, result.Output);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
|
@ -50,8 +55,9 @@ namespace RulesEngine.UnitTest{
|
|||
}
|
||||
|
||||
|
||||
private WorkflowRules[] GetWorkflowRulesWithoutActions(){
|
||||
var workflow1 = new WorkflowRules{
|
||||
private WorkflowRules[] GetWorkflowRulesWithoutActions()
|
||||
{
|
||||
var workflow1 = new WorkflowRules {
|
||||
WorkflowName = "NoActionWorkflow",
|
||||
Rules = new List<Rule>{
|
||||
new Rule{
|
||||
|
@ -62,12 +68,13 @@ namespace RulesEngine.UnitTest{
|
|||
|
||||
}
|
||||
};
|
||||
return new []{workflow1};
|
||||
return new[] { workflow1 };
|
||||
}
|
||||
|
||||
private WorkflowRules[] GetWorkflowWithActions(){
|
||||
|
||||
var workflow1 = new WorkflowRules{
|
||||
private WorkflowRules[] GetWorkflowWithActions()
|
||||
{
|
||||
|
||||
var workflow1 = new WorkflowRules {
|
||||
WorkflowName = "ActionWorkflow",
|
||||
Rules = new List<Rule>{
|
||||
new Rule{
|
||||
|
@ -100,7 +107,7 @@ namespace RulesEngine.UnitTest{
|
|||
|
||||
}
|
||||
};
|
||||
return new []{workflow1};
|
||||
return new[] { workflow1 };
|
||||
}
|
||||
}
|
||||
}
|
|
@ -2,20 +2,20 @@
|
|||
// Licensed under the MIT License.
|
||||
|
||||
using Microsoft.Extensions.Logging;
|
||||
using RulesEngine.Exceptions;
|
||||
using RulesEngine.Models;
|
||||
using Moq;
|
||||
using Newtonsoft.Json;
|
||||
using Newtonsoft.Json.Converters;
|
||||
using RulesEngine.Exceptions;
|
||||
using RulesEngine.HelperFunctions;
|
||||
using RulesEngine.Models;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Diagnostics.CodeAnalysis;
|
||||
using System.Dynamic;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using Xunit;
|
||||
using Newtonsoft.Json.Converters;
|
||||
using RulesEngine.HelperFunctions;
|
||||
using System.Diagnostics.CodeAnalysis;
|
||||
using System.Threading.Tasks;
|
||||
using Xunit;
|
||||
|
||||
namespace RulesEngine.UnitTest
|
||||
{
|
||||
|
@ -41,7 +41,7 @@ namespace RulesEngine.UnitTest
|
|||
dynamic input2 = GetInput2();
|
||||
dynamic input3 = GetInput3();
|
||||
|
||||
var result = await re.ExecuteAllRulesAsync("inputWorkflowReference",input1, input2, input3);
|
||||
var result = await re.ExecuteAllRulesAsync("inputWorkflowReference", input1, input2, input3);
|
||||
Assert.NotNull(result);
|
||||
Assert.IsType<List<RuleResultTree>>(result);
|
||||
}
|
||||
|
@ -59,7 +59,7 @@ namespace RulesEngine.UnitTest
|
|||
List<RuleResultTree> result = await re.ExecuteAllRulesAsync("inputWorkflow", input1, input2, input3);
|
||||
Assert.NotNull(result);
|
||||
Assert.IsType<List<RuleResultTree>>(result);
|
||||
Assert.Contains(result,c => c.IsSuccess);
|
||||
Assert.Contains(result, c => c.IsSuccess);
|
||||
}
|
||||
|
||||
[Theory]
|
||||
|
@ -79,7 +79,7 @@ namespace RulesEngine.UnitTest
|
|||
dynamic input7 = GetInput1();
|
||||
dynamic input8 = GetInput2();
|
||||
dynamic input9 = GetInput3();
|
||||
|
||||
|
||||
dynamic input10 = GetInput1();
|
||||
dynamic input11 = GetInput2();
|
||||
dynamic input12 = GetInput3();
|
||||
|
@ -93,7 +93,7 @@ namespace RulesEngine.UnitTest
|
|||
dynamic input17 = GetInput2();
|
||||
dynamic input18 = GetInput3();
|
||||
|
||||
List<RuleResultTree> result = await re.ExecuteAllRulesAsync("inputWorkflow", input1, input2, input3,input4, input5, input6, input7, input8, input9, input10, input11, input12, input13, input14, input15, input16, input17, input18);
|
||||
List<RuleResultTree> result = await re.ExecuteAllRulesAsync("inputWorkflow", input1, input2, input3, input4, input5, input6, input7, input8, input9, input10, input11, input12, input13, input14, input15, input16, input17, input18);
|
||||
Assert.NotNull(result);
|
||||
Assert.IsType<List<RuleResultTree>>(result);
|
||||
Assert.Contains(result, c => c.IsSuccess);
|
||||
|
@ -123,8 +123,8 @@ namespace RulesEngine.UnitTest
|
|||
var expected = result1.Select(c => new { c.Rule.RuleName, c.IsSuccess });
|
||||
var actual = result2.Select(c => new { c.Rule.RuleName, c.IsSuccess });
|
||||
Assert.Equal(expected, actual);
|
||||
|
||||
|
||||
|
||||
|
||||
}
|
||||
|
||||
[Theory]
|
||||
|
@ -140,7 +140,7 @@ namespace RulesEngine.UnitTest
|
|||
List<RuleResultTree> result = await re.ExecuteAllRulesAsync("inputWorkflow", input1);
|
||||
Assert.NotNull(result);
|
||||
Assert.IsType<List<RuleResultTree>>(result);
|
||||
Assert.DoesNotContain(result,c => c.IsSuccess);
|
||||
Assert.DoesNotContain(result, c => c.IsSuccess);
|
||||
}
|
||||
|
||||
[Theory]
|
||||
|
@ -168,7 +168,7 @@ namespace RulesEngine.UnitTest
|
|||
dynamic input2 = GetInput2();
|
||||
dynamic input3 = GetInput3();
|
||||
|
||||
List<RuleResultTree> result = await re.ExecuteAllRulesAsync("inputWorkflow",input1, input2, input3);
|
||||
List<RuleResultTree> result = await re.ExecuteAllRulesAsync("inputWorkflow", input1, input2, input3);
|
||||
Assert.NotNull(result);
|
||||
Assert.NotNull(result.First().GetMessages());
|
||||
Assert.NotNull(result.First().GetMessages().WarningMessages);
|
||||
|
@ -177,14 +177,12 @@ namespace RulesEngine.UnitTest
|
|||
[Fact]
|
||||
public void RulesEngine_New_IncorrectJSON_ThrowsException()
|
||||
{
|
||||
Assert.Throws<RuleValidationException>(() =>
|
||||
{
|
||||
Assert.Throws<RuleValidationException>(() => {
|
||||
var workflow = new WorkflowRules();
|
||||
var re = CreateRulesEngine(workflow);
|
||||
});
|
||||
|
||||
Assert.Throws<RuleValidationException>(() =>
|
||||
{
|
||||
Assert.Throws<RuleValidationException>(() => {
|
||||
var workflow = new WorkflowRules() { WorkflowName = "test" };
|
||||
var re = CreateRulesEngine(workflow);
|
||||
});
|
||||
|
@ -198,7 +196,7 @@ namespace RulesEngine.UnitTest
|
|||
var re = GetRulesEngine(ruleFileName);
|
||||
dynamic input = GetInput1();
|
||||
|
||||
await Assert.ThrowsAsync<ArgumentException>(async() => { await re.ExecuteAllRulesAsync("inputWorkflow1", input); });
|
||||
await Assert.ThrowsAsync<ArgumentException>(async () => { await re.ExecuteAllRulesAsync("inputWorkflow1", input); });
|
||||
}
|
||||
|
||||
[Theory]
|
||||
|
@ -214,7 +212,7 @@ namespace RulesEngine.UnitTest
|
|||
Assert.NotNull(result);
|
||||
re.RemoveWorkflow("inputWorkflow");
|
||||
|
||||
await Assert.ThrowsAsync<ArgumentException>(async() => await re.ExecuteAllRulesAsync("inputWorkflow",input1, input2, input3 ));
|
||||
await Assert.ThrowsAsync<ArgumentException>(async () => await re.ExecuteAllRulesAsync("inputWorkflow", input1, input2, input3));
|
||||
}
|
||||
|
||||
|
||||
|
@ -229,8 +227,8 @@ namespace RulesEngine.UnitTest
|
|||
dynamic input2 = GetInput2();
|
||||
dynamic input3 = GetInput3();
|
||||
|
||||
await Assert.ThrowsAsync<ArgumentException>(async() => await re.ExecuteAllRulesAsync("inputWorkflow", input1, input2, input3));
|
||||
await Assert.ThrowsAsync<ArgumentException>(async() => await re.ExecuteAllRulesAsync("inputWorkflowReference", input1, input2, input3));
|
||||
await Assert.ThrowsAsync<ArgumentException>(async () => await re.ExecuteAllRulesAsync("inputWorkflow", input1, input2, input3));
|
||||
await Assert.ThrowsAsync<ArgumentException>(async () => await re.ExecuteAllRulesAsync("inputWorkflowReference", input1, input2, input3));
|
||||
}
|
||||
|
||||
|
||||
|
@ -248,14 +246,14 @@ namespace RulesEngine.UnitTest
|
|||
List<RuleResultTree> result = await re.ExecuteAllRulesAsync("inputWorkflow", input1, input2, input3);
|
||||
Assert.NotNull(result);
|
||||
Assert.IsType<List<RuleResultTree>>(result);
|
||||
Assert.Contains(result,c => c.IsSuccess);
|
||||
Assert.Contains(result, c => c.IsSuccess);
|
||||
|
||||
input3.hello = "world";
|
||||
|
||||
result = await re.ExecuteAllRulesAsync("inputWorkflow", input1, input2, input3);
|
||||
Assert.NotNull(result);
|
||||
Assert.IsType<List<RuleResultTree>>(result);
|
||||
Assert.Contains(result,c => c.IsSuccess);
|
||||
Assert.Contains(result, c => c.IsSuccess);
|
||||
}
|
||||
|
||||
|
||||
|
@ -263,11 +261,11 @@ namespace RulesEngine.UnitTest
|
|||
[InlineData("rules4.json")]
|
||||
public async Task RulesEngine_Execute_Rule_For_Nested_Rule_Params_Returns_Success(string ruleFileName)
|
||||
{
|
||||
dynamic[] inputs = GetInputs4();
|
||||
var inputs = GetInputs4();
|
||||
|
||||
var ruleParams = new List<RuleParameter>();
|
||||
|
||||
for (int i = 0; i < inputs.Length; i++)
|
||||
for (var i = 0; i < inputs.Length; i++)
|
||||
{
|
||||
var input = inputs[i];
|
||||
var obj = Utils.GetTypedObject(input);
|
||||
|
@ -276,7 +274,9 @@ namespace RulesEngine.UnitTest
|
|||
|
||||
var files = Directory.GetFiles(Directory.GetCurrentDirectory(), ruleFileName, SearchOption.AllDirectories);
|
||||
if (files == null || files.Length == 0)
|
||||
{
|
||||
throw new Exception("Rules not found.");
|
||||
}
|
||||
|
||||
var fileData = File.ReadAllText(files[0]);
|
||||
var bre = new RulesEngine(JsonConvert.DeserializeObject<WorkflowRules[]>(fileData), null);
|
||||
|
@ -291,36 +291,40 @@ namespace RulesEngine.UnitTest
|
|||
{
|
||||
var re = GetRulesEngine(ruleFileName);
|
||||
|
||||
var input1 = new RuleParameter("customName",GetInput1());
|
||||
var input2 = new RuleParameter("input2",GetInput2());
|
||||
var input3 = new RuleParameter("input3",GetInput3());
|
||||
var input1 = new RuleParameter("customName", GetInput1());
|
||||
var input2 = new RuleParameter("input2", GetInput2());
|
||||
var input3 = new RuleParameter("input3", GetInput3());
|
||||
|
||||
List<RuleResultTree> result = await re.ExecuteAllRulesAsync("inputWorkflow", input1,input2, input3);
|
||||
var result = await re.ExecuteAllRulesAsync("inputWorkflow", input1, input2, input3);
|
||||
Assert.NotNull(result);
|
||||
Assert.IsType<List<RuleResultTree>>(result);
|
||||
Assert.Contains(result.First().ChildResults, c => c.ExceptionMessage.Contains("Unknown identifier 'input1'"));
|
||||
}
|
||||
|
||||
[Theory]
|
||||
[InlineData("rules5.json","hello",true)]
|
||||
[InlineData("rules5.json",null,false)]
|
||||
public async Task ExecuteRule_WithInjectedUtils_ReturnsListOfRuleResultTree(string ruleFileName,string propValue,bool expectedResult)
|
||||
[InlineData("rules5.json", "hello", true)]
|
||||
[InlineData("rules5.json", null, false)]
|
||||
public async Task ExecuteRule_WithInjectedUtils_ReturnsListOfRuleResultTree(string ruleFileName, string propValue, bool expectedResult)
|
||||
{
|
||||
var re = GetRulesEngine(ruleFileName);
|
||||
|
||||
dynamic input1 = new ExpandoObject();
|
||||
if(propValue != null)
|
||||
input1.Property1 = propValue;
|
||||
if (propValue != null)
|
||||
{
|
||||
input1.Property1 = propValue;
|
||||
}
|
||||
|
||||
if(propValue == null)
|
||||
input1.Property1 = null;
|
||||
if (propValue == null)
|
||||
{
|
||||
input1.Property1 = null;
|
||||
}
|
||||
|
||||
var utils = new TestInstanceUtils();
|
||||
|
||||
List<RuleResultTree> result = await re.ExecuteAllRulesAsync("inputWorkflow", new RuleParameter("input1",input1),new RuleParameter("utils",utils));
|
||||
var result = await re.ExecuteAllRulesAsync("inputWorkflow", new RuleParameter("input1", input1), new RuleParameter("utils", utils));
|
||||
Assert.NotNull(result);
|
||||
Assert.IsType<List<RuleResultTree>>(result);
|
||||
Assert.All(result,c => Assert.Equal(expectedResult,c.IsSuccess));
|
||||
Assert.All(result, c => Assert.Equal(expectedResult, c.IsSuccess));
|
||||
}
|
||||
|
||||
[Theory]
|
||||
|
@ -338,7 +342,7 @@ namespace RulesEngine.UnitTest
|
|||
|
||||
var utils = new TestInstanceUtils();
|
||||
|
||||
List<RuleResultTree> result = await re.ExecuteAllRulesAsync("inputWorkflow", new RuleParameter("input1", input1));
|
||||
var result = await re.ExecuteAllRulesAsync("inputWorkflow", new RuleParameter("input1", input1));
|
||||
Assert.NotNull(result);
|
||||
Assert.IsType<List<RuleResultTree>>(result);
|
||||
Assert.All(result, c => Assert.True(c.IsSuccess));
|
||||
|
@ -355,7 +359,7 @@ namespace RulesEngine.UnitTest
|
|||
|
||||
var utils = new TestInstanceUtils();
|
||||
|
||||
List<RuleResultTree> result = await re.ExecuteAllRulesAsync("inputWorkflow", new RuleParameter("input1", input1));
|
||||
var result = await re.ExecuteAllRulesAsync("inputWorkflow", new RuleParameter("input1", input1));
|
||||
Assert.NotNull(result);
|
||||
Assert.IsType<List<RuleResultTree>>(result);
|
||||
Assert.All(result, c => Assert.True(c.IsSuccess));
|
||||
|
@ -372,7 +376,7 @@ namespace RulesEngine.UnitTest
|
|||
|
||||
var utils = new TestInstanceUtils();
|
||||
|
||||
List<RuleResultTree> result = await re.ExecuteAllRulesAsync("inputWorkflow", new RuleParameter("input1", input1));
|
||||
var result = await re.ExecuteAllRulesAsync("inputWorkflow", new RuleParameter("input1", input1));
|
||||
Assert.NotNull(result);
|
||||
Assert.IsType<List<RuleResultTree>>(result);
|
||||
Assert.All(result, c => Assert.False(c.IsSuccess));
|
||||
|
@ -390,9 +394,8 @@ namespace RulesEngine.UnitTest
|
|||
|
||||
var utils = new TestInstanceUtils();
|
||||
|
||||
await Assert.ThrowsAsync<System.Linq.Dynamic.Core.Exceptions.ParseException>(async()=>
|
||||
{
|
||||
List<RuleResultTree> result = await re.ExecuteAllRulesAsync("inputWorkflow", new RuleParameter("input1", input1));
|
||||
await Assert.ThrowsAsync<System.Linq.Dynamic.Core.Exceptions.ParseException>(async () => {
|
||||
var result = await re.ExecuteAllRulesAsync("inputWorkflow", new RuleParameter("input1", input1));
|
||||
});
|
||||
}
|
||||
|
||||
|
@ -408,7 +411,7 @@ namespace RulesEngine.UnitTest
|
|||
|
||||
var utils = new TestInstanceUtils();
|
||||
|
||||
List<RuleResultTree> result = await re.ExecuteAllRulesAsync("inputWorkflow", new RuleParameter("input1", input1));
|
||||
var result = await re.ExecuteAllRulesAsync("inputWorkflow", new RuleParameter("input1", input1));
|
||||
Assert.NotNull(result);
|
||||
Assert.IsType<List<RuleResultTree>>(result);
|
||||
Assert.All(result, c => Assert.False(c.IsSuccess));
|
||||
|
@ -424,8 +427,7 @@ namespace RulesEngine.UnitTest
|
|||
var filePath = Path.Combine(Directory.GetCurrentDirectory() as string, "TestData", filename);
|
||||
var data = File.ReadAllText(filePath);
|
||||
|
||||
var injectWorkflow = new WorkflowRules
|
||||
{
|
||||
var injectWorkflow = new WorkflowRules {
|
||||
WorkflowName = "inputWorkflowReference",
|
||||
WorkflowRulesToInject = new List<string> { "inputWorkflow" }
|
||||
};
|
||||
|
@ -490,10 +492,15 @@ namespace RulesEngine.UnitTest
|
|||
}
|
||||
|
||||
[ExcludeFromCodeCoverage]
|
||||
private class TestInstanceUtils{
|
||||
public bool CheckExists(string str){
|
||||
if(str != null && str.Length > 0)
|
||||
private class TestInstanceUtils
|
||||
{
|
||||
public bool CheckExists(string str)
|
||||
{
|
||||
if (str != null && str.Length > 0)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
|
|
|
@ -1,11 +1,10 @@
|
|||
// Copyright (c) Microsoft Corporation.
|
||||
// Licensed under the MIT License.
|
||||
|
||||
using RulesEngine;
|
||||
using Moq;
|
||||
using System;
|
||||
using Xunit;
|
||||
using System.Diagnostics.CodeAnalysis;
|
||||
using Xunit;
|
||||
|
||||
namespace RulesEngine.UnitTest
|
||||
{
|
||||
|
@ -13,15 +12,15 @@ namespace RulesEngine.UnitTest
|
|||
[ExcludeFromCodeCoverage]
|
||||
public class CustomTypeProviderTests : IDisposable
|
||||
{
|
||||
private MockRepository mockRepository;
|
||||
private readonly MockRepository _mockRepository;
|
||||
public CustomTypeProviderTests()
|
||||
{
|
||||
this.mockRepository = new MockRepository(MockBehavior.Strict);
|
||||
_mockRepository = new MockRepository(MockBehavior.Strict);
|
||||
}
|
||||
|
||||
public void Dispose()
|
||||
{
|
||||
this.mockRepository.VerifyAll();
|
||||
_mockRepository.VerifyAll();
|
||||
}
|
||||
|
||||
private CustomTypeProvider CreateProvider()
|
||||
|
@ -33,7 +32,7 @@ namespace RulesEngine.UnitTest
|
|||
public void GetCustomTypes_StateUnderTest_ExpectedBehavior()
|
||||
{
|
||||
// Arrange
|
||||
var unitUnderTest = this.CreateProvider();
|
||||
var unitUnderTest = CreateProvider();
|
||||
|
||||
// Act
|
||||
var result = unitUnderTest.GetCustomTypes();
|
||||
|
|
|
@ -1,12 +1,10 @@
|
|||
// Copyright (c) Microsoft Corporation.
|
||||
// Licensed under the MIT License.
|
||||
|
||||
using RulesEngine;
|
||||
using RulesEngine.ExpressionBuilders;
|
||||
using RulesEngine.Models;
|
||||
using System.Collections.Generic;
|
||||
using System.Diagnostics.CodeAnalysis;
|
||||
using System.Linq.Expressions;
|
||||
using Xunit;
|
||||
|
||||
namespace RulesEngine.UnitTest
|
||||
|
@ -19,7 +17,7 @@ namespace RulesEngine.UnitTest
|
|||
public void BuildExpressionForRuleTest()
|
||||
{
|
||||
var reSettings = new ReSettings();
|
||||
var objBuilderFactory = new RuleExpressionBuilderFactory(reSettings,new RuleExpressionParser(reSettings));
|
||||
var objBuilderFactory = new RuleExpressionBuilderFactory(reSettings, new RuleExpressionParser(reSettings));
|
||||
var builder = objBuilderFactory.RuleGetExpressionBuilder(RuleExpressionType.LambdaExpression);
|
||||
|
||||
var ruleParameters = new RuleParameter[] {
|
||||
|
@ -29,15 +27,17 @@ namespace RulesEngine.UnitTest
|
|||
};
|
||||
|
||||
|
||||
Rule mainRule = new Rule();
|
||||
mainRule.RuleName = "rule1";
|
||||
mainRule.Operator = "And";
|
||||
mainRule.Rules = new List<Rule>();
|
||||
var mainRule = new Rule {
|
||||
RuleName = "rule1",
|
||||
Operator = "And",
|
||||
Rules = new List<Rule>()
|
||||
};
|
||||
|
||||
Rule dummyRule = new Rule();
|
||||
dummyRule.RuleName = "testRule1";
|
||||
dummyRule.RuleExpressionType = RuleExpressionType.LambdaExpression;
|
||||
dummyRule.Expression = "RequestType == \"vod\"";
|
||||
var dummyRule = new Rule {
|
||||
RuleName = "testRule1",
|
||||
RuleExpressionType = RuleExpressionType.LambdaExpression,
|
||||
Expression = "RequestType == \"vod\""
|
||||
};
|
||||
|
||||
mainRule.Rules.Add(dummyRule);
|
||||
var func = builder.BuildDelegateForRule(dummyRule, ruleParameters);
|
||||
|
|
|
@ -1,9 +1,10 @@
|
|||
using RulesEngine.Extensions;
|
||||
// Copyright (c) Microsoft Corporation.
|
||||
// Licensed under the MIT License.
|
||||
|
||||
using RulesEngine.Extensions;
|
||||
using RulesEngine.Models;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Diagnostics.CodeAnalysis;
|
||||
using System.Text;
|
||||
using Xunit;
|
||||
|
||||
namespace RulesEngine.UnitTest
|
||||
|
@ -44,8 +45,7 @@ namespace RulesEngine.UnitTest
|
|||
|
||||
var successEventName = string.Empty;
|
||||
|
||||
rulesResultTree.OnSuccess((eventName) =>
|
||||
{
|
||||
rulesResultTree.OnSuccess((eventName) => {
|
||||
successEventName = eventName;
|
||||
});
|
||||
|
||||
|
@ -85,8 +85,7 @@ namespace RulesEngine.UnitTest
|
|||
|
||||
var successEventName = string.Empty;
|
||||
|
||||
rulesResultTree.OnSuccess((eventName) =>
|
||||
{
|
||||
rulesResultTree.OnSuccess((eventName) => {
|
||||
successEventName = eventName;
|
||||
});
|
||||
|
||||
|
@ -125,8 +124,7 @@ namespace RulesEngine.UnitTest
|
|||
|
||||
var successEventName = string.Empty;
|
||||
|
||||
rulesResultTree.OnSuccess((eventName) =>
|
||||
{
|
||||
rulesResultTree.OnSuccess((eventName) => {
|
||||
successEventName = eventName;
|
||||
});
|
||||
|
||||
|
@ -166,8 +164,7 @@ namespace RulesEngine.UnitTest
|
|||
|
||||
var successEventName = true;
|
||||
|
||||
rulesResultTree.OnFail(() =>
|
||||
{
|
||||
rulesResultTree.OnFail(() => {
|
||||
successEventName = false;
|
||||
});
|
||||
|
||||
|
@ -206,8 +203,7 @@ namespace RulesEngine.UnitTest
|
|||
|
||||
var successEventName = true;
|
||||
|
||||
rulesResultTree.OnFail(() =>
|
||||
{
|
||||
rulesResultTree.OnFail(() => {
|
||||
successEventName = false;
|
||||
});
|
||||
|
||||
|
|
|
@ -10,7 +10,7 @@ using Xunit;
|
|||
|
||||
namespace RulesEngine.UnitTest
|
||||
{
|
||||
[Trait("Category","Unit")]
|
||||
[Trait("Category", "Unit")]
|
||||
[ExcludeFromCodeCoverage]
|
||||
public class RuleCompilerTest
|
||||
{
|
||||
|
@ -20,7 +20,7 @@ namespace RulesEngine.UnitTest
|
|||
Assert.Throws<ArgumentNullException>(() => new RuleCompiler(null, null));
|
||||
var reSettings = new ReSettings();
|
||||
var parser = new RuleExpressionParser(reSettings);
|
||||
Assert.Throws<ArgumentNullException>(() => new RuleCompiler(new RuleExpressionBuilderFactory(reSettings,parser), null));
|
||||
Assert.Throws<ArgumentNullException>(() => new RuleCompiler(new RuleExpressionBuilderFactory(reSettings, parser), null));
|
||||
}
|
||||
|
||||
[Fact]
|
||||
|
@ -28,9 +28,9 @@ namespace RulesEngine.UnitTest
|
|||
{
|
||||
var reSettings = new ReSettings();
|
||||
var parser = new RuleExpressionParser(reSettings);
|
||||
var compiler = new RuleCompiler(new RuleExpressionBuilderFactory(reSettings,parser), new NullLogger<RuleCompiler>());
|
||||
var compiler = new RuleCompiler(new RuleExpressionBuilderFactory(reSettings, parser), new NullLogger<RuleCompiler>());
|
||||
Assert.Throws<ArgumentNullException>(() => compiler.CompileRule(null, null));
|
||||
Assert.Throws<ArgumentNullException>(() => compiler.CompileRule(null, new RuleParameter[] { null}));
|
||||
Assert.Throws<ArgumentNullException>(() => compiler.CompileRule(null, new RuleParameter[] { null }));
|
||||
}
|
||||
|
||||
|
||||
|
|
|
@ -1,7 +1,6 @@
|
|||
// Copyright (c) Microsoft Corporation.
|
||||
// Licensed under the MIT License.
|
||||
|
||||
using RulesEngine;
|
||||
using RulesEngine.ExpressionBuilders;
|
||||
using RulesEngine.Models;
|
||||
using System;
|
||||
|
@ -20,7 +19,7 @@ namespace RulesEngine.UnitTest
|
|||
{
|
||||
var reSettings = new ReSettings();
|
||||
var parser = new RuleExpressionParser(reSettings);
|
||||
var objBuilderFactory = new RuleExpressionBuilderFactory(reSettings,parser);
|
||||
var objBuilderFactory = new RuleExpressionBuilderFactory(reSettings, parser);
|
||||
var builder = objBuilderFactory.RuleGetExpressionBuilder(expressionType);
|
||||
|
||||
var builderType = builder.GetType();
|
||||
|
|
|
@ -1,8 +1,8 @@
|
|||
using Newtonsoft.Json;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
// Copyright (c) Microsoft Corporation.
|
||||
// Licensed under the MIT License.
|
||||
|
||||
using Newtonsoft.Json;
|
||||
using System.Diagnostics.CodeAnalysis;
|
||||
using System.Text;
|
||||
|
||||
namespace RulesEngine.UnitTest
|
||||
{
|
||||
|
|
|
@ -6,7 +6,6 @@ using System;
|
|||
using System.Collections.Generic;
|
||||
using System.Diagnostics.CodeAnalysis;
|
||||
using System.Dynamic;
|
||||
using System.Text;
|
||||
using Xunit;
|
||||
|
||||
namespace RulesEngine.UnitTest
|
||||
|
@ -14,11 +13,11 @@ namespace RulesEngine.UnitTest
|
|||
[ExcludeFromCodeCoverage]
|
||||
public class TestClass
|
||||
{
|
||||
public string test { get; set; }
|
||||
public List<int> testList { get; set; }
|
||||
public string Test { get; set; }
|
||||
public List<int> TestList { get; set; }
|
||||
}
|
||||
|
||||
[Trait("Category","Unit")]
|
||||
[Trait("Category", "Unit")]
|
||||
[ExcludeFromCodeCoverage]
|
||||
public class UtilsTests
|
||||
{
|
||||
|
@ -27,27 +26,27 @@ namespace RulesEngine.UnitTest
|
|||
public void GetTypedObject_dynamicObject()
|
||||
{
|
||||
dynamic obj = new ExpandoObject();
|
||||
obj.test = "hello";
|
||||
obj.testList = new List<int> { 1, 2, 3 };
|
||||
obj.Test = "hello";
|
||||
obj.TestList = new List<int> { 1, 2, 3 };
|
||||
object typedobj = Utils.GetTypedObject(obj);
|
||||
Assert.IsNotType<ExpandoObject>(typedobj);
|
||||
Assert.NotNull(typedobj.GetType().GetProperty("test"));
|
||||
Assert.NotNull(typedobj.GetType().GetProperty("Test"));
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void GetTypedObject_dynamicObject_multipleObjects()
|
||||
{
|
||||
dynamic obj = new ExpandoObject();
|
||||
obj.test = "hello";
|
||||
obj.testList = new List<int> { 1, 2, 3 };
|
||||
obj.Test = "hello";
|
||||
obj.TestList = new List<int> { 1, 2, 3 };
|
||||
dynamic obj2 = new ExpandoObject();
|
||||
obj2.test = "world";
|
||||
obj2.testList = new List<int> { 1, 2, 3 };
|
||||
obj2.Test = "world";
|
||||
obj2.TestList = new List<int> { 1, 2, 3 };
|
||||
object typedobj = Utils.GetTypedObject(obj);
|
||||
object typedobj2 = Utils.GetTypedObject(obj2);
|
||||
Assert.IsNotType<ExpandoObject>(typedobj);
|
||||
Assert.NotNull(typedobj.GetType().GetProperty("test"));
|
||||
Assert.Equal(typedobj.GetType(),typedobj2.GetType());
|
||||
Assert.NotNull(typedobj.GetType().GetProperty("Test"));
|
||||
Assert.Equal(typedobj.GetType(), typedobj2.GetType());
|
||||
}
|
||||
|
||||
|
||||
|
@ -55,23 +54,23 @@ namespace RulesEngine.UnitTest
|
|||
public void GetTypedObject_nonDynamicObject()
|
||||
{
|
||||
var obj = new {
|
||||
test = "hello"
|
||||
Test = "hello"
|
||||
};
|
||||
object typedobj = Utils.GetTypedObject(obj);
|
||||
var typedobj = Utils.GetTypedObject(obj);
|
||||
Assert.IsNotType<ExpandoObject>(typedobj);
|
||||
Assert.NotNull(typedobj.GetType().GetProperty("test"));
|
||||
Assert.NotNull(typedobj.GetType().GetProperty("Test"));
|
||||
}
|
||||
|
||||
[Fact]
|
||||
[Fact]
|
||||
public void CreateObject_dynamicObject()
|
||||
{
|
||||
dynamic obj = new ExpandoObject();
|
||||
obj.test = "test";
|
||||
obj.testList = new List<int> { 1, 2, 3 };
|
||||
obj.Test = "test";
|
||||
obj.TestList = new List<int> { 1, 2, 3 };
|
||||
|
||||
object newObj = Utils.CreateObject(typeof(TestClass), obj);
|
||||
Assert.IsNotType<ExpandoObject>(newObj);
|
||||
Assert.NotNull(newObj.GetType().GetProperty("test"));
|
||||
Assert.NotNull(newObj.GetType().GetProperty("Test"));
|
||||
|
||||
}
|
||||
|
||||
|
@ -79,13 +78,13 @@ namespace RulesEngine.UnitTest
|
|||
public void CreateAbstractType_dynamicObject()
|
||||
{
|
||||
dynamic obj = new ExpandoObject();
|
||||
obj.test = "test";
|
||||
obj.testList = new List<int> { 1, 2, 3 };
|
||||
obj.Test = "test";
|
||||
obj.TestList = new List<int> { 1, 2, 3 };
|
||||
obj.testEmptyList = new List<object>();
|
||||
|
||||
Type type = Utils.CreateAbstractClassType( obj);
|
||||
Type type = Utils.CreateAbstractClassType(obj);
|
||||
Assert.NotEqual(typeof(ExpandoObject), type);
|
||||
Assert.NotNull(type.GetProperty("test"));
|
||||
Assert.NotNull(type.GetProperty("Test"));
|
||||
|
||||
}
|
||||
|
||||
|
|
Loading…
Reference in New Issue