diff --git a/.editorconfig b/.editorconfig new file mode 100644 index 0000000..703b01b --- /dev/null +++ b/.editorconfig @@ -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 diff --git a/.github/workflows/codeql-analysis.yml b/.github/workflows/codeql-analysis.yml index 60a0945..3a030fc 100644 --- a/.github/workflows/codeql-analysis.yml +++ b/.github/workflows/codeql-analysis.yml @@ -2,9 +2,9 @@ name: "Code scanning" on: push: - branches: [ master ] + branches: [ main ] pull_request: - branches: [ master ] + branches: [ main ] schedule: - cron: '0 18 * * 1' diff --git a/.github/workflows/dotnetcore-build.yml b/.github/workflows/dotnetcore-build.yml index b88e702..852f9f9 100644 --- a/.github/workflows/dotnetcore-build.yml +++ b/.github/workflows/dotnetcore-build.yml @@ -2,9 +2,9 @@ name: build on: push: - branches: [ master ] + branches: [ main ] pull_request: - branches: [ master, develop ] + branches: [ main, develop ] jobs: build: diff --git a/CHANGELOG.md b/CHANGELOG.md index 772a139..9f10fce 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -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) diff --git a/RulesEngine.sln b/RulesEngine.sln index bff4a74..85f2fd7 100644 --- a/RulesEngine.sln +++ b/RulesEngine.sln @@ -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 diff --git a/benchmark/RulesEngineBenchmark/Program.cs b/benchmark/RulesEngineBenchmark/Program.cs index 3f9b54a..683dc46 100644 --- a/benchmark/RulesEngineBenchmark/Program.cs +++ b/benchmark/RulesEngineBenchmark/Program.cs @@ -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 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>(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 { @@ -67,15 +71,15 @@ namespace RulesEngineBenchmark { foreach (var workflow in workflows) { - List 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(); + _ = BenchmarkRunner.Run(); } } } diff --git a/demo/DemoApp/BasicDemo.cs b/demo/DemoApp/BasicDemo.cs index 7036650..9e70e9f 100644 --- a/demo/DemoApp/BasicDemo.cs +++ b/demo/DemoApp/BasicDemo.cs @@ -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 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."; }); diff --git a/demo/DemoApp/NestedInputDemo.cs b/demo/DemoApp/NestedInputDemo.cs index 9dd9afe..4d845b9 100644 --- a/demo/DemoApp/NestedInputDemo.cs +++ b/demo/DemoApp/NestedInputDemo.cs @@ -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 { @@ -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>(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 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"); }); - + } diff --git a/demo/DemoApp/Program.cs b/demo/DemoApp/Program.cs index e32873b..08eca3d 100644 --- a/demo/DemoApp/Program.cs +++ b/demo/DemoApp/Program.cs @@ -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(); diff --git a/src/RulesEngine/Actions/ActionBase.cs b/src/RulesEngine/Actions/ActionBase.cs index bfbbd66..76d3c5f 100644 --- a/src/RulesEngine/Actions/ActionBase.cs +++ b/src/RulesEngine/Actions/ActionBase.cs @@ -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 ExecuteAndReturnResultAsync(ActionContext context, RuleParameter[] ruleParameters,bool includeRuleResults=false){ - ActionRuleResult result = new ActionRuleResult(); + internal async virtual ValueTask 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() { context.GetParentRuleResult() diff --git a/src/RulesEngine/Actions/ActionContext.cs b/src/RulesEngine/Actions/ActionContext.cs index 6361ce8..4d0ba47 100644 --- a/src/RulesEngine/Actions/ActionContext.cs +++ b/src/RulesEngine/Actions/ActionContext.cs @@ -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(string name) diff --git a/src/RulesEngine/Actions/ActionFactory.cs b/src/RulesEngine/Actions/ActionFactory.cs index 2b7b504..741d18b 100644 --- a/src/RulesEngine/Actions/ActionFactory.cs +++ b/src/RulesEngine/Actions/ActionFactory.cs @@ -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>(StringComparer.OrdinalIgnoreCase); } - internal ActionFactory(IDictionary> actionRegistry): this() + internal ActionFactory(IDictionary> actionRegistry) : this() { - foreach(var kv in actionRegistry){ + foreach (var kv in actionRegistry) + { _actionRegistry.Add(kv.Key, kv.Value); } } diff --git a/src/RulesEngine/Actions/EvaluateRuleAction.cs b/src/RulesEngine/Actions/EvaluateRuleAction.cs index 605d2d2..a93f747 100644 --- a/src/RulesEngine/Actions/EvaluateRuleAction.cs +++ b/src/RulesEngine/Actions/EvaluateRuleAction.cs @@ -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 ExecuteAndReturnResultAsync(ActionContext context, RuleParameter[] ruleParameters, bool includeRuleResults=false){ - var innerResult = await base.ExecuteAndReturnResultAsync(context,ruleParameters,includeRuleResults); + internal async override ValueTask ExecuteAndReturnResultAsync(ActionContext context, RuleParameter[] ruleParameters, bool includeRuleResults = false) + { + var innerResult = await base.ExecuteAndReturnResultAsync(context, ruleParameters, includeRuleResults); var output = innerResult.Output as ActionRuleResult; List resultList = null; - if(includeRuleResults){ + if (includeRuleResults) + { resultList = new List(output.Results); resultList.AddRange(innerResult.Results); } @@ -29,11 +33,11 @@ namespace RulesEngine.Actions }; } - public override async ValueTask Run(ActionContext context, RuleParameter[] ruleParameters) + public async override ValueTask Run(ActionContext context, RuleParameter[] ruleParameters) { var workflowName = context.GetContext("workflowName"); var ruleName = context.GetContext("ruleName"); - var ruleResult = await _ruleEngine.ExecuteActionWorkflowAsync(workflowName,ruleName,ruleParameters); + var ruleResult = await _ruleEngine.ExecuteActionWorkflowAsync(workflowName, ruleName, ruleParameters); return ruleResult; } } diff --git a/src/RulesEngine/Actions/ExpressionOutputAction.cs b/src/RulesEngine/Actions/ExpressionOutputAction.cs index ae327a7..315b996 100644 --- a/src/RulesEngine/Actions/ExpressionOutputAction.cs +++ b/src/RulesEngine/Actions/ExpressionOutputAction.cs @@ -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 { diff --git a/src/RulesEngine/Enums/ActionTriggerType.cs b/src/RulesEngine/Enums/ActionTriggerType.cs index e2854e7..25b3ccb 100644 --- a/src/RulesEngine/Enums/ActionTriggerType.cs +++ b/src/RulesEngine/Enums/ActionTriggerType.cs @@ -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 { diff --git a/src/RulesEngine/ExpressionBuilders/LambdaExpressionBuilder.cs b/src/RulesEngine/ExpressionBuilders/LambdaExpressionBuilder.cs index 6b3ebd1..adb54d9 100644 --- a/src/RulesEngine/ExpressionBuilders/LambdaExpressionBuilder.cs +++ b/src/RulesEngine/ExpressionBuilders/LambdaExpressionBuilder.cs @@ -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); - } + } } } } diff --git a/src/RulesEngine/ExpressionBuilders/RuleExpressionBuilderBase.cs b/src/RulesEngine/ExpressionBuilders/RuleExpressionBuilderBase.cs index 84966ec..0d03dc5 100644 --- a/src/RulesEngine/ExpressionBuilders/RuleExpressionBuilderBase.cs +++ b/src/RulesEngine/ExpressionBuilders/RuleExpressionBuilderBase.cs @@ -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 { diff --git a/src/RulesEngine/ExpressionBuilders/RuleExpressionParser.cs b/src/RulesEngine/ExpressionBuilders/RuleExpressionParser.cs index 04bf936..2c7f72b 100644 --- a/src/RulesEngine/ExpressionBuilders/RuleExpressionParser.cs +++ b/src/RulesEngine/ExpressionBuilders/RuleExpressionParser.cs @@ -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 Compile(string expression, RuleParameter[] ruleParams) + public Func Compile(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(e,typeParamExpressions); - return wrappedExpression.CompileFast>(); + var wrappedExpression = WrapExpression(e, typeParamExpressions); + return wrappedExpression.CompileFast>(); }); - + } - private Expression> WrapExpression(LambdaExpression expression, ParameterExpression[] parameters){ - var argExp = Expression.Parameter(typeof(object[]),"args"); - IEnumerable paramExps = parameters.Select((c, i) => { + private Expression> WrapExpression(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.Body }); var blockExp = Expression.Block(parameters, blockExpSteps); - return Expression.Lambda>(blockExp, argExp); + return Expression.Lambda>(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; } diff --git a/src/RulesEngine/HelperFunctions/Helpers.cs b/src/RulesEngine/HelperFunctions/Helpers.cs index dbd382c..3aa0a8e 100644 --- a/src/RulesEngine/HelperFunctions/Helpers.cs +++ b/src/RulesEngine/HelperFunctions/Helpers.cs @@ -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 /// internal static class Helpers { - internal static RuleFunc ToResultTree(Rule rule, IEnumerable childRuleResults, Func isSuccessFunc, string exceptionMessage = "") + internal static RuleFunc ToResultTree(Rule rule, IEnumerable childRuleResults, Func 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 diff --git a/src/RulesEngine/HelperFunctions/Utils.cs b/src/RulesEngine/HelperFunctions/Utils.cs index f22f8a8..431295b 100644 --- a/src/RulesEngine/HelperFunctions/Utils.cs +++ b/src/RulesEngine/HelperFunctions/Utils.cs @@ -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 props = new List(); - 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().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(); for (int i = 0; i < temp.Count; i++) @@ -123,5 +123,5 @@ namespace RulesEngine.HelperFunctions } } - + } diff --git a/src/RulesEngine/Interfaces/IRulesEngine.cs b/src/RulesEngine/Interfaces/IRulesEngine.cs index 7922930..c8298a0 100644 --- a/src/RulesEngine/Interfaces/IRulesEngine.cs +++ b/src/RulesEngine/Interfaces/IRulesEngine.cs @@ -8,7 +8,7 @@ using System.Threading.Tasks; namespace RulesEngine.Interfaces { public interface IRulesEngine - { + { /// /// This will execute all the rules of the specified workflow /// diff --git a/src/RulesEngine/Models/ActionInfo.cs b/src/RulesEngine/Models/ActionInfo.cs index 7964a91..1899f9d 100644 --- a/src/RulesEngine/Models/ActionInfo.cs +++ b/src/RulesEngine/Models/ActionInfo.cs @@ -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; } diff --git a/src/RulesEngine/Models/ActionResult.cs b/src/RulesEngine/Models/ActionResult.cs index 30a4ebc..04cb808 100644 --- a/src/RulesEngine/Models/ActionResult.cs +++ b/src/RulesEngine/Models/ActionResult.cs @@ -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; } -} \ No newline at end of file +using System; +using System.Diagnostics.CodeAnalysis; + +namespace RulesEngine.Models +{ + [ExcludeFromCodeCoverage] + public class ActionResult + { + public object Output { get; set; } + public Exception Exception { get; set; } + } +} diff --git a/src/RulesEngine/Models/ActionRuleResult.cs b/src/RulesEngine/Models/ActionRuleResult.cs index ba84d30..88897fe 100644 --- a/src/RulesEngine/Models/ActionRuleResult.cs +++ b/src/RulesEngine/Models/ActionRuleResult.cs @@ -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 Results {get; set;} -} \ No newline at end of file +namespace RulesEngine.Models +{ + [ExcludeFromCodeCoverage] + public class ActionRuleResult : ActionResult + { + public List Results { get; set; } + } +} diff --git a/src/RulesEngine/Models/CompiledParam.cs b/src/RulesEngine/Models/CompiledParam.cs index 07b2c94..c6e2788 100644 --- a/src/RulesEngine/Models/CompiledParam.cs +++ b/src/RulesEngine/Models/CompiledParam.cs @@ -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 Value { get; set; } + internal Func Value { get; set; } internal RuleParameter AsRuleParameter() { - return new RuleParameter(Name,ReturnType); + return new RuleParameter(Name, ReturnType); } } } diff --git a/src/RulesEngine/Models/LocalParam.cs b/src/RulesEngine/Models/LocalParam.cs index 5de9744..6792b4a 100644 --- a/src/RulesEngine/Models/LocalParam.cs +++ b/src/RulesEngine/Models/LocalParam.cs @@ -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 diff --git a/src/RulesEngine/Models/ReSettings.cs b/src/RulesEngine/Models/ReSettings.cs index a62519b..c8cbb36 100644 --- a/src/RulesEngine/Models/ReSettings.cs +++ b/src/RulesEngine/Models/ReSettings.cs @@ -14,7 +14,7 @@ namespace RulesEngine.Models public Type[] CustomTypes { get; set; } public Dictionary> 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; } } diff --git a/src/RulesEngine/Models/Rule.cs b/src/RulesEngine/Models/Rule.cs index 58cc9d9..6ee2e26 100644 --- a/src/RulesEngine/Models/Rule.cs +++ b/src/RulesEngine/Models/Rule.cs @@ -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 { diff --git a/src/RulesEngine/Models/RuleParameter.cs b/src/RulesEngine/Models/RuleParameter.cs index a000494..b509731 100644 --- a/src/RulesEngine/Models/RuleParameter.cs +++ b/src/RulesEngine/Models/RuleParameter.cs @@ -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; } diff --git a/src/RulesEngine/Models/RuleResultTree.cs b/src/RulesEngine/Models/RuleResultTree.cs index a4e392b..5282503 100644 --- a/src/RulesEngine/Models/RuleResultTree.cs +++ b/src/RulesEngine/Models/RuleResultTree.cs @@ -40,9 +40,9 @@ namespace RulesEngine.Models /// /// Gets or sets the input object /// - public Dictionary Inputs { get; set; } + public Dictionary Inputs { get; set; } - public ActionResult ActionResult {get; set;} + public ActionResult ActionResult { get; set; } /// /// Gets the exception message in case an error is thrown during rules calculation. diff --git a/src/RulesEngine/ParamCompiler.cs b/src/RulesEngine/ParamCompiler.cs index af3293d..56587de 100644 --- a/src/RulesEngine/ParamCompiler.cs +++ b/src/RulesEngine/ParamCompiler.cs @@ -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 /// public IEnumerable CompileParamsExpression(Rule rule, IEnumerable ruleParams) { - - if(rule.LocalParams == null) return null; + + if (rule.LocalParams == null) return null; var compiledParameters = new List(); var evaluatedParameters = new List(); @@ -54,7 +56,7 @@ namespace RulesEngine /// The compiled parameter. /// The rule parameters. /// RuleParameter. - public RuleParameter EvaluateCompiledParam(string paramName, Func compiledParam, IEnumerable inputs) + public RuleParameter EvaluateCompiledParam(string paramName, Func compiledParam, IEnumerable inputs) { var result = compiledParam(inputs.Select(c => c.Value).ToArray()); return new RuleParameter(paramName, result); @@ -68,7 +70,7 @@ namespace RulesEngine /// The type parameter expressions. /// The rule input exp. /// - private Func GetDelegateForRuleParam(LocalParam param, RuleParameter[] ruleParameters) + private Func GetDelegateForRuleParam(LocalParam param, RuleParameter[] ruleParameters) { return _ruleExpressionParser.Compile(param.Expression, ruleParameters); } diff --git a/src/RulesEngine/RuleCompiler.cs b/src/RulesEngine/RuleCompiler.cs index 0084772..39f620a 100644 --- a/src/RulesEngine/RuleCompiler.cs +++ b/src/RulesEngine/RuleCompiler.cs @@ -38,18 +38,8 @@ namespace RulesEngine /// expressionBuilderFactory 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."); } /// @@ -60,15 +50,15 @@ namespace RulesEngine /// /// /// Compiled func delegate - internal RuleFunc CompileRule(Rule rule,params RuleParameter[] ruleParams) + internal RuleFunc CompileRule(Rule rule, params RuleParameter[] ruleParams) { try { - if(rule == null) + if (rule == null) { throw new ArgumentNullException(nameof(rule)); } - RuleFunc ruleExpression = GetDelegateForRule(rule,ruleParams); + var ruleExpression = GetDelegateForRule(rule, ruleParams); return ruleExpression; } catch (Exception ex) @@ -78,7 +68,7 @@ namespace RulesEngine } } - + /// /// Gets the expression for rule. @@ -89,9 +79,7 @@ namespace RulesEngine /// private RuleFunc 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 isSuccess = (p) => ApplyOperation(resultList, operation); - RuleFunc result = Helpers.ToResultTree(parentRule, resultList,isSuccess); - return result(paramArray); - }; + return (paramArray) => { + var resultList = ruleFuncList.Select(fn => fn(paramArray)); + Func isSuccess = (p) => ApplyOperation(resultList, operation); + var result = Helpers.ToResultTree(parentRule, resultList, isSuccess); + return result(paramArray); + }; } diff --git a/src/RulesEngine/RulesCache.cs b/src/RulesEngine/RulesCache.cs index 755dd3b..713ce1c 100644 --- a/src/RulesEngine/RulesCache.cs +++ b/src/RulesEngine/RulesCache.cs @@ -13,7 +13,7 @@ namespace RulesEngine internal class RulesCache { /// The compile rules - private ConcurrentDictionary>> _compileRules = new ConcurrentDictionary>>(); + private ConcurrentDictionary>> _compileRules = new ConcurrentDictionary>>(); /// The workflow rules private ConcurrentDictionary _workflowRules = new ConcurrentDictionary(); @@ -47,7 +47,7 @@ namespace RulesEngine /// Adds the or update compiled rule. /// The compiled rule key. /// The compiled rule. - public void AddOrUpdateCompiledRule(string compiledRuleKey, IDictionary> compiledRule) + public void AddOrUpdateCompiledRule(string compiledRuleKey, IDictionary> compiledRule) { _compileRules.AddOrUpdate(compiledRuleKey, compiledRule, (k, v) => compiledRule); } @@ -100,7 +100,7 @@ namespace RulesEngine return workflowRules; } } - + /// Gets the compiled rules. /// The compiled rules key. @@ -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> val); + _compileRules.TryRemove(key, out IDictionary> val); } } } diff --git a/src/RulesEngine/RulesEngine.cs b/src/RulesEngine/RulesEngine.cs index 538b62b..aa243f0 100644 --- a/src/RulesEngine/RulesEngine.cs +++ b/src/RulesEngine/RulesEngine.cs @@ -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> GetActionRegistry(ReSettings reSettings) + private IDictionary> GetActionRegistry(ReSettings reSettings) { var actionDictionary = GetDefaultActionRegistry(); var customActions = reSettings.CustomActions ?? new Dictionary>(); - 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(); - 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 /// List of rule results public async ValueTask> 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 ExecuteActionForRuleResult(RuleResultTree resultTree, bool includeRuleResults=false) + private async ValueTask 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() { resultTree }: null + Results = includeRuleResults ? new List() { resultTree } : null }; } } @@ -226,20 +227,22 @@ namespace RulesEngine /// 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>(); + var dictFunc = new Dictionary>(); 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 CompileRule(string workflowName,string ruleName,RuleParameter[] ruleParameters){ + private RuleFunc 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 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 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(); var updatedRuleParams = ruleParams?.Concat(compiledRuleParameters); var compiledRule = _ruleCompiler.CompileRule(rule, updatedRuleParams?.ToArray()); - RuleFunc updatedRule = (RuleParameter[] paramList) => - { + RuleFunc updatedRule = (RuleParameter[] paramList) => { var inputs = paramList.AsEnumerable(); - IEnumerable localParams = compiledParamList ?? new List(); + var localParams = compiledParamList ?? new List(); var evaluatedParamList = new List(); foreach (var localParam in localParams) { @@ -288,7 +293,7 @@ namespace RulesEngine return updatedRule; } - + /// /// This will execute the compiled rules @@ -300,8 +305,8 @@ namespace RulesEngine { _logger.LogTrace($"Compiled rules found for {workflowName} workflow and executed"); - List result = new List(); - string compiledRulesCacheKey = GetCompiledRulesKey(workflowName,ruleParameters); + var result = new List(); + 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> GetDefaultActionRegistry(){ + private IDictionary> GetDefaultActionRegistry() + { return new Dictionary>{ {"OutputExpression",() => new OutputExpressionAction(_ruleExpressionParser) }, {"EvaluateRule", () => new EvaluateRuleAction(this) } @@ -338,11 +344,13 @@ namespace RulesEngine /// Updated error message. private IEnumerable FormatErrorMessages(IEnumerable 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 /// Name of the type. /// Name of the property. /// Updated error message. - private static string UpdateErrorMessage(string errorMessage, IDictionary inputs, string property, string typeName, string propertyName) + private static string UpdateErrorMessage(string errorMessage, IDictionary 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) { diff --git a/src/RulesEngine/RulesEngine.csproj b/src/RulesEngine/RulesEngine.csproj index 4e6c8e6..ef41525 100644 --- a/src/RulesEngine/RulesEngine.csproj +++ b/src/RulesEngine/RulesEngine.csproj @@ -2,7 +2,7 @@ netstandard2.0 - 3.0.0 + 3.0.1 Copyright (c) Microsoft Corporation. LICENSE https://github.com/microsoft/RulesEngine diff --git a/src/RulesEngine/Validators/RuleValidator.cs b/src/RulesEngine/Validators/RuleValidator.cs index b5ff157..23f5a09 100644 --- a/src/RulesEngine/Validators/RuleValidator.cs +++ b/src/RulesEngine/Validators/RuleValidator.cs @@ -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; } diff --git a/src/RulesEngine/Validators/WorkflowRulesValidator.cs b/src/RulesEngine/Validators/WorkflowRulesValidator.cs index 4a8c363..b175acb 100644 --- a/src/RulesEngine/Validators/WorkflowRulesValidator.cs +++ b/src/RulesEngine/Validators/WorkflowRulesValidator.cs @@ -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(); diff --git a/test/RulesEngine.UnitTest/ActionTests/ActionContextTests.cs b/test/RulesEngine.UnitTest/ActionTests/ActionContextTests.cs index cb13cf0..1c8bf62 100644 --- a/test/RulesEngine.UnitTest/ActionTests/ActionContextTests.cs +++ b/test/RulesEngine.UnitTest/ActionTests/ActionContextTests.cs @@ -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; diff --git a/test/RulesEngine.UnitTest/ActionTests/RulesEngineWithActionsTests.cs b/test/RulesEngine.UnitTest/ActionTests/RulesEngineWithActionsTests.cs index 65d7f53..a35cf62 100644 --- a/test/RulesEngine.UnitTest/ActionTests/RulesEngineWithActionsTests.cs +++ b/test/RulesEngine.UnitTest/ActionTests/RulesEngineWithActionsTests.cs @@ -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{ 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{ new Rule{ @@ -100,7 +107,7 @@ namespace RulesEngine.UnitTest{ } }; - return new []{workflow1}; + return new[] { workflow1 }; } } } \ No newline at end of file diff --git a/test/RulesEngine.UnitTest/BusinessRuleEngineTest.cs b/test/RulesEngine.UnitTest/BusinessRuleEngineTest.cs index 481900a..44a59fc 100644 --- a/test/RulesEngine.UnitTest/BusinessRuleEngineTest.cs +++ b/test/RulesEngine.UnitTest/BusinessRuleEngineTest.cs @@ -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>(result); } @@ -59,7 +59,7 @@ namespace RulesEngine.UnitTest List result = await re.ExecuteAllRulesAsync("inputWorkflow", input1, input2, input3); Assert.NotNull(result); Assert.IsType>(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 result = await re.ExecuteAllRulesAsync("inputWorkflow", input1, input2, input3,input4, input5, input6, input7, input8, input9, input10, input11, input12, input13, input14, input15, input16, input17, input18); + List 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>(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 result = await re.ExecuteAllRulesAsync("inputWorkflow", input1); Assert.NotNull(result); Assert.IsType>(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 result = await re.ExecuteAllRulesAsync("inputWorkflow",input1, input2, input3); + List 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(() => - { + Assert.Throws(() => { var workflow = new WorkflowRules(); var re = CreateRulesEngine(workflow); }); - Assert.Throws(() => - { + Assert.Throws(() => { 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(async() => { await re.ExecuteAllRulesAsync("inputWorkflow1", input); }); + await Assert.ThrowsAsync(async () => { await re.ExecuteAllRulesAsync("inputWorkflow1", input); }); } [Theory] @@ -214,7 +212,7 @@ namespace RulesEngine.UnitTest Assert.NotNull(result); re.RemoveWorkflow("inputWorkflow"); - await Assert.ThrowsAsync(async() => await re.ExecuteAllRulesAsync("inputWorkflow",input1, input2, input3 )); + await Assert.ThrowsAsync(async () => await re.ExecuteAllRulesAsync("inputWorkflow", input1, input2, input3)); } @@ -229,8 +227,8 @@ namespace RulesEngine.UnitTest dynamic input2 = GetInput2(); dynamic input3 = GetInput3(); - await Assert.ThrowsAsync(async() => await re.ExecuteAllRulesAsync("inputWorkflow", input1, input2, input3)); - await Assert.ThrowsAsync(async() => await re.ExecuteAllRulesAsync("inputWorkflowReference", input1, input2, input3)); + await Assert.ThrowsAsync(async () => await re.ExecuteAllRulesAsync("inputWorkflow", input1, input2, input3)); + await Assert.ThrowsAsync(async () => await re.ExecuteAllRulesAsync("inputWorkflowReference", input1, input2, input3)); } @@ -248,14 +246,14 @@ namespace RulesEngine.UnitTest List result = await re.ExecuteAllRulesAsync("inputWorkflow", input1, input2, input3); Assert.NotNull(result); Assert.IsType>(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>(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(); - 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(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 result = await re.ExecuteAllRulesAsync("inputWorkflow", input1,input2, input3); + var result = await re.ExecuteAllRulesAsync("inputWorkflow", input1, input2, input3); Assert.NotNull(result); Assert.IsType>(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 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>(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 result = await re.ExecuteAllRulesAsync("inputWorkflow", new RuleParameter("input1", input1)); + var result = await re.ExecuteAllRulesAsync("inputWorkflow", new RuleParameter("input1", input1)); Assert.NotNull(result); Assert.IsType>(result); Assert.All(result, c => Assert.True(c.IsSuccess)); @@ -355,7 +359,7 @@ namespace RulesEngine.UnitTest var utils = new TestInstanceUtils(); - List result = await re.ExecuteAllRulesAsync("inputWorkflow", new RuleParameter("input1", input1)); + var result = await re.ExecuteAllRulesAsync("inputWorkflow", new RuleParameter("input1", input1)); Assert.NotNull(result); Assert.IsType>(result); Assert.All(result, c => Assert.True(c.IsSuccess)); @@ -372,7 +376,7 @@ namespace RulesEngine.UnitTest var utils = new TestInstanceUtils(); - List result = await re.ExecuteAllRulesAsync("inputWorkflow", new RuleParameter("input1", input1)); + var result = await re.ExecuteAllRulesAsync("inputWorkflow", new RuleParameter("input1", input1)); Assert.NotNull(result); Assert.IsType>(result); Assert.All(result, c => Assert.False(c.IsSuccess)); @@ -390,9 +394,8 @@ namespace RulesEngine.UnitTest var utils = new TestInstanceUtils(); - await Assert.ThrowsAsync(async()=> - { - List result = await re.ExecuteAllRulesAsync("inputWorkflow", new RuleParameter("input1", input1)); + await Assert.ThrowsAsync(async () => { + var result = await re.ExecuteAllRulesAsync("inputWorkflow", new RuleParameter("input1", input1)); }); } @@ -408,7 +411,7 @@ namespace RulesEngine.UnitTest var utils = new TestInstanceUtils(); - List result = await re.ExecuteAllRulesAsync("inputWorkflow", new RuleParameter("input1", input1)); + var result = await re.ExecuteAllRulesAsync("inputWorkflow", new RuleParameter("input1", input1)); Assert.NotNull(result); Assert.IsType>(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 { "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; } diff --git a/test/RulesEngine.UnitTest/CustomTypeProviderTests.cs b/test/RulesEngine.UnitTest/CustomTypeProviderTests.cs index 6e55a0f..4564791 100644 --- a/test/RulesEngine.UnitTest/CustomTypeProviderTests.cs +++ b/test/RulesEngine.UnitTest/CustomTypeProviderTests.cs @@ -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(); diff --git a/test/RulesEngine.UnitTest/LambdaExpressionBuilderTest.cs b/test/RulesEngine.UnitTest/LambdaExpressionBuilderTest.cs index 8466fe3..beed4cb 100644 --- a/test/RulesEngine.UnitTest/LambdaExpressionBuilderTest.cs +++ b/test/RulesEngine.UnitTest/LambdaExpressionBuilderTest.cs @@ -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(); + var mainRule = new Rule { + RuleName = "rule1", + Operator = "And", + Rules = new List() + }; - 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); diff --git a/test/RulesEngine.UnitTest/ListofRuleResultTreeExtensionTest.cs b/test/RulesEngine.UnitTest/ListofRuleResultTreeExtensionTest.cs index 1774ccc..29e3853 100644 --- a/test/RulesEngine.UnitTest/ListofRuleResultTreeExtensionTest.cs +++ b/test/RulesEngine.UnitTest/ListofRuleResultTreeExtensionTest.cs @@ -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; }); diff --git a/test/RulesEngine.UnitTest/RuleCompilerTest.cs b/test/RulesEngine.UnitTest/RuleCompilerTest.cs index 4dd5f22..a77e8f4 100644 --- a/test/RulesEngine.UnitTest/RuleCompilerTest.cs +++ b/test/RulesEngine.UnitTest/RuleCompilerTest.cs @@ -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(() => new RuleCompiler(null, null)); var reSettings = new ReSettings(); var parser = new RuleExpressionParser(reSettings); - Assert.Throws(() => new RuleCompiler(new RuleExpressionBuilderFactory(reSettings,parser), null)); + Assert.Throws(() => 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()); + var compiler = new RuleCompiler(new RuleExpressionBuilderFactory(reSettings, parser), new NullLogger()); Assert.Throws(() => compiler.CompileRule(null, null)); - Assert.Throws(() => compiler.CompileRule(null, new RuleParameter[] { null})); + Assert.Throws(() => compiler.CompileRule(null, new RuleParameter[] { null })); } diff --git a/test/RulesEngine.UnitTest/RuleExpressionBuilderFactoryTest.cs b/test/RulesEngine.UnitTest/RuleExpressionBuilderFactoryTest.cs index 00558f5..2ee4891 100644 --- a/test/RulesEngine.UnitTest/RuleExpressionBuilderFactoryTest.cs +++ b/test/RulesEngine.UnitTest/RuleExpressionBuilderFactoryTest.cs @@ -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(); diff --git a/test/RulesEngine.UnitTest/RuleTestClass.cs b/test/RulesEngine.UnitTest/RuleTestClass.cs index 40c0ece..0a028f0 100644 --- a/test/RulesEngine.UnitTest/RuleTestClass.cs +++ b/test/RulesEngine.UnitTest/RuleTestClass.cs @@ -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 { diff --git a/test/RulesEngine.UnitTest/UtilsTests.cs b/test/RulesEngine.UnitTest/UtilsTests.cs index 0056ec9..5432f99 100644 --- a/test/RulesEngine.UnitTest/UtilsTests.cs +++ b/test/RulesEngine.UnitTest/UtilsTests.cs @@ -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 testList { get; set; } + public string Test { get; set; } + public List 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 { 1, 2, 3 }; + obj.Test = "hello"; + obj.TestList = new List { 1, 2, 3 }; object typedobj = Utils.GetTypedObject(obj); Assert.IsNotType(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 { 1, 2, 3 }; + obj.Test = "hello"; + obj.TestList = new List { 1, 2, 3 }; dynamic obj2 = new ExpandoObject(); - obj2.test = "world"; - obj2.testList = new List { 1, 2, 3 }; + obj2.Test = "world"; + obj2.TestList = new List { 1, 2, 3 }; object typedobj = Utils.GetTypedObject(obj); object typedobj2 = Utils.GetTypedObject(obj2); Assert.IsNotType(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(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 { 1, 2, 3 }; + obj.Test = "test"; + obj.TestList = new List { 1, 2, 3 }; object newObj = Utils.CreateObject(typeof(TestClass), obj); Assert.IsNotType(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 { 1, 2, 3 }; + obj.Test = "test"; + obj.TestList = new List { 1, 2, 3 }; obj.testEmptyList = new List(); - 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")); }