* fixed namespace issue (#82)

* fixed namespace issue
* added editorconfig
* cleaned up files based on editorconfig
pull/93/head v3.0.1
Abbas Cyclewala 2020-12-23 11:04:10 +05:30 committed by GitHub
parent 2886bca157
commit 9c8b9d484e
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
47 changed files with 539 additions and 348 deletions

134
.editorconfig Normal file
View File

@ -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

View File

@ -2,9 +2,9 @@ name: "Code scanning"
on:
push:
branches: [ master ]
branches: [ main ]
pull_request:
branches: [ master ]
branches: [ main ]
schedule:
- cron: '0 18 * * 1'

View File

@ -2,9 +2,9 @@ name: build
on:
push:
branches: [ master ]
branches: [ main ]
pull_request:
branches: [ master, develop ]
branches: [ main, develop ]
jobs:
build:

View File

@ -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)

View File

@ -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

View File

@ -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,7 +29,9 @@ 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);
@ -35,11 +41,9 @@ namespace RulesEngineBenchmark
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>();
}
}
}

View File

@ -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.";
});

View File

@ -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; }
}
@ -20,8 +23,7 @@ namespace DemoApp
Console.WriteLine($"Running {nameof(NestedInputDemo)}....");
var nestedInput = new {
SimpleProp = "simpleProp",
NestedProp = new
{
NestedProp = new {
SimpleProp = "nestedSimpleProp",
ListProp = new List<ListItem>
{
@ -42,7 +44,9 @@ 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);
@ -50,13 +54,11 @@ namespace DemoApp
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");
});

View File

@ -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();

View File

@ -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)
{
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()

View File

@ -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)

View File

@ -1,4 +1,7 @@
using System;
// Copyright (c) Microsoft Corporation.
// Licensed under the MIT License.
using System;
using System.Collections.Generic;
namespace RulesEngine.Actions
@ -14,7 +17,8 @@ namespace RulesEngine.Actions
}
internal ActionFactory(IDictionary<string, Func<ActionBase>> actionRegistry) : this()
{
foreach(var kv in actionRegistry){
foreach (var kv in actionRegistry)
{
_actionRegistry.Add(kv.Key, kv.Value);
}
}

View File

@ -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){
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,7 +33,7 @@ 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");

View File

@ -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
{

View File

@ -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
{

View File

@ -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
{

View File

@ -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
{
@ -36,9 +39,10 @@ namespace RulesEngine.ExpressionBuilders
}
private Expression<Func<object[],T>> WrapExpression<T>(LambdaExpression expression, ParameterExpression[] parameters){
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) => {
var paramExps = parameters.Select((c, i) => {
var arg = Expression.ArrayAccess(argExp, Expression.Constant(i));
return (Expression)Expression.Assign(c, Expression.Convert(arg, c.Type));
});
@ -77,7 +81,8 @@ namespace RulesEngine.ExpressionBuilders
}
}
private string GetCacheKey(string expression, RuleParameter[] ruleParameters,Type returnType){
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}";

View File

@ -5,7 +5,6 @@ using RulesEngine.Models;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Linq.Expressions;
namespace RulesEngine.HelperFunctions
{
@ -16,8 +15,7 @@ namespace RulesEngine.HelperFunctions
{
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),
IsSuccess = isSuccessFunc(inputs.Select(c => c.Value).ToArray()),

View File

@ -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; }

View File

@ -1,6 +1,15 @@
using System;
// Copyright (c) Microsoft Corporation.
// Licensed under the MIT License.
public class ActionResult{
using System;
using System.Diagnostics.CodeAnalysis;
namespace RulesEngine.Models
{
[ExcludeFromCodeCoverage]
public class ActionResult
{
public object Output { get; set; }
public Exception Exception { get; set; }
}
}

View File

@ -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{
namespace RulesEngine.Models
{
[ExcludeFromCodeCoverage]
public class ActionRuleResult : ActionResult
{
public List<RuleResultTree> Results { get; set; }
}
}

View File

@ -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
{

View File

@ -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

View File

@ -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
{

View File

@ -1,9 +1,9 @@
// Copyright (c) Microsoft Corporation.
// Licensed under the MIT License.
using RulesEngine.HelperFunctions;
using System;
using System.Diagnostics.CodeAnalysis;
using RulesEngine.HelperFunctions;
namespace RulesEngine.Models
{
@ -17,7 +17,8 @@ namespace RulesEngine.Models
Name = name;
}
internal RuleParameter(string name,Type type){
internal RuleParameter(string name, Type type)
{
Name = name;
Type = type;
}

View File

@ -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
{

View File

@ -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>
@ -68,7 +58,7 @@ namespace RulesEngine
{
throw new ArgumentNullException(nameof(rule));
}
RuleFunc<RuleResultTree> ruleExpression = GetDelegateForRule(rule,ruleParams);
var ruleExpression = GetDelegateForRule(rule, ruleParams);
return ruleExpression;
}
catch (Exception ex)
@ -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,11 +130,10 @@ namespace RulesEngine
ruleFuncList.Add(GetDelegateForRule(r, ruleParams));
}
return (paramArray) =>
{
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);
var result = Helpers.ToResultTree(parentRule, resultList, isSuccess);
return result(paramArray);
};
}

View File

@ -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
{
@ -66,7 +66,8 @@ namespace RulesEngine
{
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));
@ -106,7 +107,8 @@ namespace RulesEngine
public async ValueTask<List<RuleResultTree>> ExecuteAllRulesAsync(string workflowName, params RuleParameter[] ruleParams)
{
var ruleResultList = ValidateWorkflowAndExecuteRule(workflowName, ruleParams);
foreach(var ruleResult in ruleResultList){
foreach (var ruleResult in ruleResultList)
{
var actionResult = await ExecuteActionForRuleResult(ruleResult, false);
ruleResult.ActionResult = new ActionResult {
Output = actionResult.Output,
@ -126,7 +128,7 @@ namespace RulesEngine
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))
{
@ -138,8 +140,7 @@ namespace RulesEngine
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
};
@ -226,9 +227,11 @@ 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)
@ -250,10 +253,12 @@ 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);
@ -261,19 +266,19 @@ namespace RulesEngine
private RuleFunc<RuleResultTree> CompileRule(string workflowName, RuleParameter[] ruleParams, Rule rule)
{
if(!_reSettings.EnableLocalParams){
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)
{
@ -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);
@ -314,17 +319,18 @@ namespace RulesEngine
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)
{
var key = $"compiledparams-{workflowName}-{ruleName}" + String.Join("-", ruleParams.Select(c => c.Type.Name));
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;

View File

@ -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>

View File

@ -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;
}

View File

@ -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();

View File

@ -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;

View File

@ -1,19 +1,24 @@
// 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);
@ -50,7 +55,8 @@ namespace RulesEngine.UnitTest{
}
private WorkflowRules[] GetWorkflowRulesWithoutActions(){
private WorkflowRules[] GetWorkflowRulesWithoutActions()
{
var workflow1 = new WorkflowRules {
WorkflowName = "NoActionWorkflow",
Rules = new List<Rule>{
@ -65,7 +71,8 @@ namespace RulesEngine.UnitTest{
return new[] { workflow1 };
}
private WorkflowRules[] GetWorkflowWithActions(){
private WorkflowRules[] GetWorkflowWithActions()
{
var workflow1 = new WorkflowRules {
WorkflowName = "ActionWorkflow",

View File

@ -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
{
@ -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);
});
@ -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);
@ -295,7 +295,7 @@ namespace RulesEngine.UnitTest
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'"));
@ -310,14 +310,18 @@ namespace RulesEngine.UnitTest
dynamic input1 = new ExpandoObject();
if (propValue != null)
{
input1.Property1 = propValue;
}
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));
@ -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){
private class TestInstanceUtils
{
public bool CheckExists(string str)
{
if (str != null && str.Length > 0)
{
return true;
}
return false;
}

View File

@ -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();

View File

@ -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
@ -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);

View File

@ -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;
});

View File

@ -1,7 +1,6 @@
// Copyright (c) Microsoft Corporation.
// Licensed under the MIT License.
using RulesEngine;
using RulesEngine.ExpressionBuilders;
using RulesEngine.Models;
using System;

View File

@ -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
{

View File

@ -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,8 +13,8 @@ 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")]
@ -27,26 +26,26 @@ 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.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]
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);
Assert.NotEqual(typeof(ExpandoObject), type);
Assert.NotNull(type.GetProperty("test"));
Assert.NotNull(type.GetProperty("Test"));
}