From b5dc10ede489d8f8a4e9c14cfea959cfa427a403 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Lu=C3=ADs=20Garc=C3=AAs?= Date: Fri, 26 Jul 2024 17:03:28 +0100 Subject: [PATCH 1/6] refactor!: remove obsolete APIs (#167) --- .../Engine/RulesEngineProvider.cs | 3 +- .../RuleFactory.cs | 79 +++++----------- src/Rules.Framework/AssemblyMetadata.cs | 2 +- .../Builder/ConditionNodeFactory.cs | 33 ++++++- .../ComposedConditionNodeBuilder.cs | 41 -------- .../Deprecated/ConditionNodeBuilder.cs | 14 --- .../IComposedConditionNodeBuilder.cs | 33 ------- .../Deprecated/IConditionNodeBuilder.cs | 26 ------ .../Deprecated/IValueConditionNodeBuilder.cs | 60 ------------ .../Deprecated/ValueConditionNodeBuilder.cs | 93 ------------------- src/Rules.Framework/Builder/IRuleBuilder.cs | 18 ---- src/Rules.Framework/Builder/RuleBuilder.cs | 19 ---- .../Builder/RuleBuilderResult.cs | 19 ++-- src/Rules.Framework/Condition.cs | 8 -- src/Rules.Framework/IRulesEngineOptions.cs | 6 -- src/Rules.Framework/RulesEngineOptions.cs | 11 --- .../BuildingSecuritySystemControlTests.cs | 6 +- 17 files changed, 62 insertions(+), 409 deletions(-) delete mode 100644 src/Rules.Framework/Builder/Deprecated/ComposedConditionNodeBuilder.cs delete mode 100644 src/Rules.Framework/Builder/Deprecated/ConditionNodeBuilder.cs delete mode 100644 src/Rules.Framework/Builder/Deprecated/IComposedConditionNodeBuilder.cs delete mode 100644 src/Rules.Framework/Builder/Deprecated/IConditionNodeBuilder.cs delete mode 100644 src/Rules.Framework/Builder/Deprecated/IValueConditionNodeBuilder.cs delete mode 100644 src/Rules.Framework/Builder/Deprecated/ValueConditionNodeBuilder.cs diff --git a/samples/Rules.Framework.WebUI.Sample/Engine/RulesEngineProvider.cs b/samples/Rules.Framework.WebUI.Sample/Engine/RulesEngineProvider.cs index 8d8d733c..41b67f44 100644 --- a/samples/Rules.Framework.WebUI.Sample/Engine/RulesEngineProvider.cs +++ b/samples/Rules.Framework.WebUI.Sample/Engine/RulesEngineProvider.cs @@ -3,7 +3,6 @@ namespace Rules.Framework.WebUI.Sample.Engine using System; using System.Threading; using System.Threading.Tasks; - using global::Rules.Framework.Providers.InMemory; using global::Rules.Framework.WebUI.Sample.Enums; internal class RulesEngineProvider @@ -19,7 +18,7 @@ public RulesEngineProvider(RulesBuilder rulesBuilder) .WithContentType() .WithConditionType() .SetInMemoryDataSource() - .Configure(c => c.PriotityCriteria = PriorityCriterias.TopmostRuleWins) + .Configure(c => c.PriorityCriteria = PriorityCriterias.TopmostRuleWins) .Build(); await rulesBuilder.BuildAsync(rulesEngine).ConfigureAwait(false); diff --git a/src/Rules.Framework.Providers.MongoDb/RuleFactory.cs b/src/Rules.Framework.Providers.MongoDb/RuleFactory.cs index c41fdfeb..54cc31d0 100644 --- a/src/Rules.Framework.Providers.MongoDb/RuleFactory.cs +++ b/src/Rules.Framework.Providers.MongoDb/RuleFactory.cs @@ -4,7 +4,6 @@ namespace Rules.Framework.Providers.MongoDb using System.Collections.Generic; using System.Globalization; using System.Linq; - using Rules.Framework.Builder; using Rules.Framework.Core; using Rules.Framework.Core.ConditionNodes; using Rules.Framework.Providers.MongoDb.DataModel; @@ -32,7 +31,7 @@ public Rule CreateRule(RuleDataModel ruleDataModel .WithName(ruleDataModel.Name) .WithDatesInterval(ruleDataModel.DateBegin, ruleDataModel.DateEnd) .WithActive(ruleDataModel.Active ?? true) - .WithCondition(cnb => ruleDataModel.RootCondition is { } ? ConvertConditionNode(cnb, ruleDataModel.RootCondition) : null) + .WithCondition(_ => ruleDataModel.RootCondition is { } ? ConvertConditionNode(ruleDataModel.RootCondition) : null) .WithSerializedContent(contentType, (object)ruleDataModel.Content, this.contentSerializationProvider) .Build(); @@ -78,27 +77,25 @@ public RuleDataModel CreateRule(Rule rule) return ruleDataModel; } - private static IConditionNode ConvertConditionNode( - IConditionNodeBuilder conditionNodeBuilder, ConditionNodeDataModel conditionNodeDataModel) + private static IConditionNode ConvertConditionNode(ConditionNodeDataModel conditionNodeDataModel) { if (conditionNodeDataModel.LogicalOperator == LogicalOperators.Eval) { - return CreateValueConditionNode(conditionNodeBuilder, conditionNodeDataModel as ValueConditionNodeDataModel); + return CreateValueConditionNode(conditionNodeDataModel as ValueConditionNodeDataModel); } var composedConditionNodeDataModel = conditionNodeDataModel as ComposedConditionNodeDataModel; - - var composedConditionNodeBuilder = conditionNodeBuilder.AsComposed() - .WithLogicalOperator(composedConditionNodeDataModel.LogicalOperator); - var childConditionNodes = composedConditionNodeDataModel.ChildConditionNodes; - var count = childConditionNodes.Length; - var i = -1; - while (++i < count) + var childConditionNodeDataModels = composedConditionNodeDataModel.ChildConditionNodes; + var count = childConditionNodeDataModels.Length; + var childConditionNodes = new IConditionNode[count]; + for (int i = 0; i < count; i++) { - composedConditionNodeBuilder.AddCondition(cnb => ConvertConditionNode(cnb, childConditionNodes[i])); + childConditionNodes[i] = ConvertConditionNode(childConditionNodeDataModels[i]); } - var composedConditionNode = composedConditionNodeBuilder.Build(); + var composedConditionNode = new ComposedConditionNode( + composedConditionNodeDataModel.LogicalOperator, + childConditionNodes); foreach (var property in composedConditionNodeDataModel.Properties) { composedConditionNode.Properties[property.Key] = property.Value; @@ -122,55 +119,21 @@ private static ValueConditionNodeDataModel ConvertValueConditionNode(ValueCondit }; } - private static IConditionNode CreateValueConditionNode(IConditionNodeBuilder conditionNodeBuilder, ValueConditionNodeDataModel conditionNodeDataModel) + private static ValueConditionNode CreateValueConditionNode(ValueConditionNodeDataModel conditionNodeDataModel) { TConditionType conditionType = Parse(conditionNodeDataModel.ConditionType); - var valueConditionNode = conditionNodeDataModel.DataType switch + var operand = conditionNodeDataModel.DataType switch { - DataTypes.Integer => conditionNodeBuilder.AsValued(conditionType) - .OfDataType() - .WithComparisonOperator(conditionNodeDataModel.Operator) - .SetOperand(Convert.ToInt32(conditionNodeDataModel.Operand, CultureInfo.InvariantCulture)) - .Build(), - DataTypes.Decimal => conditionNodeBuilder.AsValued(conditionType) - .OfDataType() - .WithComparisonOperator(conditionNodeDataModel.Operator) - .SetOperand(Convert.ToDecimal(conditionNodeDataModel.Operand, CultureInfo.InvariantCulture)) - .Build(), - DataTypes.String => conditionNodeBuilder.AsValued(conditionType) - .OfDataType() - .WithComparisonOperator(conditionNodeDataModel.Operator) - .SetOperand(Convert.ToString(conditionNodeDataModel.Operand, CultureInfo.InvariantCulture)) - .Build(), - DataTypes.Boolean => conditionNodeBuilder.AsValued(conditionType) - .OfDataType() - .WithComparisonOperator(conditionNodeDataModel.Operator) - .SetOperand(Convert.ToBoolean(conditionNodeDataModel.Operand, CultureInfo.InvariantCulture)) - .Build(), - - DataTypes.ArrayInteger => conditionNodeBuilder.AsValued(conditionType) - .OfDataType>() - .WithComparisonOperator(conditionNodeDataModel.Operator) - .SetOperand(conditionNodeDataModel.Operand as IEnumerable) - .Build(), - DataTypes.ArrayDecimal => conditionNodeBuilder.AsValued(conditionType) - .OfDataType>() - .WithComparisonOperator(conditionNodeDataModel.Operator) - .SetOperand(conditionNodeDataModel.Operand as IEnumerable) - .Build(), - DataTypes.ArrayString => conditionNodeBuilder.AsValued(conditionType) - .OfDataType>() - .WithComparisonOperator(conditionNodeDataModel.Operator) - .SetOperand(conditionNodeDataModel.Operand as IEnumerable) - .Build(), - DataTypes.ArrayBoolean => conditionNodeBuilder.AsValued(conditionType) - .OfDataType>() - .WithComparisonOperator(conditionNodeDataModel.Operator) - .SetOperand(conditionNodeDataModel.Operand as IEnumerable) - .Build(), + DataTypes.Integer => Convert.ToInt32(conditionNodeDataModel.Operand, CultureInfo.InvariantCulture), + DataTypes.Decimal => Convert.ToDecimal(conditionNodeDataModel.Operand, CultureInfo.InvariantCulture), + DataTypes.String => Convert.ToString(conditionNodeDataModel.Operand, CultureInfo.InvariantCulture), + DataTypes.Boolean => Convert.ToBoolean(conditionNodeDataModel.Operand, CultureInfo.InvariantCulture), + DataTypes.ArrayInteger or DataTypes.ArrayDecimal or DataTypes.ArrayString or DataTypes.ArrayBoolean => conditionNodeDataModel.Operand, _ => throw new NotSupportedException($"Unsupported data type: {conditionNodeDataModel.DataType}."), }; + var valueConditionNode = new ValueConditionNode(conditionNodeDataModel.DataType, conditionType, conditionNodeDataModel.Operator, operand); + foreach (var property in conditionNodeDataModel.Properties) { valueConditionNode.Properties[property.Key] = property.Value; @@ -230,4 +193,4 @@ private ConditionNodeDataModel ConvertConditionNode(IConditionNode); } } -} +} \ No newline at end of file diff --git a/src/Rules.Framework/AssemblyMetadata.cs b/src/Rules.Framework/AssemblyMetadata.cs index a88ba7ef..c5c22406 100644 --- a/src/Rules.Framework/AssemblyMetadata.cs +++ b/src/Rules.Framework/AssemblyMetadata.cs @@ -2,6 +2,6 @@ [assembly: InternalsVisibleTo("Rules.Framework.Tests")] [assembly: InternalsVisibleTo("Rules.Framework.IntegrationTests")] -[assembly: InternalsVisibleTo("Rules.Framework.Providers.InMemory.Tests")] [assembly: InternalsVisibleTo("Rules.Framework.Providers.InMemory.IntegrationTests")] +[assembly: InternalsVisibleTo("Rules.Framework.Providers.MongoDb")] [assembly: InternalsVisibleTo("DynamicProxyGenAssembly2")] \ No newline at end of file diff --git a/src/Rules.Framework/Builder/ConditionNodeFactory.cs b/src/Rules.Framework/Builder/ConditionNodeFactory.cs index 2fd7da0d..881cb162 100644 --- a/src/Rules.Framework/Builder/ConditionNodeFactory.cs +++ b/src/Rules.Framework/Builder/ConditionNodeFactory.cs @@ -1,7 +1,9 @@ namespace Rules.Framework.Builder { using System; + using System.Collections.Generic; using Rules.Framework.Core; + using Rules.Framework.Core.ConditionNodes; /// /// Factory for creating condition nodes. @@ -39,8 +41,35 @@ public static IConditionNode CreateComposedNode( public static IConditionNode CreateValueNode( TConditionType conditionType, Operators condOperator, TDataType operand) { - return new ValueConditionNodeBuilder(conditionType, condOperator, operand) - .Build(); + switch (operand) + { + case decimal _: + return new ValueConditionNode(DataTypes.Decimal, conditionType, condOperator, operand); + + case IEnumerable _: + return new ValueConditionNode(DataTypes.ArrayDecimal, conditionType, condOperator, operand); + + case int _: + return new ValueConditionNode(DataTypes.Integer, conditionType, condOperator, operand); + + case IEnumerable _: + return new ValueConditionNode(DataTypes.ArrayInteger, conditionType, condOperator, operand); + + case bool _: + return new ValueConditionNode(DataTypes.Boolean, conditionType, condOperator, operand); + + case IEnumerable _: + return new ValueConditionNode(DataTypes.ArrayBoolean, conditionType, condOperator, operand); + + case string _: + return new ValueConditionNode(DataTypes.String, conditionType, condOperator, operand); + + case IEnumerable _: + return new ValueConditionNode(DataTypes.ArrayString, conditionType, condOperator, operand); + + default: + throw new NotSupportedException($"The data type is not supported: {typeof(TDataType).FullName}."); + } } } } \ No newline at end of file diff --git a/src/Rules.Framework/Builder/Deprecated/ComposedConditionNodeBuilder.cs b/src/Rules.Framework/Builder/Deprecated/ComposedConditionNodeBuilder.cs deleted file mode 100644 index e8baa10e..00000000 --- a/src/Rules.Framework/Builder/Deprecated/ComposedConditionNodeBuilder.cs +++ /dev/null @@ -1,41 +0,0 @@ -namespace Rules.Framework.Builder -{ - using System; - using System.Collections.Generic; - using Rules.Framework.Core; - using Rules.Framework.Core.ConditionNodes; - - internal sealed class ComposedConditionNodeBuilder : IComposedConditionNodeBuilder - { - private readonly IConditionNodeBuilder conditionNodeBuilder; - private readonly List> conditions; - private LogicalOperators logicalOperator; - - public ComposedConditionNodeBuilder(IConditionNodeBuilder conditionNodeBuilder) - { - this.conditionNodeBuilder = conditionNodeBuilder; - this.conditions = new List>(2); // Most probable number of conditions, so that collection is initialized with right size most times. - } - - public IComposedConditionNodeBuilder AddCondition(Func, IConditionNode> conditionFunc) - { - var conditionNode = conditionFunc.Invoke(this.conditionNodeBuilder); - - this.conditions.Add(conditionNode); - - return this; - } - - public IConditionNode Build() - { - return new ComposedConditionNode(this.logicalOperator, this.conditions); - } - - public IComposedConditionNodeBuilder WithLogicalOperator(LogicalOperators logicalOperator) - { - this.logicalOperator = logicalOperator; - - return this; - } - } -} \ No newline at end of file diff --git a/src/Rules.Framework/Builder/Deprecated/ConditionNodeBuilder.cs b/src/Rules.Framework/Builder/Deprecated/ConditionNodeBuilder.cs deleted file mode 100644 index 502d17bb..00000000 --- a/src/Rules.Framework/Builder/Deprecated/ConditionNodeBuilder.cs +++ /dev/null @@ -1,14 +0,0 @@ -namespace Rules.Framework.Builder -{ - using System; - - [Obsolete("This way of building conditions has been deprecated. Please use the IRootConditionNodeBuilder and IFluentComposedConditionNodeBuilder interfaces.")] - internal sealed class ConditionNodeBuilder : IConditionNodeBuilder - { - public IComposedConditionNodeBuilder AsComposed() - => new ComposedConditionNodeBuilder(this); - - public IValueConditionNodeBuilder AsValued(TConditionType conditionType) - => new ValueConditionNodeBuilder(conditionType); - } -} \ No newline at end of file diff --git a/src/Rules.Framework/Builder/Deprecated/IComposedConditionNodeBuilder.cs b/src/Rules.Framework/Builder/Deprecated/IComposedConditionNodeBuilder.cs deleted file mode 100644 index 5165c621..00000000 --- a/src/Rules.Framework/Builder/Deprecated/IComposedConditionNodeBuilder.cs +++ /dev/null @@ -1,33 +0,0 @@ -namespace Rules.Framework.Builder -{ - using System; - using Rules.Framework.Core; - - /// - /// Builder for composed condition nodes. - /// - /// The type of the condition type. - [Obsolete("This way of building and adding composed conditions has been deprecated. Please use the IRootConditionNodeBuilder and IFluentComposedConditionNodeBuilder interfaces.")] - public interface IComposedConditionNodeBuilder - { - /// - /// Adds a condition to the composed condition node builder. - /// - /// The function containing the logic for the new condition. - /// - IComposedConditionNodeBuilder AddCondition(Func, IConditionNode> conditionFunc); - - /// - /// Builds the composed condition node. - /// - /// - IConditionNode Build(); - - /// - /// Sets the composed condition node with the specified logical operator. - /// - /// The logical operator. - /// - IComposedConditionNodeBuilder WithLogicalOperator(LogicalOperators logicalOperator); - } -} \ No newline at end of file diff --git a/src/Rules.Framework/Builder/Deprecated/IConditionNodeBuilder.cs b/src/Rules.Framework/Builder/Deprecated/IConditionNodeBuilder.cs deleted file mode 100644 index e6c279a9..00000000 --- a/src/Rules.Framework/Builder/Deprecated/IConditionNodeBuilder.cs +++ /dev/null @@ -1,26 +0,0 @@ -namespace Rules.Framework.Builder -{ - using System; - - /// - /// Builder to specify a new condition node. Allows for choosing between composed and valued - /// condition nodes. - /// - /// The type of the condition type. - [Obsolete("This way of building conditions has been deprecated. Please use the IRootConditionNodeBuilder and IFluentComposedConditionNodeBuilder interfaces.")] - public interface IConditionNodeBuilder - { - /// - /// Begins building a condition node as composed. - /// - /// - IComposedConditionNodeBuilder AsComposed(); - - /// - /// Begins building a condition node as valued. - /// - /// Type of the condition. - /// - IValueConditionNodeBuilder AsValued(TConditionType conditionType); - } -} \ No newline at end of file diff --git a/src/Rules.Framework/Builder/Deprecated/IValueConditionNodeBuilder.cs b/src/Rules.Framework/Builder/Deprecated/IValueConditionNodeBuilder.cs deleted file mode 100644 index cf6ec9e1..00000000 --- a/src/Rules.Framework/Builder/Deprecated/IValueConditionNodeBuilder.cs +++ /dev/null @@ -1,60 +0,0 @@ -namespace Rules.Framework.Builder -{ - using System; - using System.Collections.Generic; - using Rules.Framework.Core; - using Rules.Framework.Core.ConditionNodes; - - /// - /// Builder to specify the data type for a valued condition node. - /// - /// The type of the condition type. - [Obsolete("This way of building and adding value conditions has been deprecated. Please use the IRootConditionNodeBuilder and IFluentComposedConditionNodeBuilder interfaces.")] - public interface IValueConditionNodeBuilder - { - /// - /// Sets the new value condition node to have the type . - /// - /// the data type of the new value condition node. - /// - IValueConditionNodeBuilder OfDataType(); - } - - /// - /// Builder to specify create a new value condition node. - /// - /// The type of the condition type. - /// The type of the data type. - [Obsolete("This way of building and adding value conditions has been deprecated. Please use the IRootConditionNodeBuilder and IFluentComposedConditionNodeBuilder interfaces.")] - public interface IValueConditionNodeBuilder - { - /// - /// Builds the new value condition node. - /// - /// - IValueConditionNode Build(); - - /// - /// Sets the condition node right hand operand (as a single value). Remember that the rules - /// engine input conditions will be evaluated as left hand operands. - /// - /// The value. - /// - IValueConditionNodeBuilder SetOperand(TDataType value); - - /// - /// Sets the condition node right hand operand (as collection of values). Remember that the - /// rules engine input conditions will be evaluated as left hand operands. - /// - /// The value. - /// - IValueConditionNodeBuilder SetOperand(IEnumerable value); - - /// - /// Sets the new value condition node with the specified comparison operator. - /// - /// The comparison operator. - /// - IValueConditionNodeBuilder WithComparisonOperator(Operators comparisonOperator); - } -} \ No newline at end of file diff --git a/src/Rules.Framework/Builder/Deprecated/ValueConditionNodeBuilder.cs b/src/Rules.Framework/Builder/Deprecated/ValueConditionNodeBuilder.cs deleted file mode 100644 index afb803a4..00000000 --- a/src/Rules.Framework/Builder/Deprecated/ValueConditionNodeBuilder.cs +++ /dev/null @@ -1,93 +0,0 @@ -namespace Rules.Framework.Builder -{ - using System; - using System.Collections.Generic; - using Rules.Framework.Core; - using Rules.Framework.Core.ConditionNodes; - - internal sealed class ValueConditionNodeBuilder : IValueConditionNodeBuilder - { - private readonly TConditionType conditionType; - - public ValueConditionNodeBuilder(TConditionType conditionType) - { - this.conditionType = conditionType; - } - - public IValueConditionNodeBuilder OfDataType() - => new ValueConditionNodeBuilder(this.conditionType); - } - - internal sealed class ValueConditionNodeBuilder : IValueConditionNodeBuilder - { - private readonly TConditionType conditionType; - private Operators comparisonOperator; - private object operand; - - public ValueConditionNodeBuilder(TConditionType conditionType) - { - this.conditionType = conditionType; - } - - public ValueConditionNodeBuilder(TConditionType conditionType, Operators comparisonOperator, object operand) - { - this.conditionType = conditionType; - this.comparisonOperator = comparisonOperator; - this.operand = operand; - } - - public IValueConditionNode Build() - { - switch (this.operand) - { - case decimal _: - return new ValueConditionNode(DataTypes.Decimal, this.conditionType, this.comparisonOperator, this.operand); - - case IEnumerable _: - return new ValueConditionNode(DataTypes.ArrayDecimal, this.conditionType, this.comparisonOperator, this.operand); - - case int _: - return new ValueConditionNode(DataTypes.Integer, this.conditionType, this.comparisonOperator, this.operand); - - case IEnumerable _: - return new ValueConditionNode(DataTypes.ArrayInteger, this.conditionType, this.comparisonOperator, this.operand); - - case bool _: - return new ValueConditionNode(DataTypes.Boolean, this.conditionType, this.comparisonOperator, this.operand); - - case IEnumerable _: - return new ValueConditionNode(DataTypes.ArrayBoolean, this.conditionType, this.comparisonOperator, this.operand); - - case string _: - return new ValueConditionNode(DataTypes.String, this.conditionType, this.comparisonOperator, this.operand); - - case IEnumerable _: - return new ValueConditionNode(DataTypes.ArrayString, this.conditionType, this.comparisonOperator, this.operand); - - default: - throw new NotSupportedException($"The data type is not supported: {typeof(TDataType).FullName}."); - } - } - - public IValueConditionNodeBuilder SetOperand(TDataType value) - { - this.operand = value; - - return this; - } - - public IValueConditionNodeBuilder SetOperand(IEnumerable value) - { - this.operand = value; - - return this; - } - - public IValueConditionNodeBuilder WithComparisonOperator(Operators comparisonOperator) - { - this.comparisonOperator = comparisonOperator; - - return this; - } - } -} \ No newline at end of file diff --git a/src/Rules.Framework/Builder/IRuleBuilder.cs b/src/Rules.Framework/Builder/IRuleBuilder.cs index aaac41aa..31e727d0 100644 --- a/src/Rules.Framework/Builder/IRuleBuilder.cs +++ b/src/Rules.Framework/Builder/IRuleBuilder.cs @@ -24,16 +24,6 @@ public interface IRuleBuilder /// IRuleBuilder WithActive(bool active); - /// - /// Sets the new rule with the specified condition. - /// - /// - /// The function with specific logic to create the condition for the rule. - /// - /// - [Obsolete("This way of adding conditions is being deprecated. Please use a non-deprecated overload instead.")] - IRuleBuilder WithCondition(Func, IConditionNode> conditionFunc); - /// /// Sets the new rule with the specified root condition. /// @@ -67,14 +57,6 @@ IRuleBuilder WithCondition( /// IRuleBuilder WithContent(TContentType contentType, object content); - /// - /// Sets the new rule with the specified content container. - /// - /// The content container. - /// - [Obsolete("This way of building the content is being deprecated. Please use WithContent().")] - IRuleBuilder WithContentContainer(ContentContainer contentContainer); - /// /// Sets the new rule with the specified date begin. /// diff --git a/src/Rules.Framework/Builder/RuleBuilder.cs b/src/Rules.Framework/Builder/RuleBuilder.cs index a5510e4c..506bbc42 100644 --- a/src/Rules.Framework/Builder/RuleBuilder.cs +++ b/src/Rules.Framework/Builder/RuleBuilder.cs @@ -52,17 +52,6 @@ public IRuleBuilder WithCondition(IConditionNode WithCondition( - Func, IConditionNode> conditionFunc) - { - var conditionNodeBuilder = new ConditionNodeBuilder(); - - var condition = conditionFunc.Invoke(conditionNodeBuilder); - - return this.WithCondition(condition); - } - public IRuleBuilder WithCondition( Func, IConditionNode> conditionFunc) { @@ -90,14 +79,6 @@ public IRuleBuilder WithContent(TContentType conte return this; } - [Obsolete("This way of building the content is being deprecated. Please use WithContent().")] - public IRuleBuilder WithContentContainer(ContentContainer contentContainer) - { - this.contentContainer = contentContainer; - - return this; - } - public IRuleBuilder WithDateBegin(DateTime dateBegin) { this.dateBegin = dateBegin; diff --git a/src/Rules.Framework/Builder/RuleBuilderResult.cs b/src/Rules.Framework/Builder/RuleBuilderResult.cs index a9d69fd9..be8ea684 100644 --- a/src/Rules.Framework/Builder/RuleBuilderResult.cs +++ b/src/Rules.Framework/Builder/RuleBuilderResult.cs @@ -22,7 +22,7 @@ public static RuleBuilderResult Failure(false, null, errors); + return new RuleBuilderResult(isSuccess: false, null!, errors); } /// @@ -38,7 +38,7 @@ public static RuleBuilderResult Success(true, rule, Enumerable.Empty()); + return new RuleBuilderResult(isSuccess: true, rule, Enumerable.Empty()); } } @@ -50,7 +50,8 @@ public static RuleBuilderResult Success { /// - /// Initializes a new instance of the class. + /// Initializes a new instance of the class. /// internal RuleBuilderResult(bool isSuccess, Rule rule, IEnumerable errors) { @@ -62,25 +63,19 @@ internal RuleBuilderResult(bool isSuccess, Rule ru /// /// Gets the errors. /// - /// - /// The errors. - /// + /// The errors. public IEnumerable Errors { get; } /// /// Gets a value indicating whether rule was built successfuly without validation errors. /// - /// - /// true if rule was built; otherwise, false. - /// + /// true if rule was built; otherwise, false. public bool IsSuccess { get; } /// /// Gets the rule. /// - /// - /// The rule. - /// + /// The rule. public Rule Rule { get; } } } \ No newline at end of file diff --git a/src/Rules.Framework/Condition.cs b/src/Rules.Framework/Condition.cs index 878170dd..6931f564 100644 --- a/src/Rules.Framework/Condition.cs +++ b/src/Rules.Framework/Condition.cs @@ -21,14 +21,6 @@ public Condition(TConditionType type, object value) this.Value = value; } - /// - /// Creates a Condition. - /// - [Obsolete("Please use the constructor with parameters instead.")] - public Condition() - { - } - /// /// Gets or sets the condition type. /// diff --git a/src/Rules.Framework/IRulesEngineOptions.cs b/src/Rules.Framework/IRulesEngineOptions.cs index 4386deaa..dd03a1af 100644 --- a/src/Rules.Framework/IRulesEngineOptions.cs +++ b/src/Rules.Framework/IRulesEngineOptions.cs @@ -20,12 +20,6 @@ public interface IRulesEngineOptions /// public MissingConditionBehaviors MissingConditionBehavior { get; } - /// - /// Gets the priority criteria to untie when multiples rules are matched. - /// - [Obsolete("This property has a typo and has been replaced by PriorityCriteria.")] - public PriorityCriterias PriotityCriteria { get; } - /// /// Gets the priority criteria to untie when multiples rules are matched. /// diff --git a/src/Rules.Framework/RulesEngineOptions.cs b/src/Rules.Framework/RulesEngineOptions.cs index f812c667..caa0d78a 100644 --- a/src/Rules.Framework/RulesEngineOptions.cs +++ b/src/Rules.Framework/RulesEngineOptions.cs @@ -41,16 +41,6 @@ private RulesEngineOptions() /// public PriorityCriterias PriorityCriteria { get; set; } - /// - /// Gets or sets the priority criteria to untie when multiples rules are matched. - /// - [Obsolete("This property has a typo and has been replaced by PriorityCriteria.")] - public PriorityCriterias PriotityCriteria - { - get { return this.PriorityCriteria; } - set { this.PriorityCriteria = value; } - } - /// /// Creates a new set of rules engine options with framework-configured defaults. /// @@ -82,7 +72,6 @@ public static RulesEngineOptions NewWithDefaults() }, }; - return rulesEngineOptions; } } diff --git a/tests/Rules.Framework.Providers.MongoDb.IntegrationTests/Scenarios/Scenario3/BuildingSecuritySystemControlTests.cs b/tests/Rules.Framework.Providers.MongoDb.IntegrationTests/Scenarios/Scenario3/BuildingSecuritySystemControlTests.cs index a9d151c9..8c6d6fec 100644 --- a/tests/Rules.Framework.Providers.MongoDb.IntegrationTests/Scenarios/Scenario3/BuildingSecuritySystemControlTests.cs +++ b/tests/Rules.Framework.Providers.MongoDb.IntegrationTests/Scenarios/Scenario3/BuildingSecuritySystemControlTests.cs @@ -92,11 +92,7 @@ public async Task BuildingSecuritySystem_FireScenario_ReturnsActionsToTrigger(bo ActionId = new Guid("ef0d65ae-ec76-492a-84db-5cb9090c3eaa"), ActionName = "ActivateVentilationSystem" }) - .WithCondition(b => b.AsValued(SecuritySystemConditions.SmokeRate) - .OfDataType() - .WithComparisonOperator(Core.Operators.GreaterThanOrEqual) - .SetOperand(30.0m) - .Build()) + .WithCondition(b => b.Value(SecuritySystemConditions.SmokeRate, Core.Operators.GreaterThanOrEqual, 30.0m)) .Build(); var newRule = newRuleResult.Rule; From b0de99acc62c1ed283aa15ab69910a1688ff1fff Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Tue, 6 Aug 2024 12:37:37 +0100 Subject: [PATCH 2/6] chore(deps): bump System.Text.Json in /src/Rules.Framework.WebUI (#168) Bumps System.Text.Json from 6.0.6 to 8.0.4. --- updated-dependencies: - dependency-name: System.Text.Json dependency-type: direct:production ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- src/Rules.Framework.WebUI/Rules.Framework.WebUI.csproj | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Rules.Framework.WebUI/Rules.Framework.WebUI.csproj b/src/Rules.Framework.WebUI/Rules.Framework.WebUI.csproj index 50e7336a..adc3426e 100644 --- a/src/Rules.Framework.WebUI/Rules.Framework.WebUI.csproj +++ b/src/Rules.Framework.WebUI/Rules.Framework.WebUI.csproj @@ -69,7 +69,7 @@ - + From c9213a048be0adc697e8491c330f263622aaf4c1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Lu=C3=ADs=20Garc=C3=AAs?= Date: Tue, 24 Sep 2024 15:26:19 +0100 Subject: [PATCH 3/6] feat: create non generic rules engine (#169) * refactor!: create non-generic rules engine * chore: change var style rules for C# * feat!: add APIs to create content types * chore: resolve codacy code analysis issues * chore: resolve codacy code analysis issues #2 --- .editorconfig | 7 +- .../Engine/IContentTypes.cs | 3 + .../Engine/RuleSpecification.cs | 2 +- .../Engine/RulesBuilder.cs | 7 +- .../Engine/RulesEngineProvider.cs | 10 +- .../Engine/RulesService.cs | 1 + .../Rules/TestNumberRules.cs | 17 +- .../Engine/IContentTypes.cs | 3 + .../Engine/RuleSpecification.cs | 2 +- .../Engine/RuleSpecificationBase.cs | 2 +- .../Engine/RulesBuilder.cs | 10 +- .../Engine/RulesEngineProvider.cs | 9 +- .../Rules.Framework.WebUI.Sample/Program.cs | 5 +- .../ReadmeExample/BasicRulesEngineExample.cs | 15 +- .../Rules/RulesRandomFactory.cs | 18 +- .../DataModel/ConditionNodeDataModel.cs | 2 +- .../DataModel/ContentTypeDataModel.cs | 17 + .../DataModel/ValueConditionNodeDataModel.cs | 2 +- .../IRuleFactory.cs | 7 +- .../MongoDbProviderRulesDataSource.cs | 77 +- .../MongoDbProviderSettings.cs | 24 +- ...ongoDbRulesDataSourceSelectorExtensions.cs | 12 +- .../RuleFactory.cs | 56 +- ...oStrongTypeContentSerializationProvider.cs | 9 +- .../Extensions/RuleDtoExtensions.cs | 18 +- .../Handlers/GetConfigurationsHandler.cs | 26 +- .../Handlers/GetContentTypeHandler.cs | 23 +- .../Handlers/GetRulesHandler.cs | 22 +- .../WebUIApplicationBuilderExtensions.cs | 11 +- .../Builder/ConditionNodeFactory.cs | 48 +- .../Builder/ConfiguredRulesEngineBuilder.cs | 34 +- .../FluentComposedConditionNodeBuilder.cs | 32 +- .../FluentComposedConditionNodeBuilder.cs | 62 ++ .../IFluentComposedConditionNodeBuilder.cs | 50 ++ .../Generic/IRootConditionNodeBuilder.cs | 45 ++ .../Builder/Generic/IRuleBuilder.cs | 96 +++ .../Generic/RootConditionNodeBuilder.cs | 33 + .../Builder/Generic/RuleBuilder.cs | 112 +++ .../Builder/Generic/RuleBuilderResult.cs | 62 ++ .../Builder/IConditionTypeSelector.cs | 16 - .../Builder/IConfiguredRulesEngineBuilder.cs | 15 +- .../Builder/IContentTypeSelector.cs | 15 - .../IFluentComposedConditionNodeBuilder.cs | 19 +- .../Builder/IRootConditionNodeBuilder.cs | 17 +- src/Rules.Framework/Builder/IRuleBuilder.cs | 31 +- .../Builder/IRulesDataSourceSelector.cs | 10 +- .../Builder/RootConditionNodeBuilder.cs | 22 +- src/Rules.Framework/Builder/RuleBuilder.cs | 62 +- .../Builder/RuleBuilderResult.cs | 68 +- .../Builder/RuleBuilderResultBase.cs | 33 + .../Builder/RulesEngineOptionsValidator.cs | 2 +- .../Builder/RulesEngineSelectors.cs | 17 +- .../ComposedConditionNodeValidator.cs | 14 +- .../Validation/ConditionNodeValidationArgs.cs | 6 +- .../ConditionNodeValidationExtensions.cs | 35 +- .../GenericComposedConditionNodeValidator.cs | 25 + .../GenericConditionNodeValidationArgs.cs | 11 + .../Validation/GenericRuleValidator.cs | 36 + .../GenericValueConditionNodeValidator.cs | 16 + .../Builder/Validation/RuleValidator.cs | 27 +- .../Validation/ValueConditionNodeValidator.cs | 11 +- .../ConditionNodes/ComposedConditionNode.cs | 22 +- .../ConditionNodes/IValueConditionNode.cs | 30 + .../ConditionNodes/ValueConditionNode.cs | 26 +- src/Rules.Framework/ConditionTypeExtractor.cs | 21 +- .../{Core => }/ContentContainer.cs | 20 +- .../{Core => }/ContentTypeException.cs | 2 +- .../Core/PropertiesDictionary.cs | 1 + src/Rules.Framework/Core/TypesCache.cs | 9 + src/Rules.Framework/{Core => }/DataTypes.cs | 2 +- .../BuildValueConditionNodeExpressionArgs.cs | 2 +- .../CompilationRulesSourceMiddleware.cs | 40 +- .../Compiled/CompiledConditionsEvalEngine.cs | 13 +- ...sWithOneToOneConditionExpressionBuilder.cs | 2 +- ...sWithOneToOneConditionExpressionBuilder.cs | 2 +- .../ConditionExpressionBuilderProvider.cs | 2 +- ...ainsManyToOneConditionExpressionBuilder.cs | 2 +- ...tainsOneToOneConditionExpressionBuilder.cs | 2 +- ...sWithOneToOneConditionExpressionBuilder.cs | 2 +- ...rThanOneToOneConditionExpressionBuilder.cs | 2 +- ...EqualOneToOneConditionExpressionBuilder.cs | 2 +- .../IConditionExpressionBuilderProvider.cs | 2 +- ...rThanOneToOneConditionExpressionBuilder.cs | 2 +- ...EqualOneToOneConditionExpressionBuilder.cs | 2 +- ...tainsOneToOneConditionExpressionBuilder.cs | 2 +- ...sWithOneToOneConditionExpressionBuilder.cs | 2 +- ...sWithOneToOneConditionExpressionBuilder.cs | 2 +- ...sWithOneToOneConditionExpressionBuilder.cs | 2 +- .../ConditionsValueLookupExtension.cs | 2 +- .../Evaluation/Compiled/EvaluationContext.cs | 6 +- .../IRuleConditionsExpressionBuilder.cs | 5 +- .../RuleConditionsExpressionBuilder.cs | 29 +- .../Evaluation/ConditionsTreeAnalyzer.cs | 15 +- .../Evaluation/DataTypeConfiguration.cs | 2 +- .../DataTypesConfigurationProvider.cs | 2 +- .../Evaluation/IConditionsEvalEngine.cs | 4 +- .../Evaluation/IConditionsTreeAnalyzer.cs | 5 +- .../IDataTypesConfigurationProvider.cs | 2 +- .../Evaluation/IMultiplicityEvaluator.cs | 2 +- .../Evaluation/Interpreted/DeferredEval.cs | 6 +- .../Evaluation/Interpreted/IDeferredEval.cs | 4 +- .../InterpretedConditionsEvalEngine.cs | 28 +- .../ConditionEvalDispatchProvider.cs | 2 +- .../ConditionEvalDispatcherBase.cs | 2 +- .../IConditionEvalDispatchProvider.cs | 2 +- .../Dispatchers/IConditionEvalDispatcher.cs | 2 +- .../ManyToManyConditionEvalDispatcher.cs | 2 +- .../ManyToOneConditionEvalDispatcher.cs | 2 +- .../OneToManyConditionEvalDispatcher.cs | 2 +- .../OneToOneConditionEvalDispatcher.cs | 2 +- .../IOperatorEvalStrategyFactory.cs | 2 +- .../OperatorEvalStrategyFactory.cs | 2 +- .../Evaluation/MultiplicityEvaluator.cs | 2 +- .../Evaluation/OperatorMetadata.cs | 2 +- .../Evaluation/OperatorsMetadata.cs | 2 +- .../Extensions/GenericRuleExtensions.cs | 57 -- .../Extensions/GenericSearchArgsExtensions.cs | 45 -- .../Extensions/RulesEngineExtensions.cs | 8 +- .../ConditionNodes/ComposedConditionNode.cs | 84 ++ .../ConditionNodes/IValueConditionNode.cs | 7 +- .../ConditionNodes/ValueConditionNode.cs | 88 +++ .../Generic/GenericConversions.cs | 31 + .../{Core => Generic}/IConditionNode.cs | 3 +- src/Rules.Framework/Generic/IRulesEngine.cs | 145 ++++ src/Rules.Framework/Generic/Rule.cs | 104 +++ src/Rules.Framework/Generic/RuleExtensions.cs | 25 + src/Rules.Framework/Generic/RulesEngine.cs | 154 ++++ .../Generics/GenericComposedConditionNode.cs | 16 - .../Generics/GenericConditionNode.cs | 15 - .../Generics/GenericConditionType.cs | 31 - .../Generics/GenericContentType.cs | 31 - src/Rules.Framework/Generics/GenericRule.cs | 45 -- .../Generics/GenericRulesEngine.cs | 48 -- .../Generics/GenericValueConditionNode.cs | 30 - .../Generics/IGenericRulesEngine.cs | 33 - src/Rules.Framework/IConditionNode.cs | 26 + .../IConditionTypeExtractor.cs | 8 +- src/Rules.Framework/IRulesDataSource.cs | 31 +- src/Rules.Framework/IRulesEngine.cs | 138 +++- src/Rules.Framework/IRulesEngineOptions.cs | 13 +- .../{Core => }/LogicalOperators.cs | 2 +- .../Management/IManagementOperation.cs | 4 +- .../Management/ManagementOperations.cs | 14 +- .../ManagementOperationsController.cs | 49 +- .../Operations/AddRuleManagementOperation.cs | 18 +- ...ilterPrioritiesRangeManagementOperation.cs | 8 +- .../MovePriorityManagementOperation.cs | 6 +- .../SetRuleForUpdateManagementOperation.cs | 10 +- .../UpdateRulesManagementOperation.cs | 13 +- src/Rules.Framework/OperationResult.cs | 49 ++ src/Rules.Framework/{Core => }/Operators.cs | 2 +- .../ComposedConditionNodeDataModel.cs | 4 +- .../DataModel/ConditionNodeDataModel.cs | 4 +- .../InMemory/DataModel/RuleDataModel.cs | 8 +- .../DataModel/ValueConditionNodeDataModel.cs | 6 +- .../InMemory/IInMemoryRulesStorage.cs | 14 +- .../Providers/InMemory/IRuleFactory.cs | 7 +- .../InMemoryProviderRulesDataSource.cs | 71 +- ...oviderRulesDataSourceSelectorExtensions.cs | 28 +- .../InMemory/InMemoryRulesStorage.cs | 34 +- .../Providers/InMemory/RuleFactory.cs | 50 +- .../InMemory/ServiceCollectionExtensions.cs | 10 +- src/Rules.Framework/{Core => }/Rule.cs | 44 +- src/Rules.Framework/RuleBuilder.cs | 19 - src/Rules.Framework/RuleOperationResult.cs | 51 -- src/Rules.Framework/RulesEngine.cs | 288 ++++--- src/Rules.Framework/RulesEngineBuilder.cs | 4 +- src/Rules.Framework/RulesEngineOptions.cs | 32 +- src/Rules.Framework/RulesFilterArgs.cs | 17 +- .../IContentSerializationProvider.cs | 10 +- .../SerializedContentContainer.cs | 16 +- src/Rules.Framework/Source/AddRuleArgs.cs | 6 +- src/Rules.Framework/Source/AddRuleDelegate.cs | 5 +- .../Source/CreateContentTypeArgs.cs | 7 + .../Source/CreateContentTypeDelegate.cs | 6 + .../Source/GetContentTypesArgs.cs | 6 + .../Source/GetContentTypesDelegate.cs | 7 + src/Rules.Framework/Source/GetRulesArgs.cs | 6 +- .../Source/GetRulesDelegate.cs | 6 +- .../Source/GetRulesFilteredArgs.cs | 4 +- .../Source/GetRulesFilteredDelegate.cs | 6 +- src/Rules.Framework/Source/IRulesSource.cs | 17 +- .../Source/IRulesSourceMiddleware.cs | 33 +- src/Rules.Framework/Source/RulesSource.cs | 123 ++- src/Rules.Framework/Source/UpdateRuleArgs.cs | 6 +- .../Source/UpdateRuleDelegate.cs | 5 +- .../Rules.Framework.BenchmarkTests/Program.cs | 2 +- .../Rules.Framework.BenchmarkTests.csproj | 4 +- .../Tests/Benchmark1/Benchmark1.cs | 17 +- .../Tests/Benchmark2/Benchmark2.cs | 17 +- .../Tests/Benchmark3/Benchmark3.cs | 17 +- .../Tests/Extensions.cs | 5 +- .../Features/RuleSpecification.cs | 5 +- .../Scenarios/IScenarioData.cs | 2 +- ...work-tests.body-mass-index.datasource.json | 18 +- ...framework-tests.car-insurance-advisor.json | 162 ++-- ...ork-tests.security-system-actionables.json | 266 +++---- .../Scenarios/Scenario6/Scenario6Data.cs | 5 +- .../Scenarios/Scenario7/Scenario7Data.cs | 6 +- .../Scenario8/Scenario8Data.Flush.cs | 12 +- .../Scenario8/Scenario8Data.FourOfAKind.cs | 30 +- .../Scenario8/Scenario8Data.HighCard.cs | 30 +- .../Scenarios/Scenario8/Scenario8Data.Pair.cs | 30 +- .../Scenario8/Scenario8Data.RoyalFlush.cs | 11 +- .../Scenario8/Scenario8Data.Straight.cs | 19 +- .../Scenario8/Scenario8Data.StraightFlush.cs | 68 +- .../Scenario8/Scenario8Data.ThreeOfAKind.cs | 30 +- .../Scenarios/Scenario8/Scenario8Data.cs | 2 +- .../Scenarios/ScenarioLoader.cs | 8 +- .../DataSource/RuleDataModel.cs | 4 +- .../JsonContentSerializationProvider.cs | 4 +- .../RulesFromJsonFile.cs | 22 +- .../Scenarios/Scenario1/BodyMassIndexTests.cs | 81 +- .../Scenario2/CarInsuranceAdvisorTests.cs | 78 +- .../BuildingSecuritySystemControlTests.cs | 27 +- .../Scenario4/DiscountCampaignTests.cs | 83 +- .../Scenarios/Scenario5/BestServerTests.cs | 45 +- ...TexasHoldEmPokerSingleCombinationsTests.cs | 5 +- .../RulesEngine/RulesEngineTestsBase.cs | 24 +- .../OperatorContainsManyToOneTests.cs | 7 +- .../RulesDeactivateAndActivateTests.cs | 9 +- .../RulesMatching/RulesInSequenceTests.cs | 10 +- .../RulesMatching/RulesUpdateDateEndTests.cs | 9 +- .../Scenarios/BaseScenarioTests.cs | 33 +- .../Scenario2/CarInsuranceAdvisorTests.cs | 43 +- .../BuildingSecuritySystemControlTests.cs | 40 +- .../Scenarios/Scenario5/BestServerTests.cs | 21 +- .../RulesEngine/RulesEngineTestsBase.cs | 17 +- .../RulesDeactivateAndActivateTests.cs | 10 +- .../RulesMatching/RulesInSequenceTests.cs | 15 +- .../RulesMatching/RulesUpdateDateEndTests.cs | 14 +- .../Scenario2/CarInsuranceAdvisorTests.cs | 78 +- .../BuildingSecuritySystemControlTests.cs | 53 +- .../Scenarios/Scenario5/BestServerTests.cs | 26 +- .../MongoDbProviderRulesDataSourceTests.cs | 126 ++- .../RuleFactoryTests.cs | 58 +- ...ngTypeContentSerializationProviderTests.cs | 5 +- .../ConfiguredRulesEngineBuilderTests.cs | 13 +- .../Builder/RuleBuilderResultTests.cs | 14 +- .../Builder/RuleBuilderTests.cs | 41 +- .../RuleEngineOptionsValidatorTests.cs | 2 +- .../Builder/SelectorsTests.cs | 36 +- .../ComposedConditionNodeTests.cs | 23 +- .../ConditionNodes/ValueConditionNodeTests.cs | 238 ++++++ .../ConditionTypeExtractorTests.cs | 82 +- .../{Core => }/ContentContainerTests.cs | 26 +- .../BooleanConditionNodeTests.cs | 68 -- .../DecimalConditionNodeTests.cs | 68 -- .../IntegerConditionNodeTests.cs | 68 -- .../StringConditionNodeTests.cs | 68 -- .../CompilationRulesSourceMiddlewareTests.cs | 301 ++++---- .../CompiledConditionsEvalEngineTests.cs | 47 +- ...OneToOneConditionExpressionBuilderTests.cs | 2 +- ...OneToOneConditionExpressionBuilderTests.cs | 2 +- ...ConditionExpressionBuilderProviderTests.cs | 2 +- ...anyToOneConditionExpressionBuilderTests.cs | 2 +- ...OneToOneConditionExpressionBuilderTests.cs | 2 +- ...OneToOneConditionExpressionBuilderTests.cs | 2 +- ...OneToOneConditionExpressionBuilderTests.cs | 2 +- ...OneToOneConditionExpressionBuilderTests.cs | 2 +- ...OneToOneConditionExpressionBuilderTests.cs | 2 +- ...neToManyConditionExpressionBuilderTests.cs | 2 +- ...OneToOneConditionExpressionBuilderTests.cs | 2 +- ...OneToOneConditionExpressionBuilderTests.cs | 2 +- ...OneToOneConditionExpressionBuilderTests.cs | 2 +- ...OneToOneConditionExpressionBuilderTests.cs | 2 +- ...OneToOneConditionExpressionBuilderTests.cs | 2 +- ...neToManyConditionExpressionBuilderTests.cs | 2 +- ...OneToOneConditionExpressionBuilderTests.cs | 2 +- ...OneToOneConditionExpressionBuilderTests.cs | 2 +- .../ConditionsValueLookupExtensionTests.cs | 10 +- ...alueConditionNodeExpressionBuilderTests.cs | 2 +- ...alueConditionNodeExpressionBuilderTests.cs | 2 +- ...alueConditionNodeExpressionBuilderTests.cs | 2 +- ...alueConditionNodeExpressionBuilderTests.cs | 2 +- ...ionsExpressionBuilderTests.GoldenFile1.csx | 8 +- ...ionsExpressionBuilderTests.GoldenFile2.csx | 8 +- .../RuleConditionsExpressionBuilderTests.cs | 110 +-- .../Evaluation/ConditionsTreeAnalyzerTests.cs | 56 +- .../Evaluation/DataTypeConfigurationTests.cs | 2 +- .../DataTypesConfigurationProviderTests.cs | 2 +- .../Interpreted/DeferredEvalTests.cs | 42 +- .../InterpretedConditionsEvalEngineTests.cs | 88 +-- .../ManyToManyConditionEvalDispatcherTests.cs | 2 +- .../ManyToOneConditionEvalDispatcherTests.cs | 2 +- .../OneToManyConditionEvalDispatcherTests.cs | 2 +- .../OneToOneConditionEvalDispatcherTests.cs | 2 +- .../OperatorEvalStrategyFactoryTests.cs | 2 +- .../Evaluation/MultiplicityEvaluatorTests.cs | 2 +- .../Evaluation/OperatorMetadataTests.cs | 2 +- .../Evaluation/StubConditionNode.cs | 6 +- .../Extensions/GenericRuleExtensionsTests.cs | 115 +-- .../GenericSearchArgsExtensionsTests.cs | 91 --- .../Extensions/RulesEngineExtensionsTests.cs | 22 +- .../Generic/RulesEngineTests.cs | 196 +++++ .../Generics/GenericRulesEngineTests.cs | 146 ---- ...rRulesDataSourceSelectorExtensionsTests.cs | 29 +- .../InMemoryProviderRulesDataSourceTests.cs | 60 +- .../Providers/InMemory/RuleFactoryTests.cs | 63 +- .../ServiceCollectionExtensionsTests.cs | 3 +- .../RuleOperationResultTests.cs | 10 +- .../{Core => }/RuleTests.cs | 36 +- .../Rules.Framework.Tests/RulesEngineTests.cs | 721 +++++++++++------- .../SerializedContentContainerTests.cs | 14 +- .../Source/RulesSourceTests.cs | 414 +++++++--- .../Source/StubRulesSourceMiddleware.cs | 63 +- .../Extensions/RuleDtoExtensionsTests.cs | 10 +- .../Handlers/GetConfigurationsHandlerTests.cs | 20 +- .../Handlers/GetContentTypeHandlerTests.cs | 15 +- .../Handlers/GetRulesHandlerTests.cs | 25 +- 310 files changed, 5481 insertions(+), 3976 deletions(-) create mode 100644 src/Rules.Framework.Providers.MongoDb/DataModel/ContentTypeDataModel.cs create mode 100644 src/Rules.Framework/Builder/Generic/FluentComposedConditionNodeBuilder.cs create mode 100644 src/Rules.Framework/Builder/Generic/IFluentComposedConditionNodeBuilder.cs create mode 100644 src/Rules.Framework/Builder/Generic/IRootConditionNodeBuilder.cs create mode 100644 src/Rules.Framework/Builder/Generic/IRuleBuilder.cs create mode 100644 src/Rules.Framework/Builder/Generic/RootConditionNodeBuilder.cs create mode 100644 src/Rules.Framework/Builder/Generic/RuleBuilder.cs create mode 100644 src/Rules.Framework/Builder/Generic/RuleBuilderResult.cs delete mode 100644 src/Rules.Framework/Builder/IConditionTypeSelector.cs delete mode 100644 src/Rules.Framework/Builder/IContentTypeSelector.cs create mode 100644 src/Rules.Framework/Builder/RuleBuilderResultBase.cs create mode 100644 src/Rules.Framework/Builder/Validation/GenericComposedConditionNodeValidator.cs create mode 100644 src/Rules.Framework/Builder/Validation/GenericConditionNodeValidationArgs.cs create mode 100644 src/Rules.Framework/Builder/Validation/GenericRuleValidator.cs create mode 100644 src/Rules.Framework/Builder/Validation/GenericValueConditionNodeValidator.cs rename src/Rules.Framework/{Core => }/ConditionNodes/ComposedConditionNode.cs (77%) create mode 100644 src/Rules.Framework/ConditionNodes/IValueConditionNode.cs rename src/Rules.Framework/{Core => }/ConditionNodes/ValueConditionNode.cs (73%) rename src/Rules.Framework/{Core => }/ContentContainer.cs (61%) rename src/Rules.Framework/{Core => }/ContentTypeException.cs (97%) create mode 100644 src/Rules.Framework/Core/TypesCache.cs rename src/Rules.Framework/{Core => }/DataTypes.cs (97%) delete mode 100644 src/Rules.Framework/Extensions/GenericRuleExtensions.cs delete mode 100644 src/Rules.Framework/Extensions/GenericSearchArgsExtensions.cs create mode 100644 src/Rules.Framework/Generic/ConditionNodes/ComposedConditionNode.cs rename src/Rules.Framework/{Core => Generic}/ConditionNodes/IValueConditionNode.cs (85%) create mode 100644 src/Rules.Framework/Generic/ConditionNodes/ValueConditionNode.cs create mode 100644 src/Rules.Framework/Generic/GenericConversions.cs rename src/Rules.Framework/{Core => Generic}/IConditionNode.cs (93%) create mode 100644 src/Rules.Framework/Generic/IRulesEngine.cs create mode 100644 src/Rules.Framework/Generic/Rule.cs create mode 100644 src/Rules.Framework/Generic/RuleExtensions.cs create mode 100644 src/Rules.Framework/Generic/RulesEngine.cs delete mode 100644 src/Rules.Framework/Generics/GenericComposedConditionNode.cs delete mode 100644 src/Rules.Framework/Generics/GenericConditionNode.cs delete mode 100644 src/Rules.Framework/Generics/GenericConditionType.cs delete mode 100644 src/Rules.Framework/Generics/GenericContentType.cs delete mode 100644 src/Rules.Framework/Generics/GenericRule.cs delete mode 100644 src/Rules.Framework/Generics/GenericRulesEngine.cs delete mode 100644 src/Rules.Framework/Generics/GenericValueConditionNode.cs delete mode 100644 src/Rules.Framework/Generics/IGenericRulesEngine.cs create mode 100644 src/Rules.Framework/IConditionNode.cs rename src/Rules.Framework/{Core => }/LogicalOperators.cs (94%) create mode 100644 src/Rules.Framework/OperationResult.cs rename src/Rules.Framework/{Core => }/Operators.cs (98%) rename src/Rules.Framework/{Core => }/Rule.cs (56%) delete mode 100644 src/Rules.Framework/RuleBuilder.cs delete mode 100644 src/Rules.Framework/RuleOperationResult.cs create mode 100644 src/Rules.Framework/Source/CreateContentTypeArgs.cs create mode 100644 src/Rules.Framework/Source/CreateContentTypeDelegate.cs create mode 100644 src/Rules.Framework/Source/GetContentTypesArgs.cs create mode 100644 src/Rules.Framework/Source/GetContentTypesDelegate.cs rename tests/Rules.Framework.Tests/{Core => }/ConditionNodes/ComposedConditionNodeTests.cs (70%) create mode 100644 tests/Rules.Framework.Tests/ConditionNodes/ValueConditionNodeTests.cs rename tests/Rules.Framework.Tests/{Core => }/ContentContainerTests.cs (55%) delete mode 100644 tests/Rules.Framework.Tests/Core/ConditionNodes/BooleanConditionNodeTests.cs delete mode 100644 tests/Rules.Framework.Tests/Core/ConditionNodes/DecimalConditionNodeTests.cs delete mode 100644 tests/Rules.Framework.Tests/Core/ConditionNodes/IntegerConditionNodeTests.cs delete mode 100644 tests/Rules.Framework.Tests/Core/ConditionNodes/StringConditionNodeTests.cs delete mode 100644 tests/Rules.Framework.Tests/Extensions/GenericSearchArgsExtensionsTests.cs create mode 100644 tests/Rules.Framework.Tests/Generic/RulesEngineTests.cs delete mode 100644 tests/Rules.Framework.Tests/Generics/GenericRulesEngineTests.cs rename tests/Rules.Framework.Tests/{Core => }/RuleTests.cs (74%) diff --git a/.editorconfig b/.editorconfig index e122fba1..4b268ac5 100644 --- a/.editorconfig +++ b/.editorconfig @@ -66,9 +66,9 @@ dotnet_code_quality_unused_parameters = all:suggestion #### C# Coding Conventions #### # var preferences -csharp_style_var_elsewhere = false:silent -csharp_style_var_for_built_in_types = false:silent -csharp_style_var_when_type_is_apparent = false:silent +csharp_style_var_elsewhere = true:silent +csharp_style_var_for_built_in_types = true:silent +csharp_style_var_when_type_is_apparent = true:silent # Expression-bodied members csharp_style_expression_bodied_accessors = true:silent @@ -231,6 +231,7 @@ dotnet_style_namespace_match_folder = true:suggestion csharp_style_prefer_switch_expression = true:suggestion csharp_style_prefer_pattern_matching = true:silent csharp_style_prefer_not_pattern = true:suggestion +csharp_style_prefer_primary_constructors = true:suggestion [*.vb] visual_basic_preferred_modifier_order = Partial,Default,Private,Protected,Public,Friend,NotOverridable,Overridable,MustOverride,Overloads,Overrides,MustInherit,NotInheritable,Static,Shared,Shadows,ReadOnly,WriteOnly,Dim,Const,WithEvents,Widening,Narrowing,Custom,Async:suggestion:suggestion diff --git a/samples/Rules.Framework.InMemory.Sample/Engine/IContentTypes.cs b/samples/Rules.Framework.InMemory.Sample/Engine/IContentTypes.cs index 9c852cef..4983e7ea 100644 --- a/samples/Rules.Framework.InMemory.Sample/Engine/IContentTypes.cs +++ b/samples/Rules.Framework.InMemory.Sample/Engine/IContentTypes.cs @@ -1,9 +1,12 @@ namespace Rules.Framework.InMemory.Sample.Engine { using System.Collections.Generic; + using global::Rules.Framework.InMemory.Sample.Enums; internal interface IContentTypes { + ContentTypes ContentType { get; } + IEnumerable GetRulesSpecifications(); } } \ No newline at end of file diff --git a/samples/Rules.Framework.InMemory.Sample/Engine/RuleSpecification.cs b/samples/Rules.Framework.InMemory.Sample/Engine/RuleSpecification.cs index 4799dc03..5bae5f93 100644 --- a/samples/Rules.Framework.InMemory.Sample/Engine/RuleSpecification.cs +++ b/samples/Rules.Framework.InMemory.Sample/Engine/RuleSpecification.cs @@ -1,7 +1,7 @@ namespace Rules.Framework.InMemory.Sample.Engine { using global::Rules.Framework; - using global::Rules.Framework.Builder; + using global::Rules.Framework.Builder.Generic; using global::Rules.Framework.InMemory.Sample.Enums; internal class RuleSpecification diff --git a/samples/Rules.Framework.InMemory.Sample/Engine/RulesBuilder.cs b/samples/Rules.Framework.InMemory.Sample/Engine/RulesBuilder.cs index 7941ff07..82d8bca7 100644 --- a/samples/Rules.Framework.InMemory.Sample/Engine/RulesBuilder.cs +++ b/samples/Rules.Framework.InMemory.Sample/Engine/RulesBuilder.cs @@ -2,7 +2,6 @@ namespace Rules.Framework.InMemory.Sample.Engine { using System.Collections.Generic; using System.Threading.Tasks; - using global::Rules.Framework.InMemory.Sample.Enums; using global::Rules.Framework.InMemory.Sample.Exceptions; internal class RulesBuilder @@ -11,10 +10,12 @@ internal class RulesBuilder public RulesBuilder(IEnumerable contentTypes) => this.contentTypes = contentTypes; - public async Task BuildAsync(RulesEngine rulesEngine) + public async Task BuildAsync(IRulesEngine rulesEngine) { foreach (var contentType in contentTypes) { + await rulesEngine.CreateContentTypeAsync(contentType.ContentType.ToString()); + var rulesSpecifications = contentType.GetRulesSpecifications(); foreach (var ruleSpecification in rulesSpecifications) @@ -28,7 +29,7 @@ public async Task BuildAsync(RulesEngine rulesEngi .AddRuleAsync( ruleSpecification.RuleBuilderResult.Rule, ruleSpecification.RuleAddPriorityOption - ).ConfigureAwait(false); + ); if (!ruleOperationResult.IsSuccess) { diff --git a/samples/Rules.Framework.InMemory.Sample/Engine/RulesEngineProvider.cs b/samples/Rules.Framework.InMemory.Sample/Engine/RulesEngineProvider.cs index 949b4d08..f24a6f91 100644 --- a/samples/Rules.Framework.InMemory.Sample/Engine/RulesEngineProvider.cs +++ b/samples/Rules.Framework.InMemory.Sample/Engine/RulesEngineProvider.cs @@ -3,21 +3,17 @@ namespace Rules.Framework.InMemory.Sample.Engine using System; using System.Threading; using System.Threading.Tasks; - using global::Rules.Framework.InMemory.Sample.Enums; - using global::Rules.Framework.Providers.InMemory; internal class RulesEngineProvider { - private readonly Lazy>> lazyRulesEngine; + private readonly Lazy> lazyRulesEngine; public RulesEngineProvider(RulesBuilder rulesBuilder) { - lazyRulesEngine = new Lazy>>(async () => + lazyRulesEngine = new Lazy>(async () => { var rulesEngine = RulesEngineBuilder .CreateRulesEngine() - .WithContentType() - .WithConditionType() .SetInMemoryDataSource() .Configure(opt => opt.PriorityCriteria = PriorityCriterias.BottommostRuleWins) .Build(); @@ -28,7 +24,7 @@ public RulesEngineProvider(RulesBuilder rulesBuilder) }, LazyThreadSafetyMode.ExecutionAndPublication); } - public Task> GetRulesEngineAsync() + public Task GetRulesEngineAsync() => lazyRulesEngine.Value; } } \ No newline at end of file diff --git a/samples/Rules.Framework.InMemory.Sample/Engine/RulesService.cs b/samples/Rules.Framework.InMemory.Sample/Engine/RulesService.cs index 879e228f..f55db187 100644 --- a/samples/Rules.Framework.InMemory.Sample/Engine/RulesService.cs +++ b/samples/Rules.Framework.InMemory.Sample/Engine/RulesService.cs @@ -31,6 +31,7 @@ public async Task MatchOneAsync( .ConfigureAwait(false); var match = await rulesEngine + .MakeGeneric() .MatchOneAsync(contentType, dateTime, rulesConditions) .ConfigureAwait(false); diff --git a/samples/Rules.Framework.InMemory.Sample/Rules/TestNumberRules.cs b/samples/Rules.Framework.InMemory.Sample/Rules/TestNumberRules.cs index b4539520..5409f683 100644 --- a/samples/Rules.Framework.InMemory.Sample/Rules/TestNumberRules.cs +++ b/samples/Rules.Framework.InMemory.Sample/Rules/TestNumberRules.cs @@ -2,8 +2,7 @@ namespace Rules.Framework.InMemory.Sample.Rules { using System; using System.Collections.Generic; - using global::Rules.Framework.Builder; - using global::Rules.Framework.Core; + using global::Rules.Framework.Builder.Generic; using global::Rules.Framework.InMemory.Sample.Engine; using global::Rules.Framework.InMemory.Sample.Enums; @@ -16,6 +15,8 @@ public TestNumberRules() this.rulesSpecifications = new List(); } + public ContentTypes ContentType => ContentTypes.TestNumber; + public IEnumerable GetRulesSpecifications() { Add(CreateRuleForCoolNumbers(), RuleAddPriorityOption.ByPriorityNumber(3)); @@ -34,17 +35,13 @@ private void Add( RuleAddPriorityOption = ruleAddPriorityOption, }); - private RuleBuilderResult CreateDefaultRule() => - RuleBuilder - .NewRule() + private RuleBuilderResult CreateDefaultRule() => Rule.New() .WithName("Default rule for test number") .WithContent(ContentTypes.TestNumber, ":| default nothing special about this number") .WithDateBegin(new DateTime(2019, 01, 01)) .Build(); - private RuleBuilderResult CreateRuleForCoolNumbers() => - RuleBuilder - .NewRule() + private RuleBuilderResult CreateRuleForCoolNumbers() => Rule.New() .WithName("Rule for cool numbers") .WithContent(ContentTypes.TestNumber, ":D this number is so COOL!") .WithDateBegin(new DateTime(2019, 01, 01)) @@ -56,9 +53,7 @@ private RuleBuilderResult CreateRuleForCoolNumbers .Value(ConditionTypes.SumAll, Operators.StartsWith, "5")))) .Build(); - private RuleBuilderResult CreateRuleForSosoNumbers() => - RuleBuilder - .NewRule() + private RuleBuilderResult CreateRuleForSosoNumbers() => Rule.New() .WithName("Rule for so so numbers") .WithContent(ContentTypes.TestNumber, ":) this number is so so") .WithDateBegin(new DateTime(2019, 01, 01)) diff --git a/samples/Rules.Framework.WebUI.Sample/Engine/IContentTypes.cs b/samples/Rules.Framework.WebUI.Sample/Engine/IContentTypes.cs index 30fbfdf6..2d4f988f 100644 --- a/samples/Rules.Framework.WebUI.Sample/Engine/IContentTypes.cs +++ b/samples/Rules.Framework.WebUI.Sample/Engine/IContentTypes.cs @@ -1,9 +1,12 @@ namespace Rules.Framework.WebUI.Sample.Engine { using System.Collections.Generic; + using global::Rules.Framework.WebUI.Sample.Enums; internal interface IContentTypes { + ContentTypes[] ContentTypes { get; } + IEnumerable GetRulesSpecifications(); } } \ No newline at end of file diff --git a/samples/Rules.Framework.WebUI.Sample/Engine/RuleSpecification.cs b/samples/Rules.Framework.WebUI.Sample/Engine/RuleSpecification.cs index d912faf9..84749d4b 100644 --- a/samples/Rules.Framework.WebUI.Sample/Engine/RuleSpecification.cs +++ b/samples/Rules.Framework.WebUI.Sample/Engine/RuleSpecification.cs @@ -1,7 +1,7 @@ namespace Rules.Framework.WebUI.Sample.Engine { using global::Rules.Framework; - using global::Rules.Framework.Builder; + using global::Rules.Framework.Builder.Generic; using global::Rules.Framework.WebUI.Sample.Enums; internal sealed class RuleSpecification : RuleSpecificationBase diff --git a/samples/Rules.Framework.WebUI.Sample/Engine/RuleSpecificationBase.cs b/samples/Rules.Framework.WebUI.Sample/Engine/RuleSpecificationBase.cs index d8a0bbea..b0b408e5 100644 --- a/samples/Rules.Framework.WebUI.Sample/Engine/RuleSpecificationBase.cs +++ b/samples/Rules.Framework.WebUI.Sample/Engine/RuleSpecificationBase.cs @@ -1,7 +1,7 @@ namespace Rules.Framework.WebUI.Sample.Engine { using global::Rules.Framework; - using global::Rules.Framework.Builder; + using global::Rules.Framework.Builder.Generic; internal class RuleSpecificationBase { diff --git a/samples/Rules.Framework.WebUI.Sample/Engine/RulesBuilder.cs b/samples/Rules.Framework.WebUI.Sample/Engine/RulesBuilder.cs index 2ae3e7da..d0587bdd 100644 --- a/samples/Rules.Framework.WebUI.Sample/Engine/RulesBuilder.cs +++ b/samples/Rules.Framework.WebUI.Sample/Engine/RulesBuilder.cs @@ -2,7 +2,6 @@ namespace Rules.Framework.WebUI.Sample.Engine { using System.Collections.Generic; using System.Threading.Tasks; - using global::Rules.Framework.WebUI.Sample.Enums; using global::Rules.Framework.WebUI.Sample.Exceptions; internal class RulesBuilder @@ -11,10 +10,15 @@ internal class RulesBuilder public RulesBuilder(IEnumerable contentTypes) => this.contentTypes = contentTypes; - public async Task BuildAsync(RulesEngine rulesEngine) + public async Task BuildAsync(IRulesEngine rulesEngine) { foreach (var contentType in contentTypes) { + foreach (var contentTypeValue in contentType.ContentTypes) + { + await rulesEngine.CreateContentTypeAsync(contentTypeValue.ToString()); + } + var rulesSpecifications = contentType.GetRulesSpecifications(); foreach (var ruleSpecification in rulesSpecifications) @@ -28,7 +32,7 @@ public async Task BuildAsync(RulesEngine rulesEngi .AddRuleAsync( ruleSpecification.RuleBuilderResult.Rule, ruleSpecification.RuleAddPriorityOption - ).ConfigureAwait(false); + ); if (!ruleOperationResult.IsSuccess) { diff --git a/samples/Rules.Framework.WebUI.Sample/Engine/RulesEngineProvider.cs b/samples/Rules.Framework.WebUI.Sample/Engine/RulesEngineProvider.cs index 41b67f44..ac5c8a1c 100644 --- a/samples/Rules.Framework.WebUI.Sample/Engine/RulesEngineProvider.cs +++ b/samples/Rules.Framework.WebUI.Sample/Engine/RulesEngineProvider.cs @@ -3,20 +3,17 @@ namespace Rules.Framework.WebUI.Sample.Engine using System; using System.Threading; using System.Threading.Tasks; - using global::Rules.Framework.WebUI.Sample.Enums; internal class RulesEngineProvider { - private readonly Lazy>> lazyRulesEngine; + private readonly Lazy> lazyRulesEngine; public RulesEngineProvider(RulesBuilder rulesBuilder) { - lazyRulesEngine = new Lazy>>(async () => + lazyRulesEngine = new Lazy>(async () => { var rulesEngine = RulesEngineBuilder .CreateRulesEngine() - .WithContentType() - .WithConditionType() .SetInMemoryDataSource() .Configure(c => c.PriorityCriteria = PriorityCriterias.TopmostRuleWins) .Build(); @@ -27,7 +24,7 @@ public RulesEngineProvider(RulesBuilder rulesBuilder) }, LazyThreadSafetyMode.ExecutionAndPublication); } - public Task> GetRulesEngineAsync() + public Task GetRulesEngineAsync() => lazyRulesEngine.Value; } } \ No newline at end of file diff --git a/samples/Rules.Framework.WebUI.Sample/Program.cs b/samples/Rules.Framework.WebUI.Sample/Program.cs index a28f73c5..7ccd9f3d 100644 --- a/samples/Rules.Framework.WebUI.Sample/Program.cs +++ b/samples/Rules.Framework.WebUI.Sample/Program.cs @@ -1,6 +1,5 @@ namespace Rules.Framework.WebUI.Sample { - using global::Rules.Framework.Extension; using global::Rules.Framework.WebUI.Sample.Engine; using global::Rules.Framework.WebUI.Sample.ReadmeExample; using global::Rules.Framework.WebUI.Sample.Rules; @@ -46,7 +45,7 @@ private static void AddRulesFrameworkUI(IApplicationBuilder app, bool useReadmeE { if (useReadmeExample) { - app.UseRulesFrameworkWebUI(new BasicRulesEngineExample().RulesEngine.CreateGenericEngine()); + app.UseRulesFrameworkWebUI(new BasicRulesEngineExample().RulesEngine); return; } @@ -62,7 +61,7 @@ private static void AddRulesFrameworkUI(IApplicationBuilder app, bool useReadmeE .GetAwaiter() .GetResult(); - app.UseRulesFrameworkWebUI(rulesEngine.CreateGenericEngine()); + app.UseRulesFrameworkWebUI(rulesEngine); } } } \ No newline at end of file diff --git a/samples/Rules.Framework.WebUI.Sample/ReadmeExample/BasicRulesEngineExample.cs b/samples/Rules.Framework.WebUI.Sample/ReadmeExample/BasicRulesEngineExample.cs index 3d5ae365..47f0f912 100644 --- a/samples/Rules.Framework.WebUI.Sample/ReadmeExample/BasicRulesEngineExample.cs +++ b/samples/Rules.Framework.WebUI.Sample/ReadmeExample/BasicRulesEngineExample.cs @@ -1,8 +1,6 @@ namespace Rules.Framework.WebUI.Sample.ReadmeExample { using System; - using global::Rules.Framework.Core; - using global::Rules.Framework.Providers.InMemory; using global::Rules.Framework.WebUI.Sample.Engine; internal class BasicRulesEngineExample @@ -11,8 +9,6 @@ public BasicRulesEngineExample() { this.RulesEngine = RulesEngineBuilder .CreateRulesEngine() - .WithContentType() - .WithConditionType() .SetInMemoryDataSource() .Configure(c => c.PriorityCriteria = PriorityCriterias.TopmostRuleWins) .Build(); @@ -22,7 +18,7 @@ public BasicRulesEngineExample() this.AddRules(rules); } - public RulesEngine RulesEngine { get; } + public IRulesEngine RulesEngine { get; } protected void AddRules(IEnumerable> ruleSpecifications) { @@ -37,24 +33,21 @@ protected void AddRules(IEnumerable> CreateRules() { - var ruleForPremiumFreeSampleJanuary = RuleBuilder - .NewRule() + var ruleForPremiumFreeSampleJanuary = Rule.New() .WithName("Rule for January sample for premium clients.") .WithContent(BasicContentType.FreeSample, "SmallPerfumeSample") .WithCondition(BasicConditionType.ClientType, Operators.Equal, "Premium") .WithDatesInterval(new DateTime(2023, 01, 01), new DateTime(2023, 02, 01)) .Build(); - var ruleForPremiumFreeSampleApril = RuleBuilder - .NewRule() + var ruleForPremiumFreeSampleApril = Rule.New() .WithName("Rule for April sample for premium clients.") .WithContent(BasicContentType.FreeSample, "ShampooSample") .WithCondition(BasicConditionType.ClientType, Operators.Equal, "Premium") .WithDatesInterval(new DateTime(2023, 04, 01), new DateTime(2023, 05, 01)) .Build(); - var ruleForPremiumFreeSampleSeptember = RuleBuilder - .NewRule() + var ruleForPremiumFreeSampleSeptember = Rule.New() .WithName("Rule for September sample for premium clients.") .WithContent(BasicContentType.FreeSample, "ConditionerSample") .WithCondition(BasicConditionType.ClientType, Operators.Equal, "Premium") diff --git a/samples/Rules.Framework.WebUI.Sample/Rules/RulesRandomFactory.cs b/samples/Rules.Framework.WebUI.Sample/Rules/RulesRandomFactory.cs index 113cdaba..de6c24c0 100644 --- a/samples/Rules.Framework.WebUI.Sample/Rules/RulesRandomFactory.cs +++ b/samples/Rules.Framework.WebUI.Sample/Rules/RulesRandomFactory.cs @@ -2,8 +2,7 @@ namespace Rules.Framework.WebUI.Sample.Rules { using System; using System.Collections.Generic; - using global::Rules.Framework.Builder; - using global::Rules.Framework.Core; + using global::Rules.Framework.Builder.Generic; using global::Rules.Framework.WebUI.Sample.Engine; using global::Rules.Framework.WebUI.Sample.Enums; @@ -18,6 +17,18 @@ public RulesRandomFactory() this.random = new Random(); } + public ContentTypes[] ContentTypes => new[] + { + Enums.ContentTypes.TestDateTime, + Enums.ContentTypes.TestDecimal, + Enums.ContentTypes.TestLong, + Enums.ContentTypes.TestBoolean, + Enums.ContentTypes.TestShort, + Enums.ContentTypes.TestNumber, + Enums.ContentTypes.TestString, + Enums.ContentTypes.TestBlob, + }; + public IEnumerable GetRulesSpecifications() { var currentYear = DateTime.UtcNow.Year; @@ -49,8 +60,7 @@ private static RuleBuilderResult CreateMultipleRul int value, DateTime dateBegin, DateTime? dateEnd, - bool isActive = true) => RuleBuilder - .NewRule() + bool isActive = true) => Rule.New() .WithName($"Multi rule for test {contentTypes} {value}") .WithContent(contentTypes, new { Value = value }) .WithDatesInterval(dateBegin, dateEnd) diff --git a/src/Rules.Framework.Providers.MongoDb/DataModel/ConditionNodeDataModel.cs b/src/Rules.Framework.Providers.MongoDb/DataModel/ConditionNodeDataModel.cs index 858f353f..a35084d3 100644 --- a/src/Rules.Framework.Providers.MongoDb/DataModel/ConditionNodeDataModel.cs +++ b/src/Rules.Framework.Providers.MongoDb/DataModel/ConditionNodeDataModel.cs @@ -5,7 +5,7 @@ namespace Rules.Framework.Providers.MongoDb.DataModel using MongoDB.Bson; using MongoDB.Bson.Serialization.Attributes; using MongoDB.Bson.Serialization.Options; - using Rules.Framework.Core; + using Rules.Framework; [BsonKnownTypes(typeof(ComposedConditionNodeDataModel), typeof(ValueConditionNodeDataModel))] internal class ConditionNodeDataModel diff --git a/src/Rules.Framework.Providers.MongoDb/DataModel/ContentTypeDataModel.cs b/src/Rules.Framework.Providers.MongoDb/DataModel/ContentTypeDataModel.cs new file mode 100644 index 00000000..b185b3c6 --- /dev/null +++ b/src/Rules.Framework.Providers.MongoDb/DataModel/ContentTypeDataModel.cs @@ -0,0 +1,17 @@ +namespace Rules.Framework.Providers.MongoDb.DataModel +{ + using System; + using MongoDB.Bson.Serialization.Attributes; + + internal class ContentTypeDataModel + { + [BsonElement("creation", Order = 3)] + public DateTime Creation { get; set; } + + [BsonElement("id", Order = 1)] + public Guid Id { get; set; } + + [BsonElement("name", Order = 2)] + public string Name { get; set; } + } +} \ No newline at end of file diff --git a/src/Rules.Framework.Providers.MongoDb/DataModel/ValueConditionNodeDataModel.cs b/src/Rules.Framework.Providers.MongoDb/DataModel/ValueConditionNodeDataModel.cs index 6a4613a1..05853a12 100644 --- a/src/Rules.Framework.Providers.MongoDb/DataModel/ValueConditionNodeDataModel.cs +++ b/src/Rules.Framework.Providers.MongoDb/DataModel/ValueConditionNodeDataModel.cs @@ -1,7 +1,7 @@ namespace Rules.Framework.Providers.MongoDb.DataModel { using MongoDB.Bson.Serialization.Attributes; - using Rules.Framework.Core; + using Rules.Framework; [BsonDiscriminator("value")] internal sealed class ValueConditionNodeDataModel : ConditionNodeDataModel diff --git a/src/Rules.Framework.Providers.MongoDb/IRuleFactory.cs b/src/Rules.Framework.Providers.MongoDb/IRuleFactory.cs index 30ed89dc..ed43d3ee 100644 --- a/src/Rules.Framework.Providers.MongoDb/IRuleFactory.cs +++ b/src/Rules.Framework.Providers.MongoDb/IRuleFactory.cs @@ -1,12 +1,11 @@ namespace Rules.Framework.Providers.MongoDb { - using Rules.Framework.Core; using Rules.Framework.Providers.MongoDb.DataModel; - internal interface IRuleFactory + internal interface IRuleFactory { - Rule CreateRule(RuleDataModel ruleDataModel); + Rule CreateRule(RuleDataModel ruleDataModel); - RuleDataModel CreateRule(Rule rule); + RuleDataModel CreateRule(Rule rule); } } \ No newline at end of file diff --git a/src/Rules.Framework.Providers.MongoDb/MongoDbProviderRulesDataSource.cs b/src/Rules.Framework.Providers.MongoDb/MongoDbProviderRulesDataSource.cs index dd5893b5..f027618f 100644 --- a/src/Rules.Framework.Providers.MongoDb/MongoDbProviderRulesDataSource.cs +++ b/src/Rules.Framework.Providers.MongoDb/MongoDbProviderRulesDataSource.cs @@ -5,25 +5,22 @@ namespace Rules.Framework.Providers.MongoDb using System.Linq; using System.Threading.Tasks; using MongoDB.Driver; - using Rules.Framework.Core; using Rules.Framework.Providers.MongoDb.DataModel; /// /// The rules data source implementation for usage backed with a Mongo DB database. /// - /// The type of the content type. - /// The type of the condition type. - /// - public class MongoDbProviderRulesDataSource : IRulesDataSource + /// + public class MongoDbProviderRulesDataSource : IRulesDataSource { private readonly IMongoDatabase mongoDatabase; private readonly MongoDbProviderSettings mongoDbProviderSettings; - private readonly IRuleFactory ruleFactory; + private readonly IRuleFactory ruleFactory; internal MongoDbProviderRulesDataSource( IMongoClient mongoClient, MongoDbProviderSettings mongoDbProviderSettings, - IRuleFactory ruleFactory) + IRuleFactory ruleFactory) { if (mongoClient is null) { @@ -39,7 +36,7 @@ internal MongoDbProviderRulesDataSource( /// Adds a new rule to data source. /// /// The rule. - public async Task AddRuleAsync(Rule rule) + public async Task AddRuleAsync(Rule rule) { var rulesCollection = this.mongoDatabase.GetCollection(this.mongoDbProviderSettings.RulesCollectionName); @@ -48,6 +45,42 @@ public async Task AddRuleAsync(Rule rule) await rulesCollection.InsertOneAsync(ruleDataModel).ConfigureAwait(false); } + /// + /// Creates a new content type on the data source. + /// + /// Type of the content. + public async Task CreateContentTypeAsync(string contentType) + { + var contentTypesCollection = this.mongoDatabase.GetCollection(this.mongoDbProviderSettings.ContentTypesCollectionName); + + var contentTypeDataModel = new ContentTypeDataModel + { + Creation = DateTime.UtcNow, + Id = Guid.NewGuid(), + Name = contentType, + }; + + await contentTypesCollection.InsertOneAsync(contentTypeDataModel).ConfigureAwait(false); + } + + /// + /// Gets the content types from the data source. + /// + /// + public async Task> GetContentTypesAsync() + { + var contentTypesCollection = this.mongoDatabase.GetCollection(this.mongoDbProviderSettings.ContentTypesCollectionName); + + var findAllFilterDefinition = FilterDefinition.Empty; + var findOptions = new FindOptions + { + Projection = Builders.Projection.Expression(x => x.Name), + }; + + var resultsCursor = await contentTypesCollection.FindAsync(findAllFilterDefinition, findOptions).ConfigureAwait(false); + return await resultsCursor.ToListAsync().ConfigureAwait(false); + } + /// /// Gets the rules categorized with specified between /// and . @@ -56,9 +89,9 @@ public async Task AddRuleAsync(Rule rule) /// the filtering begin date. /// the filtering end date. /// - public async Task>> GetRulesAsync(TContentType contentType, DateTime dateBegin, DateTime dateEnd) + public async Task> GetRulesAsync(string contentType, DateTime dateBegin, DateTime dateEnd) { - var getRulesByContentTypeAndDatesInterval = MongoDbProviderRulesDataSource + var getRulesByContentTypeAndDatesInterval = MongoDbProviderRulesDataSource .BuildFilterByContentTypeAndDatesInterval(contentType, dateBegin, dateEnd); return await this.GetRulesAsync(getRulesByContentTypeAndDatesInterval).ConfigureAwait(false); @@ -69,14 +102,14 @@ public async Task>> GetRulesAsync /// /// The rules filter arguments. /// - public Task>> GetRulesByAsync(RulesFilterArgs rulesFilterArgs) + public Task> GetRulesByAsync(RulesFilterArgs rulesFilterArgs) { if (rulesFilterArgs is null) { throw new ArgumentNullException(nameof(rulesFilterArgs)); } - var filterDefinition = MongoDbProviderRulesDataSource + var filterDefinition = MongoDbProviderRulesDataSource .BuildFilterFromRulesFilterArgs(rulesFilterArgs); return this.GetRulesAsync(filterDefinition); @@ -86,7 +119,7 @@ public Task>> GetRulesByAsync(Rul /// Updates the existent rule on data source. /// /// The rule. - public async Task UpdateRuleAsync(Rule rule) + public async Task UpdateRuleAsync(Rule rule) { var rulesCollection = this.mongoDatabase.GetCollection(this.mongoDbProviderSettings.RulesCollectionName); @@ -111,9 +144,9 @@ public async Task UpdateRuleAsync(Rule rule) await rulesCollection.UpdateOneAsync(filterDefinition, updateDefinition).ConfigureAwait(false); } - private static FilterDefinition BuildFilterByContentTypeAndDatesInterval(TContentType contentType, DateTime dateBegin, DateTime dateEnd) + private static FilterDefinition BuildFilterByContentTypeAndDatesInterval(string contentType, DateTime dateBegin, DateTime dateEnd) { - var contentTypeFilter = Builders.Filter.Eq(x => x.ContentType, contentType.ToString()); + var contentTypeFilter = Builders.Filter.Eq(x => x.ContentType, contentType); var datesFilter = Builders.Filter.And( Builders.Filter.Lte(rule => rule.DateBegin, dateEnd), @@ -125,13 +158,13 @@ private static FilterDefinition BuildFilterByContentTypeAndDatesI return Builders.Filter.And(contentTypeFilter, datesFilter); } - private static FilterDefinition BuildFilterFromRulesFilterArgs(RulesFilterArgs rulesFilterArgs) + private static FilterDefinition BuildFilterFromRulesFilterArgs(RulesFilterArgs rulesFilterArgs) { var filtersToApply = new List>(3); - if (!object.Equals(rulesFilterArgs.ContentType, default(TContentType))) + if (!object.Equals(rulesFilterArgs.ContentType, default(string))) { - filtersToApply.Add(Builders.Filter.Eq(x => x.ContentType, rulesFilterArgs.ContentType.ToString())); + filtersToApply.Add(Builders.Filter.Eq(x => x.ContentType, rulesFilterArgs.ContentType)); } if (!string.IsNullOrWhiteSpace(rulesFilterArgs.Name)) @@ -147,7 +180,7 @@ private static FilterDefinition BuildFilterFromRulesFilterArgs(Ru return filtersToApply.Any() ? Builders.Filter.And(filtersToApply) : Builders.Filter.Empty; } - private async Task>> GetRulesAsync(FilterDefinition getRulesByContentTypeAndDatesInterval) + private async Task> GetRulesAsync(FilterDefinition getRulesByContentTypeAndDatesInterval) { var rulesCollection = this.mongoDatabase.GetCollection(this.mongoDbProviderSettings.RulesCollectionName); @@ -158,8 +191,8 @@ private async Task>> GetRulesAsyn // We won't use LINQ from this point onwards to avoid projected queries to database at a // later point. This approach assures the definitive realization of the query results // and does not produce side effects later on. - var result = new Rule[fetchedRules.Count]; - for (int i = 0; i < result.Length; i++) + var result = new Rule[fetchedRules.Count]; + for (var i = 0; i < result.Length; i++) { result[i] = this.ruleFactory.CreateRule(fetchedRules[i]); } @@ -167,4 +200,4 @@ private async Task>> GetRulesAsyn return result; } } -} +} \ No newline at end of file diff --git a/src/Rules.Framework.Providers.MongoDb/MongoDbProviderSettings.cs b/src/Rules.Framework.Providers.MongoDb/MongoDbProviderSettings.cs index 94fd89c3..4d4075e8 100644 --- a/src/Rules.Framework.Providers.MongoDb/MongoDbProviderSettings.cs +++ b/src/Rules.Framework.Providers.MongoDb/MongoDbProviderSettings.cs @@ -5,20 +5,32 @@ namespace Rules.Framework.Providers.MongoDb /// public class MongoDbProviderSettings { + private const string DefaultContentTypesCollectionName = "content_types"; + + /// + /// Initializes a new instance of the class. + /// + public MongoDbProviderSettings() + { + this.ContentTypesCollectionName = DefaultContentTypesCollectionName; + } + + /// + /// Gets or sets the name of the content types collection. + /// + /// The name of the content types collection. + public string ContentTypesCollectionName { get; set; } + /// /// Gets or sets the name of the database. /// - /// - /// The name of the database. - /// + /// The name of the database. public string DatabaseName { get; set; } /// /// Gets or sets the name of the rules collection. /// - /// - /// The name of the rules collection. - /// + /// The name of the rules collection. public string RulesCollectionName { get; set; } } } \ No newline at end of file diff --git a/src/Rules.Framework.Providers.MongoDb/MongoDbRulesDataSourceSelectorExtensions.cs b/src/Rules.Framework.Providers.MongoDb/MongoDbRulesDataSourceSelectorExtensions.cs index 6d97fa50..4a2c0a2c 100644 --- a/src/Rules.Framework.Providers.MongoDb/MongoDbRulesDataSourceSelectorExtensions.cs +++ b/src/Rules.Framework.Providers.MongoDb/MongoDbRulesDataSourceSelectorExtensions.cs @@ -23,8 +23,8 @@ public static class MongoDbRulesDataSourceSelectorExtensions /// /// rulesDataSourceSelector or mongoClient or mongoDbProviderSettings /// - public static IConfiguredRulesEngineBuilder SetMongoDbDataSource( - this IRulesDataSourceSelector rulesDataSourceSelector, + public static IConfiguredRulesEngineBuilder SetMongoDbDataSource( + this IRulesDataSourceSelector rulesDataSourceSelector, IMongoClient mongoClient, MongoDbProviderSettings mongoDbProviderSettings) { @@ -44,10 +44,10 @@ public static IConfiguredRulesEngineBuilder SetMon } MongoDbRulesDataSourceInitializer.InitializeAsync(mongoClient, mongoDbProviderSettings).GetAwaiter().GetResult(); - IContentSerializationProvider contentSerializationProvider = new DynamicToStrongTypeContentSerializationProvider(); - IRuleFactory ruleFactory = new RuleFactory(contentSerializationProvider); - MongoDbProviderRulesDataSource mongoDbProviderRulesDataSource - = new MongoDbProviderRulesDataSource( + IContentSerializationProvider contentSerializationProvider = new DynamicToStrongTypeContentSerializationProvider(); + IRuleFactory ruleFactory = new RuleFactory(contentSerializationProvider); + var mongoDbProviderRulesDataSource + = new MongoDbProviderRulesDataSource( mongoClient, mongoDbProviderSettings, ruleFactory); diff --git a/src/Rules.Framework.Providers.MongoDb/RuleFactory.cs b/src/Rules.Framework.Providers.MongoDb/RuleFactory.cs index 54cc31d0..d6e6f94b 100644 --- a/src/Rules.Framework.Providers.MongoDb/RuleFactory.cs +++ b/src/Rules.Framework.Providers.MongoDb/RuleFactory.cs @@ -4,35 +4,32 @@ namespace Rules.Framework.Providers.MongoDb using System.Collections.Generic; using System.Globalization; using System.Linq; - using Rules.Framework.Core; - using Rules.Framework.Core.ConditionNodes; + using Rules.Framework.ConditionNodes; using Rules.Framework.Providers.MongoDb.DataModel; using Rules.Framework.Serialization; - internal sealed class RuleFactory : IRuleFactory + internal sealed class RuleFactory : IRuleFactory { - private readonly IContentSerializationProvider contentSerializationProvider; + private readonly IContentSerializationProvider contentSerializationProvider; - public RuleFactory(IContentSerializationProvider contentSerializationProvider) + public RuleFactory(IContentSerializationProvider contentSerializationProvider) { this.contentSerializationProvider = contentSerializationProvider; } - public Rule CreateRule(RuleDataModel ruleDataModel) + public Rule CreateRule(RuleDataModel ruleDataModel) { if (ruleDataModel is null) { throw new ArgumentNullException(nameof(ruleDataModel)); } - var contentType = Parse(ruleDataModel.ContentType); - - var ruleBuilderResult = RuleBuilder.NewRule() + var ruleBuilderResult = Rule.New() .WithName(ruleDataModel.Name) .WithDatesInterval(ruleDataModel.DateBegin, ruleDataModel.DateEnd) .WithActive(ruleDataModel.Active ?? true) .WithCondition(_ => ruleDataModel.RootCondition is { } ? ConvertConditionNode(ruleDataModel.RootCondition) : null) - .WithSerializedContent(contentType, (object)ruleDataModel.Content, this.contentSerializationProvider) + .WithSerializedContent(ruleDataModel.ContentType, (object)ruleDataModel.Content, this.contentSerializationProvider) .Build(); if (!ruleBuilderResult.IsSuccess) @@ -52,7 +49,7 @@ public Rule CreateRule(RuleDataModel ruleDataModel return ruleBuilderResult.Rule; } - public RuleDataModel CreateRule(Rule rule) + public RuleDataModel CreateRule(Rule rule) { if (rule is null) { @@ -60,12 +57,12 @@ public RuleDataModel CreateRule(Rule rule) } var content = rule.ContentContainer.GetContentAs(); - var serializedContent = this.contentSerializationProvider.GetContentSerializer(rule.ContentContainer.ContentType).Serialize(content); + var serializedContent = this.contentSerializationProvider.GetContentSerializer(rule.ContentType).Serialize(content); var ruleDataModel = new RuleDataModel { Content = serializedContent, - ContentType = Convert.ToString(rule.ContentContainer.ContentType, CultureInfo.InvariantCulture), + ContentType = rule.ContentType, DateBegin = rule.DateBegin, DateEnd = rule.DateEnd, Name = rule.Name, @@ -77,7 +74,7 @@ public RuleDataModel CreateRule(Rule rule) return ruleDataModel; } - private static IConditionNode ConvertConditionNode(ConditionNodeDataModel conditionNodeDataModel) + private static IConditionNode ConvertConditionNode(ConditionNodeDataModel conditionNodeDataModel) { if (conditionNodeDataModel.LogicalOperator == LogicalOperators.Eval) { @@ -87,13 +84,13 @@ private static IConditionNode ConvertConditionNode(ConditionNode var composedConditionNodeDataModel = conditionNodeDataModel as ComposedConditionNodeDataModel; var childConditionNodeDataModels = composedConditionNodeDataModel.ChildConditionNodes; var count = childConditionNodeDataModels.Length; - var childConditionNodes = new IConditionNode[count]; - for (int i = 0; i < count; i++) + var childConditionNodes = new IConditionNode[count]; + for (var i = 0; i < count; i++) { childConditionNodes[i] = ConvertConditionNode(childConditionNodeDataModels[i]); } - var composedConditionNode = new ComposedConditionNode( + var composedConditionNode = new ComposedConditionNode( composedConditionNodeDataModel.LogicalOperator, childConditionNodes); foreach (var property in composedConditionNodeDataModel.Properties) @@ -104,7 +101,7 @@ private static IConditionNode ConvertConditionNode(ConditionNode return composedConditionNode; } - private static ValueConditionNodeDataModel ConvertValueConditionNode(ValueConditionNode valueConditionNode) + private static ValueConditionNodeDataModel ConvertValueConditionNode(ValueConditionNode valueConditionNode) { var properties = FilterProperties(valueConditionNode.Properties); @@ -119,9 +116,8 @@ private static ValueConditionNodeDataModel ConvertValueConditionNode(ValueCondit }; } - private static ValueConditionNode CreateValueConditionNode(ValueConditionNodeDataModel conditionNodeDataModel) + private static ValueConditionNode CreateValueConditionNode(ValueConditionNodeDataModel conditionNodeDataModel) { - TConditionType conditionType = Parse(conditionNodeDataModel.ConditionType); var operand = conditionNodeDataModel.DataType switch { DataTypes.Integer => Convert.ToInt32(conditionNodeDataModel.Operand, CultureInfo.InvariantCulture), @@ -132,7 +128,11 @@ private static ValueConditionNode CreateValueConditionNode(Value _ => throw new NotSupportedException($"Unsupported data type: {conditionNodeDataModel.DataType}."), }; - var valueConditionNode = new ValueConditionNode(conditionNodeDataModel.DataType, conditionType, conditionNodeDataModel.Operator, operand); + var valueConditionNode = new ValueConditionNode( + conditionNodeDataModel.DataType, + conditionNodeDataModel.ConditionType, + conditionNodeDataModel.Operator, + operand); foreach (var property in conditionNodeDataModel.Properties) { @@ -158,13 +158,7 @@ private static IDictionary FilterProperties(IDictionary(string value) - => (T)Parse(value, typeof(T)); - - private static object Parse(string value, Type type) - => type.IsEnum ? Enum.Parse(type, value) : Convert.ChangeType(value, type, CultureInfo.InvariantCulture); - - private ConditionNodeDataModel ConvertComposedConditionNode(ComposedConditionNode composedConditionNode) + private ComposedConditionNodeDataModel ConvertComposedConditionNode(ComposedConditionNode composedConditionNode) { var conditionNodeDataModels = new ConditionNodeDataModel[composedConditionNode.ChildConditionNodes.Count()]; var i = 0; @@ -183,14 +177,14 @@ private ConditionNodeDataModel ConvertComposedConditionNode(ComposedConditionNod }; } - private ConditionNodeDataModel ConvertConditionNode(IConditionNode conditionNode) + private ConditionNodeDataModel ConvertConditionNode(IConditionNode conditionNode) { if (conditionNode.LogicalOperator == LogicalOperators.Eval) { - return ConvertValueConditionNode(conditionNode as ValueConditionNode); + return ConvertValueConditionNode(conditionNode as ValueConditionNode); } - return ConvertComposedConditionNode(conditionNode as ComposedConditionNode); + return ConvertComposedConditionNode(conditionNode as ComposedConditionNode); } } } \ No newline at end of file diff --git a/src/Rules.Framework.Providers.MongoDb/Serialization/DynamicToStrongTypeContentSerializationProvider.cs b/src/Rules.Framework.Providers.MongoDb/Serialization/DynamicToStrongTypeContentSerializationProvider.cs index 926758ad..42a79da4 100644 --- a/src/Rules.Framework.Providers.MongoDb/Serialization/DynamicToStrongTypeContentSerializationProvider.cs +++ b/src/Rules.Framework.Providers.MongoDb/Serialization/DynamicToStrongTypeContentSerializationProvider.cs @@ -6,15 +6,14 @@ namespace Rules.Framework.Providers.MongoDb.Serialization /// /// Defines a content serialization provider for dynamic types. /// - /// The type of the content type. - /// - public class DynamicToStrongTypeContentSerializationProvider : IContentSerializationProvider + /// + public class DynamicToStrongTypeContentSerializationProvider : IContentSerializationProvider { private readonly Lazy contentSerializerLazy; /// /// Initializes a new instance of the class. + /// cref="DynamicToStrongTypeContentSerializationProvider"/> class. /// public DynamicToStrongTypeContentSerializationProvider() { @@ -28,6 +27,6 @@ public DynamicToStrongTypeContentSerializationProvider() /// /// the content type. /// the content serializer to deal with contents for specified content type. - public IContentSerializer GetContentSerializer(TContentType contentType) => this.contentSerializerLazy.Value; + public IContentSerializer GetContentSerializer(string contentType) => this.contentSerializerLazy.Value; } } \ No newline at end of file diff --git a/src/Rules.Framework.WebUI/Extensions/RuleDtoExtensions.cs b/src/Rules.Framework.WebUI/Extensions/RuleDtoExtensions.cs index e50298fc..eeee5cc8 100644 --- a/src/Rules.Framework.WebUI/Extensions/RuleDtoExtensions.cs +++ b/src/Rules.Framework.WebUI/Extensions/RuleDtoExtensions.cs @@ -2,30 +2,30 @@ namespace Rules.Framework.WebUI.Extensions { using System.Collections.Generic; using System.Linq; - using Rules.Framework.Generics; + using Rules.Framework.ConditionNodes; using Rules.Framework.WebUI.Dto; internal static class RuleDtoExtensions { private const string dateFormat = "dd/MM/yyyy HH:mm:ss"; - public static ConditionNodeDto ToConditionNodeDto(this GenericConditionNode rootCondition) + public static ConditionNodeDto ToConditionNodeDto(this IConditionNode rootCondition) { - if (rootCondition.LogicalOperator == Core.LogicalOperators.Eval || + if (rootCondition.LogicalOperator == Framework.LogicalOperators.Eval || rootCondition.LogicalOperator == 0) { - var condition = rootCondition as GenericValueConditionNode; + var condition = rootCondition as ValueConditionNode; return new ValueConditionNodeDto { - ConditionTypeName = condition.ConditionTypeName, + ConditionTypeName = condition.ConditionType, DataType = condition.DataType.ToString(), Operand = condition.Operand, Operator = condition.Operator.ToString(), }; } - var composedConditionNode = rootCondition as GenericComposedConditionNode; + var composedConditionNode = rootCondition as ComposedConditionNode; var conditionNodeDataModels = new List(composedConditionNode.ChildConditionNodes.Count()); @@ -41,7 +41,7 @@ public static ConditionNodeDto ToConditionNodeDto(this GenericConditionNode root }; } - public static RuleDto ToRuleDto(this GenericRule rule, string ContentType, IRuleStatusDtoAnalyzer ruleStatusDtoAnalyzer) + public static RuleDto ToRuleDto(this Rule rule, string ContentType, IRuleStatusDtoAnalyzer ruleStatusDtoAnalyzer) { return new RuleDto { @@ -49,11 +49,11 @@ public static RuleDto ToRuleDto(this GenericRule rule, string ContentType, IRule ContentType = ContentType, Priority = rule.Priority, Name = rule.Name, - Value = rule.Content, + Value = rule.ContentContainer.GetContentAs(), DateEnd = !rule.DateEnd.HasValue ? null : rule.DateEnd.Value.ToString(dateFormat), DateBegin = rule.DateBegin.ToString(dateFormat), Status = !rule.Active ? RuleStatusDto.Deactivated.ToString() : ruleStatusDtoAnalyzer.Analyze(rule.DateBegin, rule.DateEnd).ToString(), }; } } -} +} \ No newline at end of file diff --git a/src/Rules.Framework.WebUI/Handlers/GetConfigurationsHandler.cs b/src/Rules.Framework.WebUI/Handlers/GetConfigurationsHandler.cs index 60f17e85..6ac4a0ce 100644 --- a/src/Rules.Framework.WebUI/Handlers/GetConfigurationsHandler.cs +++ b/src/Rules.Framework.WebUI/Handlers/GetConfigurationsHandler.cs @@ -5,15 +5,14 @@ namespace Rules.Framework.WebUI.Handlers using System.Net; using System.Threading.Tasks; using Microsoft.AspNetCore.Http; - using Rules.Framework.Generics; internal sealed class GetConfigurationsHandler : WebUIRequestHandlerBase { private static readonly string[] resourcePath = new[] { "/{0}/api/v1/configurations" }; - private readonly IGenericRulesEngine rulesEngine; + private readonly IRulesEngine rulesEngine; - public GetConfigurationsHandler(IGenericRulesEngine rulesEngine, WebUIOptions webUIOptions) : base(resourcePath, webUIOptions) + public GetConfigurationsHandler(IRulesEngine rulesEngine, WebUIOptions webUIOptions) : base(resourcePath, webUIOptions) { this.rulesEngine = rulesEngine; } @@ -24,11 +23,24 @@ protected override Task HandleRequestAsync(HttpRequest httpRequest, HttpResponse { try { - var priorityCriteria = this.rulesEngine.GetPriorityCriteria(); - - var configurations = new Dictionary + var configurations = new Dictionary { - { "PriorityCriteria", priorityCriteria.ToString() } + { "PriorityCriteria", this.rulesEngine.Options.PriorityCriteria.ToString() }, + { "MissingConditionBehavior", this.rulesEngine.Options.MissingConditionBehavior.ToString() }, + { + "DataTypeDefaults", + new Dictionary + { + { "ArrayBoolean", this.rulesEngine.Options.DataTypeDefaults[DataTypes.ArrayBoolean].ToString() }, + { "ArrayDecimal", this.rulesEngine.Options.DataTypeDefaults[DataTypes.ArrayDecimal].ToString() }, + { "ArrayInteger", this.rulesEngine.Options.DataTypeDefaults[DataTypes.ArrayInteger].ToString() }, + { "ArrayString", this.rulesEngine.Options.DataTypeDefaults[DataTypes.ArrayString].ToString() }, + { "Boolean", this.rulesEngine.Options.DataTypeDefaults[DataTypes.Boolean].ToString() }, + { "Decimal", this.rulesEngine.Options.DataTypeDefaults[DataTypes.Decimal].ToString() }, + { "Integer", this.rulesEngine.Options.DataTypeDefaults[DataTypes.Integer].ToString() }, + { "String", this.rulesEngine.Options.DataTypeDefaults[DataTypes.String].ToString() }, + } + } }; return this.WriteResponseAsync(httpResponse, configurations, (int)HttpStatusCode.OK); diff --git a/src/Rules.Framework.WebUI/Handlers/GetContentTypeHandler.cs b/src/Rules.Framework.WebUI/Handlers/GetContentTypeHandler.cs index b4464799..96303f4e 100644 --- a/src/Rules.Framework.WebUI/Handlers/GetContentTypeHandler.cs +++ b/src/Rules.Framework.WebUI/Handlers/GetContentTypeHandler.cs @@ -6,21 +6,20 @@ namespace Rules.Framework.WebUI.Handlers using System.Net; using System.Threading.Tasks; using Microsoft.AspNetCore.Http; - using Rules.Framework.Generics; using Rules.Framework.WebUI.Dto; internal sealed class GetContentTypeHandler : WebUIRequestHandlerBase { private static readonly string[] resourcePath = new[] { "/{0}/api/v1/contentTypes" }; - private readonly IGenericRulesEngine genericRulesEngine; + private readonly IRulesEngine rulesEngine; private readonly IRuleStatusDtoAnalyzer ruleStatusDtoAnalyzer; - public GetContentTypeHandler(IGenericRulesEngine genericRulesEngine, + public GetContentTypeHandler(IRulesEngine rulesEngine, IRuleStatusDtoAnalyzer ruleStatusDtoAnalyzer, WebUIOptions webUIOptions) : base(resourcePath, webUIOptions) { - this.genericRulesEngine = genericRulesEngine; + this.rulesEngine = rulesEngine; this.ruleStatusDtoAnalyzer = ruleStatusDtoAnalyzer; } @@ -30,16 +29,14 @@ protected override async Task HandleRequestAsync(HttpRequest httpRequest, HttpRe { try { - var contents = this.genericRulesEngine.GetContentTypes(); + var contents = await this.rulesEngine.GetContentTypesAsync().ConfigureAwait(false); var contentTypes = new List(); var index = 0; - foreach (var identifier in contents.Select(c => c.Identifier)) + foreach (var identifier in contents) { - var genericContentType = new GenericContentType { Identifier = identifier }; - - var genericRules = await this.genericRulesEngine - .SearchAsync(new SearchArgs(genericContentType, + var genericRules = await this.rulesEngine + .SearchAsync(new SearchArgs(identifier, DateTime.MinValue, DateTime.MaxValue)) .ConfigureAwait(false); @@ -62,9 +59,9 @@ protected override async Task HandleRequestAsync(HttpRequest httpRequest, HttpRe } } - private bool IsActive(GenericRule genericRule) + private bool IsActive(Rule rule) { - return this.ruleStatusDtoAnalyzer.Analyze(genericRule.DateBegin, genericRule.DateEnd) == RuleStatusDto.Active; + return this.ruleStatusDtoAnalyzer.Analyze(rule.DateBegin, rule.DateEnd) == RuleStatusDto.Active; } } -} +} \ No newline at end of file diff --git a/src/Rules.Framework.WebUI/Handlers/GetRulesHandler.cs b/src/Rules.Framework.WebUI/Handlers/GetRulesHandler.cs index cf7c00d7..020e354e 100644 --- a/src/Rules.Framework.WebUI/Handlers/GetRulesHandler.cs +++ b/src/Rules.Framework.WebUI/Handlers/GetRulesHandler.cs @@ -8,19 +8,18 @@ namespace Rules.Framework.WebUI.Handlers using System.Threading.Tasks; using System.Web; using Microsoft.AspNetCore.Http; - using Rules.Framework.Generics; using Rules.Framework.WebUI.Dto; using Rules.Framework.WebUI.Extensions; internal sealed class GetRulesHandler : WebUIRequestHandlerBase { private static readonly string[] resourcePath = new[] { "/{0}/api/v1/rules" }; - private readonly IGenericRulesEngine genericRulesEngine; + private readonly IRulesEngine rulesEngine; private readonly IRuleStatusDtoAnalyzer ruleStatusDtoAnalyzer; - public GetRulesHandler(IGenericRulesEngine genericRulesEngine, IRuleStatusDtoAnalyzer ruleStatusDtoAnalyzer, WebUIOptions webUIOptions) : base(resourcePath, webUIOptions) + public GetRulesHandler(IRulesEngine rulesEngine, IRuleStatusDtoAnalyzer ruleStatusDtoAnalyzer, WebUIOptions webUIOptions) : base(resourcePath, webUIOptions) { - this.genericRulesEngine = genericRulesEngine; + this.rulesEngine = rulesEngine; this.ruleStatusDtoAnalyzer = ruleStatusDtoAnalyzer; } @@ -46,9 +45,9 @@ protected override async Task HandleRequestAsync(HttpRequest httpRequest, if (rulesFilter.ContentType.Equals("all")) { - var contents = this.genericRulesEngine.GetContentTypes(); + var contents = await this.rulesEngine.GetContentTypesAsync(); - foreach (var identifier in contents.Select(c => c.Identifier)) + foreach (var identifier in contents) { var rulesForContentType = await this.GetRulesForContentyType(identifier, rulesFilter).ConfigureAwait(false); rules.AddRange(rulesForContentType); @@ -129,13 +128,14 @@ private RulesFilterDto GetRulesFilterFromRequest(HttpRequest httpRequest) private async Task> GetRulesForContentyType(string identifier, RulesFilterDto rulesFilter) { - var genericRules = await this.genericRulesEngine.SearchAsync( - new SearchArgs( - new GenericContentType { Identifier = identifier }, - rulesFilter.DateBegin.Value, rulesFilter.DateEnd.Value)) + var genericRules = await this.rulesEngine.SearchAsync( + new SearchArgs( + identifier, + rulesFilter.DateBegin.Value, + rulesFilter.DateEnd.Value)) .ConfigureAwait(false); - var priorityCriteria = this.genericRulesEngine.GetPriorityCriteria(); + var priorityCriteria = this.rulesEngine.Options.PriorityCriteria; if (genericRules != null && genericRules.Any()) { diff --git a/src/Rules.Framework.WebUI/WebUIApplicationBuilderExtensions.cs b/src/Rules.Framework.WebUI/WebUIApplicationBuilderExtensions.cs index ab9d7105..4e8bcea3 100644 --- a/src/Rules.Framework.WebUI/WebUIApplicationBuilderExtensions.cs +++ b/src/Rules.Framework.WebUI/WebUIApplicationBuilderExtensions.cs @@ -5,7 +5,6 @@ namespace Rules.Framework.WebUI using Microsoft.AspNetCore.Builder; using Microsoft.Extensions.DependencyInjection; using Microsoft.Extensions.Options; - using Rules.Framework.Generics; using Rules.Framework.WebUI.Dto; using Rules.Framework.WebUI.Handlers; @@ -22,7 +21,7 @@ public static class WebUIApplicationBuilderExtensions /// The web UI options action. /// public static IApplicationBuilder UseRulesFrameworkWebUI(this IApplicationBuilder app, - Func genericRulesEngineFactory, + Func genericRulesEngineFactory, Action webUIOptionsAction) { var genericRulesEngine = genericRulesEngineFactory.Invoke(app.ApplicationServices); @@ -36,7 +35,7 @@ public static IApplicationBuilder UseRulesFrameworkWebUI(this IApplicationBuilde /// The generic rules engine factory. /// public static IApplicationBuilder UseRulesFrameworkWebUI(this IApplicationBuilder app, - Func genericRulesEngineFactory) + Func genericRulesEngineFactory) { return app.UseRulesFrameworkWebUI(genericRulesEngineFactory, null); } @@ -48,7 +47,7 @@ public static IApplicationBuilder UseRulesFrameworkWebUI(this IApplicationBuilde /// The generic rules engine. /// public static IApplicationBuilder UseRulesFrameworkWebUI(this IApplicationBuilder app, - IGenericRulesEngine genericRulesEngine) + IRulesEngine genericRulesEngine) { return app.UseRulesFrameworkWebUI(genericRulesEngine, new WebUIOptions()); } @@ -61,7 +60,7 @@ public static IApplicationBuilder UseRulesFrameworkWebUI(this IApplicationBuilde /// The web UI options action. /// public static IApplicationBuilder UseRulesFrameworkWebUI(this IApplicationBuilder app, - IGenericRulesEngine genericRulesEngine, + IRulesEngine genericRulesEngine, Action webUIOptionsAction) { WebUIOptions webUIOptions; @@ -82,7 +81,7 @@ public static IApplicationBuilder UseRulesFrameworkWebUI(this IApplicationBuilde /// The generic rules engine. /// The web UI options. /// - private static IApplicationBuilder UseRulesFrameworkWebUI(this IApplicationBuilder app, IGenericRulesEngine genericRulesEngine, + private static IApplicationBuilder UseRulesFrameworkWebUI(this IApplicationBuilder app, IRulesEngine genericRulesEngine, WebUIOptions webUIOptions) { var ruleStatusDtoAnalyzer = new RuleStatusDtoAnalyzer(); diff --git a/src/Rules.Framework/Builder/ConditionNodeFactory.cs b/src/Rules.Framework/Builder/ConditionNodeFactory.cs index 881cb162..561a6aaa 100644 --- a/src/Rules.Framework/Builder/ConditionNodeFactory.cs +++ b/src/Rules.Framework/Builder/ConditionNodeFactory.cs @@ -2,8 +2,9 @@ namespace Rules.Framework.Builder { using System; using System.Collections.Generic; - using Rules.Framework.Core; - using Rules.Framework.Core.ConditionNodes; + using Rules.Framework; + using Rules.Framework.Builder.Generic; + using Rules.Framework.ConditionNodes; /// /// Factory for creating condition nodes. @@ -18,7 +19,28 @@ public static class ConditionNodeFactory /// The function containing the logic for the composed condition node. /// /// - public static IConditionNode CreateComposedNode( + public static IConditionNode CreateComposedNode( + LogicalOperators logicalOperator, + Func conditionFunc) + { + var composedConditionNodeBuilder = new FluentComposedConditionNodeBuilder(logicalOperator); + + var composedConditionNode = conditionFunc + .Invoke(composedConditionNodeBuilder) + .Build(); + + return composedConditionNode; + } + + /// + /// Creates a composed condition node. + /// + /// The logical operator. + /// + /// The function containing the logic for the composed condition node. + /// + /// + public static IConditionNode CreateComposedNode( LogicalOperators logicalOperator, Func, IFluentComposedConditionNodeBuilder> conditionFunc) { @@ -38,34 +60,34 @@ public static IConditionNode CreateComposedNode( /// The condition operator. /// The condition operand. /// - public static IConditionNode CreateValueNode( - TConditionType conditionType, Operators condOperator, TDataType operand) + public static IValueConditionNode CreateValueNode( + string conditionType, Operators condOperator, TDataType operand) { switch (operand) { case decimal _: - return new ValueConditionNode(DataTypes.Decimal, conditionType, condOperator, operand); + return new ValueConditionNode(DataTypes.Decimal, conditionType, condOperator, operand); case IEnumerable _: - return new ValueConditionNode(DataTypes.ArrayDecimal, conditionType, condOperator, operand); + return new ValueConditionNode(DataTypes.ArrayDecimal, conditionType, condOperator, operand); case int _: - return new ValueConditionNode(DataTypes.Integer, conditionType, condOperator, operand); + return new ValueConditionNode(DataTypes.Integer, conditionType, condOperator, operand); case IEnumerable _: - return new ValueConditionNode(DataTypes.ArrayInteger, conditionType, condOperator, operand); + return new ValueConditionNode(DataTypes.ArrayInteger, conditionType, condOperator, operand); case bool _: - return new ValueConditionNode(DataTypes.Boolean, conditionType, condOperator, operand); + return new ValueConditionNode(DataTypes.Boolean, conditionType, condOperator, operand); case IEnumerable _: - return new ValueConditionNode(DataTypes.ArrayBoolean, conditionType, condOperator, operand); + return new ValueConditionNode(DataTypes.ArrayBoolean, conditionType, condOperator, operand); case string _: - return new ValueConditionNode(DataTypes.String, conditionType, condOperator, operand); + return new ValueConditionNode(DataTypes.String, conditionType, condOperator, operand); case IEnumerable _: - return new ValueConditionNode(DataTypes.ArrayString, conditionType, condOperator, operand); + return new ValueConditionNode(DataTypes.ArrayString, conditionType, condOperator, operand); default: throw new NotSupportedException($"The data type is not supported: {typeof(TDataType).FullName}."); diff --git a/src/Rules.Framework/Builder/ConfiguredRulesEngineBuilder.cs b/src/Rules.Framework/Builder/ConfiguredRulesEngineBuilder.cs index f2e1da5d..a2cdbded 100644 --- a/src/Rules.Framework/Builder/ConfiguredRulesEngineBuilder.cs +++ b/src/Rules.Framework/Builder/ConfiguredRulesEngineBuilder.cs @@ -12,38 +12,38 @@ namespace Rules.Framework.Builder using Rules.Framework.Source; using Rules.Framework.Validation; - internal sealed class ConfiguredRulesEngineBuilder : IConfiguredRulesEngineBuilder + internal sealed class ConfiguredRulesEngineBuilder : IConfiguredRulesEngineBuilder { - private readonly IRulesDataSource rulesDataSource; + private readonly IRulesDataSource rulesDataSource; private readonly RulesEngineOptions rulesEngineOptions; - public ConfiguredRulesEngineBuilder(IRulesDataSource rulesDataSource) + public ConfiguredRulesEngineBuilder(IRulesDataSource rulesDataSource) { this.rulesDataSource = rulesDataSource; this.rulesEngineOptions = RulesEngineOptions.NewWithDefaults(); } - public RulesEngine Build() + public IRulesEngine Build() { - var rulesSourceMiddlewares = new List>(); + var rulesSourceMiddlewares = new List(); var dataTypesConfigurationProvider = new DataTypesConfigurationProvider(this.rulesEngineOptions); var multiplicityEvaluator = new MultiplicityEvaluator(); - var conditionsTreeAnalyzer = new ConditionsTreeAnalyzer(); + var conditionsTreeAnalyzer = new ConditionsTreeAnalyzer(); - IConditionsEvalEngine conditionsEvalEngine; + IConditionsEvalEngine conditionsEvalEngine; if (this.rulesEngineOptions.EnableCompilation) { // Use specific conditions eval engine to use compiled parts of conditions tree. var conditionExpressionBuilderProvider = new ConditionExpressionBuilderProvider(); var valueConditionNodeCompilerProvider = new ValueConditionNodeExpressionBuilderProvider(conditionExpressionBuilderProvider); - var ruleConditionsExpressionBuilder = new RuleConditionsExpressionBuilder(valueConditionNodeCompilerProvider, dataTypesConfigurationProvider); - conditionsEvalEngine = new CompiledConditionsEvalEngine(conditionsTreeAnalyzer, this.rulesEngineOptions); + var ruleConditionsExpressionBuilder = new RuleConditionsExpressionBuilder(valueConditionNodeCompilerProvider, dataTypesConfigurationProvider); + conditionsEvalEngine = new CompiledConditionsEvalEngine(conditionsTreeAnalyzer, this.rulesEngineOptions); // Add conditions compiler middleware to ensure compilation occurs before rules // engine uses the rules, while also ensuring that the compilation result is kept on // data source (avoiding future re-compilation). - var compilationRulesSourceMiddleware = new CompilationRulesSourceMiddleware(ruleConditionsExpressionBuilder, this.rulesDataSource); + var compilationRulesSourceMiddleware = new CompilationRulesSourceMiddleware(ruleConditionsExpressionBuilder, this.rulesDataSource); rulesSourceMiddlewares.Add(compilationRulesSourceMiddleware); } else @@ -53,22 +53,22 @@ public RulesEngine Build() var operatorEvalStrategyFactory = new OperatorEvalStrategyFactory(); var conditionEvalDispatchProvider = new ConditionEvalDispatchProvider(operatorEvalStrategyFactory, multiplicityEvaluator, dataTypesConfigurationProvider); var deferredEval = new DeferredEval(conditionEvalDispatchProvider, this.rulesEngineOptions); - conditionsEvalEngine = new InterpretedConditionsEvalEngine(deferredEval, conditionsTreeAnalyzer); + conditionsEvalEngine = new InterpretedConditionsEvalEngine(deferredEval, conditionsTreeAnalyzer); } - var conditionTypeExtractor = new ConditionTypeExtractor(); + var conditionTypeExtractor = new ConditionTypeExtractor(); var validationProvider = ValidationProvider.New() - .MapValidatorFor(new SearchArgsValidator()); + .MapValidatorFor(new SearchArgsValidator()); var orderedMiddlewares = rulesSourceMiddlewares - .Reverse>(); - var rulesSource = new RulesSource(this.rulesDataSource, orderedMiddlewares); + .Reverse(); + var rulesSource = new RulesSource(this.rulesDataSource, orderedMiddlewares); - return new RulesEngine(conditionsEvalEngine, rulesSource, validationProvider, this.rulesEngineOptions, conditionTypeExtractor); + return new RulesEngine(conditionsEvalEngine, rulesSource, validationProvider, this.rulesEngineOptions, conditionTypeExtractor); } - public IConfiguredRulesEngineBuilder Configure(Action configurationAction) + public IConfiguredRulesEngineBuilder Configure(Action configurationAction) { configurationAction.Invoke(this.rulesEngineOptions); RulesEngineOptionsValidator.Validate(this.rulesEngineOptions); diff --git a/src/Rules.Framework/Builder/FluentComposedConditionNodeBuilder.cs b/src/Rules.Framework/Builder/FluentComposedConditionNodeBuilder.cs index 5698d404..54840941 100644 --- a/src/Rules.Framework/Builder/FluentComposedConditionNodeBuilder.cs +++ b/src/Rules.Framework/Builder/FluentComposedConditionNodeBuilder.cs @@ -1,23 +1,24 @@ -namespace Rules.Framework.Builder +namespace Rules.Framework.Builder.Generic { using System; using System.Collections.Generic; - using Rules.Framework.Core; - using Rules.Framework.Core.ConditionNodes; + using Rules.Framework; + using Rules.Framework.ConditionNodes; + using Rules.Framework.Generic; - internal sealed class FluentComposedConditionNodeBuilder : IFluentComposedConditionNodeBuilder + internal sealed class FluentComposedConditionNodeBuilder : IFluentComposedConditionNodeBuilder { - private readonly List> conditions; + private readonly List conditions; private readonly LogicalOperators logicalOperator; public FluentComposedConditionNodeBuilder(LogicalOperators logicalOperator) { this.logicalOperator = logicalOperator; - this.conditions = new List>(2); // Most probable number of conditions, so that collection is initialized with right size most times. + this.conditions = new List(2); // Most probable number of conditions, so that collection is initialized with right size most times. } - public IFluentComposedConditionNodeBuilder And( - Func, IFluentComposedConditionNodeBuilder> conditionFunc) + public IFluentComposedConditionNodeBuilder And( + Func conditionFunc) { var composedConditionNode = ConditionNodeFactory.CreateComposedNode(LogicalOperators.And, conditionFunc); @@ -26,20 +27,20 @@ public IFluentComposedConditionNodeBuilder And( return this; } - public IConditionNode Build() + public IConditionNode Build() { - return new ComposedConditionNode(this.logicalOperator, this.conditions); + return new ComposedConditionNode(this.logicalOperator, this.conditions); } - public IFluentComposedConditionNodeBuilder Condition(IConditionNode conditionNode) + public IFluentComposedConditionNodeBuilder Condition(IConditionNode conditionNode) { this.conditions.Add(conditionNode); return this; } - public IFluentComposedConditionNodeBuilder Or( - Func, IFluentComposedConditionNodeBuilder> conditionFunc) + public IFluentComposedConditionNodeBuilder Or( + Func conditionFunc) { var composedConditionNode = ConditionNodeFactory.CreateComposedNode(LogicalOperators.Or, conditionFunc); @@ -48,9 +49,10 @@ public IFluentComposedConditionNodeBuilder Or( return this; } - public IFluentComposedConditionNodeBuilder Value(TConditionType conditionType, Operators condOperator, TDataType operand) + public IFluentComposedConditionNodeBuilder Value(string conditionType, Operators condOperator, TDataType operand) { - var valueConditionNode = ConditionNodeFactory.CreateValueNode(conditionType, condOperator, operand); + var conditionTypeAsString = GenericConversions.Convert(conditionType); + var valueConditionNode = ConditionNodeFactory.CreateValueNode(conditionTypeAsString, condOperator, operand); this.conditions.Add(valueConditionNode); diff --git a/src/Rules.Framework/Builder/Generic/FluentComposedConditionNodeBuilder.cs b/src/Rules.Framework/Builder/Generic/FluentComposedConditionNodeBuilder.cs new file mode 100644 index 00000000..258b93fb --- /dev/null +++ b/src/Rules.Framework/Builder/Generic/FluentComposedConditionNodeBuilder.cs @@ -0,0 +1,62 @@ +namespace Rules.Framework.Builder.Generic +{ + using System; + using System.Collections.Generic; + using Rules.Framework; + using Rules.Framework.ConditionNodes; + using Rules.Framework.Generic; + + internal sealed class FluentComposedConditionNodeBuilder : IFluentComposedConditionNodeBuilder + { + private readonly List conditions; + private readonly LogicalOperators logicalOperator; + + public FluentComposedConditionNodeBuilder(LogicalOperators logicalOperator) + { + this.logicalOperator = logicalOperator; + this.conditions = new List(2); // Most probable number of conditions, so that collection is initialized with right size most times. + } + + public IFluentComposedConditionNodeBuilder And( + Func, IFluentComposedConditionNodeBuilder> conditionFunc) + { + var composedConditionNode = ConditionNodeFactory.CreateComposedNode(LogicalOperators.And, conditionFunc); + + this.conditions.Add(composedConditionNode); + + return this; + } + + public IConditionNode Build() + { + return new ComposedConditionNode(this.logicalOperator, this.conditions); + } + + public IFluentComposedConditionNodeBuilder Condition(IConditionNode conditionNode) + { + this.conditions.Add(conditionNode); + + return this; + } + + public IFluentComposedConditionNodeBuilder Or( + Func, IFluentComposedConditionNodeBuilder> conditionFunc) + { + var composedConditionNode = ConditionNodeFactory.CreateComposedNode(LogicalOperators.Or, conditionFunc); + + this.conditions.Add(composedConditionNode); + + return this; + } + + public IFluentComposedConditionNodeBuilder Value(TConditionType conditionType, Operators condOperator, TDataType operand) + { + var conditionTypeAsString = GenericConversions.Convert(conditionType); + var valueConditionNode = ConditionNodeFactory.CreateValueNode(conditionTypeAsString, condOperator, operand); + + this.conditions.Add(valueConditionNode); + + return this; + } + } +} \ No newline at end of file diff --git a/src/Rules.Framework/Builder/Generic/IFluentComposedConditionNodeBuilder.cs b/src/Rules.Framework/Builder/Generic/IFluentComposedConditionNodeBuilder.cs new file mode 100644 index 00000000..2de0cab8 --- /dev/null +++ b/src/Rules.Framework/Builder/Generic/IFluentComposedConditionNodeBuilder.cs @@ -0,0 +1,50 @@ +namespace Rules.Framework.Builder.Generic +{ + using System; + using Rules.Framework; + using Rules.Framework.Generic; + + /// + /// Fluent builder for composed condition nodes. + /// + /// The type of the condition type. + public interface IFluentComposedConditionNodeBuilder + { + /// + /// Adds a And composed condition to the fluent condition node builder. + /// + /// The function containing the logic for the new condition. + /// + IFluentComposedConditionNodeBuilder And( + Func, IFluentComposedConditionNodeBuilder> conditionFunc); + + /// + /// Builds the composed condition node. + /// + /// + IConditionNode Build(); + + /// + /// Adds a Condition to the fluent condition node builder. + /// + /// The condition node. + IFluentComposedConditionNodeBuilder Condition(IConditionNode conditionNode); + + /// + /// Adds a Or composed condition to the fluent condition node builder. + /// + /// The function containing the logic for the new condition. + /// + IFluentComposedConditionNodeBuilder Or( + Func, IFluentComposedConditionNodeBuilder> conditionFunc); + + /// + /// Adds a Value condition to the fluent condition node builder. + /// + /// The condition type. + /// The condition operator. + /// The condition operand. + /// + IFluentComposedConditionNodeBuilder Value(TConditionType conditionType, Operators condOperator, TDataType operand); + } +} \ No newline at end of file diff --git a/src/Rules.Framework/Builder/Generic/IRootConditionNodeBuilder.cs b/src/Rules.Framework/Builder/Generic/IRootConditionNodeBuilder.cs new file mode 100644 index 00000000..2417af5b --- /dev/null +++ b/src/Rules.Framework/Builder/Generic/IRootConditionNodeBuilder.cs @@ -0,0 +1,45 @@ +namespace Rules.Framework.Builder +{ + using System; + using Rules.Framework; + using Rules.Framework.Builder.Generic; + using Rules.Framework.Generic; + + /// + /// Builder for the root condition node. + /// + /// The type of the condition type. + public interface IRootConditionNodeBuilder + { + /// + /// Sets a And composed condition to the root condition node builder. + /// + /// The function containing the logic for the root condition. + /// + IConditionNode And( + Func, IFluentComposedConditionNodeBuilder> conditionFunc); + + /// + /// Sets a Condition to the root condition node builder. + /// + /// The condition node. + IConditionNode Condition(IConditionNode conditionNode); + + /// + /// Sets a Or composed condition to the root condition node builder. + /// + /// The function containing the logic for the root condition. + /// + IConditionNode Or( + Func, IFluentComposedConditionNodeBuilder> conditionFunc); + + /// + /// Sets a Value condition to the root condition node builder. + /// + /// The condition type. + /// The condition operator. + /// The condition operand. + /// + IConditionNode Value(TConditionType conditionType, Operators condOperator, TDataType operand); + } +} \ No newline at end of file diff --git a/src/Rules.Framework/Builder/Generic/IRuleBuilder.cs b/src/Rules.Framework/Builder/Generic/IRuleBuilder.cs new file mode 100644 index 00000000..327b6a3d --- /dev/null +++ b/src/Rules.Framework/Builder/Generic/IRuleBuilder.cs @@ -0,0 +1,96 @@ +namespace Rules.Framework.Builder.Generic +{ + using System; + using Rules.Framework; + using Rules.Framework.Builder; + using Rules.Framework.Serialization; + + /// + /// Builder to create a new rule. + /// + /// The type of the content type. + /// The type of the condition type. + public interface IRuleBuilder + { + /// + /// Builds the new rule. + /// + /// + RuleBuilderResult Build(); + + /// + /// Sets the new rule with the specified active status. + /// + /// The active status. + /// + IRuleBuilder WithActive(bool active); + + /// + /// Sets the new rule with the specified root condition. + /// + /// The condition. + /// + IRuleBuilder WithCondition(IConditionNode condition); + + /// + /// Sets the new rule with a value condition with the specified parameters. + /// + /// The type of the data type. + /// The content type. + /// The operator. + /// The operand. + /// + IRuleBuilder WithCondition(TConditionType conditionType, Operators condOperator, TDataType operand); + + /// + /// Sets the new rule with the specified root condition. + /// + /// The condition func. + /// + IRuleBuilder WithCondition( + Func, IConditionNode> conditionFunc); + + /// + /// Sets the new rule with the specified content. + /// + /// The content type. + /// The content. + /// + IRuleBuilder WithContent(TContentType contentType, object content); + + /// + /// Sets the new rule with the specified date begin. + /// + /// The date begin. + /// + IRuleBuilder WithDateBegin(DateTime dateBegin); + + /// + /// Sets the new rule with the specified dates interval. + /// + /// The date begin. + /// The date end. + /// + IRuleBuilder WithDatesInterval(DateTime dateBegin, DateTime? dateEnd); + + /// + ///Sets the new rule with the specified name. + /// + /// The name. + /// + IRuleBuilder WithName(string name); + + /// + /// Sets the new rule with the specified serialized content. + /// + /// The type of the content. + /// The serialized content. + /// The content serialization provider. + /// + /// ruleBuilder or contentSerializationProvider + IRuleBuilder WithSerializedContent( + TContentType contentType, + object serializedContent, + IContentSerializationProvider contentSerializationProvider); + } +} \ No newline at end of file diff --git a/src/Rules.Framework/Builder/Generic/RootConditionNodeBuilder.cs b/src/Rules.Framework/Builder/Generic/RootConditionNodeBuilder.cs new file mode 100644 index 00000000..235b3cb0 --- /dev/null +++ b/src/Rules.Framework/Builder/Generic/RootConditionNodeBuilder.cs @@ -0,0 +1,33 @@ +namespace Rules.Framework.Builder.Generic +{ + using System; + using Rules.Framework; + using Rules.Framework.Generic; + + internal sealed class RootConditionNodeBuilder : IRootConditionNodeBuilder + { + public IConditionNode And( + Func, IFluentComposedConditionNodeBuilder> conditionFunc) + { + return ConditionNodeFactory.CreateComposedNode(LogicalOperators.And, conditionFunc); + } + + public IConditionNode Condition(IConditionNode conditionNode) + { + return conditionNode; + } + + public IConditionNode Or( + Func, IFluentComposedConditionNodeBuilder> conditionFunc) + { + return ConditionNodeFactory.CreateComposedNode(LogicalOperators.Or, conditionFunc); + } + + public IConditionNode Value( + TConditionType conditionType, Operators condOperator, TDataType operand) + { + var conditionTypeAsString = GenericConversions.Convert(conditionType); + return ConditionNodeFactory.CreateValueNode(conditionTypeAsString, condOperator, operand); + } + } +} \ No newline at end of file diff --git a/src/Rules.Framework/Builder/Generic/RuleBuilder.cs b/src/Rules.Framework/Builder/Generic/RuleBuilder.cs new file mode 100644 index 00000000..bcda47ad --- /dev/null +++ b/src/Rules.Framework/Builder/Generic/RuleBuilder.cs @@ -0,0 +1,112 @@ +namespace Rules.Framework.Builder.Generic +{ + using System; + using System.Linq; + using Rules.Framework; + using Rules.Framework.Builder.Validation; + using Rules.Framework.Generic; + using Rules.Framework.Serialization; + + internal sealed class RuleBuilder : IRuleBuilder + { + private readonly GenericRuleValidator genericRuleValidator = GenericRuleValidator.Instance; + private readonly RuleBuilder ruleBuilder; + + public RuleBuilder() + { + this.ruleBuilder = new RuleBuilder(); + } + + public RuleBuilderResult Build() + { + var ruleBuilderResult = this.ruleBuilder.Build(); + + if (ruleBuilderResult.IsSuccess) + { + var genericRule = new Rule(ruleBuilderResult.Rule); + var validationResult = this.genericRuleValidator.Validate(genericRule); + if (validationResult.IsValid) + { + return RuleBuilderResult.Success(genericRule); + } + + return RuleBuilderResult.Failure(validationResult.Errors.Select(ve => ve.ErrorMessage).ToList()); + } + + return RuleBuilderResult.Failure(ruleBuilderResult.Errors); + } + + public IRuleBuilder WithActive(bool active) + { + this.ruleBuilder.WithActive(active); + + return this; + } + + public IRuleBuilder WithCondition(IConditionNode condition) + { + this.ruleBuilder.WithCondition(condition); + + return this; + } + + public IRuleBuilder WithCondition( + Func, IConditionNode> conditionFunc) + { + var rootConditionNodeBuilder = new RootConditionNodeBuilder(); + + var condition = conditionFunc.Invoke(rootConditionNodeBuilder); + + return this.WithCondition(condition); + } + + public IRuleBuilder WithCondition( + TConditionType conditionType, Operators condOperator, TDataType operand) + { + var rootConditionNodeBuilder = new RootConditionNodeBuilder(); + + var valueCondition = rootConditionNodeBuilder.Value(conditionType, condOperator, operand); + + return this.WithCondition(valueCondition); + } + + public IRuleBuilder WithContent(TContentType contentType, object content) + { + this.ruleBuilder.WithContent(GenericConversions.Convert(contentType), content); + + return this; + } + + public IRuleBuilder WithDateBegin(DateTime dateBegin) + { + this.ruleBuilder.WithDateBegin(dateBegin); + + return this; + } + + public IRuleBuilder WithDatesInterval(DateTime dateBegin, DateTime? dateEnd) + { + this.ruleBuilder.WithDatesInterval(dateBegin, dateEnd); + + return this; + } + + public IRuleBuilder WithName(string name) + { + this.ruleBuilder.WithName(name); + + return this; + } + + public IRuleBuilder WithSerializedContent( + TContentType contentType, + object serializedContent, + IContentSerializationProvider contentSerializationProvider) + { + var contentTypeAsString = GenericConversions.Convert(contentType); + this.ruleBuilder.WithSerializedContent(contentTypeAsString, serializedContent, contentSerializationProvider); + + return this; + } + } +} \ No newline at end of file diff --git a/src/Rules.Framework/Builder/Generic/RuleBuilderResult.cs b/src/Rules.Framework/Builder/Generic/RuleBuilderResult.cs new file mode 100644 index 00000000..08b375c9 --- /dev/null +++ b/src/Rules.Framework/Builder/Generic/RuleBuilderResult.cs @@ -0,0 +1,62 @@ +namespace Rules.Framework.Builder.Generic +{ + using System.Collections.Generic; + using System.Linq; + using Rules.Framework.Generic; + + /// + /// Contains the results information from a generic rule build operation. + /// + public class RuleBuilderResult : RuleBuilderResultBase + { + /// + /// Initializes a new instance of the class. + /// + /// if set to true [is success]. + /// The rule. + /// The errors. + internal RuleBuilderResult(bool isSuccess, Rule rule, IEnumerable errors) + : base(isSuccess, errors) + { + this.Rule = rule; + } + + /// + /// Gets the rule. + /// + /// The rule. + public Rule Rule { get; } + + /// + /// Creates a result marked with failure. + /// + /// The errors. + /// + /// errors + public static RuleBuilderResult Failure(IEnumerable errors) + { + if (errors is null) + { + throw new System.ArgumentNullException(nameof(errors)); + } + + return new RuleBuilderResult(isSuccess: false, null!, errors); + } + + /// + /// Creates a result marked with success. + /// + /// The rule. + /// + /// rule + public static RuleBuilderResult Success(Rule rule) + { + if (rule is null) + { + throw new System.ArgumentNullException(nameof(rule)); + } + + return new RuleBuilderResult(isSuccess: true, rule, Enumerable.Empty()); + } + } +} \ No newline at end of file diff --git a/src/Rules.Framework/Builder/IConditionTypeSelector.cs b/src/Rules.Framework/Builder/IConditionTypeSelector.cs deleted file mode 100644 index ed961aa9..00000000 --- a/src/Rules.Framework/Builder/IConditionTypeSelector.cs +++ /dev/null @@ -1,16 +0,0 @@ -namespace Rules.Framework.Builder -{ - /// - /// Exposes the interface contract for selecting a rules engine condition type. - /// - /// The content type that allows to categorize rules. - public interface IConditionTypeSelector - { - /// - /// Sets the condition type to use on the set of conditions to supply to rules engine, according to . - /// - /// The condition type that allows to filter rules based on a set of conditions. - /// a rules data source selector. - IRulesDataSourceSelector WithConditionType(); - } -} \ No newline at end of file diff --git a/src/Rules.Framework/Builder/IConfiguredRulesEngineBuilder.cs b/src/Rules.Framework/Builder/IConfiguredRulesEngineBuilder.cs index b0ad7e1e..9c6cbd5b 100644 --- a/src/Rules.Framework/Builder/IConfiguredRulesEngineBuilder.cs +++ b/src/Rules.Framework/Builder/IConfiguredRulesEngineBuilder.cs @@ -3,23 +3,24 @@ namespace Rules.Framework.Builder using System; /// - /// Exposes the interface contract for a configured rules engine builder. Allows to perform additional optional configurations and finish rules engine build. + /// Exposes the interface contract for a configured rules engine builder. Allows to perform + /// additional optional configurations and finish rules engine build. /// - /// The content type that allows to categorize rules. - /// The condition type that allows to filter rules based on a set of conditions. - public interface IConfiguredRulesEngineBuilder + public interface IConfiguredRulesEngineBuilder { /// /// Builds a rules engine instance using all supplied configuration options. /// /// the rules engine instance. - RulesEngine Build(); + IRulesEngine Build(); /// /// Allows configuration of rules engine options. /// - /// the action with configuration logic for rules engine options. + /// + /// the action with configuration logic for rules engine options. + /// /// the configured rules engine builder. - IConfiguredRulesEngineBuilder Configure(Action configurationAction); + IConfiguredRulesEngineBuilder Configure(Action configurationAction); } } \ No newline at end of file diff --git a/src/Rules.Framework/Builder/IContentTypeSelector.cs b/src/Rules.Framework/Builder/IContentTypeSelector.cs deleted file mode 100644 index 58b506a6..00000000 --- a/src/Rules.Framework/Builder/IContentTypeSelector.cs +++ /dev/null @@ -1,15 +0,0 @@ -namespace Rules.Framework.Builder -{ - /// - /// Exposes the interface contract for selecting a rules engine content type. - /// - public interface IContentTypeSelector - { - /// - /// Sets the rules engine content type to use, according to supplied . - /// - /// The content type that allows to categorize rules. - /// a condition type selector. - IConditionTypeSelector WithContentType(); - } -} \ No newline at end of file diff --git a/src/Rules.Framework/Builder/IFluentComposedConditionNodeBuilder.cs b/src/Rules.Framework/Builder/IFluentComposedConditionNodeBuilder.cs index 3d6ecaff..4b573d9a 100644 --- a/src/Rules.Framework/Builder/IFluentComposedConditionNodeBuilder.cs +++ b/src/Rules.Framework/Builder/IFluentComposedConditionNodeBuilder.cs @@ -1,41 +1,40 @@ namespace Rules.Framework.Builder { using System; - using Rules.Framework.Core; + using Rules.Framework; /// /// Fluent builder for composed condition nodes. /// - /// The type of the condition type. - public interface IFluentComposedConditionNodeBuilder + public interface IFluentComposedConditionNodeBuilder { /// /// Adds a And composed condition to the fluent condition node builder. /// /// The function containing the logic for the new condition. /// - IFluentComposedConditionNodeBuilder And( - Func, IFluentComposedConditionNodeBuilder> conditionFunc); + IFluentComposedConditionNodeBuilder And( + Func conditionFunc); /// /// Builds the composed condition node. /// /// - IConditionNode Build(); + IConditionNode Build(); /// /// Adds a Condition to the fluent condition node builder. /// /// The condition node. - IFluentComposedConditionNodeBuilder Condition(IConditionNode conditionNode); + IFluentComposedConditionNodeBuilder Condition(IConditionNode conditionNode); /// /// Adds a Or composed condition to the fluent condition node builder. /// /// The function containing the logic for the new condition. /// - IFluentComposedConditionNodeBuilder Or( - Func, IFluentComposedConditionNodeBuilder> conditionFunc); + IFluentComposedConditionNodeBuilder Or( + Func conditionFunc); /// /// Adds a Value condition to the fluent condition node builder. @@ -44,6 +43,6 @@ IFluentComposedConditionNodeBuilder Or( /// The condition operator. /// The condition operand. /// - IFluentComposedConditionNodeBuilder Value(TConditionType conditionType, Operators condOperator, TDataType operand); + IFluentComposedConditionNodeBuilder Value(string conditionType, Operators condOperator, TDataType operand); } } \ No newline at end of file diff --git a/src/Rules.Framework/Builder/IRootConditionNodeBuilder.cs b/src/Rules.Framework/Builder/IRootConditionNodeBuilder.cs index 7c04d4b6..65f6d523 100644 --- a/src/Rules.Framework/Builder/IRootConditionNodeBuilder.cs +++ b/src/Rules.Framework/Builder/IRootConditionNodeBuilder.cs @@ -1,35 +1,34 @@ namespace Rules.Framework.Builder { using System; - using Rules.Framework.Core; + using Rules.Framework; /// /// Builder for the root condition node. /// - /// The type of the condition type. - public interface IRootConditionNodeBuilder + public interface IRootConditionNodeBuilder { /// /// Sets a And composed condition to the root condition node builder. /// /// The function containing the logic for the root condition. /// - IConditionNode And( - Func, IFluentComposedConditionNodeBuilder> conditionFunc); + IConditionNode And( + Func conditionFunc); /// /// Sets a Condition to the root condition node builder. /// /// The condition node. - IConditionNode Condition(IConditionNode conditionNode); + IConditionNode Condition(IConditionNode conditionNode); /// /// Sets a Or composed condition to the root condition node builder. /// /// The function containing the logic for the root condition. /// - IConditionNode Or( - Func, IFluentComposedConditionNodeBuilder> conditionFunc); + IConditionNode Or( + Func conditionFunc); /// /// Sets a Value condition to the root condition node builder. @@ -38,6 +37,6 @@ IConditionNode Or( /// The condition operator. /// The condition operand. /// - IConditionNode Value(TConditionType conditionType, Operators condOperator, TDataType operand); + IConditionNode Value(string conditionType, Operators condOperator, TDataType operand); } } \ No newline at end of file diff --git a/src/Rules.Framework/Builder/IRuleBuilder.cs b/src/Rules.Framework/Builder/IRuleBuilder.cs index 31e727d0..ab07c428 100644 --- a/src/Rules.Framework/Builder/IRuleBuilder.cs +++ b/src/Rules.Framework/Builder/IRuleBuilder.cs @@ -1,35 +1,32 @@ namespace Rules.Framework.Builder { using System; - using Rules.Framework.Core; using Rules.Framework.Serialization; /// /// Builder to create a new rule. /// - /// The type of the content type. - /// The type of the condition type. - public interface IRuleBuilder + public interface IRuleBuilder { /// /// Builds the new rule. /// /// - RuleBuilderResult Build(); + RuleBuilderResult Build(); /// /// Sets the new rule with the specified active status. /// /// The active status. /// - IRuleBuilder WithActive(bool active); + IRuleBuilder WithActive(bool active); /// /// Sets the new rule with the specified root condition. /// /// The condition. /// - IRuleBuilder WithCondition(IConditionNode condition); + IRuleBuilder WithCondition(IConditionNode condition); /// /// Sets the new rule with a value condition with the specified parameters. @@ -39,15 +36,15 @@ public interface IRuleBuilder /// The operator. /// The operand. /// - IRuleBuilder WithCondition(TConditionType conditionType, Operators condOperator, TDataType operand); + IRuleBuilder WithCondition(string conditionType, Operators condOperator, TDataType operand); /// /// Sets the new rule with the specified root condition. /// /// The condition func. /// - IRuleBuilder WithCondition( - Func, IConditionNode> conditionFunc); + IRuleBuilder WithCondition( + Func conditionFunc); /// /// Sets the new rule with the specified content. @@ -55,14 +52,14 @@ IRuleBuilder WithCondition( /// The content type. /// The content. /// - IRuleBuilder WithContent(TContentType contentType, object content); + IRuleBuilder WithContent(string contentType, object content); /// /// Sets the new rule with the specified date begin. /// /// The date begin. /// - IRuleBuilder WithDateBegin(DateTime dateBegin); + IRuleBuilder WithDateBegin(DateTime dateBegin); /// /// Sets the new rule with the specified dates interval. @@ -70,14 +67,14 @@ IRuleBuilder WithCondition( /// The date begin. /// The date end. /// - IRuleBuilder WithDatesInterval(DateTime dateBegin, DateTime? dateEnd); + IRuleBuilder WithDatesInterval(DateTime dateBegin, DateTime? dateEnd); /// ///Sets the new rule with the specified name. /// /// The name. /// - IRuleBuilder WithName(string name); + IRuleBuilder WithName(string name); /// /// Sets the new rule with the specified serialized content. @@ -87,9 +84,9 @@ IRuleBuilder WithCondition( /// The content serialization provider. /// /// ruleBuilder or contentSerializationProvider - IRuleBuilder WithSerializedContent( - TContentType contentType, + IRuleBuilder WithSerializedContent( + string contentType, object serializedContent, - IContentSerializationProvider contentSerializationProvider); + IContentSerializationProvider contentSerializationProvider); } } \ No newline at end of file diff --git a/src/Rules.Framework/Builder/IRulesDataSourceSelector.cs b/src/Rules.Framework/Builder/IRulesDataSourceSelector.cs index 89dbc563..4fd6b502 100644 --- a/src/Rules.Framework/Builder/IRulesDataSourceSelector.cs +++ b/src/Rules.Framework/Builder/IRulesDataSourceSelector.cs @@ -1,17 +1,15 @@ namespace Rules.Framework.Builder { /// - /// The interface contract for a rules data source for rules with previously specified and . + /// The interface contract for a rules data source for rules. /// - /// The content type that allows to categorize rules. - /// The condition type that allows to filter rules based on a set of conditions. - public interface IRulesDataSourceSelector + public interface IRulesDataSourceSelector { /// - /// Sets the rules data source for rules with previously specified and . + /// Sets the rules data source for rules. /// /// the rules data source. /// a configured rules engine builder. - IConfiguredRulesEngineBuilder SetDataSource(IRulesDataSource rulesDataSource); + IConfiguredRulesEngineBuilder SetDataSource(IRulesDataSource rulesDataSource); } } \ No newline at end of file diff --git a/src/Rules.Framework/Builder/RootConditionNodeBuilder.cs b/src/Rules.Framework/Builder/RootConditionNodeBuilder.cs index 9ff83fad..1b6a1922 100644 --- a/src/Rules.Framework/Builder/RootConditionNodeBuilder.cs +++ b/src/Rules.Framework/Builder/RootConditionNodeBuilder.cs @@ -1,31 +1,33 @@ namespace Rules.Framework.Builder { using System; - using Rules.Framework.Core; + using Rules.Framework; + using Rules.Framework.Generic; - internal sealed class RootConditionNodeBuilder : IRootConditionNodeBuilder + internal sealed class RootConditionNodeBuilder : IRootConditionNodeBuilder { - public IConditionNode And( - Func, IFluentComposedConditionNodeBuilder> conditionFunc) + public IConditionNode And( + Func conditionFunc) { return ConditionNodeFactory.CreateComposedNode(LogicalOperators.And, conditionFunc); } - public IConditionNode Condition(IConditionNode conditionNode) + public IConditionNode Condition(IConditionNode conditionNode) { return conditionNode; } - public IConditionNode Or( - Func, IFluentComposedConditionNodeBuilder> conditionFunc) + public IConditionNode Or( + Func conditionFunc) { return ConditionNodeFactory.CreateComposedNode(LogicalOperators.Or, conditionFunc); } - public IConditionNode Value( - TConditionType conditionType, Operators condOperator, TDataType operand) + public IConditionNode Value( + string conditionType, Operators condOperator, TDataType operand) { - return ConditionNodeFactory.CreateValueNode(conditionType, condOperator, operand); + var conditionTypeAsString = GenericConversions.Convert(conditionType); + return ConditionNodeFactory.CreateValueNode(conditionTypeAsString, condOperator, operand); } } } \ No newline at end of file diff --git a/src/Rules.Framework/Builder/RuleBuilder.cs b/src/Rules.Framework/Builder/RuleBuilder.cs index 506bbc42..a687a4fd 100644 --- a/src/Rules.Framework/Builder/RuleBuilder.cs +++ b/src/Rules.Framework/Builder/RuleBuilder.cs @@ -3,24 +3,32 @@ namespace Rules.Framework.Builder using System; using System.Linq; using Rules.Framework.Builder.Validation; - using Rules.Framework.Core; using Rules.Framework.Serialization; - internal sealed class RuleBuilder : IRuleBuilder + internal sealed class RuleBuilder : IRuleBuilder { - private readonly RuleValidator ruleValidator = RuleValidator.Instance; + private readonly RuleValidator ruleValidator = RuleValidator.Instance; + private bool? active; - private ContentContainer contentContainer; + + private ContentContainer contentContainer; + + private string contentType; + private DateTime dateBegin; + private DateTime? dateEnd; + private string name; - private IConditionNode rootCondition; - public RuleBuilderResult Build() + private IConditionNode rootCondition; + + public RuleBuilderResult Build() { - var rule = new Rule + var rule = new Rule { ContentContainer = this.contentContainer, + ContentType = this.contentType, DateBegin = this.dateBegin, DateEnd = this.dateEnd, Name = this.name, @@ -35,58 +43,58 @@ public RuleBuilderResult Build() return RuleBuilderResult.Success(rule); } - return RuleBuilderResult.Failure(validationResult.Errors.Select(ve => ve.ErrorMessage).ToList()); + return RuleBuilderResult.Failure(validationResult.Errors.Select(ve => ve.ErrorMessage).ToList()); } - public IRuleBuilder WithActive(bool active) + public IRuleBuilder WithActive(bool active) { this.active = active; return this; } - public IRuleBuilder WithCondition(IConditionNode condition) + public IRuleBuilder WithCondition(IConditionNode condition) { this.rootCondition = condition; return this; } - public IRuleBuilder WithCondition( - Func, IConditionNode> conditionFunc) + public IRuleBuilder WithCondition( + Func conditionFunc) { - var rootConditionNodeBuilder = new RootConditionNodeBuilder(); + var rootConditionNodeBuilder = new RootConditionNodeBuilder(); var condition = conditionFunc.Invoke(rootConditionNodeBuilder); return this.WithCondition(condition); } - public IRuleBuilder WithCondition( - TConditionType conditionType, Operators condOperator, TDataType operand) + public IRuleBuilder WithCondition( + string conditionType, Operators condOperator, TDataType operand) { - var rootConditionNodeBuilder = new RootConditionNodeBuilder(); + var rootConditionNodeBuilder = new RootConditionNodeBuilder(); var valueCondition = rootConditionNodeBuilder.Value(conditionType, condOperator, operand); - return this.WithCondition(valueCondition); } - public IRuleBuilder WithContent(TContentType contentType, object content) + public IRuleBuilder WithContent(string contentType, object content) { - this.contentContainer = new ContentContainer(contentType, _ => content); + this.contentType = contentType; + this.contentContainer = new ContentContainer(_ => content); return this; } - public IRuleBuilder WithDateBegin(DateTime dateBegin) + public IRuleBuilder WithDateBegin(DateTime dateBegin) { this.dateBegin = dateBegin; return this; } - public IRuleBuilder WithDatesInterval(DateTime dateBegin, DateTime? dateEnd) + public IRuleBuilder WithDatesInterval(DateTime dateBegin, DateTime? dateEnd) { this.dateBegin = dateBegin; this.dateEnd = dateEnd; @@ -94,24 +102,24 @@ public IRuleBuilder WithDatesInterval(DateTime dat return this; } - public IRuleBuilder WithName(string name) + public IRuleBuilder WithName(string name) { this.name = name; - return this; } - public IRuleBuilder WithSerializedContent( - TContentType contentType, + public IRuleBuilder WithSerializedContent( + string contentType, object serializedContent, - IContentSerializationProvider contentSerializationProvider) + IContentSerializationProvider contentSerializationProvider) { if (contentSerializationProvider is null) { throw new ArgumentNullException(nameof(contentSerializationProvider)); } - this.contentContainer = new SerializedContentContainer(contentType, serializedContent, contentSerializationProvider); + this.contentType = contentType; + this.contentContainer = new SerializedContentContainer(contentType, serializedContent, contentSerializationProvider); return this; } diff --git a/src/Rules.Framework/Builder/RuleBuilderResult.cs b/src/Rules.Framework/Builder/RuleBuilderResult.cs index be8ea684..2c005089 100644 --- a/src/Rules.Framework/Builder/RuleBuilderResult.cs +++ b/src/Rules.Framework/Builder/RuleBuilderResult.cs @@ -2,27 +2,44 @@ namespace Rules.Framework.Builder { using System.Collections.Generic; using System.Linq; - using Rules.Framework.Core; /// - /// Allows creation of a new . + /// Contains the results information from a non-generic rule build operation. /// - public static class RuleBuilderResult + public class RuleBuilderResult : RuleBuilderResultBase { + /// + /// Initializes a new instance of the class. + /// + /// if set to true [is success]. + /// The rule. + /// The errors. + internal RuleBuilderResult(bool isSuccess, Rule rule, IEnumerable errors) + : base(isSuccess, errors) + { + this.Rule = rule; + } + + /// + /// Gets the rule. + /// + /// The rule. + public Rule Rule { get; } + /// /// Creates a result marked with failure. /// /// The errors. /// /// errors - public static RuleBuilderResult Failure(IEnumerable errors) + public static RuleBuilderResult Failure(IEnumerable errors) { if (errors is null) { throw new System.ArgumentNullException(nameof(errors)); } - return new RuleBuilderResult(isSuccess: false, null!, errors); + return new RuleBuilderResult(isSuccess: false, null!, errors); } /// @@ -31,51 +48,14 @@ public static RuleBuilderResult FailureThe rule. /// /// rule - public static RuleBuilderResult Success(Rule rule) + public static RuleBuilderResult Success(Rule rule) { if (rule is null) { throw new System.ArgumentNullException(nameof(rule)); } - return new RuleBuilderResult(isSuccess: true, rule, Enumerable.Empty()); - } - } - - /// - /// Contains the results information from a rule build operation. - /// - /// The type of the content type. - /// The type of the condition type. - public class RuleBuilderResult - { - /// - /// Initializes a new instance of the class. - /// - internal RuleBuilderResult(bool isSuccess, Rule rule, IEnumerable errors) - { - this.IsSuccess = isSuccess; - this.Rule = rule; - this.Errors = errors; + return new RuleBuilderResult(isSuccess: true, rule, Enumerable.Empty()); } - - /// - /// Gets the errors. - /// - /// The errors. - public IEnumerable Errors { get; } - - /// - /// Gets a value indicating whether rule was built successfuly without validation errors. - /// - /// true if rule was built; otherwise, false. - public bool IsSuccess { get; } - - /// - /// Gets the rule. - /// - /// The rule. - public Rule Rule { get; } } } \ No newline at end of file diff --git a/src/Rules.Framework/Builder/RuleBuilderResultBase.cs b/src/Rules.Framework/Builder/RuleBuilderResultBase.cs new file mode 100644 index 00000000..010a2f95 --- /dev/null +++ b/src/Rules.Framework/Builder/RuleBuilderResultBase.cs @@ -0,0 +1,33 @@ +namespace Rules.Framework.Builder +{ + using System.Collections.Generic; + + /// + /// Contains the common results information from a rule build operation. + /// + public class RuleBuilderResultBase + { + /// + /// Initializes a new instance of the class. + /// + /// if set to true [is success]. + /// The errors. + protected RuleBuilderResultBase(bool isSuccess, IEnumerable errors) + { + this.IsSuccess = isSuccess; + this.Errors = errors; + } + + /// + /// Gets the errors. + /// + /// The errors. + public IEnumerable Errors { get; } + + /// + /// Gets a value indicating whether rule was built successfuly without validation errors. + /// + /// true if rule was built; otherwise, false. + public bool IsSuccess { get; } + } +} \ No newline at end of file diff --git a/src/Rules.Framework/Builder/RulesEngineOptionsValidator.cs b/src/Rules.Framework/Builder/RulesEngineOptionsValidator.cs index 19a639b4..9c159307 100644 --- a/src/Rules.Framework/Builder/RulesEngineOptionsValidator.cs +++ b/src/Rules.Framework/Builder/RulesEngineOptionsValidator.cs @@ -3,7 +3,7 @@ namespace Rules.Framework.Builder using System; using System.Collections.Generic; using System.Globalization; - using Rules.Framework.Core; + using Rules.Framework; internal static class RulesEngineOptionsValidator { diff --git a/src/Rules.Framework/Builder/RulesEngineSelectors.cs b/src/Rules.Framework/Builder/RulesEngineSelectors.cs index b105af8f..87da7b4e 100644 --- a/src/Rules.Framework/Builder/RulesEngineSelectors.cs +++ b/src/Rules.Framework/Builder/RulesEngineSelectors.cs @@ -4,27 +4,16 @@ namespace Rules.Framework.Builder internal static class RulesEngineSelectors { - internal sealed class ConditionTypeSelector : IConditionTypeSelector + internal sealed class RulesDataSourceSelector : IRulesDataSourceSelector { - public IRulesDataSourceSelector WithConditionType() - => new RulesDataSourceSelector(); - } - - internal sealed class ContentTypeSelector : IContentTypeSelector - { - public IConditionTypeSelector WithContentType() => new ConditionTypeSelector(); - } - - internal sealed class RulesDataSourceSelector : IRulesDataSourceSelector - { - public IConfiguredRulesEngineBuilder SetDataSource(IRulesDataSource rulesDataSource) + public IConfiguredRulesEngineBuilder SetDataSource(IRulesDataSource rulesDataSource) { if (rulesDataSource == null) { throw new ArgumentNullException(nameof(rulesDataSource)); } - return new ConfiguredRulesEngineBuilder(rulesDataSource); + return new ConfiguredRulesEngineBuilder(rulesDataSource); } } } diff --git a/src/Rules.Framework/Builder/Validation/ComposedConditionNodeValidator.cs b/src/Rules.Framework/Builder/Validation/ComposedConditionNodeValidator.cs index 3273b037..af1db45b 100644 --- a/src/Rules.Framework/Builder/Validation/ComposedConditionNodeValidator.cs +++ b/src/Rules.Framework/Builder/Validation/ComposedConditionNodeValidator.cs @@ -1,21 +1,21 @@ namespace Rules.Framework.Builder.Validation { using FluentValidation; - using Rules.Framework.Core; - using Rules.Framework.Core.ConditionNodes; + using Rules.Framework; + using Rules.Framework.ConditionNodes; - internal sealed class ComposedConditionNodeValidator : AbstractValidator> + internal sealed class ComposedConditionNodeValidator : AbstractValidator { - private readonly ValueConditionNodeValidator valueConditionNodeValidator; + private readonly ValueConditionNodeValidator valueConditionNodeValidator; public ComposedConditionNodeValidator() { - this.valueConditionNodeValidator = new ValueConditionNodeValidator(); + this.valueConditionNodeValidator = new ValueConditionNodeValidator(); - this.RuleFor(c => c.LogicalOperator).IsContainedOn(LogicalOperators.And, LogicalOperators.Or); + this.RuleFor(c => c.LogicalOperator).IsContainedOn(LogicalOperators.And, LogicalOperators.Or); this.RuleForEach(c => c.ChildConditionNodes) .NotNull() - .Custom((cn, cc) => cn.PerformValidation(new ConditionNodeValidationArgs> + .Custom((cn, cc) => cn.PerformValidation(new ConditionNodeValidationArgs { ComposedConditionNodeValidator = this, ValidationContext = cc, diff --git a/src/Rules.Framework/Builder/Validation/ConditionNodeValidationArgs.cs b/src/Rules.Framework/Builder/Validation/ConditionNodeValidationArgs.cs index 12626dbe..7f51687e 100644 --- a/src/Rules.Framework/Builder/Validation/ConditionNodeValidationArgs.cs +++ b/src/Rules.Framework/Builder/Validation/ConditionNodeValidationArgs.cs @@ -2,10 +2,10 @@ namespace Rules.Framework.Builder.Validation { using FluentValidation; - internal sealed class ConditionNodeValidationArgs + internal sealed class ConditionNodeValidationArgs { - public ComposedConditionNodeValidator ComposedConditionNodeValidator { get; set; } + public ComposedConditionNodeValidator ComposedConditionNodeValidator { get; set; } public ValidationContext ValidationContext { get; set; } - public ValueConditionNodeValidator ValueConditionNodeValidator { get; set; } + public ValueConditionNodeValidator ValueConditionNodeValidator { get; set; } } } \ No newline at end of file diff --git a/src/Rules.Framework/Builder/Validation/ConditionNodeValidationExtensions.cs b/src/Rules.Framework/Builder/Validation/ConditionNodeValidationExtensions.cs index c4418755..e20c6584 100644 --- a/src/Rules.Framework/Builder/Validation/ConditionNodeValidationExtensions.cs +++ b/src/Rules.Framework/Builder/Validation/ConditionNodeValidationExtensions.cs @@ -1,12 +1,13 @@ namespace Rules.Framework.Builder.Validation { using FluentValidation.Results; - using Rules.Framework.Core; - using Rules.Framework.Core.ConditionNodes; + using Rules.Framework.ConditionNodes; + using Rules.Framework.Generic; + using Rules.Framework.Generic.ConditionNodes; internal static class ConditionNodeValidationExtensions { - public static void PerformValidation(this IConditionNode conditionNode, ConditionNodeValidationArgs conditionNodeValidationArgs) + public static void PerformValidation(this IConditionNode conditionNode, GenericConditionNodeValidationArgs conditionNodeValidationArgs) { ValidationResult validationResult; switch (conditionNode) @@ -19,7 +20,33 @@ public static void PerformValidation(this IC return; default: - validationResult = conditionNodeValidationArgs.ValueConditionNodeValidator.Validate(conditionNode as ValueConditionNode); + validationResult = conditionNodeValidationArgs.ValueConditionNodeValidator.Validate((ValueConditionNode)conditionNode); + break; + } + + if (!validationResult.IsValid) + { + foreach (ValidationFailure validationFailure in validationResult.Errors) + { + conditionNodeValidationArgs.ValidationContext.AddFailure(validationFailure); + } + } + } + + public static void PerformValidation(this IConditionNode conditionNode, ConditionNodeValidationArgs conditionNodeValidationArgs) + { + ValidationResult validationResult; + switch (conditionNode) + { + case ComposedConditionNode composedConditionNode: + validationResult = conditionNodeValidationArgs.ComposedConditionNodeValidator.Validate(composedConditionNode); + break; + + case null: + return; + + default: + validationResult = conditionNodeValidationArgs.ValueConditionNodeValidator.Validate((ValueConditionNode)conditionNode); break; } diff --git a/src/Rules.Framework/Builder/Validation/GenericComposedConditionNodeValidator.cs b/src/Rules.Framework/Builder/Validation/GenericComposedConditionNodeValidator.cs new file mode 100644 index 00000000..4398682f --- /dev/null +++ b/src/Rules.Framework/Builder/Validation/GenericComposedConditionNodeValidator.cs @@ -0,0 +1,25 @@ +namespace Rules.Framework.Builder.Validation +{ + using FluentValidation; + using Rules.Framework; + using Rules.Framework.Generic.ConditionNodes; + + internal sealed class GenericComposedConditionNodeValidator : AbstractValidator> + { + private readonly GenericValueConditionNodeValidator valueConditionNodeValidator; + + public GenericComposedConditionNodeValidator() + { + this.valueConditionNodeValidator = new GenericValueConditionNodeValidator(); + + this.RuleForEach(c => c.ChildConditionNodes) + .NotNull() + .Custom((cn, cc) => cn.PerformValidation(new GenericConditionNodeValidationArgs> + { + ComposedConditionNodeValidator = this, + ValidationContext = cc, + ValueConditionNodeValidator = this.valueConditionNodeValidator + })); + } + } +} \ No newline at end of file diff --git a/src/Rules.Framework/Builder/Validation/GenericConditionNodeValidationArgs.cs b/src/Rules.Framework/Builder/Validation/GenericConditionNodeValidationArgs.cs new file mode 100644 index 00000000..c3785a30 --- /dev/null +++ b/src/Rules.Framework/Builder/Validation/GenericConditionNodeValidationArgs.cs @@ -0,0 +1,11 @@ +namespace Rules.Framework.Builder.Validation +{ + using FluentValidation; + + internal sealed class GenericConditionNodeValidationArgs + { + public GenericComposedConditionNodeValidator ComposedConditionNodeValidator { get; set; } + public ValidationContext ValidationContext { get; set; } + public GenericValueConditionNodeValidator ValueConditionNodeValidator { get; set; } + } +} \ No newline at end of file diff --git a/src/Rules.Framework/Builder/Validation/GenericRuleValidator.cs b/src/Rules.Framework/Builder/Validation/GenericRuleValidator.cs new file mode 100644 index 00000000..5ee00a96 --- /dev/null +++ b/src/Rules.Framework/Builder/Validation/GenericRuleValidator.cs @@ -0,0 +1,36 @@ +namespace Rules.Framework.Builder.Validation +{ + using FluentValidation; + using Rules.Framework.Generic; + + internal sealed class GenericRuleValidator : AbstractValidator> + { + private static GenericRuleValidator ruleValidator; + + private readonly GenericComposedConditionNodeValidator composedConditionNodeValidator; + + private readonly GenericValueConditionNodeValidator valueConditionNodeValidator; + + private GenericRuleValidator() + { + this.composedConditionNodeValidator = new GenericComposedConditionNodeValidator(); + this.valueConditionNodeValidator = new GenericValueConditionNodeValidator(); + this.RuleFor(r => r.RootCondition).Custom((cn, cc) => cn.PerformValidation(new GenericConditionNodeValidationArgs> + { + ComposedConditionNodeValidator = this.composedConditionNodeValidator, + ValidationContext = cc, + ValueConditionNodeValidator = this.valueConditionNodeValidator, + })); + } + + public static GenericRuleValidator Instance + { + get + { + ruleValidator ??= new GenericRuleValidator(); + + return ruleValidator; + } + } + } +} \ No newline at end of file diff --git a/src/Rules.Framework/Builder/Validation/GenericValueConditionNodeValidator.cs b/src/Rules.Framework/Builder/Validation/GenericValueConditionNodeValidator.cs new file mode 100644 index 00000000..96e27685 --- /dev/null +++ b/src/Rules.Framework/Builder/Validation/GenericValueConditionNodeValidator.cs @@ -0,0 +1,16 @@ +namespace Rules.Framework.Builder.Validation +{ + using FluentValidation; + using Rules.Framework.Generic.ConditionNodes; + + internal sealed class GenericValueConditionNodeValidator : AbstractValidator> + { + public GenericValueConditionNodeValidator() + { + this.RuleFor(c => c.ConditionType) + .NotEmpty() + .IsInEnum() + .When(c => c.ConditionType.GetType().IsEnum); + } + } +} \ No newline at end of file diff --git a/src/Rules.Framework/Builder/Validation/RuleValidator.cs b/src/Rules.Framework/Builder/Validation/RuleValidator.cs index 5cb99bfc..02d2ba46 100644 --- a/src/Rules.Framework/Builder/Validation/RuleValidator.cs +++ b/src/Rules.Framework/Builder/Validation/RuleValidator.cs @@ -1,41 +1,30 @@ namespace Rules.Framework.Builder.Validation { using FluentValidation; - using Rules.Framework.Core; - internal sealed class RuleValidator : AbstractValidator> + internal sealed class RuleValidator : AbstractValidator { - private static RuleValidator ruleValidator; + private readonly ComposedConditionNodeValidator composedConditionNodeValidator; - private readonly ComposedConditionNodeValidator composedConditionNodeValidator; - - private readonly ValueConditionNodeValidator valueConditionNodeValidator; + private readonly ValueConditionNodeValidator valueConditionNodeValidator; private RuleValidator() { - this.composedConditionNodeValidator = new ComposedConditionNodeValidator(); - this.valueConditionNodeValidator = new ValueConditionNodeValidator(); + this.composedConditionNodeValidator = new ComposedConditionNodeValidator(); + this.valueConditionNodeValidator = new ValueConditionNodeValidator(); this.RuleFor(r => r.ContentContainer).NotNull(); this.RuleFor(r => r.DateBegin).NotEmpty(); this.RuleFor(r => r.DateEnd).GreaterThanOrEqualTo(r => r.DateBegin).When(r => r.DateEnd != null); this.RuleFor(r => r.Name).NotNull().NotEmpty(); - this.RuleFor(r => r.RootCondition).Custom((cn, cc) => cn.PerformValidation(new ConditionNodeValidationArgs> + this.RuleFor(r => r.RootCondition).Custom((cn, cc) => cn.PerformValidation(new ConditionNodeValidationArgs { ComposedConditionNodeValidator = this.composedConditionNodeValidator, ValidationContext = cc, - ValueConditionNodeValidator = this.valueConditionNodeValidator + ValueConditionNodeValidator = this.valueConditionNodeValidator, })); } - public static RuleValidator Instance - { - get - { - ruleValidator ??= new RuleValidator(); - - return ruleValidator; - } - } + public static RuleValidator Instance { get; } = new RuleValidator(); } } \ No newline at end of file diff --git a/src/Rules.Framework/Builder/Validation/ValueConditionNodeValidator.cs b/src/Rules.Framework/Builder/Validation/ValueConditionNodeValidator.cs index d8281cfe..ab3cbcb9 100644 --- a/src/Rules.Framework/Builder/Validation/ValueConditionNodeValidator.cs +++ b/src/Rules.Framework/Builder/Validation/ValueConditionNodeValidator.cs @@ -2,17 +2,16 @@ namespace Rules.Framework.Builder.Validation { using System.Collections.Generic; using FluentValidation; - using Rules.Framework.Core; - using Rules.Framework.Core.ConditionNodes; + using Rules.Framework; + using Rules.Framework.ConditionNodes; - internal sealed class ValueConditionNodeValidator : AbstractValidator> + internal sealed class ValueConditionNodeValidator : AbstractValidator { public ValueConditionNodeValidator() { this.RuleFor(c => c.ConditionType) - .NotEmpty() - .IsInEnum() - .When(c => c.ConditionType.GetType().IsEnum); + .NotNull() + .NotEmpty(); this.RuleFor(c => c.DataType) .IsInEnum() diff --git a/src/Rules.Framework/Core/ConditionNodes/ComposedConditionNode.cs b/src/Rules.Framework/ConditionNodes/ComposedConditionNode.cs similarity index 77% rename from src/Rules.Framework/Core/ConditionNodes/ComposedConditionNode.cs rename to src/Rules.Framework/ConditionNodes/ComposedConditionNode.cs index d159c94e..a21beb41 100644 --- a/src/Rules.Framework/Core/ConditionNodes/ComposedConditionNode.cs +++ b/src/Rules.Framework/ConditionNodes/ComposedConditionNode.cs @@ -1,19 +1,19 @@ -namespace Rules.Framework.Core.ConditionNodes +namespace Rules.Framework.ConditionNodes { using System; using System.Collections.Generic; using System.Diagnostics; using System.Linq; + using Rules.Framework; + using Rules.Framework.Core; + using Rules.Framework.Generic.ConditionNodes; /// /// A composed condition node which aggregates a set of child condition nodes and defines a /// logical operator to apply to them. /// - /// - /// The condition type that allows to filter rules based on a set of conditions. - /// [DebuggerDisplay("Composed condition: apply {LogicalOperator.ToString(),nq} operator for {System.Linq.Enumerable.Count(ChildConditionNodes),nq} nodes")] - public class ComposedConditionNode : IConditionNode + public class ComposedConditionNode : IConditionNode { /// /// Creates a new . @@ -22,7 +22,7 @@ public class ComposedConditionNode : IConditionNodethe set of child condition nodes. public ComposedConditionNode( LogicalOperators logicalOperator, - IEnumerable> childConditionNodes) + IEnumerable childConditionNodes) : this(logicalOperator, childConditionNodes, new PropertiesDictionary(Constants.DefaultPropertiesDictionarySize)) { } @@ -35,7 +35,7 @@ public ComposedConditionNode( /// the properties. public ComposedConditionNode( LogicalOperators logicalOperator, - IEnumerable> childConditionNodes, + IEnumerable childConditionNodes, IDictionary properties) { this.LogicalOperator = logicalOperator; @@ -46,7 +46,7 @@ public ComposedConditionNode( /// /// Gets the child condition nodes. /// - public IEnumerable> ChildConditionNodes { get; } + public IEnumerable ChildConditionNodes { get; } /// /// Gets the logical operator to apply between child condition nodes. @@ -62,8 +62,8 @@ public ComposedConditionNode( /// Clones the condition node into a different instance. /// /// - public IConditionNode Clone() - => new ComposedConditionNode( + public IConditionNode Clone() + => new ComposedConditionNode( this.LogicalOperator, this.ChildConditionNodes.Select(cn => cn.Clone()).ToList().AsReadOnly(), new PropertiesDictionary(this.Properties)); @@ -76,7 +76,7 @@ public IConditionNode Clone() /// true if the specified is equal to this instance; /// otherwise, false. /// - public override bool Equals(object obj) => obj is ComposedConditionNode node && EqualityComparer>>.Default.Equals(this.ChildConditionNodes, node.ChildConditionNodes) && this.LogicalOperator == node.LogicalOperator && EqualityComparer>.Default.Equals(this.Properties, node.Properties); + public override bool Equals(object obj) => obj is ComposedConditionNode node && EqualityComparer>.Default.Equals(this.ChildConditionNodes, node.ChildConditionNodes) && this.LogicalOperator == node.LogicalOperator && EqualityComparer>.Default.Equals(this.Properties, node.Properties); /// /// Returns a hash code for this instance. diff --git a/src/Rules.Framework/ConditionNodes/IValueConditionNode.cs b/src/Rules.Framework/ConditionNodes/IValueConditionNode.cs new file mode 100644 index 00000000..665fc6ea --- /dev/null +++ b/src/Rules.Framework/ConditionNodes/IValueConditionNode.cs @@ -0,0 +1,30 @@ +namespace Rules.Framework.ConditionNodes +{ + using Rules.Framework; + + /// + /// Defines the interface contract for a condition node based on a value comparison. + /// + public interface IValueConditionNode : IConditionNode + { + /// + /// Gets the condition node type. + /// + string ConditionType { get; } + + /// + /// Gets the condition node data type. + /// + DataTypes DataType { get; } + + /// + /// Gets the condition's operand. + /// + public object Operand { get; } + + /// + /// Gets the condition node operator. + /// + Operators Operator { get; } + } +} \ No newline at end of file diff --git a/src/Rules.Framework/Core/ConditionNodes/ValueConditionNode.cs b/src/Rules.Framework/ConditionNodes/ValueConditionNode.cs similarity index 73% rename from src/Rules.Framework/Core/ConditionNodes/ValueConditionNode.cs rename to src/Rules.Framework/ConditionNodes/ValueConditionNode.cs index ffd387a6..473ebfdf 100644 --- a/src/Rules.Framework/Core/ConditionNodes/ValueConditionNode.cs +++ b/src/Rules.Framework/ConditionNodes/ValueConditionNode.cs @@ -1,18 +1,18 @@ -namespace Rules.Framework.Core.ConditionNodes +namespace Rules.Framework.ConditionNodes { using System; using System.Collections.Generic; using System.Diagnostics; + using Rules.Framework; + using Rules.Framework.Core; + using Rules.Framework.Generic.ConditionNodes; /// /// A generic implementation for a valued condition node. /// - /// - /// The condition type that allows to filter rules based on a set of conditions. - /// - /// - [DebuggerDisplay("{DataType.ToString(),nq} condition: <{ConditionType.ToString(),nq}> {Operator} {Operand}")] - public class ValueConditionNode : IValueConditionNode + /// + [DebuggerDisplay("{DataType.ToString(),nq} condition: <{ConditionType,nq}> {Operator} {Operand}")] + public class ValueConditionNode : IValueConditionNode { /// /// Initializes a new instance of the class. @@ -21,7 +21,7 @@ public class ValueConditionNode : IValueConditionNodeType of the condition. /// The operator. /// The operand. - public ValueConditionNode(DataTypes dataType, TConditionType conditionType, Operators @operator, object operand) + public ValueConditionNode(DataTypes dataType, string conditionType, Operators @operator, object operand) : this(dataType, conditionType, @operator, operand, new PropertiesDictionary(Constants.DefaultPropertiesDictionarySize)) { } @@ -34,7 +34,7 @@ public ValueConditionNode(DataTypes dataType, TConditionType conditionType, Oper /// The operator. /// The operand. /// The properties. - public ValueConditionNode(DataTypes dataType, TConditionType conditionType, Operators @operator, object operand, IDictionary properties) + public ValueConditionNode(DataTypes dataType, string conditionType, Operators @operator, object operand, IDictionary properties) { this.ConditionType = conditionType; this.DataType = dataType; @@ -46,7 +46,7 @@ public ValueConditionNode(DataTypes dataType, TConditionType conditionType, Oper /// /// Gets the condition node type. /// - public TConditionType ConditionType { get; } + public string ConditionType { get; } /// /// Gets the condition node data type. @@ -78,8 +78,8 @@ public ValueConditionNode(DataTypes dataType, TConditionType conditionType, Oper /// Clones the condition node into a different instance. /// /// - public IConditionNode Clone() - => new ValueConditionNode( + public IConditionNode Clone() + => new ValueConditionNode( this.DataType, this.ConditionType, this.Operator, @@ -94,7 +94,7 @@ public IConditionNode Clone() /// true if the specified is equal to this instance; /// otherwise, false. /// - public override bool Equals(object obj) => obj is ValueConditionNode node && EqualityComparer.Default.Equals(this.ConditionType, node.ConditionType) && this.DataType == node.DataType && this.LogicalOperator == node.LogicalOperator && EqualityComparer.Default.Equals(this.Operand, node.Operand) && this.Operator == node.Operator && EqualityComparer>.Default.Equals(this.Properties, node.Properties); + public override bool Equals(object obj) => obj is ValueConditionNode node && StringComparer.Ordinal.Equals(this.ConditionType, node.ConditionType) && this.DataType == node.DataType && this.LogicalOperator == node.LogicalOperator && EqualityComparer.Default.Equals(this.Operand, node.Operand) && this.Operator == node.Operator && EqualityComparer>.Default.Equals(this.Properties, node.Properties); /// /// Returns a hash code for this instance. diff --git a/src/Rules.Framework/ConditionTypeExtractor.cs b/src/Rules.Framework/ConditionTypeExtractor.cs index eb52e57a..9850183e 100644 --- a/src/Rules.Framework/ConditionTypeExtractor.cs +++ b/src/Rules.Framework/ConditionTypeExtractor.cs @@ -3,17 +3,12 @@ namespace Rules.Framework using System; using System.Collections.Generic; using System.Linq; - using Rules.Framework.Core; - using Rules.Framework.Core.ConditionNodes; + using Rules.Framework.ConditionNodes; /// /// Extracts Conditions Types from a Group of Rules. /// - /// The content type that allows to categorize rules. - /// - /// The condition type that allows to filter rules based on a set of conditions. - /// - public class ConditionTypeExtractor : IConditionTypeExtractor + public class ConditionTypeExtractor : IConditionTypeExtractor { /// /// Get the unique condition types associated with rules of a specific content type. @@ -27,9 +22,9 @@ public class ConditionTypeExtractor : IConditionTy /// All rules matching supplied conditions are returned. /// /// the matched rule; otherwise, empty. - public IEnumerable GetConditionTypes(IEnumerable> matchedRules) + public IEnumerable GetConditionTypes(IEnumerable matchedRules) { - var conditionTypes = new HashSet(); + var conditionTypes = new HashSet(StringComparer.Ordinal); if (!matchedRules.Any()) { @@ -49,18 +44,18 @@ public IEnumerable GetConditionTypes(IEnumerable conditionNode, HashSet conditionTypes) + private static void VisitConditionNode(IConditionNode conditionNode, HashSet conditionTypes) { switch (conditionNode) { - case IValueConditionNode valueConditionNode: + case IValueConditionNode valueConditionNode: conditionTypes.Add(valueConditionNode.ConditionType); break; - case ComposedConditionNode composedConditionNode: + case ComposedConditionNode composedConditionNode: - foreach (IConditionNode childConditionNode in composedConditionNode.ChildConditionNodes) + foreach (IConditionNode childConditionNode in composedConditionNode.ChildConditionNodes) { VisitConditionNode(childConditionNode, conditionTypes); } diff --git a/src/Rules.Framework/Core/ContentContainer.cs b/src/Rules.Framework/ContentContainer.cs similarity index 61% rename from src/Rules.Framework/Core/ContentContainer.cs rename to src/Rules.Framework/ContentContainer.cs index b45cbee5..da7377cf 100644 --- a/src/Rules.Framework/Core/ContentContainer.cs +++ b/src/Rules.Framework/ContentContainer.cs @@ -1,31 +1,25 @@ -namespace Rules.Framework.Core +namespace Rules.Framework { using System; /// /// Defines a content container with lazily loaded content. /// - /// - public class ContentContainer + public class ContentContainer { private readonly Func getContentFunc; /// - /// Creates a new . + /// Creates a new . /// - /// the content type. - /// the function used to fetch content casted to provided type. - public ContentContainer(TContentType contentType, Func getContentFunc) + /// + /// the function used to fetch content casted to provided type. + /// + public ContentContainer(Func getContentFunc) { - this.ContentType = contentType; this.getContentFunc = getContentFunc; } - /// - /// Gets the content type. - /// - public TContentType ContentType { get; } - /// /// Gets the content from container casted/converted to specified . /// diff --git a/src/Rules.Framework/Core/ContentTypeException.cs b/src/Rules.Framework/ContentTypeException.cs similarity index 97% rename from src/Rules.Framework/Core/ContentTypeException.cs rename to src/Rules.Framework/ContentTypeException.cs index b33ac389..711907eb 100644 --- a/src/Rules.Framework/Core/ContentTypeException.cs +++ b/src/Rules.Framework/ContentTypeException.cs @@ -1,4 +1,4 @@ -namespace Rules.Framework.Core +namespace Rules.Framework { using System; using System.Diagnostics.CodeAnalysis; diff --git a/src/Rules.Framework/Core/PropertiesDictionary.cs b/src/Rules.Framework/Core/PropertiesDictionary.cs index 37914120..75904f27 100644 --- a/src/Rules.Framework/Core/PropertiesDictionary.cs +++ b/src/Rules.Framework/Core/PropertiesDictionary.cs @@ -4,6 +4,7 @@ namespace Rules.Framework.Core using System.Collections; using System.Collections.Generic; using System.Runtime.CompilerServices; + using Rules.Framework.Generic; /// /// A dictionary to hold the properties of a . diff --git a/src/Rules.Framework/Core/TypesCache.cs b/src/Rules.Framework/Core/TypesCache.cs new file mode 100644 index 00000000..60d3bda6 --- /dev/null +++ b/src/Rules.Framework/Core/TypesCache.cs @@ -0,0 +1,9 @@ +namespace Rules.Framework.Core +{ + using System; + + internal static class TypesCache + { + public static Type String { get; } = typeof(string); + } +} \ No newline at end of file diff --git a/src/Rules.Framework/Core/DataTypes.cs b/src/Rules.Framework/DataTypes.cs similarity index 97% rename from src/Rules.Framework/Core/DataTypes.cs rename to src/Rules.Framework/DataTypes.cs index 43ece110..30a30439 100644 --- a/src/Rules.Framework/Core/DataTypes.cs +++ b/src/Rules.Framework/DataTypes.cs @@ -1,4 +1,4 @@ -namespace Rules.Framework.Core +namespace Rules.Framework { /// /// Defines the supported data types a condition node can assume. diff --git a/src/Rules.Framework/Evaluation/Compiled/BuildValueConditionNodeExpressionArgs.cs b/src/Rules.Framework/Evaluation/Compiled/BuildValueConditionNodeExpressionArgs.cs index d507fed6..f5be24eb 100644 --- a/src/Rules.Framework/Evaluation/Compiled/BuildValueConditionNodeExpressionArgs.cs +++ b/src/Rules.Framework/Evaluation/Compiled/BuildValueConditionNodeExpressionArgs.cs @@ -3,7 +3,7 @@ namespace Rules.Framework.Evaluation.Compiled using System; using System.Collections.Generic; using System.Linq.Expressions; - using Rules.Framework.Core; + using Rules.Framework; internal struct BuildValueConditionNodeExpressionArgs : IEquatable { diff --git a/src/Rules.Framework/Evaluation/Compiled/CompilationRulesSourceMiddleware.cs b/src/Rules.Framework/Evaluation/Compiled/CompilationRulesSourceMiddleware.cs index ff12eecd..15ccf81b 100644 --- a/src/Rules.Framework/Evaluation/Compiled/CompilationRulesSourceMiddleware.cs +++ b/src/Rules.Framework/Evaluation/Compiled/CompilationRulesSourceMiddleware.cs @@ -5,37 +5,41 @@ namespace Rules.Framework.Evaluation.Compiled using Rules.Framework.Core; using Rules.Framework.Source; - internal sealed class CompilationRulesSourceMiddleware : IRulesSourceMiddleware + internal sealed class CompilationRulesSourceMiddleware : IRulesSourceMiddleware { - private readonly IRuleConditionsExpressionBuilder ruleConditionsExpressionBuilder; - private readonly IRulesDataSource rulesDataSource; + private readonly IRuleConditionsExpressionBuilder ruleConditionsExpressionBuilder; + private readonly IRulesDataSource rulesDataSource; public CompilationRulesSourceMiddleware( - IRuleConditionsExpressionBuilder ruleConditionsExpressionBuilder, - IRulesDataSource rulesDataSource) + IRuleConditionsExpressionBuilder ruleConditionsExpressionBuilder, + IRulesDataSource rulesDataSource) { this.ruleConditionsExpressionBuilder = ruleConditionsExpressionBuilder; this.rulesDataSource = rulesDataSource; } public async Task HandleAddRuleAsync( - AddRuleArgs args, - AddRuleDelegate next) + AddRuleArgs args, + AddRuleDelegate next) { this.TryCompile(args.Rule); await next.Invoke(args).ConfigureAwait(false); } - public async Task>> HandleGetRulesAsync( - GetRulesArgs args, - GetRulesDelegate next) + public Task HandleCreateContentTypeAsync(CreateContentTypeArgs args, CreateContentTypeDelegate next) => next.Invoke(args); + + public Task> HandleGetContentTypesAsync(GetContentTypesArgs args, GetContentTypesDelegate next) => next.Invoke(args); + + public async Task> HandleGetRulesAsync( + GetRulesArgs args, + GetRulesDelegate next) { var rules = await next.Invoke(args).ConfigureAwait(false); foreach (var rule in rules) { - bool compiled = this.TryCompile(rule); + var compiled = this.TryCompile(rule); if (compiled) { // Commit compilation result to data source, so that next time rule is loaded, @@ -47,15 +51,15 @@ public async Task>> HandleGetRule return rules; } - public async Task>> HandleGetRulesFilteredAsync( - GetRulesFilteredArgs args, - GetRulesFilteredDelegate next) + public async Task> HandleGetRulesFilteredAsync( + GetRulesFilteredArgs args, + GetRulesFilteredDelegate next) { var rules = await next.Invoke(args).ConfigureAwait(false); foreach (var rule in rules) { - bool compiled = this.TryCompile(rule); + var compiled = this.TryCompile(rule); if (compiled) { // Commit compilation result to data source, so that next time rule is loaded, @@ -68,15 +72,15 @@ public async Task>> HandleGetRule } public async Task HandleUpdateRuleAsync( - UpdateRuleArgs args, - UpdateRuleDelegate next) + UpdateRuleArgs args, + UpdateRuleDelegate next) { this.TryCompile(args.Rule); await next.Invoke(args).ConfigureAwait(false); } - private bool TryCompile(Rule rule) + private bool TryCompile(Rule rule) { var conditionNode = rule.RootCondition; diff --git a/src/Rules.Framework/Evaluation/Compiled/CompiledConditionsEvalEngine.cs b/src/Rules.Framework/Evaluation/Compiled/CompiledConditionsEvalEngine.cs index ee7c4f5d..9b54a69f 100644 --- a/src/Rules.Framework/Evaluation/Compiled/CompiledConditionsEvalEngine.cs +++ b/src/Rules.Framework/Evaluation/Compiled/CompiledConditionsEvalEngine.cs @@ -3,21 +3,22 @@ namespace Rules.Framework.Evaluation.Compiled using System; using System.Collections.Generic; using Rules.Framework.Core; + using Rules.Framework.Generic; - internal sealed class CompiledConditionsEvalEngine : IConditionsEvalEngine + internal sealed class CompiledConditionsEvalEngine : IConditionsEvalEngine { - private readonly IConditionsTreeAnalyzer conditionsTreeAnalyzer; + private readonly IConditionsTreeAnalyzer conditionsTreeAnalyzer; private readonly RulesEngineOptions rulesEngineOptions; public CompiledConditionsEvalEngine( - IConditionsTreeAnalyzer conditionsTreeAnalyzer, + IConditionsTreeAnalyzer conditionsTreeAnalyzer, RulesEngineOptions rulesEngineOptions) { this.conditionsTreeAnalyzer = conditionsTreeAnalyzer; this.rulesEngineOptions = rulesEngineOptions; } - public bool Eval(IConditionNode conditionNode, IDictionary conditions, EvaluationOptions evaluationOptions) + public bool Eval(IConditionNode conditionNode, IDictionary conditions, EvaluationOptions evaluationOptions) { if (evaluationOptions.ExcludeRulesWithoutSearchConditions && !this.conditionsTreeAnalyzer.AreAllSearchConditionsPresent(conditionNode, conditions)) { @@ -29,8 +30,8 @@ public bool Eval(IConditionNode conditionNode, IDictionary, bool>)conditionFuncAux; - var compiledConditionsEvaluationContext = new EvaluationContext( + var conditionFunc = (Func)conditionFuncAux; + var compiledConditionsEvaluationContext = new EvaluationContext( conditions, evaluationOptions.MatchMode, this.rulesEngineOptions.MissingConditionBehavior); diff --git a/src/Rules.Framework/Evaluation/Compiled/ConditionBuilders/CaseInsensitiveEndsWithOneToOneConditionExpressionBuilder.cs b/src/Rules.Framework/Evaluation/Compiled/ConditionBuilders/CaseInsensitiveEndsWithOneToOneConditionExpressionBuilder.cs index 6d673c20..ffbf3f9c 100644 --- a/src/Rules.Framework/Evaluation/Compiled/ConditionBuilders/CaseInsensitiveEndsWithOneToOneConditionExpressionBuilder.cs +++ b/src/Rules.Framework/Evaluation/Compiled/ConditionBuilders/CaseInsensitiveEndsWithOneToOneConditionExpressionBuilder.cs @@ -3,7 +3,7 @@ namespace Rules.Framework.Evaluation.Compiled.ConditionBuilders using System; using System.Linq.Expressions; using System.Reflection; - using Rules.Framework.Core; + using Rules.Framework; using Rules.Framework.Evaluation.Compiled.ExpressionBuilders; internal sealed class CaseInsensitiveEndsWithOneToOneConditionExpressionBuilder : IConditionExpressionBuilder diff --git a/src/Rules.Framework/Evaluation/Compiled/ConditionBuilders/CaseInsensitiveStartsWithOneToOneConditionExpressionBuilder.cs b/src/Rules.Framework/Evaluation/Compiled/ConditionBuilders/CaseInsensitiveStartsWithOneToOneConditionExpressionBuilder.cs index 87beb23a..85b6b670 100644 --- a/src/Rules.Framework/Evaluation/Compiled/ConditionBuilders/CaseInsensitiveStartsWithOneToOneConditionExpressionBuilder.cs +++ b/src/Rules.Framework/Evaluation/Compiled/ConditionBuilders/CaseInsensitiveStartsWithOneToOneConditionExpressionBuilder.cs @@ -3,7 +3,7 @@ namespace Rules.Framework.Evaluation.Compiled.ConditionBuilders using System; using System.Linq.Expressions; using System.Reflection; - using Rules.Framework.Core; + using Rules.Framework; using Rules.Framework.Evaluation.Compiled.ExpressionBuilders; internal sealed class CaseInsensitiveStartsWithOneToOneConditionExpressionBuilder : IConditionExpressionBuilder diff --git a/src/Rules.Framework/Evaluation/Compiled/ConditionBuilders/ConditionExpressionBuilderProvider.cs b/src/Rules.Framework/Evaluation/Compiled/ConditionBuilders/ConditionExpressionBuilderProvider.cs index 13ac327d..a3e25031 100644 --- a/src/Rules.Framework/Evaluation/Compiled/ConditionBuilders/ConditionExpressionBuilderProvider.cs +++ b/src/Rules.Framework/Evaluation/Compiled/ConditionBuilders/ConditionExpressionBuilderProvider.cs @@ -2,7 +2,7 @@ namespace Rules.Framework.Evaluation.Compiled.ConditionBuilders { using System; using System.Collections.Generic; - using Rules.Framework.Core; + using Rules.Framework; internal sealed class ConditionExpressionBuilderProvider : IConditionExpressionBuilderProvider { diff --git a/src/Rules.Framework/Evaluation/Compiled/ConditionBuilders/ContainsManyToOneConditionExpressionBuilder.cs b/src/Rules.Framework/Evaluation/Compiled/ConditionBuilders/ContainsManyToOneConditionExpressionBuilder.cs index 91f5873f..f17226b2 100644 --- a/src/Rules.Framework/Evaluation/Compiled/ConditionBuilders/ContainsManyToOneConditionExpressionBuilder.cs +++ b/src/Rules.Framework/Evaluation/Compiled/ConditionBuilders/ContainsManyToOneConditionExpressionBuilder.cs @@ -5,7 +5,7 @@ namespace Rules.Framework.Evaluation.Compiled.ConditionBuilders using System.Linq; using System.Linq.Expressions; using System.Reflection; - using Rules.Framework.Core; + using Rules.Framework; using Rules.Framework.Evaluation.Compiled.ExpressionBuilders; internal sealed class ContainsManyToOneConditionExpressionBuilder : IConditionExpressionBuilder diff --git a/src/Rules.Framework/Evaluation/Compiled/ConditionBuilders/ContainsOneToOneConditionExpressionBuilder.cs b/src/Rules.Framework/Evaluation/Compiled/ConditionBuilders/ContainsOneToOneConditionExpressionBuilder.cs index 00cc3b56..2374bdb5 100644 --- a/src/Rules.Framework/Evaluation/Compiled/ConditionBuilders/ContainsOneToOneConditionExpressionBuilder.cs +++ b/src/Rules.Framework/Evaluation/Compiled/ConditionBuilders/ContainsOneToOneConditionExpressionBuilder.cs @@ -4,7 +4,7 @@ namespace Rules.Framework.Evaluation.Compiled.ConditionBuilders using System.Linq; using System.Linq.Expressions; using System.Reflection; - using Rules.Framework.Core; + using Rules.Framework; using Rules.Framework.Evaluation.Compiled.ExpressionBuilders; internal sealed class ContainsOneToOneConditionExpressionBuilder : IConditionExpressionBuilder diff --git a/src/Rules.Framework/Evaluation/Compiled/ConditionBuilders/EndsWithOneToOneConditionExpressionBuilder.cs b/src/Rules.Framework/Evaluation/Compiled/ConditionBuilders/EndsWithOneToOneConditionExpressionBuilder.cs index 70e0ee57..3b8f6061 100644 --- a/src/Rules.Framework/Evaluation/Compiled/ConditionBuilders/EndsWithOneToOneConditionExpressionBuilder.cs +++ b/src/Rules.Framework/Evaluation/Compiled/ConditionBuilders/EndsWithOneToOneConditionExpressionBuilder.cs @@ -3,7 +3,7 @@ namespace Rules.Framework.Evaluation.Compiled.ConditionBuilders using System; using System.Linq.Expressions; using System.Reflection; - using Rules.Framework.Core; + using Rules.Framework; using Rules.Framework.Evaluation.Compiled.ExpressionBuilders; internal sealed class EndsWithOneToOneConditionExpressionBuilder : IConditionExpressionBuilder diff --git a/src/Rules.Framework/Evaluation/Compiled/ConditionBuilders/GreaterThanOneToOneConditionExpressionBuilder.cs b/src/Rules.Framework/Evaluation/Compiled/ConditionBuilders/GreaterThanOneToOneConditionExpressionBuilder.cs index 40a578c5..1071aa5c 100644 --- a/src/Rules.Framework/Evaluation/Compiled/ConditionBuilders/GreaterThanOneToOneConditionExpressionBuilder.cs +++ b/src/Rules.Framework/Evaluation/Compiled/ConditionBuilders/GreaterThanOneToOneConditionExpressionBuilder.cs @@ -2,7 +2,7 @@ namespace Rules.Framework.Evaluation.Compiled.ConditionBuilders { using System; using System.Linq.Expressions; - using Rules.Framework.Core; + using Rules.Framework; using Rules.Framework.Evaluation.Compiled.ExpressionBuilders; internal sealed class GreaterThanOneToOneConditionExpressionBuilder : IConditionExpressionBuilder diff --git a/src/Rules.Framework/Evaluation/Compiled/ConditionBuilders/GreaterThanOrEqualOneToOneConditionExpressionBuilder.cs b/src/Rules.Framework/Evaluation/Compiled/ConditionBuilders/GreaterThanOrEqualOneToOneConditionExpressionBuilder.cs index b658b96a..620a815f 100644 --- a/src/Rules.Framework/Evaluation/Compiled/ConditionBuilders/GreaterThanOrEqualOneToOneConditionExpressionBuilder.cs +++ b/src/Rules.Framework/Evaluation/Compiled/ConditionBuilders/GreaterThanOrEqualOneToOneConditionExpressionBuilder.cs @@ -2,7 +2,7 @@ namespace Rules.Framework.Evaluation.Compiled.ConditionBuilders { using System; using System.Linq.Expressions; - using Rules.Framework.Core; + using Rules.Framework; using Rules.Framework.Evaluation.Compiled.ExpressionBuilders; internal sealed class GreaterThanOrEqualOneToOneConditionExpressionBuilder : IConditionExpressionBuilder diff --git a/src/Rules.Framework/Evaluation/Compiled/ConditionBuilders/IConditionExpressionBuilderProvider.cs b/src/Rules.Framework/Evaluation/Compiled/ConditionBuilders/IConditionExpressionBuilderProvider.cs index 159d62d0..66e6f665 100644 --- a/src/Rules.Framework/Evaluation/Compiled/ConditionBuilders/IConditionExpressionBuilderProvider.cs +++ b/src/Rules.Framework/Evaluation/Compiled/ConditionBuilders/IConditionExpressionBuilderProvider.cs @@ -1,6 +1,6 @@ namespace Rules.Framework.Evaluation.Compiled.ConditionBuilders { - using Rules.Framework.Core; + using Rules.Framework; internal interface IConditionExpressionBuilderProvider { diff --git a/src/Rules.Framework/Evaluation/Compiled/ConditionBuilders/LesserThanOneToOneConditionExpressionBuilder.cs b/src/Rules.Framework/Evaluation/Compiled/ConditionBuilders/LesserThanOneToOneConditionExpressionBuilder.cs index d89e9931..6830f399 100644 --- a/src/Rules.Framework/Evaluation/Compiled/ConditionBuilders/LesserThanOneToOneConditionExpressionBuilder.cs +++ b/src/Rules.Framework/Evaluation/Compiled/ConditionBuilders/LesserThanOneToOneConditionExpressionBuilder.cs @@ -2,7 +2,7 @@ namespace Rules.Framework.Evaluation.Compiled.ConditionBuilders { using System; using System.Linq.Expressions; - using Rules.Framework.Core; + using Rules.Framework; using Rules.Framework.Evaluation.Compiled.ExpressionBuilders; internal sealed class LesserThanOneToOneConditionExpressionBuilder : IConditionExpressionBuilder diff --git a/src/Rules.Framework/Evaluation/Compiled/ConditionBuilders/LesserThanOrEqualOneToOneConditionExpressionBuilder.cs b/src/Rules.Framework/Evaluation/Compiled/ConditionBuilders/LesserThanOrEqualOneToOneConditionExpressionBuilder.cs index e1597901..e2f65ab4 100644 --- a/src/Rules.Framework/Evaluation/Compiled/ConditionBuilders/LesserThanOrEqualOneToOneConditionExpressionBuilder.cs +++ b/src/Rules.Framework/Evaluation/Compiled/ConditionBuilders/LesserThanOrEqualOneToOneConditionExpressionBuilder.cs @@ -2,7 +2,7 @@ namespace Rules.Framework.Evaluation.Compiled.ConditionBuilders { using System; using System.Linq.Expressions; - using Rules.Framework.Core; + using Rules.Framework; using Rules.Framework.Evaluation.Compiled.ExpressionBuilders; internal sealed class LesserThanOrEqualOneToOneConditionExpressionBuilder : IConditionExpressionBuilder diff --git a/src/Rules.Framework/Evaluation/Compiled/ConditionBuilders/NotContainsOneToOneConditionExpressionBuilder.cs b/src/Rules.Framework/Evaluation/Compiled/ConditionBuilders/NotContainsOneToOneConditionExpressionBuilder.cs index cd6f3dc4..70bbac33 100644 --- a/src/Rules.Framework/Evaluation/Compiled/ConditionBuilders/NotContainsOneToOneConditionExpressionBuilder.cs +++ b/src/Rules.Framework/Evaluation/Compiled/ConditionBuilders/NotContainsOneToOneConditionExpressionBuilder.cs @@ -3,7 +3,7 @@ namespace Rules.Framework.Evaluation.Compiled.ConditionBuilders using System; using System.Linq.Expressions; using System.Reflection; - using Rules.Framework.Core; + using Rules.Framework; using Rules.Framework.Evaluation.Compiled.ExpressionBuilders; internal sealed class NotContainsOneToOneConditionExpressionBuilder : IConditionExpressionBuilder diff --git a/src/Rules.Framework/Evaluation/Compiled/ConditionBuilders/NotEndsWithOneToOneConditionExpressionBuilder.cs b/src/Rules.Framework/Evaluation/Compiled/ConditionBuilders/NotEndsWithOneToOneConditionExpressionBuilder.cs index 55b422e2..9cf575ad 100644 --- a/src/Rules.Framework/Evaluation/Compiled/ConditionBuilders/NotEndsWithOneToOneConditionExpressionBuilder.cs +++ b/src/Rules.Framework/Evaluation/Compiled/ConditionBuilders/NotEndsWithOneToOneConditionExpressionBuilder.cs @@ -3,7 +3,7 @@ namespace Rules.Framework.Evaluation.Compiled.ConditionBuilders using System; using System.Linq.Expressions; using System.Reflection; - using Rules.Framework.Core; + using Rules.Framework; using Rules.Framework.Evaluation.Compiled.ExpressionBuilders; internal class NotEndsWithOneToOneConditionExpressionBuilder : IConditionExpressionBuilder diff --git a/src/Rules.Framework/Evaluation/Compiled/ConditionBuilders/NotStartsWithOneToOneConditionExpressionBuilder.cs b/src/Rules.Framework/Evaluation/Compiled/ConditionBuilders/NotStartsWithOneToOneConditionExpressionBuilder.cs index 49696d7e..f102a2d9 100644 --- a/src/Rules.Framework/Evaluation/Compiled/ConditionBuilders/NotStartsWithOneToOneConditionExpressionBuilder.cs +++ b/src/Rules.Framework/Evaluation/Compiled/ConditionBuilders/NotStartsWithOneToOneConditionExpressionBuilder.cs @@ -3,7 +3,7 @@ namespace Rules.Framework.Evaluation.Compiled.ConditionBuilders using System; using System.Linq.Expressions; using System.Reflection; - using Rules.Framework.Core; + using Rules.Framework; using Rules.Framework.Evaluation.Compiled.ExpressionBuilders; internal class NotStartsWithOneToOneConditionExpressionBuilder : IConditionExpressionBuilder diff --git a/src/Rules.Framework/Evaluation/Compiled/ConditionBuilders/StartsWithOneToOneConditionExpressionBuilder.cs b/src/Rules.Framework/Evaluation/Compiled/ConditionBuilders/StartsWithOneToOneConditionExpressionBuilder.cs index 7e5668a0..c8d919de 100644 --- a/src/Rules.Framework/Evaluation/Compiled/ConditionBuilders/StartsWithOneToOneConditionExpressionBuilder.cs +++ b/src/Rules.Framework/Evaluation/Compiled/ConditionBuilders/StartsWithOneToOneConditionExpressionBuilder.cs @@ -3,7 +3,7 @@ namespace Rules.Framework.Evaluation.Compiled.ConditionBuilders using System; using System.Linq.Expressions; using System.Reflection; - using Rules.Framework.Core; + using Rules.Framework; using Rules.Framework.Evaluation.Compiled.ExpressionBuilders; internal sealed class StartsWithOneToOneConditionExpressionBuilder : IConditionExpressionBuilder diff --git a/src/Rules.Framework/Evaluation/Compiled/ConditionsValueLookupExtension.cs b/src/Rules.Framework/Evaluation/Compiled/ConditionsValueLookupExtension.cs index a7969401..5e403d04 100644 --- a/src/Rules.Framework/Evaluation/Compiled/ConditionsValueLookupExtension.cs +++ b/src/Rules.Framework/Evaluation/Compiled/ConditionsValueLookupExtension.cs @@ -6,7 +6,7 @@ namespace Rules.Framework.Evaluation.Compiled internal static class ConditionsValueLookupExtension { [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static object GetValueOrDefault(IDictionary conditions, TConditionType conditionType) + public static object GetValueOrDefault(IDictionary conditions, string conditionType) { if (conditions.TryGetValue(conditionType, out var conditionValue)) { diff --git a/src/Rules.Framework/Evaluation/Compiled/EvaluationContext.cs b/src/Rules.Framework/Evaluation/Compiled/EvaluationContext.cs index 8ab74ce6..5edb16af 100644 --- a/src/Rules.Framework/Evaluation/Compiled/EvaluationContext.cs +++ b/src/Rules.Framework/Evaluation/Compiled/EvaluationContext.cs @@ -2,10 +2,10 @@ namespace Rules.Framework.Evaluation.Compiled { using System.Collections.Generic; - internal sealed class EvaluationContext + internal sealed class EvaluationContext { public EvaluationContext( - IDictionary conditions, + IDictionary conditions, MatchModes matchMode, MissingConditionBehaviors missingConditionBehavior) { @@ -14,7 +14,7 @@ public EvaluationContext( this.MissingConditionBehavior = missingConditionBehavior; } - public IDictionary Conditions { get; } + public IDictionary Conditions { get; } public MatchModes MatchMode { get; } diff --git a/src/Rules.Framework/Evaluation/Compiled/IRuleConditionsExpressionBuilder.cs b/src/Rules.Framework/Evaluation/Compiled/IRuleConditionsExpressionBuilder.cs index 55cc7fc3..ce0d1818 100644 --- a/src/Rules.Framework/Evaluation/Compiled/IRuleConditionsExpressionBuilder.cs +++ b/src/Rules.Framework/Evaluation/Compiled/IRuleConditionsExpressionBuilder.cs @@ -2,10 +2,9 @@ namespace Rules.Framework.Evaluation.Compiled { using System; using System.Linq.Expressions; - using Rules.Framework.Core; - internal interface IRuleConditionsExpressionBuilder + internal interface IRuleConditionsExpressionBuilder { - Expression, bool>> BuildExpression(IConditionNode rootConditionNode); + Expression> BuildExpression(IConditionNode rootConditionNode); } } \ No newline at end of file diff --git a/src/Rules.Framework/Evaluation/Compiled/RuleConditionsExpressionBuilder.cs b/src/Rules.Framework/Evaluation/Compiled/RuleConditionsExpressionBuilder.cs index 8544e02f..d6176c86 100644 --- a/src/Rules.Framework/Evaluation/Compiled/RuleConditionsExpressionBuilder.cs +++ b/src/Rules.Framework/Evaluation/Compiled/RuleConditionsExpressionBuilder.cs @@ -7,22 +7,21 @@ namespace Rules.Framework.Evaluation.Compiled using System.Reflection; using System.Text; using System.Text.RegularExpressions; - using Rules.Framework.Core; - using Rules.Framework.Core.ConditionNodes; + using Rules.Framework; + using Rules.Framework.ConditionNodes; using Rules.Framework.Evaluation.Compiled.ExpressionBuilders; - internal sealed class RuleConditionsExpressionBuilder : RuleConditionsExpressionBuilderBase, IRuleConditionsExpressionBuilder + internal sealed class RuleConditionsExpressionBuilder : RuleConditionsExpressionBuilderBase, IRuleConditionsExpressionBuilder { - private static readonly MethodInfo conditionsGetterMethod = typeof(EvaluationContext) + private static readonly MethodInfo conditionsGetterMethod = typeof(EvaluationContext) .GetProperty("Conditions") .GetGetMethod(); - private static readonly MethodInfo evaluationContextMatchModeGetterMethod = typeof(EvaluationContext).GetProperty("MatchMode").GetGetMethod(); - private static readonly MethodInfo evaluationContextMissingConditionsBehaviorGetterMethod = typeof(EvaluationContext).GetProperty("MissingConditionBehavior").GetGetMethod(); + private static readonly MethodInfo evaluationContextMatchModeGetterMethod = typeof(EvaluationContext).GetProperty("MatchMode").GetGetMethod(); + private static readonly MethodInfo evaluationContextMissingConditionsBehaviorGetterMethod = typeof(EvaluationContext).GetProperty("MissingConditionBehavior").GetGetMethod(); private static readonly MethodInfo getValueOrDefaultMethod = typeof(ConditionsValueLookupExtension) - .GetMethod(nameof(ConditionsValueLookupExtension.GetValueOrDefault)) - .MakeGenericMethod(typeof(TConditionType)); + .GetMethod(nameof(ConditionsValueLookupExtension.GetValueOrDefault)); private readonly IDataTypesConfigurationProvider dataTypesConfigurationProvider; private readonly IValueConditionNodeExpressionBuilderProvider valueConditionNodeExpressionBuilderProvider; @@ -35,12 +34,12 @@ public RuleConditionsExpressionBuilder( this.dataTypesConfigurationProvider = dataTypesConfigurationProvider; } - public Expression, bool>> BuildExpression(IConditionNode rootConditionNode) + public Expression> BuildExpression(IConditionNode rootConditionNode) { var expressionResult = ExpressionBuilder.NewExpression("EvaluateConditions") .WithParameters(p => { - p.CreateParameter>("evaluationContext"); + p.CreateParameter("evaluationContext"); }) .HavingReturn(defaultValue: false) .SetImplementation(x => @@ -53,7 +52,7 @@ public Expression, bool>> BuildExpression }) .Build(); - return Expression.Lambda, bool>>( + return Expression.Lambda>( body: expressionResult.Implementation, parameters: expressionResult.Parameters); } @@ -86,11 +85,11 @@ private static void BuildExpressionForBehaviorOnNullLeftOperand(IExpressionBlock })); } - private void BuildExpression(IConditionNode conditionNode, IExpressionBlockBuilder builder) + private void BuildExpression(IConditionNode conditionNode, IExpressionBlockBuilder builder) { switch (conditionNode) { - case ComposedConditionNode composedConditionNode: + case ComposedConditionNode composedConditionNode: var conditionExpressions = new List(composedConditionNode.ChildConditionNodes.Count()); var counter = 0; foreach (var childConditionNode in composedConditionNode.ChildConditionNodes) @@ -118,7 +117,7 @@ private void BuildExpression(IConditionNode conditionNode, IExpr builder.Assign(composedResultVariableExpression, conditionExpression); break; - case ValueConditionNode valueConditionNode: + case ValueConditionNode valueConditionNode: // Variables, constants, and labels. var leftOperandVariableExpression = builder.CreateVariable("LeftOperand"); var rightOperandVariableExpression = builder.CreateVariable("RightOperand"); @@ -147,7 +146,7 @@ private void BuildExpression(IConditionNode conditionNode, IExpr private void BuildFetchAndSwitchOverMultiplicity( IExpressionBlockBuilder builder, - ValueConditionNode valueConditionNode) + ValueConditionNode valueConditionNode) { var operatorConstantExpression = builder.Constant(valueConditionNode.Operator); var multiplicityVariableExpression = builder.CreateVariable("Multiplicity", typeof(string)); diff --git a/src/Rules.Framework/Evaluation/ConditionsTreeAnalyzer.cs b/src/Rules.Framework/Evaluation/ConditionsTreeAnalyzer.cs index 8ff589a7..0e1dee68 100644 --- a/src/Rules.Framework/Evaluation/ConditionsTreeAnalyzer.cs +++ b/src/Rules.Framework/Evaluation/ConditionsTreeAnalyzer.cs @@ -3,25 +3,24 @@ namespace Rules.Framework.Evaluation using System; using System.Collections.Generic; using System.Linq; - using Rules.Framework.Core; - using Rules.Framework.Core.ConditionNodes; + using Rules.Framework.ConditionNodes; - internal sealed class ConditionsTreeAnalyzer : IConditionsTreeAnalyzer + internal sealed class ConditionsTreeAnalyzer : IConditionsTreeAnalyzer { - public bool AreAllSearchConditionsPresent(IConditionNode conditionNode, IDictionary conditions) + public bool AreAllSearchConditionsPresent(IConditionNode conditionNode, IDictionary conditions) { // Conditions checklist is a mere control construct to avoid a full sweep of the // condition nodes tree when we already found all conditions. - var conditionsChecklist = new Dictionary(conditions.ToDictionary(ks => ks.Key, vs => false)); + var conditionsChecklist = conditions.ToDictionary(ks => ks.Key, vs => false, StringComparer.Ordinal); return VisitConditionNode(conditionNode, conditionsChecklist); } - private static bool VisitConditionNode(IConditionNode conditionNode, IDictionary conditionsChecklist) + private static bool VisitConditionNode(IConditionNode conditionNode, IDictionary conditionsChecklist) { switch (conditionNode) { - case IValueConditionNode valueConditionNode: + case IValueConditionNode valueConditionNode: if (conditionsChecklist.ContainsKey(valueConditionNode.ConditionType)) { conditionsChecklist[valueConditionNode.ConditionType] = true; @@ -29,7 +28,7 @@ private static bool VisitConditionNode(IConditionNode conditionN return conditionsChecklist.All(kvp => kvp.Value); - case ComposedConditionNode composedConditionNode: + case ComposedConditionNode composedConditionNode: foreach (var childConditionNode in composedConditionNode.ChildConditionNodes) { var allPresentAlready = VisitConditionNode(childConditionNode, conditionsChecklist); diff --git a/src/Rules.Framework/Evaluation/DataTypeConfiguration.cs b/src/Rules.Framework/Evaluation/DataTypeConfiguration.cs index 2b3e7a81..6ff652ed 100644 --- a/src/Rules.Framework/Evaluation/DataTypeConfiguration.cs +++ b/src/Rules.Framework/Evaluation/DataTypeConfiguration.cs @@ -1,7 +1,7 @@ namespace Rules.Framework.Evaluation { using System; - using Rules.Framework.Core; + using Rules.Framework; internal sealed class DataTypeConfiguration { diff --git a/src/Rules.Framework/Evaluation/DataTypesConfigurationProvider.cs b/src/Rules.Framework/Evaluation/DataTypesConfigurationProvider.cs index 71d7503f..991eb101 100644 --- a/src/Rules.Framework/Evaluation/DataTypesConfigurationProvider.cs +++ b/src/Rules.Framework/Evaluation/DataTypesConfigurationProvider.cs @@ -2,7 +2,7 @@ namespace Rules.Framework.Evaluation { using System; using System.Collections.Generic; - using Rules.Framework.Core; + using Rules.Framework; internal sealed class DataTypesConfigurationProvider : IDataTypesConfigurationProvider { diff --git a/src/Rules.Framework/Evaluation/IConditionsEvalEngine.cs b/src/Rules.Framework/Evaluation/IConditionsEvalEngine.cs index 10d5cb98..afc27d68 100644 --- a/src/Rules.Framework/Evaluation/IConditionsEvalEngine.cs +++ b/src/Rules.Framework/Evaluation/IConditionsEvalEngine.cs @@ -3,8 +3,8 @@ namespace Rules.Framework.Evaluation using System.Collections.Generic; using Rules.Framework.Core; - internal interface IConditionsEvalEngine + internal interface IConditionsEvalEngine { - bool Eval(IConditionNode conditionNode, IDictionary conditions, EvaluationOptions evaluationOptions); + bool Eval(IConditionNode conditionNode, IDictionary conditions, EvaluationOptions evaluationOptions); } } \ No newline at end of file diff --git a/src/Rules.Framework/Evaluation/IConditionsTreeAnalyzer.cs b/src/Rules.Framework/Evaluation/IConditionsTreeAnalyzer.cs index 5471de8d..ce29edfe 100644 --- a/src/Rules.Framework/Evaluation/IConditionsTreeAnalyzer.cs +++ b/src/Rules.Framework/Evaluation/IConditionsTreeAnalyzer.cs @@ -1,10 +1,9 @@ namespace Rules.Framework.Evaluation { using System.Collections.Generic; - using Rules.Framework.Core; - internal interface IConditionsTreeAnalyzer + internal interface IConditionsTreeAnalyzer { - bool AreAllSearchConditionsPresent(IConditionNode conditionNode, IDictionary conditions); + bool AreAllSearchConditionsPresent(IConditionNode conditionNode, IDictionary conditions); } } \ No newline at end of file diff --git a/src/Rules.Framework/Evaluation/IDataTypesConfigurationProvider.cs b/src/Rules.Framework/Evaluation/IDataTypesConfigurationProvider.cs index fa842750..6c845dc0 100644 --- a/src/Rules.Framework/Evaluation/IDataTypesConfigurationProvider.cs +++ b/src/Rules.Framework/Evaluation/IDataTypesConfigurationProvider.cs @@ -1,6 +1,6 @@ namespace Rules.Framework.Evaluation { - using Rules.Framework.Core; + using Rules.Framework; internal interface IDataTypesConfigurationProvider { diff --git a/src/Rules.Framework/Evaluation/IMultiplicityEvaluator.cs b/src/Rules.Framework/Evaluation/IMultiplicityEvaluator.cs index 7c540d43..cd07a5de 100644 --- a/src/Rules.Framework/Evaluation/IMultiplicityEvaluator.cs +++ b/src/Rules.Framework/Evaluation/IMultiplicityEvaluator.cs @@ -1,6 +1,6 @@ namespace Rules.Framework.Evaluation { - using Rules.Framework.Core; + using Rules.Framework; internal interface IMultiplicityEvaluator { diff --git a/src/Rules.Framework/Evaluation/Interpreted/DeferredEval.cs b/src/Rules.Framework/Evaluation/Interpreted/DeferredEval.cs index ce0b757c..30ae24a6 100644 --- a/src/Rules.Framework/Evaluation/Interpreted/DeferredEval.cs +++ b/src/Rules.Framework/Evaluation/Interpreted/DeferredEval.cs @@ -2,7 +2,7 @@ namespace Rules.Framework.Evaluation.Interpreted { using System; using System.Collections.Generic; - using Rules.Framework.Core.ConditionNodes; + using Rules.Framework.ConditionNodes; using Rules.Framework.Evaluation.Interpreted.ValueEvaluation.Dispatchers; internal sealed class DeferredEval : IDeferredEval @@ -18,10 +18,10 @@ public DeferredEval( this.rulesEngineOptions = rulesEngineOptions; } - public Func, bool> GetDeferredEvalFor(IValueConditionNode valueConditionNode, MatchModes matchMode) + public Func, bool> GetDeferredEvalFor(IValueConditionNode valueConditionNode, MatchModes matchMode) => (conditions) => Eval(conditions, valueConditionNode, matchMode); - private bool Eval(IDictionary conditions, IValueConditionNode valueConditionNode, MatchModes matchMode) + private bool Eval(IDictionary conditions, IValueConditionNode valueConditionNode, MatchModes matchMode) { var rightOperand = valueConditionNode.Operand; diff --git a/src/Rules.Framework/Evaluation/Interpreted/IDeferredEval.cs b/src/Rules.Framework/Evaluation/Interpreted/IDeferredEval.cs index 7e6333dc..f13276ad 100644 --- a/src/Rules.Framework/Evaluation/Interpreted/IDeferredEval.cs +++ b/src/Rules.Framework/Evaluation/Interpreted/IDeferredEval.cs @@ -2,10 +2,10 @@ namespace Rules.Framework.Evaluation.Interpreted { using System; using System.Collections.Generic; - using Rules.Framework.Core.ConditionNodes; + using Rules.Framework.ConditionNodes; internal interface IDeferredEval { - Func, bool> GetDeferredEvalFor(IValueConditionNode valueConditionNode, MatchModes matchMode); + Func, bool> GetDeferredEvalFor(IValueConditionNode valueConditionNode, MatchModes matchMode); } } \ No newline at end of file diff --git a/src/Rules.Framework/Evaluation/Interpreted/InterpretedConditionsEvalEngine.cs b/src/Rules.Framework/Evaluation/Interpreted/InterpretedConditionsEvalEngine.cs index b0d04a2b..a9e092ed 100644 --- a/src/Rules.Framework/Evaluation/Interpreted/InterpretedConditionsEvalEngine.cs +++ b/src/Rules.Framework/Evaluation/Interpreted/InterpretedConditionsEvalEngine.cs @@ -3,47 +3,47 @@ namespace Rules.Framework.Evaluation.Interpreted using System; using System.Collections.Generic; using System.Linq; - using Rules.Framework.Core; - using Rules.Framework.Core.ConditionNodes; + using Rules.Framework; + using Rules.Framework.ConditionNodes; - internal sealed class InterpretedConditionsEvalEngine : IConditionsEvalEngine + internal sealed class InterpretedConditionsEvalEngine : IConditionsEvalEngine { - private readonly IConditionsTreeAnalyzer conditionsTreeAnalyzer; + private readonly IConditionsTreeAnalyzer conditionsTreeAnalyzer; private readonly IDeferredEval deferredEval; public InterpretedConditionsEvalEngine( IDeferredEval deferredEval, - IConditionsTreeAnalyzer conditionsTreeAnalyzer) + IConditionsTreeAnalyzer conditionsTreeAnalyzer) { this.deferredEval = deferredEval; this.conditionsTreeAnalyzer = conditionsTreeAnalyzer; } - public bool Eval(IConditionNode conditionNode, IDictionary conditions, EvaluationOptions evaluationOptions) + public bool Eval(IConditionNode conditionNode, IDictionary conditions, EvaluationOptions evaluationOptions) { if (evaluationOptions.ExcludeRulesWithoutSearchConditions && !this.conditionsTreeAnalyzer.AreAllSearchConditionsPresent(conditionNode, conditions)) { return false; } - ISpecification> specification = this.BuildSpecification(conditionNode, evaluationOptions.MatchMode); + ISpecification> specification = this.BuildSpecification(conditionNode, evaluationOptions.MatchMode); return specification.IsSatisfiedBy(conditions); } - private ISpecification> BuildSpecification(IConditionNode conditionNode, MatchModes matchMode) + private ISpecification> BuildSpecification(IConditionNode conditionNode, MatchModes matchMode) { return conditionNode switch { - IValueConditionNode valueConditionNode => this.BuildSpecificationForValueNode(valueConditionNode, matchMode), - ComposedConditionNode composedConditionNode => this.BuildSpecificationForComposedNode(composedConditionNode, matchMode), + IValueConditionNode valueConditionNode => this.BuildSpecificationForValueNode(valueConditionNode, matchMode), + ComposedConditionNode composedConditionNode => this.BuildSpecificationForComposedNode(composedConditionNode, matchMode), _ => throw new NotSupportedException($"Unsupported condition node: '{conditionNode.GetType().Name}'."), }; } - private ISpecification> BuildSpecificationForComposedNode(ComposedConditionNode composedConditionNode, MatchModes matchMode) + private ISpecification> BuildSpecificationForComposedNode(ComposedConditionNode composedConditionNode, MatchModes matchMode) { - IEnumerable>> childConditionNodesSpecifications = composedConditionNode + IEnumerable>> childConditionNodesSpecifications = composedConditionNode .ChildConditionNodes .Select(cn => this.BuildSpecification(cn, matchMode)); @@ -55,9 +55,9 @@ private ISpecification> BuildSpecificationFo }; } - private ISpecification> BuildSpecificationForValueNode(IValueConditionNode valueConditionNode, MatchModes matchMode) + private ISpecification> BuildSpecificationForValueNode(IValueConditionNode valueConditionNode, MatchModes matchMode) { - return new FuncSpecification>(this.deferredEval.GetDeferredEvalFor(valueConditionNode, matchMode)); + return new FuncSpecification>(this.deferredEval.GetDeferredEvalFor(valueConditionNode, matchMode)); } } } \ No newline at end of file diff --git a/src/Rules.Framework/Evaluation/Interpreted/ValueEvaluation/Dispatchers/ConditionEvalDispatchProvider.cs b/src/Rules.Framework/Evaluation/Interpreted/ValueEvaluation/Dispatchers/ConditionEvalDispatchProvider.cs index 7cc820e3..e62df71b 100644 --- a/src/Rules.Framework/Evaluation/Interpreted/ValueEvaluation/Dispatchers/ConditionEvalDispatchProvider.cs +++ b/src/Rules.Framework/Evaluation/Interpreted/ValueEvaluation/Dispatchers/ConditionEvalDispatchProvider.cs @@ -2,7 +2,7 @@ namespace Rules.Framework.Evaluation.Interpreted.ValueEvaluation.Dispatchers { using System; using System.Collections.Generic; - using Rules.Framework.Core; + using Rules.Framework; internal sealed class ConditionEvalDispatchProvider : IConditionEvalDispatchProvider { diff --git a/src/Rules.Framework/Evaluation/Interpreted/ValueEvaluation/Dispatchers/ConditionEvalDispatcherBase.cs b/src/Rules.Framework/Evaluation/Interpreted/ValueEvaluation/Dispatchers/ConditionEvalDispatcherBase.cs index 592c2577..e32ed58f 100644 --- a/src/Rules.Framework/Evaluation/Interpreted/ValueEvaluation/Dispatchers/ConditionEvalDispatcherBase.cs +++ b/src/Rules.Framework/Evaluation/Interpreted/ValueEvaluation/Dispatchers/ConditionEvalDispatcherBase.cs @@ -5,7 +5,7 @@ namespace Rules.Framework.Evaluation.Interpreted.ValueEvaluation.Dispatchers using System.Collections.Generic; using System.Globalization; using System.Linq; - using Rules.Framework.Core; + using Rules.Framework; internal abstract class ConditionEvalDispatcherBase { diff --git a/src/Rules.Framework/Evaluation/Interpreted/ValueEvaluation/Dispatchers/IConditionEvalDispatchProvider.cs b/src/Rules.Framework/Evaluation/Interpreted/ValueEvaluation/Dispatchers/IConditionEvalDispatchProvider.cs index ac697806..3fa3a04a 100644 --- a/src/Rules.Framework/Evaluation/Interpreted/ValueEvaluation/Dispatchers/IConditionEvalDispatchProvider.cs +++ b/src/Rules.Framework/Evaluation/Interpreted/ValueEvaluation/Dispatchers/IConditionEvalDispatchProvider.cs @@ -1,6 +1,6 @@ namespace Rules.Framework.Evaluation.Interpreted.ValueEvaluation.Dispatchers { - using Rules.Framework.Core; + using Rules.Framework; internal interface IConditionEvalDispatchProvider { diff --git a/src/Rules.Framework/Evaluation/Interpreted/ValueEvaluation/Dispatchers/IConditionEvalDispatcher.cs b/src/Rules.Framework/Evaluation/Interpreted/ValueEvaluation/Dispatchers/IConditionEvalDispatcher.cs index cde1ce2d..83612a85 100644 --- a/src/Rules.Framework/Evaluation/Interpreted/ValueEvaluation/Dispatchers/IConditionEvalDispatcher.cs +++ b/src/Rules.Framework/Evaluation/Interpreted/ValueEvaluation/Dispatchers/IConditionEvalDispatcher.cs @@ -1,6 +1,6 @@ namespace Rules.Framework.Evaluation.Interpreted.ValueEvaluation.Dispatchers { - using Rules.Framework.Core; + using Rules.Framework; internal interface IConditionEvalDispatcher { diff --git a/src/Rules.Framework/Evaluation/Interpreted/ValueEvaluation/Dispatchers/ManyToManyConditionEvalDispatcher.cs b/src/Rules.Framework/Evaluation/Interpreted/ValueEvaluation/Dispatchers/ManyToManyConditionEvalDispatcher.cs index 9b3462ec..8b931a1c 100644 --- a/src/Rules.Framework/Evaluation/Interpreted/ValueEvaluation/Dispatchers/ManyToManyConditionEvalDispatcher.cs +++ b/src/Rules.Framework/Evaluation/Interpreted/ValueEvaluation/Dispatchers/ManyToManyConditionEvalDispatcher.cs @@ -2,7 +2,7 @@ namespace Rules.Framework.Evaluation.Interpreted.ValueEvaluation.Dispatchers { using System.Collections.Generic; using System.Linq; - using Rules.Framework.Core; + using Rules.Framework; internal sealed class ManyToManyConditionEvalDispatcher : ConditionEvalDispatcherBase, IConditionEvalDispatcher { diff --git a/src/Rules.Framework/Evaluation/Interpreted/ValueEvaluation/Dispatchers/ManyToOneConditionEvalDispatcher.cs b/src/Rules.Framework/Evaluation/Interpreted/ValueEvaluation/Dispatchers/ManyToOneConditionEvalDispatcher.cs index 44ca5841..c1d3242b 100644 --- a/src/Rules.Framework/Evaluation/Interpreted/ValueEvaluation/Dispatchers/ManyToOneConditionEvalDispatcher.cs +++ b/src/Rules.Framework/Evaluation/Interpreted/ValueEvaluation/Dispatchers/ManyToOneConditionEvalDispatcher.cs @@ -2,7 +2,7 @@ namespace Rules.Framework.Evaluation.Interpreted.ValueEvaluation.Dispatchers { using System.Collections.Generic; using System.Linq; - using Rules.Framework.Core; + using Rules.Framework; internal sealed class ManyToOneConditionEvalDispatcher : ConditionEvalDispatcherBase, IConditionEvalDispatcher { diff --git a/src/Rules.Framework/Evaluation/Interpreted/ValueEvaluation/Dispatchers/OneToManyConditionEvalDispatcher.cs b/src/Rules.Framework/Evaluation/Interpreted/ValueEvaluation/Dispatchers/OneToManyConditionEvalDispatcher.cs index af3998a8..03474b57 100644 --- a/src/Rules.Framework/Evaluation/Interpreted/ValueEvaluation/Dispatchers/OneToManyConditionEvalDispatcher.cs +++ b/src/Rules.Framework/Evaluation/Interpreted/ValueEvaluation/Dispatchers/OneToManyConditionEvalDispatcher.cs @@ -2,7 +2,7 @@ namespace Rules.Framework.Evaluation.Interpreted.ValueEvaluation.Dispatchers { using System.Collections.Generic; using System.Linq; - using Rules.Framework.Core; + using Rules.Framework; internal sealed class OneToManyConditionEvalDispatcher : ConditionEvalDispatcherBase, IConditionEvalDispatcher { diff --git a/src/Rules.Framework/Evaluation/Interpreted/ValueEvaluation/Dispatchers/OneToOneConditionEvalDispatcher.cs b/src/Rules.Framework/Evaluation/Interpreted/ValueEvaluation/Dispatchers/OneToOneConditionEvalDispatcher.cs index cd422b7f..ec74fae5 100644 --- a/src/Rules.Framework/Evaluation/Interpreted/ValueEvaluation/Dispatchers/OneToOneConditionEvalDispatcher.cs +++ b/src/Rules.Framework/Evaluation/Interpreted/ValueEvaluation/Dispatchers/OneToOneConditionEvalDispatcher.cs @@ -1,6 +1,6 @@ namespace Rules.Framework.Evaluation.Interpreted.ValueEvaluation.Dispatchers { - using Rules.Framework.Core; + using Rules.Framework; internal sealed class OneToOneConditionEvalDispatcher : ConditionEvalDispatcherBase, IConditionEvalDispatcher { diff --git a/src/Rules.Framework/Evaluation/Interpreted/ValueEvaluation/IOperatorEvalStrategyFactory.cs b/src/Rules.Framework/Evaluation/Interpreted/ValueEvaluation/IOperatorEvalStrategyFactory.cs index 5610bd09..9e2e1b55 100644 --- a/src/Rules.Framework/Evaluation/Interpreted/ValueEvaluation/IOperatorEvalStrategyFactory.cs +++ b/src/Rules.Framework/Evaluation/Interpreted/ValueEvaluation/IOperatorEvalStrategyFactory.cs @@ -1,6 +1,6 @@ namespace Rules.Framework.Evaluation.Interpreted.ValueEvaluation { - using Rules.Framework.Core; + using Rules.Framework; internal interface IOperatorEvalStrategyFactory { diff --git a/src/Rules.Framework/Evaluation/Interpreted/ValueEvaluation/OperatorEvalStrategyFactory.cs b/src/Rules.Framework/Evaluation/Interpreted/ValueEvaluation/OperatorEvalStrategyFactory.cs index 6119f5cc..3b71dca8 100644 --- a/src/Rules.Framework/Evaluation/Interpreted/ValueEvaluation/OperatorEvalStrategyFactory.cs +++ b/src/Rules.Framework/Evaluation/Interpreted/ValueEvaluation/OperatorEvalStrategyFactory.cs @@ -2,7 +2,7 @@ namespace Rules.Framework.Evaluation.Interpreted.ValueEvaluation { using System; using System.Collections.Generic; - using Rules.Framework.Core; + using Rules.Framework; internal sealed class OperatorEvalStrategyFactory : IOperatorEvalStrategyFactory { diff --git a/src/Rules.Framework/Evaluation/MultiplicityEvaluator.cs b/src/Rules.Framework/Evaluation/MultiplicityEvaluator.cs index c3c7c945..a48edd56 100644 --- a/src/Rules.Framework/Evaluation/MultiplicityEvaluator.cs +++ b/src/Rules.Framework/Evaluation/MultiplicityEvaluator.cs @@ -2,7 +2,7 @@ namespace Rules.Framework.Evaluation { using System; using System.Collections; - using Rules.Framework.Core; + using Rules.Framework; internal sealed class MultiplicityEvaluator : IMultiplicityEvaluator { diff --git a/src/Rules.Framework/Evaluation/OperatorMetadata.cs b/src/Rules.Framework/Evaluation/OperatorMetadata.cs index b9614e70..26eec03b 100644 --- a/src/Rules.Framework/Evaluation/OperatorMetadata.cs +++ b/src/Rules.Framework/Evaluation/OperatorMetadata.cs @@ -3,7 +3,7 @@ namespace Rules.Framework.Evaluation using System; using System.Collections.Generic; using System.Linq; - using Rules.Framework.Core; + using Rules.Framework; internal sealed class OperatorMetadata { diff --git a/src/Rules.Framework/Evaluation/OperatorsMetadata.cs b/src/Rules.Framework/Evaluation/OperatorsMetadata.cs index c11a2216..dc36e32a 100644 --- a/src/Rules.Framework/Evaluation/OperatorsMetadata.cs +++ b/src/Rules.Framework/Evaluation/OperatorsMetadata.cs @@ -4,7 +4,7 @@ namespace Rules.Framework.Evaluation using System.Collections.Generic; using System.Collections.ObjectModel; using System.Linq; - using Rules.Framework.Core; + using Rules.Framework; internal static class OperatorsMetadata { diff --git a/src/Rules.Framework/Extensions/GenericRuleExtensions.cs b/src/Rules.Framework/Extensions/GenericRuleExtensions.cs deleted file mode 100644 index 7ed33f25..00000000 --- a/src/Rules.Framework/Extensions/GenericRuleExtensions.cs +++ /dev/null @@ -1,57 +0,0 @@ -namespace Rules.Framework.Extensions -{ - using System.Collections.Generic; - using System.Linq; - using Rules.Framework.Core; - using Rules.Framework.Core.ConditionNodes; - using Rules.Framework.Generics; - - internal static class GenericRuleExtensions - { - public static GenericConditionNode ToGenericConditionNode(this IConditionNode rootCondition) - { - if (rootCondition.LogicalOperator == LogicalOperators.Eval) - { - var condition = rootCondition as ValueConditionNode; - - return new GenericValueConditionNode - { - ConditionTypeName = condition.ConditionType.ToString(), - DataType = condition.DataType, - LogicalOperator = condition.LogicalOperator, - Operand = condition.Operand, - Operator = condition.Operator, - }; - } - - var composedConditionNode = rootCondition as ComposedConditionNode; - - var conditionNodeDataModels = new List(composedConditionNode.ChildConditionNodes.Count()); - - foreach (var child in composedConditionNode.ChildConditionNodes) - { - conditionNodeDataModels.Add(child.ToGenericConditionNode()); - } - - return new GenericComposedConditionNode - { - ChildConditionNodes = conditionNodeDataModels, - LogicalOperator = composedConditionNode.LogicalOperator, - }; - } - - public static GenericRule ToGenericRule(this Rule rule) - { - return new GenericRule - { - RootCondition = rule.RootCondition?.ToGenericConditionNode(), - Content = rule.ContentContainer.GetContentAs(), - DateBegin = rule.DateBegin, - DateEnd = rule.DateEnd, - Name = rule.Name, - Priority = rule.Priority, - Active = rule.Active, - }; - } - } -} diff --git a/src/Rules.Framework/Extensions/GenericSearchArgsExtensions.cs b/src/Rules.Framework/Extensions/GenericSearchArgsExtensions.cs deleted file mode 100644 index dcb0c839..00000000 --- a/src/Rules.Framework/Extensions/GenericSearchArgsExtensions.cs +++ /dev/null @@ -1,45 +0,0 @@ -namespace Rules.Framework.Extensions -{ - using System; - using System.Linq; - using Rules.Framework.Generics; - - internal static class GenericSearchArgsExtensions - { - public static SearchArgs ToSearchArgs( - this SearchArgs genericSearchArgs) - { - if (!typeof(TContentType).IsEnum) - { - throw new ArgumentException("Only TContentType of type enum are currently supported."); - } - - var contentType = (TContentType)Enum.Parse(typeof(TContentType), genericSearchArgs.ContentType.Identifier); - - if (genericSearchArgs.Active.HasValue) - { - return new SearchArgs(contentType, genericSearchArgs.DateBegin, genericSearchArgs.DateEnd, genericSearchArgs.Active.Value) - { - Conditions = genericSearchArgs.Conditions.Select(condition => new Condition - ( - (TConditionType)Enum.Parse(typeof(TConditionType), condition.Type.Identifier), - condition.Value - )).ToList(), - ExcludeRulesWithoutSearchConditions = genericSearchArgs.ExcludeRulesWithoutSearchConditions - }; - } - - var searchArgs = new SearchArgs(contentType, genericSearchArgs.DateBegin, genericSearchArgs.DateEnd) - { - Conditions = genericSearchArgs.Conditions.Select(condition => new Condition - ( - (TConditionType)Enum.Parse(typeof(TConditionType), condition.Type.Identifier), - condition.Value - )).ToList(), - ExcludeRulesWithoutSearchConditions = genericSearchArgs.ExcludeRulesWithoutSearchConditions - }; - - return searchArgs; - } - } -} \ No newline at end of file diff --git a/src/Rules.Framework/Extensions/RulesEngineExtensions.cs b/src/Rules.Framework/Extensions/RulesEngineExtensions.cs index 60ce6941..b1371f84 100644 --- a/src/Rules.Framework/Extensions/RulesEngineExtensions.cs +++ b/src/Rules.Framework/Extensions/RulesEngineExtensions.cs @@ -1,6 +1,6 @@ -namespace Rules.Framework.Extension +namespace Rules.Framework { - using Rules.Framework.Generics; + using Rules.Framework.Generic; /// /// Extensions for rules engine @@ -14,9 +14,9 @@ public static class RulesEngineExtensions /// The type of the condition type. /// The rules engine. /// A new instance of generic engine - public static IGenericRulesEngine CreateGenericEngine(this RulesEngine rulesEngine) + public static IRulesEngine MakeGeneric(this IRulesEngine rulesEngine) { - return new GenericRulesEngine(rulesEngine); + return new RulesEngine(rulesEngine); } } } \ No newline at end of file diff --git a/src/Rules.Framework/Generic/ConditionNodes/ComposedConditionNode.cs b/src/Rules.Framework/Generic/ConditionNodes/ComposedConditionNode.cs new file mode 100644 index 00000000..9621de90 --- /dev/null +++ b/src/Rules.Framework/Generic/ConditionNodes/ComposedConditionNode.cs @@ -0,0 +1,84 @@ +namespace Rules.Framework.Generic.ConditionNodes +{ + using System; + using System.Collections.Generic; + using System.Diagnostics; + using System.Linq; + using Rules.Framework; + using Rules.Framework.ConditionNodes; + using Rules.Framework.Generic; + + /// + /// A composed condition node which aggregates a set of child condition nodes and defines a + /// logical operator to apply to them. + /// + /// + /// The condition type that allows to filter rules based on a set of conditions. + /// + [DebuggerDisplay("Composed condition: apply {LogicalOperator.ToString(),nq} operator for {System.Linq.Enumerable.Count(ChildConditionNodes),nq} nodes")] + public class ComposedConditionNode : IConditionNode + { + private readonly ComposedConditionNode composedConditionNode; + private List>? children; + + /// + /// Creates a new . + /// + /// The composed condition node. + public ComposedConditionNode(ComposedConditionNode composedConditionNode) + { + this.composedConditionNode = composedConditionNode; + } + + /// + /// Gets the child condition nodes. + /// + public IEnumerable> ChildConditionNodes + { + get + { + this.children ??= this.composedConditionNode.ChildConditionNodes + .Select(cn => cn.ToGenericConditionNode()) + .ToList(); + + return this.children; + } + } + + /// + /// Gets the logical operator to apply between child condition nodes. + /// + public LogicalOperators LogicalOperator => this.composedConditionNode.LogicalOperator; + + /// + /// Gets the condition node properties. + /// + public IDictionary Properties => this.composedConditionNode.Properties; + + /// + /// Clones the condition node into a different instance. + /// + /// + public IConditionNode Clone() + => new ComposedConditionNode((ComposedConditionNode)this.composedConditionNode.Clone()); + + /// + /// Determines whether the specified , is equal to this instance. + /// + /// The to compare with this instance. + /// + /// true if the specified is equal to this instance; otherwise, false. + /// + public override bool Equals(object obj) => obj is ComposedConditionNode node && EqualityComparer.Default.Equals(this.composedConditionNode, node.composedConditionNode); + + /// + /// Returns a hash code for this instance. + /// + /// + /// A hash code for this instance, suitable for use in hashing algorithms and data + /// structures like a hash table. + /// + public override int GetHashCode() + => this.composedConditionNode.GetHashCode(); + } +} \ No newline at end of file diff --git a/src/Rules.Framework/Core/ConditionNodes/IValueConditionNode.cs b/src/Rules.Framework/Generic/ConditionNodes/IValueConditionNode.cs similarity index 85% rename from src/Rules.Framework/Core/ConditionNodes/IValueConditionNode.cs rename to src/Rules.Framework/Generic/ConditionNodes/IValueConditionNode.cs index 7f75aa4a..074ebd7f 100644 --- a/src/Rules.Framework/Core/ConditionNodes/IValueConditionNode.cs +++ b/src/Rules.Framework/Generic/ConditionNodes/IValueConditionNode.cs @@ -1,5 +1,8 @@ -namespace Rules.Framework.Core.ConditionNodes +namespace Rules.Framework.Generic.ConditionNodes { + using Rules.Framework; + using Rules.Framework.Generic; + /// /// Defines the interface contract for a condition node based on a value comparison. /// @@ -21,7 +24,7 @@ public interface IValueConditionNode : IConditionNode /// Gets the condition's operand. /// - public object Operand { get; } + object Operand { get; } /// /// Gets the condition node operator. diff --git a/src/Rules.Framework/Generic/ConditionNodes/ValueConditionNode.cs b/src/Rules.Framework/Generic/ConditionNodes/ValueConditionNode.cs new file mode 100644 index 00000000..b6a6fbed --- /dev/null +++ b/src/Rules.Framework/Generic/ConditionNodes/ValueConditionNode.cs @@ -0,0 +1,88 @@ +namespace Rules.Framework.Generic.ConditionNodes +{ + using System; + using System.Collections.Generic; + using System.Diagnostics; + using Rules.Framework; + using Rules.Framework.ConditionNodes; + using Rules.Framework.Generic; + + /// + /// A generic implementation for a valued condition node. + /// + /// + /// The condition type that allows to filter rules based on a set of conditions. + /// + /// + [DebuggerDisplay("{DataType.ToString(),nq} condition: <{ConditionType.ToString(),nq}> {Operator} {Operand}")] + public class ValueConditionNode : IValueConditionNode + { + private readonly ValueConditionNode valueConditionNode; + + /// + /// Initializes a new instance of the class. + /// + /// The value condition node. + public ValueConditionNode(ValueConditionNode valueConditionNode) + { + this.valueConditionNode = valueConditionNode; + } + + /// + /// Gets the condition node type. + /// + public TConditionType ConditionType => GenericConversions.Convert(valueConditionNode.ConditionType); + + /// + /// Gets the condition node data type. + /// + public DataTypes DataType => this.valueConditionNode.DataType; + + /// + /// Gets the logical operator to apply to condition node. + /// + public LogicalOperators LogicalOperator => LogicalOperators.Eval; + + /// + /// Gets the condition's operand. + /// + /// The operand. + public object Operand => this.valueConditionNode.Operand; + + /// + /// Gets the condition node operator. + /// + public Operators Operator => this.valueConditionNode.Operator; + + /// + /// Gets the condition node properties. + /// + public IDictionary Properties => this.valueConditionNode.Properties; + + /// + /// Clones the condition node into a different instance. + /// + /// + public IConditionNode Clone() + => new ValueConditionNode((ValueConditionNode)this.valueConditionNode.Clone()); + + /// + /// Determines whether the specified , is equal to this instance. + /// + /// The to compare with this instance. + /// + /// true if the specified is equal to this instance; otherwise, false. + /// + public override bool Equals(object obj) => obj is ValueConditionNode node && EqualityComparer.Default.Equals(this.valueConditionNode, node.valueConditionNode); + + /// + /// Returns a hash code for this instance. + /// + /// + /// A hash code for this instance, suitable for use in hashing algorithms and data + /// structures like a hash table. + /// + public override int GetHashCode() + => this.valueConditionNode.GetHashCode(); + } +} \ No newline at end of file diff --git a/src/Rules.Framework/Generic/GenericConversions.cs b/src/Rules.Framework/Generic/GenericConversions.cs new file mode 100644 index 00000000..e3903731 --- /dev/null +++ b/src/Rules.Framework/Generic/GenericConversions.cs @@ -0,0 +1,31 @@ +namespace Rules.Framework.Generic +{ + using System; + using System.Collections.Generic; + using System.Globalization; + using System.Text; + + internal static class GenericConversions + { + public static T Convert(string value) + { + var valueType = typeof(T); + if (valueType.IsEnum) + { + return (T)Enum.Parse(valueType, value, ignoreCase: false); + } + + return (T)System.Convert.ChangeType(value, valueType, CultureInfo.InvariantCulture); + } + + public static string Convert(T value) + { + if (value is string stringValue) + { + return stringValue; + } + + return value!.ToString(); + } + } +} \ No newline at end of file diff --git a/src/Rules.Framework/Core/IConditionNode.cs b/src/Rules.Framework/Generic/IConditionNode.cs similarity index 93% rename from src/Rules.Framework/Core/IConditionNode.cs rename to src/Rules.Framework/Generic/IConditionNode.cs index d0c12762..eab78ebc 100644 --- a/src/Rules.Framework/Core/IConditionNode.cs +++ b/src/Rules.Framework/Generic/IConditionNode.cs @@ -1,6 +1,7 @@ -namespace Rules.Framework.Core +namespace Rules.Framework.Generic { using System.Collections.Generic; + using Rules.Framework; /// /// Defines the interface contract for a rule's condition node. diff --git a/src/Rules.Framework/Generic/IRulesEngine.cs b/src/Rules.Framework/Generic/IRulesEngine.cs new file mode 100644 index 00000000..ec1e679b --- /dev/null +++ b/src/Rules.Framework/Generic/IRulesEngine.cs @@ -0,0 +1,145 @@ +namespace Rules.Framework.Generic +{ + using System; + using System.Collections.Generic; + using System.Threading.Tasks; + + /// + /// The engine that holds the logic to match and manage rules. + /// + /// The type of the content type. + /// The type of the condition type. + public interface IRulesEngine + { + /// + /// Gets the options. + /// + /// The options. + IRulesEngineOptions Options { get; } + + /// + /// Activates the specified existing rule. + /// + /// The rule. + /// + /// the operation result, containing success/failure indication and messages associated to + /// errors occurred during the operation. + /// + /// rule + Task ActivateRuleAsync(Rule rule); + + /// + /// Adds a new rule. + /// + /// The rule. + /// The rule add priority option. + /// + /// the operation result, containing success/failure indication and messages associated to + /// errors occurred during the operation. + /// + /// rule or rule + /// The priority option is not supported. + Task AddRuleAsync(Rule rule, RuleAddPriorityOption ruleAddPriorityOption); + + /// + /// Creates a content type. + /// + /// Type of the content. + /// + Task CreateContentTypeAsync(TContentType contentType); + + /// + /// Deactivates the specified existing rule. + /// + /// The rule. + /// + /// the operation result, containing success/failure indication and messages associated to + /// errors occurred during the operation. + /// + /// rule + Task DeactivateRuleAsync(Rule rule); + + /// + /// Gets the content types. + /// + /// List of content types + Task> GetContentTypesAsync(); + + /// + /// Get the unique condition types associated with rules of a specific content type. + /// + /// + /// + /// + /// + /// + /// A set of rules is requested to rules data source and all conditions are evaluated + /// against them to provide a set of matches. + /// + /// All rules matching supplied conditions are returned. + /// + /// the matched rule; otherwise, empty. + Task> GetUniqueConditionTypesAsync(TContentType contentType, DateTime dateBegin, DateTime dateEnd); + + /// + /// Provides all rule matches (if any) to the given content type at the specified and satisfying the supplied . + /// + /// + /// + /// + /// + /// + /// A set of rules is requested to rules data source and all conditions are evaluated + /// against them to provide a set of matches. + /// + /// All rules matching supplied conditions are returned. + /// + /// the matched rule; otherwise, null. + Task>> MatchManyAsync(TContentType contentType, DateTime matchDateTime, IEnumerable> conditions); + + /// + /// Provides a rule match (if any) to the given content type at the specified and satisfying the supplied . + /// + /// + /// + /// + /// + /// + /// A set of rules is requested to rules data source and all conditions are evaluated + /// against them to provide a set of matches. + /// + /// + /// If there's more than one match, a rule is selected based on the priority criteria and + /// value: topmost selects the lowest priority number and bottommost selects highest priority. + /// + /// + /// the matched rule; otherwise, null. + Task> MatchOneAsync(TContentType contentType, DateTime matchDateTime, IEnumerable> conditions); + + /// + /// Searches for rules on given content type that match on supplied . + /// + /// + /// + /// + /// Only the condition types supplied on input conditions are evaluated, the remaining + /// conditions are ignored. + /// + /// + /// the set of rules matching the conditions. + Task>> SearchAsync(SearchArgs searchArgs); + + /// + /// Updates the specified existing rule. + /// + /// The rule. + /// + /// the operation result, containing success/failure indication and messages associated to + /// errors occurred during the operation. + /// + /// rule + Task UpdateRuleAsync(Rule rule); + } +} \ No newline at end of file diff --git a/src/Rules.Framework/Generic/Rule.cs b/src/Rules.Framework/Generic/Rule.cs new file mode 100644 index 00000000..2bf9ae61 --- /dev/null +++ b/src/Rules.Framework/Generic/Rule.cs @@ -0,0 +1,104 @@ +namespace Rules.Framework.Generic +{ + using System; + using Rules.Framework.Core; + + /// + /// Defines a rule. + /// + /// The content type that allows to categorize rules. + /// + /// The condition type that allows to filter rules based on a set of conditions. + /// + public class Rule + { + private readonly Rule wrappedRule; + private IConditionNode? rootCondition; + + internal Rule(Rule wrappedRule) + { + var typeForContentType = typeof(TContentType); + if (!typeForContentType.IsEnum && typeForContentType != TypesCache.String) + { + throw new NotSupportedException($"Only enum types or string are supported as {nameof(TContentType)}."); + } + + var typeForConditionType = typeof(TConditionType); + if (!typeForConditionType.IsEnum && typeForConditionType != TypesCache.String) + { + throw new NotSupportedException($"Only enum types or string are supported as {nameof(TConditionType)}."); + } + + this.wrappedRule = wrappedRule ?? throw new ArgumentNullException(nameof(wrappedRule)); + } + + /// + /// Gets if the rule is active. + /// + public bool Active => this.wrappedRule.Active; + + /// + /// Gets the content container which contains the rule content. + /// + public ContentContainer ContentContainer => this.wrappedRule.ContentContainer; + + /// + /// Gets the content type. + /// + public TContentType ContentType => GenericConversions.Convert(this.wrappedRule.ContentType); + + /// + /// Gets the date from which the rule begins being applicable. + /// + public DateTime DateBegin => this.wrappedRule.DateBegin; + + /// + /// Gets and sets the date from which the rule ceases to be applicable. + /// + public DateTime? DateEnd + { + get => this.wrappedRule.DateEnd; + set => this.wrappedRule.DateEnd = value; + } + + /// + /// Gets the rule name. + /// + public string Name => this.wrappedRule.Name; + + /// + /// Gets and sets the rule priority compared to other rules (preferably it is unique). + /// + public int Priority + { + get => this.wrappedRule.Priority; + set => this.wrappedRule.Priority = value; + } + + /// + /// Gets the rule root condition. This property is null when rule has no conditions. + /// + public IConditionNode RootCondition + { + get + { + this.rootCondition ??= this.wrappedRule.RootCondition?.ToGenericConditionNode(); + return this.rootCondition!; + } + } + + /// + /// Obtains the non-generic contained on the given instance of . + /// + /// The rule. + /// The non-generic rule. + public static implicit operator Rule(Rule rule) => rule.wrappedRule; + + /// + /// Clones the rule into a different instance. + /// + /// + public virtual Rule Clone() => new(this.wrappedRule.Clone()); + } +} \ No newline at end of file diff --git a/src/Rules.Framework/Generic/RuleExtensions.cs b/src/Rules.Framework/Generic/RuleExtensions.cs new file mode 100644 index 00000000..1733ba86 --- /dev/null +++ b/src/Rules.Framework/Generic/RuleExtensions.cs @@ -0,0 +1,25 @@ +namespace Rules.Framework.Generic +{ + using Rules.Framework; + using Rules.Framework.ConditionNodes; + using Rules.Framework.Core; + using Rules.Framework.Generic.ConditionNodes; + + internal static class RuleExtensions + { + public static IConditionNode ToGenericConditionNode(this IConditionNode rootCondition) + { + if (rootCondition.LogicalOperator == LogicalOperators.Eval) + { + var condition = (ValueConditionNode)rootCondition; + + return new ValueConditionNode(condition); + } + + var composedConditionNode = (ComposedConditionNode)rootCondition; + return new ComposedConditionNode(composedConditionNode); + } + + public static Rule ToGenericRule(this Rule rule) => new(rule); + } +} \ No newline at end of file diff --git a/src/Rules.Framework/Generic/RulesEngine.cs b/src/Rules.Framework/Generic/RulesEngine.cs new file mode 100644 index 00000000..f0d2b003 --- /dev/null +++ b/src/Rules.Framework/Generic/RulesEngine.cs @@ -0,0 +1,154 @@ +namespace Rules.Framework.Generic +{ + using System; + using System.Collections.Generic; + using System.Linq; + using System.Threading.Tasks; + using Rules.Framework.Builder.Validation; + + /// + /// Exposes rules engine logic to provide rule matches to requests. + /// + /// The content type that allows to categorize rules. + /// + /// The condition type that allows to filter rules based on a set of conditions. + /// + public class RulesEngine : IRulesEngine + { + private readonly GenericRuleValidator ruleValidator = GenericRuleValidator.Instance; + private readonly IRulesEngine wrappedRulesEngine; + + internal RulesEngine(IRulesEngine wrappedRulesEngine) + { + this.wrappedRulesEngine = wrappedRulesEngine; + } + + /// + public IRulesEngineOptions Options => this.wrappedRulesEngine.Options; + + /// + public Task ActivateRuleAsync(Rule rule) + { + if (rule is null) + { + throw new ArgumentNullException(nameof(rule)); + } + + // Implicit conversion from Rule to Rule. + return this.wrappedRulesEngine.ActivateRuleAsync(rule); + } + + /// + public Task AddRuleAsync(Rule rule, RuleAddPriorityOption ruleAddPriorityOption) + { + if (rule is null) + { + throw new ArgumentNullException(nameof(rule)); + } + + // Implicit conversion from Rule to Rule. + return this.wrappedRulesEngine.AddRuleAsync(rule, ruleAddPriorityOption); + } + + /// + public async Task CreateContentTypeAsync(TContentType contentType) + { + var contentTypeAsString = GenericConversions.Convert(contentType); + await this.wrappedRulesEngine.CreateContentTypeAsync(contentTypeAsString).ConfigureAwait(false); + } + + /// + public Task DeactivateRuleAsync(Rule rule) + { + if (rule is null) + { + throw new ArgumentNullException(nameof(rule)); + } + + // Implicit conversion from Rule to Rule. + return this.wrappedRulesEngine.DeactivateRuleAsync(rule); + } + + /// + public async Task> GetContentTypesAsync() + { + var contentTypes = await this.wrappedRulesEngine.GetContentTypesAsync().ConfigureAwait(false); + + return contentTypes.Select(x => GenericConversions.Convert(x)).ToArray(); + } + + /// + public async Task> GetUniqueConditionTypesAsync(TContentType contentType, DateTime dateBegin, DateTime dateEnd) + { + var contentTypeAsString = GenericConversions.Convert(contentType); + var conditionTypes = await this.wrappedRulesEngine.GetUniqueConditionTypesAsync(contentTypeAsString, dateBegin, dateEnd).ConfigureAwait(false); + return conditionTypes.Select(t => GenericConversions.Convert(t)).ToArray(); + } + + /// + public async Task>> MatchManyAsync( + TContentType contentType, + DateTime matchDateTime, + IEnumerable> conditions) + { + var contentTypeAsString = GenericConversions.Convert(contentType); + var rules = await this.wrappedRulesEngine.MatchManyAsync( + contentTypeAsString, + matchDateTime, + conditions + .Select(c => new Condition(GenericConversions.Convert(c.Type), c.Value)) + .ToArray()).ConfigureAwait(false); + + return rules.Select(r => r.ToGenericRule()).ToArray(); + } + + /// + public async Task> MatchOneAsync( + TContentType contentType, + DateTime matchDateTime, + IEnumerable> conditions) + { + var contentTypeAsString = GenericConversions.Convert(contentType); + var rule = await this.wrappedRulesEngine.MatchOneAsync( + contentTypeAsString, + matchDateTime, + conditions + .Select(c => new Condition(GenericConversions.Convert(c.Type), c.Value)) + .ToArray()).ConfigureAwait(false); + + return rule?.ToGenericRule()!; + } + + /// + public async Task>> SearchAsync(SearchArgs searchArgs) + { + if (searchArgs is null) + { + throw new ArgumentNullException(nameof(searchArgs)); + } + + var contentTypeAsString = GenericConversions.Convert(searchArgs.ContentType); + var searchArgsNew = new SearchArgs(contentTypeAsString, searchArgs.DateBegin, searchArgs.DateEnd) + { + Conditions = searchArgs.Conditions.Select(c => new Condition(GenericConversions.Convert(c.Type), c.Value)).ToArray(), + ExcludeRulesWithoutSearchConditions = searchArgs.ExcludeRulesWithoutSearchConditions, + }; + + var rules = await this.wrappedRulesEngine.SearchAsync(searchArgsNew).ConfigureAwait(false); + + return rules.Select(r => r.ToGenericRule()).ToArray(); + } + + /// + public Task UpdateRuleAsync(Rule rule) + { + if (rule is null) + { + throw new ArgumentNullException(nameof(rule)); + } + + // Implicit conversion from Rule to Rule. + return this.wrappedRulesEngine.UpdateRuleAsync(rule); + } + } +} \ No newline at end of file diff --git a/src/Rules.Framework/Generics/GenericComposedConditionNode.cs b/src/Rules.Framework/Generics/GenericComposedConditionNode.cs deleted file mode 100644 index 38901d2c..00000000 --- a/src/Rules.Framework/Generics/GenericComposedConditionNode.cs +++ /dev/null @@ -1,16 +0,0 @@ -namespace Rules.Framework.Generics -{ - using System.Collections.Generic; - - /// - /// Defines generic condition node - /// - /// - public sealed class GenericComposedConditionNode : GenericConditionNode - { - /// - /// Gets the child condition nodes. - /// - public IEnumerable ChildConditionNodes { get; internal set; } - } -} \ No newline at end of file diff --git a/src/Rules.Framework/Generics/GenericConditionNode.cs b/src/Rules.Framework/Generics/GenericConditionNode.cs deleted file mode 100644 index 2fab53c8..00000000 --- a/src/Rules.Framework/Generics/GenericConditionNode.cs +++ /dev/null @@ -1,15 +0,0 @@ -namespace Rules.Framework.Generics -{ - using Rules.Framework.Core; - - /// - /// Defines generic condition node - /// - public class GenericConditionNode - { - /// - /// Gets the logical operator to apply to condition node. - /// - public LogicalOperators LogicalOperator { get; internal set; } - } -} \ No newline at end of file diff --git a/src/Rules.Framework/Generics/GenericConditionType.cs b/src/Rules.Framework/Generics/GenericConditionType.cs deleted file mode 100644 index 1a0f9d4a..00000000 --- a/src/Rules.Framework/Generics/GenericConditionType.cs +++ /dev/null @@ -1,31 +0,0 @@ -namespace Rules.Framework.Generics -{ - using System; - - /// - /// Defines generic condition type - /// - public struct GenericConditionType : IEquatable - { - /// - /// Gets or sets the identifier. - /// - /// - /// The identifier. - /// - public string Identifier { get; set; } - - /// - /// Indicates whether the current object is equal to another object of the same type. - /// - /// An object to compare with this object. - /// - /// true if the current object is equal to the other - /// parameter; otherwise, false. - /// - public bool Equals(GenericConditionType other) - { - return other.Identifier == this.Identifier; - } - } -} \ No newline at end of file diff --git a/src/Rules.Framework/Generics/GenericContentType.cs b/src/Rules.Framework/Generics/GenericContentType.cs deleted file mode 100644 index f6c6ae46..00000000 --- a/src/Rules.Framework/Generics/GenericContentType.cs +++ /dev/null @@ -1,31 +0,0 @@ -namespace Rules.Framework.Generics -{ - using System; - - /// - /// Defines generic content type - /// - public struct GenericContentType : IEquatable - { - /// - /// Gets or sets the identifier. - /// - /// - /// The identifier. - /// - public string Identifier { get; set; } - - /// - /// Indicates whether the current object is equal to another object of the same type. - /// - /// An object to compare with this object. - /// - /// true if the current object is equal to the other - /// parameter; otherwise, false. - /// - public bool Equals(GenericContentType other) - { - return other.Identifier == this.Identifier; - } - } -} \ No newline at end of file diff --git a/src/Rules.Framework/Generics/GenericRule.cs b/src/Rules.Framework/Generics/GenericRule.cs deleted file mode 100644 index a6037ed7..00000000 --- a/src/Rules.Framework/Generics/GenericRule.cs +++ /dev/null @@ -1,45 +0,0 @@ -namespace Rules.Framework.Generics -{ - using System; - - /// - /// Defines a generic rule - /// - public sealed class GenericRule - { - /// - /// Gets and sets the if the rules ia active. - /// - public bool Active { get; internal set; } - - /// - /// Gets the content which contains the rule content. - /// - public object Content { get; internal set; } - - /// - /// Gets the date from which the rule begins being applicable. - /// - public DateTime DateBegin { get; internal set; } - - /// - /// Gets and sets the date from which the rule ceases to be applicable. - /// - public DateTime? DateEnd { get; internal set; } - - /// - /// Gets the rule name. - /// - public string Name { get; internal set; } - - /// - /// Gets the rule priority compared to other rules (preferrably it is unique). - /// - public int Priority { get; internal set; } - - /// - /// Gets the rule root condition. This property is null when rule has no conditions. - /// - public GenericConditionNode RootCondition { get; internal set; } - } -} \ No newline at end of file diff --git a/src/Rules.Framework/Generics/GenericRulesEngine.cs b/src/Rules.Framework/Generics/GenericRulesEngine.cs deleted file mode 100644 index 956eaa41..00000000 --- a/src/Rules.Framework/Generics/GenericRulesEngine.cs +++ /dev/null @@ -1,48 +0,0 @@ -namespace Rules.Framework.Generics -{ - using System; - using System.Collections.Generic; - using System.Linq; - using System.Threading.Tasks; - using Rules.Framework.Extensions; - - internal sealed class GenericRulesEngine : IGenericRulesEngine - { - private readonly IRulesEngine rulesEngine; - - public GenericRulesEngine(IRulesEngine rulesEngine) - { - this.rulesEngine = rulesEngine; - } - - public IEnumerable GetContentTypes() - { - if (!typeof(TContentType).IsEnum) - { - throw new ArgumentException("Method only works if TContentType is a enum"); - } - - return Enum.GetValues(typeof(TContentType)) - .Cast() - .Select(t => new GenericContentType - { - Identifier = Enum.Parse(typeof(TContentType), t.ToString()).ToString() - }); - } - - - public PriorityCriterias GetPriorityCriteria() - { - return this.rulesEngine.GetPriorityCriteria(); - } - - public async Task> SearchAsync(SearchArgs genericSearchArgs) - { - var searchArgs = genericSearchArgs.ToSearchArgs(); - - var result = await this.rulesEngine.SearchAsync(searchArgs).ConfigureAwait(false); - - return result.Select(rule => rule.ToGenericRule()).ToList(); - } - } -} \ No newline at end of file diff --git a/src/Rules.Framework/Generics/GenericValueConditionNode.cs b/src/Rules.Framework/Generics/GenericValueConditionNode.cs deleted file mode 100644 index 2d4b7bc3..00000000 --- a/src/Rules.Framework/Generics/GenericValueConditionNode.cs +++ /dev/null @@ -1,30 +0,0 @@ -namespace Rules.Framework.Generics -{ - using Rules.Framework.Core; - - /// - /// Defines generic value condition node - /// - public sealed class GenericValueConditionNode : GenericConditionNode - { - /// - /// Gets the condition node type name. - /// - public string ConditionTypeName { get; internal set; } - - /// - /// Gets the condition node data type. - /// - public DataTypes DataType { get; internal set; } - - /// - /// Gets the condition's operand. - /// - public object Operand { get; internal set; } - - /// - /// Gets the condition node operator. - /// - public Operators Operator { get; internal set; } - } -} \ No newline at end of file diff --git a/src/Rules.Framework/Generics/IGenericRulesEngine.cs b/src/Rules.Framework/Generics/IGenericRulesEngine.cs deleted file mode 100644 index 9c0e322d..00000000 --- a/src/Rules.Framework/Generics/IGenericRulesEngine.cs +++ /dev/null @@ -1,33 +0,0 @@ -namespace Rules.Framework.Generics -{ - using System.Collections.Generic; - using System.Threading.Tasks; - - /// - /// Exposes generic rules engine logic to provide rule matches to requests. - /// - public interface IGenericRulesEngine - { - /// - /// Gets the content types. - /// - /// List of content types - /// - /// Method only works if TContentType is a enum - /// - IEnumerable GetContentTypes(); - - /// - /// Gets the priority criterias. - /// - /// Rules engine priority criterias - PriorityCriterias GetPriorityCriteria(); - - /// - /// Searches the asynchronous. - /// - /// The search arguments. - /// List of generic rules - Task> SearchAsync(SearchArgs genericSearchArgs); - } -} \ No newline at end of file diff --git a/src/Rules.Framework/IConditionNode.cs b/src/Rules.Framework/IConditionNode.cs new file mode 100644 index 00000000..503de12c --- /dev/null +++ b/src/Rules.Framework/IConditionNode.cs @@ -0,0 +1,26 @@ +namespace Rules.Framework +{ + using System.Collections.Generic; + + /// + /// Defines the interface contract for a rule's condition node. + /// + public interface IConditionNode + { + /// + /// Gets the logical operator to apply to condition node. + /// + LogicalOperators LogicalOperator { get; } + + /// + /// Gets the condition node properties. + /// + IDictionary Properties { get; } + + /// + /// Clones the condition node into a different instance. + /// + /// + IConditionNode Clone(); + } +} \ No newline at end of file diff --git a/src/Rules.Framework/IConditionTypeExtractor.cs b/src/Rules.Framework/IConditionTypeExtractor.cs index fb80c7eb..fb9b6014 100644 --- a/src/Rules.Framework/IConditionTypeExtractor.cs +++ b/src/Rules.Framework/IConditionTypeExtractor.cs @@ -6,11 +6,7 @@ namespace Rules.Framework /// /// Extracts Conditions Types from a Group of Rules. /// - /// The content type that allows to categorize rules. - /// - /// The condition type that allows to filter rules based on a set of conditions. - /// - public interface IConditionTypeExtractor + public interface IConditionTypeExtractor { /// /// Get the unique condition types associated with rules of a specific content type. @@ -24,6 +20,6 @@ public interface IConditionTypeExtractor /// All rules matching supplied conditions are returned. /// /// the matched rule; otherwise, null. - IEnumerable GetConditionTypes(IEnumerable> matchedRules); + IEnumerable GetConditionTypes(IEnumerable matchedRules); } } \ No newline at end of file diff --git a/src/Rules.Framework/IRulesDataSource.cs b/src/Rules.Framework/IRulesDataSource.cs index 00ea664c..4629f841 100644 --- a/src/Rules.Framework/IRulesDataSource.cs +++ b/src/Rules.Framework/IRulesDataSource.cs @@ -3,43 +3,54 @@ namespace Rules.Framework using System; using System.Collections.Generic; using System.Threading.Tasks; - using Rules.Framework.Core; /// - /// Exposes the interface contract for a rules data source for specified . + /// Exposes the interface contract for a rules data source for specified content type. /// - /// The content type that allows to categorize rules. - /// The condition type that allows to filter rules based on a set of conditions. - public interface IRulesDataSource + public interface IRulesDataSource { /// /// Adds a new rule to data source. /// /// The rule. /// - Task AddRuleAsync(Rule rule); + Task AddRuleAsync(Rule rule); /// - /// Gets the rules categorized with specified between and . + /// Creates a new content type on the data source. + /// + /// Type of the content. + /// + Task CreateContentTypeAsync(string contentType); + + /// + /// Gets the content types from the data source. + /// + /// + Task> GetContentTypesAsync(); + + /// + /// Gets the rules categorized with specified between + /// and . /// /// the content type categorization. /// the filtering begin date. /// the filtering end date. /// - Task>> GetRulesAsync(TContentType contentType, DateTime dateBegin, DateTime dateEnd); + Task> GetRulesAsync(string contentType, DateTime dateBegin, DateTime dateEnd); /// /// Gets the rules filtered by specified arguments. /// /// The rules filter arguments. /// - Task>> GetRulesByAsync(RulesFilterArgs rulesFilterArgs); + Task> GetRulesByAsync(RulesFilterArgs rulesFilterArgs); /// /// Updates the existent rule on data source. /// /// The rule. /// - Task UpdateRuleAsync(Rule rule); + Task UpdateRuleAsync(Rule rule); } } \ No newline at end of file diff --git a/src/Rules.Framework/IRulesEngine.cs b/src/Rules.Framework/IRulesEngine.cs index 5b29c9ea..c2618b0b 100644 --- a/src/Rules.Framework/IRulesEngine.cs +++ b/src/Rules.Framework/IRulesEngine.cs @@ -3,22 +3,142 @@ namespace Rules.Framework using System; using System.Collections.Generic; using System.Threading.Tasks; - using Rules.Framework.Core; - internal interface IRulesEngine + /// + /// The engine that holds the logic to match and manage rules. + /// + public interface IRulesEngine { - Task AddRuleAsync(Rule rule, RuleAddPriorityOption ruleAddPriorityOption); + /// + /// Gets the options. + /// + /// The options. + IRulesEngineOptions Options { get; } - PriorityCriterias GetPriorityCriteria(); + /// + /// Sets an existent inactive rule as active. + /// + /// The rule. + /// + /// the operation result, containing success/failure indication and messages associated to + /// errors occurred during the operation. + /// + /// rule + Task ActivateRuleAsync(Rule rule); - Task> GetUniqueConditionTypesAsync(TContentType contentType, DateTime dateBegin, DateTime dateEnd); + /// + /// Adds a rule. + /// + /// The rule. + /// The rule add priority option. + /// + /// the operation result, containing success/failure indication and messages associated to + /// errors occurred during the operation. + /// + Task AddRuleAsync(Rule rule, RuleAddPriorityOption ruleAddPriorityOption); - Task>> MatchManyAsync(TContentType contentType, DateTime matchDateTime, IEnumerable> conditions); + /// + /// Creates a content type. + /// + /// Type of the content. + /// + /// the operation result, containing success/failure indication and messages associated to + /// errors occurred during the operation. + /// + /// contentType + Task CreateContentTypeAsync(string contentType); - Task> MatchOneAsync(TContentType contentType, DateTime matchDateTime, IEnumerable> conditions); + /// + /// Sets an existent active rule as inactive. + /// + /// The rule. + /// + /// the operation result, containing success/failure indication and messages associated to + /// errors occurred during the operation. + /// + Task DeactivateRuleAsync(Rule rule); - Task>> SearchAsync(SearchArgs searchArgs); + /// + /// Gets the content types. + /// + /// List of content types + Task> GetContentTypesAsync(); - Task UpdateRuleAsync(Rule rule); + /// + /// Get the unique condition types associated with rules of a specific content type. + /// + /// + /// + /// + /// + /// + /// A set of rules is requested to rules data source and all conditions are evaluated + /// against them to provide a set of matches. + /// + /// All rules matching supplied conditions are returned. + /// + /// the matched rule; otherwise, empty. + Task> GetUniqueConditionTypesAsync(string contentType, DateTime dateBegin, DateTime dateEnd); + + /// + /// Provides all rule matches (if any) to the given content type at the specified and satisfying the supplied . + /// + /// + /// + /// + /// + /// + /// A set of rules is requested to rules data source and all conditions are evaluated + /// against them to provide a set of matches. + /// + /// All rules matching supplied conditions are returned. + /// + /// the matched rule; otherwise, null. + Task> MatchManyAsync(string contentType, DateTime matchDateTime, IEnumerable> conditions); + + /// + /// Provides a rule match (if any) to the given content type at the specified and satisfying the supplied . + /// + /// + /// + /// + /// + /// + /// A set of rules is requested to rules data source and all conditions are evaluated + /// against them to provide a set of matches. + /// + /// + /// If there's more than one match, a rule is selected based on the priority criteria and + /// value: topmost selects the lowest priority number and bottommost selects highest priority. + /// + /// + /// the matched rule; otherwise, null. + Task MatchOneAsync(string contentType, DateTime matchDateTime, IEnumerable> conditions); + + /// + /// Searches for rules on given content type that match on supplied . + /// + /// + /// + /// + /// Only the condition types supplied on input conditions are evaluated, the remaining + /// conditions are ignored. + /// + /// + /// the set of rules matching the conditions. + Task> SearchAsync(SearchArgs searchArgs); + + /// + /// Updates an existing rule. + /// + /// The rule. + /// + /// the operation result, containing success/failure indication and messages associated to + /// errors occurred during the operation. + /// + /// rule + Task UpdateRuleAsync(Rule rule); } } \ No newline at end of file diff --git a/src/Rules.Framework/IRulesEngineOptions.cs b/src/Rules.Framework/IRulesEngineOptions.cs index dd03a1af..9fbd22e9 100644 --- a/src/Rules.Framework/IRulesEngineOptions.cs +++ b/src/Rules.Framework/IRulesEngineOptions.cs @@ -1,14 +1,21 @@ namespace Rules.Framework { - using System; using System.Collections.Generic; - using Rules.Framework.Core; /// - /// The set of rules engine options that influence rules engine rules matching. + /// The set of rules engine options that influence rules engine behavior. /// public interface IRulesEngineOptions { + /// + /// Gets a value indicating whether automatic creation of content types is enabled, allowing + /// them to be added when a rule is added, when enabled. + /// + /// + /// true if content types should be automatically created on rule add; otherwise, false. + /// + bool AutoCreateContentTypes { get; } + /// /// Gets the default values for each of the supported data types. /// diff --git a/src/Rules.Framework/Core/LogicalOperators.cs b/src/Rules.Framework/LogicalOperators.cs similarity index 94% rename from src/Rules.Framework/Core/LogicalOperators.cs rename to src/Rules.Framework/LogicalOperators.cs index f2bd7b9a..40928908 100644 --- a/src/Rules.Framework/Core/LogicalOperators.cs +++ b/src/Rules.Framework/LogicalOperators.cs @@ -1,4 +1,4 @@ -namespace Rules.Framework.Core +namespace Rules.Framework { /// /// Defines the logical operators to use between multiple rule's condition nodes. diff --git a/src/Rules.Framework/Management/IManagementOperation.cs b/src/Rules.Framework/Management/IManagementOperation.cs index 86b9578c..c44acef0 100644 --- a/src/Rules.Framework/Management/IManagementOperation.cs +++ b/src/Rules.Framework/Management/IManagementOperation.cs @@ -4,8 +4,8 @@ namespace Rules.Framework.Management using System.Threading.Tasks; using Rules.Framework.Core; - internal interface IManagementOperation + internal interface IManagementOperation { - Task>> ApplyAsync(IEnumerable> rules); + Task> ApplyAsync(IEnumerable rules); } } \ No newline at end of file diff --git a/src/Rules.Framework/Management/ManagementOperations.cs b/src/Rules.Framework/Management/ManagementOperations.cs index 4d09908f..9033201c 100644 --- a/src/Rules.Framework/Management/ManagementOperations.cs +++ b/src/Rules.Framework/Management/ManagementOperations.cs @@ -6,21 +6,19 @@ namespace Rules.Framework.Management internal static class ManagementOperations { - public static ManagementOperationsSelector Manage( - IEnumerable> rules) - => new ManagementOperationsSelector(rules); + public static ManagementOperationsSelector Manage(IEnumerable rules) => new(rules); - internal sealed class ManagementOperationsSelector + internal sealed class ManagementOperationsSelector { - private readonly IEnumerable> rules; + private readonly IEnumerable rules; - public ManagementOperationsSelector(IEnumerable> rules) + public ManagementOperationsSelector(IEnumerable rules) { this.rules = rules; } - public ManagementOperationsController UsingSource(IRulesSource rulesDataSource) - => new ManagementOperationsController(rulesDataSource, this.rules); + public ManagementOperationsController UsingSource(IRulesSource rulesDataSource) + => new ManagementOperationsController(rulesDataSource, this.rules); } } } \ No newline at end of file diff --git a/src/Rules.Framework/Management/ManagementOperationsController.cs b/src/Rules.Framework/Management/ManagementOperationsController.cs index 67a4b6a4..fd054261 100644 --- a/src/Rules.Framework/Management/ManagementOperationsController.cs +++ b/src/Rules.Framework/Management/ManagementOperationsController.cs @@ -2,55 +2,54 @@ namespace Rules.Framework.Management { using System.Collections.Generic; using System.Threading.Tasks; - using Rules.Framework.Core; using Rules.Framework.Management.Operations; using Rules.Framework.Source; - internal sealed class ManagementOperationsController + internal sealed class ManagementOperationsController { - private readonly List> managementOperations; - private readonly IEnumerable> rules; - private readonly IRulesSource rulesSource; + private readonly List managementOperations; + private readonly IEnumerable rules; + private readonly IRulesSource rulesSource; - public ManagementOperationsController(IRulesSource rulesSource, IEnumerable> rules) + public ManagementOperationsController(IRulesSource rulesSource, IEnumerable rules) { - this.managementOperations = new List>(); + this.managementOperations = new List(); this.rulesSource = rulesSource; this.rules = rules; } - public ManagementOperationsController AddRule(Rule rule) - => this.AddOperation(new AddRuleManagementOperation(this.rulesSource, rule)); + public ManagementOperationsController AddRule(Rule rule) + => this.AddOperation(new AddRuleManagementOperation(this.rulesSource, rule)); + + public ManagementOperationsController DecreasePriority() + => this.AddOperation(new MovePriorityManagementOperation(-1)); public async Task ExecuteOperationsAsync() { - IEnumerable> rulesIntermediateResult = rules; + IEnumerable rulesIntermediateResult = rules; - foreach (IManagementOperation managementOperation in this.managementOperations) + foreach (IManagementOperation managementOperation in this.managementOperations) { rulesIntermediateResult = await managementOperation.ApplyAsync(rulesIntermediateResult).ConfigureAwait(false); } } - public ManagementOperationsController FilterFromThresholdPriorityToBottom(int thresholdPriority) - => this.AddOperation(new FilterPrioritiesRangeManagementOperation(thresholdPriority, null)); - - public ManagementOperationsController FilterPrioritiesRange(int topPriorityThreshold, int bottomPriorityThreshold) - => this.AddOperation(new FilterPrioritiesRangeManagementOperation(topPriorityThreshold, bottomPriorityThreshold)); + public ManagementOperationsController FilterFromThresholdPriorityToBottom(int thresholdPriority) + => this.AddOperation(new FilterPrioritiesRangeManagementOperation(thresholdPriority, null)); - public ManagementOperationsController IncreasePriority() - => this.AddOperation(new MovePriorityManagementOperation(1)); + public ManagementOperationsController FilterPrioritiesRange(int topPriorityThreshold, int bottomPriorityThreshold) + => this.AddOperation(new FilterPrioritiesRangeManagementOperation(topPriorityThreshold, bottomPriorityThreshold)); - public ManagementOperationsController DecreasePriority() - => this.AddOperation(new MovePriorityManagementOperation(-1)); + public ManagementOperationsController IncreasePriority() + => this.AddOperation(new MovePriorityManagementOperation(1)); - public ManagementOperationsController SetRuleForUpdate(Rule updatedRule) - => this.AddOperation(new SetRuleForUpdateManagementOperation(updatedRule)); + public ManagementOperationsController SetRuleForUpdate(Rule updatedRule) + => this.AddOperation(new SetRuleForUpdateManagementOperation(updatedRule)); - public ManagementOperationsController UpdateRules() - => this.AddOperation(new UpdateRulesManagementOperation(this.rulesSource)); + public ManagementOperationsController UpdateRules() + => this.AddOperation(new UpdateRulesManagementOperation(this.rulesSource)); - private ManagementOperationsController AddOperation(IManagementOperation managementOperation) + private ManagementOperationsController AddOperation(IManagementOperation managementOperation) { this.managementOperations.Add(managementOperation); diff --git a/src/Rules.Framework/Management/Operations/AddRuleManagementOperation.cs b/src/Rules.Framework/Management/Operations/AddRuleManagementOperation.cs index 8bd09402..95f127c0 100644 --- a/src/Rules.Framework/Management/Operations/AddRuleManagementOperation.cs +++ b/src/Rules.Framework/Management/Operations/AddRuleManagementOperation.cs @@ -2,33 +2,29 @@ namespace Rules.Framework.Management.Operations { using System.Collections.Generic; using System.Threading.Tasks; - using Rules.Framework.Core; using Rules.Framework.Source; - internal sealed class AddRuleManagementOperation : IManagementOperation + internal sealed class AddRuleManagementOperation : IManagementOperation { - private readonly Rule rule; - private readonly IRulesSource rulesDataSource; + private readonly Rule rule; + private readonly IRulesSource rulesDataSource; - public AddRuleManagementOperation(IRulesSource rulesDataSource, Rule rule) + public AddRuleManagementOperation(IRulesSource rulesDataSource, Rule rule) { this.rulesDataSource = rulesDataSource; this.rule = rule; } - public async Task>> ApplyAsync(IEnumerable> rules) + public async Task> ApplyAsync(IEnumerable rules) { - AddRuleArgs addRuleArgs = new() + var addRuleArgs = new AddRuleArgs { Rule = this.rule, }; await this.rulesDataSource.AddRuleAsync(addRuleArgs).ConfigureAwait(false); - List> rulesResult = new List>(rules) - { - this.rule - }; + var rulesResult = new List(rules) { this.rule }; return rulesResult; } diff --git a/src/Rules.Framework/Management/Operations/FilterPrioritiesRangeManagementOperation.cs b/src/Rules.Framework/Management/Operations/FilterPrioritiesRangeManagementOperation.cs index e138693f..039a8e78 100644 --- a/src/Rules.Framework/Management/Operations/FilterPrioritiesRangeManagementOperation.cs +++ b/src/Rules.Framework/Management/Operations/FilterPrioritiesRangeManagementOperation.cs @@ -5,10 +5,10 @@ namespace Rules.Framework.Management.Operations using System.Threading.Tasks; using Rules.Framework.Core; - internal sealed class FilterPrioritiesRangeManagementOperation : IManagementOperation + internal sealed class FilterPrioritiesRangeManagementOperation : IManagementOperation { - private readonly int? topPriorityThreshold; private readonly int? bottomPriorityThreshold; + private readonly int? topPriorityThreshold; public FilterPrioritiesRangeManagementOperation(int? topPriorityThreshold, int? bottomPriorityThreshold) { @@ -16,9 +16,9 @@ public FilterPrioritiesRangeManagementOperation(int? topPriorityThreshold, int? this.bottomPriorityThreshold = bottomPriorityThreshold; } - public Task>> ApplyAsync(IEnumerable> rules) + public Task> ApplyAsync(IEnumerable rules) { - IEnumerable> filteredRules = rules; + var filteredRules = rules; if (this.topPriorityThreshold.HasValue) { diff --git a/src/Rules.Framework/Management/Operations/MovePriorityManagementOperation.cs b/src/Rules.Framework/Management/Operations/MovePriorityManagementOperation.cs index 4edf5bdb..7fdd1bd3 100644 --- a/src/Rules.Framework/Management/Operations/MovePriorityManagementOperation.cs +++ b/src/Rules.Framework/Management/Operations/MovePriorityManagementOperation.cs @@ -5,7 +5,7 @@ namespace Rules.Framework.Management.Operations using System.Threading.Tasks; using Rules.Framework.Core; - internal sealed class MovePriorityManagementOperation : IManagementOperation + internal sealed class MovePriorityManagementOperation : IManagementOperation { private readonly int priorityMoveFactor; @@ -14,9 +14,9 @@ public MovePriorityManagementOperation(int priorityMoveFactor) this.priorityMoveFactor = priorityMoveFactor; } - public Task>> ApplyAsync(IEnumerable> rules) + public Task> ApplyAsync(IEnumerable rules) { - IEnumerable> updatedPrioritiesRules = rules.Select(r => + IEnumerable updatedPrioritiesRules = rules.Select(r => { r.Priority += this.priorityMoveFactor; return r; diff --git a/src/Rules.Framework/Management/Operations/SetRuleForUpdateManagementOperation.cs b/src/Rules.Framework/Management/Operations/SetRuleForUpdateManagementOperation.cs index f92fb888..185f7a04 100644 --- a/src/Rules.Framework/Management/Operations/SetRuleForUpdateManagementOperation.cs +++ b/src/Rules.Framework/Management/Operations/SetRuleForUpdateManagementOperation.cs @@ -6,18 +6,18 @@ namespace Rules.Framework.Management.Operations using System.Threading.Tasks; using Rules.Framework.Core; - internal sealed class SetRuleForUpdateManagementOperation : IManagementOperation + internal sealed class SetRuleForUpdateManagementOperation : IManagementOperation { - private readonly Rule updatedRule; + private readonly Rule updatedRule; - public SetRuleForUpdateManagementOperation(Rule updatedRule) + public SetRuleForUpdateManagementOperation(Rule updatedRule) { this.updatedRule = updatedRule; } - public Task>> ApplyAsync(IEnumerable> rules) + public Task> ApplyAsync(IEnumerable rules) { - List> result = new List>(rules); + var result = new List(rules); result.RemoveAll(r => string.Equals(r.Name, this.updatedRule.Name, StringComparison.InvariantCultureIgnoreCase)); result.Add(this.updatedRule); diff --git a/src/Rules.Framework/Management/Operations/UpdateRulesManagementOperation.cs b/src/Rules.Framework/Management/Operations/UpdateRulesManagementOperation.cs index e1d9d7f6..49eddbcf 100644 --- a/src/Rules.Framework/Management/Operations/UpdateRulesManagementOperation.cs +++ b/src/Rules.Framework/Management/Operations/UpdateRulesManagementOperation.cs @@ -2,23 +2,22 @@ namespace Rules.Framework.Management.Operations { using System.Collections.Generic; using System.Threading.Tasks; - using Rules.Framework.Core; using Rules.Framework.Source; - internal sealed class UpdateRulesManagementOperation : IManagementOperation + internal sealed class UpdateRulesManagementOperation : IManagementOperation { - private readonly IRulesSource rulesSource; + private readonly IRulesSource rulesSource; - public UpdateRulesManagementOperation(IRulesSource rulesSource) + public UpdateRulesManagementOperation(IRulesSource rulesSource) { this.rulesSource = rulesSource; } - public async Task>> ApplyAsync(IEnumerable> rules) + public async Task> ApplyAsync(IEnumerable rules) { - foreach (Rule existentRule in rules) + foreach (var existentRule in rules) { - UpdateRuleArgs updateRuleArgs = new() + var updateRuleArgs = new UpdateRuleArgs { Rule = existentRule, }; diff --git a/src/Rules.Framework/OperationResult.cs b/src/Rules.Framework/OperationResult.cs new file mode 100644 index 00000000..4352aa34 --- /dev/null +++ b/src/Rules.Framework/OperationResult.cs @@ -0,0 +1,49 @@ +namespace Rules.Framework +{ + using System; + using System.Collections.Generic; + using System.Linq; + + /// + /// Represents the result of an operation performed on the rules engine. + /// + public class OperationResult + { + /// + /// Initializes a new instance of the class. + /// + /// if set to true it represents a success operation result. + /// The errors. + protected OperationResult(bool isSuccess, IEnumerable errors) + { + this.IsSuccess = isSuccess; + this.Errors = errors; + } + + /// + /// Gets the errors occurred during the operation. + /// + /// The errors. + public IEnumerable Errors { get; } + + /// + /// Gets a value indicating whether the operation was successfull or not. + /// + /// true if rule operation was successfull; otherwise, false. + public bool IsSuccess { get; } + + internal static OperationResult Failure(string error) => Failure(new[] { error }); + + internal static OperationResult Failure(IEnumerable errors) + { + if (errors is null) + { + throw new ArgumentNullException(nameof(errors)); + } + + return new OperationResult(isSuccess: false, errors: errors); + } + + internal static OperationResult Success() => new(isSuccess: true, errors: Enumerable.Empty()); + } +} \ No newline at end of file diff --git a/src/Rules.Framework/Core/Operators.cs b/src/Rules.Framework/Operators.cs similarity index 98% rename from src/Rules.Framework/Core/Operators.cs rename to src/Rules.Framework/Operators.cs index d7101a08..d49b3d4c 100644 --- a/src/Rules.Framework/Core/Operators.cs +++ b/src/Rules.Framework/Operators.cs @@ -1,4 +1,4 @@ -namespace Rules.Framework.Core +namespace Rules.Framework { /// /// Defines the set of operators supported for rule's conditions. diff --git a/src/Rules.Framework/Providers/InMemory/DataModel/ComposedConditionNodeDataModel.cs b/src/Rules.Framework/Providers/InMemory/DataModel/ComposedConditionNodeDataModel.cs index 18a0966b..cb788cef 100644 --- a/src/Rules.Framework/Providers/InMemory/DataModel/ComposedConditionNodeDataModel.cs +++ b/src/Rules.Framework/Providers/InMemory/DataModel/ComposedConditionNodeDataModel.cs @@ -1,7 +1,7 @@ namespace Rules.Framework.Providers.InMemory.DataModel { - internal sealed class ComposedConditionNodeDataModel : ConditionNodeDataModel + internal sealed class ComposedConditionNodeDataModel : ConditionNodeDataModel { - public ConditionNodeDataModel[] ChildConditionNodes { get; set; } + public ConditionNodeDataModel[] ChildConditionNodes { get; set; } } } \ No newline at end of file diff --git a/src/Rules.Framework/Providers/InMemory/DataModel/ConditionNodeDataModel.cs b/src/Rules.Framework/Providers/InMemory/DataModel/ConditionNodeDataModel.cs index 75dfd00a..775cdc0b 100644 --- a/src/Rules.Framework/Providers/InMemory/DataModel/ConditionNodeDataModel.cs +++ b/src/Rules.Framework/Providers/InMemory/DataModel/ConditionNodeDataModel.cs @@ -1,9 +1,9 @@ namespace Rules.Framework.Providers.InMemory.DataModel { using System.Collections.Generic; - using Rules.Framework.Core; + using Rules.Framework; - internal class ConditionNodeDataModel + internal class ConditionNodeDataModel { public LogicalOperators LogicalOperator { get; set; } diff --git a/src/Rules.Framework/Providers/InMemory/DataModel/RuleDataModel.cs b/src/Rules.Framework/Providers/InMemory/DataModel/RuleDataModel.cs index 02efa123..a355c9d0 100644 --- a/src/Rules.Framework/Providers/InMemory/DataModel/RuleDataModel.cs +++ b/src/Rules.Framework/Providers/InMemory/DataModel/RuleDataModel.cs @@ -2,13 +2,13 @@ namespace Rules.Framework.Providers.InMemory.DataModel { using System; - internal sealed class RuleDataModel + internal sealed class RuleDataModel { public bool Active { get; set; } = true; public dynamic Content { get; set; } - public TContentType ContentType { get; set; } + public string ContentType { get; set; } public DateTime DateBegin { get; set; } @@ -18,6 +18,6 @@ internal sealed class RuleDataModel public int Priority { get; set; } - public ConditionNodeDataModel RootCondition { get; set; } + public ConditionNodeDataModel RootCondition { get; set; } } -} +} \ No newline at end of file diff --git a/src/Rules.Framework/Providers/InMemory/DataModel/ValueConditionNodeDataModel.cs b/src/Rules.Framework/Providers/InMemory/DataModel/ValueConditionNodeDataModel.cs index a0d43179..5de5fe43 100644 --- a/src/Rules.Framework/Providers/InMemory/DataModel/ValueConditionNodeDataModel.cs +++ b/src/Rules.Framework/Providers/InMemory/DataModel/ValueConditionNodeDataModel.cs @@ -1,10 +1,10 @@ namespace Rules.Framework.Providers.InMemory.DataModel { - using Rules.Framework.Core; + using Rules.Framework; - internal sealed class ValueConditionNodeDataModel : ConditionNodeDataModel + internal sealed class ValueConditionNodeDataModel : ConditionNodeDataModel { - public TConditionType ConditionType { get; set; } + public string ConditionType { get; set; } public DataTypes DataType { get; set; } diff --git a/src/Rules.Framework/Providers/InMemory/IInMemoryRulesStorage.cs b/src/Rules.Framework/Providers/InMemory/IInMemoryRulesStorage.cs index 0ae7d5e6..2ed20e4f 100644 --- a/src/Rules.Framework/Providers/InMemory/IInMemoryRulesStorage.cs +++ b/src/Rules.Framework/Providers/InMemory/IInMemoryRulesStorage.cs @@ -3,14 +3,18 @@ namespace Rules.Framework.Providers.InMemory using System.Collections.Generic; using Rules.Framework.Providers.InMemory.DataModel; - internal interface IInMemoryRulesStorage + internal interface IInMemoryRulesStorage { - void AddRule(RuleDataModel ruleDataModel); + void AddRule(RuleDataModel ruleDataModel); - IReadOnlyCollection> GetAllRules(); + void CreateContentType(string contentType); - IReadOnlyCollection> GetRulesBy(TContentType contentType); + IReadOnlyCollection GetAllRules(); - void UpdateRule(RuleDataModel ruleDataModel); + IReadOnlyCollection GetContentTypes(); + + IReadOnlyCollection GetRulesBy(string contentType); + + void UpdateRule(RuleDataModel ruleDataModel); } } \ No newline at end of file diff --git a/src/Rules.Framework/Providers/InMemory/IRuleFactory.cs b/src/Rules.Framework/Providers/InMemory/IRuleFactory.cs index 57f6b6d3..08936dd9 100644 --- a/src/Rules.Framework/Providers/InMemory/IRuleFactory.cs +++ b/src/Rules.Framework/Providers/InMemory/IRuleFactory.cs @@ -1,12 +1,11 @@ namespace Rules.Framework.Providers.InMemory { - using Rules.Framework.Core; using Rules.Framework.Providers.InMemory.DataModel; - internal interface IRuleFactory + internal interface IRuleFactory { - Rule CreateRule(RuleDataModel ruleDataModel); + Rule CreateRule(RuleDataModel ruleDataModel); - RuleDataModel CreateRule(Rule rule); + RuleDataModel CreateRule(Rule rule); } } \ No newline at end of file diff --git a/src/Rules.Framework/Providers/InMemory/InMemoryProviderRulesDataSource.cs b/src/Rules.Framework/Providers/InMemory/InMemoryProviderRulesDataSource.cs index 2232e333..0179fe16 100644 --- a/src/Rules.Framework/Providers/InMemory/InMemoryProviderRulesDataSource.cs +++ b/src/Rules.Framework/Providers/InMemory/InMemoryProviderRulesDataSource.cs @@ -2,23 +2,21 @@ namespace Rules.Framework.Providers.InMemory { using System; using System.Collections.Generic; + using System.Linq; using System.Threading.Tasks; - using Rules.Framework.Core; /// /// The rules data source implementation for usage backed with a in-memory database. /// - /// The type of the content type. - /// The type of the condition type. - /// - public class InMemoryProviderRulesDataSource : IRulesDataSource + /// + public class InMemoryProviderRulesDataSource : IRulesDataSource { - private readonly IInMemoryRulesStorage inMemoryRulesStorage; - private readonly IRuleFactory ruleFactory; + private readonly IInMemoryRulesStorage inMemoryRulesStorage; + private readonly IRuleFactory ruleFactory; internal InMemoryProviderRulesDataSource( - IInMemoryRulesStorage inMemoryRulesStorage, - IRuleFactory ruleFactory) + IInMemoryRulesStorage inMemoryRulesStorage, + IRuleFactory ruleFactory) { this.inMemoryRulesStorage = inMemoryRulesStorage ?? throw new ArgumentNullException(nameof(inMemoryRulesStorage)); this.ruleFactory = ruleFactory ?? throw new ArgumentNullException(nameof(ruleFactory)); @@ -30,7 +28,7 @@ internal InMemoryProviderRulesDataSource( /// The rule. /// /// rule - public Task AddRuleAsync(Rule rule) + public Task AddRuleAsync(Rule rule) { if (rule is null) { @@ -44,6 +42,41 @@ public Task AddRuleAsync(Rule rule) return Task.CompletedTask; } + /// + /// Creates a new content type on the data source. + /// + /// Type of the content. + /// + /// contentType + /// + /// The content type '{contentType}' already exists. + /// + public Task CreateContentTypeAsync(string contentType) + { + if (string.IsNullOrWhiteSpace(contentType)) + { + throw new ArgumentNullException(nameof(contentType)); + } + + var contentTypes = this.inMemoryRulesStorage.GetContentTypes(); + + if (contentTypes.Contains(contentType, StringComparer.Ordinal)) + { + throw new InvalidOperationException($"The content type '{contentType}' already exists."); + } + + this.inMemoryRulesStorage.CreateContentType(contentType); + + return Task.CompletedTask; + } + + /// + /// Gets the content types from the data source. + /// + /// + public Task> GetContentTypesAsync() + => Task.FromResult>(this.inMemoryRulesStorage.GetContentTypes()); + /// /// Gets the rules categorized with specified between /// and . @@ -52,11 +85,11 @@ public Task AddRuleAsync(Rule rule) /// the filtering begin date. /// the filtering end date. /// - public Task>> GetRulesAsync(TContentType contentType, DateTime dateBegin, DateTime dateEnd) + public Task> GetRulesAsync(string contentType, DateTime dateBegin, DateTime dateEnd) { var filteredByContent = this.inMemoryRulesStorage.GetRulesBy(contentType); - var filteredRules = new Rule[filteredByContent.Count]; + var filteredRules = new Rule[filteredByContent.Count]; var i = 0; foreach (var ruleDataModel in filteredByContent) { @@ -72,7 +105,7 @@ public Task>> GetRulesAsync(TCont Array.Resize(ref filteredRules, i); } - return Task.FromResult>>(filteredRules); + return Task.FromResult>(filteredRules); } /// @@ -81,7 +114,7 @@ public Task>> GetRulesAsync(TCont /// The rules filter arguments. /// /// rulesFilterArgs - public Task>> GetRulesByAsync(RulesFilterArgs rulesFilterArgs) + public Task> GetRulesByAsync(RulesFilterArgs rulesFilterArgs) { if (rulesFilterArgs is null) { @@ -90,11 +123,11 @@ public Task>> GetRulesByAsync(Rul var ruleDataModels = this.inMemoryRulesStorage.GetAllRules(); - var filteredRules = new Rule[ruleDataModels.Count]; + var filteredRules = new Rule[ruleDataModels.Count]; var i = 0; foreach (var ruleDataModel in ruleDataModels) { - if (!object.Equals(rulesFilterArgs.ContentType, default(TContentType)) + if (!object.Equals(rulesFilterArgs.ContentType, default(string)) && !object.Equals(ruleDataModel.ContentType, rulesFilterArgs.ContentType)) { continue; @@ -121,7 +154,7 @@ public Task>> GetRulesByAsync(Rul Array.Resize(ref filteredRules, i); } - return Task.FromResult>>(filteredRules); + return Task.FromResult>(filteredRules); } /// @@ -130,7 +163,7 @@ public Task>> GetRulesByAsync(Rul /// The rule. /// /// rule - public Task UpdateRuleAsync(Rule rule) + public Task UpdateRuleAsync(Rule rule) { if (rule is null) { @@ -144,4 +177,4 @@ public Task UpdateRuleAsync(Rule rule) return Task.CompletedTask; } } -} +} \ No newline at end of file diff --git a/src/Rules.Framework/Providers/InMemory/InMemoryProviderRulesDataSourceSelectorExtensions.cs b/src/Rules.Framework/Providers/InMemory/InMemoryProviderRulesDataSourceSelectorExtensions.cs index 4c0cb8f0..377557e6 100644 --- a/src/Rules.Framework/Providers/InMemory/InMemoryProviderRulesDataSourceSelectorExtensions.cs +++ b/src/Rules.Framework/Providers/InMemory/InMemoryProviderRulesDataSourceSelectorExtensions.cs @@ -12,26 +12,22 @@ public static class InMemoryProviderRulesDataSourceSelectorExtensions /// /// Sets the rules engine data source from a in-memory data source. /// - /// The type of the content type. - /// The type of the condition type. /// The rules data source selector. /// /// rulesDataSourceSelector - public static IConfiguredRulesEngineBuilder SetInMemoryDataSource( - this IRulesDataSourceSelector rulesDataSourceSelector) - => rulesDataSourceSelector.SetInMemoryDataSource(new InMemoryRulesStorage()); + public static IConfiguredRulesEngineBuilder SetInMemoryDataSource( + this IRulesDataSourceSelector rulesDataSourceSelector) + => rulesDataSourceSelector.SetInMemoryDataSource(new InMemoryRulesStorage()); /// /// Sets the rules engine data source from a in-memory data source. /// - /// The type of the content type. - /// The type of the condition type. /// The rules data source selector. /// The service provider. /// /// rulesDataSourceSelector or serviceProvider - public static IConfiguredRulesEngineBuilder SetInMemoryDataSource( - this IRulesDataSourceSelector rulesDataSourceSelector, + public static IConfiguredRulesEngineBuilder SetInMemoryDataSource( + this IRulesDataSourceSelector rulesDataSourceSelector, IServiceProvider serviceProvider) { if (serviceProvider is null) @@ -39,24 +35,24 @@ public static IConfiguredRulesEngineBuilder SetInM throw new ArgumentNullException(nameof(serviceProvider)); } - var inMemoryRulesStorage = (IInMemoryRulesStorage)serviceProvider - .GetService(typeof(IInMemoryRulesStorage)); + var inMemoryRulesStorage = (IInMemoryRulesStorage)serviceProvider + .GetService(typeof(IInMemoryRulesStorage)); return rulesDataSourceSelector.SetInMemoryDataSource(inMemoryRulesStorage); } - private static IConfiguredRulesEngineBuilder SetInMemoryDataSource( - this IRulesDataSourceSelector rulesDataSourceSelector, - IInMemoryRulesStorage inMemoryRulesStorage) + private static IConfiguredRulesEngineBuilder SetInMemoryDataSource( + this IRulesDataSourceSelector rulesDataSourceSelector, + IInMemoryRulesStorage inMemoryRulesStorage) { if (rulesDataSourceSelector is null) { throw new ArgumentNullException(nameof(rulesDataSourceSelector)); } - var ruleFactory = new RuleFactory(); + var ruleFactory = new RuleFactory(); var inMemoryProviderRulesDataSource - = new InMemoryProviderRulesDataSource(inMemoryRulesStorage, ruleFactory); + = new InMemoryProviderRulesDataSource(inMemoryRulesStorage, ruleFactory); return rulesDataSourceSelector.SetDataSource(inMemoryProviderRulesDataSource); } diff --git a/src/Rules.Framework/Providers/InMemory/InMemoryRulesStorage.cs b/src/Rules.Framework/Providers/InMemory/InMemoryRulesStorage.cs index 14a6a70f..791db04c 100644 --- a/src/Rules.Framework/Providers/InMemory/InMemoryRulesStorage.cs +++ b/src/Rules.Framework/Providers/InMemory/InMemoryRulesStorage.cs @@ -6,18 +6,18 @@ namespace Rules.Framework.Providers.InMemory using System.Linq; using Rules.Framework.Providers.InMemory.DataModel; - internal sealed class InMemoryRulesStorage : IInMemoryRulesStorage + internal sealed class InMemoryRulesStorage : IInMemoryRulesStorage { - private readonly ConcurrentDictionary>> rulesByContentType; + private readonly ConcurrentDictionary> rulesByContentType; public InMemoryRulesStorage() { - this.rulesByContentType = new ConcurrentDictionary>>(); + this.rulesByContentType = new ConcurrentDictionary>(StringComparer.Ordinal); } - public void AddRule(RuleDataModel ruleDataModel) + public void AddRule(RuleDataModel ruleDataModel) { - List> contentTypeRules = GetRulesCollectionByContentType(ruleDataModel.ContentType); + var contentTypeRules = GetRulesCollectionByContentType(ruleDataModel.ContentType); lock (contentTypeRules) { @@ -30,23 +30,31 @@ public void AddRule(RuleDataModel ruleDataModel) } } - public IReadOnlyCollection> GetAllRules() + public void CreateContentType(string contentType) + { + _ = this.rulesByContentType.TryAdd(contentType, new List()); + } + + public IReadOnlyCollection GetAllRules() => this.rulesByContentType.SelectMany(kvp => kvp.Value).ToList().AsReadOnly(); - public IReadOnlyCollection> GetRulesBy(TContentType contentType) + public IReadOnlyCollection GetContentTypes() + => this.rulesByContentType.Keys.ToList().AsReadOnly(); + + public IReadOnlyCollection GetRulesBy(string contentType) { - List> contentTypeRules = GetRulesCollectionByContentType(contentType); + var contentTypeRules = GetRulesCollectionByContentType(contentType); return contentTypeRules.AsReadOnly(); } - public void UpdateRule(RuleDataModel ruleDataModel) + public void UpdateRule(RuleDataModel ruleDataModel) { - List> contentTypeRules = GetRulesCollectionByContentType(ruleDataModel.ContentType); + var contentTypeRules = GetRulesCollectionByContentType(ruleDataModel.ContentType); lock (contentTypeRules) { - RuleDataModel existent = contentTypeRules.Find(r => string.Equals(r.Name, ruleDataModel.Name, StringComparison.Ordinal)); + var existent = contentTypeRules.Find(r => string.Equals(r.Name, ruleDataModel.Name, StringComparison.Ordinal)); if (existent is null) { throw new InvalidOperationException($"Rule with name '{ruleDataModel.Name}' does not exist, no update can be done."); @@ -57,7 +65,7 @@ public void UpdateRule(RuleDataModel ruleDataModel } } - private List> GetRulesCollectionByContentType(TContentType contentType) => this.rulesByContentType - .GetOrAdd(contentType, (ct) => new List>()); + private List GetRulesCollectionByContentType(string contentType) => this.rulesByContentType + .GetOrAdd(contentType, _ => new List()); } } \ No newline at end of file diff --git a/src/Rules.Framework/Providers/InMemory/RuleFactory.cs b/src/Rules.Framework/Providers/InMemory/RuleFactory.cs index bf099b8a..6e23b227 100644 --- a/src/Rules.Framework/Providers/InMemory/RuleFactory.cs +++ b/src/Rules.Framework/Providers/InMemory/RuleFactory.cs @@ -3,25 +3,27 @@ namespace Rules.Framework.Providers.InMemory using System; using System.Linq; using System.Runtime.CompilerServices; + using Rules.Framework; + using Rules.Framework.ConditionNodes; using Rules.Framework.Core; - using Rules.Framework.Core.ConditionNodes; using Rules.Framework.Providers.InMemory.DataModel; - internal sealed class RuleFactory : IRuleFactory + internal sealed class RuleFactory : IRuleFactory { - public Rule CreateRule(RuleDataModel ruleDataModel) + public Rule CreateRule(RuleDataModel ruleDataModel) { if (ruleDataModel is null) { throw new ArgumentNullException(nameof(ruleDataModel)); } - var contentContainer = new ContentContainer(ruleDataModel.ContentType, (_) => ruleDataModel.Content); + var contentContainer = new ContentContainer((_) => ruleDataModel.Content); - var rule = new Rule + var rule = new Rule { Active = ruleDataModel.Active, ContentContainer = contentContainer, + ContentType = ruleDataModel.ContentType, DateBegin = ruleDataModel.DateBegin, DateEnd = ruleDataModel.DateEnd, Name = ruleDataModel.Name, @@ -32,7 +34,7 @@ public Rule CreateRule(RuleDataModel CreateRule(Rule rule) + public RuleDataModel CreateRule(Rule rule) { if (rule is null) { @@ -41,10 +43,10 @@ public RuleDataModel CreateRule(Rule(); - var ruleDataModel = new RuleDataModel + var ruleDataModel = new RuleDataModel { Content = content, - ContentType = rule.ContentContainer.ContentType, + ContentType = rule.ContentType, DateBegin = rule.DateBegin, DateEnd = rule.DateEnd, Name = rule.Name, @@ -56,17 +58,17 @@ public RuleDataModel CreateRule(Rule ConvertConditionNode(ConditionNodeDataModel conditionNodeDataModel) + private static IConditionNode ConvertConditionNode(ConditionNodeDataModel conditionNodeDataModel) { if (conditionNodeDataModel.LogicalOperator == LogicalOperators.Eval) { - return CreateValueConditionNode((ValueConditionNodeDataModel)conditionNodeDataModel); + return CreateValueConditionNode((ValueConditionNodeDataModel)conditionNodeDataModel); } - var composedConditionNodeDataModel = (ComposedConditionNodeDataModel)conditionNodeDataModel; + var composedConditionNodeDataModel = (ComposedConditionNodeDataModel)conditionNodeDataModel; var count = composedConditionNodeDataModel.ChildConditionNodes.Length; var childConditionNodeDataModels = composedConditionNodeDataModel.ChildConditionNodes; - var childConditionNodes = new IConditionNode[count]; + var childConditionNodes = new IConditionNode[count]; var i = -1; while (++i < count) @@ -74,16 +76,16 @@ private static IConditionNode ConvertConditionNode(ConditionNode childConditionNodes[i] = ConvertConditionNode(childConditionNodeDataModels[i]); } - return new ComposedConditionNode( + return new ComposedConditionNode( composedConditionNodeDataModel.LogicalOperator, childConditionNodes, new PropertiesDictionary(conditionNodeDataModel.Properties)); } [MethodImpl(MethodImplOptions.AggressiveInlining)] - private static ValueConditionNodeDataModel ConvertValueConditionNode(ValueConditionNode valueConditionNode) + private static ValueConditionNodeDataModel ConvertValueConditionNode(ValueConditionNode valueConditionNode) { - return new ValueConditionNodeDataModel + return new ValueConditionNodeDataModel { ConditionType = valueConditionNode.ConditionType, LogicalOperator = LogicalOperators.Eval, @@ -95,9 +97,9 @@ private static ValueConditionNodeDataModel ConvertValueCondition } [MethodImpl(MethodImplOptions.AggressiveInlining)] - private static IConditionNode CreateValueConditionNode(ValueConditionNodeDataModel conditionNodeDataModel) + private static IConditionNode CreateValueConditionNode(ValueConditionNodeDataModel conditionNodeDataModel) { - return new ValueConditionNode( + return new ValueConditionNode( conditionNodeDataModel.DataType, conditionNodeDataModel.ConditionType, conditionNodeDataModel.Operator, @@ -106,17 +108,17 @@ private static IConditionNode CreateValueConditionNode(ValueCond } [MethodImpl(MethodImplOptions.AggressiveInlining)] - private ConditionNodeDataModel ConvertComposedConditionNode(ComposedConditionNode composedConditionNode) + private ConditionNodeDataModel ConvertComposedConditionNode(ComposedConditionNode composedConditionNode) { - var conditionNodeDataModels = new ConditionNodeDataModel[composedConditionNode.ChildConditionNodes.Count()]; + var conditionNodeDataModels = new ConditionNodeDataModel[composedConditionNode.ChildConditionNodes.Count()]; var i = 0; - foreach (IConditionNode child in composedConditionNode.ChildConditionNodes) + foreach (var child in composedConditionNode.ChildConditionNodes) { conditionNodeDataModels[i++] = ConvertConditionNode(child); } - return new ComposedConditionNodeDataModel + return new ComposedConditionNodeDataModel { ChildConditionNodes = conditionNodeDataModels, LogicalOperator = composedConditionNode.LogicalOperator, @@ -124,14 +126,14 @@ private ConditionNodeDataModel ConvertComposedConditionNode(Comp }; } - private ConditionNodeDataModel ConvertConditionNode(IConditionNode conditionNode) + private ConditionNodeDataModel ConvertConditionNode(IConditionNode conditionNode) { if (conditionNode.LogicalOperator == LogicalOperators.Eval) { - return ConvertValueConditionNode((ValueConditionNode)conditionNode); + return ConvertValueConditionNode((ValueConditionNode)conditionNode); } - return ConvertComposedConditionNode((ComposedConditionNode)conditionNode); + return ConvertComposedConditionNode((ComposedConditionNode)conditionNode); } } } \ No newline at end of file diff --git a/src/Rules.Framework/Providers/InMemory/ServiceCollectionExtensions.cs b/src/Rules.Framework/Providers/InMemory/ServiceCollectionExtensions.cs index 51cb7c06..577c57d8 100644 --- a/src/Rules.Framework/Providers/InMemory/ServiceCollectionExtensions.cs +++ b/src/Rules.Framework/Providers/InMemory/ServiceCollectionExtensions.cs @@ -10,16 +10,14 @@ public static class ServiceCollectionExtensions /// /// Adds the in memory rules data source with specified service lifetime. /// - /// The type of the content type. - /// The type of the condition type. /// The service descriptors. /// The service lifetime. /// - public static IServiceCollection AddInMemoryRulesDataSource(this IServiceCollection serviceDescriptors, ServiceLifetime serviceLifetime) + public static IServiceCollection AddInMemoryRulesDataSource(this IServiceCollection serviceDescriptors, ServiceLifetime serviceLifetime) { - ServiceDescriptor item = ServiceDescriptor.Describe( - typeof(IInMemoryRulesStorage), - (sp) => new InMemoryRulesStorage(), + var item = ServiceDescriptor.Describe( + typeof(IInMemoryRulesStorage), + _ => new InMemoryRulesStorage(), serviceLifetime); serviceDescriptors.Add(item); diff --git a/src/Rules.Framework/Core/Rule.cs b/src/Rules.Framework/Rule.cs similarity index 56% rename from src/Rules.Framework/Core/Rule.cs rename to src/Rules.Framework/Rule.cs index 31f8009b..d4db94af 100644 --- a/src/Rules.Framework/Core/Rule.cs +++ b/src/Rules.Framework/Rule.cs @@ -1,25 +1,28 @@ -namespace Rules.Framework.Core +namespace Rules.Framework { using System; + using Rules.Framework.Builder; + using Rules.Framework.Builder.Generic; /// /// Defines a rule. /// - /// The content type that allows to categorize rules. - /// - /// The condition type that allows to filter rules based on a set of conditions. - /// - public class Rule + public class Rule { /// - /// Gets and sets the if the rules ia active. + /// Gets and sets the if the rules is active. /// public bool Active { get; internal set; } = true; /// /// Gets the content container which contains the rule content. /// - public ContentContainer ContentContainer { get; internal set; } + public ContentContainer ContentContainer { get; internal set; } + + /// + /// Gets the content type. + /// + public string ContentType { get; internal set; } /// /// Gets the date from which the rule begins being applicable. @@ -44,15 +47,32 @@ public class Rule /// /// Gets the rule root condition. This property is null when rule has no conditions. /// - public IConditionNode RootCondition { get; internal set; } + public IConditionNode RootCondition { get; internal set; } + + /// + /// Creates a new rule with generic content type and condition type. + /// + /// The type of the content type. + /// The type of the condition type. + /// + public static IRuleBuilder New() + => new RuleBuilder(); + + /// + /// Creates a new rule. + /// + /// + public static IRuleBuilder New() + => new RuleBuilder(); /// /// Clones the rule into a different instance. /// /// - public virtual Rule Clone() - => new Rule + public virtual Rule Clone() + => new Rule { + ContentType = this.ContentType, ContentContainer = this.ContentContainer, DateBegin = this.DateBegin, DateEnd = this.DateEnd, @@ -62,4 +82,4 @@ public virtual Rule Clone() Active = this.Active, }; } -} +} \ No newline at end of file diff --git a/src/Rules.Framework/RuleBuilder.cs b/src/Rules.Framework/RuleBuilder.cs deleted file mode 100644 index 8cf16a57..00000000 --- a/src/Rules.Framework/RuleBuilder.cs +++ /dev/null @@ -1,19 +0,0 @@ -namespace Rules.Framework -{ - using Rules.Framework.Builder; - - /// - /// The builder to create a new rule. - /// - public static class RuleBuilder - { - /// - /// Creates a new rule. - /// - /// The type of the content type. - /// The type of the condition type. - /// - public static IRuleBuilder NewRule() - => new RuleBuilder(); - } -} \ No newline at end of file diff --git a/src/Rules.Framework/RuleOperationResult.cs b/src/Rules.Framework/RuleOperationResult.cs deleted file mode 100644 index c3e68edf..00000000 --- a/src/Rules.Framework/RuleOperationResult.cs +++ /dev/null @@ -1,51 +0,0 @@ -namespace Rules.Framework -{ - using System; - using System.Collections.Generic; - using System.Linq; - - /// - /// Represents the result of a rule operation. - /// - public class RuleOperationResult - { - /// - /// Initializes a new instance of the class. - /// - /// if set to true [is success]. - /// The errors. - protected RuleOperationResult(bool isSuccess, IEnumerable errors) - { - this.IsSuccess = isSuccess; - this.Errors = errors; - } - - /// - /// Gets the errors occurred during rule operation. - /// - /// - /// The errors. - /// - public IEnumerable Errors { get; } - - /// - /// Gets a value indicating whether rule operation was successfull or not. - /// - /// - /// true if rule operation was successfull; otherwise, false. - /// - public bool IsSuccess { get; } - - internal static RuleOperationResult Error(IEnumerable errors) - { - if (errors is null) - { - throw new ArgumentNullException(nameof(errors)); - } - - return new RuleOperationResult(false, errors); - } - - internal static RuleOperationResult Success() => new RuleOperationResult(true, Enumerable.Empty()); - } -} \ No newline at end of file diff --git a/src/Rules.Framework/RulesEngine.cs b/src/Rules.Framework/RulesEngine.cs index f6af512a..420e4b91 100644 --- a/src/Rules.Framework/RulesEngine.cs +++ b/src/Rules.Framework/RulesEngine.cs @@ -8,7 +8,6 @@ namespace Rules.Framework using System.Text; using System.Threading.Tasks; using Rules.Framework.Builder.Validation; - using Rules.Framework.Core; using Rules.Framework.Evaluation; using Rules.Framework.Extensions; using Rules.Framework.Management; @@ -18,40 +17,33 @@ namespace Rules.Framework /// /// Exposes rules engine logic to provide rule matches to requests. /// - /// The content type that allows to categorize rules. - /// - /// The condition type that allows to filter rules based on a set of conditions. - /// - public class RulesEngine : IRulesEngine + public class RulesEngine : IRulesEngine { - private readonly IConditionsEvalEngine conditionsEvalEngine; - private readonly IConditionTypeExtractor conditionTypeExtractor; - private readonly RulesEngineOptions rulesEngineOptions; - private readonly IRulesSource rulesSource; - private readonly RuleValidator ruleValidator = RuleValidator.Instance; + private readonly IConditionsEvalEngine conditionsEvalEngine; + private readonly IConditionTypeExtractor conditionTypeExtractor; + private readonly IRulesSource rulesSource; + private readonly RuleValidator ruleValidator = RuleValidator.Instance; private readonly IValidatorProvider validatorProvider; internal RulesEngine( - IConditionsEvalEngine conditionsEvalEngine, - IRulesSource rulesSource, + IConditionsEvalEngine conditionsEvalEngine, + IRulesSource rulesSource, IValidatorProvider validatorProvider, RulesEngineOptions rulesEngineOptions, - IConditionTypeExtractor conditionTypeExtractor) + IConditionTypeExtractor conditionTypeExtractor) { this.conditionsEvalEngine = conditionsEvalEngine; this.rulesSource = rulesSource; this.validatorProvider = validatorProvider; - this.rulesEngineOptions = rulesEngineOptions; + this.Options = rulesEngineOptions; this.conditionTypeExtractor = conditionTypeExtractor; } - /// - /// Activates the specified existing rule. - /// - /// The rule. - /// - /// rule - public Task ActivateRuleAsync(Rule rule) + /// + public IRulesEngineOptions Options { get; } + + /// + public Task ActivateRuleAsync(Rule rule) { if (rule is null) { @@ -63,17 +55,8 @@ public Task ActivateRuleAsync(Rule - /// Adds a new rule. - /// - /// The rule. - /// The rule add priority option. - /// - /// rule or rule - /// - /// The placement option '{ruleAddPriorityOption.PriorityOption}' is not supported. - /// - public Task AddRuleAsync(Rule rule, RuleAddPriorityOption ruleAddPriorityOption) + /// + public Task AddRuleAsync(Rule rule, RuleAddPriorityOption ruleAddPriorityOption) { if (rule is null) { @@ -82,19 +65,32 @@ public Task AddRuleAsync(Rule if (ruleAddPriorityOption is null) { - throw new ArgumentNullException(nameof(rule)); + throw new ArgumentNullException(nameof(ruleAddPriorityOption)); } return this.AddRuleInternalAsync(rule, ruleAddPriorityOption); } - /// - /// Deactivates the specified existing rule. - /// - /// The rule. - /// - /// rule - public Task DeactivateRuleAsync(Rule rule) + /// + public async Task CreateContentTypeAsync(string contentType) + { + if (string.IsNullOrWhiteSpace(contentType)) + { + throw new ArgumentNullException(nameof(contentType)); + } + + var getContentTypesArgs = new GetContentTypesArgs(); + var existentContentTypes = await this.rulesSource.GetContentTypesAsync(getContentTypesArgs).ConfigureAwait(false); + if (existentContentTypes.Contains(contentType, StringComparer.Ordinal)) + { + return OperationResult.Failure($"The content type '{contentType}' already exists."); + } + + return await this.CreateContentTypeInternalAsync(contentType).ConfigureAwait(false); + } + + /// + public Task DeactivateRuleAsync(Rule rule) { if (rule is null) { @@ -106,32 +102,21 @@ public Task DeactivateRuleAsync(Rule - /// Gets the priority criterias. - /// - /// Rules engine priority criterias - public PriorityCriterias GetPriorityCriteria() + /// + public Task> GetContentTypesAsync() { - return this.rulesEngineOptions.PriorityCriteria; + return this.rulesSource.GetContentTypesAsync(new GetContentTypesArgs()); } - /// - /// Get the unique condition types associated with rules of a specific content type. - /// - /// - /// - /// - /// - /// - /// A set of rules is requested to rules data source and all conditions are evaluated - /// against them to provide a set of matches. - /// - /// All rules matching supplied conditions are returned. - /// - /// the matched rule; otherwise, empty. - public async Task> GetUniqueConditionTypesAsync(TContentType contentType, DateTime dateBegin, DateTime dateEnd) + /// + public async Task> GetUniqueConditionTypesAsync(string contentType, DateTime dateBegin, DateTime dateEnd) { - var getRulesArgs = new GetRulesArgs + if (string.IsNullOrWhiteSpace(contentType)) + { + throw new ArgumentNullException(nameof(contentType)); + } + + var getRulesArgs = new GetRulesArgs { ContentType = contentType, DateBegin = dateBegin, @@ -143,74 +128,53 @@ public async Task> GetUniqueConditionTypesAsync(TCon return this.conditionTypeExtractor.GetConditionTypes(matchedRules); } - /// - /// Provides all rule matches (if any) to the given content type at the specified and satisfying the supplied . - /// - /// - /// - /// - /// - /// - /// A set of rules is requested to rules data source and all conditions are evaluated - /// against them to provide a set of matches. - /// - /// All rules matching supplied conditions are returned. - /// - /// the matched rule; otherwise, null. - public async Task>> MatchManyAsync( - TContentType contentType, + /// + public async Task> MatchManyAsync( + string contentType, DateTime matchDateTime, - IEnumerable> conditions) + IEnumerable> conditions) { + if (string.IsNullOrWhiteSpace(contentType)) + { + throw new ArgumentNullException(nameof(contentType)); + } + var evaluationOptions = new EvaluationOptions { ExcludeRulesWithoutSearchConditions = false, MatchMode = MatchModes.Exact, }; - var getRulesArgs = new GetRulesArgs + var getRulesArgs = new GetRulesArgs { ContentType = contentType, DateBegin = matchDateTime, DateEnd = matchDateTime, }; - var conditionsAsDictionary = conditions.ToDictionary(ks => ks.Type, ks => ks.Value); + var conditionsAsDictionary = conditions.ToDictionary(ks => ks.Type, ks => ks.Value, StringComparer.Ordinal); var orderedRules = await this.GetRulesOrderedAscendingAsync(getRulesArgs).ConfigureAwait(false); return this.EvalAll(orderedRules, evaluationOptions, conditionsAsDictionary, active: true); } - /// - /// Provides a rule match (if any) to the given content type at the specified and satisfying the supplied . - /// - /// - /// - /// - /// - /// - /// A set of rules is requested to rules data source and all conditions are evaluated - /// against them to provide a set of matches. - /// - /// - /// If there's more than one match, a rule is selected based on the priority criteria and - /// value: topmost selects the lowest priority number and bottommost selects highest priority. - /// - /// - /// the matched rule; otherwise, null. - public async Task> MatchOneAsync( - TContentType contentType, + /// + public async Task MatchOneAsync( + string contentType, DateTime matchDateTime, - IEnumerable> conditions) + IEnumerable> conditions) { + if (string.IsNullOrWhiteSpace(contentType)) + { + throw new ArgumentNullException(nameof(contentType)); + } + var evaluationOptions = new EvaluationOptions { ExcludeRulesWithoutSearchConditions = false, MatchMode = MatchModes.Exact, }; - var getRulesArgs = new GetRulesArgs + var getRulesArgs = new GetRulesArgs { ContentType = contentType, DateBegin = matchDateTime, @@ -219,30 +183,20 @@ public async Task> MatchOneAsync( var conditionsAsDictionary = conditions.ToDictionary(ks => ks.Type, ks => ks.Value); var orderedRules = await this.GetRulesOrderedAscendingAsync(getRulesArgs).ConfigureAwait(false); - return this.rulesEngineOptions.PriorityCriteria == PriorityCriterias.TopmostRuleWins + return this.Options.PriorityCriteria == PriorityCriterias.TopmostRuleWins ? EvalOneTraverse(orderedRules, evaluationOptions, conditionsAsDictionary, active: true) : EvalOneReverse(orderedRules, evaluationOptions, conditionsAsDictionary, active: true); } - /// - /// Searches for rules on given content type that match on supplied . - /// - /// - /// - /// - /// Only the condition types supplied on input conditions are evaluated, the remaining - /// conditions are ignored. - /// - /// - /// the set of rules matching the conditions. - public async Task>> SearchAsync(SearchArgs searchArgs) + /// + public async Task> SearchAsync(SearchArgs searchArgs) { if (searchArgs is null) { throw new ArgumentNullException(nameof(searchArgs)); } - var validator = this.validatorProvider.GetValidatorFor>(); + var validator = this.validatorProvider.GetValidatorFor>(); var validationResult = await validator.ValidateAsync(searchArgs).ConfigureAwait(false); if (!validationResult.IsValid) { @@ -265,7 +219,7 @@ public async Task>> SearchAsync(S MatchMode = MatchModes.Search, }; - var getRulesArgs = new GetRulesArgs + var getRulesArgs = new GetRulesArgs { ContentType = searchArgs.ContentType, DateBegin = searchArgs.DateBegin, @@ -277,13 +231,8 @@ public async Task>> SearchAsync(S return this.EvalAll(orderedRules, evaluationOptions, conditionsAsDictionary, searchArgs.Active); } - /// - /// Updates the specified existing rule. - /// - /// The rule. - /// - /// rule - public Task UpdateRuleAsync(Rule rule) + /// + public Task UpdateRuleAsync(Rule rule) { if (rule is null) { @@ -293,12 +242,26 @@ public Task UpdateRuleAsync(Rule AddRuleInternalAsync(Rule rule, RuleAddPriorityOption ruleAddPriorityOption) + private async Task AddRuleInternalAsync(Rule rule, RuleAddPriorityOption ruleAddPriorityOption) { var errors = new List(); - var rulesFilterArgs = new GetRulesFilteredArgs + var contentTypes = await this.rulesSource.GetContentTypesAsync(new GetContentTypesArgs()).ConfigureAwait(false); + + if (!contentTypes.Contains(rule.ContentType, StringComparer.Ordinal)) { - ContentType = rule.ContentContainer.ContentType, + if (!this.Options.AutoCreateContentTypes) + { + errors.Add($"Specified content type '{rule.ContentType}' does not exist. " + + $"Please create the content type first or set the rules engine option '{nameof(this.Options.AutoCreateContentTypes)}' to true."); + return OperationResult.Failure(errors); + } + + await this.CreateContentTypeInternalAsync(rule.ContentType).ConfigureAwait(false); + } + + var rulesFilterArgs = new GetRulesFilteredArgs + { + ContentType = rule.ContentType, }; var existentRules = await this.rulesSource.GetRulesFilteredAsync(rulesFilterArgs).ConfigureAwait(false); @@ -316,7 +279,7 @@ private async Task AddRuleInternalAsync(Rule AddRuleInternalAsync(Rule rule, IEnumerable> existentRules) + private async Task AddRuleInternalAtBottomAsync(Rule rule, IEnumerable existentRules) { rule.Priority = !existentRules.Any() ? 1 : existentRules.Max(r => r.Priority) + 1; @@ -360,7 +323,7 @@ await ManagementOperations.Manage(existentRules) .ConfigureAwait(false); } - private async Task AddRuleInternalAtPriorityNumberAsync(Rule rule, RuleAddPriorityOption ruleAddPriorityOption, IEnumerable> existentRules) + private async Task AddRuleInternalAtPriorityNumberAsync(Rule rule, RuleAddPriorityOption ruleAddPriorityOption, IEnumerable existentRules) { var priorityMin = existentRules.MinOrDefault(r => r.Priority); var priorityMax = existentRules.MaxOrDefault(r => r.Priority); @@ -381,7 +344,7 @@ await ManagementOperations.Manage(existentRules) .ConfigureAwait(false); } - private async Task AddRuleInternalAtRuleNameAsync(Rule rule, RuleAddPriorityOption ruleAddPriorityOption, IEnumerable> existentRules) + private async Task AddRuleInternalAtRuleNameAsync(Rule rule, RuleAddPriorityOption ruleAddPriorityOption, IEnumerable existentRules) { var firstPriorityToIncrement = existentRules .FirstOrDefault(r => string.Equals(r.Name, ruleAddPriorityOption.AtRuleNameOptionValue, StringComparison.OrdinalIgnoreCase)) @@ -398,7 +361,7 @@ await ManagementOperations.Manage(existentRules) .ConfigureAwait(false); } - private async Task AddRuleInternalAtTopAsync(Rule rule, IEnumerable> existentRules) + private async Task AddRuleInternalAtTopAsync(Rule rule, IEnumerable existentRules) { rule.Priority = 1; @@ -411,15 +374,22 @@ await ManagementOperations.Manage(existentRules) .ConfigureAwait(false); } - private IEnumerable> EvalAll( - List> orderedRules, + private async Task CreateContentTypeInternalAsync(string contentType) + { + var createContentTypeArgs = new CreateContentTypeArgs { Name = contentType }; + await this.rulesSource.CreateContentTypeAsync(createContentTypeArgs).ConfigureAwait(false); + return OperationResult.Success(); + } + + private IEnumerable EvalAll( + List orderedRules, EvaluationOptions evaluationOptions, - Dictionary conditionsAsDictionary, + Dictionary conditionsAsDictionary, bool? active) { // Begins evaluation at the first element of the given list as parameter. Returns all // rules that match. Assumes given list is ordered. - var matchedRules = new List>(orderedRules.Count); + var matchedRules = new List(orderedRules.Count); foreach (var rule in orderedRules) { if (this.EvalRule(rule, evaluationOptions, conditionsAsDictionary, active)) @@ -431,15 +401,15 @@ private IEnumerable> EvalAll( return matchedRules.AsReadOnly(); } - private Rule EvalOneReverse( - List> rules, + private Rule EvalOneReverse( + List rules, EvaluationOptions evaluationOptions, - Dictionary conditionsAsDictionary, + Dictionary conditionsAsDictionary, bool? active) { // Begins evaluation at the last element of the given list as parameter. Returns the // first rule that matches. Assumes given list is ordered. - for (int i = rules.Count - 1; i >= 0; i--) + for (var i = rules.Count - 1; i >= 0; i--) { var rule = rules[i]; if (this.EvalRule(rule, evaluationOptions, conditionsAsDictionary, active)) @@ -451,15 +421,15 @@ private Rule EvalOneReverse( return null!; } - private Rule EvalOneTraverse( - List> rules, + private Rule EvalOneTraverse( + List rules, EvaluationOptions evaluationOptions, - Dictionary conditionsAsDictionary, + Dictionary conditionsAsDictionary, bool? active) { // Begins evaluation at the first element of the given list as parameter. Returns the // first rule that matches. Assumes given list is ordered. - for (int i = 0; i < rules.Count; i++) + for (var i = 0; i < rules.Count; i++) { var rule = rules[i]; if (this.EvalRule(rule, evaluationOptions, conditionsAsDictionary, active)) @@ -473,16 +443,16 @@ private Rule EvalOneTraverse( [MethodImpl(MethodImplOptions.AggressiveInlining)] private bool EvalRule( - Rule rule, + Rule rule, EvaluationOptions evaluationOptions, - Dictionary conditionsAsDictionary, + Dictionary conditionsAsDictionary, bool? active) => rule.Active == active.GetValueOrDefault(defaultValue: true) && (rule.RootCondition == null || this.conditionsEvalEngine.Eval(rule.RootCondition, conditionsAsDictionary, evaluationOptions)); - private async Task>> GetRulesOrderedAscendingAsync(GetRulesArgs getRulesArgs) + private async Task> GetRulesOrderedAscendingAsync(GetRulesArgs getRulesArgs) { var rules = await this.rulesSource.GetRulesAsync(getRulesArgs).ConfigureAwait(false); - var orderedRules = new List>(rules.Count()); + var orderedRules = new List(rules.Count()); var greatestPriority = 0; foreach (var rule in rules) { @@ -493,7 +463,7 @@ private async Task>> GetRulesOrderedAsce continue; } - for (int i = 0; i < orderedRules.Count; i++) + for (var i = 0; i < orderedRules.Count; i++) { var currentRule = orderedRules[i]; if (rule.Priority < currentRule.Priority) @@ -507,11 +477,11 @@ private async Task>> GetRulesOrderedAsce return orderedRules; } - private async Task UpdateRuleInternalAsync(Rule rule) + private async Task UpdateRuleInternalAsync(Rule rule) { - var rulesFilterArgs = new GetRulesFilteredArgs + var rulesFilterArgs = new GetRulesFilteredArgs { - ContentType = rule.ContentContainer.ContentType, + ContentType = rule.ContentType, }; var existentRules = await this.rulesSource.GetRulesFilteredAsync(rulesFilterArgs).ConfigureAwait(false); @@ -519,14 +489,14 @@ private async Task UpdateRuleInternalAsync(Rule string.Equals(r.Name, rule.Name, StringComparison.OrdinalIgnoreCase)); if (existentRule is null) { - return RuleOperationResult.Error(new[] { $"Rule with name '{rule.Name}' does not exist." }); + return OperationResult.Failure($"Rule with name '{rule.Name}' does not exist."); } var validationResult = this.ruleValidator.Validate(rule); if (!validationResult.IsValid) { - return RuleOperationResult.Error(validationResult.Errors.Select(ve => ve.ErrorMessage)); + return OperationResult.Failure(validationResult.Errors.Select(ve => ve.ErrorMessage)); } var topPriorityThreshold = Math.Min(rule.Priority, existentRule.Priority); @@ -567,7 +537,7 @@ await ManagementOperations.Manage(existentRules) break; } - return RuleOperationResult.Success(); + return OperationResult.Success(); } } } \ No newline at end of file diff --git a/src/Rules.Framework/RulesEngineBuilder.cs b/src/Rules.Framework/RulesEngineBuilder.cs index 12053412..b3089c61 100644 --- a/src/Rules.Framework/RulesEngineBuilder.cs +++ b/src/Rules.Framework/RulesEngineBuilder.cs @@ -11,7 +11,7 @@ public static class RulesEngineBuilder /// /// Starts building a rules engine. /// - /// a content type selector. - public static IContentTypeSelector CreateRulesEngine() => new ContentTypeSelector(); + /// the rules data source selector. + public static IRulesDataSourceSelector CreateRulesEngine() => new RulesDataSourceSelector(); } } \ No newline at end of file diff --git a/src/Rules.Framework/RulesEngineOptions.cs b/src/Rules.Framework/RulesEngineOptions.cs index caa0d78a..d6a9161e 100644 --- a/src/Rules.Framework/RulesEngineOptions.cs +++ b/src/Rules.Framework/RulesEngineOptions.cs @@ -1,8 +1,6 @@ namespace Rules.Framework { - using System; using System.Collections.Generic; - using Rules.Framework.Core; /// /// The set of rules engine options that influence rules engine rules matching. @@ -14,6 +12,15 @@ private RulesEngineOptions() this.DataTypeDefaults = new Dictionary(); } + /// + /// Gets or sets a value indicating whether automatic creation of content types is enabled, + /// allowing them to be added when a rule is added, when enabled. + /// + /// + /// true if content types should be automatically created on rule add; otherwise, false. + /// + public bool AutoCreateContentTypes { get; set; } + /// /// Gets the default values for each of the supported data types. /// @@ -60,16 +67,17 @@ public static RulesEngineOptions NewWithDefaults() MissingConditionBehavior = MissingConditionBehaviors.UseDataTypeDefault, PriorityCriteria = PriorityCriterias.TopmostRuleWins, DataTypeDefaults = - { - [DataTypes.Boolean] = default(bool), - [DataTypes.Decimal] = default(decimal), - [DataTypes.Integer] = default(int), - [DataTypes.String] = string.Empty, - [DataTypes.ArrayBoolean] = default(bool), - [DataTypes.ArrayDecimal] = default(decimal), - [DataTypes.ArrayInteger] = default(int), - [DataTypes.ArrayString] = string.Empty, - }, + { + [DataTypes.Boolean] = default(bool), + [DataTypes.Decimal] = default(decimal), + [DataTypes.Integer] = default(int), + [DataTypes.String] = string.Empty, + [DataTypes.ArrayBoolean] = default(bool), + [DataTypes.ArrayDecimal] = default(decimal), + [DataTypes.ArrayInteger] = default(int), + [DataTypes.ArrayString] = string.Empty, + }, + AutoCreateContentTypes = false, }; return rulesEngineOptions; diff --git a/src/Rules.Framework/RulesFilterArgs.cs b/src/Rules.Framework/RulesFilterArgs.cs index fa3993c7..a5554947 100644 --- a/src/Rules.Framework/RulesFilterArgs.cs +++ b/src/Rules.Framework/RulesFilterArgs.cs @@ -5,32 +5,25 @@ namespace Rules.Framework /// /// The set of arguments to filter rules. /// - /// The type of the content type. [ExcludeFromCodeCoverage] - public class RulesFilterArgs + public class RulesFilterArgs { /// /// Gets or sets the content type to filter. /// - /// - /// The type of the content. - /// - public TContentType ContentType { get; set; } + /// The type of the content. + public string ContentType { get; set; } /// /// Gets or sets the name to filter. /// - /// - /// The name. - /// + /// The name. public string Name { get; set; } /// /// Gets or sets the priority to filter. /// - /// - /// The priority. - /// + /// The priority. public int? Priority { get; set; } } } \ No newline at end of file diff --git a/src/Rules.Framework/Serialization/IContentSerializationProvider.cs b/src/Rules.Framework/Serialization/IContentSerializationProvider.cs index d8a866b8..bf88bf96 100644 --- a/src/Rules.Framework/Serialization/IContentSerializationProvider.cs +++ b/src/Rules.Framework/Serialization/IContentSerializationProvider.cs @@ -1,17 +1,17 @@ namespace Rules.Framework.Serialization { /// - /// Defines the interface contract for a content serialization provider. Provides content serializers per - /// value, allowing for customization of serializers per each content type. + /// Defines the interface contract for a content serialization provider. Provides content + /// serializers per content type value, allowing for customization of serializers per each + /// content type. /// - /// The content type that allows to categorize rules. - public interface IContentSerializationProvider + public interface IContentSerializationProvider { /// /// Gets the content serializer associated with the given . /// /// the content type. /// the content serializer to deal with contents for specified content type. - IContentSerializer GetContentSerializer(TContentType contentType); + IContentSerializer GetContentSerializer(string contentType); } } \ No newline at end of file diff --git a/src/Rules.Framework/Serialization/SerializedContentContainer.cs b/src/Rules.Framework/Serialization/SerializedContentContainer.cs index 7d3892df..47d1cddb 100644 --- a/src/Rules.Framework/Serialization/SerializedContentContainer.cs +++ b/src/Rules.Framework/Serialization/SerializedContentContainer.cs @@ -1,24 +1,22 @@ namespace Rules.Framework.Serialization { - using Rules.Framework.Core; - /// - /// Defines a content container that relies on a to get a content serializer to deserialize container content. + /// Defines a content container that relies on a to + /// get a content serializer to deserialize container content. /// - /// The content type that allows to categorize rules. - public class SerializedContentContainer : ContentContainer + public class SerializedContentContainer : ContentContainer { /// - /// Creates a new . + /// Creates a new . /// /// the content type. /// the serialized content. /// the content serialization provider. public SerializedContentContainer( - TContentType contentType, + string contentType, object serializedContent, - IContentSerializationProvider contentSerializationProvider) - : base(contentType, (t) => contentSerializationProvider.GetContentSerializer(contentType).Deserialize(serializedContent, t)) + IContentSerializationProvider contentSerializationProvider) + : base((t) => contentSerializationProvider.GetContentSerializer(contentType).Deserialize(serializedContent, t)) { } } diff --git a/src/Rules.Framework/Source/AddRuleArgs.cs b/src/Rules.Framework/Source/AddRuleArgs.cs index 220349b2..f4fac87d 100644 --- a/src/Rules.Framework/Source/AddRuleArgs.cs +++ b/src/Rules.Framework/Source/AddRuleArgs.cs @@ -1,9 +1,7 @@ namespace Rules.Framework.Source { - using Rules.Framework.Core; - - internal sealed class AddRuleArgs + internal sealed class AddRuleArgs { - public Rule Rule { get; set; } + public Rule Rule { get; set; } } } \ No newline at end of file diff --git a/src/Rules.Framework/Source/AddRuleDelegate.cs b/src/Rules.Framework/Source/AddRuleDelegate.cs index d14822ab..90b1ed5d 100644 --- a/src/Rules.Framework/Source/AddRuleDelegate.cs +++ b/src/Rules.Framework/Source/AddRuleDelegate.cs @@ -2,6 +2,5 @@ namespace Rules.Framework.Source { using System.Threading.Tasks; - internal delegate Task AddRuleDelegate( - AddRuleArgs args); -} + internal delegate Task AddRuleDelegate(AddRuleArgs args); +} \ No newline at end of file diff --git a/src/Rules.Framework/Source/CreateContentTypeArgs.cs b/src/Rules.Framework/Source/CreateContentTypeArgs.cs new file mode 100644 index 00000000..aec48026 --- /dev/null +++ b/src/Rules.Framework/Source/CreateContentTypeArgs.cs @@ -0,0 +1,7 @@ +namespace Rules.Framework.Source +{ + internal sealed class CreateContentTypeArgs + { + public string Name { get; set; } + } +} \ No newline at end of file diff --git a/src/Rules.Framework/Source/CreateContentTypeDelegate.cs b/src/Rules.Framework/Source/CreateContentTypeDelegate.cs new file mode 100644 index 00000000..5c61f918 --- /dev/null +++ b/src/Rules.Framework/Source/CreateContentTypeDelegate.cs @@ -0,0 +1,6 @@ +namespace Rules.Framework.Source +{ + using System.Threading.Tasks; + + internal delegate Task CreateContentTypeDelegate(CreateContentTypeArgs args); +} \ No newline at end of file diff --git a/src/Rules.Framework/Source/GetContentTypesArgs.cs b/src/Rules.Framework/Source/GetContentTypesArgs.cs new file mode 100644 index 00000000..dbd824fb --- /dev/null +++ b/src/Rules.Framework/Source/GetContentTypesArgs.cs @@ -0,0 +1,6 @@ +namespace Rules.Framework.Source +{ + internal sealed class GetContentTypesArgs + { + } +} \ No newline at end of file diff --git a/src/Rules.Framework/Source/GetContentTypesDelegate.cs b/src/Rules.Framework/Source/GetContentTypesDelegate.cs new file mode 100644 index 00000000..4f611270 --- /dev/null +++ b/src/Rules.Framework/Source/GetContentTypesDelegate.cs @@ -0,0 +1,7 @@ +namespace Rules.Framework.Source +{ + using System.Collections.Generic; + using System.Threading.Tasks; + + internal delegate Task> GetContentTypesDelegate(GetContentTypesArgs args); +} \ No newline at end of file diff --git a/src/Rules.Framework/Source/GetRulesArgs.cs b/src/Rules.Framework/Source/GetRulesArgs.cs index 39f7259a..1d7cc200 100644 --- a/src/Rules.Framework/Source/GetRulesArgs.cs +++ b/src/Rules.Framework/Source/GetRulesArgs.cs @@ -2,12 +2,12 @@ namespace Rules.Framework.Source { using System; - internal sealed class GetRulesArgs + internal sealed class GetRulesArgs { - public TContentType ContentType { get; set; } + public string ContentType { get; set; } public DateTime DateBegin { get; set; } public DateTime DateEnd { get; set; } } -} +} \ No newline at end of file diff --git a/src/Rules.Framework/Source/GetRulesDelegate.cs b/src/Rules.Framework/Source/GetRulesDelegate.cs index 7ca02458..19b3bf8e 100644 --- a/src/Rules.Framework/Source/GetRulesDelegate.cs +++ b/src/Rules.Framework/Source/GetRulesDelegate.cs @@ -1,9 +1,7 @@ namespace Rules.Framework.Source { - using Rules.Framework.Core; using System.Collections.Generic; using System.Threading.Tasks; - internal delegate Task>> GetRulesDelegate( - GetRulesArgs args); -} + internal delegate Task> GetRulesDelegate(GetRulesArgs args); +} \ No newline at end of file diff --git a/src/Rules.Framework/Source/GetRulesFilteredArgs.cs b/src/Rules.Framework/Source/GetRulesFilteredArgs.cs index 0a9e1eb7..e3864b23 100644 --- a/src/Rules.Framework/Source/GetRulesFilteredArgs.cs +++ b/src/Rules.Framework/Source/GetRulesFilteredArgs.cs @@ -1,8 +1,8 @@ namespace Rules.Framework.Source { - internal sealed class GetRulesFilteredArgs + internal sealed class GetRulesFilteredArgs { - public TContentType ContentType { get; set; } + public string ContentType { get; set; } public string Name { get; set; } diff --git a/src/Rules.Framework/Source/GetRulesFilteredDelegate.cs b/src/Rules.Framework/Source/GetRulesFilteredDelegate.cs index 06a1fd98..f9ae2302 100644 --- a/src/Rules.Framework/Source/GetRulesFilteredDelegate.cs +++ b/src/Rules.Framework/Source/GetRulesFilteredDelegate.cs @@ -1,9 +1,7 @@ namespace Rules.Framework.Source { - using Rules.Framework.Core; using System.Collections.Generic; using System.Threading.Tasks; - internal delegate Task>> GetRulesFilteredDelegate( - GetRulesFilteredArgs args); -} + internal delegate Task> GetRulesFilteredDelegate(GetRulesFilteredArgs args); +} \ No newline at end of file diff --git a/src/Rules.Framework/Source/IRulesSource.cs b/src/Rules.Framework/Source/IRulesSource.cs index f711a60f..dc6d3e3d 100644 --- a/src/Rules.Framework/Source/IRulesSource.cs +++ b/src/Rules.Framework/Source/IRulesSource.cs @@ -1,17 +1,20 @@ namespace Rules.Framework.Source { - using Rules.Framework.Core; using System.Collections.Generic; using System.Threading.Tasks; - internal interface IRulesSource + internal interface IRulesSource { - Task AddRuleAsync(AddRuleArgs args); + Task AddRuleAsync(AddRuleArgs args); - Task>> GetRulesAsync(GetRulesArgs args); + Task CreateContentTypeAsync(CreateContentTypeArgs args); - Task>> GetRulesFilteredAsync(GetRulesFilteredArgs args); + Task> GetContentTypesAsync(GetContentTypesArgs args); - Task UpdateRuleAsync(UpdateRuleArgs args); + Task> GetRulesAsync(GetRulesArgs args); + + Task> GetRulesFilteredAsync(GetRulesFilteredArgs args); + + Task UpdateRuleAsync(UpdateRuleArgs args); } -} +} \ No newline at end of file diff --git a/src/Rules.Framework/Source/IRulesSourceMiddleware.cs b/src/Rules.Framework/Source/IRulesSourceMiddleware.cs index 470ec214..3c5054a8 100644 --- a/src/Rules.Framework/Source/IRulesSourceMiddleware.cs +++ b/src/Rules.Framework/Source/IRulesSourceMiddleware.cs @@ -1,25 +1,32 @@ namespace Rules.Framework.Source { - using Rules.Framework.Core; using System.Collections.Generic; using System.Threading.Tasks; - internal interface IRulesSourceMiddleware + internal interface IRulesSourceMiddleware { Task HandleAddRuleAsync( - AddRuleArgs args, - AddRuleDelegate next); + AddRuleArgs args, + AddRuleDelegate next); - Task>> HandleGetRulesAsync( - GetRulesArgs args, - GetRulesDelegate next); + Task HandleCreateContentTypeAsync( + CreateContentTypeArgs args, + CreateContentTypeDelegate next); - Task>> HandleGetRulesFilteredAsync( - GetRulesFilteredArgs args, - GetRulesFilteredDelegate next); + Task> HandleGetContentTypesAsync( + GetContentTypesArgs args, + GetContentTypesDelegate next); + + Task> HandleGetRulesAsync( + GetRulesArgs args, + GetRulesDelegate next); + + Task> HandleGetRulesFilteredAsync( + GetRulesFilteredArgs args, + GetRulesFilteredDelegate next); Task HandleUpdateRuleAsync( - UpdateRuleArgs args, - UpdateRuleDelegate next); + UpdateRuleArgs args, + UpdateRuleDelegate next); } -} +} \ No newline at end of file diff --git a/src/Rules.Framework/Source/RulesSource.cs b/src/Rules.Framework/Source/RulesSource.cs index c21618be..2cf837b3 100644 --- a/src/Rules.Framework/Source/RulesSource.cs +++ b/src/Rules.Framework/Source/RulesSource.cs @@ -2,51 +2,66 @@ namespace Rules.Framework.Source { using System.Collections.Generic; using System.Threading.Tasks; - using Rules.Framework.Core; - internal sealed class RulesSource : IRulesSource + internal sealed class RulesSource : IRulesSource { - private readonly AddRuleDelegate addRuleDelegate; - private readonly GetRulesDelegate getRulesDelegate; - private readonly GetRulesFilteredDelegate getRulesFilteredDelegate; - private readonly UpdateRuleDelegate updateRuleDelegate; + private readonly AddRuleDelegate addRuleDelegate; + private readonly CreateContentTypeDelegate createContentTypeDelegate; + private readonly GetContentTypesDelegate getContentTypesDelegate; + private readonly GetRulesDelegate getRulesDelegate; + private readonly GetRulesFilteredDelegate getRulesFilteredDelegate; + private readonly IRulesDataSource rulesDataSource; + private readonly UpdateRuleDelegate updateRuleDelegate; public RulesSource( - IRulesDataSource rulesDataSource, - IEnumerable> middlewares) + IRulesDataSource rulesDataSource, + IEnumerable middlewares) { - var middlewaresLinkedList = new LinkedList>(middlewares); + var middlewaresLinkedList = new LinkedList(middlewares); this.addRuleDelegate = CreateAddRulePipelineDelegate(rulesDataSource, middlewaresLinkedList); + this.createContentTypeDelegate = CreateCreateContentTypePipelineDelegate(rulesDataSource, middlewaresLinkedList); + this.getContentTypesDelegate = CreateGetContentTypesPipelineDelegate(rulesDataSource, middlewaresLinkedList); this.getRulesDelegate = CreateGetRulesPipelineDelegate(rulesDataSource, middlewaresLinkedList); this.getRulesFilteredDelegate = CreateGetRulesFilteredPipelineDelegate(rulesDataSource, middlewaresLinkedList); this.updateRuleDelegate = CreateUpdateRulePipelineDelegate(rulesDataSource, middlewaresLinkedList); + this.rulesDataSource = rulesDataSource; } - public async Task AddRuleAsync(AddRuleArgs args) + public async Task AddRuleAsync(AddRuleArgs args) { await this.addRuleDelegate.Invoke(args).ConfigureAwait(false); } - public async Task>> GetRulesAsync(GetRulesArgs args) + public async Task CreateContentTypeAsync(CreateContentTypeArgs args) + { + await this.createContentTypeDelegate(args).ConfigureAwait(false); + } + + public async Task> GetContentTypesAsync(GetContentTypesArgs args) + { + return await this.getContentTypesDelegate(args).ConfigureAwait(false); + } + + public async Task> GetRulesAsync(GetRulesArgs args) { return await this.getRulesDelegate.Invoke(args).ConfigureAwait(false); } - public async Task>> GetRulesFilteredAsync(GetRulesFilteredArgs args) + public async Task> GetRulesFilteredAsync(GetRulesFilteredArgs args) { return await this.getRulesFilteredDelegate.Invoke(args).ConfigureAwait(false); } - public async Task UpdateRuleAsync(UpdateRuleArgs args) + public async Task UpdateRuleAsync(UpdateRuleArgs args) { await this.updateRuleDelegate.Invoke(args).ConfigureAwait(false); } - private static AddRuleDelegate CreateAddRulePipelineDelegate( - IRulesDataSource rulesDataSource, - LinkedList> middlewares) + private static AddRuleDelegate CreateAddRulePipelineDelegate( + IRulesDataSource rulesDataSource, + LinkedList middlewares) { - AddRuleDelegate action = async (args) => await rulesDataSource.AddRuleAsync(args.Rule).ConfigureAwait(false); + AddRuleDelegate action = async (args) => await rulesDataSource.AddRuleAsync(args.Rule).ConfigureAwait(false); if (middlewares.Count > 0) { @@ -66,14 +81,62 @@ private static AddRuleDelegate CreateAddRulePipeli return action; } - private static GetRulesFilteredDelegate CreateGetRulesFilteredPipelineDelegate( - IRulesDataSource rulesDataSource, - LinkedList> middlewares) + private static CreateContentTypeDelegate CreateCreateContentTypePipelineDelegate( + IRulesDataSource rulesDataSource, + LinkedList middlewares) + { + CreateContentTypeDelegate action = async (args) => await rulesDataSource.CreateContentTypeAsync(args.Name).ConfigureAwait(false); + + if (middlewares.Count > 0) + { + var middlewareNode = middlewares.Last; + + while (middlewareNode is { }) + { + var middleware = middlewareNode.Value; + var immutableAction = action; + action = async (args) => await middleware.HandleCreateContentTypeAsync(args, immutableAction).ConfigureAwait(false); + + // Get previous middleware node. + middlewareNode = middlewareNode.Previous; + } + } + + return action; + } + + private static GetContentTypesDelegate CreateGetContentTypesPipelineDelegate( + IRulesDataSource rulesDataSource, + LinkedList middlewares) + { + GetContentTypesDelegate action = async (_) => await rulesDataSource.GetContentTypesAsync().ConfigureAwait(false); + + if (middlewares.Count > 0) + { + var middlewareNode = middlewares.Last; + + while (middlewareNode is { }) + { + var middleware = middlewareNode.Value; + var immutableAction = action; + action = async (args) => await middleware.HandleGetContentTypesAsync(args, immutableAction).ConfigureAwait(false); + + // Get previous middleware node. + middlewareNode = middlewareNode.Previous; + } + } + + return action; + } + + private static GetRulesFilteredDelegate CreateGetRulesFilteredPipelineDelegate( + IRulesDataSource rulesDataSource, + LinkedList middlewares) { - GetRulesFilteredDelegate action = + GetRulesFilteredDelegate action = async (args) => { - RulesFilterArgs rulesFilterArgs = new() + RulesFilterArgs rulesFilterArgs = new() { ContentType = args.ContentType, Name = args.Name, @@ -101,11 +164,11 @@ private static GetRulesFilteredDelegate CreateGetR return action; } - private static GetRulesDelegate CreateGetRulesPipelineDelegate( - IRulesDataSource rulesDataSource, - LinkedList> middlewares) + private static GetRulesDelegate CreateGetRulesPipelineDelegate( + IRulesDataSource rulesDataSource, + LinkedList middlewares) { - GetRulesDelegate action = + GetRulesDelegate action = async (args) => await rulesDataSource.GetRulesAsync(args.ContentType, args.DateBegin, args.DateEnd).ConfigureAwait(false); @@ -127,11 +190,11 @@ private static GetRulesDelegate CreateGetRulesPipe return action; } - private static UpdateRuleDelegate CreateUpdateRulePipelineDelegate( - IRulesDataSource rulesDataSource, - LinkedList> middlewares) + private static UpdateRuleDelegate CreateUpdateRulePipelineDelegate( + IRulesDataSource rulesDataSource, + LinkedList middlewares) { - UpdateRuleDelegate action = + UpdateRuleDelegate action = async (args) => await rulesDataSource.UpdateRuleAsync(args.Rule).ConfigureAwait(false); diff --git a/src/Rules.Framework/Source/UpdateRuleArgs.cs b/src/Rules.Framework/Source/UpdateRuleArgs.cs index 69ae0981..26df9b5d 100644 --- a/src/Rules.Framework/Source/UpdateRuleArgs.cs +++ b/src/Rules.Framework/Source/UpdateRuleArgs.cs @@ -1,9 +1,7 @@ namespace Rules.Framework.Source { - using Rules.Framework.Core; - - internal sealed class UpdateRuleArgs + internal sealed class UpdateRuleArgs { - public Rule Rule { get; set; } + public Rule Rule { get; set; } } } \ No newline at end of file diff --git a/src/Rules.Framework/Source/UpdateRuleDelegate.cs b/src/Rules.Framework/Source/UpdateRuleDelegate.cs index 650d981f..8428516c 100644 --- a/src/Rules.Framework/Source/UpdateRuleDelegate.cs +++ b/src/Rules.Framework/Source/UpdateRuleDelegate.cs @@ -2,6 +2,5 @@ namespace Rules.Framework.Source { using System.Threading.Tasks; - internal delegate Task UpdateRuleDelegate( - UpdateRuleArgs args); -} + internal delegate Task UpdateRuleDelegate(UpdateRuleArgs args); +} \ No newline at end of file diff --git a/tests/Rules.Framework.BenchmarkTests/Program.cs b/tests/Rules.Framework.BenchmarkTests/Program.cs index bc12cfa0..65b5885c 100644 --- a/tests/Rules.Framework.BenchmarkTests/Program.cs +++ b/tests/Rules.Framework.BenchmarkTests/Program.cs @@ -8,7 +8,7 @@ using BenchmarkDotNet.Running; using McMaster.Extensions.CommandLineUtils; -[assembly: SimpleJob(RuntimeMoniker.Net60)] +[assembly: SimpleJob(RuntimeMoniker.Net80)] internal static class Program { diff --git a/tests/Rules.Framework.BenchmarkTests/Rules.Framework.BenchmarkTests.csproj b/tests/Rules.Framework.BenchmarkTests/Rules.Framework.BenchmarkTests.csproj index c6a32a4a..49bda302 100644 --- a/tests/Rules.Framework.BenchmarkTests/Rules.Framework.BenchmarkTests.csproj +++ b/tests/Rules.Framework.BenchmarkTests/Rules.Framework.BenchmarkTests.csproj @@ -11,8 +11,8 @@ - - + + diff --git a/tests/Rules.Framework.BenchmarkTests/Tests/Benchmark1/Benchmark1.cs b/tests/Rules.Framework.BenchmarkTests/Tests/Benchmark1/Benchmark1.cs index b7d87530..5f1bc6aa 100644 --- a/tests/Rules.Framework.BenchmarkTests/Tests/Benchmark1/Benchmark1.cs +++ b/tests/Rules.Framework.BenchmarkTests/Tests/Benchmark1/Benchmark1.cs @@ -2,12 +2,13 @@ namespace Rules.Framework.BenchmarkTests.Tests.Benchmark1 { using System.Threading.Tasks; using BenchmarkDotNet.Attributes; + using Rules.Framework.Generic; [SkewnessColumn, KurtosisColumn] public class Benchmark1 : IBenchmark { private readonly Scenario6Data benchmarkData = new Scenario6Data(); - private RulesEngine? rulesEngine; + private IRulesEngine? genericRulesEngine; [ParamsAllValues] public bool EnableCompilation { get; set; } @@ -18,15 +19,13 @@ public class Benchmark1 : IBenchmark [Benchmark] public async Task RunAsync() { - await this.rulesEngine!.MatchOneAsync(ContentTypes.ContentType1, this.benchmarkData.MatchDate, this.benchmarkData.Conditions).ConfigureAwait(false); + await this.genericRulesEngine!.MatchOneAsync(ContentTypes.ContentType1, this.benchmarkData.MatchDate, this.benchmarkData.Conditions).ConfigureAwait(false); } [GlobalSetup] public async Task SetUpAsync() { - this.rulesEngine = RulesEngineBuilder.CreateRulesEngine() - .WithContentType() - .WithConditionType() + var rulesEngine = RulesEngineBuilder.CreateRulesEngine() .SetDataSourceForBenchmark(this.Provider!, nameof(Benchmark1)) .Configure(options => { @@ -34,17 +33,21 @@ public async Task SetUpAsync() }) .Build(); + await rulesEngine.CreateContentTypeAsync(nameof(ContentTypes.ContentType1)); + foreach (var rule in this.benchmarkData.Rules) { - await this.rulesEngine.AddRuleAsync(rule, RuleAddPriorityOption.AtTop).ConfigureAwait(false); + await rulesEngine.AddRuleAsync(rule, RuleAddPriorityOption.AtTop); } + + this.genericRulesEngine = rulesEngine.MakeGeneric(); } [GlobalCleanup] public async Task TearDownAsync() { await Extensions.TearDownProviderAsync(this.Provider!, nameof(Benchmark1)).ConfigureAwait(false); - this.rulesEngine = null; + this.genericRulesEngine = null; } } } \ No newline at end of file diff --git a/tests/Rules.Framework.BenchmarkTests/Tests/Benchmark2/Benchmark2.cs b/tests/Rules.Framework.BenchmarkTests/Tests/Benchmark2/Benchmark2.cs index 66444194..c3d32b0f 100644 --- a/tests/Rules.Framework.BenchmarkTests/Tests/Benchmark2/Benchmark2.cs +++ b/tests/Rules.Framework.BenchmarkTests/Tests/Benchmark2/Benchmark2.cs @@ -2,12 +2,13 @@ namespace Rules.Framework.BenchmarkTests.Tests.Benchmark2 { using System.Threading.Tasks; using BenchmarkDotNet.Attributes; + using Rules.Framework.Generic; [SkewnessColumn, KurtosisColumn] public class Benchmark2 : IBenchmark { private readonly Scenario7Data benchmarkData = new Scenario7Data(); - private RulesEngine? rulesEngine; + private IRulesEngine? genericRulesEngine; [ParamsAllValues] public bool EnableCompilation { get; set; } @@ -18,15 +19,13 @@ public class Benchmark2 : IBenchmark [Benchmark] public async Task RunAsync() { - await this.rulesEngine!.MatchOneAsync(ContentTypes.Songs, this.benchmarkData.MatchDate, this.benchmarkData.Conditions).ConfigureAwait(false); + await this.genericRulesEngine!.MatchOneAsync(ContentTypes.Songs, this.benchmarkData.MatchDate, this.benchmarkData.Conditions).ConfigureAwait(false); } [GlobalSetup] public async Task SetUpAsync() { - this.rulesEngine = RulesEngineBuilder.CreateRulesEngine() - .WithContentType() - .WithConditionType() + var rulesEngine = RulesEngineBuilder.CreateRulesEngine() .SetDataSourceForBenchmark(this.Provider!, nameof(Benchmark2)) .Configure(options => { @@ -34,17 +33,21 @@ public async Task SetUpAsync() }) .Build(); + await rulesEngine.CreateContentTypeAsync(nameof(ContentTypes.Songs)); + foreach (var rule in this.benchmarkData.Rules) { - await this.rulesEngine.AddRuleAsync(rule, RuleAddPriorityOption.AtTop).ConfigureAwait(false); + await rulesEngine.AddRuleAsync(rule, RuleAddPriorityOption.AtTop).ConfigureAwait(false); } + + this.genericRulesEngine = rulesEngine.MakeGeneric(); } [GlobalCleanup] public async Task TearDownAsync() { await Extensions.TearDownProviderAsync(this.Provider!, nameof(Benchmark2)).ConfigureAwait(false); - this.rulesEngine = null; + this.genericRulesEngine = null; } } } \ No newline at end of file diff --git a/tests/Rules.Framework.BenchmarkTests/Tests/Benchmark3/Benchmark3.cs b/tests/Rules.Framework.BenchmarkTests/Tests/Benchmark3/Benchmark3.cs index 900f0e91..60339bf2 100644 --- a/tests/Rules.Framework.BenchmarkTests/Tests/Benchmark3/Benchmark3.cs +++ b/tests/Rules.Framework.BenchmarkTests/Tests/Benchmark3/Benchmark3.cs @@ -2,12 +2,13 @@ namespace Rules.Framework.BenchmarkTests.Tests.Benchmark3 { using System.Threading.Tasks; using BenchmarkDotNet.Attributes; + using Rules.Framework.Generic; [SkewnessColumn, KurtosisColumn] public class Benchmark3 : IBenchmark { private readonly Scenario8Data benchmarkData = new Scenario8Data(); - private RulesEngine? rulesEngine; + private IRulesEngine? genericRulesEngine; [ParamsAllValues] public bool EnableCompilation { get; set; } @@ -18,15 +19,13 @@ public class Benchmark3 : IBenchmark [Benchmark] public async Task RunAsync() { - await this.rulesEngine!.MatchOneAsync(ContentTypes.TexasHoldemPokerSingleCombinations, this.benchmarkData.MatchDate, this.benchmarkData.Conditions).ConfigureAwait(false); + await this.genericRulesEngine!.MatchOneAsync(ContentTypes.TexasHoldemPokerSingleCombinations, this.benchmarkData.MatchDate, this.benchmarkData.Conditions).ConfigureAwait(false); } [GlobalSetup] public async Task SetUpAsync() { - this.rulesEngine = RulesEngineBuilder.CreateRulesEngine() - .WithContentType() - .WithConditionType() + var rulesEngine = RulesEngineBuilder.CreateRulesEngine() .SetDataSourceForBenchmark(this.Provider!, nameof(Benchmark3)) .Configure(options => { @@ -34,17 +33,21 @@ public async Task SetUpAsync() }) .Build(); + await rulesEngine.CreateContentTypeAsync(nameof(ContentTypes.TexasHoldemPokerSingleCombinations)); + foreach (var rule in this.benchmarkData.Rules) { - await this.rulesEngine.AddRuleAsync(rule, RuleAddPriorityOption.AtTop).ConfigureAwait(false); + await rulesEngine.AddRuleAsync(rule, RuleAddPriorityOption.AtTop).ConfigureAwait(false); } + + this.genericRulesEngine = rulesEngine.MakeGeneric(); } [GlobalCleanup] public async Task TearDownAsync() { await Extensions.TearDownProviderAsync(this.Provider!, nameof(Benchmark3)).ConfigureAwait(false); - this.rulesEngine = null; + this.genericRulesEngine = null; } } } \ No newline at end of file diff --git a/tests/Rules.Framework.BenchmarkTests/Tests/Extensions.cs b/tests/Rules.Framework.BenchmarkTests/Tests/Extensions.cs index 581a959c..a7459ac4 100644 --- a/tests/Rules.Framework.BenchmarkTests/Tests/Extensions.cs +++ b/tests/Rules.Framework.BenchmarkTests/Tests/Extensions.cs @@ -2,15 +2,14 @@ namespace Rules.Framework.BenchmarkTests.Tests { using MongoDB.Driver; using Rules.Framework.Builder; - using Rules.Framework.Providers.InMemory; using Rules.Framework.Providers.MongoDb; internal static class Extensions { private const string DatabaseName = "benchmarks-database"; - public static IConfiguredRulesEngineBuilder SetDataSourceForBenchmark( - this IRulesDataSourceSelector rulesDataSourceSelector, + public static IConfiguredRulesEngineBuilder SetDataSourceForBenchmark( + this IRulesDataSourceSelector rulesDataSourceSelector, string dataSourceName, string benchmarkName) { return dataSourceName switch diff --git a/tests/Rules.Framework.IntegrationTests.Common/Features/RuleSpecification.cs b/tests/Rules.Framework.IntegrationTests.Common/Features/RuleSpecification.cs index 2dfcfdfc..c1f93b6e 100644 --- a/tests/Rules.Framework.IntegrationTests.Common/Features/RuleSpecification.cs +++ b/tests/Rules.Framework.IntegrationTests.Common/Features/RuleSpecification.cs @@ -1,6 +1,6 @@ namespace Rules.Framework.IntegrationTests.Common.Features { - using Rules.Framework.Core; + using Rules.Framework.Generic; using Rules.Framework.Tests.Stubs; public class RuleSpecification @@ -11,8 +11,7 @@ public RuleSpecification(Rule ruleBuilderResult, Rul this.RuleAddPriorityOption = ruleAddPriorityOption; } - public RuleAddPriorityOption RuleAddPriorityOption { get; set; } - public Rule Rule { get; set; } + public RuleAddPriorityOption RuleAddPriorityOption { get; set; } } } \ No newline at end of file diff --git a/tests/Rules.Framework.IntegrationTests.Common/Scenarios/IScenarioData.cs b/tests/Rules.Framework.IntegrationTests.Common/Scenarios/IScenarioData.cs index 3d080c4c..30e16557 100644 --- a/tests/Rules.Framework.IntegrationTests.Common/Scenarios/IScenarioData.cs +++ b/tests/Rules.Framework.IntegrationTests.Common/Scenarios/IScenarioData.cs @@ -3,7 +3,7 @@ namespace Rules.Framework.BenchmarkTests.Tests using System; using System.Collections.Generic; using Rules.Framework; - using Rules.Framework.Core; + using Rules.Framework.Generic; public interface IScenarioData { diff --git a/tests/Rules.Framework.IntegrationTests.Common/Scenarios/Scenario1/rules-framework-tests.body-mass-index.datasource.json b/tests/Rules.Framework.IntegrationTests.Common/Scenarios/Scenario1/rules-framework-tests.body-mass-index.datasource.json index 9ebb3ea0..4fce00c1 100644 --- a/tests/Rules.Framework.IntegrationTests.Common/Scenarios/Scenario1/rules-framework-tests.body-mass-index.datasource.json +++ b/tests/Rules.Framework.IntegrationTests.Common/Scenarios/Scenario1/rules-framework-tests.body-mass-index.datasource.json @@ -1,11 +1,11 @@ [ - { - "Content": "{\"Description\":\"Body Mass Index default formula\",\"Value\":\"weight / (height ^ 2)\"}", - "ContentTypeCode": 1, - "DateBegin": "2018-01-01", - "DateEnd": null, - "Name": "Body Mass Index default", - "Priority": 1, - "RootCondition": null - } + { + "Content": "{\"Description\":\"Body Mass Index default formula\",\"Value\":\"weight / (height ^ 2)\"}", + "ContentTypeCode": "BodyMassIndexFormula", + "DateBegin": "2018-01-01", + "DateEnd": null, + "Name": "Body Mass Index default", + "Priority": 1, + "RootCondition": null + } ] \ No newline at end of file diff --git a/tests/Rules.Framework.IntegrationTests.Common/Scenarios/Scenario2/rules-framework-tests.car-insurance-advisor.json b/tests/Rules.Framework.IntegrationTests.Common/Scenarios/Scenario2/rules-framework-tests.car-insurance-advisor.json index 4cefc6fd..e7b1c1b0 100644 --- a/tests/Rules.Framework.IntegrationTests.Common/Scenarios/Scenario2/rules-framework-tests.car-insurance-advisor.json +++ b/tests/Rules.Framework.IntegrationTests.Common/Scenarios/Scenario2/rules-framework-tests.car-insurance-advisor.json @@ -1,86 +1,86 @@ [ - { - "Content": "RefusePaymentPerFranchise", - "ContentTypeCode": 1, - "DateBegin": "2018-01-01", - "DateEnd": null, - "Name": "Car Insurance Advise on repair costs lower than franchise boundary", - "Priority": 4, - "RootCondition": { - "LogicalOperator": "And", - "ChildConditionNodes": [ - { - "ConditionType": "RepairCosts", - "DataType": "Decimal", - "LogicalOperator": "Eval", - "Operator": "LesserThan", - "Operand": "1000" - }, - { - "ConditionType": "RepairCostsCommercialValueRate", - "DataType": "Decimal", - "LogicalOperator": "Eval", - "Operator": "LesserThan", - "Operand": "80" + { + "Content": "RefusePaymentPerFranchise", + "ContentTypeCode": "CarInsuranceAdvice", + "DateBegin": "2018-01-01", + "DateEnd": null, + "Name": "Car Insurance Advise on repair costs lower than franchise boundary", + "Priority": 4, + "RootCondition": { + "LogicalOperator": "And", + "ChildConditionNodes": [ + { + "ConditionType": "RepairCosts", + "DataType": "Decimal", + "LogicalOperator": "Eval", + "Operator": "LesserThan", + "Operand": "1000" + }, + { + "ConditionType": "RepairCostsCommercialValueRate", + "DataType": "Decimal", + "LogicalOperator": "Eval", + "Operator": "LesserThan", + "Operand": "80" + } + ] } - ] - } - }, - { - "Content": "PayOldCar", - "ContentTypeCode": 1, - "DateBegin": "2010-01-01", - "DateEnd": "2016-06-01 23:59:59.999", - "Name": "Car Insurance Advise on repair costs equal to 0", - "Priority": 3, - "RootCondition": { - "LogicalOperator": "And", - "ChildConditionNodes": [ - { - "ConditionType": "RepairCosts", - "DataType": "Decimal", - "LogicalOperator": "Eval", - "Operator": "Equal", - "Operand": "0.0" - }, - { - "ConditionType": "RepairCostsCommercialValueRate", - "DataType": "Decimal", - "LogicalOperator": "Eval", - "Operator": "Equal", - "Operand": "0.0" + }, + { + "Content": "PayOldCar", + "ContentTypeCode": "CarInsuranceAdvice", + "DateBegin": "2010-01-01", + "DateEnd": "2016-06-01 23:59:59.999", + "Name": "Car Insurance Advise on repair costs equal to 0", + "Priority": 3, + "RootCondition": { + "LogicalOperator": "And", + "ChildConditionNodes": [ + { + "ConditionType": "RepairCosts", + "DataType": "Decimal", + "LogicalOperator": "Eval", + "Operator": "Equal", + "Operand": "0.0" + }, + { + "ConditionType": "RepairCostsCommercialValueRate", + "DataType": "Decimal", + "LogicalOperator": "Eval", + "Operator": "Equal", + "Operand": "0.0" + } + ] + } + }, + { + "Content": "PayNewCar", + "ContentTypeCode": "CarInsuranceAdvice", + "DateBegin": "2018-01-01", + "DateEnd": null, + "Name": "Car Insurance Advise on repair costs greater than 80% of commercial value", + "Priority": 2, + "RootCondition": { + "ConditionType": "RepairCostsCommercialValueRate", + "DataType": "Decimal", + "LogicalOperator": "Eval", + "Operator": "GreaterThanOrEqual", + "Operand": "80" + } + }, + { + "Content": "Pay", + "ContentTypeCode": "CarInsuranceAdvice", + "DateBegin": "2018-01-01", + "DateEnd": null, + "Name": "Car Insurance Advise on repair costs lesser than 80% of commercial value", + "Priority": 1, + "RootCondition": { + "ConditionType": "RepairCostsCommercialValueRate", + "DataType": "Decimal", + "LogicalOperator": "Eval", + "Operator": "LesserThan", + "Operand": "80" } - ] - } - }, - { - "Content": "PayNewCar", - "ContentTypeCode": 1, - "DateBegin": "2018-01-01", - "DateEnd": null, - "Name": "Car Insurance Advise on repair costs greater than 80% of commercial value", - "Priority": 2, - "RootCondition": { - "ConditionType": "RepairCostsCommercialValueRate", - "DataType": "Decimal", - "LogicalOperator": "Eval", - "Operator": "GreaterThanOrEqual", - "Operand": "80" - } - }, - { - "Content": "Pay", - "ContentTypeCode": 1, - "DateBegin": "2018-01-01", - "DateEnd": null, - "Name": "Car Insurance Advise on repair costs lesser than 80% of commercial value", - "Priority": 1, - "RootCondition": { - "ConditionType": "RepairCostsCommercialValueRate", - "DataType": "Decimal", - "LogicalOperator": "Eval", - "Operator": "LesserThan", - "Operand": "80" } - } ] \ No newline at end of file diff --git a/tests/Rules.Framework.IntegrationTests.Common/Scenarios/Scenario3/rules-framework-tests.security-system-actionables.json b/tests/Rules.Framework.IntegrationTests.Common/Scenarios/Scenario3/rules-framework-tests.security-system-actionables.json index 15901c4f..699070b8 100644 --- a/tests/Rules.Framework.IntegrationTests.Common/Scenarios/Scenario3/rules-framework-tests.security-system-actionables.json +++ b/tests/Rules.Framework.IntegrationTests.Common/Scenarios/Scenario3/rules-framework-tests.security-system-actionables.json @@ -1,140 +1,140 @@ [ - { - "Content": "{\"ActionId\":\"7367d5d8-bac1-48bb-9b88-28cfe534aed2\",\"ActionName\":\"ActivateSprinklers\"}", - "ContentTypeCode": 1, - "DateBegin": "2018-01-01", - "DateEnd": null, - "Name": "Sprinkler system activation rule", - "Priority": 2, - "RootCondition": { - "LogicalOperator": "Or", - "ChildConditionNodes": [ - { - "ConditionType": "TemperatureCelsius", - "DataType": "Decimal", - "LogicalOperator": "Eval", - "Operator": "GreaterThanOrEqual", - "Operand": "50" - }, - { - "ConditionType": "SmokeRate", - "DataType": "Decimal", - "LogicalOperator": "Eval", - "Operator": "GreaterThan", - "Operand": "40" + { + "Content": "{\"ActionId\":\"7367d5d8-bac1-48bb-9b88-28cfe534aed2\",\"ActionName\":\"ActivateSprinklers\"}", + "ContentTypeCode": "FireSystem", + "DateBegin": "2018-01-01", + "DateEnd": null, + "Name": "Sprinkler system activation rule", + "Priority": 2, + "RootCondition": { + "LogicalOperator": "Or", + "ChildConditionNodes": [ + { + "ConditionType": "TemperatureCelsius", + "DataType": "Decimal", + "LogicalOperator": "Eval", + "Operator": "GreaterThanOrEqual", + "Operand": "50" + }, + { + "ConditionType": "SmokeRate", + "DataType": "Decimal", + "LogicalOperator": "Eval", + "Operator": "GreaterThan", + "Operand": "40" + } + ] } - ] - } - }, - { - "Content": "{\"ActionId\":\"96cce7f0-f8ba-4e8a-a3ce-b0d200d49ab2\",\"ActionName\":\"CallFireBrigade\"}", - "ContentTypeCode": 1, - "DateBegin": "2018-01-01", - "DateEnd": null, - "Name": "Fire brigade call rule", - "Priority": 1, - "RootCondition": { - "LogicalOperator": "Or", - "ChildConditionNodes":[ - { - "ConditionType": "TemperatureCelsius", - "DataType": "Decimal", - "LogicalOperator": "Eval", - "Operator": "GreaterThanOrEqual", - "Operand": "70" - }, - { - "ConditionType": "SmokeRate", - "DataType": "Decimal", - "LogicalOperator": "Eval", - "Operator": "GreaterThanOrEqual", - "Operand": "50" + }, + { + "Content": "{\"ActionId\":\"96cce7f0-f8ba-4e8a-a3ce-b0d200d49ab2\",\"ActionName\":\"CallFireBrigade\"}", + "ContentTypeCode": "FireSystem", + "DateBegin": "2018-01-01", + "DateEnd": null, + "Name": "Fire brigade call rule", + "Priority": 1, + "RootCondition": { + "LogicalOperator": "Or", + "ChildConditionNodes": [ + { + "ConditionType": "TemperatureCelsius", + "DataType": "Decimal", + "LogicalOperator": "Eval", + "Operator": "GreaterThanOrEqual", + "Operand": "70" + }, + { + "ConditionType": "SmokeRate", + "DataType": "Decimal", + "LogicalOperator": "Eval", + "Operator": "GreaterThanOrEqual", + "Operand": "50" + } + ] } - ] - } - }, - { - "Content": "{\"ActionId\":\"4f771d96-43c7-4939-a8a8-aabd9ad0eee5\",\"ActionName\":\"CallPolice\"}", - "ContentTypeCode": 1, - "DateBegin": "2018-01-01", - "DateEnd": null, - "Name": "Police call rule", - "Priority": 3, - "RootCondition": { - "LogicalOperator": "Or", - "ChildConditionNodes":[ - { - "ConditionType": "TemperatureCelsius", - "DataType": "Decimal", - "LogicalOperator": "Eval", - "Operator": "GreaterThanOrEqual", - "Operand": "70" - }, - { - "ConditionType": "SmokeRate", - "DataType": "Decimal", - "LogicalOperator": "Eval", - "Operator": "GreaterThanOrEqual", - "Operand": "50" + }, + { + "Content": "{\"ActionId\":\"4f771d96-43c7-4939-a8a8-aabd9ad0eee5\",\"ActionName\":\"CallPolice\"}", + "ContentTypeCode": "FireSystem", + "DateBegin": "2018-01-01", + "DateEnd": null, + "Name": "Police call rule", + "Priority": 3, + "RootCondition": { + "LogicalOperator": "Or", + "ChildConditionNodes": [ + { + "ConditionType": "TemperatureCelsius", + "DataType": "Decimal", + "LogicalOperator": "Eval", + "Operator": "GreaterThanOrEqual", + "Operand": "70" + }, + { + "ConditionType": "SmokeRate", + "DataType": "Decimal", + "LogicalOperator": "Eval", + "Operator": "GreaterThanOrEqual", + "Operand": "50" + } + ] } - ] - } - }, - { - "Content": "{\"ActionId\":\"39958de2-1201-4904-9555-65f97e8a1d1d\",\"ActionName\":\"EnableEmergencyPower\"}", - "ContentTypeCode": 2, - "DateBegin": "2018-01-01", - "DateEnd": null, - "Name": "Emergency power activation rule", - "Priority": 4, - "RootCondition": { - "ConditionType": "PowerStatus", - "DataType": "String", - "LogicalOperator": "Eval", - "Operator": "Equal", - "Operand": "Offline" - } - }, - { - "Content": "{\"ActionId\":\"5f1c1e0c-6f49-448d-b9ce-7b154436fe5c\",\"ActionName\":\"EnableEmergencyLights\"}", - "ContentTypeCode": 2, - "DateBegin": "2018-01-01", - "DateEnd": null, - "Name": "Enable emergency lights rule", - "Priority": 5, - "RootCondition": { - "LogicalOperator": "Or", - "ChildConditionNodes":[ - { - "ConditionType": "PowerStatus", - "DataType": "String", - "LogicalOperator": "Eval", - "Operator": "Equal", - "Operand": "Offline" - }, - { - "ConditionType": "PowerStatus", - "DataType": "String", - "LogicalOperator": "Eval", - "Operator": "Equal", - "Operand": "Shutdown" + }, + { + "Content": "{\"ActionId\":\"39958de2-1201-4904-9555-65f97e8a1d1d\",\"ActionName\":\"EnableEmergencyPower\"}", + "ContentTypeCode": "PowerSystem", + "DateBegin": "2018-01-01", + "DateEnd": null, + "Name": "Emergency power activation rule", + "Priority": 4, + "RootCondition": { + "ConditionType": "PowerStatus", + "DataType": "String", + "LogicalOperator": "Eval", + "Operator": "Equal", + "Operand": "Offline" + } + }, + { + "Content": "{\"ActionId\":\"5f1c1e0c-6f49-448d-b9ce-7b154436fe5c\",\"ActionName\":\"EnableEmergencyLights\"}", + "ContentTypeCode": "PowerSystem", + "DateBegin": "2018-01-01", + "DateEnd": null, + "Name": "Enable emergency lights rule", + "Priority": 5, + "RootCondition": { + "LogicalOperator": "Or", + "ChildConditionNodes": [ + { + "ConditionType": "PowerStatus", + "DataType": "String", + "LogicalOperator": "Eval", + "Operator": "Equal", + "Operand": "Offline" + }, + { + "ConditionType": "PowerStatus", + "DataType": "String", + "LogicalOperator": "Eval", + "Operator": "Equal", + "Operand": "Shutdown" + } + ] + } + }, + { + "Content": "{\"ActionId\":\"3dd3eadc-15c2-4f66-9e01-4cdf106fd9d6\",\"ActionName\":\"CallPowerGridPicket\"}", + "ContentTypeCode": "PowerSystem", + "DateBegin": "2018-01-01", + "DateEnd": null, + "Name": "Call power grid picket rule", + "Priority": 6, + "RootCondition": { + "ConditionType": "PowerStatus", + "DataType": "String", + "LogicalOperator": "Eval", + "Operator": "Equal", + "Operand": "Offline" } - ] - } - }, - { - "Content": "{\"ActionId\":\"3dd3eadc-15c2-4f66-9e01-4cdf106fd9d6\",\"ActionName\":\"CallPowerGridPicket\"}", - "ContentTypeCode": 2, - "DateBegin": "2018-01-01", - "DateEnd": null, - "Name": "Call power grid picket rule", - "Priority": 6, - "RootCondition": { - "ConditionType": "PowerStatus", - "DataType": "String", - "LogicalOperator": "Eval", - "Operator": "Equal", - "Operand": "Offline" } - } ] \ No newline at end of file diff --git a/tests/Rules.Framework.IntegrationTests.Common/Scenarios/Scenario6/Scenario6Data.cs b/tests/Rules.Framework.IntegrationTests.Common/Scenarios/Scenario6/Scenario6Data.cs index 430e9183..770da864 100644 --- a/tests/Rules.Framework.IntegrationTests.Common/Scenarios/Scenario6/Scenario6Data.cs +++ b/tests/Rules.Framework.IntegrationTests.Common/Scenarios/Scenario6/Scenario6Data.cs @@ -2,8 +2,9 @@ namespace Rules.Framework.BenchmarkTests.Tests.Benchmark1 { using System; using System.Collections.Generic; + using Rules.Framework; using Rules.Framework.BenchmarkTests.Tests; - using Rules.Framework.Core; + using Rules.Framework.Generic; public class Scenario6Data : IScenarioData { @@ -18,7 +19,7 @@ public class Scenario6Data : IScenarioData private IEnumerable> GetRules() { - var ruleResult = RuleBuilder.NewRule() + var ruleResult = Rule.New() .WithName("Benchmark 1 - Test rule") .WithDateBegin(DateTime.Parse("2000-01-01")) .WithContent(ContentTypes.ContentType1, "Dummy Content") diff --git a/tests/Rules.Framework.IntegrationTests.Common/Scenarios/Scenario7/Scenario7Data.cs b/tests/Rules.Framework.IntegrationTests.Common/Scenarios/Scenario7/Scenario7Data.cs index 028e4b6e..f21c6493 100644 --- a/tests/Rules.Framework.IntegrationTests.Common/Scenarios/Scenario7/Scenario7Data.cs +++ b/tests/Rules.Framework.IntegrationTests.Common/Scenarios/Scenario7/Scenario7Data.cs @@ -3,7 +3,7 @@ namespace Rules.Framework.BenchmarkTests.Tests.Benchmark2 using System; using System.Collections.Generic; using Rules.Framework; - using Rules.Framework.Core; + using Rules.Framework.Generic; public class Scenario7Data : IScenarioData { @@ -20,7 +20,7 @@ public class Scenario7Data : IScenarioData private IEnumerable> GetRules() { - var rule1Result = RuleBuilder.NewRule() + var rule1Result = Rule.New() .WithName("Benchmark 2 - Bohemian Rapsody") .WithDateBegin(DateTime.Parse("2000-01-01")) .WithContent(ContentTypes.Songs, "Bohemian Rapsody") @@ -34,7 +34,7 @@ private IEnumerable> GetRules() ) .Build(); - var rule2Result = RuleBuilder.NewRule() + var rule2Result = Rule.New() .WithName("Benchmark 2 - Stairway to Heaven") .WithDateBegin(DateTime.Parse("2000-01-01")) .WithContent(ContentTypes.Songs, "Stairway to Heaven") diff --git a/tests/Rules.Framework.IntegrationTests.Common/Scenarios/Scenario8/Scenario8Data.Flush.cs b/tests/Rules.Framework.IntegrationTests.Common/Scenarios/Scenario8/Scenario8Data.Flush.cs index 2efa715e..6ac19239 100644 --- a/tests/Rules.Framework.IntegrationTests.Common/Scenarios/Scenario8/Scenario8Data.Flush.cs +++ b/tests/Rules.Framework.IntegrationTests.Common/Scenarios/Scenario8/Scenario8Data.Flush.cs @@ -2,8 +2,8 @@ namespace Rules.Framework.BenchmarkTests.Tests.Benchmark3 { using System; using System.Collections.Generic; - using Rules.Framework.Builder; - using Rules.Framework.Core; + using Rules.Framework; + using Rules.Framework.Generic; public partial class Scenario8Data : IScenarioData { @@ -11,25 +11,25 @@ private IEnumerable> GetFlushRules() { return new[] { - RuleBuilder.NewRule() + Rule.New < ContentTypes, ConditionTypes >() .WithName("Benchmark 3 - Flush of Clubs") .WithDateBegin(DateTime.Parse("2000-01-01")) .WithContent(ContentTypes.TexasHoldemPokerSingleCombinations, new SingleCombinationPokerScore { Combination = "Flush" }) .WithCondition(ConditionTypes.NumberOfClubs, Operators.GreaterThanOrEqual, 5) .Build().Rule, - RuleBuilder.NewRule() + Rule.New < ContentTypes, ConditionTypes >() .WithName("Benchmark 3 - Flush of Diamonds") .WithDateBegin(DateTime.Parse("2000-01-01")) .WithContent(ContentTypes.TexasHoldemPokerSingleCombinations, new SingleCombinationPokerScore { Combination = "Flush" }) .WithCondition(ConditionTypes.NumberOfDiamonds, Operators.GreaterThanOrEqual, 5) .Build().Rule, - RuleBuilder.NewRule() + Rule.New < ContentTypes, ConditionTypes >() .WithName("Benchmark 3 - Flush of Hearts") .WithDateBegin(DateTime.Parse("2000-01-01")) .WithContent(ContentTypes.TexasHoldemPokerSingleCombinations, new SingleCombinationPokerScore { Combination = "Flush" }) .WithCondition(ConditionTypes.NumberOfHearts, Operators.GreaterThanOrEqual, 5) .Build().Rule, - RuleBuilder.NewRule() + Rule.New() .WithName("Benchmark 3 - Flush of Spades") .WithDateBegin(DateTime.Parse("2000-01-01")) .WithContent(ContentTypes.TexasHoldemPokerSingleCombinations, new SingleCombinationPokerScore { Combination = "Flush" }) diff --git a/tests/Rules.Framework.IntegrationTests.Common/Scenarios/Scenario8/Scenario8Data.FourOfAKind.cs b/tests/Rules.Framework.IntegrationTests.Common/Scenarios/Scenario8/Scenario8Data.FourOfAKind.cs index fcbbc45a..e25bfed9 100644 --- a/tests/Rules.Framework.IntegrationTests.Common/Scenarios/Scenario8/Scenario8Data.FourOfAKind.cs +++ b/tests/Rules.Framework.IntegrationTests.Common/Scenarios/Scenario8/Scenario8Data.FourOfAKind.cs @@ -2,8 +2,8 @@ namespace Rules.Framework.BenchmarkTests.Tests.Benchmark3 { using System; using System.Collections.Generic; - using Rules.Framework.Builder; - using Rules.Framework.Core; + using Rules.Framework; + using Rules.Framework.Generic; public partial class Scenario8Data : IScenarioData { @@ -11,79 +11,79 @@ private IEnumerable> GetFourOfAKindRules() { return new[] { - RuleBuilder.NewRule() + Rule.New() .WithName("Benchmark 3 - Four Of A Kind Deuces") .WithDateBegin(DateTime.Parse("2000-01-01")) .WithContent(ContentTypes.TexasHoldemPokerSingleCombinations, new SingleCombinationPokerScore { Combination = "Four Of A Kind" }) .WithCondition(ConditionTypes.NumberOfDeuces, Operators.Equal, 4) .Build().Rule, - RuleBuilder.NewRule() + Rule.New() .WithName("Benchmark 3 - Four Of A Kind Treys") .WithDateBegin(DateTime.Parse("2000-01-01")) .WithContent(ContentTypes.TexasHoldemPokerSingleCombinations, new SingleCombinationPokerScore { Combination = "Four Of A Kind" }) .WithCondition(ConditionTypes.NumberOfTreys, Operators.Equal, 4) .Build().Rule, - RuleBuilder.NewRule() + Rule.New() .WithName("Benchmark 3 - Four Of A Kind Fours") .WithDateBegin(DateTime.Parse("2000-01-01")) .WithContent(ContentTypes.TexasHoldemPokerSingleCombinations, new SingleCombinationPokerScore { Combination = "Four Of A Kind" }) .WithCondition(ConditionTypes.NumberOfFours, Operators.Equal, 4) .Build().Rule, - RuleBuilder.NewRule() + Rule.New() .WithName("Benchmark 3 - Four Of A Kind Fives") .WithDateBegin(DateTime.Parse("2000-01-01")) .WithContent(ContentTypes.TexasHoldemPokerSingleCombinations, new SingleCombinationPokerScore { Combination = "Four Of A Kind" }) .WithCondition(ConditionTypes.NumberOfFives, Operators.Equal, 4) .Build().Rule, - RuleBuilder.NewRule() + Rule.New() .WithName("Benchmark 3 - Four Of A Kind Sixes") .WithDateBegin(DateTime.Parse("2000-01-01")) .WithContent(ContentTypes.TexasHoldemPokerSingleCombinations, new SingleCombinationPokerScore { Combination = "Four Of A Kind" }) .WithCondition(ConditionTypes.NumberOfSixes, Operators.Equal, 4) .Build().Rule, - RuleBuilder.NewRule() + Rule.New() .WithName("Benchmark 3 - Four Of A Kind Sevens") .WithDateBegin(DateTime.Parse("2000-01-01")) .WithContent(ContentTypes.TexasHoldemPokerSingleCombinations, new SingleCombinationPokerScore { Combination = "Four Of A Kind" }) .WithCondition(ConditionTypes.NumberOfSevens, Operators.Equal, 4) .Build().Rule, - RuleBuilder.NewRule() + Rule.New() .WithName("Benchmark 3 - Four Of A Kind Eights") .WithDateBegin(DateTime.Parse("2000-01-01")) .WithContent(ContentTypes.TexasHoldemPokerSingleCombinations, new SingleCombinationPokerScore { Combination = "Four Of A Kind" }) .WithCondition(ConditionTypes.NumberOfEigths, Operators.Equal, 4) .Build().Rule, - RuleBuilder.NewRule() + Rule.New() .WithName("Benchmark 3 - Four Of A Kind Nines") .WithDateBegin(DateTime.Parse("2000-01-01")) .WithContent(ContentTypes.TexasHoldemPokerSingleCombinations, new SingleCombinationPokerScore { Combination = "Three Of A Kind" }) .WithCondition(ConditionTypes.NumberOfNines, Operators.Equal, 4) .Build().Rule, - RuleBuilder.NewRule() + Rule.New() .WithName("Benchmark 3 - Four Of A Kind Tens") .WithDateBegin(DateTime.Parse("2000-01-01")) .WithContent(ContentTypes.TexasHoldemPokerSingleCombinations, new SingleCombinationPokerScore { Combination = "Four Of A Kind" }) .WithCondition(ConditionTypes.NumberOfTens, Operators.Equal, 4) .Build().Rule, - RuleBuilder.NewRule() + Rule.New() .WithName("Benchmark 3 - Four Of A Kind Jacks") .WithDateBegin(DateTime.Parse("2000-01-01")) .WithContent(ContentTypes.TexasHoldemPokerSingleCombinations, new SingleCombinationPokerScore { Combination = "Four Of A Kind" }) .WithCondition(ConditionTypes.NumberOfJacks, Operators.Equal, 4) .Build().Rule, - RuleBuilder.NewRule() + Rule.New() .WithName("Benchmark 3 - Four Of A Kind Queens") .WithDateBegin(DateTime.Parse("2000-01-01")) .WithContent(ContentTypes.TexasHoldemPokerSingleCombinations, new SingleCombinationPokerScore { Combination = "Four Of A Kind" }) .WithCondition(ConditionTypes.NumberOfQueens, Operators.Equal, 4) .Build().Rule, - RuleBuilder.NewRule() + Rule.New() .WithName("Benchmark 3 - Four Of A Kind Kings") .WithDateBegin(DateTime.Parse("2000-01-01")) .WithContent(ContentTypes.TexasHoldemPokerSingleCombinations, new SingleCombinationPokerScore { Combination = "Four Of A Kind" }) .WithCondition(ConditionTypes.NumberOfKings, Operators.Equal, 4) .Build().Rule, - RuleBuilder.NewRule() + Rule.New() .WithName("Benchmark 3 - Four Of A Kind Aces") .WithDateBegin(DateTime.Parse("2000-01-01")) .WithContent(ContentTypes.TexasHoldemPokerSingleCombinations, new SingleCombinationPokerScore { Combination = "Four Of A Kind" }) diff --git a/tests/Rules.Framework.IntegrationTests.Common/Scenarios/Scenario8/Scenario8Data.HighCard.cs b/tests/Rules.Framework.IntegrationTests.Common/Scenarios/Scenario8/Scenario8Data.HighCard.cs index d1851617..363dacb6 100644 --- a/tests/Rules.Framework.IntegrationTests.Common/Scenarios/Scenario8/Scenario8Data.HighCard.cs +++ b/tests/Rules.Framework.IntegrationTests.Common/Scenarios/Scenario8/Scenario8Data.HighCard.cs @@ -2,8 +2,8 @@ namespace Rules.Framework.BenchmarkTests.Tests.Benchmark3 { using System; using System.Collections.Generic; - using Rules.Framework.Builder; - using Rules.Framework.Core; + using Rules.Framework; + using Rules.Framework.Generic; public partial class Scenario8Data : IScenarioData { @@ -11,79 +11,79 @@ private IEnumerable> GetHighCardsRules() { return new[] { - RuleBuilder.NewRule() + Rule.New() .WithName("Benchmark 3 - High Card Deuces") .WithDateBegin(DateTime.Parse("2000-01-01")) .WithContent(ContentTypes.TexasHoldemPokerSingleCombinations, new SingleCombinationPokerScore { Combination = "High Card" }) .WithCondition(ConditionTypes.NumberOfDeuces, Operators.Equal, 1) .Build().Rule, - RuleBuilder.NewRule() + Rule.New() .WithName("Benchmark 3 - High Card Treys") .WithDateBegin(DateTime.Parse("2000-01-01")) .WithContent(ContentTypes.TexasHoldemPokerSingleCombinations, new SingleCombinationPokerScore { Combination = "High Card" }) .WithCondition(ConditionTypes.NumberOfTreys, Operators.Equal, 1) .Build().Rule, - RuleBuilder.NewRule() + Rule.New() .WithName("Benchmark 3 - High Card Fours") .WithDateBegin(DateTime.Parse("2000-01-01")) .WithContent(ContentTypes.TexasHoldemPokerSingleCombinations, new SingleCombinationPokerScore { Combination = "High Card" }) .WithCondition(ConditionTypes.NumberOfFours, Operators.Equal, 1) .Build().Rule, - RuleBuilder.NewRule() + Rule.New() .WithName("Benchmark 3 - High Card Fives") .WithDateBegin(DateTime.Parse("2000-01-01")) .WithContent(ContentTypes.TexasHoldemPokerSingleCombinations, new SingleCombinationPokerScore { Combination = "High Card" }) .WithCondition(ConditionTypes.NumberOfFives, Operators.Equal, 1) .Build().Rule, - RuleBuilder.NewRule() + Rule.New() .WithName("Benchmark 3 - High Card Sixes") .WithDateBegin(DateTime.Parse("2000-01-01")) .WithContent(ContentTypes.TexasHoldemPokerSingleCombinations, new SingleCombinationPokerScore { Combination = "High Card" }) .WithCondition(ConditionTypes.NumberOfSixes, Operators.Equal, 1) .Build().Rule, - RuleBuilder.NewRule() + Rule.New() .WithName("Benchmark 3 - High Card Sevens") .WithDateBegin(DateTime.Parse("2000-01-01")) .WithContent(ContentTypes.TexasHoldemPokerSingleCombinations, new SingleCombinationPokerScore { Combination = "High Card" }) .WithCondition(ConditionTypes.NumberOfSevens, Operators.Equal, 1) .Build().Rule, - RuleBuilder.NewRule() + Rule.New() .WithName("Benchmark 3 - High Card Eights") .WithDateBegin(DateTime.Parse("2000-01-01")) .WithContent(ContentTypes.TexasHoldemPokerSingleCombinations, new SingleCombinationPokerScore { Combination = "High Card" }) .WithCondition(ConditionTypes.NumberOfEigths, Operators.Equal, 1) .Build().Rule, - RuleBuilder.NewRule() + Rule.New() .WithName("Benchmark 3 - High Card Nines") .WithDateBegin(DateTime.Parse("2000-01-01")) .WithContent(ContentTypes.TexasHoldemPokerSingleCombinations, new SingleCombinationPokerScore { Combination = "High Card" }) .WithCondition(ConditionTypes.NumberOfNines, Operators.Equal, 1) .Build().Rule, - RuleBuilder.NewRule() + Rule.New() .WithName("Benchmark 3 - High Card Tens") .WithDateBegin(DateTime.Parse("2000-01-01")) .WithContent(ContentTypes.TexasHoldemPokerSingleCombinations, new SingleCombinationPokerScore { Combination = "High Card" }) .WithCondition(ConditionTypes.NumberOfTens, Operators.Equal, 1) .Build().Rule, - RuleBuilder.NewRule() + Rule.New() .WithName("Benchmark 3 - High Card Jacks") .WithDateBegin(DateTime.Parse("2000-01-01")) .WithContent(ContentTypes.TexasHoldemPokerSingleCombinations, new SingleCombinationPokerScore { Combination = "High Card" }) .WithCondition(ConditionTypes.NumberOfJacks, Operators.Equal, 1) .Build().Rule, - RuleBuilder.NewRule() + Rule.New() .WithName("Benchmark 3 - High Card Queens") .WithDateBegin(DateTime.Parse("2000-01-01")) .WithContent(ContentTypes.TexasHoldemPokerSingleCombinations, new SingleCombinationPokerScore { Combination = "High Card" }) .WithCondition(ConditionTypes.NumberOfQueens, Operators.Equal, 1) .Build().Rule, - RuleBuilder.NewRule() + Rule.New() .WithName("Benchmark 3 - High Card Kings") .WithDateBegin(DateTime.Parse("2000-01-01")) .WithContent(ContentTypes.TexasHoldemPokerSingleCombinations, new SingleCombinationPokerScore { Combination = "High Card" }) .WithCondition(ConditionTypes.NumberOfKings, Operators.Equal, 1) .Build().Rule, - RuleBuilder.NewRule() + Rule.New() .WithName("Benchmark 3 - High Card Aces") .WithDateBegin(DateTime.Parse("2000-01-01")) .WithContent(ContentTypes.TexasHoldemPokerSingleCombinations, new SingleCombinationPokerScore { Combination = "High Card" }) diff --git a/tests/Rules.Framework.IntegrationTests.Common/Scenarios/Scenario8/Scenario8Data.Pair.cs b/tests/Rules.Framework.IntegrationTests.Common/Scenarios/Scenario8/Scenario8Data.Pair.cs index 72649fd8..0b10823d 100644 --- a/tests/Rules.Framework.IntegrationTests.Common/Scenarios/Scenario8/Scenario8Data.Pair.cs +++ b/tests/Rules.Framework.IntegrationTests.Common/Scenarios/Scenario8/Scenario8Data.Pair.cs @@ -2,8 +2,8 @@ namespace Rules.Framework.BenchmarkTests.Tests.Benchmark3 { using System; using System.Collections.Generic; - using Rules.Framework.Builder; - using Rules.Framework.Core; + using Rules.Framework; + using Rules.Framework.Generic; public partial class Scenario8Data : IScenarioData { @@ -11,79 +11,79 @@ private IEnumerable> GetPairsRules() { return new[] { - RuleBuilder.NewRule() + Rule.New() .WithName("Benchmark 3 - Pair Deuces") .WithDateBegin(DateTime.Parse("2000-01-01")) .WithContent(ContentTypes.TexasHoldemPokerSingleCombinations, new SingleCombinationPokerScore { Combination = "Pair" }) .WithCondition(ConditionTypes.NumberOfDeuces, Operators.Equal, 2) .Build().Rule, - RuleBuilder.NewRule() + Rule.New() .WithName("Benchmark 3 - Pair Treys") .WithDateBegin(DateTime.Parse("2000-01-01")) .WithContent(ContentTypes.TexasHoldemPokerSingleCombinations, new SingleCombinationPokerScore { Combination = "Pair" }) .WithCondition(ConditionTypes.NumberOfTreys, Operators.Equal, 2) .Build().Rule, - RuleBuilder.NewRule() + Rule.New() .WithName("Benchmark 3 - Pair Fours") .WithDateBegin(DateTime.Parse("2000-01-01")) .WithContent(ContentTypes.TexasHoldemPokerSingleCombinations, new SingleCombinationPokerScore { Combination = "Pair" }) .WithCondition(ConditionTypes.NumberOfFours, Operators.Equal, 2) .Build().Rule, - RuleBuilder.NewRule() + Rule.New() .WithName("Benchmark 3 - Pair Fives") .WithDateBegin(DateTime.Parse("2000-01-01")) .WithContent(ContentTypes.TexasHoldemPokerSingleCombinations, new SingleCombinationPokerScore { Combination = "Pair" }) .WithCondition(ConditionTypes.NumberOfFives, Operators.Equal, 2) .Build().Rule, - RuleBuilder.NewRule() + Rule.New() .WithName("Benchmark 3 - Pair Sixes") .WithDateBegin(DateTime.Parse("2000-01-01")) .WithContent(ContentTypes.TexasHoldemPokerSingleCombinations, new SingleCombinationPokerScore { Combination = "Pair" }) .WithCondition(ConditionTypes.NumberOfSixes, Operators.Equal, 2) .Build().Rule, - RuleBuilder.NewRule() + Rule.New() .WithName("Benchmark 3 - Pair Sevens") .WithDateBegin(DateTime.Parse("2000-01-01")) .WithContent(ContentTypes.TexasHoldemPokerSingleCombinations, new SingleCombinationPokerScore { Combination = "Pair" }) .WithCondition(ConditionTypes.NumberOfSevens, Operators.Equal, 2) .Build().Rule, - RuleBuilder.NewRule() + Rule.New() .WithName("Benchmark 3 - Pair Eights") .WithDateBegin(DateTime.Parse("2000-01-01")) .WithContent(ContentTypes.TexasHoldemPokerSingleCombinations, new SingleCombinationPokerScore { Combination = "Pair" }) .WithCondition(ConditionTypes.NumberOfEigths, Operators.Equal, 2) .Build().Rule, - RuleBuilder.NewRule() + Rule.New() .WithName("Benchmark 3 - Pair Nines") .WithDateBegin(DateTime.Parse("2000-01-01")) .WithContent(ContentTypes.TexasHoldemPokerSingleCombinations, new SingleCombinationPokerScore { Combination = "Pair" }) .WithCondition(ConditionTypes.NumberOfNines, Operators.Equal, 2) .Build().Rule, - RuleBuilder.NewRule() + Rule.New() .WithName("Benchmark 3 - Pair Tens") .WithDateBegin(DateTime.Parse("2000-01-01")) .WithContent(ContentTypes.TexasHoldemPokerSingleCombinations, new SingleCombinationPokerScore { Combination = "Pair" }) .WithCondition(ConditionTypes.NumberOfTens, Operators.Equal, 2) .Build().Rule, - RuleBuilder.NewRule() + Rule.New() .WithName("Benchmark 3 - Pair Jacks") .WithDateBegin(DateTime.Parse("2000-01-01")) .WithContent(ContentTypes.TexasHoldemPokerSingleCombinations, new SingleCombinationPokerScore { Combination = "Pair" }) .WithCondition(ConditionTypes.NumberOfJacks, Operators.Equal, 2) .Build().Rule, - RuleBuilder.NewRule() + Rule.New() .WithName("Benchmark 3 - Pair Queens") .WithDateBegin(DateTime.Parse("2000-01-01")) .WithContent(ContentTypes.TexasHoldemPokerSingleCombinations, new SingleCombinationPokerScore { Combination = "Pair" }) .WithCondition(ConditionTypes.NumberOfQueens, Operators.Equal, 2) .Build().Rule, - RuleBuilder.NewRule() + Rule.New() .WithName("Benchmark 3 - Pair Kings") .WithDateBegin(DateTime.Parse("2000-01-01")) .WithContent(ContentTypes.TexasHoldemPokerSingleCombinations, new SingleCombinationPokerScore { Combination = "Pair" }) .WithCondition(ConditionTypes.NumberOfKings, Operators.Equal, 2) .Build().Rule, - RuleBuilder.NewRule() + Rule.New() .WithName("Benchmark 3 - Pair Aces") .WithDateBegin(DateTime.Parse("2000-01-01")) .WithContent(ContentTypes.TexasHoldemPokerSingleCombinations, new SingleCombinationPokerScore { Combination = "Pair" }) diff --git a/tests/Rules.Framework.IntegrationTests.Common/Scenarios/Scenario8/Scenario8Data.RoyalFlush.cs b/tests/Rules.Framework.IntegrationTests.Common/Scenarios/Scenario8/Scenario8Data.RoyalFlush.cs index 57297782..515ba293 100644 --- a/tests/Rules.Framework.IntegrationTests.Common/Scenarios/Scenario8/Scenario8Data.RoyalFlush.cs +++ b/tests/Rules.Framework.IntegrationTests.Common/Scenarios/Scenario8/Scenario8Data.RoyalFlush.cs @@ -2,7 +2,8 @@ namespace Rules.Framework.BenchmarkTests.Tests.Benchmark3 { using System; using System.Collections.Generic; - using Rules.Framework.Core; + using Rules.Framework; + using Rules.Framework.Generic; public partial class Scenario8Data : IScenarioData { @@ -10,7 +11,7 @@ private IEnumerable> GetRoyalFlushRules() { return new[] { - RuleBuilder.NewRule() + Rule.New() .WithName("Benchmark 3 - Royal flush of Clubs: Ace, King, Queen, Jack, 10") .WithDateBegin(DateTime.Parse("2000-01-01")) .WithContent(ContentTypes.TexasHoldemPokerSingleCombinations, new SingleCombinationPokerScore { Combination = "Royal Flush" }) @@ -24,7 +25,7 @@ private IEnumerable> GetRoyalFlushRules() ) ) .Build().Rule, - RuleBuilder.NewRule() + Rule.New() .WithName("Benchmark 3 - Royal flush of Diamonds: Ace, King, Queen, Jack, 10") .WithDateBegin(DateTime.Parse("2000-01-01")) .WithContent(ContentTypes.TexasHoldemPokerSingleCombinations, new SingleCombinationPokerScore { Combination = "Royal Flush" }) @@ -38,7 +39,7 @@ private IEnumerable> GetRoyalFlushRules() ) ) .Build().Rule, - RuleBuilder.NewRule() + Rule.New() .WithName("Benchmark 3 - Royal flush of Hearts: Ace, King, Queen, Jack, 10") .WithDateBegin(DateTime.Parse("2000-01-01")) .WithContent(ContentTypes.TexasHoldemPokerSingleCombinations, new SingleCombinationPokerScore { Combination = "Royal Flush" }) @@ -52,7 +53,7 @@ private IEnumerable> GetRoyalFlushRules() ) ) .Build().Rule, - RuleBuilder.NewRule() + Rule.New() .WithName("Benchmark 3 - Royal flush of Spades: Ace, King, Queen, Jack, 10") .WithDateBegin(DateTime.Parse("2000-01-01")) .WithContent(ContentTypes.TexasHoldemPokerSingleCombinations, new SingleCombinationPokerScore { Combination = "Royal Flush" }) diff --git a/tests/Rules.Framework.IntegrationTests.Common/Scenarios/Scenario8/Scenario8Data.Straight.cs b/tests/Rules.Framework.IntegrationTests.Common/Scenarios/Scenario8/Scenario8Data.Straight.cs index 8cad58e1..2f629a39 100644 --- a/tests/Rules.Framework.IntegrationTests.Common/Scenarios/Scenario8/Scenario8Data.Straight.cs +++ b/tests/Rules.Framework.IntegrationTests.Common/Scenarios/Scenario8/Scenario8Data.Straight.cs @@ -2,7 +2,8 @@ namespace Rules.Framework.BenchmarkTests.Tests.Benchmark3 { using System; using System.Collections.Generic; - using Rules.Framework.Core; + using Rules.Framework; + using Rules.Framework.Generic; public partial class Scenario8Data : IScenarioData { @@ -10,7 +11,7 @@ private IEnumerable> GetStraightRules() { return new[] { - RuleBuilder.NewRule() + Rule.New() .WithName("Benchmark 3 - Straight 6, 5, 4, 3, 2") .WithDateBegin(DateTime.Parse("2000-01-01")) .WithContent(ContentTypes.TexasHoldemPokerSingleCombinations, new SingleCombinationPokerScore { Combination = "Straight" }) @@ -24,7 +25,7 @@ private IEnumerable> GetStraightRules() ) ) .Build().Rule, - RuleBuilder.NewRule() + Rule.New() .WithName("Benchmark 3 - Straight 7, 6, 5, 4, 3") .WithDateBegin(DateTime.Parse("2000-01-01")) .WithContent(ContentTypes.TexasHoldemPokerSingleCombinations, new SingleCombinationPokerScore { Combination = "Straight" }) @@ -38,7 +39,7 @@ private IEnumerable> GetStraightRules() ) ) .Build().Rule, - RuleBuilder.NewRule() + Rule.New() .WithName("Benchmark 3 - Straight 8, 7, 6, 5, 4") .WithDateBegin(DateTime.Parse("2000-01-01")) .WithContent(ContentTypes.TexasHoldemPokerSingleCombinations, new SingleCombinationPokerScore { Combination = "Straight" }) @@ -52,7 +53,7 @@ private IEnumerable> GetStraightRules() ) ) .Build().Rule, - RuleBuilder.NewRule() + Rule.New() .WithName("Benchmark 3 - Straight 9, 8, 7, 6, 5") .WithDateBegin(DateTime.Parse("2000-01-01")) .WithContent(ContentTypes.TexasHoldemPokerSingleCombinations, new SingleCombinationPokerScore { Combination = "Straight" }) @@ -66,7 +67,7 @@ private IEnumerable> GetStraightRules() ) ) .Build().Rule, - RuleBuilder.NewRule() + Rule.New() .WithName("Benchmark 3 - Straight 10, 9, 8, 7, 6") .WithDateBegin(DateTime.Parse("2000-01-01")) .WithContent(ContentTypes.TexasHoldemPokerSingleCombinations, new SingleCombinationPokerScore { Combination = "Straight" }) @@ -80,7 +81,7 @@ private IEnumerable> GetStraightRules() ) ) .Build().Rule, - RuleBuilder.NewRule() + Rule.New() .WithName("Benchmark 3 - Straight Jack, 10, 9, 8, 7") .WithDateBegin(DateTime.Parse("2000-01-01")) .WithContent(ContentTypes.TexasHoldemPokerSingleCombinations, new SingleCombinationPokerScore { Combination = "Straight" }) @@ -94,7 +95,7 @@ private IEnumerable> GetStraightRules() ) ) .Build().Rule, - RuleBuilder.NewRule() + Rule.New() .WithName("Benchmark 3 - Straight Queen, Jack, 10, 9, 8") .WithDateBegin(DateTime.Parse("2000-01-01")) .WithContent(ContentTypes.TexasHoldemPokerSingleCombinations, new SingleCombinationPokerScore { Combination = "Straight" }) @@ -108,7 +109,7 @@ private IEnumerable> GetStraightRules() ) ) .Build().Rule, - RuleBuilder.NewRule() + Rule.New() .WithName("Benchmark 3 - Straight King, Queen, Jack, 10, 9") .WithDateBegin(DateTime.Parse("2000-01-01")) .WithContent(ContentTypes.TexasHoldemPokerSingleCombinations, new SingleCombinationPokerScore { Combination = "Straight" }) diff --git a/tests/Rules.Framework.IntegrationTests.Common/Scenarios/Scenario8/Scenario8Data.StraightFlush.cs b/tests/Rules.Framework.IntegrationTests.Common/Scenarios/Scenario8/Scenario8Data.StraightFlush.cs index 2cbcb60a..f1b2dea8 100644 --- a/tests/Rules.Framework.IntegrationTests.Common/Scenarios/Scenario8/Scenario8Data.StraightFlush.cs +++ b/tests/Rules.Framework.IntegrationTests.Common/Scenarios/Scenario8/Scenario8Data.StraightFlush.cs @@ -2,8 +2,8 @@ namespace Rules.Framework.BenchmarkTests.Tests.Benchmark3 { using System; using System.Collections.Generic; - using Rules.Framework.Builder; - using Rules.Framework.Core; + using Rules.Framework; + using Rules.Framework.Generic; public partial class Scenario8Data : IScenarioData { @@ -12,7 +12,7 @@ private IEnumerable> GetStraightFlushRules() return new[] { // Straight flush of Clubs: - RuleBuilder.NewRule() + Rule.New() .WithName("Benchmark 3 - Straight flush of Clubs: 6, 5, 4, 3, 2") .WithDateBegin(DateTime.Parse("2000-01-01")) .WithContent(ContentTypes.TexasHoldemPokerSingleCombinations, new SingleCombinationPokerScore { Combination = "Straight Flush" }) @@ -26,7 +26,7 @@ private IEnumerable> GetStraightFlushRules() ) ) .Build().Rule, - RuleBuilder.NewRule() + Rule.New() .WithName("Benchmark 3 - Straight flush of Clubs: 7, 6, 5, 4, 3") .WithDateBegin(DateTime.Parse("2000-01-01")) .WithContent(ContentTypes.TexasHoldemPokerSingleCombinations, new SingleCombinationPokerScore { Combination = "Straight Flush" }) @@ -40,7 +40,7 @@ private IEnumerable> GetStraightFlushRules() ) ) .Build().Rule, - RuleBuilder.NewRule() + Rule.New() .WithName("Benchmark 3 - Straight flush of Clubs: 8, 7, 6, 5, 4") .WithDateBegin(DateTime.Parse("2000-01-01")) .WithContent(ContentTypes.TexasHoldemPokerSingleCombinations, new SingleCombinationPokerScore { Combination = "Straight Flush" }) @@ -54,7 +54,7 @@ private IEnumerable> GetStraightFlushRules() ) ) .Build().Rule, - RuleBuilder.NewRule() + Rule.New() .WithName("Benchmark 3 - Straight flush of Clubs: 9, 8, 7, 6, 5") .WithDateBegin(DateTime.Parse("2000-01-01")) .WithContent(ContentTypes.TexasHoldemPokerSingleCombinations, new SingleCombinationPokerScore { Combination = "Straight Flush" }) @@ -68,7 +68,7 @@ private IEnumerable> GetStraightFlushRules() ) ) .Build().Rule, - RuleBuilder.NewRule() + Rule.New() .WithName("Benchmark 3 - Straight flush of Clubs: 10, 9, 8, 7, 6") .WithDateBegin(DateTime.Parse("2000-01-01")) .WithContent(ContentTypes.TexasHoldemPokerSingleCombinations, new SingleCombinationPokerScore { Combination = "Straight Flush" }) @@ -82,7 +82,7 @@ private IEnumerable> GetStraightFlushRules() ) ) .Build().Rule, - RuleBuilder.NewRule() + Rule.New() .WithName("Benchmark 3 - Straight flush of Clubs: Jack, 10, 9, 8, 7") .WithDateBegin(DateTime.Parse("2000-01-01")) .WithContent(ContentTypes.TexasHoldemPokerSingleCombinations, new SingleCombinationPokerScore { Combination = "Straight Flush" }) @@ -96,7 +96,7 @@ private IEnumerable> GetStraightFlushRules() ) ) .Build().Rule, - RuleBuilder.NewRule() + Rule.New() .WithName("Benchmark 3 - Straight flush of Clubs: Queen, Jack, 10, 9, 8") .WithDateBegin(DateTime.Parse("2000-01-01")) .WithContent(ContentTypes.TexasHoldemPokerSingleCombinations, new SingleCombinationPokerScore { Combination = "Straight Flush" }) @@ -110,7 +110,7 @@ private IEnumerable> GetStraightFlushRules() ) ) .Build().Rule, - RuleBuilder.NewRule() + Rule.New() .WithName("Benchmark 3 - Straight flush of Clubs: King, Queen, Jack, 10, 9") .WithDateBegin(DateTime.Parse("2000-01-01")) .WithContent(ContentTypes.TexasHoldemPokerSingleCombinations, new SingleCombinationPokerScore { Combination = "Straight Flush" }) @@ -126,7 +126,7 @@ private IEnumerable> GetStraightFlushRules() .Build().Rule, // Straight flush of Diamonds: - RuleBuilder.NewRule() + Rule.New() .WithName("Benchmark 3 - Straight flush of Diamonds: 6, 5, 4, 3, 2") .WithDateBegin(DateTime.Parse("2000-01-01")) .WithContent(ContentTypes.TexasHoldemPokerSingleCombinations, new SingleCombinationPokerScore { Combination = "Straight Flush" }) @@ -140,7 +140,7 @@ private IEnumerable> GetStraightFlushRules() ) ) .Build().Rule, - RuleBuilder.NewRule() + Rule.New() .WithName("Benchmark 3 - Straight flush of Diamonds: 7, 6, 5, 4, 3") .WithDateBegin(DateTime.Parse("2000-01-01")) .WithContent(ContentTypes.TexasHoldemPokerSingleCombinations, new SingleCombinationPokerScore { Combination = "Straight Flush" }) @@ -154,7 +154,7 @@ private IEnumerable> GetStraightFlushRules() ) ) .Build().Rule, - RuleBuilder.NewRule() + Rule.New() .WithName("Benchmark 3 - Straight flush of Diamonds: 8, 7, 6, 5, 4") .WithDateBegin(DateTime.Parse("2000-01-01")) .WithContent(ContentTypes.TexasHoldemPokerSingleCombinations, new SingleCombinationPokerScore { Combination = "Straight Flush" }) @@ -168,7 +168,7 @@ private IEnumerable> GetStraightFlushRules() ) ) .Build().Rule, - RuleBuilder.NewRule() + Rule.New() .WithName("Benchmark 3 - Straight flush of Diamonds: 9, 8, 7, 6, 5") .WithDateBegin(DateTime.Parse("2000-01-01")) .WithContent(ContentTypes.TexasHoldemPokerSingleCombinations, new SingleCombinationPokerScore { Combination = "Straight Flush" }) @@ -182,7 +182,7 @@ private IEnumerable> GetStraightFlushRules() ) ) .Build().Rule, - RuleBuilder.NewRule() + Rule.New() .WithName("Benchmark 3 - Straight flush of Diamonds: 10, 9, 8, 7, 6") .WithDateBegin(DateTime.Parse("2000-01-01")) .WithContent(ContentTypes.TexasHoldemPokerSingleCombinations, new SingleCombinationPokerScore { Combination = "Straight Flush" }) @@ -196,7 +196,7 @@ private IEnumerable> GetStraightFlushRules() ) ) .Build().Rule, - RuleBuilder.NewRule() + Rule.New() .WithName("Benchmark 3 - Straight flush of Diamonds: Jack, 10, 9, 8, 7") .WithDateBegin(DateTime.Parse("2000-01-01")) .WithContent(ContentTypes.TexasHoldemPokerSingleCombinations, new SingleCombinationPokerScore { Combination = "Straight Flush" }) @@ -210,7 +210,7 @@ private IEnumerable> GetStraightFlushRules() ) ) .Build().Rule, - RuleBuilder.NewRule() + Rule.New() .WithName("Benchmark 3 - Straight flush of Diamonds: Queen, Jack, 10, 9, 8") .WithDateBegin(DateTime.Parse("2000-01-01")) .WithContent(ContentTypes.TexasHoldemPokerSingleCombinations, new SingleCombinationPokerScore { Combination = "Straight Flush" }) @@ -224,7 +224,7 @@ private IEnumerable> GetStraightFlushRules() ) ) .Build().Rule, - RuleBuilder.NewRule() + Rule.New() .WithName("Benchmark 3 - Straight flush of Diamonds: King, Queen, Jack, 10, 9") .WithDateBegin(DateTime.Parse("2000-01-01")) .WithContent(ContentTypes.TexasHoldemPokerSingleCombinations, new SingleCombinationPokerScore { Combination = "Straight Flush" }) @@ -240,7 +240,7 @@ private IEnumerable> GetStraightFlushRules() .Build().Rule, // Straight flush of Hearts: - RuleBuilder.NewRule() + Rule.New() .WithName("Benchmark 3 - Straight flush of Hearts: 6, 5, 4, 3, 2") .WithDateBegin(DateTime.Parse("2000-01-01")) .WithContent(ContentTypes.TexasHoldemPokerSingleCombinations, new SingleCombinationPokerScore { Combination = "Straight Flush" }) @@ -254,7 +254,7 @@ private IEnumerable> GetStraightFlushRules() ) ) .Build().Rule, - RuleBuilder.NewRule() + Rule.New() .WithName("Benchmark 3 - Straight flush of Hearts: 7, 6, 5, 4, 3") .WithDateBegin(DateTime.Parse("2000-01-01")) .WithContent(ContentTypes.TexasHoldemPokerSingleCombinations, new SingleCombinationPokerScore { Combination = "Straight Flush" }) @@ -268,7 +268,7 @@ private IEnumerable> GetStraightFlushRules() ) ) .Build().Rule, - RuleBuilder.NewRule() + Rule.New() .WithName("Benchmark 3 - Straight flush of Hearts: 8, 7, 6, 5, 4") .WithDateBegin(DateTime.Parse("2000-01-01")) .WithContent(ContentTypes.TexasHoldemPokerSingleCombinations, new SingleCombinationPokerScore { Combination = "Straight Flush" }) @@ -282,7 +282,7 @@ private IEnumerable> GetStraightFlushRules() ) ) .Build().Rule, - RuleBuilder.NewRule() + Rule.New() .WithName("Benchmark 3 - Straight flush of Hearts: 9, 8, 7, 6, 5") .WithDateBegin(DateTime.Parse("2000-01-01")) .WithContent(ContentTypes.TexasHoldemPokerSingleCombinations, new SingleCombinationPokerScore { Combination = "Straight Flush" }) @@ -296,7 +296,7 @@ private IEnumerable> GetStraightFlushRules() ) ) .Build().Rule, - RuleBuilder.NewRule() + Rule.New() .WithName("Benchmark 3 - Straight flush of Hearts: 10, 9, 8, 7, 6") .WithDateBegin(DateTime.Parse("2000-01-01")) .WithContent(ContentTypes.TexasHoldemPokerSingleCombinations, new SingleCombinationPokerScore { Combination = "Straight Flush" }) @@ -310,7 +310,7 @@ private IEnumerable> GetStraightFlushRules() ) ) .Build().Rule, - RuleBuilder.NewRule() + Rule.New() .WithName("Benchmark 3 - Straight flush of Hearts: Jack, 10, 9, 8, 7") .WithDateBegin(DateTime.Parse("2000-01-01")) .WithContent(ContentTypes.TexasHoldemPokerSingleCombinations, new SingleCombinationPokerScore { Combination = "Straight Flush" }) @@ -324,7 +324,7 @@ private IEnumerable> GetStraightFlushRules() ) ) .Build().Rule, - RuleBuilder.NewRule() + Rule.New() .WithName("Benchmark 3 - Straight flush of Hearts: Queen, Jack, 10, 9, 8") .WithDateBegin(DateTime.Parse("2000-01-01")) .WithContent(ContentTypes.TexasHoldemPokerSingleCombinations, new SingleCombinationPokerScore { Combination = "Straight Flush" }) @@ -338,7 +338,7 @@ private IEnumerable> GetStraightFlushRules() ) ) .Build().Rule, - RuleBuilder.NewRule() + Rule.New() .WithName("Benchmark 3 - Straight flush of Hearts: King, Queen, Jack, 10, 9") .WithDateBegin(DateTime.Parse("2000-01-01")) .WithContent(ContentTypes.TexasHoldemPokerSingleCombinations, new SingleCombinationPokerScore { Combination = "Straight Flush" }) @@ -354,7 +354,7 @@ private IEnumerable> GetStraightFlushRules() .Build().Rule, // Straight flush of Spades: - RuleBuilder.NewRule() + Rule.New() .WithName("Benchmark 3 - Straight flush of Spades: 6, 5, 4, 3, 2") .WithDateBegin(DateTime.Parse("2000-01-01")) .WithContent(ContentTypes.TexasHoldemPokerSingleCombinations, new SingleCombinationPokerScore { Combination = "Straight Flush" }) @@ -368,7 +368,7 @@ private IEnumerable> GetStraightFlushRules() ) ) .Build().Rule, - RuleBuilder.NewRule() + Rule.New() .WithName("Benchmark 3 - Straight flush of Spades: 7, 6, 5, 4, 3") .WithDateBegin(DateTime.Parse("2000-01-01")) .WithContent(ContentTypes.TexasHoldemPokerSingleCombinations, new SingleCombinationPokerScore { Combination = "Straight Flush" }) @@ -382,7 +382,7 @@ private IEnumerable> GetStraightFlushRules() ) ) .Build().Rule, - RuleBuilder.NewRule() + Rule.New() .WithName("Benchmark 3 - Straight flush of Spades: 8, 7, 6, 5, 4") .WithDateBegin(DateTime.Parse("2000-01-01")) .WithContent(ContentTypes.TexasHoldemPokerSingleCombinations, new SingleCombinationPokerScore { Combination = "Straight Flush" }) @@ -396,7 +396,7 @@ private IEnumerable> GetStraightFlushRules() ) ) .Build().Rule, - RuleBuilder.NewRule() + Rule.New() .WithName("Benchmark 3 - Straight flush of Spades: 9, 8, 7, 6, 5") .WithDateBegin(DateTime.Parse("2000-01-01")) .WithContent(ContentTypes.TexasHoldemPokerSingleCombinations, new SingleCombinationPokerScore { Combination = "Straight Flush" }) @@ -410,7 +410,7 @@ private IEnumerable> GetStraightFlushRules() ) ) .Build().Rule, - RuleBuilder.NewRule() + Rule.New() .WithName("Benchmark 3 - Straight flush of Spades: 10, 9, 8, 7, 6") .WithDateBegin(DateTime.Parse("2000-01-01")) .WithContent(ContentTypes.TexasHoldemPokerSingleCombinations, new SingleCombinationPokerScore { Combination = "Straight Flush" }) @@ -424,7 +424,7 @@ private IEnumerable> GetStraightFlushRules() ) ) .Build().Rule, - RuleBuilder.NewRule() + Rule.New() .WithName("Benchmark 3 - Straight flush of Spades: Jack, 10, 9, 8, 7") .WithDateBegin(DateTime.Parse("2000-01-01")) .WithContent(ContentTypes.TexasHoldemPokerSingleCombinations, new SingleCombinationPokerScore { Combination = "Straight Flush" }) @@ -438,7 +438,7 @@ private IEnumerable> GetStraightFlushRules() ) ) .Build().Rule, - RuleBuilder.NewRule() + Rule.New() .WithName("Benchmark 3 - Straight flush of Spades: Queen, Jack, 10, 9, 8") .WithDateBegin(DateTime.Parse("2000-01-01")) .WithContent(ContentTypes.TexasHoldemPokerSingleCombinations, new SingleCombinationPokerScore { Combination = "Straight Flush" }) @@ -452,7 +452,7 @@ private IEnumerable> GetStraightFlushRules() ) ) .Build().Rule, - RuleBuilder.NewRule() + Rule.New() .WithName("Benchmark 3 - Straight flush of Spades: King, Queen, Jack, 10, 9") .WithDateBegin(DateTime.Parse("2000-01-01")) .WithContent(ContentTypes.TexasHoldemPokerSingleCombinations, new SingleCombinationPokerScore { Combination = "Straight Flush" }) diff --git a/tests/Rules.Framework.IntegrationTests.Common/Scenarios/Scenario8/Scenario8Data.ThreeOfAKind.cs b/tests/Rules.Framework.IntegrationTests.Common/Scenarios/Scenario8/Scenario8Data.ThreeOfAKind.cs index 637c3cb4..90e7ee6d 100644 --- a/tests/Rules.Framework.IntegrationTests.Common/Scenarios/Scenario8/Scenario8Data.ThreeOfAKind.cs +++ b/tests/Rules.Framework.IntegrationTests.Common/Scenarios/Scenario8/Scenario8Data.ThreeOfAKind.cs @@ -2,8 +2,8 @@ namespace Rules.Framework.BenchmarkTests.Tests.Benchmark3 { using System; using System.Collections.Generic; - using Rules.Framework.Builder; - using Rules.Framework.Core; + using Rules.Framework; + using Rules.Framework.Generic; public partial class Scenario8Data : IScenarioData { @@ -11,79 +11,79 @@ private IEnumerable> GetThreeOfAKindRules() { return new[] { - RuleBuilder.NewRule() + Rule.New() .WithName("Benchmark 3 - Three Of A Kind Deuces") .WithDateBegin(DateTime.Parse("2000-01-01")) .WithContent(ContentTypes.TexasHoldemPokerSingleCombinations, new SingleCombinationPokerScore { Combination = "Three Of A Kind" }) .WithCondition(ConditionTypes.NumberOfDeuces, Operators.Equal, 3) .Build().Rule, - RuleBuilder.NewRule() + Rule.New() .WithName("Benchmark 3 - Three Of A Kind Treys") .WithDateBegin(DateTime.Parse("2000-01-01")) .WithContent(ContentTypes.TexasHoldemPokerSingleCombinations, new SingleCombinationPokerScore { Combination = "Three Of A Kind" }) .WithCondition(ConditionTypes.NumberOfTreys, Operators.Equal, 3) .Build().Rule, - RuleBuilder.NewRule() + Rule.New() .WithName("Benchmark 3 - Three Of A Kind Fours") .WithDateBegin(DateTime.Parse("2000-01-01")) .WithContent(ContentTypes.TexasHoldemPokerSingleCombinations, new SingleCombinationPokerScore { Combination = "Three Of A Kind" }) .WithCondition(ConditionTypes.NumberOfDeuces, Operators.Equal, 3) .Build().Rule, - RuleBuilder.NewRule() + Rule.New() .WithName("Benchmark 3 - Three Of A Kind Fives") .WithDateBegin(DateTime.Parse("2000-01-01")) .WithContent(ContentTypes.TexasHoldemPokerSingleCombinations, new SingleCombinationPokerScore { Combination = "Three Of A Kind" }) .WithCondition(ConditionTypes.NumberOfFives, Operators.Equal, 3) .Build().Rule, - RuleBuilder.NewRule() + Rule.New() .WithName("Benchmark 3 - Three Of A Kind Sixes") .WithDateBegin(DateTime.Parse("2000-01-01")) .WithContent(ContentTypes.TexasHoldemPokerSingleCombinations, new SingleCombinationPokerScore { Combination = "Three Of A Kind" }) .WithCondition(ConditionTypes.NumberOfSixes, Operators.Equal, 3) .Build().Rule, - RuleBuilder.NewRule() + Rule.New() .WithName("Benchmark 3 - Three Of A Kind Sevens") .WithDateBegin(DateTime.Parse("2000-01-01")) .WithContent(ContentTypes.TexasHoldemPokerSingleCombinations, new SingleCombinationPokerScore { Combination = "Three Of A Kind" }) .WithCondition(ConditionTypes.NumberOfSevens, Operators.Equal, 3) .Build().Rule, - RuleBuilder.NewRule() + Rule.New() .WithName("Benchmark 3 - Three Of A Kind Eights") .WithDateBegin(DateTime.Parse("2000-01-01")) .WithContent(ContentTypes.TexasHoldemPokerSingleCombinations, new SingleCombinationPokerScore { Combination = "Three Of A Kind" }) .WithCondition(ConditionTypes.NumberOfEigths, Operators.Equal, 3) .Build().Rule, - RuleBuilder.NewRule() + Rule.New() .WithName("Benchmark 3 - Three Of A Kind Nines") .WithDateBegin(DateTime.Parse("2000-01-01")) .WithContent(ContentTypes.TexasHoldemPokerSingleCombinations, new SingleCombinationPokerScore { Combination = "Three Of A Kind" }) .WithCondition(ConditionTypes.NumberOfNines, Operators.Equal, 3) .Build().Rule, - RuleBuilder.NewRule() + Rule.New() .WithName("Benchmark 3 - Three Of A Kind Tens") .WithDateBegin(DateTime.Parse("2000-01-01")) .WithContent(ContentTypes.TexasHoldemPokerSingleCombinations, new SingleCombinationPokerScore { Combination = "Three Of A Kind" }) .WithCondition(ConditionTypes.NumberOfTens, Operators.Equal, 3) .Build().Rule, - RuleBuilder.NewRule() + Rule.New() .WithName("Benchmark 3 - Three Of A Kind Jacks") .WithDateBegin(DateTime.Parse("2000-01-01")) .WithContent(ContentTypes.TexasHoldemPokerSingleCombinations, new SingleCombinationPokerScore { Combination = "Three Of A Kind" }) .WithCondition(ConditionTypes.NumberOfJacks, Operators.Equal, 3) .Build().Rule, - RuleBuilder.NewRule() + Rule.New() .WithName("Benchmark 3 - Three Of A Kind Queens") .WithDateBegin(DateTime.Parse("2000-01-01")) .WithContent(ContentTypes.TexasHoldemPokerSingleCombinations, new SingleCombinationPokerScore { Combination = "Three Of A Kind" }) .WithCondition(ConditionTypes.NumberOfQueens, Operators.Equal, 3) .Build().Rule, - RuleBuilder.NewRule() + Rule.New() .WithName("Benchmark 3 - Three Of A Kind Kings") .WithDateBegin(DateTime.Parse("2000-01-01")) .WithContent(ContentTypes.TexasHoldemPokerSingleCombinations, new SingleCombinationPokerScore { Combination = "Three Of A Kind" }) .WithCondition(ConditionTypes.NumberOfKings, Operators.Equal, 3) .Build().Rule, - RuleBuilder.NewRule() + Rule.New() .WithName("Benchmark 3 - Three Of A Kind Aces") .WithDateBegin(DateTime.Parse("2000-01-01")) .WithContent(ContentTypes.TexasHoldemPokerSingleCombinations, new SingleCombinationPokerScore { Combination = "Three Of A Kind" }) diff --git a/tests/Rules.Framework.IntegrationTests.Common/Scenarios/Scenario8/Scenario8Data.cs b/tests/Rules.Framework.IntegrationTests.Common/Scenarios/Scenario8/Scenario8Data.cs index 47c1eb16..a6b7dc00 100644 --- a/tests/Rules.Framework.IntegrationTests.Common/Scenarios/Scenario8/Scenario8Data.cs +++ b/tests/Rules.Framework.IntegrationTests.Common/Scenarios/Scenario8/Scenario8Data.cs @@ -4,7 +4,7 @@ namespace Rules.Framework.BenchmarkTests.Tests.Benchmark3 using System.Collections.Generic; using System.Linq; using Rules.Framework; - using Rules.Framework.Core; + using Rules.Framework.Generic; public partial class Scenario8Data : IScenarioData { diff --git a/tests/Rules.Framework.IntegrationTests.Common/Scenarios/ScenarioLoader.cs b/tests/Rules.Framework.IntegrationTests.Common/Scenarios/ScenarioLoader.cs index df2e64a2..d243586d 100644 --- a/tests/Rules.Framework.IntegrationTests.Common/Scenarios/ScenarioLoader.cs +++ b/tests/Rules.Framework.IntegrationTests.Common/Scenarios/ScenarioLoader.cs @@ -5,9 +5,15 @@ namespace Rules.Framework.IntegrationTests.Common.Scenarios public static class ScenarioLoader { public static async Task LoadScenarioAsync( - RulesEngine rulesEngine, + IRulesEngine rulesEngine, IScenarioData scenarioData) { + var contentTypes = scenarioData.Rules.Select(r => ((Rule)r).ContentType).Distinct().ToArray(); + foreach (var contentType in contentTypes) + { + await rulesEngine.CreateContentTypeAsync(contentType).ConfigureAwait(false); + } + foreach (var rule in scenarioData.Rules) { await rulesEngine.AddRuleAsync(rule, RuleAddPriorityOption.AtTop).ConfigureAwait(false); diff --git a/tests/Rules.Framework.IntegrationTests/DataSource/RuleDataModel.cs b/tests/Rules.Framework.IntegrationTests/DataSource/RuleDataModel.cs index 67808701..c59aada6 100644 --- a/tests/Rules.Framework.IntegrationTests/DataSource/RuleDataModel.cs +++ b/tests/Rules.Framework.IntegrationTests/DataSource/RuleDataModel.cs @@ -5,7 +5,7 @@ namespace Rules.Framework.IntegrationTests.DataSource internal class RuleDataModel { public string Content { get; set; } - public short ContentTypeCode { get; set; } + public string ContentTypeCode { get; set; } public DateTime DateBegin { get; set; } @@ -17,4 +17,4 @@ internal class RuleDataModel public ConditionNodeDataModel RootCondition { get; set; } } -} +} \ No newline at end of file diff --git a/tests/Rules.Framework.IntegrationTests/JsonContentSerializationProvider.cs b/tests/Rules.Framework.IntegrationTests/JsonContentSerializationProvider.cs index 44dfdc6b..52897fbd 100644 --- a/tests/Rules.Framework.IntegrationTests/JsonContentSerializationProvider.cs +++ b/tests/Rules.Framework.IntegrationTests/JsonContentSerializationProvider.cs @@ -2,9 +2,9 @@ namespace Rules.Framework.IntegrationTests { using Rules.Framework.Serialization; - internal class JsonContentSerializationProvider : IContentSerializationProvider + internal class JsonContentSerializationProvider : IContentSerializationProvider { - public IContentSerializer GetContentSerializer(TContentType contentType) + public IContentSerializer GetContentSerializer(string contentType) { return new JsonContentSerializer(); } diff --git a/tests/Rules.Framework.IntegrationTests/RulesFromJsonFile.cs b/tests/Rules.Framework.IntegrationTests/RulesFromJsonFile.cs index 8a567d1f..3b6c56c1 100644 --- a/tests/Rules.Framework.IntegrationTests/RulesFromJsonFile.cs +++ b/tests/Rules.Framework.IntegrationTests/RulesFromJsonFile.cs @@ -6,8 +6,10 @@ namespace Rules.Framework.IntegrationTests using System.IO; using System.Threading.Tasks; using Newtonsoft.Json; + using Rules.Framework; using Rules.Framework.Builder; - using Rules.Framework.Core; + using Rules.Framework.Builder.Generic; + using Rules.Framework.Generic; using Rules.Framework.IntegrationTests.DataSource; internal class RulesFromJsonFile @@ -16,7 +18,7 @@ internal class RulesFromJsonFile public static RulesFromJsonFile Load => instance; - public async Task FromJsonFileAsync(RulesEngine rulesEngine, string filePath, Type contentRuntimeType, bool serializedContent = true) + public async Task FromJsonFileAsync(IRulesEngine rulesEngine, string filePath, Type contentRuntimeType, bool serializedContent = true) where TContentType : new() { using (var fileStream = new FileStream(filePath, FileMode.Open, FileAccess.Read)) @@ -24,12 +26,18 @@ public async Task FromJsonFileAsync(RulesEngine>(contents); + var addedContentTypes = new HashSet(); foreach (var ruleDataModel in ruleDataModels) { var contentType = GetContentType(ruleDataModel.ContentTypeCode); + if (!addedContentTypes.Contains(contentType)) + { + await rulesEngine.CreateContentTypeAsync(contentType); + addedContentTypes.Add(contentType); + } - var ruleBuilder = RuleBuilder.NewRule() + var ruleBuilder = Rule.New() .WithName(ruleDataModel.Name) .WithDatesInterval(ruleDataModel.DateBegin, ruleDataModel.DateEnd); @@ -101,7 +109,7 @@ private static IFluentComposedConditionNodeBuilder CreateValueCo } } - private static IConditionNode CreateValueConditionNode(IRootConditionNodeBuilder conditionNodeBuilder, ConditionNodeDataModel conditionNodeDataModel) + private static IConditionNode CreateValueConditionNode(IRootConditionNodeBuilder conditionNodeBuilder, ConditionNodeDataModel conditionNodeDataModel) { var dataType = RulesFromJsonFile.Parse(conditionNodeDataModel.DataType); var integrationTestsConditionType = RulesFromJsonFile.Parse(conditionNodeDataModel.ConditionType); @@ -138,8 +146,8 @@ private static IConditionNode CreateValueConditionNode(short contentTypeCode) where TContentType : new() - => RulesFromJsonFile.Parse(contentTypeCode.ToString()); + private static TContentType GetContentType(string contentTypeCode) where TContentType : new() + => RulesFromJsonFile.Parse(contentTypeCode); private static T Parse(string value) => (T)Parse(value, typeof(T)); @@ -147,7 +155,7 @@ private static T Parse(string value) private static object Parse(string value, Type type) => type.IsEnum ? Enum.Parse(type, value) : Convert.ChangeType(value, type, CultureInfo.InvariantCulture); - private IConditionNode ConvertConditionNode(IRootConditionNodeBuilder conditionNodeBuilder, ConditionNodeDataModel conditionNodeDataModel) + private IConditionNode ConvertConditionNode(IRootConditionNodeBuilder conditionNodeBuilder, ConditionNodeDataModel conditionNodeDataModel) { var logicalOperator = RulesFromJsonFile.Parse(conditionNodeDataModel.LogicalOperator); diff --git a/tests/Rules.Framework.IntegrationTests/Scenarios/Scenario1/BodyMassIndexTests.cs b/tests/Rules.Framework.IntegrationTests/Scenarios/Scenario1/BodyMassIndexTests.cs index 3a8fc253..bcb9c850 100644 --- a/tests/Rules.Framework.IntegrationTests/Scenarios/Scenario1/BodyMassIndexTests.cs +++ b/tests/Rules.Framework.IntegrationTests/Scenarios/Scenario1/BodyMassIndexTests.cs @@ -4,12 +4,11 @@ namespace Rules.Framework.IntegrationTests.Scenarios.Scenario1 using System.Threading.Tasks; using FluentAssertions; using Microsoft.Extensions.DependencyInjection; - using Rules.Framework.Core; + using Rules.Framework; using Rules.Framework.IntegrationTests.Common.Scenarios.Scenario1; using Rules.Framework.Providers.InMemory; using Xunit; - [System.Runtime.InteropServices.Guid("309D98C5-4007-4116-92B1-9FEAD18B9DC3")] public class BodyMassIndexTests { private static string DataSourceFilePath => $@"{Environment.CurrentDirectory}/Scenarios/Scenario1/rules-framework-tests.body-mass-index.datasource.json"; @@ -21,20 +20,21 @@ public async Task AddRule_AddingNewRuleFromScratchWithAgeConditionAtPriority1And { // Arrange var serviceProvider = new ServiceCollection() - .AddInMemoryRulesDataSource(ServiceLifetime.Singleton) + .AddInMemoryRulesDataSource(ServiceLifetime.Singleton) .BuildServiceProvider(); var rulesEngine = RulesEngineBuilder.CreateRulesEngine() - .WithContentType() - .WithConditionType() .SetInMemoryDataSource(serviceProvider) .Configure(options => { options.EnableCompilation = enableCompilation; }) .Build(); + var genericRulesEngine = rulesEngine.MakeGeneric(); - var newRuleResult1 = RuleBuilder.NewRule() + await genericRulesEngine.CreateContentTypeAsync(ContentTypes.BodyMassIndexFormula); + + var newRuleResult1 = Rule.New() .WithName("Body Mass Index up to 18 years formula") .WithDateBegin(DateTime.Parse("2018-01-01")) .WithContent(ContentTypes.BodyMassIndexFormula, new Formula @@ -48,7 +48,7 @@ public async Task AddRule_AddingNewRuleFromScratchWithAgeConditionAtPriority1And var newRule1 = newRuleResult1.Rule; var ruleAddPriorityOption1 = RuleAddPriorityOption.ByPriorityNumber(1); - var ruleBuilderResult2 = RuleBuilder.NewRule() + var ruleBuilderResult2 = Rule.New() .WithName("Sample rule") .WithDateBegin(DateTime.Parse("2021-01-01")) .WithContent(ContentTypes.BodyMassIndexFormula, new Formula @@ -62,8 +62,8 @@ public async Task AddRule_AddingNewRuleFromScratchWithAgeConditionAtPriority1And var ruleAddPriorityOption2 = RuleAddPriorityOption.ByPriorityNumber(4); // Act - var ruleOperationResult1 = await rulesEngine.AddRuleAsync(newRule1, ruleAddPriorityOption1).ConfigureAwait(false); - var ruleOperationResult2 = await rulesEngine.AddRuleAsync(newRule2, ruleAddPriorityOption2).ConfigureAwait(false); + var ruleOperationResult1 = await genericRulesEngine.AddRuleAsync(newRule1, ruleAddPriorityOption1); + var ruleOperationResult2 = await genericRulesEngine.AddRuleAsync(newRule2, ruleAddPriorityOption2); // Assert ruleOperationResult1.Should().NotBeNull(); @@ -72,11 +72,11 @@ public async Task AddRule_AddingNewRuleFromScratchWithAgeConditionAtPriority1And ruleOperationResult2.Should().NotBeNull(); ruleOperationResult2.IsSuccess.Should().BeTrue(); - var inMemoryRulesStorage = serviceProvider.GetService>(); + var inMemoryRulesStorage = serviceProvider.GetService(); var rulesDataSource = CreateRulesDataSource(inMemoryRulesStorage); - var rules = await rulesDataSource.GetRulesByAsync(new RulesFilterArgs()).ConfigureAwait(false); + var rules = await rulesDataSource.GetRulesByAsync(new RulesFilterArgs()); rules.Should().NotBeNull().And.HaveCount(2); - rules.Should().ContainEquivalentOf(newRule1); + rules.Should().ContainEquivalentOf((Rule)newRule1); newRule1.Priority.Should().Be(1, "rule should to priority 1 if inserted at priority 1"); newRule2.Priority.Should().Be(2, "rule should have priority 2 if inserted at priority 2, given that last rule after insert was at priority 2."); } @@ -88,23 +88,22 @@ public async Task AddRule_AddingNewRuleWithAgeConditionAtPriority1AndNewRuleAtPr { // Arrange var serviceProvider = new ServiceCollection() - .AddInMemoryRulesDataSource(ServiceLifetime.Singleton) + .AddInMemoryRulesDataSource(ServiceLifetime.Singleton) .BuildServiceProvider(); var rulesEngine = RulesEngineBuilder.CreateRulesEngine() - .WithContentType() - .WithConditionType() .SetInMemoryDataSource(serviceProvider) .Configure(options => { options.EnableCompilation = enableCompilation; }) .Build(); + var genericRulesEngine = rulesEngine.MakeGeneric(); await RulesFromJsonFile.Load - .FromJsonFileAsync(rulesEngine, DataSourceFilePath, typeof(Formula)); + .FromJsonFileAsync(genericRulesEngine, DataSourceFilePath, typeof(Formula)); - var newRuleResult1 = RuleBuilder.NewRule() + var newRuleResult1 = Rule.New() .WithName("Body Mass Index up to 18 years formula") .WithDateBegin(DateTime.Parse("2018-01-01")) .WithContent(ContentTypes.BodyMassIndexFormula, new Formula @@ -118,7 +117,7 @@ await RulesFromJsonFile.Load var newRule1 = newRuleResult1.Rule; var ruleAddPriorityOption1 = RuleAddPriorityOption.ByPriorityNumber(1); - var ruleBuilderResult2 = RuleBuilder.NewRule() + var ruleBuilderResult2 = Rule.New() .WithName("Sample rule") .WithDateBegin(DateTime.Parse("2021-01-01")) .WithContent(ContentTypes.BodyMassIndexFormula, new Formula @@ -132,8 +131,8 @@ await RulesFromJsonFile.Load var ruleAddPriorityOption2 = RuleAddPriorityOption.ByPriorityNumber(4); // Act - var ruleOperationResult1 = await rulesEngine.AddRuleAsync(newRule1, ruleAddPriorityOption1).ConfigureAwait(false); - var ruleOperationResult2 = await rulesEngine.AddRuleAsync(newRule2, ruleAddPriorityOption2).ConfigureAwait(false); + var ruleOperationResult1 = await genericRulesEngine.AddRuleAsync(newRule1, ruleAddPriorityOption1); + var ruleOperationResult2 = await genericRulesEngine.AddRuleAsync(newRule2, ruleAddPriorityOption2); // Assert ruleOperationResult1.Should().NotBeNull(); @@ -142,11 +141,11 @@ await RulesFromJsonFile.Load ruleOperationResult2.Should().NotBeNull(); ruleOperationResult2.IsSuccess.Should().BeTrue(); - var inMemoryRulesStorage = serviceProvider.GetService>(); + var inMemoryRulesStorage = serviceProvider.GetService(); var rulesDataSource = CreateRulesDataSource(inMemoryRulesStorage); - var rules = await rulesDataSource.GetRulesByAsync(new RulesFilterArgs()).ConfigureAwait(false); + var rules = await rulesDataSource.GetRulesByAsync(new RulesFilterArgs()); rules.Should().NotBeNull().And.HaveCount(3); - rules.Should().ContainEquivalentOf(newRule1); + rules.Should().ContainEquivalentOf((Rule)newRule1); newRule1.Priority.Should().Be(1, "rule should to priority 1 if inserted at priority 1"); newRule2.Priority.Should().Be(3, "rule should have priority 3 if inserted at priority 3, given that last rule after insert was at priority 2."); } @@ -158,23 +157,22 @@ public async Task AddRule_AddingNewRuleWithAgeConditionOnTop_NewRuleIsInsertedAn { // Arrange var serviceProvider = new ServiceCollection() - .AddInMemoryRulesDataSource(ServiceLifetime.Singleton) + .AddInMemoryRulesDataSource(ServiceLifetime.Singleton) .BuildServiceProvider(); var rulesEngine = RulesEngineBuilder.CreateRulesEngine() - .WithContentType() - .WithConditionType() .SetInMemoryDataSource(serviceProvider) .Configure(options => { options.EnableCompilation = enableCompilation; }) .Build(); + var genericRulesEngine = rulesEngine.MakeGeneric(); await RulesFromJsonFile.Load - .FromJsonFileAsync(rulesEngine, DataSourceFilePath, typeof(Formula)); + .FromJsonFileAsync(genericRulesEngine, DataSourceFilePath, typeof(Formula)); - var newRuleResult = RuleBuilder.NewRule() + var newRuleResult = Rule.New() .WithName("Body Mass Index up to 18 years formula") .WithDateBegin(DateTime.Parse("2018-01-01")) .WithContent(ContentTypes.BodyMassIndexFormula, new Formula @@ -192,17 +190,17 @@ await RulesFromJsonFile.Load }; // Act - var ruleOperationResult = await rulesEngine.AddRuleAsync(newRule, ruleAddPriorityOption).ConfigureAwait(false); + var ruleOperationResult = await genericRulesEngine.AddRuleAsync(newRule, ruleAddPriorityOption); // Assert ruleOperationResult.Should().NotBeNull(); ruleOperationResult.IsSuccess.Should().BeTrue(); - var inMemoryRulesStorage = serviceProvider.GetService>(); + var inMemoryRulesStorage = serviceProvider.GetService(); var rulesDataSource = CreateRulesDataSource(inMemoryRulesStorage); - var rules = await rulesDataSource.GetRulesByAsync(new RulesFilterArgs()).ConfigureAwait(false); + var rules = await rulesDataSource.GetRulesByAsync(new RulesFilterArgs()); rules.Should().NotBeNull().And.HaveCount(2); - rules.Should().ContainEquivalentOf(newRule, o => o.Excluding(x => x.RootCondition.Properties)); + rules.Should().ContainEquivalentOf((Rule)newRule, o => o.Excluding(x => x.RootCondition.Properties)); newRule.Priority.Should().Be(1, "rule should to priority 1 if inserted at top."); } @@ -212,31 +210,30 @@ await RulesFromJsonFile.Load public async Task BodyMassIndex_NoConditions_ReturnsDefaultFormula(bool enableCompilation) { // Arrange - string expectedFormulaDescription = "Body Mass Index default formula"; - string expectedFormulaValue = "weight / (height ^ 2)"; + var expectedFormulaDescription = "Body Mass Index default formula"; + var expectedFormulaValue = "weight / (height ^ 2)"; const ContentTypes expectedContent = ContentTypes.BodyMassIndexFormula; var expectedMatchDate = new DateTime(2018, 06, 01); var expectedConditions = new Condition[0]; var serviceProvider = new ServiceCollection() - .AddInMemoryRulesDataSource(ServiceLifetime.Singleton) + .AddInMemoryRulesDataSource(ServiceLifetime.Singleton) .BuildServiceProvider(); var rulesEngine = RulesEngineBuilder.CreateRulesEngine() - .WithContentType() - .WithConditionType() .SetInMemoryDataSource(serviceProvider) .Configure(options => { options.EnableCompilation = enableCompilation; }) .Build(); + var genericRulesEngine = rulesEngine.MakeGeneric(); await RulesFromJsonFile.Load - .FromJsonFileAsync(rulesEngine, DataSourceFilePath, typeof(Formula)); + .FromJsonFileAsync(genericRulesEngine, DataSourceFilePath, typeof(Formula)); // Act - var actual = await rulesEngine.MatchOneAsync(expectedContent, expectedMatchDate, expectedConditions); + var actual = await genericRulesEngine.MatchOneAsync(expectedContent, expectedMatchDate, expectedConditions); // Assert actual.Should().NotBeNull(); @@ -245,10 +242,10 @@ await RulesFromJsonFile.Load actualFormula.Value.Should().Be(expectedFormulaValue); } - private static IRulesDataSource CreateRulesDataSource(IInMemoryRulesStorage inMemoryRulesStorage) + private static InMemoryProviderRulesDataSource CreateRulesDataSource(IInMemoryRulesStorage inMemoryRulesStorage) { - var ruleFactory = new RuleFactory(); - return new InMemoryProviderRulesDataSource(inMemoryRulesStorage, ruleFactory); + var ruleFactory = new RuleFactory(); + return new InMemoryProviderRulesDataSource(inMemoryRulesStorage, ruleFactory); } } } \ No newline at end of file diff --git a/tests/Rules.Framework.IntegrationTests/Scenarios/Scenario2/CarInsuranceAdvisorTests.cs b/tests/Rules.Framework.IntegrationTests/Scenarios/Scenario2/CarInsuranceAdvisorTests.cs index 5107d60f..808a61d6 100644 --- a/tests/Rules.Framework.IntegrationTests/Scenarios/Scenario2/CarInsuranceAdvisorTests.cs +++ b/tests/Rules.Framework.IntegrationTests/Scenarios/Scenario2/CarInsuranceAdvisorTests.cs @@ -5,7 +5,7 @@ namespace Rules.Framework.IntegrationTests.Scenarios.Scenario2 using System.Threading.Tasks; using FluentAssertions; using Microsoft.Extensions.DependencyInjection; - using Rules.Framework.Core; + using Rules.Framework; using Rules.Framework.IntegrationTests.Common.Scenarios.Scenario2; using Rules.Framework.Providers.InMemory; using Xunit; @@ -31,12 +31,10 @@ public async Task GetCarInsuranceAdvice_ClaimDescriptionContionsAlcoholOrDrugs_R }; var serviceProvider = new ServiceCollection() - .AddInMemoryRulesDataSource(ServiceLifetime.Singleton) + .AddInMemoryRulesDataSource(ServiceLifetime.Singleton) .BuildServiceProvider(); var rulesEngine = RulesEngineBuilder.CreateRulesEngine() - .WithContentType() - .WithConditionType() .SetInMemoryDataSource(serviceProvider) .Configure(opt => { @@ -44,11 +42,12 @@ public async Task GetCarInsuranceAdvice_ClaimDescriptionContionsAlcoholOrDrugs_R opt.EnableCompilation = enableCompilation; }) .Build(); + var genericRulesEngine = rulesEngine.MakeGeneric(); await RulesFromJsonFile.Load - .FromJsonFileAsync(rulesEngine, DataSourceFilePath, typeof(CarInsuranceAdvices), serializedContent: false); + .FromJsonFileAsync(genericRulesEngine, DataSourceFilePath, typeof(CarInsuranceAdvices), serializedContent: false); - var ruleBuilderResult = RuleBuilder.NewRule() + var ruleBuilderResult = Rule.New() .WithName("Car Insurance Advise on on accident under the effect of drugs or alcohol") .WithDateBegin(DateTime.Parse("2020-01-01")) .WithCondition(c => c @@ -60,9 +59,9 @@ await RulesFromJsonFile.Load .Build(); // Act - await rulesEngine.AddRuleAsync(ruleBuilderResult.Rule, RuleAddPriorityOption.AtBottom).ConfigureAwait(false); + await genericRulesEngine.AddRuleAsync(ruleBuilderResult.Rule, RuleAddPriorityOption.AtBottom); - var actual = await rulesEngine.MatchOneAsync(expectedContent, expectedMatchDate, expectedConditions); + var actual = await genericRulesEngine.MatchOneAsync(expectedContent, expectedMatchDate, expectedConditions); // Assert actual.Should().NotBeNull(); @@ -86,12 +85,10 @@ public async Task GetCarInsuranceAdvice_RepairCostsNotWorthIt_ReturnsRefusePayme }; var serviceProvider = new ServiceCollection() - .AddInMemoryRulesDataSource(ServiceLifetime.Singleton) + .AddInMemoryRulesDataSource(ServiceLifetime.Singleton) .BuildServiceProvider(); var rulesEngine = RulesEngineBuilder.CreateRulesEngine() - .WithContentType() - .WithConditionType() .SetInMemoryDataSource(serviceProvider) .Configure(opt => { @@ -99,12 +96,13 @@ public async Task GetCarInsuranceAdvice_RepairCostsNotWorthIt_ReturnsRefusePayme opt.EnableCompilation = enableCompilation; }) .Build(); + var genericRulesEngine = rulesEngine.MakeGeneric(); await RulesFromJsonFile.Load - .FromJsonFileAsync(rulesEngine, DataSourceFilePath, typeof(CarInsuranceAdvices), serializedContent: false); + .FromJsonFileAsync(genericRulesEngine, DataSourceFilePath, typeof(CarInsuranceAdvices), serializedContent: false); // Act - var actual = await rulesEngine.MatchOneAsync(expectedContent, expectedMatchDate, expectedConditions); + var actual = await genericRulesEngine.MatchOneAsync(expectedContent, expectedMatchDate, expectedConditions); // Assert actual.Should().NotBeNull(); @@ -131,12 +129,10 @@ public async Task GetCarInsuranceAdvice_SearchForRulesExcludingRulesWithoutSearc }; var serviceProvider = new ServiceCollection() - .AddInMemoryRulesDataSource(ServiceLifetime.Singleton) + .AddInMemoryRulesDataSource(ServiceLifetime.Singleton) .BuildServiceProvider(); var rulesEngine = RulesEngineBuilder.CreateRulesEngine() - .WithContentType() - .WithConditionType() .SetInMemoryDataSource(serviceProvider) .Configure(opt => { @@ -144,12 +140,13 @@ public async Task GetCarInsuranceAdvice_SearchForRulesExcludingRulesWithoutSearc opt.EnableCompilation = enableCompilation; }) .Build(); + var genericRulesEngine = rulesEngine.MakeGeneric(); await RulesFromJsonFile.Load - .FromJsonFileAsync(rulesEngine, DataSourceFilePath, typeof(CarInsuranceAdvices), serializedContent: false); + .FromJsonFileAsync(genericRulesEngine, DataSourceFilePath, typeof(CarInsuranceAdvices), serializedContent: false); // Act - var actual = await rulesEngine.SearchAsync(searchArgs); + var actual = await genericRulesEngine.SearchAsync(searchArgs); // Assert actual.Should().NotBeNull(); @@ -174,12 +171,10 @@ public async Task GetCarInsuranceAdvice_SearchForRulesWithRepairCostsGreaterThan }; var serviceProvider = new ServiceCollection() - .AddInMemoryRulesDataSource(ServiceLifetime.Singleton) + .AddInMemoryRulesDataSource(ServiceLifetime.Singleton) .BuildServiceProvider(); var rulesEngine = RulesEngineBuilder.CreateRulesEngine() - .WithContentType() - .WithConditionType() .SetInMemoryDataSource(serviceProvider) .Configure(opt => { @@ -187,12 +182,13 @@ public async Task GetCarInsuranceAdvice_SearchForRulesWithRepairCostsGreaterThan opt.EnableCompilation = enableCompilation; }) .Build(); + var genericRulesEngine = rulesEngine.MakeGeneric(); await RulesFromJsonFile.Load - .FromJsonFileAsync(rulesEngine, DataSourceFilePath, typeof(CarInsuranceAdvices), serializedContent: false); + .FromJsonFileAsync(genericRulesEngine, DataSourceFilePath, typeof(CarInsuranceAdvices), serializedContent: false); // Act - var actual = await rulesEngine.SearchAsync(searchArgs); + var actual = await genericRulesEngine.SearchAsync(searchArgs); // Assert actual.Should().NotBeNull(); @@ -216,12 +212,10 @@ public async Task GetCarInsuranceAdvice_UpdatesRuleAndAddsNewOneAndEvaluates_Ret }; var serviceProvider = new ServiceCollection() - .AddInMemoryRulesDataSource(ServiceLifetime.Singleton) + .AddInMemoryRulesDataSource(ServiceLifetime.Singleton) .BuildServiceProvider(); var rulesEngine = RulesEngineBuilder.CreateRulesEngine() - .WithContentType() - .WithConditionType() .SetInMemoryDataSource(serviceProvider) .Configure(opt => { @@ -229,20 +223,20 @@ public async Task GetCarInsuranceAdvice_UpdatesRuleAndAddsNewOneAndEvaluates_Ret opt.EnableCompilation = enableCompilation; }) .Build(); + var genericRulesEngine = rulesEngine.MakeGeneric(); await RulesFromJsonFile.Load - .FromJsonFileAsync(rulesEngine, DataSourceFilePath, typeof(CarInsuranceAdvices), serializedContent: false); + .FromJsonFileAsync(genericRulesEngine, DataSourceFilePath, typeof(CarInsuranceAdvices), serializedContent: false); - var ruleBuilderResult = RuleBuilder - .NewRule() + var ruleBuilderResult = Rule.New() .WithName("Car Insurance Advise on self damage coverage") .WithDateBegin(DateTime.Parse("2018-01-01")) .WithContent(ContentTypes.CarInsuranceAdvice, CarInsuranceAdvices.Pay) .Build(); - var inMemoryRulesStorage = serviceProvider.GetService>(); + var inMemoryRulesStorage = serviceProvider.GetService(); var rulesDataSource = CreateRulesDataSource(inMemoryRulesStorage); - var existentRules1 = await rulesDataSource.GetRulesByAsync(new RulesFilterArgs + var existentRules1 = await rulesDataSource.GetRulesByAsync(new RulesFilterArgs { Name = "Car Insurance Advise on repair costs lower than franchise boundary" }); @@ -254,9 +248,9 @@ await RulesFromJsonFile.Load // Act 1 var updateOperationResult1 = await rulesEngine.UpdateRuleAsync(ruleToUpdate1); - var eval1 = await rulesEngine.MatchOneAsync(expectedContent, expectedMatchDate, expectedConditions); + var eval1 = await genericRulesEngine.MatchOneAsync(expectedContent, expectedMatchDate, expectedConditions); - var rules1 = await rulesDataSource.GetRulesByAsync(new RulesFilterArgs()); + var rules1 = await rulesDataSource.GetRulesByAsync(new RulesFilterArgs()); // Assert 1 updateOperationResult1.Should().NotBeNull(); @@ -279,15 +273,15 @@ await RulesFromJsonFile.Load rule13.Priority.Should().Be(3); // Act 2 - var addOperationResult = await rulesEngine.AddRuleAsync(ruleToAdd, new RuleAddPriorityOption + var addOperationResult = await genericRulesEngine.AddRuleAsync(ruleToAdd, new RuleAddPriorityOption { PriorityOption = PriorityOptions.AtRuleName, AtRuleNameOptionValue = "Car Insurance Advise on repair costs lower than franchise boundary" }); - var eval2 = await rulesEngine.MatchOneAsync(expectedContent, expectedMatchDate, expectedConditions).ConfigureAwait(false); + var eval2 = await genericRulesEngine.MatchOneAsync(expectedContent, expectedMatchDate, expectedConditions); - var rules2 = await rulesDataSource.GetRulesByAsync(new RulesFilterArgs()); + var rules2 = await rulesDataSource.GetRulesByAsync(new RulesFilterArgs()); // Assert 2 addOperationResult.Should().NotBeNull(); @@ -314,7 +308,7 @@ await RulesFromJsonFile.Load rule24.Priority.Should().Be(4); // Act 3 - var existentRules2 = await rulesDataSource.GetRulesByAsync(new RulesFilterArgs + var existentRules2 = await rulesDataSource.GetRulesByAsync(new RulesFilterArgs { Name = "Car Insurance Advise on repair costs lower than franchise boundary" }); @@ -324,9 +318,9 @@ await RulesFromJsonFile.Load var updateOperationResult2 = await rulesEngine.UpdateRuleAsync(ruleToUpdate2); - var eval3 = await rulesEngine.MatchOneAsync(expectedContent, expectedMatchDate, expectedConditions); + var eval3 = await genericRulesEngine.MatchOneAsync(expectedContent, expectedMatchDate, expectedConditions); - var rules3 = await rulesDataSource.GetRulesByAsync(new RulesFilterArgs()); + var rules3 = await rulesDataSource.GetRulesByAsync(new RulesFilterArgs()); // Assert 3 updateOperationResult2.Should().NotBeNull(); @@ -353,10 +347,10 @@ await RulesFromJsonFile.Load rule34.Priority.Should().Be(4); } - private static IRulesDataSource CreateRulesDataSource(IInMemoryRulesStorage inMemoryRulesStorage) + private static IRulesDataSource CreateRulesDataSource(IInMemoryRulesStorage inMemoryRulesStorage) { - var ruleFactory = new RuleFactory(); - return new InMemoryProviderRulesDataSource(inMemoryRulesStorage, ruleFactory); + var ruleFactory = new RuleFactory(); + return new InMemoryProviderRulesDataSource(inMemoryRulesStorage, ruleFactory); } } } \ No newline at end of file diff --git a/tests/Rules.Framework.IntegrationTests/Scenarios/Scenario3/BuildingSecuritySystemControlTests.cs b/tests/Rules.Framework.IntegrationTests/Scenarios/Scenario3/BuildingSecuritySystemControlTests.cs index cf01a8a8..f4961693 100644 --- a/tests/Rules.Framework.IntegrationTests/Scenarios/Scenario3/BuildingSecuritySystemControlTests.cs +++ b/tests/Rules.Framework.IntegrationTests/Scenarios/Scenario3/BuildingSecuritySystemControlTests.cs @@ -27,20 +27,19 @@ public async Task BuildingSecuritySystem_FireScenario_ReturnsActionsToTrigger() }; var serviceProvider = new ServiceCollection() - .AddInMemoryRulesDataSource(ServiceLifetime.Singleton) + .AddInMemoryRulesDataSource(ServiceLifetime.Singleton) .BuildServiceProvider(); var rulesEngine = RulesEngineBuilder.CreateRulesEngine() - .WithContentType() - .WithConditionType() .SetInMemoryDataSource(serviceProvider) .Build(); + var genericRulesEngine = rulesEngine.MakeGeneric(); await RulesFromJsonFile.Load - .FromJsonFileAsync(rulesEngine, DataSourceFilePath, typeof(SecuritySystemAction)); + .FromJsonFileAsync(genericRulesEngine, DataSourceFilePath, typeof(SecuritySystemAction)); // Act - var actual = await rulesEngine.MatchManyAsync(securitySystemActionable, expectedMatchDate, expectedConditions); + var actual = await genericRulesEngine.MatchManyAsync(securitySystemActionable, expectedMatchDate, expectedConditions); // Assert actual.Should().NotBeNull(); @@ -67,20 +66,19 @@ public async Task BuildingSecuritySystem_PowerFailureScenario_ReturnsActionsToTr }; var serviceProvider = new ServiceCollection() - .AddInMemoryRulesDataSource(ServiceLifetime.Singleton) + .AddInMemoryRulesDataSource(ServiceLifetime.Singleton) .BuildServiceProvider(); var rulesEngine = RulesEngineBuilder.CreateRulesEngine() - .WithContentType() - .WithConditionType() .SetInMemoryDataSource(serviceProvider) .Build(); + var genericRulesEngine = rulesEngine.MakeGeneric(); await RulesFromJsonFile.Load - .FromJsonFileAsync(rulesEngine, DataSourceFilePath, typeof(SecuritySystemAction)); + .FromJsonFileAsync(genericRulesEngine, DataSourceFilePath, typeof(SecuritySystemAction)); // Act - var actual = await rulesEngine.MatchManyAsync(securitySystemActionable, expectedMatchDate, expectedConditions); + var actual = await genericRulesEngine.MatchManyAsync(securitySystemActionable, expectedMatchDate, expectedConditions); // Assert actual.Should().NotBeNull(); @@ -106,20 +104,19 @@ public async Task BuildingSecuritySystem_PowerShutdownScenario_ReturnsActionsToT }; var serviceProvider = new ServiceCollection() - .AddInMemoryRulesDataSource(ServiceLifetime.Singleton) + .AddInMemoryRulesDataSource(ServiceLifetime.Singleton) .BuildServiceProvider(); var rulesEngine = RulesEngineBuilder.CreateRulesEngine() - .WithContentType() - .WithConditionType() .SetInMemoryDataSource(serviceProvider) .Build(); + var genericRulesEngine = rulesEngine.MakeGeneric(); await RulesFromJsonFile.Load - .FromJsonFileAsync(rulesEngine, DataSourceFilePath, typeof(SecuritySystemAction)); + .FromJsonFileAsync(genericRulesEngine, DataSourceFilePath, typeof(SecuritySystemAction)); // Act - var actual = await rulesEngine.MatchManyAsync(securitySystemActionable, expectedMatchDate, expectedConditions); + var actual = await genericRulesEngine.MatchManyAsync(securitySystemActionable, expectedMatchDate, expectedConditions); // Assert actual.Should().NotBeNull(); diff --git a/tests/Rules.Framework.IntegrationTests/Scenarios/Scenario4/DiscountCampaignTests.cs b/tests/Rules.Framework.IntegrationTests/Scenarios/Scenario4/DiscountCampaignTests.cs index 601c47b7..0ca3dc62 100644 --- a/tests/Rules.Framework.IntegrationTests/Scenarios/Scenario4/DiscountCampaignTests.cs +++ b/tests/Rules.Framework.IntegrationTests/Scenarios/Scenario4/DiscountCampaignTests.cs @@ -6,7 +6,7 @@ namespace Rules.Framework.IntegrationTests.Scenarios.Scenario4 using System.Threading.Tasks; using FluentAssertions; using Microsoft.Extensions.DependencyInjection; - using Rules.Framework.Core; + using Rules.Framework; using Rules.Framework.IntegrationTests.Common.Scenarios.Scenario4; using Xunit; @@ -26,22 +26,21 @@ public async Task DiscountsWeekend_Adding15PercentRulePerBrandAndEvaluatingOneOf { // Arrange var serviceProvider = new ServiceCollection() - .AddInMemoryRulesDataSource(ServiceLifetime.Singleton) + .AddInMemoryRulesDataSource(ServiceLifetime.Singleton) .BuildServiceProvider(); var rulesEngine = RulesEngineBuilder.CreateRulesEngine() - .WithContentType() - .WithConditionType() .SetInMemoryDataSource(serviceProvider) .Configure(options => { + options.AutoCreateContentTypes = true; options.EnableCompilation = enableCompilation; }) .Build(); + var genericRulesEngine = rulesEngine.MakeGeneric(); // Act 1 - Create rule with "in" operator - var ruleBuilderResult = RuleBuilder - .NewRule() + var ruleBuilderResult = Rule.New() .WithName("Discounts Weekend MAY2021") .WithDatesInterval(DateTime.Parse("2021-05-29Z"), DateTime.Parse("2021-05-31Z")) .WithContent(DiscountConfigurations.DiscountCampaigns, 15m) @@ -60,7 +59,7 @@ public async Task DiscountsWeekend_Adding15PercentRulePerBrandAndEvaluatingOneOf // Act 2 - Add new rule with "in" operator var rule = ruleBuilderResult.Rule; - var addRuleResult = await rulesEngine.AddRuleAsync(rule, RuleAddPriorityOption.AtTop).ConfigureAwait(false); + var addRuleResult = await genericRulesEngine.AddRuleAsync(rule, RuleAddPriorityOption.AtTop); // Assert 2 - Verify if rule was added addRuleResult.Should().NotBeNull(); @@ -74,7 +73,7 @@ public async Task DiscountsWeekend_Adding15PercentRulePerBrandAndEvaluatingOneOf new Condition(DiscountConditions.ProductRecommendedRetailPrice,1249.90m) }; - var actual = await rulesEngine.MatchOneAsync(DiscountConfigurations.DiscountCampaigns, matchDateTime, conditions).ConfigureAwait(false); + var actual = await genericRulesEngine.MatchOneAsync(DiscountConfigurations.DiscountCampaigns, matchDateTime, conditions); // Assert 3 actual.Should().NotBeNull(); @@ -88,21 +87,21 @@ public async Task DiscountsWeekend_Adding20PercentRulePerProductTierAndEvaluatin { // Arrange var serviceProvider = new ServiceCollection() - .AddInMemoryRulesDataSource(ServiceLifetime.Singleton) + .AddInMemoryRulesDataSource(ServiceLifetime.Singleton) .BuildServiceProvider(); var rulesEngine = RulesEngineBuilder.CreateRulesEngine() - .WithContentType() - .WithConditionType() .SetInMemoryDataSource(serviceProvider) .Configure(options => { + options.AutoCreateContentTypes = true; options.EnableCompilation = enableCompilation; }) .Build(); + var genericRulesEngine = rulesEngine.MakeGeneric(); // Act 1 - Create rule with "in" operator - var ruleBuilderResult = RuleBuilder.NewRule() + var ruleBuilderResult = Rule.New() .WithName("Discounts Weekend MAY2021 - Tiered discount") .WithDatesInterval(DateTime.Parse("2021-05-29Z"), DateTime.Parse("2021-05-31Z")) .WithContent(DiscountConfigurations.DiscountCampaigns, 15m) @@ -121,7 +120,7 @@ public async Task DiscountsWeekend_Adding20PercentRulePerProductTierAndEvaluatin // Act 2 - Add new rule with "in" operator var rule = ruleBuilderResult.Rule; - var addRuleResult = await rulesEngine.AddRuleAsync(rule, RuleAddPriorityOption.AtTop).ConfigureAwait(false); + var addRuleResult = await genericRulesEngine.AddRuleAsync(rule, RuleAddPriorityOption.AtTop); // Assert 2 - Verify if rule was added addRuleResult.Should().NotBeNull(); @@ -136,7 +135,7 @@ public async Task DiscountsWeekend_Adding20PercentRulePerProductTierAndEvaluatin new Condition(DiscountConditions.ProductRecommendedRetailPrice, 1249.90m) }; - var actual = await rulesEngine.MatchOneAsync(DiscountConfigurations.DiscountCampaigns, matchDateTime, conditions).ConfigureAwait(false); + var actual = await genericRulesEngine.MatchOneAsync(DiscountConfigurations.DiscountCampaigns, matchDateTime, conditions); // Assert 3 actual.Should().NotBeNull(); @@ -150,23 +149,21 @@ public async Task DiscountsWeekend_Adding5PercentRuleWithNotContainsTestConditio { // Arrange var serviceProvider = new ServiceCollection() - .AddInMemoryRulesDataSource(ServiceLifetime.Singleton) + .AddInMemoryRulesDataSource(ServiceLifetime.Singleton) .BuildServiceProvider(); var rulesEngine = RulesEngineBuilder.CreateRulesEngine() - .WithContentType() - .WithConditionType() .SetInMemoryDataSource(serviceProvider) .Configure(options => { + options.AutoCreateContentTypes = true; options.EnableCompilation = enableCompilation; }) .Build(); + var genericRulesEngine = rulesEngine.MakeGeneric(); // Act 1 - Create rule with "not contains" operator - var ruleBuilderResult = - RuleBuilder - .NewRule() + var ruleBuilderResult = Rule.New() .WithName("Not a staff discount") .WithContent(DiscountConfigurations.DiscountCampaigns, 5m) .WithDateBegin(DateTime.Parse("2021-05-29Z")) @@ -182,7 +179,7 @@ public async Task DiscountsWeekend_Adding5PercentRuleWithNotContainsTestConditio // Act 2 - Add new rule with "not contains" operator var rule = ruleBuilderResult.Rule; - var addRuleResult = await rulesEngine.AddRuleAsync(rule, RuleAddPriorityOption.AtTop).ConfigureAwait(false); + var addRuleResult = await genericRulesEngine.AddRuleAsync(rule, RuleAddPriorityOption.AtTop); // Assert 2 - Verify if rule was added addRuleResult.Should().NotBeNull(); @@ -195,7 +192,7 @@ public async Task DiscountsWeekend_Adding5PercentRuleWithNotContainsTestConditio new Condition(DiscountConditions.CustomerEmail, "user12345@somewhere.com") }; - var actual = await rulesEngine.MatchOneAsync(DiscountConfigurations.DiscountCampaigns, matchDateTime, conditions).ConfigureAwait(false); + var actual = await genericRulesEngine.MatchOneAsync(DiscountConfigurations.DiscountCampaigns, matchDateTime, conditions); // Assert 3 actual.Should().NotBeNull(); @@ -209,23 +206,21 @@ public async Task DiscountsWeekend_AddingRuleWithNullTestConditionAndInputWithMa { // Arrange var serviceProvider = new ServiceCollection() - .AddInMemoryRulesDataSource(ServiceLifetime.Singleton) + .AddInMemoryRulesDataSource(ServiceLifetime.Singleton) .BuildServiceProvider(); var rulesEngine = RulesEngineBuilder.CreateRulesEngine() - .WithContentType() - .WithConditionType() .SetInMemoryDataSource(serviceProvider) .Configure(options => { + options.AutoCreateContentTypes = true; options.EnableCompilation = enableCompilation; }) .Build(); + var genericRulesEngine = rulesEngine.MakeGeneric(); // Act 1 - Create rule with "equal" operator - var ruleBuilderResult = - RuleBuilder - .NewRule() + var ruleBuilderResult = Rule.New() .WithName("Blue Product") .WithContent(DiscountConfigurations.DiscountCampaigns, ProductColor.Blue.ToString()) .WithDateBegin(DateTime.Parse("2021-05-29Z")) @@ -241,7 +236,7 @@ public async Task DiscountsWeekend_AddingRuleWithNullTestConditionAndInputWithMa // Act 2 - Add new rule with "in" operator var rule = ruleBuilderResult.Rule; - var addRuleResult = await rulesEngine.AddRuleAsync(rule, RuleAddPriorityOption.AtTop).ConfigureAwait(false); + var addRuleResult = await genericRulesEngine.AddRuleAsync(rule, RuleAddPriorityOption.AtTop); // Assert 2 - Verify if rule was added addRuleResult.Should().NotBeNull(); @@ -254,7 +249,7 @@ public async Task DiscountsWeekend_AddingRuleWithNullTestConditionAndInputWithMa new Condition(DiscountConditions.ProductColor, ProductColor.Blue.ToString()) }; - var actual = await rulesEngine.MatchOneAsync(DiscountConfigurations.DiscountCampaigns, matchDateTime, conditions).ConfigureAwait(false); + var actual = await genericRulesEngine.MatchOneAsync(DiscountConfigurations.DiscountCampaigns, matchDateTime, conditions); // Assert 3 actual.Should().NotBeNull(); @@ -268,23 +263,21 @@ public async Task DiscountsWeekend_AddingRuleWithNullTestConditionAndInputWithou { // Arrange var serviceProvider = new ServiceCollection() - .AddInMemoryRulesDataSource(ServiceLifetime.Singleton) + .AddInMemoryRulesDataSource(ServiceLifetime.Singleton) .BuildServiceProvider(); var rulesEngine = RulesEngineBuilder.CreateRulesEngine() - .WithContentType() - .WithConditionType() .SetInMemoryDataSource(serviceProvider) .Configure(options => { + options.AutoCreateContentTypes = true; options.EnableCompilation = enableCompilation; }) .Build(); + var genericRulesEngine = rulesEngine.MakeGeneric(); // Act 1 - Create rule with "equal" operator - var ruleBuilderResult = - RuleBuilder - .NewRule() + var ruleBuilderResult = Rule.New() .WithName("Blue Product") .WithContent(DiscountConfigurations.DiscountCampaigns, ProductColor.Blue.ToString()) .WithDateBegin(DateTime.Parse("2021-05-29Z")) @@ -300,7 +293,7 @@ public async Task DiscountsWeekend_AddingRuleWithNullTestConditionAndInputWithou // Act 2 - Add new rule with "in" operator var rule = ruleBuilderResult.Rule; - var addRuleResult = await rulesEngine.AddRuleAsync(rule, RuleAddPriorityOption.AtTop).ConfigureAwait(false); + var addRuleResult = await genericRulesEngine.AddRuleAsync(rule, RuleAddPriorityOption.AtTop); // Assert 2 - Verify if rule was added addRuleResult.Should().NotBeNull(); @@ -310,7 +303,7 @@ public async Task DiscountsWeekend_AddingRuleWithNullTestConditionAndInputWithou var matchDateTime = DateTime.Parse("2021-05-29T12:34:52Z"); var conditions = new List>(); - var actual = await rulesEngine.MatchOneAsync(DiscountConfigurations.DiscountCampaigns, matchDateTime, conditions).ConfigureAwait(false); + var actual = await genericRulesEngine.MatchOneAsync(DiscountConfigurations.DiscountCampaigns, matchDateTime, conditions); // Assert 3 actual.Should().BeNull(); @@ -323,23 +316,21 @@ public async Task DiscountsWeekend_AddingRuleWithNullTestConditionAndInputWithou { // Arrange var serviceProvider = new ServiceCollection() - .AddInMemoryRulesDataSource(ServiceLifetime.Singleton) + .AddInMemoryRulesDataSource(ServiceLifetime.Singleton) .BuildServiceProvider(); var rulesEngine = RulesEngineBuilder.CreateRulesEngine() - .WithContentType() - .WithConditionType() .SetInMemoryDataSource(serviceProvider) .Configure(options => { + options.AutoCreateContentTypes = true; options.EnableCompilation = enableCompilation; }) .Build(); + var genericRulesEngine = rulesEngine.MakeGeneric(); // Act 1 - Create rule with "equal" operator - var ruleBuilderResult = - RuleBuilder - .NewRule() + var ruleBuilderResult = Rule.New() .WithName("Blue Product") .WithContent(DiscountConfigurations.DiscountCampaigns, ProductColor.Blue.ToString()) .WithDateBegin(DateTime.Parse("2021-05-29Z")) @@ -355,7 +346,7 @@ public async Task DiscountsWeekend_AddingRuleWithNullTestConditionAndInputWithou // Act 2 - Add new rule with "in" operator var rule = ruleBuilderResult.Rule; - var addRuleResult = await rulesEngine.AddRuleAsync(rule, RuleAddPriorityOption.AtTop).ConfigureAwait(false); + var addRuleResult = await genericRulesEngine.AddRuleAsync(rule, RuleAddPriorityOption.AtTop); // Assert 2 - Verify if rule was added addRuleResult.Should().NotBeNull(); @@ -368,7 +359,7 @@ public async Task DiscountsWeekend_AddingRuleWithNullTestConditionAndInputWithou new Condition(DiscountConditions.ProductColor, ProductColor.White.ToString()) }; - var actual = await rulesEngine.MatchOneAsync(DiscountConfigurations.DiscountCampaigns, matchDateTime, conditions).ConfigureAwait(false); + var actual = await genericRulesEngine.MatchOneAsync(DiscountConfigurations.DiscountCampaigns, matchDateTime, conditions); // Assert 3 actual.Should().BeNull(); diff --git a/tests/Rules.Framework.IntegrationTests/Scenarios/Scenario5/BestServerTests.cs b/tests/Rules.Framework.IntegrationTests/Scenarios/Scenario5/BestServerTests.cs index 00c6f389..69df85e2 100644 --- a/tests/Rules.Framework.IntegrationTests/Scenarios/Scenario5/BestServerTests.cs +++ b/tests/Rules.Framework.IntegrationTests/Scenarios/Scenario5/BestServerTests.cs @@ -5,7 +5,7 @@ namespace Rules.Framework.IntegrationTests.Scenarios.Scenario5 using System.Threading.Tasks; using FluentAssertions; using Microsoft.Extensions.DependencyInjection; - using Rules.Framework.Core; + using Rules.Framework; using Rules.Framework.IntegrationTests.Common.Scenarios.Scenario5; using Xunit; @@ -16,17 +16,18 @@ public async Task BestServer_DeactivatingBestServerTop5_ReturnsBestServerDefault { // Arrange var serviceProvider = new ServiceCollection() - .AddInMemoryRulesDataSource(ServiceLifetime.Singleton) + .AddInMemoryRulesDataSource(ServiceLifetime.Singleton) .BuildServiceProvider(); var rulesEngine = RulesEngineBuilder.CreateRulesEngine() - .WithContentType() - .WithConditionType() .SetInMemoryDataSource(serviceProvider) .Build(); + var genericRulesEngine = rulesEngine.MakeGeneric(); + + await genericRulesEngine.CreateContentTypeAsync(BestServerConfigurations.BestServerEvaluation); // Act 1 - Create rule with "in" operator - var ruleBuilderResult = RuleBuilder.NewRule() + var ruleBuilderResult = Rule.New() .WithName("Best Server Top5") .WithDatesInterval(DateTime.Parse("2021-05-29T11:00:00Z"), DateTime.Parse("2021-05-31Z")) .WithContent(BestServerConfigurations.BestServerEvaluation, "Top5") @@ -49,15 +50,14 @@ public async Task BestServer_DeactivatingBestServerTop5_ReturnsBestServerDefault // Act 2 - Add new rule with "in" operator var rule = ruleBuilderResult.Rule; - var addRuleResult = await rulesEngine.AddRuleAsync(rule, RuleAddPriorityOption.AtTop).ConfigureAwait(false); + var addRuleResult = await genericRulesEngine.AddRuleAsync(rule, RuleAddPriorityOption.AtTop); // Assert 2 - Verify if rule was added addRuleResult.Should().NotBeNull(); addRuleResult.IsSuccess.Should().BeTrue(); // Act 3 - Create rule default - var ruleBuilderResultDefault = RuleBuilder - .NewRule() + var ruleBuilderResultDefault = Rule.New() .WithName("Best Server Default") .WithDatesInterval(DateTime.Parse("2021-05-29Z"), DateTime.Parse("2021-05-31Z")) .WithContent(BestServerConfigurations.BestServerEvaluation, "Default") @@ -70,7 +70,7 @@ public async Task BestServer_DeactivatingBestServerTop5_ReturnsBestServerDefault $"errors have occurred while creating rule: \n[\n- {errors}\n]"); // Act 4 - Add new default rule - addRuleResult = await rulesEngine.AddRuleAsync(ruleBuilderResultDefault.Rule, RuleAddPriorityOption.AtBottom).ConfigureAwait(false); + addRuleResult = await genericRulesEngine.AddRuleAsync(ruleBuilderResultDefault.Rule, RuleAddPriorityOption.AtBottom); // Assert 4 - Verify if rule was added addRuleResult.Should().NotBeNull(); @@ -86,21 +86,21 @@ public async Task BestServer_DeactivatingBestServerTop5_ReturnsBestServerDefault new Condition(BestServerConditions.Brand, "AMD") }; - var actual = await rulesEngine.MatchOneAsync(BestServerConfigurations.BestServerEvaluation, matchDateTime, conditions).ConfigureAwait(false); + var actual = await genericRulesEngine.MatchOneAsync(BestServerConfigurations.BestServerEvaluation, matchDateTime, conditions); // Assert 5 actual.Should().NotBeNull(); actual.Should().BeEquivalentTo(rule); // Act 6 - Update Best Server Top5 rule deactivate - var updateRuleResult = await rulesEngine.DeactivateRuleAsync(rule).ConfigureAwait(false); + var updateRuleResult = await genericRulesEngine.DeactivateRuleAsync(rule); // Assert 6 updateRuleResult.Should().NotBeNull(); updateRuleResult.IsSuccess.Should().BeTrue(); // Act 7 - Evaluate rule should be default now - actual = await rulesEngine.MatchOneAsync(BestServerConfigurations.BestServerEvaluation, matchDateTime, conditions).ConfigureAwait(false); + actual = await genericRulesEngine.MatchOneAsync(BestServerConfigurations.BestServerEvaluation, matchDateTime, conditions); // Assert 7 actual.Should().NotBeNull(); @@ -112,17 +112,18 @@ public async Task BestServer_UpdatingBestServerTop5_ReturnsBestServerDefault() { // Arrange var serviceProvider = new ServiceCollection() - .AddInMemoryRulesDataSource(ServiceLifetime.Singleton) + .AddInMemoryRulesDataSource(ServiceLifetime.Singleton) .BuildServiceProvider(); var rulesEngine = RulesEngineBuilder.CreateRulesEngine() - .WithContentType() - .WithConditionType() .SetInMemoryDataSource(serviceProvider) .Build(); + var genericRulesEngine = rulesEngine.MakeGeneric(); + + await genericRulesEngine.CreateContentTypeAsync(BestServerConfigurations.BestServerEvaluation); // Act 1 - Create rule with "in" operator - var ruleBuilderResult = RuleBuilder.NewRule() + var ruleBuilderResult = Rule.New() .WithName("Best Server Top5") .WithDatesInterval(DateTime.Parse("2021-05-29T11:00:00Z"), DateTime.Parse("2021-05-31Z")) .WithContent(BestServerConfigurations.BestServerEvaluation, "Top5") @@ -145,14 +146,14 @@ public async Task BestServer_UpdatingBestServerTop5_ReturnsBestServerDefault() // Act 2 - Add new rule with "in" operator var rule = ruleBuilderResult.Rule; - var addRuleResult = await rulesEngine.AddRuleAsync(rule, RuleAddPriorityOption.AtTop).ConfigureAwait(false); + var addRuleResult = await genericRulesEngine.AddRuleAsync(rule, RuleAddPriorityOption.AtTop); // Assert 2 - Verify if rule was added addRuleResult.Should().NotBeNull(); addRuleResult.IsSuccess.Should().BeTrue(); // Act 3 - Create rule default - var ruleBuilderResultDefault = RuleBuilder.NewRule() + var ruleBuilderResultDefault = Rule.New() .WithName("Best Server Default") .WithDatesInterval(DateTime.Parse("2021-05-29Z"), DateTime.Parse("2021-05-31Z")) .WithContent(BestServerConfigurations.BestServerEvaluation, "Default") @@ -165,7 +166,7 @@ public async Task BestServer_UpdatingBestServerTop5_ReturnsBestServerDefault() $"errors have occurred while creating rule: \n[\n- {errors}\n]"); // Act 4 - Add new default rule - addRuleResult = await rulesEngine.AddRuleAsync(ruleBuilderResultDefault.Rule, RuleAddPriorityOption.AtBottom).ConfigureAwait(false); + addRuleResult = await genericRulesEngine.AddRuleAsync(ruleBuilderResultDefault.Rule, RuleAddPriorityOption.AtBottom); // Assert 4 - Verify if rule was added addRuleResult.Should().NotBeNull(); @@ -181,7 +182,7 @@ public async Task BestServer_UpdatingBestServerTop5_ReturnsBestServerDefault() new Condition(BestServerConditions.Brand,"AMD") }; - var actual = await rulesEngine.MatchOneAsync(BestServerConfigurations.BestServerEvaluation, matchDateTime, conditions).ConfigureAwait(false); + var actual = await genericRulesEngine.MatchOneAsync(BestServerConfigurations.BestServerEvaluation, matchDateTime, conditions); // Assert 5 actual.Should().NotBeNull(); @@ -189,14 +190,14 @@ public async Task BestServer_UpdatingBestServerTop5_ReturnsBestServerDefault() // Act 6 - Update Best Server Top5 date end rule.DateEnd = DateTime.Parse("2021-05-29T12:10:00Z"); - var updateRuleResult = await rulesEngine.UpdateRuleAsync(rule).ConfigureAwait(false); + var updateRuleResult = await genericRulesEngine.UpdateRuleAsync(rule); // Assert 6 updateRuleResult.Should().NotBeNull(); updateRuleResult.IsSuccess.Should().BeTrue(); // Act 7 - Evaluate rule should be default now - actual = await rulesEngine.MatchOneAsync(BestServerConfigurations.BestServerEvaluation, matchDateTime, conditions).ConfigureAwait(false); + actual = await genericRulesEngine.MatchOneAsync(BestServerConfigurations.BestServerEvaluation, matchDateTime, conditions); // Assert 7 actual.Should().NotBeNull(); diff --git a/tests/Rules.Framework.IntegrationTests/Scenarios/Scenario8/TexasHoldEmPokerSingleCombinationsTests.cs b/tests/Rules.Framework.IntegrationTests/Scenarios/Scenario8/TexasHoldEmPokerSingleCombinationsTests.cs index 8d9c7e29..ddcf01a4 100644 --- a/tests/Rules.Framework.IntegrationTests/Scenarios/Scenario8/TexasHoldEmPokerSingleCombinationsTests.cs +++ b/tests/Rules.Framework.IntegrationTests/Scenarios/Scenario8/TexasHoldEmPokerSingleCombinationsTests.cs @@ -31,21 +31,20 @@ public async Task PokerCombinations_Given_EvaluatesStraightCombination(bool enab }; var rulesEngine = RulesEngineBuilder.CreateRulesEngine() - .WithContentType() - .WithConditionType() .SetInMemoryDataSource() .Configure(options => { options.EnableCompilation = enableCompilation; }) .Build(); + var genericRulesEngine = rulesEngine.MakeGeneric(); var scenarioData = new Scenario8Data(); await ScenarioLoader.LoadScenarioAsync(rulesEngine, scenarioData); // Act - var result = await rulesEngine.MatchOneAsync(ContentTypes.TexasHoldemPokerSingleCombinations, matchDate, conditions); + var result = await genericRulesEngine.MatchOneAsync(ContentTypes.TexasHoldemPokerSingleCombinations, matchDate, conditions); // Assert result.Should().NotBeNull(); diff --git a/tests/Rules.Framework.Providers.InMemory.IntegrationTests/Features/RulesEngine/RulesEngineTestsBase.cs b/tests/Rules.Framework.Providers.InMemory.IntegrationTests/Features/RulesEngine/RulesEngineTestsBase.cs index 642a55fd..fa743073 100644 --- a/tests/Rules.Framework.Providers.InMemory.IntegrationTests/Features/RulesEngine/RulesEngineTestsBase.cs +++ b/tests/Rules.Framework.Providers.InMemory.IntegrationTests/Features/RulesEngine/RulesEngineTestsBase.cs @@ -4,7 +4,7 @@ namespace Rules.Framework.Providers.InMemory.IntegrationTests.Features.RulesEngi using System.Collections.Generic; using System.Globalization; using System.Threading.Tasks; - using Rules.Framework.Core; + using Rules.Framework.Generic; using Rules.Framework.IntegrationTests.Common.Features; using Rules.Framework.Tests.Stubs; @@ -16,10 +16,8 @@ protected RulesEngineTestsBase(ContentType testContentType) { this.TestContentType = testContentType; - this.CompiledRulesEngine = RulesEngineBuilder + var compiledRulesEngine = RulesEngineBuilder .CreateRulesEngine() - .WithContentType() - .WithConditionType() .SetInMemoryDataSource() .Configure(c => { @@ -27,21 +25,23 @@ protected RulesEngineTestsBase(ContentType testContentType) c.PriorityCriteria = PriorityCriterias.TopmostRuleWins; }) .Build(); + this.CompiledRulesEngine = compiledRulesEngine.MakeGeneric(); + this.CompiledRulesEngine.CreateContentTypeAsync(testContentType).GetAwaiter().GetResult(); - this.InterpretedRulesEngine = RulesEngineBuilder + var interpretedRulesEngine = RulesEngineBuilder .CreateRulesEngine() - .WithContentType() - .WithConditionType() .SetInMemoryDataSource() .Configure(c => c.PriorityCriteria = PriorityCriterias.TopmostRuleWins) .Build(); + this.InterpretedRulesEngine = interpretedRulesEngine.MakeGeneric(); + this.InterpretedRulesEngine.CreateContentTypeAsync(testContentType).GetAwaiter().GetResult(); } - protected RulesEngine CompiledRulesEngine { get; } + protected IRulesEngine CompiledRulesEngine { get; } - protected RulesEngine InterpretedRulesEngine { get; } + protected IRulesEngine InterpretedRulesEngine { get; } - protected async Task ActivateRuleAsync(Rule rule, bool compiled) + protected async Task ActivateRuleAsync(Rule rule, bool compiled) { if (compiled) { @@ -67,7 +67,7 @@ protected void AddRules(IEnumerable ruleSpecifications) } } - protected async Task DeactivateRuleAsync(Rule rule, bool compiled) + protected async Task DeactivateRuleAsync(Rule rule, bool compiled) { if (compiled) { @@ -94,7 +94,7 @@ protected async Task> MatchOneAsync( } } - protected async Task UpdateRuleAsync(Rule rule, bool compiled) + protected async Task UpdateRuleAsync(Rule rule, bool compiled) { if (compiled) { diff --git a/tests/Rules.Framework.Providers.InMemory.IntegrationTests/Features/RulesEngine/RulesMatching/OperatorContainsManyToOneTests.cs b/tests/Rules.Framework.Providers.InMemory.IntegrationTests/Features/RulesEngine/RulesMatching/OperatorContainsManyToOneTests.cs index bf846d19..fd0d97da 100644 --- a/tests/Rules.Framework.Providers.InMemory.IntegrationTests/Features/RulesEngine/RulesMatching/OperatorContainsManyToOneTests.cs +++ b/tests/Rules.Framework.Providers.InMemory.IntegrationTests/Features/RulesEngine/RulesMatching/OperatorContainsManyToOneTests.cs @@ -3,7 +3,8 @@ namespace Rules.Framework.Providers.InMemory.IntegrationTests.Features.RulesEngi using System.Collections.Generic; using System.Threading.Tasks; using FluentAssertions; - using Rules.Framework.Core; + using Rules.Framework; + using Rules.Framework.Generic; using Rules.Framework.IntegrationTests.Common.Features; using Rules.Framework.Tests.Stubs; using Xunit; @@ -17,7 +18,7 @@ public class OperatorContainsManyToOneTests : RulesEngineTestsBase public OperatorContainsManyToOneTests() : base(testContentType) { - this.expectedMatchRule = RuleBuilder.NewRule() + this.expectedMatchRule = Rule.New() .WithName("Expected rule") .WithDateBegin(UtcDate("2020-01-01Z")) .WithContent(testContentType, "Just as expected!") @@ -25,7 +26,7 @@ public OperatorContainsManyToOneTests() .Build() .Rule; - this.otherRule = RuleBuilder.NewRule() + this.otherRule = Rule.New() .WithName("Other rule") .WithDateBegin(UtcDate("2020-01-01Z")) .WithContent(testContentType, "Oops! Not expected to be matched.") diff --git a/tests/Rules.Framework.Providers.InMemory.IntegrationTests/Features/RulesEngine/RulesMatching/RulesDeactivateAndActivateTests.cs b/tests/Rules.Framework.Providers.InMemory.IntegrationTests/Features/RulesEngine/RulesMatching/RulesDeactivateAndActivateTests.cs index 5771bd7b..92e38137 100644 --- a/tests/Rules.Framework.Providers.InMemory.IntegrationTests/Features/RulesEngine/RulesMatching/RulesDeactivateAndActivateTests.cs +++ b/tests/Rules.Framework.Providers.InMemory.IntegrationTests/Features/RulesEngine/RulesMatching/RulesDeactivateAndActivateTests.cs @@ -3,7 +3,7 @@ namespace Rules.Framework.Providers.InMemory.IntegrationTests.Features.RulesEngi using System; using System.Collections.Generic; using System.Threading.Tasks; - using Rules.Framework.Core; + using Rules.Framework.Generic; using Rules.Framework.IntegrationTests.Common.Features; using Rules.Framework.Providers.InMemory.IntegrationTests.Features.RulesEngine; using Rules.Framework.Tests.Stubs; @@ -23,16 +23,13 @@ public class RulesDeactivateAndActivateTests : RulesEngineTestsBase public RulesDeactivateAndActivateTests() : base(TestContentType) { - rule1 = RuleBuilder - .NewRule() + rule1 = Rule.New() .WithName(rule1Name) .WithContent(TestContentType, rule1Value) .WithDatesInterval(ruleStartDate, ruleEndDate) .Build().Rule; - rule2 = - RuleBuilder - .NewRule() + rule2 = Rule.New() .WithName(rule2Name) .WithContent(TestContentType, rule2Value) .WithDatesInterval(ruleStartDate, ruleEndDate) diff --git a/tests/Rules.Framework.Providers.InMemory.IntegrationTests/Features/RulesEngine/RulesMatching/RulesInSequenceTests.cs b/tests/Rules.Framework.Providers.InMemory.IntegrationTests/Features/RulesEngine/RulesMatching/RulesInSequenceTests.cs index 7b411fb3..fa3961a9 100644 --- a/tests/Rules.Framework.Providers.InMemory.IntegrationTests/Features/RulesEngine/RulesMatching/RulesInSequenceTests.cs +++ b/tests/Rules.Framework.Providers.InMemory.IntegrationTests/Features/RulesEngine/RulesMatching/RulesInSequenceTests.cs @@ -72,7 +72,7 @@ public async Task RulesEngine_MatchOneAsync_WithRulesInSequence_ReturnsCorrectRu // Assert Assert.Equal(expectedName, actualMatch.Name); - Assert.Equal(TestContentType, actualMatch.ContentContainer.ContentType); + Assert.Equal(TestContentType, actualMatch.ContentType); Assert.Equal(expectedValue, actualMatch.ContentContainer.GetContentAs()); } @@ -80,9 +80,7 @@ private IEnumerable CreateTestRules() { var ruleSpecs = new List(); - var rule1 = - RuleBuilder - .NewRule() + var rule1 = Rule.New() .WithName(rule1Name) .WithContent(TestContentType, rule1Value) .WithDatesInterval(rule1StartDate, ruleChangeDate) @@ -90,9 +88,7 @@ private IEnumerable CreateTestRules() ruleSpecs.Add(new RuleSpecification(rule1.Rule, RuleAddPriorityOption.ByPriorityNumber(1))); - var rule2 = - RuleBuilder - .NewRule() + var rule2 = Rule.New() .WithName(rule2Name) .WithContent(TestContentType, rule2Value) .WithDatesInterval(ruleChangeDate, rule2EndDate) diff --git a/tests/Rules.Framework.Providers.InMemory.IntegrationTests/Features/RulesEngine/RulesMatching/RulesUpdateDateEndTests.cs b/tests/Rules.Framework.Providers.InMemory.IntegrationTests/Features/RulesEngine/RulesMatching/RulesUpdateDateEndTests.cs index a265a8aa..f4030b83 100644 --- a/tests/Rules.Framework.Providers.InMemory.IntegrationTests/Features/RulesEngine/RulesMatching/RulesUpdateDateEndTests.cs +++ b/tests/Rules.Framework.Providers.InMemory.IntegrationTests/Features/RulesEngine/RulesMatching/RulesUpdateDateEndTests.cs @@ -3,7 +3,7 @@ namespace Rules.Framework.Providers.InMemory.IntegrationTests.Features.RulesEngi using System; using System.Collections.Generic; using System.Threading.Tasks; - using Rules.Framework.Core; + using Rules.Framework.Generic; using Rules.Framework.IntegrationTests.Common.Features; using Rules.Framework.Providers.InMemory.IntegrationTests.Features.RulesEngine; using Rules.Framework.Tests.Stubs; @@ -23,16 +23,13 @@ public class RulesUpdateDateEndTests : RulesEngineTestsBase public RulesUpdateDateEndTests() : base(TestContentType) { - rule1 = RuleBuilder - .NewRule() + rule1 = Rule.New() .WithName(rule1Name) .WithContent(TestContentType, rule1Value) .WithDatesInterval(ruleStartDate, ruleEndDate) .Build().Rule; - rule2 = - RuleBuilder - .NewRule() + rule2 = Rule.New() .WithName(rule2Name) .WithContent(TestContentType, rule2Value) .WithDatesInterval(ruleStartDate, ruleEndDate) diff --git a/tests/Rules.Framework.Providers.InMemory.IntegrationTests/Scenarios/BaseScenarioTests.cs b/tests/Rules.Framework.Providers.InMemory.IntegrationTests/Scenarios/BaseScenarioTests.cs index 2a741765..a3491394 100644 --- a/tests/Rules.Framework.Providers.InMemory.IntegrationTests/Scenarios/BaseScenarioTests.cs +++ b/tests/Rules.Framework.Providers.InMemory.IntegrationTests/Scenarios/BaseScenarioTests.cs @@ -6,6 +6,7 @@ namespace Rules.Framework.Providers.InMemory.IntegrationTests.Scenarios using System.IO; using System.Linq; using Newtonsoft.Json; + using Rules.Framework; using Rules.Framework.Core; using Rules.Framework.Providers.InMemory.DataModel; @@ -15,7 +16,7 @@ protected BaseScenarioTests() { } - internal ConditionNodeDataModel CreateConditionNodeDataModel(dynamic conditionNode) + internal ConditionNodeDataModel CreateConditionNodeDataModel(dynamic conditionNode) { var logicalOperator = this.Parse((string)conditionNode.LogicalOperator); @@ -34,9 +35,9 @@ internal ConditionNodeDataModel CreateConditionNodeDataModel (IEnumerable)conditionNode.Operand, _ => null, }; - return new ValueConditionNodeDataModel + return new ValueConditionNodeDataModel { - ConditionType = this.Parse((string)conditionNode.ConditionType), + ConditionType = conditionNode.ConditionType, DataType = dataType, LogicalOperator = logicalOperator, Operator = this.Parse((string)conditionNode.Operator), @@ -48,14 +49,14 @@ internal ConditionNodeDataModel CreateConditionNodeDataModel; - var conditionNodeDataModels = new ConditionNodeDataModel[childConditionNodes.Count()]; + var conditionNodeDataModels = new ConditionNodeDataModel[childConditionNodes.Count()]; var i = 0; - foreach (dynamic child in childConditionNodes) + foreach (var child in childConditionNodes) { - conditionNodeDataModels[i++] = this.CreateConditionNodeDataModel(child); + conditionNodeDataModels[i++] = this.CreateConditionNodeDataModel(child); } - return new ComposedConditionNodeDataModel + return new ComposedConditionNodeDataModel { ChildConditionNodes = conditionNodeDataModels, LogicalOperator = logicalOperator, @@ -64,20 +65,20 @@ internal ConditionNodeDataModel CreateConditionNodeDataModel CreateRulesDataSourceTest(IInMemoryRulesStorage inMemoryRulesStorage) + internal IRulesDataSource CreateRulesDataSourceTest(IInMemoryRulesStorage inMemoryRulesStorage) { - var ruleFactory = new RuleFactory(); - return new InMemoryProviderRulesDataSource(inMemoryRulesStorage, ruleFactory); + var ruleFactory = new RuleFactory(); + return new InMemoryProviderRulesDataSource(inMemoryRulesStorage, ruleFactory); } - internal void LoadInMemoryStorage( + internal void LoadInMemoryStorage( string dataSourceFilePath, - IInMemoryRulesStorage inMemoryRulesStorage, + IInMemoryRulesStorage inMemoryRulesStorage, Func contentConvertFunc) { var rulesFile = File.OpenRead(dataSourceFilePath); - IEnumerable> rules; + IEnumerable rules; using (var streamReader = new StreamReader(rulesFile ?? throw new InvalidOperationException("Could not load rules file."))) { var json = streamReader.ReadToEnd(); @@ -89,16 +90,16 @@ internal void LoadInMemoryStorage( rules = array.Select(t => { - return new RuleDataModel + return new RuleDataModel { Content = contentConvertFunc.Invoke(t.Content), - ContentType = (TContentType)t.ContentTypeCode, + ContentType = t.ContentTypeCode, DateBegin = t.DateBegin, DateEnd = t.DateEnd, Name = t.Name, Priority = t.Priority, Active = t.Active ?? true, - RootCondition = this.CreateConditionNodeDataModel(t.RootCondition) + RootCondition = this.CreateConditionNodeDataModel(t.RootCondition) }; }).ToList(); } diff --git a/tests/Rules.Framework.Providers.InMemory.IntegrationTests/Scenarios/Scenario2/CarInsuranceAdvisorTests.cs b/tests/Rules.Framework.Providers.InMemory.IntegrationTests/Scenarios/Scenario2/CarInsuranceAdvisorTests.cs index 6bbb99ca..b312d24d 100644 --- a/tests/Rules.Framework.Providers.InMemory.IntegrationTests/Scenarios/Scenario2/CarInsuranceAdvisorTests.cs +++ b/tests/Rules.Framework.Providers.InMemory.IntegrationTests/Scenarios/Scenario2/CarInsuranceAdvisorTests.cs @@ -12,12 +12,12 @@ namespace Rules.Framework.Providers.InMemory.IntegrationTests.Scenarios.Scenario public class CarInsuranceAdvisorTests : BaseScenarioTests { - private readonly IInMemoryRulesStorage inMemoryRulesStorage; + private readonly IInMemoryRulesStorage inMemoryRulesStorage; public CarInsuranceAdvisorTests() { - this.inMemoryRulesStorage = new InMemoryRulesStorage(); - this.LoadInMemoryStorage( + this.inMemoryRulesStorage = new InMemoryRulesStorage(); + this.LoadInMemoryStorage( DataSourceFilePath, this.inMemoryRulesStorage, (c) => this.Parse((string)c)); @@ -43,17 +43,16 @@ public async Task GetCarInsuranceAdvice_RepairCostsNotWorthIt_ReturnsPayOldCar() var serviceProvider = serviceDescriptors.BuildServiceProvider(); var rulesEngine = RulesEngineBuilder.CreateRulesEngine() - .WithContentType() - .WithConditionType() .SetInMemoryDataSource(serviceProvider) .Configure(opt => { opt.PriorityCriteria = PriorityCriterias.BottommostRuleWins; }) .Build(); + var genericRulesEngine = rulesEngine.MakeGeneric(); // Act - var actual = await rulesEngine.MatchOneAsync(expectedContent, expectedMatchDate, expectedConditions); + var actual = await genericRulesEngine.MatchOneAsync(expectedContent, expectedMatchDate, expectedConditions); // Assert actual.Should().NotBeNull(); @@ -79,17 +78,16 @@ public async Task GetCarInsuranceAdvice_RepairCostsNotWorthIt_ReturnsRefusePayme var serviceProvider = serviceDescriptors.BuildServiceProvider(); var rulesEngine = RulesEngineBuilder.CreateRulesEngine() - .WithContentType() - .WithConditionType() .SetInMemoryDataSource(serviceProvider) .Configure(opt => { opt.PriorityCriteria = PriorityCriterias.BottommostRuleWins; }) .Build(); + var genericRulesEngine = rulesEngine.MakeGeneric(); // Act - var actual = await rulesEngine.MatchOneAsync(expectedContent, expectedMatchDate, expectedConditions); + var actual = await genericRulesEngine.MatchOneAsync(expectedContent, expectedMatchDate, expectedConditions); // Assert actual.Should().NotBeNull(); @@ -114,24 +112,23 @@ public async Task GetCarInsuranceAdvice_UpdatesRuleAndAddsNewOneAndEvaluates_Ret var serviceProvider = serviceDescriptors.BuildServiceProvider(); var rulesEngine = RulesEngineBuilder.CreateRulesEngine() - .WithContentType() - .WithConditionType() .SetInMemoryDataSource(serviceProvider) .Configure(opt => { opt.PriorityCriteria = PriorityCriterias.BottommostRuleWins; }) .Build(); + var genericRulesEngine = rulesEngine.MakeGeneric(); - var rulesDataSource = CreateRulesDataSourceTest(this.inMemoryRulesStorage); + var rulesDataSource = CreateRulesDataSourceTest(this.inMemoryRulesStorage); - var ruleBuilderResult = RuleBuilder.NewRule() + var ruleBuilderResult = Rule.New() .WithName("Car Insurance Advise on self damage coverage") .WithDateBegin(DateTime.Parse("2018-01-01")) .WithContent(ContentTypes.CarInsuranceAdvice, CarInsuranceAdvices.Pay) .Build(); - var existentRules1 = await rulesDataSource.GetRulesByAsync(new RulesFilterArgs + var existentRules1 = await rulesDataSource.GetRulesByAsync(new RulesFilterArgs { Name = "Car Insurance Advise on repair costs lower than franchise boundary" }); @@ -143,9 +140,9 @@ public async Task GetCarInsuranceAdvice_UpdatesRuleAndAddsNewOneAndEvaluates_Ret // Act 1 var updateOperationResult1 = await rulesEngine.UpdateRuleAsync(ruleToUpdate1); - var eval1 = await rulesEngine.MatchOneAsync(expectedContent, expectedMatchDate, expectedConditions); + var eval1 = await genericRulesEngine.MatchOneAsync(expectedContent, expectedMatchDate, expectedConditions); - var rules1 = await rulesDataSource.GetRulesByAsync(new RulesFilterArgs()); + var rules1 = await rulesDataSource.GetRulesByAsync(new RulesFilterArgs()); // Assert 1 updateOperationResult1.Should().NotBeNull(); @@ -166,22 +163,22 @@ public async Task GetCarInsuranceAdvice_UpdatesRuleAndAddsNewOneAndEvaluates_Ret rule13.Priority.Should().Be(3); // Act 2 - var addOperationResult = await rulesEngine.AddRuleAsync(ruleToAdd, new RuleAddPriorityOption + var addOperationResult = await genericRulesEngine.AddRuleAsync(ruleToAdd, new RuleAddPriorityOption { PriorityOption = PriorityOptions.AtRuleName, AtRuleNameOptionValue = "Car Insurance Advise on repair costs lower than franchise boundary" }); - var eval2 = await rulesEngine.MatchOneAsync(expectedContent, expectedMatchDate, expectedConditions); + var eval2 = await genericRulesEngine.MatchOneAsync(expectedContent, expectedMatchDate, expectedConditions); - var rules2 = await rulesDataSource.GetRulesByAsync(new RulesFilterArgs()); + var rules2 = await rulesDataSource.GetRulesByAsync(new RulesFilterArgs()); // Assert 2 addOperationResult.Should().NotBeNull(); addOperationResult.IsSuccess.Should().BeTrue(); eval2.Priority.Should().Be(3); - CarInsuranceAdvices content2 = eval2.ContentContainer.GetContentAs(); + var content2 = eval2.ContentContainer.GetContentAs(); content2.Should().Be(CarInsuranceAdvices.RefusePaymentPerFranchise); var rule21 = rules2.FirstOrDefault(r => r.Name == "Car Insurance Advise on repair costs lesser than 80% of commercial value"); @@ -198,7 +195,7 @@ public async Task GetCarInsuranceAdvice_UpdatesRuleAndAddsNewOneAndEvaluates_Ret rule24.Priority.Should().Be(4); // Act 3 - var existentRules2 = await rulesDataSource.GetRulesByAsync(new RulesFilterArgs + var existentRules2 = await rulesDataSource.GetRulesByAsync(new RulesFilterArgs { Name = "Car Insurance Advise on repair costs lower than franchise boundary" }); @@ -207,9 +204,9 @@ public async Task GetCarInsuranceAdvice_UpdatesRuleAndAddsNewOneAndEvaluates_Ret var updateOperationResult2 = await rulesEngine.UpdateRuleAsync(ruleToUpdate2); - var eval3 = await rulesEngine.MatchOneAsync(expectedContent, expectedMatchDate, expectedConditions); + var eval3 = await genericRulesEngine.MatchOneAsync(expectedContent, expectedMatchDate, expectedConditions); - var rules3 = await rulesDataSource.GetRulesByAsync(new RulesFilterArgs()); + var rules3 = await rulesDataSource.GetRulesByAsync(new RulesFilterArgs()); // Assert 3 updateOperationResult2.Should().NotBeNull(); diff --git a/tests/Rules.Framework.Providers.InMemory.IntegrationTests/Scenarios/Scenario3/BuildingSecuritySystemControlTests.cs b/tests/Rules.Framework.Providers.InMemory.IntegrationTests/Scenarios/Scenario3/BuildingSecuritySystemControlTests.cs index 2f474209..e9014fef 100644 --- a/tests/Rules.Framework.Providers.InMemory.IntegrationTests/Scenarios/Scenario3/BuildingSecuritySystemControlTests.cs +++ b/tests/Rules.Framework.Providers.InMemory.IntegrationTests/Scenarios/Scenario3/BuildingSecuritySystemControlTests.cs @@ -7,20 +7,19 @@ namespace Rules.Framework.Providers.InMemory.IntegrationTests.Scenarios.Scenario using FluentAssertions; using Microsoft.Extensions.DependencyInjection; using Newtonsoft.Json; - using Rules.Framework.Core; using Rules.Framework.IntegrationTests.Common.Scenarios.Scenario3; using Rules.Framework.Providers.InMemory; using Xunit; public class BuildingSecuritySystemControlTests : BaseScenarioTests { - private readonly IInMemoryRulesStorage inMemoryRulesStorage; + private readonly IInMemoryRulesStorage inMemoryRulesStorage; public BuildingSecuritySystemControlTests() { - this.inMemoryRulesStorage = new InMemoryRulesStorage(); + this.inMemoryRulesStorage = new InMemoryRulesStorage(); - this.LoadInMemoryStorage( + this.LoadInMemoryStorage( DataSourceFilePath, this.inMemoryRulesStorage, (c) => JsonConvert.DeserializeObject((string)c)); @@ -36,8 +35,8 @@ public async Task BuildingSecuritySystem_FireScenario_ReturnsActionsToTrigger(bo // Assert const SecuritySystemActionables securitySystemActionable = SecuritySystemActionables.FireSystem; - DateTime expectedMatchDate = new DateTime(2018, 06, 01); - Condition[] expectedConditions = new Condition[] + var expectedMatchDate = new DateTime(2018, 06, 01); + var expectedConditions = new[] { new Condition(SecuritySystemConditions.TemperatureCelsius, 100.0m), new Condition(SecuritySystemConditions.SmokeRate, 55.0m), @@ -48,18 +47,17 @@ public async Task BuildingSecuritySystem_FireScenario_ReturnsActionsToTrigger(bo serviceDescriptors.AddSingleton(this.inMemoryRulesStorage); IServiceProvider serviceProvider = serviceDescriptors.BuildServiceProvider(); - RulesEngine rulesEngine = RulesEngineBuilder.CreateRulesEngine() - .WithContentType() - .WithConditionType() + var rulesEngine = RulesEngineBuilder.CreateRulesEngine() .SetInMemoryDataSource(serviceProvider) .Configure(options => { options.EnableCompilation = enableCompilation; }) .Build(); + var genericRulesEngine = rulesEngine.MakeGeneric(); // Act - IEnumerable> actual = await rulesEngine.MatchManyAsync(securitySystemActionable, expectedMatchDate, expectedConditions); + var actual = await genericRulesEngine.MatchManyAsync(securitySystemActionable, expectedMatchDate, expectedConditions); // Assert actual.Should().NotBeNull(); @@ -80,8 +78,8 @@ public async Task BuildingSecuritySystem_PowerFailureScenario_ReturnsActionsToTr // Assert const SecuritySystemActionables securitySystemActionable = SecuritySystemActionables.PowerSystem; - DateTime expectedMatchDate = new DateTime(2018, 06, 01); - Condition[] expectedConditions = new Condition[] + var expectedMatchDate = new DateTime(2018, 06, 01); + var expectedConditions = new[] { new Condition(SecuritySystemConditions.TemperatureCelsius, 100.0m), new Condition(SecuritySystemConditions.SmokeRate, 55.0m), @@ -92,18 +90,17 @@ public async Task BuildingSecuritySystem_PowerFailureScenario_ReturnsActionsToTr serviceDescriptors.AddSingleton(this.inMemoryRulesStorage); IServiceProvider serviceProvider = serviceDescriptors.BuildServiceProvider(); - RulesEngine rulesEngine = RulesEngineBuilder.CreateRulesEngine() - .WithContentType() - .WithConditionType() + var rulesEngine = RulesEngineBuilder.CreateRulesEngine() .SetInMemoryDataSource(serviceProvider) .Configure(options => { options.EnableCompilation = enableCompilation; }) .Build(); + var genericRulesEngine = rulesEngine.MakeGeneric(); // Act - IEnumerable> actual = await rulesEngine.MatchManyAsync(securitySystemActionable, expectedMatchDate, expectedConditions); + var actual = await genericRulesEngine.MatchManyAsync(securitySystemActionable, expectedMatchDate, expectedConditions); // Assert actual.Should().NotBeNull(); @@ -123,8 +120,8 @@ public async Task BuildingSecuritySystem_PowerShutdownScenario_ReturnsActionsToT // Assert const SecuritySystemActionables securitySystemActionable = SecuritySystemActionables.PowerSystem; - DateTime expectedMatchDate = new DateTime(2018, 06, 01); - Condition[] expectedConditions = new Condition[] + var expectedMatchDate = new DateTime(2018, 06, 01); + var expectedConditions = new[] { new Condition(SecuritySystemConditions.TemperatureCelsius, 100.0m), new Condition(SecuritySystemConditions.SmokeRate, 55.0m), @@ -135,18 +132,17 @@ public async Task BuildingSecuritySystem_PowerShutdownScenario_ReturnsActionsToT serviceDescriptors.AddSingleton(this.inMemoryRulesStorage); IServiceProvider serviceProvider = serviceDescriptors.BuildServiceProvider(); - RulesEngine rulesEngine = RulesEngineBuilder.CreateRulesEngine() - .WithContentType() - .WithConditionType() + var rulesEngine = RulesEngineBuilder.CreateRulesEngine() .SetInMemoryDataSource(serviceProvider) .Configure(options => { options.EnableCompilation = enableCompilation; }) .Build(); + var genericRulesEngine = rulesEngine.MakeGeneric(); // Act - IEnumerable> actual = await rulesEngine.MatchManyAsync(securitySystemActionable, expectedMatchDate, expectedConditions); + var actual = await genericRulesEngine.MatchManyAsync(securitySystemActionable, expectedMatchDate, expectedConditions); // Assert actual.Should().NotBeNull(); diff --git a/tests/Rules.Framework.Providers.InMemory.IntegrationTests/Scenarios/Scenario5/BestServerTests.cs b/tests/Rules.Framework.Providers.InMemory.IntegrationTests/Scenarios/Scenario5/BestServerTests.cs index a8560492..0beeda79 100644 --- a/tests/Rules.Framework.Providers.InMemory.IntegrationTests/Scenarios/Scenario5/BestServerTests.cs +++ b/tests/Rules.Framework.Providers.InMemory.IntegrationTests/Scenarios/Scenario5/BestServerTests.cs @@ -5,9 +5,8 @@ namespace Rules.Framework.Providers.InMemory.IntegrationTests.Scenarios.Scenario using System.Linq; using System.Threading.Tasks; using FluentAssertions; - using Rules.Framework.Core; + using Rules.Framework; using Rules.Framework.IntegrationTests.Common.Scenarios.Scenario5; - using Rules.Framework.Providers.InMemory; using Xunit; public class BestServerTests @@ -54,13 +53,13 @@ public async Task BestServer_InEvaluation(IEnumerable() - .WithConditionType() .SetInMemoryDataSource() .Build(); + var genericRulesEngine = rulesEngine.MakeGeneric(); + await genericRulesEngine.CreateContentTypeAsync(BestServerConfigurations.BestServerEvaluation); // Act 1 - Create rule with "in" operator - var ruleBuilderResult = RuleBuilder.NewRule() + var ruleBuilderResult = Rule.New() .WithName("Best Server Top5") .WithDatesInterval(DateTime.Parse("2021-05-29Z"), DateTime.Parse("2021-05-31Z")) .WithContent(BestServerConfigurations.BestServerEvaluation, "Top5") @@ -75,7 +74,7 @@ public async Task BestServer_InEvaluation(IEnumerable() + var ruleBuilderResultDefault = Rule.New() .WithName("Best Server Default") .WithDatesInterval(DateTime.Parse("2021-05-29Z"), DateTime.Parse("2021-05-31Z")) .WithContent(BestServerConfigurations.BestServerEvaluation, "Default") @@ -83,7 +82,7 @@ public async Task BestServer_InEvaluation(IEnumerable $"{s1}\n- {s2}") : string.Empty; + var errors = ruleBuilderResult.Errors.Any() ? ruleBuilderResult.Errors.Aggregate((s1, s2) => $"{s1}\n- {s2}") : string.Empty; ruleBuilderResult.IsSuccess.Should().BeTrue( $"errors have occurred while creating rule: \n[\n- {errors}\n]"); @@ -94,12 +93,12 @@ public async Task BestServer_InEvaluation(IEnumerable() - .WithConditionType() .SetMongoDbDataSource(this.mongoClient, this.mongoDbProviderSettings) .Configure(c => c.PriorityCriteria = PriorityCriterias.TopmostRuleWins) .Build(); + + this.RulesEngine = rulesEngine.MakeGeneric(); + this.RulesEngine.CreateContentTypeAsync(testContentType).GetAwaiter().GetResult(); } - protected RulesEngine RulesEngine { get; } + protected IRulesEngine RulesEngine { get; } public void Dispose() { @@ -47,7 +48,6 @@ protected void AddRules(IEnumerable ruleSpecifications) this.RulesEngine.AddRuleAsync( ruleSpecification.Rule, ruleSpecification.RuleAddPriorityOption) - .ConfigureAwait(false) .GetAwaiter() .GetResult(); } @@ -58,12 +58,11 @@ protected async Task> MatchOneAsync( Condition[] conditions) => await RulesEngine.MatchOneAsync( TestContentType, matchDate, - conditions) - .ConfigureAwait(false); + conditions); private static MongoClient CreateMongoClient() { - MongoClientSettings settings = MongoClientSettings.FromConnectionString($"mongodb://{SettingsProvider.GetMongoDbHost()}:27017"); + var settings = MongoClientSettings.FromConnectionString($"mongodb://{SettingsProvider.GetMongoDbHost()}:27017"); settings.ClusterConfigurator = (cb) => { cb.Subscribe(e => diff --git a/tests/Rules.Framework.Providers.MongoDb.IntegrationTests/Features/RulesEngine/RulesMatching/RulesDeactivateAndActivateTests.cs b/tests/Rules.Framework.Providers.MongoDb.IntegrationTests/Features/RulesEngine/RulesMatching/RulesDeactivateAndActivateTests.cs index b15f5623..c42b5fb5 100644 --- a/tests/Rules.Framework.Providers.MongoDb.IntegrationTests/Features/RulesEngine/RulesMatching/RulesDeactivateAndActivateTests.cs +++ b/tests/Rules.Framework.Providers.MongoDb.IntegrationTests/Features/RulesEngine/RulesMatching/RulesDeactivateAndActivateTests.cs @@ -3,8 +3,7 @@ namespace Rules.Framework.Providers.MongoDb.IntegrationTests.Features.RulesEngin using System; using System.Collections.Generic; using System.Threading.Tasks; - using Rules.Framework.Builder; - using Rules.Framework.Core; + using Rules.Framework.Generic; using Rules.Framework.IntegrationTests.Common.Features; using Rules.Framework.Tests.Stubs; using Xunit; @@ -23,16 +22,13 @@ public class RulesDeactivateAndActivateTests : RulesEngineTestsBase public RulesDeactivateAndActivateTests() : base(TestContentType) { - rule1 = RuleBuilder - .NewRule() + rule1 = Rule.New() .WithName(rule1Name) .WithContent(TestContentType, rule1Value) .WithDatesInterval(ruleStartDate, ruleEndDate) .Build().Rule; - rule2 = - RuleBuilder - .NewRule() + rule2 = Rule.New() .WithName(rule2Name) .WithContent(TestContentType, rule2Value) .WithDatesInterval(ruleStartDate, ruleEndDate) diff --git a/tests/Rules.Framework.Providers.MongoDb.IntegrationTests/Features/RulesEngine/RulesMatching/RulesInSequenceTests.cs b/tests/Rules.Framework.Providers.MongoDb.IntegrationTests/Features/RulesEngine/RulesMatching/RulesInSequenceTests.cs index ba279a38..41f763f4 100644 --- a/tests/Rules.Framework.Providers.MongoDb.IntegrationTests/Features/RulesEngine/RulesMatching/RulesInSequenceTests.cs +++ b/tests/Rules.Framework.Providers.MongoDb.IntegrationTests/Features/RulesEngine/RulesMatching/RulesInSequenceTests.cs @@ -3,7 +3,6 @@ namespace Rules.Framework.Providers.MongoDb.IntegrationTests.Features.RulesEngin using System; using System.Collections.Generic; using System.Threading.Tasks; - using Rules.Framework.Builder; using Rules.Framework.IntegrationTests.Common.Features; using Rules.Framework.Tests.Stubs; using Xunit; @@ -48,7 +47,7 @@ public async Task RulesEngine_MatchOneAsync_OutsideRulesPeriod_Failure(DateTime var emptyConditions = Array.Empty>(); // Act - var actualMatch = await this.MatchOneAsync(matchDate, emptyConditions).ConfigureAwait(false); + var actualMatch = await this.MatchOneAsync(matchDate, emptyConditions); // Assert Assert.Null(actualMatch); @@ -62,11 +61,11 @@ public async Task RulesEngine_MatchOneAsync_WithRulesInSequence_ReturnsCorrectRu var emptyConditions = Array.Empty>(); // Act - var actualMatch = await this.MatchOneAsync(matchDate, emptyConditions).ConfigureAwait(false); + var actualMatch = await this.MatchOneAsync(matchDate, emptyConditions); // Assert Assert.Equal(expectedName, actualMatch.Name); - Assert.Equal(TestContentType, actualMatch.ContentContainer.ContentType); + Assert.Equal(TestContentType, actualMatch.ContentType); Assert.Equal(expectedValue, actualMatch.ContentContainer.GetContentAs()); } @@ -74,9 +73,7 @@ private IEnumerable CreateTestRules() { var ruleSpecs = new List(); - var rule1 = - RuleBuilder - .NewRule() + var rule1 = Rule.New() .WithName(rule1Name) .WithContent(TestContentType, rule1Value) .WithDatesInterval(rule1StartDate, ruleChangeDate) @@ -84,9 +81,7 @@ private IEnumerable CreateTestRules() ruleSpecs.Add(new RuleSpecification(rule1.Rule, RuleAddPriorityOption.ByPriorityNumber(1))); - var rule2 = - RuleBuilder - .NewRule() + var rule2 = Rule.New() .WithName(rule2Name) .WithContent(TestContentType, rule2Value) .WithDatesInterval(ruleChangeDate, rule2EndDate) diff --git a/tests/Rules.Framework.Providers.MongoDb.IntegrationTests/Features/RulesEngine/RulesMatching/RulesUpdateDateEndTests.cs b/tests/Rules.Framework.Providers.MongoDb.IntegrationTests/Features/RulesEngine/RulesMatching/RulesUpdateDateEndTests.cs index 6487c118..39157bff 100644 --- a/tests/Rules.Framework.Providers.MongoDb.IntegrationTests/Features/RulesEngine/RulesMatching/RulesUpdateDateEndTests.cs +++ b/tests/Rules.Framework.Providers.MongoDb.IntegrationTests/Features/RulesEngine/RulesMatching/RulesUpdateDateEndTests.cs @@ -3,8 +3,7 @@ namespace Rules.Framework.Providers.MongoDb.IntegrationTests.Features.RulesEngin using System; using System.Collections.Generic; using System.Threading.Tasks; - using Rules.Framework.Builder; - using Rules.Framework.Core; + using Rules.Framework.Generic; using Rules.Framework.IntegrationTests.Common.Features; using Rules.Framework.Tests.Stubs; using Xunit; @@ -23,16 +22,13 @@ public class RulesUpdateDateEndTests : RulesEngineTestsBase public RulesUpdateDateEndTests() : base(TestContentType) { - rule1 = RuleBuilder - .NewRule() + rule1 = Rule.New() .WithName(rule1Name) .WithContent(TestContentType, rule1Value) .WithDatesInterval(ruleStartDate, ruleEndDate) .Build().Rule; - rule2 = - RuleBuilder - .NewRule() + rule2 = Rule.New() .WithName(rule2Name) .WithContent(TestContentType, rule2Value) .WithDatesInterval(ruleStartDate, ruleEndDate) @@ -64,7 +60,7 @@ public async Task RulesEngine_UpdateRuleDateEnd_Validations(DateTime dateEnd, bo Assert.Equal(success, updateResult.IsSuccess); if (success) { - var actualMatch = await this.MatchOneAsync(matchDate, emptyConditions).ConfigureAwait(false); + var actualMatch = await this.MatchOneAsync(matchDate, emptyConditions); Assert.NotNull(actualMatch); Assert.Equal(rule2.Name, actualMatch.Name); } @@ -81,4 +77,4 @@ private IEnumerable CreateTestRules() return ruleSpecs; } } -} +} \ No newline at end of file diff --git a/tests/Rules.Framework.Providers.MongoDb.IntegrationTests/Scenarios/Scenario2/CarInsuranceAdvisorTests.cs b/tests/Rules.Framework.Providers.MongoDb.IntegrationTests/Scenarios/Scenario2/CarInsuranceAdvisorTests.cs index 5c7dd99f..2f9cb019 100644 --- a/tests/Rules.Framework.Providers.MongoDb.IntegrationTests/Scenarios/Scenario2/CarInsuranceAdvisorTests.cs +++ b/tests/Rules.Framework.Providers.MongoDb.IntegrationTests/Scenarios/Scenario2/CarInsuranceAdvisorTests.cs @@ -30,20 +30,20 @@ public CarInsuranceAdvisorTests() this.mongoClient = CreateMongoClient(); this.mongoDbProviderSettings = CreateProviderSettings(); - Stream? rulesFile = Assembly.GetExecutingAssembly() + var rulesFile = Assembly.GetExecutingAssembly() .GetManifestResourceStream("Rules.Framework.Providers.MongoDb.IntegrationTests.Scenarios.Scenario2.rules-framework-tests.car-insurance-advisor.json"); IEnumerable rules; - using (StreamReader streamReader = new StreamReader(rulesFile ?? throw new InvalidOperationException("Could not load rules file."))) + using (var streamReader = new StreamReader(rulesFile ?? throw new InvalidOperationException("Could not load rules file."))) { - string json = streamReader.ReadToEnd(); + var json = streamReader.ReadToEnd(); - IEnumerable array = JsonConvert.DeserializeObject>(json, new JsonSerializerSettings + var array = JsonConvert.DeserializeObject>(json, new JsonSerializerSettings { TypeNameHandling = TypeNameHandling.All }); - rules = array.Select(t => + rules = array!.Select(t => { t.Content = t.Content as string; @@ -51,11 +51,25 @@ public CarInsuranceAdvisorTests() }).ToList(); } + var contentTypes = rules + .Select(r => new ContentTypeDataModel + { + Creation = DateTime.UtcNow, + Id = Guid.NewGuid(), + Name = r.ContentType, + }) + .Distinct() + .ToArray(); + var mongoDatabase = this.mongoClient.GetDatabase(this.mongoDbProviderSettings.DatabaseName); - mongoDatabase.DropCollection(this.mongoDbProviderSettings.RulesCollectionName); - var mongoCollection = mongoDatabase.GetCollection(this.mongoDbProviderSettings.RulesCollectionName); - mongoCollection.InsertMany(rules); + mongoDatabase.DropCollection(this.mongoDbProviderSettings.ContentTypesCollectionName); + var contentTypesMongoCollection = mongoDatabase.GetCollection(this.mongoDbProviderSettings.ContentTypesCollectionName); + contentTypesMongoCollection.InsertMany(contentTypes); + + mongoDatabase.DropCollection(this.mongoDbProviderSettings.RulesCollectionName); + var rulesMongoCollection = mongoDatabase.GetCollection(this.mongoDbProviderSettings.RulesCollectionName); + rulesMongoCollection.InsertMany(rules); } public void Dispose() @@ -80,8 +94,6 @@ public async Task GetCarInsuranceAdvice_RepairCostsNotWorthIt_ReturnsRefusePayme }; var rulesEngine = RulesEngineBuilder.CreateRulesEngine() - .WithContentType() - .WithConditionType() .SetMongoDbDataSource(this.mongoClient, this.mongoDbProviderSettings) .Configure(opt => { @@ -89,9 +101,10 @@ public async Task GetCarInsuranceAdvice_RepairCostsNotWorthIt_ReturnsRefusePayme opt.PriorityCriteria = PriorityCriterias.BottommostRuleWins; }) .Build(); + var genericRulesEngine = rulesEngine.MakeGeneric(); // Act - var actual = await rulesEngine.MatchOneAsync(expectedContent, expectedMatchDate, expectedConditions).ConfigureAwait(false); + var actual = await genericRulesEngine.MatchOneAsync(expectedContent, expectedMatchDate, expectedConditions); // Assert actual.Should().NotBeNull(); @@ -114,8 +127,6 @@ public async Task GetCarInsuranceAdvice_UpdatesRuleAndAddsNewOneAndEvaluates_Ret }; var rulesEngine = RulesEngineBuilder.CreateRulesEngine() - .WithContentType() - .WithConditionType() .SetMongoDbDataSource(this.mongoClient, this.mongoDbProviderSettings) .Configure(opt => { @@ -123,29 +134,30 @@ public async Task GetCarInsuranceAdvice_UpdatesRuleAndAddsNewOneAndEvaluates_Ret opt.PriorityCriteria = PriorityCriterias.BottommostRuleWins; }) .Build(); + var genericRulesEngine = rulesEngine.MakeGeneric(); - var rulesDataSource = CreateRulesDataSourceTest(this.mongoClient, this.mongoDbProviderSettings); + var rulesDataSource = CreateRulesDataSourceTest(this.mongoClient, this.mongoDbProviderSettings); - var ruleBuilderResult = RuleBuilder.NewRule() + var ruleBuilderResult = Rule.New() .WithName("Car Insurance Advise on self damage coverage") .WithDateBegin(DateTime.Parse("2018-01-01")) .WithContent(ContentTypes.CarInsuranceAdvice, CarInsuranceAdvices.Pay) .Build(); - var existentRules1 = await rulesDataSource.GetRulesByAsync(new RulesFilterArgs + var existentRules1 = await rulesDataSource.GetRulesByAsync(new RulesFilterArgs { Name = "Car Insurance Advise on repair costs lower than franchise boundary" - }).ConfigureAwait(false); + }); var ruleToAdd = ruleBuilderResult.Rule; var ruleToUpdate1 = existentRules1.First(); ruleToUpdate1.Priority = 2; // Act 1 - var updateOperationResult1 = await rulesEngine.UpdateRuleAsync(ruleToUpdate1).ConfigureAwait(false); + var updateOperationResult1 = await rulesEngine.UpdateRuleAsync(ruleToUpdate1); - var eval1 = await rulesEngine.MatchOneAsync(expectedContent, expectedMatchDate, expectedConditions).ConfigureAwait(false); + var eval1 = await genericRulesEngine.MatchOneAsync(expectedContent, expectedMatchDate, expectedConditions); - var rules1 = await rulesDataSource.GetRulesByAsync(new RulesFilterArgs()).ConfigureAwait(false); + var rules1 = await rulesDataSource.GetRulesByAsync(new RulesFilterArgs()); // Assert 1 updateOperationResult1.Should().NotBeNull(); @@ -172,16 +184,16 @@ public async Task GetCarInsuranceAdvice_UpdatesRuleAndAddsNewOneAndEvaluates_Ret AtRuleNameOptionValue = "Car Insurance Advise on repair costs lower than franchise boundary" }); - var eval2 = await rulesEngine.MatchOneAsync(expectedContent, expectedMatchDate, expectedConditions).ConfigureAwait(false); + var eval2 = await genericRulesEngine.MatchOneAsync(expectedContent, expectedMatchDate, expectedConditions); - var rules2 = await rulesDataSource.GetRulesByAsync(new RulesFilterArgs()).ConfigureAwait(false); + var rules2 = await rulesDataSource.GetRulesByAsync(new RulesFilterArgs()); // Assert 2 addOperationResult.Should().NotBeNull(); addOperationResult.IsSuccess.Should().BeTrue(); eval2.Priority.Should().Be(3); - CarInsuranceAdvices content2 = eval2.ContentContainer.GetContentAs(); + var content2 = eval2.ContentContainer.GetContentAs(); content2.Should().Be(CarInsuranceAdvices.RefusePaymentPerFranchise); var rule21 = rules2.First(r => r.Name == "Car Insurance Advise on repair costs lesser than 80% of commercial value"); @@ -198,18 +210,18 @@ public async Task GetCarInsuranceAdvice_UpdatesRuleAndAddsNewOneAndEvaluates_Ret rule24.Priority.Should().Be(4); // Act 3 - var existentRules2 = await rulesDataSource.GetRulesByAsync(new RulesFilterArgs + var existentRules2 = await rulesDataSource.GetRulesByAsync(new RulesFilterArgs { Name = "Car Insurance Advise on repair costs lower than franchise boundary" - }).ConfigureAwait(false); + }); var ruleToUpdate2 = existentRules2.First(); ruleToUpdate2.Priority = 4; - var updateOperationResult2 = await rulesEngine.UpdateRuleAsync(ruleToUpdate2).ConfigureAwait(false); + var updateOperationResult2 = await rulesEngine.UpdateRuleAsync(ruleToUpdate2); - var eval3 = await rulesEngine.MatchOneAsync(expectedContent, expectedMatchDate, expectedConditions).ConfigureAwait(false); + var eval3 = await genericRulesEngine.MatchOneAsync(expectedContent, expectedMatchDate, expectedConditions); - var rules3 = await rulesDataSource.GetRulesByAsync(new RulesFilterArgs()).ConfigureAwait(false); + var rules3 = await rulesDataSource.GetRulesByAsync(new RulesFilterArgs()); // Assert 3 updateOperationResult2.Should().NotBeNull(); @@ -246,19 +258,19 @@ private static MongoClient CreateMongoClient() return new MongoClient(settings); } - private static IRulesDataSource CreateRulesDataSourceTest( + private static MongoDbProviderRulesDataSource CreateRulesDataSourceTest( IMongoClient mongoClient, MongoDbProviderSettings mongoDbProviderSettings) { - var contentSerializationProvider = new DynamicToStrongTypeContentSerializationProvider(); - var ruleFactory = new RuleFactory(contentSerializationProvider); - return new MongoDbProviderRulesDataSource( + var contentSerializationProvider = new DynamicToStrongTypeContentSerializationProvider(); + var ruleFactory = new RuleFactory(contentSerializationProvider); + return new MongoDbProviderRulesDataSource( mongoClient, mongoDbProviderSettings, ruleFactory); } - private MongoDbProviderSettings CreateProviderSettings() => new MongoDbProviderSettings + private MongoDbProviderSettings CreateProviderSettings() => new() { DatabaseName = "rules-framework-tests", RulesCollectionName = "car-insurance-advisor" diff --git a/tests/Rules.Framework.Providers.MongoDb.IntegrationTests/Scenarios/Scenario3/BuildingSecuritySystemControlTests.cs b/tests/Rules.Framework.Providers.MongoDb.IntegrationTests/Scenarios/Scenario3/BuildingSecuritySystemControlTests.cs index 8c6d6fec..0d93f9bb 100644 --- a/tests/Rules.Framework.Providers.MongoDb.IntegrationTests/Scenarios/Scenario3/BuildingSecuritySystemControlTests.cs +++ b/tests/Rules.Framework.Providers.MongoDb.IntegrationTests/Scenarios/Scenario3/BuildingSecuritySystemControlTests.cs @@ -10,6 +10,7 @@ namespace Rules.Framework.Providers.MongoDb.IntegrationTests.Scenarios.Scenario3 using FluentAssertions; using MongoDB.Driver; using Newtonsoft.Json; + using Rules.Framework; using Rules.Framework.IntegrationTests.Common.Scenarios.Scenario3; using Rules.Framework.Providers.MongoDb; using Rules.Framework.Providers.MongoDb.DataModel; @@ -17,7 +18,7 @@ namespace Rules.Framework.Providers.MongoDb.IntegrationTests.Scenarios.Scenario3 public sealed class BuildingSecuritySystemControlTests : IDisposable { - private readonly IMongoClient mongoClient; + private readonly MongoClient mongoClient; private readonly MongoDbProviderSettings mongoDbProviderSettings; public BuildingSecuritySystemControlTests() @@ -25,13 +26,13 @@ public BuildingSecuritySystemControlTests() this.mongoClient = CreateMongoClient(); this.mongoDbProviderSettings = CreateProviderSettings(); - Stream? rulesFile = Assembly.GetExecutingAssembly() + var rulesFile = Assembly.GetExecutingAssembly() .GetManifestResourceStream("Rules.Framework.Providers.MongoDb.IntegrationTests.Scenarios.Scenario3.rules-framework-tests.security-system-actionables.json"); IEnumerable rules; using (var streamReader = new StreamReader(rulesFile ?? throw new InvalidOperationException("Could not load rules file."))) { - string json = streamReader.ReadToEnd(); + var json = streamReader.ReadToEnd(); var array = JsonConvert.DeserializeObject>(json, new JsonSerializerSettings { @@ -50,11 +51,25 @@ public BuildingSecuritySystemControlTests() }).ToList(); } + var contentTypes = rules + .Select(r => new ContentTypeDataModel + { + Creation = DateTime.UtcNow, + Id = Guid.NewGuid(), + Name = r.ContentType, + }) + .Distinct() + .ToArray(); + var mongoDatabase = this.mongoClient.GetDatabase(this.mongoDbProviderSettings.DatabaseName); - mongoDatabase.DropCollection(this.mongoDbProviderSettings.RulesCollectionName); - var mongoCollection = mongoDatabase.GetCollection(this.mongoDbProviderSettings.RulesCollectionName); - mongoCollection.InsertMany(rules); + mongoDatabase.DropCollection(this.mongoDbProviderSettings.ContentTypesCollectionName); + var contentTypesMongoCollection = mongoDatabase.GetCollection(this.mongoDbProviderSettings.ContentTypesCollectionName); + contentTypesMongoCollection.InsertMany(contentTypes); + + mongoDatabase.DropCollection(this.mongoDbProviderSettings.RulesCollectionName); + var rulesMongoCollection = mongoDatabase.GetCollection(this.mongoDbProviderSettings.RulesCollectionName); + rulesMongoCollection.InsertMany(rules); } [Theory] @@ -74,17 +89,16 @@ public async Task BuildingSecuritySystem_FireScenario_ReturnsActionsToTrigger(bo }; var rulesEngine = RulesEngineBuilder.CreateRulesEngine() - .WithContentType() - .WithConditionType() .SetMongoDbDataSource(this.mongoClient, this.mongoDbProviderSettings) .Configure(opt => { opt.EnableCompilation = enableCompilation; }) .Build(); + var genericRulesEngine = rulesEngine.MakeGeneric(); // Act - var newRuleResult = RuleBuilder.NewRule() + var newRuleResult = Rule.New() .WithName("Activate ventilation system rule") .WithDateBegin(new DateTime(2018, 01, 01)) .WithContent(SecuritySystemActionables.FireSystem, new SecuritySystemAction @@ -92,13 +106,13 @@ public async Task BuildingSecuritySystem_FireScenario_ReturnsActionsToTrigger(bo ActionId = new Guid("ef0d65ae-ec76-492a-84db-5cb9090c3eaa"), ActionName = "ActivateVentilationSystem" }) - .WithCondition(b => b.Value(SecuritySystemConditions.SmokeRate, Core.Operators.GreaterThanOrEqual, 30.0m)) + .WithCondition(b => b.Value(SecuritySystemConditions.SmokeRate, Operators.GreaterThanOrEqual, 30.0m)) .Build(); var newRule = newRuleResult.Rule; - _ = await rulesEngine.AddRuleAsync(newRule, RuleAddPriorityOption.AtBottom); + _ = await genericRulesEngine.AddRuleAsync(newRule, RuleAddPriorityOption.AtBottom); - var actual = await rulesEngine.MatchManyAsync(securitySystemActionable, expectedMatchDate, expectedConditions); + var actual = await genericRulesEngine.MatchManyAsync(securitySystemActionable, expectedMatchDate, expectedConditions); // Assert actual.Should().NotBeNull(); @@ -129,17 +143,16 @@ public async Task BuildingSecuritySystem_PowerFailureScenario_ReturnsActionsToTr }; var rulesEngine = RulesEngineBuilder.CreateRulesEngine() - .WithContentType() - .WithConditionType() .SetMongoDbDataSource(this.mongoClient, this.mongoDbProviderSettings) .Configure(opt => { opt.EnableCompilation = enableCompilation; }) .Build(); + var genericRulesEngine = rulesEngine.MakeGeneric(); // Act - var actual = await rulesEngine.MatchManyAsync(securitySystemActionable, expectedMatchDate, expectedConditions); + var actual = await genericRulesEngine.MatchManyAsync(securitySystemActionable, expectedMatchDate, expectedConditions); // Assert actual.Should().NotBeNull(); @@ -168,17 +181,16 @@ public async Task BuildingSecuritySystem_PowerShutdownScenario_ReturnsActionsToT }; var rulesEngine = RulesEngineBuilder.CreateRulesEngine() - .WithContentType() - .WithConditionType() .SetMongoDbDataSource(this.mongoClient, this.mongoDbProviderSettings) .Configure(opt => { opt.EnableCompilation = enableCompilation; }) .Build(); + var genericRulesEngine = rulesEngine.MakeGeneric(); // Act - var actual = await rulesEngine.MatchManyAsync(securitySystemActionable, expectedMatchDate, expectedConditions); + var actual = await genericRulesEngine.MatchManyAsync(securitySystemActionable, expectedMatchDate, expectedConditions); // Assert actual.Should().NotBeNull(); @@ -193,14 +205,15 @@ public void Dispose() { var mongoDatabase = this.mongoClient.GetDatabase(this.mongoDbProviderSettings.DatabaseName); mongoDatabase.DropCollection(this.mongoDbProviderSettings.RulesCollectionName); + mongoDatabase.DropCollection(this.mongoDbProviderSettings.ContentTypesCollectionName); } private static MongoClient CreateMongoClient() => new MongoClient($"mongodb://{SettingsProvider.GetMongoDbHost()}:27017"); - private static MongoDbProviderSettings CreateProviderSettings() => new MongoDbProviderSettings + private static MongoDbProviderSettings CreateProviderSettings() => new() { DatabaseName = "rules-framework-tests", - RulesCollectionName = "security-system-actionables" + RulesCollectionName = "security-system-actionables", }; } } \ No newline at end of file diff --git a/tests/Rules.Framework.Providers.MongoDb.IntegrationTests/Scenarios/Scenario5/BestServerTests.cs b/tests/Rules.Framework.Providers.MongoDb.IntegrationTests/Scenarios/Scenario5/BestServerTests.cs index 2c35a6d7..d26e6a69 100644 --- a/tests/Rules.Framework.Providers.MongoDb.IntegrationTests/Scenarios/Scenario5/BestServerTests.cs +++ b/tests/Rules.Framework.Providers.MongoDb.IntegrationTests/Scenarios/Scenario5/BestServerTests.cs @@ -6,7 +6,7 @@ namespace Rules.Framework.Providers.MongoDb.IntegrationTests.Scenarios.Scenario5 using System.Threading.Tasks; using FluentAssertions; using MongoDB.Driver; - using Rules.Framework.Core; + using Rules.Framework; using Rules.Framework.IntegrationTests.Common.Scenarios.Scenario5; using Rules.Framework.Providers.MongoDb; using Xunit; @@ -39,7 +39,7 @@ public sealed class BestServerTests : IDisposable } }.SelectMany(x => new[] { false, true }.Select(c => new object[] { x[0], x[1], c })); - private readonly IMongoClient mongoClient; + private readonly MongoClient mongoClient; private readonly MongoDbProviderSettings mongoDbProviderSettings; public BestServerTests() @@ -54,17 +54,17 @@ public async Task BestServer_InEvaluation(IEnumerable() - .WithConditionType() .SetMongoDbDataSource(this.mongoClient, this.mongoDbProviderSettings) .Configure(opt => { opt.EnableCompilation = enableCompilation; }) .Build(); + var genericRulesEngine = rulesEngine.MakeGeneric(); + await genericRulesEngine.CreateContentTypeAsync(BestServerConfigurations.BestServerEvaluation); // Act 1 - Create rule with "in" operator - var ruleBuilderResult = RuleBuilder.NewRule() + var ruleBuilderResult = Rule.New() .WithName("Best Server Top5") .WithDatesInterval(DateTime.Parse("2021-05-29Z"), DateTime.Parse("2021-05-31Z")) .WithContent(BestServerConfigurations.BestServerEvaluation, "Top5") @@ -79,7 +79,7 @@ public async Task BestServer_InEvaluation(IEnumerable() + var ruleBuilderResultDefault = Rule.New() .WithName("Best Server Default") .WithDatesInterval(DateTime.Parse("2021-05-29Z"), DateTime.Parse("2021-05-31Z")) .WithContent(BestServerConfigurations.BestServerEvaluation, "Default") @@ -87,7 +87,7 @@ public async Task BestServer_InEvaluation(IEnumerable $"{s1}\n- {s2}") : string.Empty; + var errors = ruleBuilderResult.Errors.Any() ? ruleBuilderResult.Errors.Aggregate((s1, s2) => $"{s1}\n- {s2}") : string.Empty; ruleBuilderResult.IsSuccess.Should().BeTrue( $"errors have occurred while creating rule: \n[\n- {errors}\n]"); @@ -98,12 +98,12 @@ public async Task BestServer_InEvaluation(IEnumerable new($"mongodb://{SettingsProvider.GetMongoDbHost()}:27017"); - private static MongoDbProviderSettings CreateProviderSettings() => new MongoDbProviderSettings + private static MongoDbProviderSettings CreateProviderSettings() => new() { DatabaseName = "rules-framework-tests", - RulesCollectionName = "best-server" + RulesCollectionName = "best-server", }; } } \ No newline at end of file diff --git a/tests/Rules.Framework.Providers.MongoDb.Tests/MongoDbProviderRulesDataSourceTests.cs b/tests/Rules.Framework.Providers.MongoDb.Tests/MongoDbProviderRulesDataSourceTests.cs index ec2571d7..d60e780f 100644 --- a/tests/Rules.Framework.Providers.MongoDb.Tests/MongoDbProviderRulesDataSourceTests.cs +++ b/tests/Rules.Framework.Providers.MongoDb.Tests/MongoDbProviderRulesDataSourceTests.cs @@ -2,26 +2,124 @@ namespace Rules.Framework.Providers.MongoDb.Tests { using System; using System.Collections.Generic; + using System.Threading; using System.Threading.Tasks; using FluentAssertions; using MongoDB.Driver; using Moq; - using Rules.Framework.Core; using Rules.Framework.Providers.MongoDb.DataModel; using Rules.Framework.Providers.MongoDb.Tests.TestStubs; using Xunit; public class MongoDbProviderRulesDataSourceTests { + [Fact] + public async Task CreateContentTypeAsync_GivenContentTypeName_InsertsContentTypeOnCollection() + { + // Arrange + var contentType = nameof(ContentType.ContentTypeSample); + ContentTypeDataModel actual = null; + var contentTypesCollection = Mock.Of>(); + Mock.Get(contentTypesCollection) + .Setup(x => x.InsertOneAsync(It.IsAny(), It.IsAny(), It.IsAny())) + .Callback((ct, _, _) => actual = ct); + + var mongoDatabase = Mock.Of(); + Mock.Get(mongoDatabase) + .Setup(x => x.GetCollection(It.IsAny(), null)) + .Returns(contentTypesCollection); + + var mongoClient = Mock.Of(); + Mock.Get(mongoClient) + .Setup(x => x.GetDatabase(It.IsAny(), null)) + .Returns(mongoDatabase); + + var mongoDbProviderSettings = new MongoDbProviderSettings + { + DatabaseName = "TestDatabaseName", + RulesCollectionName = "TestCollectionName" + }; + + var ruleFactory = Mock.Of(); + + var mongoDbProviderRulesDataSource = new MongoDbProviderRulesDataSource( + mongoClient, + mongoDbProviderSettings, + ruleFactory); + + // Act + await mongoDbProviderRulesDataSource.CreateContentTypeAsync(contentType); + + // Assert + actual.Should().NotBeNull(); + actual.Name.Should().Be(contentType); + actual.Id.Should().NotBeEmpty(); + actual.Creation.Should().BeWithin(TimeSpan.FromSeconds(5)).Before(DateTime.UtcNow); + } + + [Fact] + public async Task GetContentTypesAsync_NoConditions_ReturnsCollectionOfContentTypes() + { + // Arrange + var contentTypeDataModels = new[] { nameof(ContentType.ContentTypeSample), }; + + var fetchedRulesCursor = Mock.Of>(); + Mock.Get(fetchedRulesCursor) + .SetupSequence(x => x.MoveNextAsync(default)) + .ReturnsAsync(true) + .ReturnsAsync(false); + Mock.Get(fetchedRulesCursor) + .SetupGet(x => x.Current) + .Returns(contentTypeDataModels); + Mock.Get(fetchedRulesCursor) + .Setup(x => x.Dispose()); + + var contentTypesCollection = Mock.Of>(); + Mock.Get(contentTypesCollection) + .Setup(x => x.FindAsync(It.IsAny>(), It.IsAny>(), default)) + .ReturnsAsync(fetchedRulesCursor); + + var mongoDatabase = Mock.Of(); + Mock.Get(mongoDatabase) + .Setup(x => x.GetCollection(It.IsAny(), null)) + .Returns(contentTypesCollection); + + var mongoClient = Mock.Of(); + Mock.Get(mongoClient) + .Setup(x => x.GetDatabase(It.IsAny(), null)) + .Returns(mongoDatabase); + + var mongoDbProviderSettings = new MongoDbProviderSettings + { + DatabaseName = "TestDatabaseName", + RulesCollectionName = "TestCollectionName" + }; + + var ruleFactory = Mock.Of(); + + var mongoDbProviderRulesDataSource = new MongoDbProviderRulesDataSource( + mongoClient, + mongoDbProviderSettings, + ruleFactory); + + // Act + var actual = await mongoDbProviderRulesDataSource.GetContentTypesAsync(); + + // Assert + actual.Should().NotBeNull() + .And.HaveCount(1) + .And.Contain(nameof(ContentType.ContentTypeSample)); + } + [Fact] public async Task GetRulesAsync_GivenContentTypeAndDatesInterval_ReturnsCollectionOfRules() { // Arrange - ContentType contentType = ContentType.ContentTypeSample; - DateTime dateBegin = new DateTime(2020, 03, 01); - DateTime dateEnd = new DateTime(2020, 04, 01); + var contentType = ContentType.ContentTypeSample.ToString(); + var dateBegin = new DateTime(2020, 03, 01); + var dateEnd = new DateTime(2020, 04, 01); - List ruleDataModels = new List + var ruleDataModels = new List { new RuleDataModel { @@ -33,7 +131,7 @@ public async Task GetRulesAsync_GivenContentTypeAndDatesInterval_ReturnsCollecti } }; - IAsyncCursor fetchedRulesCursor = Mock.Of>(); + var fetchedRulesCursor = Mock.Of>(); Mock.Get(fetchedRulesCursor) .SetupSequence(x => x.MoveNextAsync(default)) .ReturnsAsync(true) @@ -44,39 +142,39 @@ public async Task GetRulesAsync_GivenContentTypeAndDatesInterval_ReturnsCollecti Mock.Get(fetchedRulesCursor) .Setup(x => x.Dispose()); - IMongoCollection rulesCollection = Mock.Of>(); + var rulesCollection = Mock.Of>(); Mock.Get(rulesCollection) .Setup(x => x.FindAsync(It.IsAny>(), null, default)) .ReturnsAsync(fetchedRulesCursor); - IMongoDatabase mongoDatabase = Mock.Of(); + var mongoDatabase = Mock.Of(); Mock.Get(mongoDatabase) .Setup(x => x.GetCollection(It.IsAny(), null)) .Returns(rulesCollection); - IMongoClient mongoClient = Mock.Of(); + var mongoClient = Mock.Of(); Mock.Get(mongoClient) .Setup(x => x.GetDatabase(It.IsAny(), null)) .Returns(mongoDatabase); - MongoDbProviderSettings mongoDbProviderSettings = new MongoDbProviderSettings + var mongoDbProviderSettings = new MongoDbProviderSettings { DatabaseName = "TestDatabaseName", RulesCollectionName = "TestCollectionName" }; - IRuleFactory ruleFactory = Mock.Of>(); + var ruleFactory = Mock.Of(); Mock.Get(ruleFactory) .Setup(x => x.CreateRule(It.IsAny())) - .Returns(x => RuleBuilder.NewRule().WithName(x.Name).Build().Rule); + .Returns(x => Rule.New().WithName(x.Name).Build().Rule); - MongoDbProviderRulesDataSource mongoDbProviderRulesDataSource = new MongoDbProviderRulesDataSource( + var mongoDbProviderRulesDataSource = new MongoDbProviderRulesDataSource( mongoClient, mongoDbProviderSettings, ruleFactory); // Act - IEnumerable> rules = await mongoDbProviderRulesDataSource.GetRulesAsync(contentType, dateBegin, dateEnd); + var rules = await mongoDbProviderRulesDataSource.GetRulesAsync(contentType, dateBegin, dateEnd); // Assert rules.Should().NotBeNull() diff --git a/tests/Rules.Framework.Providers.MongoDb.Tests/RuleFactoryTests.cs b/tests/Rules.Framework.Providers.MongoDb.Tests/RuleFactoryTests.cs index 3075bdaa..8ca96eff 100644 --- a/tests/Rules.Framework.Providers.MongoDb.Tests/RuleFactoryTests.cs +++ b/tests/Rules.Framework.Providers.MongoDb.Tests/RuleFactoryTests.cs @@ -5,9 +5,9 @@ namespace Rules.Framework.Providers.MongoDb.Tests using System.Linq; using FluentAssertions; using Moq; + using Rules.Framework; using Rules.Framework.Builder; - using Rules.Framework.Core; - using Rules.Framework.Core.ConditionNodes; + using Rules.Framework.ConditionNodes; using Rules.Framework.Providers.MongoDb.DataModel; using Rules.Framework.Providers.MongoDb.Tests.TestStubs; using Rules.Framework.Serialization; @@ -19,11 +19,11 @@ public class RuleFactoryTests public void CreateRule_GivenNullRule_ThrowsArgumentNullException() { // Arrange - Rule rule = null; + Rule rule = null; - var contentSerializationProvider = Mock.Of>(); + var contentSerializationProvider = Mock.Of(); - var ruleFactory = new RuleFactory(contentSerializationProvider); + var ruleFactory = new RuleFactory(contentSerializationProvider); // Act var argumentNullException = Assert.Throws(() => ruleFactory.CreateRule(rule)); @@ -39,9 +39,9 @@ public void CreateRule_GivenNullRuleDataModel_ThrowsArgumentNullException() // Arrange RuleDataModel ruleDataModel = null; - var contentSerializationProvider = Mock.Of>(); + var contentSerializationProvider = Mock.Of(); - var ruleFactory = new RuleFactory(contentSerializationProvider); + var ruleFactory = new RuleFactory(contentSerializationProvider); // Act var argumentNullException = Assert.Throws(() => ruleFactory.CreateRule(ruleDataModel)); @@ -117,32 +117,32 @@ public void CreateRule_GivenRuleDataModelWithComposedNodeAndChildNodesOfEachData } }; - var contentSerializationProvider = Mock.Of>(); + var contentSerializationProvider = Mock.Of(); - var ruleFactory = new RuleFactory(contentSerializationProvider); + var ruleFactory = new RuleFactory(contentSerializationProvider); // Act var rule = ruleFactory.CreateRule(ruleDataModel); // Assert rule.Should().NotBeNull(); - rule.ContentContainer.Should().NotBeNull().And.BeOfType>(); + rule.ContentContainer.Should().NotBeNull().And.BeOfType(); rule.DateBegin.Should().Be(ruleDataModel.DateBegin); rule.DateEnd.Should().BeNull(); rule.Name.Should().Be(ruleDataModel.Name); rule.Priority.Should().Be(ruleDataModel.Priority); - rule.RootCondition.Should().BeOfType>(); + rule.RootCondition.Should().BeOfType(); - var composedConditionNode = rule.RootCondition.As>(); + var composedConditionNode = rule.RootCondition.As(); composedConditionNode.LogicalOperator.Should().Be(LogicalOperators.And); composedConditionNode.ChildConditionNodes.Should().HaveCount(4); - var valueConditionNodes = composedConditionNode.ChildConditionNodes.OfType>(); + var valueConditionNodes = composedConditionNode.ChildConditionNodes.OfType(); valueConditionNodes.Should().HaveCount(4); var integerConditionNode = valueConditionNodes.First(x => x.DataType == DataTypes.Integer); integerConditionNode.Should().NotBeNull(); - integerConditionNode.ConditionType.Should().Match(x => x == Enum.Parse(integerConditionNodeDataModel.ConditionType)); + integerConditionNode.ConditionType.Should().Be(integerConditionNodeDataModel.ConditionType); integerConditionNode.DataType.Should().Be(integerConditionNodeDataModel.DataType); integerConditionNode.LogicalOperator.Should().Be(integerConditionNodeDataModel.LogicalOperator); integerConditionNode.Operand.Should().Match(x => object.Equals(x, integerConditionNodeDataModel.Operand)); @@ -150,7 +150,7 @@ public void CreateRule_GivenRuleDataModelWithComposedNodeAndChildNodesOfEachData var stringConditionNode = valueConditionNodes.First(x => x.DataType == DataTypes.String); stringConditionNode.Should().NotBeNull(); - stringConditionNode.ConditionType.Should().Match(x => x == Enum.Parse(stringConditionNodeDataModel.ConditionType)); + stringConditionNode.ConditionType.Should().Be(stringConditionNodeDataModel.ConditionType); stringConditionNode.DataType.Should().Be(stringConditionNodeDataModel.DataType); stringConditionNode.LogicalOperator.Should().Be(stringConditionNodeDataModel.LogicalOperator); stringConditionNode.Operand.Should().Match(x => object.Equals(x, stringConditionNodeDataModel.Operand)); @@ -158,7 +158,7 @@ public void CreateRule_GivenRuleDataModelWithComposedNodeAndChildNodesOfEachData var decimalConditionNode = valueConditionNodes.First(x => x.DataType == DataTypes.Decimal); decimalConditionNode.Should().NotBeNull(); - decimalConditionNode.ConditionType.Should().Match(x => x == Enum.Parse(decimalConditionNodeDataModel.ConditionType)); + decimalConditionNode.ConditionType.Should().Be(decimalConditionNodeDataModel.ConditionType); decimalConditionNode.DataType.Should().Be(decimalConditionNodeDataModel.DataType); decimalConditionNode.LogicalOperator.Should().Be(decimalConditionNodeDataModel.LogicalOperator); decimalConditionNode.Operand.Should().Match(x => object.Equals(x, decimalConditionNodeDataModel.Operand)); @@ -166,7 +166,7 @@ public void CreateRule_GivenRuleDataModelWithComposedNodeAndChildNodesOfEachData var booleanConditionNode = valueConditionNodes.First(x => x.DataType == DataTypes.Boolean); booleanConditionNode.Should().NotBeNull(); - booleanConditionNode.ConditionType.Should().Match(x => x == Enum.Parse(booleanConditionNodeDataModel.ConditionType)); + booleanConditionNode.ConditionType.Should().Be(booleanConditionNodeDataModel.ConditionType); booleanConditionNode.DataType.Should().Be(booleanConditionNodeDataModel.DataType); booleanConditionNode.LogicalOperator.Should().Be(booleanConditionNodeDataModel.LogicalOperator); booleanConditionNode.Operand.Should().Be(Convert.ToBoolean(booleanConditionNodeDataModel.Operand)); @@ -190,21 +190,21 @@ public void CreateRule_GivenRuleWithComposedNodeAndChildNodesOfEachDataType_Retu .Setup(x => x.Serialize(It.IsAny())) .Returns((object)content); - var contentSerializationProvider = Mock.Of>(); + var contentSerializationProvider = Mock.Of(); Mock.Get(contentSerializationProvider) - .Setup(x => x.GetContentSerializer(ContentType.ContentTypeSample)) + .Setup(x => x.GetContentSerializer(ContentType.ContentTypeSample.ToString())) .Returns(contentSerializer); var booleanConditionNode = ConditionNodeFactory - .CreateValueNode(ConditionType.SampleBooleanCondition, Operators.NotEqual, true) as ValueConditionNode; + .CreateValueNode(ConditionType.SampleBooleanCondition.ToString(), Operators.NotEqual, true); var decimalConditionNode = ConditionNodeFactory - .CreateValueNode(ConditionType.SampleDecimalCondition, Operators.LesserThanOrEqual, 50.3m) as ValueConditionNode; + .CreateValueNode(ConditionType.SampleDecimalCondition.ToString(), Operators.LesserThanOrEqual, 50.3m); var integerConditionNode = ConditionNodeFactory - .CreateValueNode(ConditionType.SampleIntegerCondition, Operators.GreaterThan, 20) as ValueConditionNode; + .CreateValueNode(ConditionType.SampleIntegerCondition.ToString(), Operators.GreaterThan, 20); var stringConditionNode = ConditionNodeFactory - .CreateValueNode(ConditionType.SampleStringCondition, Operators.Equal, "TEST") as ValueConditionNode; + .CreateValueNode(ConditionType.SampleStringCondition.ToString(), Operators.Equal, "TEST"); - var rule = RuleBuilder.NewRule() + var rule = Rule.New() .WithName("My rule used for testing purposes") .WithDateBegin(new DateTime(2020, 1, 1)) .WithContent(ContentType.ContentTypeSample, (object)content) @@ -217,7 +217,7 @@ public void CreateRule_GivenRuleWithComposedNodeAndChildNodesOfEachDataType_Retu )) .Build().Rule; - var ruleFactory = new RuleFactory(contentSerializationProvider); + var ruleFactory = new RuleFactory(contentSerializationProvider); // Act var ruleDataModel = ruleFactory.CreateRule(rule); @@ -241,7 +241,7 @@ public void CreateRule_GivenRuleWithComposedNodeAndChildNodesOfEachDataType_Retu var integerConditionNodeDataModel = valueConditionNodeDataModels.First(v => v.DataType == DataTypes.Integer); integerConditionNodeDataModel.Should().NotBeNull(); - integerConditionNodeDataModel.ConditionType.Should().Match(x => integerConditionNode.ConditionType == Enum.Parse(x)); + integerConditionNodeDataModel.ConditionType.Should().Be(integerConditionNode.ConditionType); integerConditionNodeDataModel.DataType.Should().Be(integerConditionNode.DataType); integerConditionNodeDataModel.LogicalOperator.Should().Be(integerConditionNode.LogicalOperator); integerConditionNodeDataModel.Operand.Should().Match(x => object.Equals(x, integerConditionNode.Operand)); @@ -249,7 +249,7 @@ public void CreateRule_GivenRuleWithComposedNodeAndChildNodesOfEachDataType_Retu var stringConditionNodeDataModel = valueConditionNodeDataModels.First(v => v.DataType == DataTypes.String); stringConditionNodeDataModel.Should().NotBeNull(); - stringConditionNodeDataModel.ConditionType.Should().Match(x => stringConditionNode.ConditionType == Enum.Parse(x)); + stringConditionNodeDataModel.ConditionType.Should().Be(stringConditionNode.ConditionType); stringConditionNodeDataModel.DataType.Should().Be(stringConditionNode.DataType); stringConditionNodeDataModel.LogicalOperator.Should().Be(stringConditionNode.LogicalOperator); stringConditionNodeDataModel.Operand.Should().Match(x => object.Equals(x, stringConditionNode.Operand)); @@ -257,7 +257,7 @@ public void CreateRule_GivenRuleWithComposedNodeAndChildNodesOfEachDataType_Retu var decimalConditionNodeDataModel = valueConditionNodeDataModels.First(v => v.DataType == DataTypes.Decimal); decimalConditionNodeDataModel.Should().NotBeNull(); - decimalConditionNodeDataModel.ConditionType.Should().Match(x => decimalConditionNode.ConditionType == Enum.Parse(x)); + decimalConditionNodeDataModel.ConditionType.Should().Be(decimalConditionNode.ConditionType); decimalConditionNodeDataModel.DataType.Should().Be(decimalConditionNode.DataType); decimalConditionNodeDataModel.LogicalOperator.Should().Be(decimalConditionNode.LogicalOperator); decimalConditionNodeDataModel.Operand.Should().Match(x => object.Equals(x, decimalConditionNode.Operand)); @@ -265,7 +265,7 @@ public void CreateRule_GivenRuleWithComposedNodeAndChildNodesOfEachDataType_Retu var booleanConditionNodeDataModel = valueConditionNodeDataModels.First(v => v.DataType == DataTypes.Boolean); booleanConditionNodeDataModel.Should().NotBeNull(); - booleanConditionNodeDataModel.ConditionType.Should().Match(x => booleanConditionNode.ConditionType == Enum.Parse(x)); + booleanConditionNodeDataModel.ConditionType.Should().Be(booleanConditionNode.ConditionType); booleanConditionNodeDataModel.DataType.Should().Be(booleanConditionNode.DataType); booleanConditionNodeDataModel.LogicalOperator.Should().Be(booleanConditionNode.LogicalOperator); booleanConditionNodeDataModel.Operand.Should().Be(Convert.ToBoolean(booleanConditionNode.Operand)); diff --git a/tests/Rules.Framework.Providers.MongoDb.Tests/Serialization/DynamicToStrongTypeContentSerializationProviderTests.cs b/tests/Rules.Framework.Providers.MongoDb.Tests/Serialization/DynamicToStrongTypeContentSerializationProviderTests.cs index f4e911d4..f5c29499 100644 --- a/tests/Rules.Framework.Providers.MongoDb.Tests/Serialization/DynamicToStrongTypeContentSerializationProviderTests.cs +++ b/tests/Rules.Framework.Providers.MongoDb.Tests/Serialization/DynamicToStrongTypeContentSerializationProviderTests.cs @@ -3,7 +3,6 @@ namespace Rules.Framework.Providers.MongoDb.Tests.Serialization using FluentAssertions; using Rules.Framework.Providers.MongoDb.Serialization; using Rules.Framework.Providers.MongoDb.Tests.TestStubs; - using Rules.Framework.Serialization; using Xunit; public class DynamicToStrongTypeContentSerializationProviderTests @@ -12,10 +11,10 @@ public class DynamicToStrongTypeContentSerializationProviderTests public void GetContentSerializer_GivenAnyContentTypeValue_ReturnsDynamicToStrongTypeContentSerializer() { // Arrange - DynamicToStrongTypeContentSerializationProvider dynamicToStrongTypeContentSerializationProvider = new DynamicToStrongTypeContentSerializationProvider(); + var dynamicToStrongTypeContentSerializationProvider = new DynamicToStrongTypeContentSerializationProvider(); // Act - IContentSerializer contentSerializer = dynamicToStrongTypeContentSerializationProvider.GetContentSerializer(ContentType.ContentTypeSample); + var contentSerializer = dynamicToStrongTypeContentSerializationProvider.GetContentSerializer(ContentType.ContentTypeSample.ToString()); // Assert contentSerializer.Should().NotBeNull() diff --git a/tests/Rules.Framework.Tests/Builder/ConfiguredRulesEngineBuilderTests.cs b/tests/Rules.Framework.Tests/Builder/ConfiguredRulesEngineBuilderTests.cs index 224210ba..0e964d26 100644 --- a/tests/Rules.Framework.Tests/Builder/ConfiguredRulesEngineBuilderTests.cs +++ b/tests/Rules.Framework.Tests/Builder/ConfiguredRulesEngineBuilderTests.cs @@ -3,7 +3,6 @@ namespace Rules.Framework.Tests.Builder using FluentAssertions; using Moq; using Rules.Framework.Builder; - using Rules.Framework.Tests.Stubs; using Xunit; public class ConfiguredRulesEngineBuilderTests @@ -12,8 +11,8 @@ public class ConfiguredRulesEngineBuilderTests public void Build_WhenCompilationIsEnabled_ReturnsRulesEngineWithCompiledEvaluation() { // Arrange - var rulesDataSource = Mock.Of>(); - var configuredRulesEngineBuilder = new ConfiguredRulesEngineBuilder(rulesDataSource); + var rulesDataSource = Mock.Of(); + var configuredRulesEngineBuilder = new ConfiguredRulesEngineBuilder(rulesDataSource); configuredRulesEngineBuilder.Configure(opt => { @@ -31,8 +30,8 @@ public void Build_WhenCompilationIsEnabled_ReturnsRulesEngineWithCompiledEvaluat public void Build_WhenCompilationIsNotEnabled_ReturnsRulesEngineWithClassicEvaluation() { // Arrange - var rulesDataSource = Mock.Of>(); - var configuredRulesEngineBuilder = new ConfiguredRulesEngineBuilder(rulesDataSource); + var rulesDataSource = Mock.Of(); + var configuredRulesEngineBuilder = new ConfiguredRulesEngineBuilder(rulesDataSource); // Act var actual = configuredRulesEngineBuilder.Build(); @@ -45,8 +44,8 @@ public void Build_WhenCompilationIsNotEnabled_ReturnsRulesEngineWithClassicEvalu public void Configure_GivenOptionsConfigurationAction_SetsOptionsAndValidates() { // Arrange - var rulesDataSource = Mock.Of>(); - var configuredRulesEngineBuilder = new ConfiguredRulesEngineBuilder(rulesDataSource); + var rulesDataSource = Mock.Of(); + var configuredRulesEngineBuilder = new ConfiguredRulesEngineBuilder(rulesDataSource); // Act var actual = configuredRulesEngineBuilder.Configure(opt => diff --git a/tests/Rules.Framework.Tests/Builder/RuleBuilderResultTests.cs b/tests/Rules.Framework.Tests/Builder/RuleBuilderResultTests.cs index 599462fa..cc8dad7a 100644 --- a/tests/Rules.Framework.Tests/Builder/RuleBuilderResultTests.cs +++ b/tests/Rules.Framework.Tests/Builder/RuleBuilderResultTests.cs @@ -4,8 +4,6 @@ namespace Rules.Framework.Tests.Builder using System.Collections.Generic; using FluentAssertions; using Rules.Framework.Builder; - using Rules.Framework.Core; - using Rules.Framework.Tests.Stubs; using Xunit; public class RuleBuilderResultTests @@ -17,7 +15,7 @@ public void Failure_GivenAllValidParameters_ReturnsRuleBuilderResultWithFailure( IEnumerable expectedErrors = new[] { "Error1", "Error2" }; // Act - RuleBuilderResult ruleBuilderResult = RuleBuilderResult.Failure(expectedErrors); + var ruleBuilderResult = RuleBuilderResult.Failure(expectedErrors); // Assert ruleBuilderResult.Should().NotBeNull(); @@ -33,7 +31,7 @@ public void Failure_GivenNullErrorsCollection_ThrowsArgumentNullException() IEnumerable expectedErrors = null; // Act - ArgumentNullException argumentNullException = Assert.Throws(() => RuleBuilderResult.Failure(expectedErrors)); + var argumentNullException = Assert.Throws(() => RuleBuilderResult.Failure(expectedErrors)); // Arrange argumentNullException.Should().NotBeNull(); @@ -44,10 +42,10 @@ public void Failure_GivenNullErrorsCollection_ThrowsArgumentNullException() public void Success_GivenAllValidParameters_ReturnsRuleBuilderResultWithSuccessAndNewRule() { // Arrange - Rule rule = new Rule(); + var rule = new Rule(); // Act - RuleBuilderResult ruleBuilderResult = RuleBuilderResult.Success(rule); + var ruleBuilderResult = RuleBuilderResult.Success(rule); // Assert ruleBuilderResult.Should().NotBeNull(); @@ -60,10 +58,10 @@ public void Success_GivenAllValidParameters_ReturnsRuleBuilderResultWithSuccessA public void Success_GivenNullErrorsCollection_ThrowsArgumentNullException() { // Arrange - Rule rule = null; + Rule rule = null; // Act - ArgumentNullException argumentNullException = Assert.Throws(() => RuleBuilderResult.Success(rule)); + var argumentNullException = Assert.Throws(() => RuleBuilderResult.Success(rule)); // Arrange argumentNullException.Should().NotBeNull(); diff --git a/tests/Rules.Framework.Tests/Builder/RuleBuilderTests.cs b/tests/Rules.Framework.Tests/Builder/RuleBuilderTests.cs index dacc3d45..bd3d2874 100644 --- a/tests/Rules.Framework.Tests/Builder/RuleBuilderTests.cs +++ b/tests/Rules.Framework.Tests/Builder/RuleBuilderTests.cs @@ -5,9 +5,7 @@ namespace Rules.Framework.Tests.Builder using FluentAssertions; using Moq; using Rules.Framework; - using Rules.Framework.Builder; - using Rules.Framework.Core; - using Rules.Framework.Core.ConditionNodes; + using Rules.Framework.Generic.ConditionNodes; using Rules.Framework.Serialization; using Rules.Framework.Tests.Stubs; using Xunit; @@ -18,13 +16,13 @@ public class RuleBuilderTests public void NewRule_GivenRuleWithComposedCondition_BuildsAndReturnsRule() { // Arrange - string ruleName = "Rule 1"; + var ruleName = "Rule 1"; var dateBegin = DateTime.Parse("2021-01-01"); var contentType = ContentType.Type1; - string content = "Content"; + var content = "Content"; // Act - var ruleBuilderResult = RuleBuilder.NewRule() + var ruleBuilderResult = Rule.New() .WithName(ruleName) .WithDateBegin(dateBegin) .WithContent(contentType, content) @@ -90,14 +88,14 @@ public void NewRule_GivenRuleWithIntegerConditionTypeAndContainsOperator_Returns var ruleName = "Rule 1"; var dateBegin = DateTime.Parse("2021-01-01"); var contentType = ContentType.Type1; - string content = "Content"; + var content = "Content"; const ConditionType conditionType = ConditionType.NumberOfSales; const int conditionValue = 40; var conditionOperator = containsOperator; const DataTypes dataType = DataTypes.Integer; // Act - RuleBuilderResult ruleBuilderResult = RuleBuilder.NewRule() + var ruleBuilderResult = Rule.New() .WithName(ruleName) .WithDateBegin(dateBegin) .WithContent(contentType, content) @@ -119,10 +117,10 @@ public void NewRule_GivenRuleWithIntegerConditionTypeAndContainsOperator_Returns public void NewRule_GivenRuleWithStringConditionTypeAndContainsOperator_BuildsAndReturnsRule(Operators containsOperator) { // Arrange - string ruleName = "Rule 1"; + var ruleName = "Rule 1"; var dateBegin = DateTime.Parse("2021-01-01"); var contentType = ContentType.Type1; - string content = "Content"; + var content = "Content"; const ConditionType conditionType = ConditionType.IsoCountryCode; const string conditionValue = "PT"; var conditionOperator = containsOperator; @@ -130,7 +128,7 @@ public void NewRule_GivenRuleWithStringConditionTypeAndContainsOperator_BuildsAn const DataTypes dataType = DataTypes.String; // Act - var ruleBuilderResult = RuleBuilder.NewRule() + var ruleBuilderResult = Rule.New() .WithName(ruleName) .WithDateBegin(dateBegin) .WithContent(contentType, content) @@ -142,7 +140,7 @@ public void NewRule_GivenRuleWithStringConditionTypeAndContainsOperator_BuildsAn ruleBuilderResult.IsSuccess.Should().BeTrue(); ruleBuilderResult.Rule.Should().NotBeNull(); - Rule rule = ruleBuilderResult.Rule; + var rule = ruleBuilderResult.Rule; rule.Name.Should().Be(ruleName); rule.DateBegin.Should().Be(dateBegin); @@ -164,8 +162,8 @@ public void NewRule_GivenRuleWithStringConditionTypeAndContainsOperator_BuildsAn public void NewRule_WithSerializedContent_GivenNullContentSerializationProvider_ThrowsArgumentNullException() { // Arrange - var ruleBuilder = RuleBuilder.NewRule(); - IContentSerializationProvider contentSerializationProvider = null; + var ruleBuilder = Rule.New(); + IContentSerializationProvider contentSerializationProvider = null; // Act var argumentNullException = Assert @@ -180,33 +178,32 @@ public void NewRule_WithSerializedContent_GivenNullContentSerializationProvider_ public void NewRule_WithSerializedContent_SetsContentAsSerializedContent() { // Arrange - string ruleName = "Rule 1"; + var ruleName = "Rule 1"; var dateBegin = DateTime.Parse("2021-01-01"); var contentType = ContentType.Type1; - string content = "TEST"; + var content = "TEST"; var contentSerializer = Mock.Of(); Mock.Get(contentSerializer) .Setup(x => x.Deserialize(It.IsAny(), It.IsAny())) .Returns(content); - var contentSerializationProvider = Mock.Of>(); + var contentSerializationProvider = Mock.Of(); Mock.Get(contentSerializationProvider) - .Setup(x => x.GetContentSerializer(contentType)) + .Setup(x => x.GetContentSerializer(contentType.ToString())) .Returns(contentSerializer); // Act - var ruleBuilderResult = RuleBuilder.NewRule() + var ruleBuilderResult = Rule.New() .WithName(ruleName) .WithDateBegin(dateBegin) .WithSerializedContent(contentType, content, contentSerializationProvider) .Build(); // Assert + ruleBuilderResult.Rule.ContentType.Should().Be(contentType); var ruleContent = ruleBuilderResult.Rule.ContentContainer; - ruleContent.Should().NotBeNull(); - ruleContent.Should().NotBeNull().And.BeOfType>(); - ruleContent.ContentType.Should().Be(contentType); + ruleContent.Should().NotBeNull().And.BeOfType(); ruleContent.GetContentAs().Should().Be(content); } } diff --git a/tests/Rules.Framework.Tests/Builder/RuleEngineOptionsValidatorTests.cs b/tests/Rules.Framework.Tests/Builder/RuleEngineOptionsValidatorTests.cs index cd81de1e..e0c1034c 100644 --- a/tests/Rules.Framework.Tests/Builder/RuleEngineOptionsValidatorTests.cs +++ b/tests/Rules.Framework.Tests/Builder/RuleEngineOptionsValidatorTests.cs @@ -1,8 +1,8 @@ namespace Rules.Framework.Tests.Builder { using FluentAssertions; + using Rules.Framework; using Rules.Framework.Builder; - using Rules.Framework.Core; using Xunit; public class RuleEngineOptionsValidatorTests diff --git a/tests/Rules.Framework.Tests/Builder/SelectorsTests.cs b/tests/Rules.Framework.Tests/Builder/SelectorsTests.cs index 1a2ba354..e69d3e5b 100644 --- a/tests/Rules.Framework.Tests/Builder/SelectorsTests.cs +++ b/tests/Rules.Framework.Tests/Builder/SelectorsTests.cs @@ -3,44 +3,16 @@ namespace Rules.Framework.Tests.Builder using System; using FluentAssertions; using Moq; - using Rules.Framework.Builder; - using Rules.Framework.Tests.Stubs; using Xunit; using static Rules.Framework.Builder.RulesEngineSelectors; public class SelectorsTests { - [Fact] - public void ConditionTypeSelector_WithConditionType_GivenTypeOfCondition_ReturnsNewRulesDataSourceSelector() - { - // Arrange - ConditionTypeSelector sut = new ConditionTypeSelector(); - - // Act - IRulesDataSourceSelector actual = sut.WithConditionType(); - - // Assert - actual.Should().BeOfType>(); - } - - [Fact] - public void ContentTypeSelector_WithContentType_GivenTypeOfContent_ReturnsNewConditionTypeSelector() - { - // Arrange - ContentTypeSelector sut = new ContentTypeSelector(); - - // Act - IConditionTypeSelector actual = sut.WithContentType(); - - // Assert - actual.Should().BeOfType>(); - } - [Fact] public void RulesDataSourceSelector_SetDataSource_GivenNullRulesDataSource_ThrowsArgumentNullException() { // Arrange - RulesDataSourceSelector sut = new RulesDataSourceSelector(); + var sut = new RulesDataSourceSelector(); // Assert Assert.Throws(() => @@ -54,12 +26,12 @@ public void RulesDataSourceSelector_SetDataSource_GivenNullRulesDataSource_Throw public void RulesDataSourceSelector_SetDataSource_GivenRulesDataSourceInstance_ReturnsRulesEngine() { // Arrange - RulesDataSourceSelector sut = new RulesDataSourceSelector(); + var sut = new RulesDataSourceSelector(); - Mock> mockRulesDataSource = new Mock>(); + var mockRulesDataSource = new Mock(); // Act - IConfiguredRulesEngineBuilder actual = sut.SetDataSource(mockRulesDataSource.Object); + var actual = sut.SetDataSource(mockRulesDataSource.Object); // Assert actual.Should().NotBeNull(); diff --git a/tests/Rules.Framework.Tests/Core/ConditionNodes/ComposedConditionNodeTests.cs b/tests/Rules.Framework.Tests/ConditionNodes/ComposedConditionNodeTests.cs similarity index 70% rename from tests/Rules.Framework.Tests/Core/ConditionNodes/ComposedConditionNodeTests.cs rename to tests/Rules.Framework.Tests/ConditionNodes/ComposedConditionNodeTests.cs index 35cc5cf3..98dffae0 100644 --- a/tests/Rules.Framework.Tests/Core/ConditionNodes/ComposedConditionNodeTests.cs +++ b/tests/Rules.Framework.Tests/ConditionNodes/ComposedConditionNodeTests.cs @@ -1,10 +1,9 @@ -namespace Rules.Framework.Tests.Core.ConditionNodes +namespace Rules.Framework.Tests.ConditionNodes { using FluentAssertions; using Moq; - using Rules.Framework.Core; - using Rules.Framework.Core.ConditionNodes; - using Rules.Framework.Tests.Stubs; + using Rules.Framework; + using Rules.Framework.ConditionNodes; using Xunit; public class ComposedConditionNodeTests @@ -14,8 +13,8 @@ public void Clone_NoConditions_ReturnsCloneInstance() { // Arrange var expectedLogicalOperator = LogicalOperators.Eval; - var conditionNode1 = Mock.Of>(); - var conditionNode2 = Mock.Of>(); + var conditionNode1 = Mock.Of(); + var conditionNode2 = Mock.Of(); Mock.Get(conditionNode1) .Setup(x => x.Clone()) .Returns(conditionNode1); @@ -25,7 +24,7 @@ public void Clone_NoConditions_ReturnsCloneInstance() var expectedChildConditionNodes = new[] { conditionNode1, conditionNode2 }; - var sut = new ComposedConditionNode(expectedLogicalOperator, expectedChildConditionNodes); + var sut = new ComposedConditionNode(expectedLogicalOperator, expectedChildConditionNodes); sut.Properties["test"] = "test"; // Act @@ -35,8 +34,8 @@ public void Clone_NoConditions_ReturnsCloneInstance() actual.Should() .NotBeNull() .And - .BeOfType>(); - var valueConditionNode = actual.As>(); + .BeOfType(); + var valueConditionNode = actual.As(); valueConditionNode.LogicalOperator.Should().Be(expectedLogicalOperator); valueConditionNode.ChildConditionNodes.Should().BeEquivalentTo(expectedChildConditionNodes); valueConditionNode.Properties.Should().BeEquivalentTo(sut.Properties); @@ -49,11 +48,11 @@ public void ComposedConditionNode_Init_GivenSetupWithChildConditionsAndLogicalOp var expectedLogicalOperator = LogicalOperators.Eval; var expectedChildConditionNodes = new[] { - new Mock>().Object, - new Mock>().Object + new Mock().Object, + new Mock().Object }; - var sut = new ComposedConditionNode(expectedLogicalOperator, expectedChildConditionNodes); + var sut = new ComposedConditionNode(expectedLogicalOperator, expectedChildConditionNodes); // Act var actualLogicalOperator = sut.LogicalOperator; diff --git a/tests/Rules.Framework.Tests/ConditionNodes/ValueConditionNodeTests.cs b/tests/Rules.Framework.Tests/ConditionNodes/ValueConditionNodeTests.cs new file mode 100644 index 00000000..a8287fe3 --- /dev/null +++ b/tests/Rules.Framework.Tests/ConditionNodes/ValueConditionNodeTests.cs @@ -0,0 +1,238 @@ +namespace Rules.Framework.Tests.ConditionNodes +{ + using FluentAssertions; + using Rules.Framework.ConditionNodes; + using Rules.Framework.Tests.Stubs; + using Xunit; + + public class ValueConditionNodeTests + { + [Fact] + public void Clone_BooleanDataType_ReturnsCloneInstance() + { + // Arrange + var expectedConditionType = ConditionType.IsoCountryCode.ToString(); + var expectedOperator = Operators.NotEqual; + var expectedOperand = false; + var expectedLogicalOperator = LogicalOperators.Eval; + var expectedDataType = DataTypes.Boolean; + + var sut = new ValueConditionNode(DataTypes.Boolean, expectedConditionType, expectedOperator, expectedOperand); + sut.Properties["test"] = "test"; + + // Act + var actual = sut.Clone(); + + // Assert + actual.Should() + .NotBeNull() + .And + .BeOfType(); + var valueConditionNode = actual.As(); + valueConditionNode.ConditionType.Should().Be(expectedConditionType); + valueConditionNode.DataType.Should().Be(expectedDataType); + valueConditionNode.LogicalOperator.Should().Be(expectedLogicalOperator); + valueConditionNode.Operator.Should().Be(expectedOperator); + valueConditionNode.Operand.Should().Be(expectedOperand); + valueConditionNode.Properties.Should().BeEquivalentTo(sut.Properties); + } + + [Fact] + public void Clone_DecimalDataType_ReturnsCloneInstance() + { + // Arrange + var expectedConditionType = ConditionType.PluviosityRate.ToString(); + var expectedOperator = Operators.NotEqual; + var expectedOperand = 5682.2654m; + var expectedLogicalOperator = LogicalOperators.Eval; + var expectedDataType = DataTypes.Decimal; + + var sut = new ValueConditionNode(expectedDataType, expectedConditionType, expectedOperator, expectedOperand); + sut.Properties["test"] = "test"; + + // Act + var actual = sut.Clone(); + + // Assert + actual.Should() + .NotBeNull() + .And + .BeOfType(); + var valueConditionNode = actual.As(); + valueConditionNode.ConditionType.Should().Be(expectedConditionType); + valueConditionNode.DataType.Should().Be(expectedDataType); + valueConditionNode.LogicalOperator.Should().Be(expectedLogicalOperator); + valueConditionNode.Operator.Should().Be(expectedOperator); + valueConditionNode.Operand.Should().Be(expectedOperand); + valueConditionNode.Properties.Should().BeEquivalentTo(sut.Properties); + } + + [Fact] + public void Clone_IntegerDataType_ReturnsCloneInstance() + { + // Arrange + var expectedConditionType = ConditionType.IsoCountryCode.ToString(); + var expectedOperator = Operators.NotEqual; + var expectedOperand = 1616; + var expectedLogicalOperator = LogicalOperators.Eval; + var expectedDataType = DataTypes.Integer; + + var sut = new ValueConditionNode(expectedDataType, expectedConditionType, expectedOperator, expectedOperand); + sut.Properties["test"] = "test"; + + // Act + var actual = sut.Clone(); + + // Assert + actual.Should() + .NotBeNull() + .And + .BeOfType(); + var valueConditionNode = actual.As(); + valueConditionNode.ConditionType.Should().Be(expectedConditionType); + valueConditionNode.DataType.Should().Be(expectedDataType); + valueConditionNode.LogicalOperator.Should().Be(expectedLogicalOperator); + valueConditionNode.Operator.Should().Be(expectedOperator); + valueConditionNode.Operand.Should().Be(expectedOperand); + valueConditionNode.Properties.Should().BeEquivalentTo(sut.Properties); + } + + [Fact] + public void Clone_StringDataType_ReturnsCloneInstance() + { + // Arrange + var expectedConditionType = ConditionType.IsoCountryCode.ToString(); + var expectedOperator = Operators.NotEqual; + var expectedOperand = "Such operand, much wow."; + var expectedLogicalOperator = LogicalOperators.Eval; + var expectedDataType = DataTypes.String; + + var sut = new ValueConditionNode(expectedDataType, expectedConditionType, expectedOperator, expectedOperand); + sut.Properties["test"] = "test"; + + // Act + var actual = sut.Clone(); + + // Assert + actual.Should() + .NotBeNull() + .And + .BeOfType(); + var valueConditionNode = actual.As(); + valueConditionNode.ConditionType.Should().Be(expectedConditionType); + valueConditionNode.DataType.Should().Be(expectedDataType); + valueConditionNode.LogicalOperator.Should().Be(expectedLogicalOperator); + valueConditionNode.Operator.Should().Be(expectedOperator); + valueConditionNode.Operand.Should().Be(expectedOperand); + valueConditionNode.Properties.Should().BeEquivalentTo(sut.Properties); + } + + [Fact] + public void Init_GivenSetupWithBooleanValue_ReturnsSettedValues() + { + // Arrange + var expectedConditionType = ConditionType.IsoCountryCode.ToString(); + var expectedOperator = Operators.NotEqual; + var expectedOperand = false; + var expectedLogicalOperator = LogicalOperators.Eval; + var expectedDataType = DataTypes.Boolean; + + var sut = new ValueConditionNode(expectedDataType, expectedConditionType, expectedOperator, expectedOperand); + + // Act + var actualConditionType = sut.ConditionType; + var actualOperator = sut.Operator; + var actualDataType = sut.DataType; + var actualLogicalOperator = sut.LogicalOperator; + var actualOperand = sut.Operand; + + // Assert + actualConditionType.Should().Be(expectedConditionType); + actualOperator.Should().Be(expectedOperator); + actualOperand.Should().Be(expectedOperand); + actualLogicalOperator.Should().Be(expectedLogicalOperator); + actualDataType.Should().Be(expectedDataType); + } + + [Fact] + public void Init_GivenSetupWithDecimalValue_ReturnsSettedValues() + { + // Arrange + var expectedConditionType = ConditionType.PluviosityRate.ToString(); + var expectedOperator = Operators.NotEqual; + var expectedOperand = 5682.2654m; + var expectedLogicalOperator = LogicalOperators.Eval; + var expectedDataType = DataTypes.Decimal; + + var sut = new ValueConditionNode(DataTypes.Decimal, expectedConditionType, expectedOperator, expectedOperand); + + // Act + var actualConditionType = sut.ConditionType; + var actualOperator = sut.Operator; + var actualDataType = sut.DataType; + var actualLogicalOperator = sut.LogicalOperator; + var actualOperand = sut.Operand; + + // Assert + actualConditionType.Should().Be(expectedConditionType); + actualOperator.Should().Be(expectedOperator); + actualOperand.Should().Be(expectedOperand); + actualLogicalOperator.Should().Be(expectedLogicalOperator); + actualDataType.Should().Be(expectedDataType); + } + + [Fact] + public void Init_GivenSetupWithIntegerValue_ReturnsSettedValues() + { + // Arrange + var expectedConditionType = ConditionType.IsoCountryCode.ToString(); + var expectedOperator = Operators.NotEqual; + var expectedOperand = 1616; + var expectedLogicalOperator = LogicalOperators.Eval; + var expectedDataType = DataTypes.Integer; + + var sut = new ValueConditionNode(expectedDataType, expectedConditionType, expectedOperator, expectedOperand); + + // Act + var actualConditionType = sut.ConditionType; + var actualOperator = sut.Operator; + var actualDataType = sut.DataType; + var actualLogicalOperator = sut.LogicalOperator; + var actualOperand = sut.Operand; + + // Assert + actualConditionType.Should().Be(expectedConditionType); + actualOperator.Should().Be(expectedOperator); + actualOperand.Should().Be(expectedOperand); + actualLogicalOperator.Should().Be(expectedLogicalOperator); + actualDataType.Should().Be(expectedDataType); + } + + [Fact] + public void Init_GivenSetupWithStringValue_ReturnsSettedValues() + { + // Arrange + var expectedConditionType = ConditionType.IsoCountryCode.ToString(); + var expectedOperator = Operators.NotEqual; + var expectedOperand = "Such operand, much wow."; + var expectedLogicalOperator = LogicalOperators.Eval; + var expectedDataType = DataTypes.String; + + var sut = new ValueConditionNode(expectedDataType, expectedConditionType, expectedOperator, expectedOperand); + + // Act + var actualConditionType = sut.ConditionType; + var actualOperator = sut.Operator; + var actualDataType = sut.DataType; + var actualLogicalOperator = sut.LogicalOperator; + var actualOperand = sut.Operand; + + // Assert + actualConditionType.Should().Be(expectedConditionType); + actualOperator.Should().Be(expectedOperator); + actualOperand.Should().Be(expectedOperand); + actualLogicalOperator.Should().Be(expectedLogicalOperator); + actualDataType.Should().Be(expectedDataType); + } + } +} \ No newline at end of file diff --git a/tests/Rules.Framework.Tests/ConditionTypeExtractorTests.cs b/tests/Rules.Framework.Tests/ConditionTypeExtractorTests.cs index 6fdf643f..5f6d85f8 100644 --- a/tests/Rules.Framework.Tests/ConditionTypeExtractorTests.cs +++ b/tests/Rules.Framework.Tests/ConditionTypeExtractorTests.cs @@ -3,8 +3,8 @@ namespace Rules.Framework.Tests using System; using System.Collections.Generic; using FluentAssertions; - using Rules.Framework.Core; - using Rules.Framework.Core.ConditionNodes; + using Rules.Framework; + using Rules.Framework.ConditionNodes; using Rules.Framework.Tests.Stubs; using Xunit; @@ -18,52 +18,50 @@ public void GetConditionTypes_ReturnsCorrectExtraction() var dateBegin = new DateTime(2018, 01, 01); var dateEnd = new DateTime(2019, 01, 01); - var contentType = ContentType.Type1; - - var rule1 = new Rule + var rule1 = new Rule { - ContentContainer = new ContentContainer(contentType, _ => new object()), + ContentContainer = new ContentContainer(_ => new object()), DateBegin = dateBegin, DateEnd = dateEnd, Name = "Rule 1", Priority = 3, - RootCondition = new ValueConditionNode(DataTypes.String, ConditionType.IsoCountryCode, Operators.Equal, "USA") + RootCondition = new ValueConditionNode(DataTypes.String, ConditionType.IsoCountryCode.ToString(), Operators.Equal, "USA") }; - var rule2 = new Rule + var rule2 = new Rule { - ContentContainer = new ContentContainer(contentType, _ => new object()), + ContentContainer = new ContentContainer(_ => new object()), DateBegin = new DateTime(2020, 01, 01), DateEnd = new DateTime(2021, 01, 01), Name = "Rule 2", Priority = 200, - RootCondition = new ValueConditionNode(DataTypes.String, ConditionType.IsoCountryCode, Operators.Equal, "USA") + RootCondition = new ValueConditionNode(DataTypes.String, ConditionType.IsoCountryCode.ToString(), Operators.Equal, "USA") }; - var rule3 = new Rule + var rule3 = new Rule { - ContentContainer = new ContentContainer(contentType, _ => new object()), + ContentContainer = new ContentContainer(_ => new object()), DateBegin = dateBegin, DateEnd = dateEnd, Name = "Rule 3", Priority = 1, - RootCondition = new ValueConditionNode(DataTypes.String, ConditionType.IsoCurrency, Operators.Equal, "EUR") + RootCondition = new ValueConditionNode(DataTypes.String, ConditionType.IsoCurrency.ToString(), Operators.Equal, "EUR") }; - var rule4 = new Rule + var rule4 = new Rule { - ContentContainer = new ContentContainer(contentType, _ => new object()), + ContentContainer = new ContentContainer(_ => new object()), DateBegin = dateBegin, DateEnd = dateEnd, Name = "Rule 4", Priority = 1, - RootCondition = new ComposedConditionNode( + RootCondition = new ComposedConditionNode( LogicalOperators.And, - new IConditionNode[] + new IConditionNode[] { - new ValueConditionNode(DataTypes.String,ConditionType.IsVip, Operators.Equal, "true"), - new ValueConditionNode(DataTypes.String,ConditionType.PluviosityRate, Operators.Equal, "15"), - new ValueConditionNode(DataTypes.String,ConditionType.IsoCurrency, Operators.Equal, "JPY") + new ValueConditionNode(DataTypes.String,ConditionType.IsVip.ToString(), Operators.Equal, "true"), + new ValueConditionNode(DataTypes.String,ConditionType.PluviosityRate.ToString(), Operators.Equal, "15"), + new ValueConditionNode(DataTypes.String,ConditionType.IsoCurrency.ToString(), Operators.Equal, "JPY") } ) }; @@ -76,15 +74,15 @@ public void GetConditionTypes_ReturnsCorrectExtraction() rule4 }; - var expectedConditionTypeList = new List + var expectedConditionTypeList = new List { - ConditionType.IsoCurrency, - ConditionType.IsoCountryCode, - ConditionType.IsVip, - ConditionType.PluviosityRate + ConditionType.IsoCurrency.ToString(), + ConditionType.IsoCountryCode.ToString(), + ConditionType.IsVip.ToString(), + ConditionType.PluviosityRate.ToString(), }; - var conditionTypeExtractor = new ConditionTypeExtractor(); + var conditionTypeExtractor = new ConditionTypeExtractor(); // Act var actual = conditionTypeExtractor.GetConditionTypes(matchRules); @@ -98,11 +96,11 @@ public void GetConditionTypes_WithEmptyMatchRules_ReturnsEmptyListConditionTypes { // Arrange - var matchRules = new List>(); + var matchRules = new List(); - var expectedConditionTypeList = new List(); + var expectedConditionTypeList = new List(); - var conditionTypeExtractor = new ConditionTypeExtractor(); + var conditionTypeExtractor = new ConditionTypeExtractor(); // Act var actual = conditionTypeExtractor.GetConditionTypes(matchRules); @@ -119,24 +117,22 @@ public void GetConditionTypes_WithNullRootCondition_ReturnsEmptyListConditionTyp var dateBegin = new DateTime(2018, 01, 01); var dateEnd = new DateTime(2019, 01, 01); - var contentType = ContentType.Type1; - - var matchRules = new List> - { - new Rule + var matchRules = new List { - ContentContainer = new ContentContainer(contentType, _ => new object()), - DateBegin = dateBegin, - DateEnd = dateEnd, - Name = "Rule 3", - Priority = 1, - RootCondition = null - } + new() + { + ContentContainer = new ContentContainer(_ => new object()), + DateBegin = dateBegin, + DateEnd = dateEnd, + Name = "Rule 3", + Priority = 1, + RootCondition = null + } }; - var expectedConditionTypeList = new List(); + var expectedConditionTypeList = new List(); - var conditionTypeExtractor = new ConditionTypeExtractor(); + var conditionTypeExtractor = new ConditionTypeExtractor(); // Act var actual = conditionTypeExtractor.GetConditionTypes(matchRules); diff --git a/tests/Rules.Framework.Tests/Core/ContentContainerTests.cs b/tests/Rules.Framework.Tests/ContentContainerTests.cs similarity index 55% rename from tests/Rules.Framework.Tests/Core/ContentContainerTests.cs rename to tests/Rules.Framework.Tests/ContentContainerTests.cs index 9bbb9338..615497df 100644 --- a/tests/Rules.Framework.Tests/Core/ContentContainerTests.cs +++ b/tests/Rules.Framework.Tests/ContentContainerTests.cs @@ -1,35 +1,19 @@ -namespace Rules.Framework.Tests.Core +namespace Rules.Framework.Tests { using System; using FluentAssertions; - using Rules.Framework.Core; - using Rules.Framework.Tests.Stubs; + using Rules.Framework; using Xunit; public class ContentContainerTests { - [Fact] - public void ContentContainer_ContentType_HavingProvidedContentTypeByCtor_ReturnsProvidedValue() - { - // Arrange - ContentType expected = ContentType.Type1; - - ContentContainer sut = new ContentContainer(expected, (t) => new object()); - - // Act - ContentType actual = sut.ContentType; - - // Assert - actual.Should().Be(expected); - } - [Fact] public void ContentContainer_GetContentAs_HavingProvidedContentByCtorAndGivenCorrectRuntimeType_ReturnsProvidedValue() { // Arrange object expected = "Just some content"; - ContentContainer sut = new ContentContainer(ContentType.Type1, (t) => expected); + var sut = new ContentContainer(_ => expected); // Act object actual = sut.GetContentAs(); @@ -44,10 +28,10 @@ public void ContentContainer_GetContentAs_HavingProvidedContentByCtorAndGivenWro // Arrange object expected = "Just some content"; - ContentContainer sut = new ContentContainer(ContentType.Type1, (t) => expected); + var sut = new ContentContainer(_ => expected); // Act - ContentTypeException contentTypeException = Assert.Throws(() => sut.GetContentAs()); + var contentTypeException = Assert.Throws(() => sut.GetContentAs()); // Assert contentTypeException.Should().NotBeNull(); diff --git a/tests/Rules.Framework.Tests/Core/ConditionNodes/BooleanConditionNodeTests.cs b/tests/Rules.Framework.Tests/Core/ConditionNodes/BooleanConditionNodeTests.cs deleted file mode 100644 index 5351c9b1..00000000 --- a/tests/Rules.Framework.Tests/Core/ConditionNodes/BooleanConditionNodeTests.cs +++ /dev/null @@ -1,68 +0,0 @@ -namespace Rules.Framework.Tests.Core.ConditionNodes -{ - using FluentAssertions; - using Rules.Framework.Core; - using Rules.Framework.Core.ConditionNodes; - using Rules.Framework.Tests.Stubs; - using Xunit; - - public class BooleanConditionNodeTests - { - [Fact] - public void Clone_NoConditions_ReturnsCloneInstance() - { - // Arrange - var expectedConditionType = ConditionType.IsoCountryCode; - var expectedOperator = Operators.NotEqual; - var expectedOperand = false; - var expectedLogicalOperator = LogicalOperators.Eval; - var expectedDataType = DataTypes.Boolean; - - var sut = new ValueConditionNode(DataTypes.Boolean, expectedConditionType, expectedOperator, expectedOperand); - sut.Properties["test"] = "test"; - - // Act - var actual = sut.Clone(); - - // Assert - actual.Should() - .NotBeNull() - .And - .BeOfType>(); - var valueConditionNode = actual.As>(); - valueConditionNode.ConditionType.Should().Be(expectedConditionType); - valueConditionNode.DataType.Should().Be(expectedDataType); - valueConditionNode.LogicalOperator.Should().Be(expectedLogicalOperator); - valueConditionNode.Operator.Should().Be(expectedOperator); - valueConditionNode.Operand.Should().Be(expectedOperand); - valueConditionNode.Properties.Should().BeEquivalentTo(sut.Properties); - } - - [Fact] - public void Init_GivenSetupWithBooleanValue_ReturnsSettedValues() - { - // Arrange - var expectedConditionType = ConditionType.IsoCountryCode; - var expectedOperator = Operators.NotEqual; - var expectedOperand = false; - var expectedLogicalOperator = LogicalOperators.Eval; - var expectedDataType = DataTypes.Boolean; - - var sut = new ValueConditionNode(expectedDataType, expectedConditionType, expectedOperator, expectedOperand); - - // Act - var actualConditionType = sut.ConditionType; - var actualOperator = sut.Operator; - var actualDataType = sut.DataType; - var actualLogicalOperator = sut.LogicalOperator; - var actualOperand = sut.Operand; - - // Assert - actualConditionType.Should().Be(expectedConditionType); - actualOperator.Should().Be(expectedOperator); - actualOperand.Should().Be(expectedOperand); - actualLogicalOperator.Should().Be(expectedLogicalOperator); - actualDataType.Should().Be(expectedDataType); - } - } -} \ No newline at end of file diff --git a/tests/Rules.Framework.Tests/Core/ConditionNodes/DecimalConditionNodeTests.cs b/tests/Rules.Framework.Tests/Core/ConditionNodes/DecimalConditionNodeTests.cs deleted file mode 100644 index 92d6e95f..00000000 --- a/tests/Rules.Framework.Tests/Core/ConditionNodes/DecimalConditionNodeTests.cs +++ /dev/null @@ -1,68 +0,0 @@ -namespace Rules.Framework.Tests.Core.ConditionNodes -{ - using FluentAssertions; - using Rules.Framework.Core; - using Rules.Framework.Core.ConditionNodes; - using Rules.Framework.Tests.Stubs; - using Xunit; - - public class DecimalConditionNodeTests - { - [Fact] - public void Clone_NoConditions_ReturnsCloneInstance() - { - // Arrange - var expectedConditionType = ConditionType.PluviosityRate; - var expectedOperator = Operators.NotEqual; - var expectedOperand = 5682.2654m; - var expectedLogicalOperator = LogicalOperators.Eval; - var expectedDataType = DataTypes.Decimal; - - var sut = new ValueConditionNode(expectedDataType, expectedConditionType, expectedOperator, expectedOperand); - sut.Properties["test"] = "test"; - - // Act - var actual = sut.Clone(); - - // Assert - actual.Should() - .NotBeNull() - .And - .BeOfType>(); - var valueConditionNode = actual.As>(); - valueConditionNode.ConditionType.Should().Be(expectedConditionType); - valueConditionNode.DataType.Should().Be(expectedDataType); - valueConditionNode.LogicalOperator.Should().Be(expectedLogicalOperator); - valueConditionNode.Operator.Should().Be(expectedOperator); - valueConditionNode.Operand.Should().Be(expectedOperand); - valueConditionNode.Properties.Should().BeEquivalentTo(sut.Properties); - } - - [Fact] - public void Init_GivenSetupWithDecimalValue_ReturnsSettedValues() - { - // Arrange - var expectedConditionType = ConditionType.PluviosityRate; - var expectedOperator = Operators.NotEqual; - var expectedOperand = 5682.2654m; - var expectedLogicalOperator = LogicalOperators.Eval; - var expectedDataType = DataTypes.Decimal; - - var sut = new ValueConditionNode(DataTypes.Decimal, expectedConditionType, expectedOperator, expectedOperand); - - // Act - var actualConditionType = sut.ConditionType; - var actualOperator = sut.Operator; - var actualDataType = sut.DataType; - var actualLogicalOperator = sut.LogicalOperator; - var actualOperand = sut.Operand; - - // Assert - actualConditionType.Should().Be(expectedConditionType); - actualOperator.Should().Be(expectedOperator); - actualOperand.Should().Be(expectedOperand); - actualLogicalOperator.Should().Be(expectedLogicalOperator); - actualDataType.Should().Be(expectedDataType); - } - } -} \ No newline at end of file diff --git a/tests/Rules.Framework.Tests/Core/ConditionNodes/IntegerConditionNodeTests.cs b/tests/Rules.Framework.Tests/Core/ConditionNodes/IntegerConditionNodeTests.cs deleted file mode 100644 index 8fbe4b6e..00000000 --- a/tests/Rules.Framework.Tests/Core/ConditionNodes/IntegerConditionNodeTests.cs +++ /dev/null @@ -1,68 +0,0 @@ -namespace Rules.Framework.Tests.Core.ConditionNodes -{ - using FluentAssertions; - using Rules.Framework.Core; - using Rules.Framework.Core.ConditionNodes; - using Rules.Framework.Tests.Stubs; - using Xunit; - - public class IntegerConditionNodeTests - { - [Fact] - public void Clone_NoConditions_ReturnsCloneInstance() - { - // Arrange - var expectedConditionType = ConditionType.IsoCountryCode; - var expectedOperator = Operators.NotEqual; - var expectedOperand = 1616; - var expectedLogicalOperator = LogicalOperators.Eval; - var expectedDataType = DataTypes.Integer; - - var sut = new ValueConditionNode(expectedDataType, expectedConditionType, expectedOperator, expectedOperand); - sut.Properties["test"] = "test"; - - // Act - var actual = sut.Clone(); - - // Assert - actual.Should() - .NotBeNull() - .And - .BeOfType>(); - var valueConditionNode = actual.As>(); - valueConditionNode.ConditionType.Should().Be(expectedConditionType); - valueConditionNode.DataType.Should().Be(expectedDataType); - valueConditionNode.LogicalOperator.Should().Be(expectedLogicalOperator); - valueConditionNode.Operator.Should().Be(expectedOperator); - valueConditionNode.Operand.Should().Be(expectedOperand); - valueConditionNode.Properties.Should().BeEquivalentTo(sut.Properties); - } - - [Fact] - public void Init_GivenSetupWithIntegerValue_ReturnsSettedValues() - { - // Arrange - var expectedConditionType = ConditionType.IsoCountryCode; - var expectedOperator = Operators.NotEqual; - var expectedOperand = 1616; - var expectedLogicalOperator = LogicalOperators.Eval; - var expectedDataType = DataTypes.Integer; - - var sut = new ValueConditionNode(expectedDataType, expectedConditionType, expectedOperator, expectedOperand); - - // Act - var actualConditionType = sut.ConditionType; - var actualOperator = sut.Operator; - var actualDataType = sut.DataType; - var actualLogicalOperator = sut.LogicalOperator; - var actualOperand = sut.Operand; - - // Assert - actualConditionType.Should().Be(expectedConditionType); - actualOperator.Should().Be(expectedOperator); - actualOperand.Should().Be(expectedOperand); - actualLogicalOperator.Should().Be(expectedLogicalOperator); - actualDataType.Should().Be(expectedDataType); - } - } -} \ No newline at end of file diff --git a/tests/Rules.Framework.Tests/Core/ConditionNodes/StringConditionNodeTests.cs b/tests/Rules.Framework.Tests/Core/ConditionNodes/StringConditionNodeTests.cs deleted file mode 100644 index 55727d71..00000000 --- a/tests/Rules.Framework.Tests/Core/ConditionNodes/StringConditionNodeTests.cs +++ /dev/null @@ -1,68 +0,0 @@ -namespace Rules.Framework.Tests.Core.ConditionNodes -{ - using FluentAssertions; - using Rules.Framework.Core; - using Rules.Framework.Core.ConditionNodes; - using Rules.Framework.Tests.Stubs; - using Xunit; - - public class StringConditionNodeTests - { - [Fact] - public void Clone_NoConditions_ReturnsCloneInstance() - { - // Arrange - var expectedConditionType = ConditionType.IsoCountryCode; - var expectedOperator = Operators.NotEqual; - var expectedOperand = "Such operand, much wow."; - var expectedLogicalOperator = LogicalOperators.Eval; - var expectedDataType = DataTypes.String; - - var sut = new ValueConditionNode(expectedDataType, expectedConditionType, expectedOperator, expectedOperand); - sut.Properties["test"] = "test"; - - // Act - var actual = sut.Clone(); - - // Assert - actual.Should() - .NotBeNull() - .And - .BeOfType>(); - var valueConditionNode = actual.As>(); - valueConditionNode.ConditionType.Should().Be(expectedConditionType); - valueConditionNode.DataType.Should().Be(expectedDataType); - valueConditionNode.LogicalOperator.Should().Be(expectedLogicalOperator); - valueConditionNode.Operator.Should().Be(expectedOperator); - valueConditionNode.Operand.Should().Be(expectedOperand); - valueConditionNode.Properties.Should().BeEquivalentTo(sut.Properties); - } - - [Fact] - public void Init_GivenSetupWithStringValue_ReturnsSettedValues() - { - // Arrange - var expectedConditionType = ConditionType.IsoCountryCode; - var expectedOperator = Operators.NotEqual; - var expectedOperand = "Such operand, much wow."; - var expectedLogicalOperator = LogicalOperators.Eval; - var expectedDataType = DataTypes.String; - - var sut = new ValueConditionNode(expectedDataType, expectedConditionType, expectedOperator, expectedOperand); - - // Act - var actualConditionType = sut.ConditionType; - var actualOperator = sut.Operator; - var actualDataType = sut.DataType; - var actualLogicalOperator = sut.LogicalOperator; - var actualOperand = sut.Operand; - - // Assert - actualConditionType.Should().Be(expectedConditionType); - actualOperator.Should().Be(expectedOperator); - actualOperand.Should().Be(expectedOperand); - actualLogicalOperator.Should().Be(expectedLogicalOperator); - actualDataType.Should().Be(expectedDataType); - } - } -} \ No newline at end of file diff --git a/tests/Rules.Framework.Tests/Evaluation/Compiled/CompilationRulesSourceMiddlewareTests.cs b/tests/Rules.Framework.Tests/Evaluation/Compiled/CompilationRulesSourceMiddlewareTests.cs index 3404db54..800fdc6f 100644 --- a/tests/Rules.Framework.Tests/Evaluation/Compiled/CompilationRulesSourceMiddlewareTests.cs +++ b/tests/Rules.Framework.Tests/Evaluation/Compiled/CompilationRulesSourceMiddlewareTests.cs @@ -7,7 +7,8 @@ namespace Rules.Framework.Tests.Evaluation.Compiled using System.Threading.Tasks; using FluentAssertions; using Moq; - using Rules.Framework.Builder; + using Rules.Framework; + using Rules.Framework.Builder.Generic; using Rules.Framework.Core; using Rules.Framework.Evaluation.Compiled; using Rules.Framework.Source; @@ -26,39 +27,39 @@ public async Task HandleAddRuleAsync_GivenRuleWithCompiledConditionAndNextDelega // Simulate compiled rule. expectedRule.RootCondition.Properties[ConditionNodeProperties.CompilationProperties.IsCompiledKey] = true; - var addRuleArgs = new AddRuleArgs + var addRuleArgs = new AddRuleArgs { Rule = expectedRule, }; - bool nextDelegateWasInvoked = false; - var nextDelegate = new AddRuleDelegate((_) => + var nextDelegateWasInvoked = false; + var nextDelegate = new AddRuleDelegate((_) => { nextDelegateWasInvoked = true; return Task.CompletedTask; }); - Expression, bool>> expectedExpression = (_) => true; + Expression> expectedExpression = (_) => true; - var ruleConditionsExpressionBuilder = Mock.Of>(); + var ruleConditionsExpressionBuilder = Mock.Of(); Mock.Get(ruleConditionsExpressionBuilder) - .Setup(x => x.BuildExpression(It.IsAny>())) + .Setup(x => x.BuildExpression(It.IsAny())) .Returns(expectedExpression); - var rulesDataSource = Mock.Of>(); + var rulesDataSource = Mock.Of(); - var compilationRulesSourceMiddleware = new CompilationRulesSourceMiddleware( + var compilationRulesSourceMiddleware = new CompilationRulesSourceMiddleware( ruleConditionsExpressionBuilder, rulesDataSource); // Act - await compilationRulesSourceMiddleware.HandleAddRuleAsync(addRuleArgs, nextDelegate).ConfigureAwait(false); + await compilationRulesSourceMiddleware.HandleAddRuleAsync(addRuleArgs, nextDelegate); // Assert nextDelegateWasInvoked.Should().BeTrue(); Mock.Get(ruleConditionsExpressionBuilder) - .Verify(x => x.BuildExpression(It.IsAny>()), Times.Never()); + .Verify(x => x.BuildExpression(It.IsAny()), Times.Never()); } [Fact] @@ -68,39 +69,39 @@ public async Task HandleAddRuleAsync_GivenRuleWithoutConditionsAndNextDelegate_I var ruleResult = CreateTestRule(withCondition: false); var expectedRule = ruleResult.Rule; - var addRuleArgs = new AddRuleArgs + var addRuleArgs = new AddRuleArgs { Rule = expectedRule, }; - bool nextDelegateWasInvoked = false; - var nextDelegate = new AddRuleDelegate((_) => + var nextDelegateWasInvoked = false; + var nextDelegate = new AddRuleDelegate((_) => { nextDelegateWasInvoked = true; return Task.CompletedTask; }); - Expression, bool>> expectedExpression = (_) => true; + Expression> expectedExpression = (_) => true; - var ruleConditionsExpressionBuilder = Mock.Of>(); + var ruleConditionsExpressionBuilder = Mock.Of(); Mock.Get(ruleConditionsExpressionBuilder) - .Setup(x => x.BuildExpression(It.IsAny>())) + .Setup(x => x.BuildExpression(It.IsAny())) .Returns(expectedExpression); - var rulesDataSource = Mock.Of>(); + var rulesDataSource = Mock.Of(); - var compilationRulesSourceMiddleware = new CompilationRulesSourceMiddleware( + var compilationRulesSourceMiddleware = new CompilationRulesSourceMiddleware( ruleConditionsExpressionBuilder, rulesDataSource); // Act - await compilationRulesSourceMiddleware.HandleAddRuleAsync(addRuleArgs, nextDelegate).ConfigureAwait(false); + await compilationRulesSourceMiddleware.HandleAddRuleAsync(addRuleArgs, nextDelegate); // Assert nextDelegateWasInvoked.Should().BeTrue(); Mock.Get(ruleConditionsExpressionBuilder) - .Verify(x => x.BuildExpression(It.IsAny>()), Times.Never()); + .Verify(x => x.BuildExpression(It.IsAny()), Times.Never()); } [Fact] @@ -110,40 +111,40 @@ public async Task HandleAddRuleAsync_GivenRuleWithUncompiledConditionAndNextDele var ruleResult = CreateTestRule(withCondition: true); var expectedRule = ruleResult.Rule; - var addRuleArgs = new AddRuleArgs + var addRuleArgs = new AddRuleArgs { Rule = expectedRule, }; - bool nextDelegateWasInvoked = false; - var nextDelegate = new AddRuleDelegate((_) => + var nextDelegateWasInvoked = false; + var nextDelegate = new AddRuleDelegate((_) => { nextDelegateWasInvoked = true; return Task.CompletedTask; }); - Expression, bool>> expectedExpression = (_) => true; + Expression> expectedExpression = (_) => true; - var ruleConditionsExpressionBuilder = Mock.Of>(); + var ruleConditionsExpressionBuilder = Mock.Of(); Mock.Get(ruleConditionsExpressionBuilder) - .Setup(x => x.BuildExpression(It.IsAny>())) + .Setup(x => x.BuildExpression(It.IsAny())) .Returns(expectedExpression); - var rulesDataSource = Mock.Of>(); + var rulesDataSource = Mock.Of(); - var compilationRulesSourceMiddleware = new CompilationRulesSourceMiddleware( + var compilationRulesSourceMiddleware = new CompilationRulesSourceMiddleware( ruleConditionsExpressionBuilder, rulesDataSource); // Act - await compilationRulesSourceMiddleware.HandleAddRuleAsync(addRuleArgs, nextDelegate).ConfigureAwait(false); + await compilationRulesSourceMiddleware.HandleAddRuleAsync(addRuleArgs, nextDelegate); // Assert expectedRule.RootCondition.Properties.Should().HaveCount(2); expectedRule.RootCondition.Properties.Should().ContainKey(ConditionNodeProperties.CompilationProperties.IsCompiledKey) .WhoseValue.Should().Be(true); expectedRule.RootCondition.Properties.Should().ContainKey(ConditionNodeProperties.CompilationProperties.CompiledDelegateKey) - .WhoseValue.Should().BeOfType, bool>>(); + .WhoseValue.Should().BeOfType>(); nextDelegateWasInvoked.Should().BeTrue(); Mock.VerifyAll( @@ -159,48 +160,48 @@ public async Task HandleGetRulesAsync_GivenArgsFilteringToRulesWithCompiledCondi // Simulate compiled rule. expectedRule.RootCondition.Properties[ConditionNodeProperties.CompilationProperties.IsCompiledKey] = true; - var expectedRules = new[] { expectedRule }; + var expectedRules = new Rule[] { expectedRule }; - var getRulesArgs = new GetRulesArgs + var getRulesArgs = new GetRulesArgs { - ContentType = ContentType.Type1, + ContentType = ContentType.Type1.ToString(), DateBegin = DateTime.UtcNow.AddDays(-1), DateEnd = DateTime.UtcNow.AddDays(1), }; - bool nextDelegateWasInvoked = false; - var nextDelegate = new GetRulesDelegate((_) => + var nextDelegateWasInvoked = false; + var nextDelegate = new GetRulesDelegate((_) => { nextDelegateWasInvoked = true; - return Task.FromResult>>(expectedRules); + return Task.FromResult>(expectedRules); }); - Expression, bool>> expectedExpression = (_) => true; + Expression> expectedExpression = (_) => true; - var ruleConditionsExpressionBuilder = Mock.Of>(); + var ruleConditionsExpressionBuilder = Mock.Of(); Mock.Get(ruleConditionsExpressionBuilder) - .Setup(x => x.BuildExpression(It.IsAny>())) + .Setup(x => x.BuildExpression(It.IsAny())) .Returns(expectedExpression); - var rulesDataSource = Mock.Of>(); + var rulesDataSource = Mock.Of(); Mock.Get(rulesDataSource) - .Setup(x => x.UpdateRuleAsync(It.IsAny>())); + .Setup(x => x.UpdateRuleAsync(It.IsAny())); - var compilationRulesSourceMiddleware = new CompilationRulesSourceMiddleware( + var compilationRulesSourceMiddleware = new CompilationRulesSourceMiddleware( ruleConditionsExpressionBuilder, rulesDataSource); // Act - var actualRules = await compilationRulesSourceMiddleware.HandleGetRulesAsync(getRulesArgs, nextDelegate).ConfigureAwait(false); + var actualRules = await compilationRulesSourceMiddleware.HandleGetRulesAsync(getRulesArgs, nextDelegate); // Assert actualRules.Should().BeEquivalentTo(expectedRules); nextDelegateWasInvoked.Should().BeTrue(); Mock.Get(ruleConditionsExpressionBuilder) - .Verify(x => x.BuildExpression(It.IsAny>()), Times.Never()); + .Verify(x => x.BuildExpression(It.IsAny()), Times.Never()); Mock.Get(rulesDataSource) - .Verify(x => x.UpdateRuleAsync(It.IsAny>()), Times.Never()); + .Verify(x => x.UpdateRuleAsync(It.IsAny()), Times.Never()); } [Fact] @@ -209,48 +210,48 @@ public async Task HandleGetRulesAsync_GivenArgsFilteringToRulesWithoutConditions // Arrange var ruleResult = CreateTestRule(withCondition: false); var expectedRule = ruleResult.Rule; - var expectedRules = new[] { expectedRule }; + var expectedRules = new Rule[] { expectedRule }; - var getRulesArgs = new GetRulesArgs + var getRulesArgs = new GetRulesArgs { - ContentType = ContentType.Type1, + ContentType = ContentType.Type1.ToString(), DateBegin = DateTime.UtcNow.AddDays(-1), DateEnd = DateTime.UtcNow.AddDays(1), }; - bool nextDelegateWasInvoked = false; - var nextDelegate = new GetRulesDelegate((_) => + var nextDelegateWasInvoked = false; + var nextDelegate = new GetRulesDelegate((_) => { nextDelegateWasInvoked = true; - return Task.FromResult>>(expectedRules); + return Task.FromResult>(expectedRules); }); - Expression, bool>> expectedExpression = (_) => true; + Expression> expectedExpression = (_) => true; - var ruleConditionsExpressionBuilder = Mock.Of>(); + var ruleConditionsExpressionBuilder = Mock.Of(); Mock.Get(ruleConditionsExpressionBuilder) - .Setup(x => x.BuildExpression(It.IsAny>())) + .Setup(x => x.BuildExpression(It.IsAny())) .Returns(expectedExpression); - var rulesDataSource = Mock.Of>(); + var rulesDataSource = Mock.Of(); Mock.Get(rulesDataSource) - .Setup(x => x.UpdateRuleAsync(It.IsAny>())); + .Setup(x => x.UpdateRuleAsync(It.IsAny())); - var compilationRulesSourceMiddleware = new CompilationRulesSourceMiddleware( + var compilationRulesSourceMiddleware = new CompilationRulesSourceMiddleware( ruleConditionsExpressionBuilder, rulesDataSource); // Act - var actualRules = await compilationRulesSourceMiddleware.HandleGetRulesAsync(getRulesArgs, nextDelegate).ConfigureAwait(false); + var actualRules = await compilationRulesSourceMiddleware.HandleGetRulesAsync(getRulesArgs, nextDelegate); // Assert actualRules.Should().BeEquivalentTo(expectedRules); nextDelegateWasInvoked.Should().BeTrue(); Mock.Get(ruleConditionsExpressionBuilder) - .Verify(x => x.BuildExpression(It.IsAny>()), Times.Never()); + .Verify(x => x.BuildExpression(It.IsAny()), Times.Never()); Mock.Get(rulesDataSource) - .Verify(x => x.UpdateRuleAsync(It.IsAny>()), Times.Never()); + .Verify(x => x.UpdateRuleAsync(It.IsAny()), Times.Never()); } [Fact] @@ -259,39 +260,39 @@ public async Task HandleGetRulesAsync_GivenArgsFilteringToRulesWithUncompiledCon // Arrange var ruleResult = CreateTestRule(withCondition: true); var expectedRule = ruleResult.Rule; - var expectedRules = new[] { expectedRule }; + var expectedRules = new Rule[] { expectedRule }; - var getRulesArgs = new GetRulesArgs + var getRulesArgs = new GetRulesArgs { - ContentType = ContentType.Type1, + ContentType = ContentType.Type1.ToString(), DateBegin = DateTime.UtcNow.AddDays(-1), DateEnd = DateTime.UtcNow.AddDays(1), }; - bool nextDelegateWasInvoked = false; - var nextDelegate = new GetRulesDelegate((_) => + var nextDelegateWasInvoked = false; + var nextDelegate = new GetRulesDelegate((_) => { nextDelegateWasInvoked = true; - return Task.FromResult>>(expectedRules); + return Task.FromResult>(expectedRules); }); - Expression, bool>> expectedExpression = (_) => true; + Expression> expectedExpression = (_) => true; - var ruleConditionsExpressionBuilder = Mock.Of>(); + var ruleConditionsExpressionBuilder = Mock.Of(); Mock.Get(ruleConditionsExpressionBuilder) - .Setup(x => x.BuildExpression(It.IsAny>())) + .Setup(x => x.BuildExpression(It.IsAny())) .Returns(expectedExpression); - var rulesDataSource = Mock.Of>(); + var rulesDataSource = Mock.Of(); Mock.Get(rulesDataSource) - .Setup(x => x.UpdateRuleAsync(It.IsAny>())); + .Setup(x => x.UpdateRuleAsync(It.IsAny())); - var compilationRulesSourceMiddleware = new CompilationRulesSourceMiddleware( + var compilationRulesSourceMiddleware = new CompilationRulesSourceMiddleware( ruleConditionsExpressionBuilder, rulesDataSource); // Act - var actualRules = await compilationRulesSourceMiddleware.HandleGetRulesAsync(getRulesArgs, nextDelegate).ConfigureAwait(false); + var actualRules = await compilationRulesSourceMiddleware.HandleGetRulesAsync(getRulesArgs, nextDelegate); // Assert actualRules.Should().HaveCount(1); @@ -300,7 +301,7 @@ public async Task HandleGetRulesAsync_GivenArgsFilteringToRulesWithUncompiledCon actualRule.RootCondition.Properties.Should().ContainKey(ConditionNodeProperties.CompilationProperties.IsCompiledKey) .WhoseValue.Should().Be(true); actualRule.RootCondition.Properties.Should().ContainKey(ConditionNodeProperties.CompilationProperties.CompiledDelegateKey) - .WhoseValue.Should().BeOfType, bool>>(); + .WhoseValue.Should().BeOfType>(); nextDelegateWasInvoked.Should().BeTrue(); Mock.VerifyAll( @@ -317,46 +318,46 @@ public async Task HandleGetRulesFilteredAsync_GivenArgsFilteringToRulesWithCompi // Simulate compiled rule. expectedRule.RootCondition.Properties[ConditionNodeProperties.CompilationProperties.IsCompiledKey] = true; - var expectedRules = new[] { expectedRule }; + var expectedRules = new Rule[] { expectedRule }; - var getRulesFilteredArgs = new GetRulesFilteredArgs + var getRulesFilteredArgs = new GetRulesFilteredArgs { - ContentType = ContentType.Type1, + ContentType = ContentType.Type1.ToString(), }; - bool nextDelegateWasInvoked = false; - var nextDelegate = new GetRulesFilteredDelegate((_) => + var nextDelegateWasInvoked = false; + var nextDelegate = new GetRulesFilteredDelegate((_) => { nextDelegateWasInvoked = true; - return Task.FromResult>>(expectedRules); + return Task.FromResult>(expectedRules); }); - Expression, bool>> expectedExpression = (_) => true; + Expression> expectedExpression = (_) => true; - var ruleConditionsExpressionBuilder = Mock.Of>(); + var ruleConditionsExpressionBuilder = Mock.Of(); Mock.Get(ruleConditionsExpressionBuilder) - .Setup(x => x.BuildExpression(It.IsAny>())) + .Setup(x => x.BuildExpression(It.IsAny())) .Returns(expectedExpression); - var rulesDataSource = Mock.Of>(); + var rulesDataSource = Mock.Of(); Mock.Get(rulesDataSource) - .Setup(x => x.UpdateRuleAsync(It.IsAny>())); + .Setup(x => x.UpdateRuleAsync(It.IsAny())); - var compilationRulesSourceMiddleware = new CompilationRulesSourceMiddleware( + var compilationRulesSourceMiddleware = new CompilationRulesSourceMiddleware( ruleConditionsExpressionBuilder, rulesDataSource); // Act - var actualRules = await compilationRulesSourceMiddleware.HandleGetRulesFilteredAsync(getRulesFilteredArgs, nextDelegate).ConfigureAwait(false); + var actualRules = await compilationRulesSourceMiddleware.HandleGetRulesFilteredAsync(getRulesFilteredArgs, nextDelegate); // Assert actualRules.Should().BeEquivalentTo(expectedRules); nextDelegateWasInvoked.Should().BeTrue(); Mock.Get(ruleConditionsExpressionBuilder) - .Verify(x => x.BuildExpression(It.IsAny>()), Times.Never()); + .Verify(x => x.BuildExpression(It.IsAny()), Times.Never()); Mock.Get(rulesDataSource) - .Verify(x => x.UpdateRuleAsync(It.IsAny>()), Times.Never()); + .Verify(x => x.UpdateRuleAsync(It.IsAny()), Times.Never()); } [Fact] @@ -365,46 +366,46 @@ public async Task HandleGetRulesFilteredAsync_GivenArgsFilteringToRulesWithoutCo // Arrange var ruleResult = CreateTestRule(withCondition: false); var expectedRule = ruleResult.Rule; - var expectedRules = new[] { expectedRule }; + var expectedRules = new Rule[] { expectedRule }; - var getRulesFilteredArgs = new GetRulesFilteredArgs + var getRulesFilteredArgs = new GetRulesFilteredArgs { - ContentType = ContentType.Type1, + ContentType = ContentType.Type1.ToString(), }; - bool nextDelegateWasInvoked = false; - var nextDelegate = new GetRulesFilteredDelegate((_) => + var nextDelegateWasInvoked = false; + var nextDelegate = new GetRulesFilteredDelegate((_) => { nextDelegateWasInvoked = true; - return Task.FromResult>>(expectedRules); + return Task.FromResult>(expectedRules); }); - Expression, bool>> expectedExpression = (_) => true; + Expression> expectedExpression = (_) => true; - var ruleConditionsExpressionBuilder = Mock.Of>(); + var ruleConditionsExpressionBuilder = Mock.Of(); Mock.Get(ruleConditionsExpressionBuilder) - .Setup(x => x.BuildExpression(It.IsAny>())) + .Setup(x => x.BuildExpression(It.IsAny())) .Returns(expectedExpression); - var rulesDataSource = Mock.Of>(); + var rulesDataSource = Mock.Of(); Mock.Get(rulesDataSource) - .Setup(x => x.UpdateRuleAsync(It.IsAny>())); + .Setup(x => x.UpdateRuleAsync(It.IsAny())); - var compilationRulesSourceMiddleware = new CompilationRulesSourceMiddleware( + var compilationRulesSourceMiddleware = new CompilationRulesSourceMiddleware( ruleConditionsExpressionBuilder, rulesDataSource); // Act - var actualRules = await compilationRulesSourceMiddleware.HandleGetRulesFilteredAsync(getRulesFilteredArgs, nextDelegate).ConfigureAwait(false); + var actualRules = await compilationRulesSourceMiddleware.HandleGetRulesFilteredAsync(getRulesFilteredArgs, nextDelegate); // Assert actualRules.Should().BeEquivalentTo(expectedRules); nextDelegateWasInvoked.Should().BeTrue(); Mock.Get(ruleConditionsExpressionBuilder) - .Verify(x => x.BuildExpression(It.IsAny>()), Times.Never()); + .Verify(x => x.BuildExpression(It.IsAny()), Times.Never()); Mock.Get(rulesDataSource) - .Verify(x => x.UpdateRuleAsync(It.IsAny>()), Times.Never()); + .Verify(x => x.UpdateRuleAsync(It.IsAny()), Times.Never()); } [Fact] @@ -413,37 +414,37 @@ public async Task HandleGetRulesFilteredAsync_GivenArgsFilteringToRulesWithUncom // Arrange var ruleResult = CreateTestRule(withCondition: true); var expectedRule = ruleResult.Rule; - var expectedRules = new[] { expectedRule }; + var expectedRules = new Rule[] { expectedRule }; - var getRulesFilteredArgs = new GetRulesFilteredArgs + var getRulesFilteredArgs = new GetRulesFilteredArgs { - ContentType = ContentType.Type1, + ContentType = ContentType.Type1.ToString(), }; - bool nextDelegateWasInvoked = false; - var nextDelegate = new GetRulesFilteredDelegate((_) => + var nextDelegateWasInvoked = false; + var nextDelegate = new GetRulesFilteredDelegate((_) => { nextDelegateWasInvoked = true; - return Task.FromResult>>(expectedRules); + return Task.FromResult>(expectedRules); }); - Expression, bool>> expectedExpression = (_) => true; + Expression> expectedExpression = (_) => true; - var ruleConditionsExpressionBuilder = Mock.Of>(); + var ruleConditionsExpressionBuilder = Mock.Of(); Mock.Get(ruleConditionsExpressionBuilder) - .Setup(x => x.BuildExpression(It.IsAny>())) + .Setup(x => x.BuildExpression(It.IsAny())) .Returns(expectedExpression); - var rulesDataSource = Mock.Of>(); + var rulesDataSource = Mock.Of(); Mock.Get(rulesDataSource) - .Setup(x => x.UpdateRuleAsync(It.IsAny>())); + .Setup(x => x.UpdateRuleAsync(It.IsAny())); - var compilationRulesSourceMiddleware = new CompilationRulesSourceMiddleware( + var compilationRulesSourceMiddleware = new CompilationRulesSourceMiddleware( ruleConditionsExpressionBuilder, rulesDataSource); // Act - var actualRules = await compilationRulesSourceMiddleware.HandleGetRulesFilteredAsync(getRulesFilteredArgs, nextDelegate).ConfigureAwait(false); + var actualRules = await compilationRulesSourceMiddleware.HandleGetRulesFilteredAsync(getRulesFilteredArgs, nextDelegate); // Assert actualRules.Should().HaveCount(1); @@ -452,7 +453,7 @@ public async Task HandleGetRulesFilteredAsync_GivenArgsFilteringToRulesWithUncom actualRule.RootCondition.Properties.Should().ContainKey(ConditionNodeProperties.CompilationProperties.IsCompiledKey) .WhoseValue.Should().Be(true); actualRule.RootCondition.Properties.Should().ContainKey(ConditionNodeProperties.CompilationProperties.CompiledDelegateKey) - .WhoseValue.Should().BeOfType, bool>>(); + .WhoseValue.Should().BeOfType>(); nextDelegateWasInvoked.Should().BeTrue(); Mock.VerifyAll( @@ -470,39 +471,39 @@ public async Task HandleUpdateRuleAsync_GivenRuleWithCompiledConditionAndNextDel // Simulate compiled rule. expectedRule.RootCondition.Properties[ConditionNodeProperties.CompilationProperties.IsCompiledKey] = true; - var updateRuleArgs = new UpdateRuleArgs + var updateRuleArgs = new UpdateRuleArgs { Rule = expectedRule, }; - bool nextDelegateWasInvoked = false; - var nextDelegate = new UpdateRuleDelegate((_) => + var nextDelegateWasInvoked = false; + var nextDelegate = new UpdateRuleDelegate((_) => { nextDelegateWasInvoked = true; return Task.CompletedTask; }); - Expression, bool>> expectedExpression = (_) => true; + Expression> expectedExpression = (_) => true; - var ruleConditionsExpressionBuilder = Mock.Of>(); + var ruleConditionsExpressionBuilder = Mock.Of(); Mock.Get(ruleConditionsExpressionBuilder) - .Setup(x => x.BuildExpression(It.IsAny>())) + .Setup(x => x.BuildExpression(It.IsAny())) .Returns(expectedExpression); - var rulesDataSource = Mock.Of>(); + var rulesDataSource = Mock.Of(); - var compilationRulesSourceMiddleware = new CompilationRulesSourceMiddleware( + var compilationRulesSourceMiddleware = new CompilationRulesSourceMiddleware( ruleConditionsExpressionBuilder, rulesDataSource); // Act - await compilationRulesSourceMiddleware.HandleUpdateRuleAsync(updateRuleArgs, nextDelegate).ConfigureAwait(false); + await compilationRulesSourceMiddleware.HandleUpdateRuleAsync(updateRuleArgs, nextDelegate); // Assert nextDelegateWasInvoked.Should().BeTrue(); Mock.Get(ruleConditionsExpressionBuilder) - .Verify(x => x.BuildExpression(It.IsAny>()), Times.Never()); + .Verify(x => x.BuildExpression(It.IsAny()), Times.Never()); } [Fact] @@ -512,39 +513,39 @@ public async Task HandleUpdateRuleAsync_GivenRuleWithoutConditionsAndNextDelegat var ruleResult = CreateTestRule(withCondition: false); var expectedRule = ruleResult.Rule; - var updateRuleArgs = new UpdateRuleArgs + var updateRuleArgs = new UpdateRuleArgs { Rule = expectedRule, }; - bool nextDelegateWasInvoked = false; - var nextDelegate = new UpdateRuleDelegate((_) => + var nextDelegateWasInvoked = false; + var nextDelegate = new UpdateRuleDelegate((_) => { nextDelegateWasInvoked = true; return Task.CompletedTask; }); - Expression, bool>> expectedExpression = (_) => true; + Expression> expectedExpression = (_) => true; - var ruleConditionsExpressionBuilder = Mock.Of>(); + var ruleConditionsExpressionBuilder = Mock.Of(); Mock.Get(ruleConditionsExpressionBuilder) - .Setup(x => x.BuildExpression(It.IsAny>())) + .Setup(x => x.BuildExpression(It.IsAny())) .Returns(expectedExpression); - var rulesDataSource = Mock.Of>(); + var rulesDataSource = Mock.Of(); - var compilationRulesSourceMiddleware = new CompilationRulesSourceMiddleware( + var compilationRulesSourceMiddleware = new CompilationRulesSourceMiddleware( ruleConditionsExpressionBuilder, rulesDataSource); // Act - await compilationRulesSourceMiddleware.HandleUpdateRuleAsync(updateRuleArgs, nextDelegate).ConfigureAwait(false); + await compilationRulesSourceMiddleware.HandleUpdateRuleAsync(updateRuleArgs, nextDelegate); // Assert nextDelegateWasInvoked.Should().BeTrue(); Mock.Get(ruleConditionsExpressionBuilder) - .Verify(x => x.BuildExpression(It.IsAny>()), Times.Never()); + .Verify(x => x.BuildExpression(It.IsAny()), Times.Never()); } [Fact] @@ -554,40 +555,40 @@ public async Task HandleUpdateRuleAsync_GivenRuleWithUncompiledConditionAndNextD var ruleResult = CreateTestRule(withCondition: true); var expectedRule = ruleResult.Rule; - var updateRuleArgs = new UpdateRuleArgs + var updateRuleArgs = new UpdateRuleArgs { Rule = expectedRule, }; - bool nextDelegateWasInvoked = false; - var nextDelegate = new UpdateRuleDelegate((_) => + var nextDelegateWasInvoked = false; + var nextDelegate = new UpdateRuleDelegate((_) => { nextDelegateWasInvoked = true; return Task.CompletedTask; }); - Expression, bool>> expectedExpression = (_) => true; + Expression> expectedExpression = (_) => true; - var ruleConditionsExpressionBuilder = Mock.Of>(); + var ruleConditionsExpressionBuilder = Mock.Of(); Mock.Get(ruleConditionsExpressionBuilder) - .Setup(x => x.BuildExpression(It.IsAny>())) + .Setup(x => x.BuildExpression(It.IsAny())) .Returns(expectedExpression); - var rulesDataSource = Mock.Of>(); + var rulesDataSource = Mock.Of(); - var compilationRulesSourceMiddleware = new CompilationRulesSourceMiddleware( + var compilationRulesSourceMiddleware = new CompilationRulesSourceMiddleware( ruleConditionsExpressionBuilder, rulesDataSource); // Act - await compilationRulesSourceMiddleware.HandleUpdateRuleAsync(updateRuleArgs, nextDelegate).ConfigureAwait(false); + await compilationRulesSourceMiddleware.HandleUpdateRuleAsync(updateRuleArgs, nextDelegate); // Assert expectedRule.RootCondition.Properties.Should().HaveCount(2); expectedRule.RootCondition.Properties.Should().ContainKey(ConditionNodeProperties.CompilationProperties.IsCompiledKey) .WhoseValue.Should().Be(true); expectedRule.RootCondition.Properties.Should().ContainKey(ConditionNodeProperties.CompilationProperties.CompiledDelegateKey) - .WhoseValue.Should().BeOfType, bool>>(); + .WhoseValue.Should().BeOfType>(); nextDelegateWasInvoked.Should().BeTrue(); Mock.VerifyAll( @@ -596,7 +597,7 @@ public async Task HandleUpdateRuleAsync_GivenRuleWithUncompiledConditionAndNextD private static RuleBuilderResult CreateTestRule(bool withCondition) { - var ruleBuilder = RuleBuilder.NewRule() + var ruleBuilder = Rule.New() .WithName("Test rule") .WithDateBegin(DateTime.UtcNow) .WithContent(ContentType.Type1, "Test content"); diff --git a/tests/Rules.Framework.Tests/Evaluation/Compiled/CompiledConditionsEvalEngineTests.cs b/tests/Rules.Framework.Tests/Evaluation/Compiled/CompiledConditionsEvalEngineTests.cs index 37d665a5..83fb21d9 100644 --- a/tests/Rules.Framework.Tests/Evaluation/Compiled/CompiledConditionsEvalEngineTests.cs +++ b/tests/Rules.Framework.Tests/Evaluation/Compiled/CompiledConditionsEvalEngineTests.cs @@ -4,7 +4,8 @@ namespace Rules.Framework.Tests.Evaluation.Compiled using System.Collections.Generic; using FluentAssertions; using Moq; - using Rules.Framework.Builder; + using Rules.Framework; + using Rules.Framework.Builder.Generic; using Rules.Framework.Core; using Rules.Framework.Evaluation; using Rules.Framework.Evaluation.Compiled; @@ -18,24 +19,24 @@ public void Eval_GivenCompiledConditionNodeConditionsAndExcludeRulesWithoutSearc { // Arrange var ruleResult = CreateTestRule(); - var expectedRule = ruleResult.Rule; - Func, bool> expectedExpression = (_) => true; + var expectedRule = (Rule)ruleResult.Rule; + Func expectedExpression = (_) => true; expectedRule.RootCondition.Properties[ConditionNodeProperties.CompilationProperties.CompiledDelegateKey] = expectedExpression; - var conditions = new Dictionary(); + var conditions = new Dictionary(); var evaluationOptions = new EvaluationOptions { ExcludeRulesWithoutSearchConditions = true, MatchMode = MatchModes.Exact, }; - var conditionsTreeAnalyzer = Mock.Of>(); + var conditionsTreeAnalyzer = Mock.Of(); Mock.Get(conditionsTreeAnalyzer) - .Setup(x => x.AreAllSearchConditionsPresent(It.IsAny>(), It.IsAny>())) + .Setup(x => x.AreAllSearchConditionsPresent(It.IsAny(), It.IsAny>())) .Returns(false); var rulesEngineOptions = RulesEngineOptions.NewWithDefaults(); - var compiledConditionsEvalEngine = new CompiledConditionsEvalEngine(conditionsTreeAnalyzer, rulesEngineOptions); + var compiledConditionsEvalEngine = new CompiledConditionsEvalEngine(conditionsTreeAnalyzer, rulesEngineOptions); // Act var result = compiledConditionsEvalEngine.Eval(expectedRule.RootCondition, conditions, evaluationOptions); @@ -49,24 +50,24 @@ public void Eval_GivenCompiledConditionNodeConditionsAndExcludeRulesWithoutSearc { // Arrange var ruleResult = CreateTestRule(); - var expectedRule = ruleResult.Rule; - Func, bool> expectedExpression = (_) => true; + var expectedRule = (Rule)ruleResult.Rule; + Func expectedExpression = (_) => true; expectedRule.RootCondition.Properties[ConditionNodeProperties.CompilationProperties.CompiledDelegateKey] = expectedExpression; - var conditions = new Dictionary(); + var conditions = new Dictionary(); var evaluationOptions = new EvaluationOptions { ExcludeRulesWithoutSearchConditions = true, MatchMode = MatchModes.Exact, }; - var conditionsTreeAnalyzer = Mock.Of>(); + var conditionsTreeAnalyzer = Mock.Of(); Mock.Get(conditionsTreeAnalyzer) - .Setup(x => x.AreAllSearchConditionsPresent(It.IsAny>(), It.IsAny>())) + .Setup(x => x.AreAllSearchConditionsPresent(It.IsAny(), It.IsAny>())) .Returns(true); var rulesEngineOptions = RulesEngineOptions.NewWithDefaults(); - var compiledConditionsEvalEngine = new CompiledConditionsEvalEngine(conditionsTreeAnalyzer, rulesEngineOptions); + var compiledConditionsEvalEngine = new CompiledConditionsEvalEngine(conditionsTreeAnalyzer, rulesEngineOptions); // Act var result = compiledConditionsEvalEngine.Eval(expectedRule.RootCondition, conditions, evaluationOptions); @@ -80,21 +81,21 @@ public void Eval_GivenCompiledConditionNodeConditionsAndIncludeRulesWithoutSearc { // Arrange var ruleResult = CreateTestRule(); - var expectedRule = ruleResult.Rule; - Func, bool> expectedExpression = (_) => true; + var expectedRule = (Rule)ruleResult.Rule; + Func expectedExpression = (_) => true; expectedRule.RootCondition.Properties[ConditionNodeProperties.CompilationProperties.CompiledDelegateKey] = expectedExpression; - var conditions = new Dictionary(); + var conditions = new Dictionary(); var evaluationOptions = new EvaluationOptions { ExcludeRulesWithoutSearchConditions = false, MatchMode = MatchModes.Exact, }; - var conditionsTreeAnalyzer = Mock.Of>(); + var conditionsTreeAnalyzer = Mock.Of(); var rulesEngineOptions = RulesEngineOptions.NewWithDefaults(); - var compiledConditionsEvalEngine = new CompiledConditionsEvalEngine(conditionsTreeAnalyzer, rulesEngineOptions); + var compiledConditionsEvalEngine = new CompiledConditionsEvalEngine(conditionsTreeAnalyzer, rulesEngineOptions); // Act var result = compiledConditionsEvalEngine.Eval(expectedRule.RootCondition, conditions, evaluationOptions); @@ -108,19 +109,19 @@ public void Eval_GivenUncompiledConditionNodeConditionsAndIncludeRulesWithoutSea { // Arrange var ruleResult = CreateTestRule(); - var expectedRule = ruleResult.Rule; - var conditions = new Dictionary(); + var expectedRule = (Rule)ruleResult.Rule; + var conditions = new Dictionary(); var evaluationOptions = new EvaluationOptions { ExcludeRulesWithoutSearchConditions = false, MatchMode = MatchModes.Exact, }; - var conditionsTreeAnalyzer = Mock.Of>(); + var conditionsTreeAnalyzer = Mock.Of(); var rulesEngineOptions = RulesEngineOptions.NewWithDefaults(); - var compiledConditionsEvalEngine = new CompiledConditionsEvalEngine(conditionsTreeAnalyzer, rulesEngineOptions); + var compiledConditionsEvalEngine = new CompiledConditionsEvalEngine(conditionsTreeAnalyzer, rulesEngineOptions); // Act var action = FluentActions.Invoking(() => compiledConditionsEvalEngine.Eval(expectedRule.RootCondition, conditions, evaluationOptions)); @@ -130,7 +131,7 @@ public void Eval_GivenUncompiledConditionNodeConditionsAndIncludeRulesWithoutSea .Which.ParamName.Should().Be("conditionNode"); } - private static RuleBuilderResult CreateTestRule() => RuleBuilder.NewRule() + private static RuleBuilderResult CreateTestRule() => Rule.New() .WithName("Test rule") .WithDateBegin(DateTime.UtcNow) .WithContent(ContentType.Type1, "Test content") diff --git a/tests/Rules.Framework.Tests/Evaluation/Compiled/ConditionBuilders/CaseInsensitiveEndsWithOneToOneConditionExpressionBuilderTests.cs b/tests/Rules.Framework.Tests/Evaluation/Compiled/ConditionBuilders/CaseInsensitiveEndsWithOneToOneConditionExpressionBuilderTests.cs index 839d0a47..55d102e7 100644 --- a/tests/Rules.Framework.Tests/Evaluation/Compiled/ConditionBuilders/CaseInsensitiveEndsWithOneToOneConditionExpressionBuilderTests.cs +++ b/tests/Rules.Framework.Tests/Evaluation/Compiled/ConditionBuilders/CaseInsensitiveEndsWithOneToOneConditionExpressionBuilderTests.cs @@ -4,7 +4,7 @@ namespace Rules.Framework.Tests.Evaluation.Compiled.ConditionBuilders using System.Linq.Expressions; using FluentAssertions; using Moq; - using Rules.Framework.Core; + using Rules.Framework; using Rules.Framework.Evaluation; using Rules.Framework.Evaluation.Compiled.ConditionBuilders; using Rules.Framework.Evaluation.Compiled.ExpressionBuilders; diff --git a/tests/Rules.Framework.Tests/Evaluation/Compiled/ConditionBuilders/CaseInsensitiveStartsWithOneToOneConditionExpressionBuilderTests.cs b/tests/Rules.Framework.Tests/Evaluation/Compiled/ConditionBuilders/CaseInsensitiveStartsWithOneToOneConditionExpressionBuilderTests.cs index f34dab4e..09e2daee 100644 --- a/tests/Rules.Framework.Tests/Evaluation/Compiled/ConditionBuilders/CaseInsensitiveStartsWithOneToOneConditionExpressionBuilderTests.cs +++ b/tests/Rules.Framework.Tests/Evaluation/Compiled/ConditionBuilders/CaseInsensitiveStartsWithOneToOneConditionExpressionBuilderTests.cs @@ -4,7 +4,7 @@ namespace Rules.Framework.Tests.Evaluation.Compiled.ConditionBuilders using System.Linq.Expressions; using FluentAssertions; using Moq; - using Rules.Framework.Core; + using Rules.Framework; using Rules.Framework.Evaluation; using Rules.Framework.Evaluation.Compiled.ConditionBuilders; using Rules.Framework.Evaluation.Compiled.ExpressionBuilders; diff --git a/tests/Rules.Framework.Tests/Evaluation/Compiled/ConditionBuilders/ConditionExpressionBuilderProviderTests.cs b/tests/Rules.Framework.Tests/Evaluation/Compiled/ConditionBuilders/ConditionExpressionBuilderProviderTests.cs index c55b877d..76a395ec 100644 --- a/tests/Rules.Framework.Tests/Evaluation/Compiled/ConditionBuilders/ConditionExpressionBuilderProviderTests.cs +++ b/tests/Rules.Framework.Tests/Evaluation/Compiled/ConditionBuilders/ConditionExpressionBuilderProviderTests.cs @@ -4,7 +4,7 @@ namespace Rules.Framework.Tests.Evaluation.Compiled.ConditionBuilders using System.Collections.Generic; using System.Linq; using FluentAssertions; - using Rules.Framework.Core; + using Rules.Framework; using Rules.Framework.Evaluation; using Rules.Framework.Evaluation.Compiled.ConditionBuilders; using Xunit; diff --git a/tests/Rules.Framework.Tests/Evaluation/Compiled/ConditionBuilders/ContainsManyToOneConditionExpressionBuilderTests.cs b/tests/Rules.Framework.Tests/Evaluation/Compiled/ConditionBuilders/ContainsManyToOneConditionExpressionBuilderTests.cs index 8c6f178e..396c2e91 100644 --- a/tests/Rules.Framework.Tests/Evaluation/Compiled/ConditionBuilders/ContainsManyToOneConditionExpressionBuilderTests.cs +++ b/tests/Rules.Framework.Tests/Evaluation/Compiled/ConditionBuilders/ContainsManyToOneConditionExpressionBuilderTests.cs @@ -5,7 +5,7 @@ namespace Rules.Framework.Tests.Evaluation.Compiled.ConditionBuilders using System.Linq.Expressions; using FluentAssertions; using Moq; - using Rules.Framework.Core; + using Rules.Framework; using Rules.Framework.Evaluation; using Rules.Framework.Evaluation.Compiled.ConditionBuilders; using Rules.Framework.Evaluation.Compiled.ExpressionBuilders; diff --git a/tests/Rules.Framework.Tests/Evaluation/Compiled/ConditionBuilders/ContainsOneToOneConditionExpressionBuilderTests.cs b/tests/Rules.Framework.Tests/Evaluation/Compiled/ConditionBuilders/ContainsOneToOneConditionExpressionBuilderTests.cs index 6ac094cf..04eb2ad4 100644 --- a/tests/Rules.Framework.Tests/Evaluation/Compiled/ConditionBuilders/ContainsOneToOneConditionExpressionBuilderTests.cs +++ b/tests/Rules.Framework.Tests/Evaluation/Compiled/ConditionBuilders/ContainsOneToOneConditionExpressionBuilderTests.cs @@ -4,7 +4,7 @@ namespace Rules.Framework.Tests.Evaluation.Compiled.ConditionBuilders using System.Linq.Expressions; using FluentAssertions; using Moq; - using Rules.Framework.Core; + using Rules.Framework; using Rules.Framework.Evaluation; using Rules.Framework.Evaluation.Compiled.ConditionBuilders; using Rules.Framework.Evaluation.Compiled.ExpressionBuilders; diff --git a/tests/Rules.Framework.Tests/Evaluation/Compiled/ConditionBuilders/EndsWithOneToOneConditionExpressionBuilderTests.cs b/tests/Rules.Framework.Tests/Evaluation/Compiled/ConditionBuilders/EndsWithOneToOneConditionExpressionBuilderTests.cs index 711c2726..682a9e1e 100644 --- a/tests/Rules.Framework.Tests/Evaluation/Compiled/ConditionBuilders/EndsWithOneToOneConditionExpressionBuilderTests.cs +++ b/tests/Rules.Framework.Tests/Evaluation/Compiled/ConditionBuilders/EndsWithOneToOneConditionExpressionBuilderTests.cs @@ -4,7 +4,7 @@ namespace Rules.Framework.Tests.Evaluation.Compiled.ConditionBuilders using System.Linq.Expressions; using FluentAssertions; using Moq; - using Rules.Framework.Core; + using Rules.Framework; using Rules.Framework.Evaluation; using Rules.Framework.Evaluation.Compiled.ConditionBuilders; using Rules.Framework.Evaluation.Compiled.ExpressionBuilders; diff --git a/tests/Rules.Framework.Tests/Evaluation/Compiled/ConditionBuilders/EqualOneToOneConditionExpressionBuilderTests.cs b/tests/Rules.Framework.Tests/Evaluation/Compiled/ConditionBuilders/EqualOneToOneConditionExpressionBuilderTests.cs index 3ceff59b..ed19cde9 100644 --- a/tests/Rules.Framework.Tests/Evaluation/Compiled/ConditionBuilders/EqualOneToOneConditionExpressionBuilderTests.cs +++ b/tests/Rules.Framework.Tests/Evaluation/Compiled/ConditionBuilders/EqualOneToOneConditionExpressionBuilderTests.cs @@ -3,7 +3,7 @@ namespace Rules.Framework.Tests.Evaluation.Compiled.ConditionBuilders using System; using System.Linq.Expressions; using FluentAssertions; - using Rules.Framework.Core; + using Rules.Framework; using Rules.Framework.Evaluation; using Rules.Framework.Evaluation.Compiled.ConditionBuilders; using Rules.Framework.Evaluation.Compiled.ExpressionBuilders; diff --git a/tests/Rules.Framework.Tests/Evaluation/Compiled/ConditionBuilders/GreaterThanOneToOneConditionExpressionBuilderTests.cs b/tests/Rules.Framework.Tests/Evaluation/Compiled/ConditionBuilders/GreaterThanOneToOneConditionExpressionBuilderTests.cs index 682973cf..50e426fa 100644 --- a/tests/Rules.Framework.Tests/Evaluation/Compiled/ConditionBuilders/GreaterThanOneToOneConditionExpressionBuilderTests.cs +++ b/tests/Rules.Framework.Tests/Evaluation/Compiled/ConditionBuilders/GreaterThanOneToOneConditionExpressionBuilderTests.cs @@ -4,7 +4,7 @@ namespace Rules.Framework.Tests.Evaluation.Compiled.ConditionBuilders using System.Linq.Expressions; using FluentAssertions; using Moq; - using Rules.Framework.Core; + using Rules.Framework; using Rules.Framework.Evaluation; using Rules.Framework.Evaluation.Compiled.ConditionBuilders; using Rules.Framework.Evaluation.Compiled.ExpressionBuilders; diff --git a/tests/Rules.Framework.Tests/Evaluation/Compiled/ConditionBuilders/GreaterThanOrEqualOneToOneConditionExpressionBuilderTests.cs b/tests/Rules.Framework.Tests/Evaluation/Compiled/ConditionBuilders/GreaterThanOrEqualOneToOneConditionExpressionBuilderTests.cs index aa6f5bd2..8337c74d 100644 --- a/tests/Rules.Framework.Tests/Evaluation/Compiled/ConditionBuilders/GreaterThanOrEqualOneToOneConditionExpressionBuilderTests.cs +++ b/tests/Rules.Framework.Tests/Evaluation/Compiled/ConditionBuilders/GreaterThanOrEqualOneToOneConditionExpressionBuilderTests.cs @@ -4,7 +4,7 @@ namespace Rules.Framework.Tests.Evaluation.Compiled.ConditionBuilders using System.Linq.Expressions; using FluentAssertions; using Moq; - using Rules.Framework.Core; + using Rules.Framework; using Rules.Framework.Evaluation; using Rules.Framework.Evaluation.Compiled.ConditionBuilders; using Rules.Framework.Evaluation.Compiled.ExpressionBuilders; diff --git a/tests/Rules.Framework.Tests/Evaluation/Compiled/ConditionBuilders/InOneToManyConditionExpressionBuilderTests.cs b/tests/Rules.Framework.Tests/Evaluation/Compiled/ConditionBuilders/InOneToManyConditionExpressionBuilderTests.cs index 14e7c059..fb17027d 100644 --- a/tests/Rules.Framework.Tests/Evaluation/Compiled/ConditionBuilders/InOneToManyConditionExpressionBuilderTests.cs +++ b/tests/Rules.Framework.Tests/Evaluation/Compiled/ConditionBuilders/InOneToManyConditionExpressionBuilderTests.cs @@ -4,7 +4,7 @@ namespace Rules.Framework.Tests.Evaluation.Compiled.ConditionBuilders using System.Collections.Generic; using System.Linq.Expressions; using FluentAssertions; - using Rules.Framework.Core; + using Rules.Framework; using Rules.Framework.Evaluation; using Rules.Framework.Evaluation.Compiled.ConditionBuilders; using Rules.Framework.Evaluation.Compiled.ExpressionBuilders; diff --git a/tests/Rules.Framework.Tests/Evaluation/Compiled/ConditionBuilders/LesserThanOneToOneConditionExpressionBuilderTests.cs b/tests/Rules.Framework.Tests/Evaluation/Compiled/ConditionBuilders/LesserThanOneToOneConditionExpressionBuilderTests.cs index f1b0e1c1..360fd3a2 100644 --- a/tests/Rules.Framework.Tests/Evaluation/Compiled/ConditionBuilders/LesserThanOneToOneConditionExpressionBuilderTests.cs +++ b/tests/Rules.Framework.Tests/Evaluation/Compiled/ConditionBuilders/LesserThanOneToOneConditionExpressionBuilderTests.cs @@ -4,7 +4,7 @@ namespace Rules.Framework.Tests.Evaluation.Compiled.ConditionBuilders using System.Linq.Expressions; using FluentAssertions; using Moq; - using Rules.Framework.Core; + using Rules.Framework; using Rules.Framework.Evaluation; using Rules.Framework.Evaluation.Compiled.ConditionBuilders; using Rules.Framework.Evaluation.Compiled.ExpressionBuilders; diff --git a/tests/Rules.Framework.Tests/Evaluation/Compiled/ConditionBuilders/LesserThanOrEqualOneToOneConditionExpressionBuilderTests.cs b/tests/Rules.Framework.Tests/Evaluation/Compiled/ConditionBuilders/LesserThanOrEqualOneToOneConditionExpressionBuilderTests.cs index 5bf384c9..579f25a2 100644 --- a/tests/Rules.Framework.Tests/Evaluation/Compiled/ConditionBuilders/LesserThanOrEqualOneToOneConditionExpressionBuilderTests.cs +++ b/tests/Rules.Framework.Tests/Evaluation/Compiled/ConditionBuilders/LesserThanOrEqualOneToOneConditionExpressionBuilderTests.cs @@ -4,7 +4,7 @@ namespace Rules.Framework.Tests.Evaluation.Compiled.ConditionBuilders using System.Linq.Expressions; using FluentAssertions; using Moq; - using Rules.Framework.Core; + using Rules.Framework; using Rules.Framework.Evaluation; using Rules.Framework.Evaluation.Compiled.ConditionBuilders; using Rules.Framework.Evaluation.Compiled.ExpressionBuilders; diff --git a/tests/Rules.Framework.Tests/Evaluation/Compiled/ConditionBuilders/NotContainsOneToOneConditionExpressionBuilderTests.cs b/tests/Rules.Framework.Tests/Evaluation/Compiled/ConditionBuilders/NotContainsOneToOneConditionExpressionBuilderTests.cs index dd78a75f..db72bd95 100644 --- a/tests/Rules.Framework.Tests/Evaluation/Compiled/ConditionBuilders/NotContainsOneToOneConditionExpressionBuilderTests.cs +++ b/tests/Rules.Framework.Tests/Evaluation/Compiled/ConditionBuilders/NotContainsOneToOneConditionExpressionBuilderTests.cs @@ -4,7 +4,7 @@ namespace Rules.Framework.Tests.Evaluation.Compiled.ConditionBuilders using System.Linq.Expressions; using FluentAssertions; using Moq; - using Rules.Framework.Core; + using Rules.Framework; using Rules.Framework.Evaluation; using Rules.Framework.Evaluation.Compiled.ConditionBuilders; using Rules.Framework.Evaluation.Compiled.ExpressionBuilders; diff --git a/tests/Rules.Framework.Tests/Evaluation/Compiled/ConditionBuilders/NotEndsWithOneToOneConditionExpressionBuilderTests.cs b/tests/Rules.Framework.Tests/Evaluation/Compiled/ConditionBuilders/NotEndsWithOneToOneConditionExpressionBuilderTests.cs index a0c79782..5abccab1 100644 --- a/tests/Rules.Framework.Tests/Evaluation/Compiled/ConditionBuilders/NotEndsWithOneToOneConditionExpressionBuilderTests.cs +++ b/tests/Rules.Framework.Tests/Evaluation/Compiled/ConditionBuilders/NotEndsWithOneToOneConditionExpressionBuilderTests.cs @@ -4,7 +4,7 @@ namespace Rules.Framework.Tests.Evaluation.Compiled.ConditionBuilders using System.Linq.Expressions; using FluentAssertions; using Moq; - using Rules.Framework.Core; + using Rules.Framework; using Rules.Framework.Evaluation; using Rules.Framework.Evaluation.Compiled.ConditionBuilders; using Rules.Framework.Evaluation.Compiled.ExpressionBuilders; diff --git a/tests/Rules.Framework.Tests/Evaluation/Compiled/ConditionBuilders/NotEqualOneToOneConditionExpressionBuilderTests.cs b/tests/Rules.Framework.Tests/Evaluation/Compiled/ConditionBuilders/NotEqualOneToOneConditionExpressionBuilderTests.cs index cf0849fe..9d874e55 100644 --- a/tests/Rules.Framework.Tests/Evaluation/Compiled/ConditionBuilders/NotEqualOneToOneConditionExpressionBuilderTests.cs +++ b/tests/Rules.Framework.Tests/Evaluation/Compiled/ConditionBuilders/NotEqualOneToOneConditionExpressionBuilderTests.cs @@ -3,7 +3,7 @@ namespace Rules.Framework.Tests.Evaluation.Compiled.ConditionBuilders using System; using System.Linq.Expressions; using FluentAssertions; - using Rules.Framework.Core; + using Rules.Framework; using Rules.Framework.Evaluation; using Rules.Framework.Evaluation.Compiled.ConditionBuilders; using Rules.Framework.Evaluation.Compiled.ExpressionBuilders; diff --git a/tests/Rules.Framework.Tests/Evaluation/Compiled/ConditionBuilders/NotInOneToManyConditionExpressionBuilderTests.cs b/tests/Rules.Framework.Tests/Evaluation/Compiled/ConditionBuilders/NotInOneToManyConditionExpressionBuilderTests.cs index b29060c5..237a786b 100644 --- a/tests/Rules.Framework.Tests/Evaluation/Compiled/ConditionBuilders/NotInOneToManyConditionExpressionBuilderTests.cs +++ b/tests/Rules.Framework.Tests/Evaluation/Compiled/ConditionBuilders/NotInOneToManyConditionExpressionBuilderTests.cs @@ -4,7 +4,7 @@ namespace Rules.Framework.Tests.Evaluation.Compiled.ConditionBuilders using System.Collections.Generic; using System.Linq.Expressions; using FluentAssertions; - using Rules.Framework.Core; + using Rules.Framework; using Rules.Framework.Evaluation; using Rules.Framework.Evaluation.Compiled.ConditionBuilders; using Rules.Framework.Evaluation.Compiled.ExpressionBuilders; diff --git a/tests/Rules.Framework.Tests/Evaluation/Compiled/ConditionBuilders/NotStartsWithOneToOneConditionExpressionBuilderTests.cs b/tests/Rules.Framework.Tests/Evaluation/Compiled/ConditionBuilders/NotStartsWithOneToOneConditionExpressionBuilderTests.cs index 44237c8e..cedd1a03 100644 --- a/tests/Rules.Framework.Tests/Evaluation/Compiled/ConditionBuilders/NotStartsWithOneToOneConditionExpressionBuilderTests.cs +++ b/tests/Rules.Framework.Tests/Evaluation/Compiled/ConditionBuilders/NotStartsWithOneToOneConditionExpressionBuilderTests.cs @@ -4,7 +4,7 @@ namespace Rules.Framework.Tests.Evaluation.Compiled.ConditionBuilders using System.Linq.Expressions; using FluentAssertions; using Moq; - using Rules.Framework.Core; + using Rules.Framework; using Rules.Framework.Evaluation; using Rules.Framework.Evaluation.Compiled.ConditionBuilders; using Rules.Framework.Evaluation.Compiled.ExpressionBuilders; diff --git a/tests/Rules.Framework.Tests/Evaluation/Compiled/ConditionBuilders/StartsWithOneToOneConditionExpressionBuilderTests.cs b/tests/Rules.Framework.Tests/Evaluation/Compiled/ConditionBuilders/StartsWithOneToOneConditionExpressionBuilderTests.cs index 309f222c..4d1f3b65 100644 --- a/tests/Rules.Framework.Tests/Evaluation/Compiled/ConditionBuilders/StartsWithOneToOneConditionExpressionBuilderTests.cs +++ b/tests/Rules.Framework.Tests/Evaluation/Compiled/ConditionBuilders/StartsWithOneToOneConditionExpressionBuilderTests.cs @@ -4,7 +4,7 @@ namespace Rules.Framework.Tests.Evaluation.Compiled.ConditionBuilders using System.Linq.Expressions; using FluentAssertions; using Moq; - using Rules.Framework.Core; + using Rules.Framework; using Rules.Framework.Evaluation; using Rules.Framework.Evaluation.Compiled.ConditionBuilders; using Rules.Framework.Evaluation.Compiled.ExpressionBuilders; diff --git a/tests/Rules.Framework.Tests/Evaluation/Compiled/ConditionsValueLookupExtensionTests.cs b/tests/Rules.Framework.Tests/Evaluation/Compiled/ConditionsValueLookupExtensionTests.cs index eb0f10ee..cf2d0153 100644 --- a/tests/Rules.Framework.Tests/Evaluation/Compiled/ConditionsValueLookupExtensionTests.cs +++ b/tests/Rules.Framework.Tests/Evaluation/Compiled/ConditionsValueLookupExtensionTests.cs @@ -13,11 +13,11 @@ public void GetValueOrDefault_GivenConditionsDictionaryAndConditionType_ReturnsN { // Arrange const string expected = "EUR"; - var conditions = new Dictionary + var conditions = new Dictionary { - { ConditionType.IsoCurrency, expected } + { ConditionType.IsoCurrency.ToString(), expected } }; - var conditionType = ConditionType.IsoCurrency; + var conditionType = ConditionType.IsoCurrency.ToString(); // Act var result = ConditionsValueLookupExtension.GetValueOrDefault(conditions, conditionType); @@ -30,8 +30,8 @@ public void GetValueOrDefault_GivenConditionsDictionaryAndConditionType_ReturnsN public void GetValueOrDefault_GivenEmptyConditionsDictionaryAndConditionType_ReturnsNull() { // Arrange - var conditions = new Dictionary(); - var conditionType = ConditionType.IsoCurrency; + var conditions = new Dictionary(); + var conditionType = ConditionType.IsoCurrency.ToString(); // Act var result = ConditionsValueLookupExtension.GetValueOrDefault(conditions, conditionType); diff --git a/tests/Rules.Framework.Tests/Evaluation/Compiled/ManyToManyValueConditionNodeExpressionBuilderTests.cs b/tests/Rules.Framework.Tests/Evaluation/Compiled/ManyToManyValueConditionNodeExpressionBuilderTests.cs index 9760f3c2..232c649d 100644 --- a/tests/Rules.Framework.Tests/Evaluation/Compiled/ManyToManyValueConditionNodeExpressionBuilderTests.cs +++ b/tests/Rules.Framework.Tests/Evaluation/Compiled/ManyToManyValueConditionNodeExpressionBuilderTests.cs @@ -9,7 +9,7 @@ namespace Rules.Framework.Tests.Evaluation.Compiled using ExpressionDebugger; using FluentAssertions; using Moq; - using Rules.Framework.Core; + using Rules.Framework; using Rules.Framework.Evaluation; using Rules.Framework.Evaluation.Compiled; using Rules.Framework.Evaluation.Compiled.ConditionBuilders; diff --git a/tests/Rules.Framework.Tests/Evaluation/Compiled/ManyToOneValueConditionNodeExpressionBuilderTests.cs b/tests/Rules.Framework.Tests/Evaluation/Compiled/ManyToOneValueConditionNodeExpressionBuilderTests.cs index a1a246e8..b68a3c93 100644 --- a/tests/Rules.Framework.Tests/Evaluation/Compiled/ManyToOneValueConditionNodeExpressionBuilderTests.cs +++ b/tests/Rules.Framework.Tests/Evaluation/Compiled/ManyToOneValueConditionNodeExpressionBuilderTests.cs @@ -9,7 +9,7 @@ namespace Rules.Framework.Tests.Evaluation.Compiled using ExpressionDebugger; using FluentAssertions; using Moq; - using Rules.Framework.Core; + using Rules.Framework; using Rules.Framework.Evaluation; using Rules.Framework.Evaluation.Compiled; using Rules.Framework.Evaluation.Compiled.ConditionBuilders; diff --git a/tests/Rules.Framework.Tests/Evaluation/Compiled/OneToManyValueConditionNodeExpressionBuilderTests.cs b/tests/Rules.Framework.Tests/Evaluation/Compiled/OneToManyValueConditionNodeExpressionBuilderTests.cs index 91166a93..54841ece 100644 --- a/tests/Rules.Framework.Tests/Evaluation/Compiled/OneToManyValueConditionNodeExpressionBuilderTests.cs +++ b/tests/Rules.Framework.Tests/Evaluation/Compiled/OneToManyValueConditionNodeExpressionBuilderTests.cs @@ -9,7 +9,7 @@ namespace Rules.Framework.Tests.Evaluation.Compiled using ExpressionDebugger; using FluentAssertions; using Moq; - using Rules.Framework.Core; + using Rules.Framework; using Rules.Framework.Evaluation; using Rules.Framework.Evaluation.Compiled; using Rules.Framework.Evaluation.Compiled.ConditionBuilders; diff --git a/tests/Rules.Framework.Tests/Evaluation/Compiled/OneToOneValueConditionNodeExpressionBuilderTests.cs b/tests/Rules.Framework.Tests/Evaluation/Compiled/OneToOneValueConditionNodeExpressionBuilderTests.cs index d7445e07..173189ea 100644 --- a/tests/Rules.Framework.Tests/Evaluation/Compiled/OneToOneValueConditionNodeExpressionBuilderTests.cs +++ b/tests/Rules.Framework.Tests/Evaluation/Compiled/OneToOneValueConditionNodeExpressionBuilderTests.cs @@ -8,7 +8,7 @@ namespace Rules.Framework.Tests.Evaluation.Compiled using ExpressionDebugger; using FluentAssertions; using Moq; - using Rules.Framework.Core; + using Rules.Framework; using Rules.Framework.Evaluation; using Rules.Framework.Evaluation.Compiled; using Rules.Framework.Evaluation.Compiled.ConditionBuilders; diff --git a/tests/Rules.Framework.Tests/Evaluation/Compiled/RuleConditionsExpressionBuilderTests.GoldenFile1.csx b/tests/Rules.Framework.Tests/Evaluation/Compiled/RuleConditionsExpressionBuilderTests.GoldenFile1.csx index 09d0c69f..cb4b0360 100644 --- a/tests/Rules.Framework.Tests/Evaluation/Compiled/RuleConditionsExpressionBuilderTests.GoldenFile1.csx +++ b/tests/Rules.Framework.Tests/Evaluation/Compiled/RuleConditionsExpressionBuilderTests.GoldenFile1.csx @@ -1,7 +1,7 @@ private Func Evaluate1; -private Func, ConditionType, object> GetValueOrDefault1; +private Func, string, object> GetValueOrDefault1; -internal bool Main(EvaluationContext evaluationContext) +internal bool Main(EvaluationContext evaluationContext) { bool cnd0Result; object cnd0LeftOperand; @@ -12,7 +12,7 @@ internal bool Main(EvaluationContext evaluationContext) object cnd1RightOperand; string cnd1Multiplicity; - cnd0LeftOperand = GetValueOrDefault1.Invoke(evaluationContext.get_Conditions(), ConditionType.NumberOfSales); + cnd0LeftOperand = GetValueOrDefault1.Invoke(evaluationContext.get_Conditions(), "NumberOfSales"); cnd0RightOperand = 100; if (cnd0LeftOperand == null) @@ -41,7 +41,7 @@ internal bool Main(EvaluationContext evaluationContext) } cnd0LabelEndValueConditionNode: - cnd1LeftOperand = GetValueOrDefault1.Invoke(evaluationContext.get_Conditions(), ConditionType.IsoCountryCode); + cnd1LeftOperand = GetValueOrDefault1.Invoke(evaluationContext.get_Conditions(), "IsoCountryCode"); cnd1RightOperand = "GB"; if (cnd1LeftOperand == null) diff --git a/tests/Rules.Framework.Tests/Evaluation/Compiled/RuleConditionsExpressionBuilderTests.GoldenFile2.csx b/tests/Rules.Framework.Tests/Evaluation/Compiled/RuleConditionsExpressionBuilderTests.GoldenFile2.csx index ddcb33f1..1211f317 100644 --- a/tests/Rules.Framework.Tests/Evaluation/Compiled/RuleConditionsExpressionBuilderTests.GoldenFile2.csx +++ b/tests/Rules.Framework.Tests/Evaluation/Compiled/RuleConditionsExpressionBuilderTests.GoldenFile2.csx @@ -1,7 +1,7 @@ private Func Evaluate1; -private Func, ConditionType, object> GetValueOrDefault1; +private Func, string, object> GetValueOrDefault1; -internal bool Main(EvaluationContext evaluationContext) +internal bool Main(EvaluationContext evaluationContext) { bool cnd0Result; object cnd0LeftOperand; @@ -12,7 +12,7 @@ internal bool Main(EvaluationContext evaluationContext) object cnd1RightOperand; string cnd1Multiplicity; - cnd0LeftOperand = GetValueOrDefault1.Invoke(evaluationContext.get_Conditions(), ConditionType.NumberOfSales); + cnd0LeftOperand = GetValueOrDefault1.Invoke(evaluationContext.get_Conditions(), "NumberOfSales"); cnd0RightOperand = 100; if (cnd0LeftOperand == null) @@ -41,7 +41,7 @@ internal bool Main(EvaluationContext evaluationContext) } cnd0LabelEndValueConditionNode: - cnd1LeftOperand = GetValueOrDefault1.Invoke(evaluationContext.get_Conditions(), ConditionType.IsoCountryCode); + cnd1LeftOperand = GetValueOrDefault1.Invoke(evaluationContext.get_Conditions(), "IsoCountryCode"); cnd1RightOperand = "GB"; if (cnd1LeftOperand == null) diff --git a/tests/Rules.Framework.Tests/Evaluation/Compiled/RuleConditionsExpressionBuilderTests.cs b/tests/Rules.Framework.Tests/Evaluation/Compiled/RuleConditionsExpressionBuilderTests.cs index f5437ee8..ef35da9a 100644 --- a/tests/Rules.Framework.Tests/Evaluation/Compiled/RuleConditionsExpressionBuilderTests.cs +++ b/tests/Rules.Framework.Tests/Evaluation/Compiled/RuleConditionsExpressionBuilderTests.cs @@ -9,8 +9,8 @@ namespace Rules.Framework.Tests.Evaluation.Compiled using ExpressionDebugger; using FluentAssertions; using Moq; - using Rules.Framework.Core; - using Rules.Framework.Core.ConditionNodes; + using Rules.Framework; + using Rules.Framework.ConditionNodes; using Rules.Framework.Evaluation; using Rules.Framework.Evaluation.Compiled; using Rules.Framework.Evaluation.Compiled.ExpressionBuilders; @@ -19,14 +19,14 @@ namespace Rules.Framework.Tests.Evaluation.Compiled public class RuleConditionsExpressionBuilderTests { - internal static IEnumerable<(string, EvaluationContext, bool)> AndComposedConditionNodeScenarios => new[] + internal static IEnumerable<(string, EvaluationContext, bool)> AndComposedConditionNodeScenarios => new[] { ( "Scenario 1 - MissingConditionsBehavior = 'Discard', MatchMode = 'Exact', and only contains condition for 'NumberOfSales'", - new EvaluationContext( - new Dictionary + new EvaluationContext( + new Dictionary { - { ConditionType.NumberOfSales, 500 }, + { ConditionType.NumberOfSales.ToString(), 500 }, }, MatchModes.Exact, MissingConditionBehaviors.Discard), @@ -34,11 +34,11 @@ public class RuleConditionsExpressionBuilderTests ), ( "Scenario 2 - MissingConditionsBehavior = 'Discard', MatchMode = 'Exact', and both needed conditions", - new EvaluationContext( - new Dictionary + new EvaluationContext( + new Dictionary { - { ConditionType.NumberOfSales, 500 }, - { ConditionType.IsoCountryCode, "PT" }, + { ConditionType.NumberOfSales.ToString(), 500 }, + { ConditionType.IsoCountryCode.ToString(), "PT" }, }, MatchModes.Exact, MissingConditionBehaviors.Discard), @@ -46,11 +46,11 @@ public class RuleConditionsExpressionBuilderTests ), ( "Scenario 3 - MissingConditionsBehavior = 'UseDataTypeDefault', MatchMode = 'Exact', and both needed conditions", - new EvaluationContext( - new Dictionary + new EvaluationContext( + new Dictionary { - { ConditionType.NumberOfSales, 500 }, - { ConditionType.IsoCountryCode, "PT" }, + { ConditionType.NumberOfSales.ToString(), 500 }, + { ConditionType.IsoCountryCode.ToString(), "PT" }, }, MatchModes.Exact, MissingConditionBehaviors.UseDataTypeDefault), @@ -58,11 +58,11 @@ public class RuleConditionsExpressionBuilderTests ), ( "Scenario 4 - MissingConditionsBehavior = 'UseDataTypeDefault', MatchMode = 'Search', and both needed conditions", - new EvaluationContext( - new Dictionary + new EvaluationContext( + new Dictionary { - { ConditionType.NumberOfSales, 500 }, - { ConditionType.IsoCountryCode, "PT" }, + { ConditionType.NumberOfSales.ToString(), 500 }, + { ConditionType.IsoCountryCode.ToString(), "PT" }, }, MatchModes.Search, MissingConditionBehaviors.UseDataTypeDefault), @@ -70,10 +70,10 @@ public class RuleConditionsExpressionBuilderTests ), ( "Scenario 5 - MissingConditionsBehavior = 'UseDataTypeDefault', MatchMode = 'Search', and only contains condition for 'NumberOfSales'", - new EvaluationContext( - new Dictionary + new EvaluationContext( + new Dictionary { - { ConditionType.NumberOfSales, 500 }, + { ConditionType.NumberOfSales.ToString(), 500 }, }, MatchModes.Search, MissingConditionBehaviors.UseDataTypeDefault), @@ -81,14 +81,14 @@ public class RuleConditionsExpressionBuilderTests ) }; - internal static IEnumerable<(string, EvaluationContext, bool)> OrComposedConditionNodeScenarios => new[] + internal static IEnumerable<(string, EvaluationContext, bool)> OrComposedConditionNodeScenarios => new[] { ( "Scenario 1 - MissingConditionsBehavior = 'Discard', MatchMode = 'Exact', and only contains condition for 'NumberOfSales'", - new EvaluationContext( - new Dictionary + new EvaluationContext( + new Dictionary { - { ConditionType.NumberOfSales, 500 }, + { ConditionType.NumberOfSales.ToString(), 500 }, }, MatchModes.Exact, MissingConditionBehaviors.Discard), @@ -96,11 +96,11 @@ public class RuleConditionsExpressionBuilderTests ), ( "Scenario 2 - MissingConditionsBehavior = 'Discard', MatchMode = 'Exact', and both needed conditions", - new EvaluationContext( - new Dictionary + new EvaluationContext( + new Dictionary { - { ConditionType.NumberOfSales, 500 }, - { ConditionType.IsoCountryCode, "PT" }, + { ConditionType.NumberOfSales.ToString(), 500 }, + { ConditionType.IsoCountryCode.ToString(), "PT" }, }, MatchModes.Exact, MissingConditionBehaviors.Discard), @@ -108,11 +108,11 @@ public class RuleConditionsExpressionBuilderTests ), ( "Scenario 3 - MissingConditionsBehavior = 'UseDataTypeDefault', MatchMode = 'Exact', and both needed conditions", - new EvaluationContext( - new Dictionary + new EvaluationContext( + new Dictionary { - { ConditionType.NumberOfSales, 500 }, - { ConditionType.IsoCountryCode, "PT" }, + { ConditionType.NumberOfSales.ToString(), 500 }, + { ConditionType.IsoCountryCode.ToString(), "PT" }, }, MatchModes.Exact, MissingConditionBehaviors.UseDataTypeDefault), @@ -120,11 +120,11 @@ public class RuleConditionsExpressionBuilderTests ), ( "Scenario 4 - MissingConditionsBehavior = 'UseDataTypeDefault', MatchMode = 'Search', and both needed conditions", - new EvaluationContext( - new Dictionary + new EvaluationContext( + new Dictionary { - { ConditionType.NumberOfSales, 500 }, - { ConditionType.IsoCountryCode, "PT" }, + { ConditionType.NumberOfSales.ToString(), 500 }, + { ConditionType.IsoCountryCode.ToString(), "PT" }, }, MatchModes.Search, MissingConditionBehaviors.UseDataTypeDefault), @@ -132,10 +132,10 @@ public class RuleConditionsExpressionBuilderTests ), ( "Scenario 5 - MissingConditionsBehavior = 'UseDataTypeDefault', MatchMode = 'Search', and only contains condition for 'NumberOfSales'", - new EvaluationContext( - new Dictionary + new EvaluationContext( + new Dictionary { - { ConditionType.NumberOfSales, 500 }, + { ConditionType.NumberOfSales.ToString(), 500 }, }, MatchModes.Search, MissingConditionBehaviors.UseDataTypeDefault), @@ -154,12 +154,12 @@ public void BuildExpression_GivenAndComposedConditionNodeWith2ChildValueConditio expectedScript = streamReader.ReadToEnd(); } var valueConditionNode1 - = new ValueConditionNode(DataTypes.Integer, ConditionType.NumberOfSales, Operators.Equal, 100); + = new ValueConditionNode(DataTypes.Integer, ConditionType.NumberOfSales.ToString(), Operators.Equal, 100); var valueConditionNode2 - = new ValueConditionNode(DataTypes.String, ConditionType.IsoCountryCode, Operators.Equal, "GB"); + = new ValueConditionNode(DataTypes.String, ConditionType.IsoCountryCode.ToString(), Operators.Equal, "GB"); var composedConditionNode - = new ComposedConditionNode(LogicalOperators.And, new[] { valueConditionNode1, valueConditionNode2 }); + = new ComposedConditionNode(LogicalOperators.And, new[] { valueConditionNode1, valueConditionNode2 }); var valueConditionNodeExpressionBuilder = Mock.Of(); Mock.Get(valueConditionNodeExpressionBuilder) @@ -184,7 +184,7 @@ var composedConditionNode .Setup(x => x.GetDataTypeConfiguration(DataTypes.Integer)) .Returns(DataTypeConfiguration.Create(DataTypes.Integer, typeof(int), 0)); - var conditionsTreeCompiler = new RuleConditionsExpressionBuilder( + var conditionsTreeCompiler = new RuleConditionsExpressionBuilder( valueConditionNodeExpressionBuilderProvider, dataTypeConfigurationProvider); @@ -197,7 +197,7 @@ var composedConditionNode var diffResult = SideBySideDiffBuilder.Diff(expectedScript, actualScript, ignoreWhiteSpace: true); diffResult.NewText.HasDifferences.Should().BeFalse(); - Func, bool> compiledLambdaExpression = null; + Func compiledLambdaExpression = null; FluentActions.Invoking(() => compiledLambdaExpression = expression.Compile()) .Should() .NotThrow("expression should be compilable"); @@ -224,12 +224,12 @@ public void BuildExpression_GivenOrComposedConditionNodeWith2ChildValueCondition expectedScript = streamReader.ReadToEnd(); } var valueConditionNode1 - = new ValueConditionNode(DataTypes.Integer, ConditionType.NumberOfSales, Operators.Equal, 100); + = new ValueConditionNode(DataTypes.Integer, ConditionType.NumberOfSales.ToString(), Operators.Equal, 100); var valueConditionNode2 - = new ValueConditionNode(DataTypes.String, ConditionType.IsoCountryCode, Operators.Equal, "GB"); + = new ValueConditionNode(DataTypes.String, ConditionType.IsoCountryCode.ToString(), Operators.Equal, "GB"); var composedConditionNode - = new ComposedConditionNode(LogicalOperators.Or, new[] { valueConditionNode1, valueConditionNode2 }); + = new ComposedConditionNode(LogicalOperators.Or, new[] { valueConditionNode1, valueConditionNode2 }); var valueConditionNodeExpressionBuilder = Mock.Of(); Mock.Get(valueConditionNodeExpressionBuilder) @@ -254,7 +254,7 @@ var composedConditionNode .Setup(x => x.GetDataTypeConfiguration(DataTypes.Integer)) .Returns(DataTypeConfiguration.Create(DataTypes.Integer, typeof(int), 0)); - var conditionsTreeCompiler = new RuleConditionsExpressionBuilder( + var conditionsTreeCompiler = new RuleConditionsExpressionBuilder( valueConditionNodeExpressionBuilderProvider, dataTypeConfigurationProvider); @@ -267,7 +267,7 @@ var composedConditionNode var diffResult = SideBySideDiffBuilder.Diff(expectedScript, actualScript, ignoreWhiteSpace: true); diffResult.NewText.HasDifferences.Should().BeFalse(); - Func, bool> compiledLambdaExpression = null; + Func compiledLambdaExpression = null; FluentActions.Invoking(() => compiledLambdaExpression = expression.Compile()) .Should() .NotThrow("expression should be compilable"); @@ -287,12 +287,12 @@ var composedConditionNode public void BuildExpression_GivenUnknownConditionNode_ThrowsNotSupportedException() { // Arrange - var stubConditionNode = new StubConditionNode(); + var stubConditionNode = new StubConditionNode(); var valueConditionNodeExpressionBuilderProvider = Mock.Of(); var dataTypeConfigurationProvider = Mock.Of(); - var ruleConditionsExpressionBuilder = new RuleConditionsExpressionBuilder( + var ruleConditionsExpressionBuilder = new RuleConditionsExpressionBuilder( valueConditionNodeExpressionBuilderProvider, dataTypeConfigurationProvider); @@ -301,19 +301,19 @@ public void BuildExpression_GivenUnknownConditionNode_ThrowsNotSupportedExceptio // Assert notSupportedException.Should().NotBeNull(); - notSupportedException.Message.Should().Contain(nameof(StubConditionNode)); + notSupportedException.Message.Should().Contain(nameof(StubConditionNode)); } [Fact] public void BuildExpression_GivenUnsupportedLogicalOperatorForComposedConditionNode_ThrowsNotSupportedException() { // Arrange - var composedConditionNode = new ComposedConditionNode(LogicalOperators.Eval, Enumerable.Empty>()); + var composedConditionNode = new ComposedConditionNode(LogicalOperators.Eval, Enumerable.Empty()); var valueConditionNodeExpressionBuilderProvider = Mock.Of(); var dataTypeConfigurationProvider = Mock.Of(); - var ruleConditionsExpressionBuilder = new RuleConditionsExpressionBuilder( + var ruleConditionsExpressionBuilder = new RuleConditionsExpressionBuilder( valueConditionNodeExpressionBuilderProvider, dataTypeConfigurationProvider); diff --git a/tests/Rules.Framework.Tests/Evaluation/ConditionsTreeAnalyzerTests.cs b/tests/Rules.Framework.Tests/Evaluation/ConditionsTreeAnalyzerTests.cs index 9a97d532..4f1b3188 100644 --- a/tests/Rules.Framework.Tests/Evaluation/ConditionsTreeAnalyzerTests.cs +++ b/tests/Rules.Framework.Tests/Evaluation/ConditionsTreeAnalyzerTests.cs @@ -3,8 +3,8 @@ namespace Rules.Framework.Tests.Evaluation using System; using System.Collections.Generic; using FluentAssertions; - using Rules.Framework.Core; - using Rules.Framework.Core.ConditionNodes; + using Rules.Framework; + using Rules.Framework.ConditionNodes; using Rules.Framework.Evaluation; using Rules.Framework.Tests.Stubs; using Xunit; @@ -15,27 +15,27 @@ public class ConditionsTreeAnalyzerTests public void AreAllSearchConditionsPresent_GivenComposedConditionNodeWithAllConditionsOnDictionary_ReturnsTrue() { // Arrange - var condition1 = new ValueConditionNode(DataTypes.String, ConditionType.IsoCountryCode, Operators.In, new[] { "US", "CA" }); - var condition2 = new ValueConditionNode(DataTypes.String, ConditionType.IsoCurrency, Operators.NotEqual, "SGD"); - var condition3 = new ValueConditionNode(DataTypes.Boolean, ConditionType.IsVip, Operators.Equal, false); + var condition1 = new ValueConditionNode(DataTypes.String, ConditionType.IsoCountryCode.ToString(), Operators.In, new[] { "US", "CA" }); + var condition2 = new ValueConditionNode(DataTypes.String, ConditionType.IsoCurrency.ToString(), Operators.NotEqual, "SGD"); + var condition3 = new ValueConditionNode(DataTypes.Boolean, ConditionType.IsVip.ToString(), Operators.Equal, false); - var composedConditionNode = new ComposedConditionNode( + var composedConditionNode = new ComposedConditionNode( LogicalOperators.Or, - new IConditionNode[] { condition1, condition2, condition3 }); + new IConditionNode[] { condition1, condition2, condition3 }); - var conditions = new Dictionary + var conditions = new Dictionary { { - ConditionType.IsoCurrency, + ConditionType.IsoCurrency.ToString(), "SGD" }, { - ConditionType.IsoCountryCode, + ConditionType.IsoCountryCode.ToString(), "PT" } }; - var conditionsTreeAnalyzer = new ConditionsTreeAnalyzer(); + var conditionsTreeAnalyzer = new ConditionsTreeAnalyzer(); // Act var result = conditionsTreeAnalyzer.AreAllSearchConditionsPresent(composedConditionNode, conditions); @@ -48,59 +48,59 @@ public void AreAllSearchConditionsPresent_GivenComposedConditionNodeWithAllCondi public void AreAllSearchConditionsPresent_GivenComposedConditionNodeWithAndOperatorAndUnknownConditionNode_ThrowsNotSupportedException() { // Arrange - var condition1 = new StubConditionNode(); - var condition2 = new ValueConditionNode(DataTypes.String, ConditionType.IsoCurrency, Operators.NotEqual, "SGD"); + var condition1 = new StubConditionNode(); + var condition2 = new ValueConditionNode(DataTypes.String, ConditionType.IsoCurrency.ToString(), Operators.NotEqual, "SGD"); - var composedConditionNode = new ComposedConditionNode( + var composedConditionNode = new ComposedConditionNode( LogicalOperators.Or, - new IConditionNode[] { condition1, condition2 }); + new IConditionNode[] { condition1, condition2 }); - var conditions = new Dictionary + var conditions = new Dictionary { { - ConditionType.IsoCurrency, + ConditionType.IsoCurrency.ToString(), "SGD" }, { - ConditionType.IsoCountryCode, + ConditionType.IsoCountryCode.ToString(), "PT" } }; - var conditionsTreeAnalyzer = new ConditionsTreeAnalyzer(); + var conditionsTreeAnalyzer = new ConditionsTreeAnalyzer(); // Act var notSupportedException = Assert.Throws(() => conditionsTreeAnalyzer.AreAllSearchConditionsPresent(composedConditionNode, conditions)); // Assert notSupportedException.Should().NotBeNull(); - notSupportedException.Message.Should().Be("Unsupported condition node: 'StubConditionNode`1'."); + notSupportedException.Message.Should().Be("Unsupported condition node: 'StubConditionNode'."); } [Fact] public void AreAllSearchConditionsPresent_GivenComposedConditionNodeWithMissingConditionOnDictionary_ReturnsFalse() { // Arrange - var condition1 = new ValueConditionNode(DataTypes.String, ConditionType.IsoCountryCode, Operators.In, new[] { "US", "CA" }); - var condition3 = new ValueConditionNode(DataTypes.Boolean, ConditionType.IsVip, Operators.Equal, false); + var condition1 = new ValueConditionNode(DataTypes.String, ConditionType.IsoCountryCode.ToString(), Operators.In, new[] { "US", "CA" }); + var condition3 = new ValueConditionNode(DataTypes.Boolean, ConditionType.IsVip.ToString(), Operators.Equal, false); - var composedConditionNode = new ComposedConditionNode( + var composedConditionNode = new ComposedConditionNode( LogicalOperators.Or, - new IConditionNode[] { condition1, condition3 }); + new IConditionNode[] { condition1, condition3 }); - var conditions = new Dictionary + var conditions = new Dictionary { { - ConditionType.IsoCurrency, + ConditionType.IsoCurrency.ToString(), "SGD" }, { - ConditionType.IsoCountryCode, + ConditionType.IsoCountryCode.ToString(), "PT" } }; - var conditionsTreeAnalyzer = new ConditionsTreeAnalyzer(); + var conditionsTreeAnalyzer = new ConditionsTreeAnalyzer(); // Act var result = conditionsTreeAnalyzer.AreAllSearchConditionsPresent(composedConditionNode, conditions); diff --git a/tests/Rules.Framework.Tests/Evaluation/DataTypeConfigurationTests.cs b/tests/Rules.Framework.Tests/Evaluation/DataTypeConfigurationTests.cs index 5918400c..c71324d7 100644 --- a/tests/Rules.Framework.Tests/Evaluation/DataTypeConfigurationTests.cs +++ b/tests/Rules.Framework.Tests/Evaluation/DataTypeConfigurationTests.cs @@ -2,7 +2,7 @@ namespace Rules.Framework.Tests.Evaluation { using System; using FluentAssertions; - using Rules.Framework.Core; + using Rules.Framework; using Rules.Framework.Evaluation; using Xunit; diff --git a/tests/Rules.Framework.Tests/Evaluation/DataTypesConfigurationProviderTests.cs b/tests/Rules.Framework.Tests/Evaluation/DataTypesConfigurationProviderTests.cs index 3acffd43..78292b1f 100644 --- a/tests/Rules.Framework.Tests/Evaluation/DataTypesConfigurationProviderTests.cs +++ b/tests/Rules.Framework.Tests/Evaluation/DataTypesConfigurationProviderTests.cs @@ -4,7 +4,7 @@ namespace Rules.Framework.Tests.Evaluation using System.Collections.Generic; using System.Linq; using FluentAssertions; - using Rules.Framework.Core; + using Rules.Framework; using Rules.Framework.Evaluation; using Xunit; diff --git a/tests/Rules.Framework.Tests/Evaluation/Interpreted/DeferredEvalTests.cs b/tests/Rules.Framework.Tests/Evaluation/Interpreted/DeferredEvalTests.cs index cce9f715..3f875098 100644 --- a/tests/Rules.Framework.Tests/Evaluation/Interpreted/DeferredEvalTests.cs +++ b/tests/Rules.Framework.Tests/Evaluation/Interpreted/DeferredEvalTests.cs @@ -3,8 +3,8 @@ namespace Rules.Framework.Tests.Evaluation.Interpreted using System.Collections.Generic; using FluentAssertions; using Moq; - using Rules.Framework.Core; - using Rules.Framework.Core.ConditionNodes; + using Rules.Framework; + using Rules.Framework.ConditionNodes; using Rules.Framework.Evaluation; using Rules.Framework.Evaluation.Interpreted; using Rules.Framework.Evaluation.Interpreted.ValueEvaluation.Dispatchers; @@ -17,7 +17,7 @@ public class DeferredEvalTests public void GetDeferredEvalFor_GivenBooleanConditionNode_ReturnsFuncToEvalConditionsCollection() { // Arrange - var conditionNode = new ValueConditionNode(DataTypes.Boolean, ConditionType.IsVip, Operators.NotEqual, true); + var conditionNode = new ValueConditionNode(DataTypes.Boolean, ConditionType.IsVip.ToString(), Operators.NotEqual, true); var mockOperatorEvalStrategy = new Mock(); mockOperatorEvalStrategy.Setup(x => x.EvalDispatch(It.IsAny(), It.IsAny(), It.IsAny(), It.IsAny())) @@ -27,9 +27,9 @@ public void GetDeferredEvalFor_GivenBooleanConditionNode_ReturnsFuncToEvalCondit mockConditionEvalDispatchProvider.Setup(x => x.GetEvalDispatcher(It.IsAny(), It.IsAny(), It.IsAny())) .Returns(mockOperatorEvalStrategy.Object); - var conditions = new Dictionary + var conditions = new Dictionary { - { ConditionType.IsVip, false } + { ConditionType.IsVip.ToString(), false } }; var matchMode = MatchModes.Exact; @@ -40,7 +40,7 @@ public void GetDeferredEvalFor_GivenBooleanConditionNode_ReturnsFuncToEvalCondit // Act var actual = sut.GetDeferredEvalFor(conditionNode, matchMode); - bool actualEvalResult = actual.Invoke(conditions); + var actualEvalResult = actual.Invoke(conditions); // Assert actualEvalResult.Should().BeTrue(); @@ -53,7 +53,7 @@ public void GetDeferredEvalFor_GivenBooleanConditionNode_ReturnsFuncToEvalCondit public void GetDeferredEvalFor_GivenDecimalConditionNode_ReturnsFuncToEvalConditionsCollection() { // Arrange - var conditionNode = new ValueConditionNode(DataTypes.Decimal, ConditionType.PluviosityRate, Operators.GreaterThan, 50); + var conditionNode = new ValueConditionNode(DataTypes.Decimal, ConditionType.PluviosityRate.ToString(), Operators.GreaterThan, 50); var mockOperatorEvalStrategy = new Mock(); mockOperatorEvalStrategy.Setup(x => x.EvalDispatch(It.IsAny(), It.IsAny(), It.IsAny(), It.IsAny())) @@ -63,9 +63,9 @@ public void GetDeferredEvalFor_GivenDecimalConditionNode_ReturnsFuncToEvalCondit mockConditionEvalDispatchProvider.Setup(x => x.GetEvalDispatcher(It.IsAny(), It.IsAny(), It.IsAny())) .Returns(mockOperatorEvalStrategy.Object); - var conditions = new Dictionary + var conditions = new Dictionary { - { ConditionType.PluviosityRate, 78 } + { ConditionType.PluviosityRate.ToString(), 78 } }; var matchMode = MatchModes.Exact; @@ -89,7 +89,7 @@ public void GetDeferredEvalFor_GivenDecimalConditionNode_ReturnsFuncToEvalCondit public void GetDeferredEvalFor_GivenIntegerConditionNode_ReturnsFuncToEvalConditionsCollection() { // Arrange - var conditionNode = new ValueConditionNode(DataTypes.Integer, ConditionType.NumberOfSales, Operators.GreaterThan, 1000); + var conditionNode = new ValueConditionNode(DataTypes.Integer, ConditionType.NumberOfSales.ToString(), Operators.GreaterThan, 1000); var mockOperatorEvalStrategy = new Mock(); mockOperatorEvalStrategy.Setup(x => x.EvalDispatch(It.IsAny(), It.IsAny(), It.IsAny(), It.IsAny())) @@ -99,9 +99,9 @@ public void GetDeferredEvalFor_GivenIntegerConditionNode_ReturnsFuncToEvalCondit mockConditionEvalDispatchProvider.Setup(x => x.GetEvalDispatcher(It.IsAny(), It.IsAny(), It.IsAny())) .Returns(mockOperatorEvalStrategy.Object); - var conditions = new Dictionary + var conditions = new Dictionary { - { ConditionType.NumberOfSales, 2300 } + { ConditionType.NumberOfSales.ToString(), 2300 } }; var matchMode = MatchModes.Exact; @@ -125,7 +125,7 @@ public void GetDeferredEvalFor_GivenIntegerConditionNode_ReturnsFuncToEvalCondit public void GetDeferredEvalFor_GivenStringConditionNode_ReturnsFuncToEvalConditionsCollection() { // Arrange - var conditionNode = new ValueConditionNode(DataTypes.String, ConditionType.IsoCurrency, Operators.Equal, "EUR"); + var conditionNode = new ValueConditionNode(DataTypes.String, ConditionType.IsoCurrency.ToString(), Operators.Equal, "EUR"); var mockOperatorEvalStrategy = new Mock(); mockOperatorEvalStrategy.Setup(x => x.EvalDispatch(It.IsAny(), It.IsAny(), It.IsAny(), It.IsAny())) @@ -135,9 +135,9 @@ public void GetDeferredEvalFor_GivenStringConditionNode_ReturnsFuncToEvalConditi mockConditionEvalDispatchProvider.Setup(x => x.GetEvalDispatcher(It.IsAny(), It.IsAny(), It.IsAny())) .Returns(mockOperatorEvalStrategy.Object); - var conditions = new Dictionary + var conditions = new Dictionary { - { ConditionType.IsoCurrency, "EUR" } + { ConditionType.IsoCurrency.ToString(), "EUR" } }; var matchMode = MatchModes.Exact; @@ -161,7 +161,7 @@ public void GetDeferredEvalFor_GivenStringConditionNode_ReturnsFuncToEvalConditi public void GetDeferredEvalFor_GivenStringConditionNodeWithNoConditionSuppliedAndRulesEngineConfiguredToDiscardWhenMissing_ReturnsFuncThatEvalsFalse() { // Arrange - var conditionNode = new ValueConditionNode(DataTypes.String, ConditionType.IsoCurrency, Operators.Equal, "EUR"); + var conditionNode = new ValueConditionNode(DataTypes.String, ConditionType.IsoCurrency.ToString(), Operators.Equal, "EUR"); var mockOperatorEvalStrategy = new Mock(); mockOperatorEvalStrategy.Setup(x => x.EvalDispatch(It.IsAny(), It.IsAny(), It.IsAny(), It.IsAny())) @@ -171,9 +171,9 @@ public void GetDeferredEvalFor_GivenStringConditionNodeWithNoConditionSuppliedAn mockConditionEvalDispatchProvider.Setup(x => x.GetEvalDispatcher(It.IsAny(), It.IsAny(), It.IsAny())) .Returns(mockOperatorEvalStrategy.Object); - var conditions = new Dictionary + var conditions = new Dictionary { - { ConditionType.IsoCountryCode, "PT" } + { ConditionType.IsoCountryCode.ToString(), "PT" } }; var matchMode = MatchModes.Exact; @@ -198,7 +198,7 @@ public void GetDeferredEvalFor_GivenStringConditionNodeWithNoConditionSuppliedAn public void GetDeferredEvalFor_GivenStringConditionNodeWithNoConditionSuppliedAndRulesEngineConfiguredToUseDataTypeDefaultWhenMissing_ReturnsFuncThatEvalsFalse() { // Arrange - var conditionNode = new ValueConditionNode(DataTypes.String, ConditionType.IsoCurrency, Operators.Equal, "EUR"); + var conditionNode = new ValueConditionNode(DataTypes.String, ConditionType.IsoCurrency.ToString(), Operators.Equal, "EUR"); var mockOperatorEvalStrategy = new Mock(); mockOperatorEvalStrategy.Setup(x => x.EvalDispatch(It.IsAny(), It.IsAny(), It.IsAny(), It.IsAny())) @@ -208,9 +208,9 @@ public void GetDeferredEvalFor_GivenStringConditionNodeWithNoConditionSuppliedAn mockConditionEvalDispatchProvider.Setup(x => x.GetEvalDispatcher(It.IsAny(), It.IsAny(), It.IsAny())) .Returns(mockOperatorEvalStrategy.Object); - var conditions = new Dictionary + var conditions = new Dictionary { - { ConditionType.IsoCountryCode, "PT" } + { ConditionType.IsoCountryCode.ToString(), "PT" } }; var matchMode = MatchModes.Exact; diff --git a/tests/Rules.Framework.Tests/Evaluation/Interpreted/InterpretedConditionsEvalEngineTests.cs b/tests/Rules.Framework.Tests/Evaluation/Interpreted/InterpretedConditionsEvalEngineTests.cs index 8fc865db..b639bfcb 100644 --- a/tests/Rules.Framework.Tests/Evaluation/Interpreted/InterpretedConditionsEvalEngineTests.cs +++ b/tests/Rules.Framework.Tests/Evaluation/Interpreted/InterpretedConditionsEvalEngineTests.cs @@ -4,8 +4,8 @@ namespace Rules.Framework.Tests.Evaluation.Interpreted using System.Collections.Generic; using FluentAssertions; using Moq; - using Rules.Framework.Core; - using Rules.Framework.Core.ConditionNodes; + using Rules.Framework; + using Rules.Framework.ConditionNodes; using Rules.Framework.Evaluation; using Rules.Framework.Evaluation.Interpreted; using Rules.Framework.Tests.Stubs; @@ -17,21 +17,21 @@ public class InterpretedConditionsEvalEngineTests public void Eval_GivenComposedConditionNodeWithAndOperatorAndMissingConditionWithSearchMode_EvalsAndReturnsResult() { // Arrange - var condition1 = new ValueConditionNode(DataTypes.Boolean, ConditionType.IsVip, Operators.Equal, true); - var condition2 = new ValueConditionNode(DataTypes.String, ConditionType.IsoCurrency, Operators.NotEqual, "SGD"); + var condition1 = new ValueConditionNode(DataTypes.Boolean, ConditionType.IsVip.ToString(), Operators.Equal, true); + var condition2 = new ValueConditionNode(DataTypes.String, ConditionType.IsoCurrency.ToString(), Operators.NotEqual, "SGD"); - var composedConditionNode = new ComposedConditionNode( + var composedConditionNode = new ComposedConditionNode( LogicalOperators.And, - new IConditionNode[] { condition1, condition2 }); + new IConditionNode[] { condition1, condition2 }); - var conditions = new Dictionary + var conditions = new Dictionary { { - ConditionType.IsoCurrency, + ConditionType.IsoCurrency.ToString(), "SGD" }, { - ConditionType.IsVip, + ConditionType.IsVip.ToString(), true } }; @@ -43,7 +43,7 @@ public void Eval_GivenComposedConditionNodeWithAndOperatorAndMissingConditionWit }; var mockDeferredEval = new Mock(); - mockDeferredEval.SetupSequence(x => x.GetDeferredEvalFor(It.IsAny>(), It.Is(mm => mm == MatchModes.Exact))) + mockDeferredEval.SetupSequence(x => x.GetDeferredEvalFor(It.IsAny(), It.Is(mm => mm == MatchModes.Exact))) .Returns(() => { return (_) => false; @@ -53,9 +53,9 @@ public void Eval_GivenComposedConditionNodeWithAndOperatorAndMissingConditionWit return (_) => true; }) .Throws(new NotImplementedException("Shouldn't have gotten any more deferred evals.")); - var conditionsTreeAnalyzer = Mock.Of>(); + var conditionsTreeAnalyzer = Mock.Of(); - var sut = new InterpretedConditionsEvalEngine(mockDeferredEval.Object, conditionsTreeAnalyzer); + var sut = new InterpretedConditionsEvalEngine(mockDeferredEval.Object, conditionsTreeAnalyzer); // Act var actual = sut.Eval(composedConditionNode, conditions, evaluationOptions); @@ -63,28 +63,28 @@ public void Eval_GivenComposedConditionNodeWithAndOperatorAndMissingConditionWit // Assert actual.Should().BeFalse(); - mockDeferredEval.Verify(x => x.GetDeferredEvalFor(It.IsAny>(), It.Is(mm => mm == MatchModes.Exact)), Times.Exactly(0)); + mockDeferredEval.Verify(x => x.GetDeferredEvalFor(It.IsAny(), It.Is(mm => mm == MatchModes.Exact)), Times.Exactly(0)); } [Fact] public void Eval_GivenComposedConditionNodeWithAndOperatorWithExactMatch_EvalsAndReturnsResult() { // Arrange - var condition1 = new ValueConditionNode(DataTypes.Boolean, ConditionType.IsVip, Operators.Equal, true); - var condition2 = new ValueConditionNode(DataTypes.String, ConditionType.IsoCurrency, Operators.NotEqual, "SGD"); + var condition1 = new ValueConditionNode(DataTypes.Boolean, ConditionType.IsVip.ToString(), Operators.Equal, true); + var condition2 = new ValueConditionNode(DataTypes.String, ConditionType.IsoCurrency.ToString(), Operators.NotEqual, "SGD"); - var composedConditionNode = new ComposedConditionNode( + var composedConditionNode = new ComposedConditionNode( LogicalOperators.Eval, - new IConditionNode[] { condition1, condition2 }); + new IConditionNode[] { condition1, condition2 }); - var conditions = new Dictionary + var conditions = new Dictionary { { - ConditionType.IsoCurrency, + ConditionType.IsoCurrency.ToString(), "SGD" }, { - ConditionType.IsVip, + ConditionType.IsVip.ToString(), true } }; @@ -95,9 +95,9 @@ public void Eval_GivenComposedConditionNodeWithAndOperatorWithExactMatch_EvalsAn }; var deferredEval = Mock.Of(); - var conditionsTreeAnalyzer = Mock.Of>(); + var conditionsTreeAnalyzer = Mock.Of(); - var sut = new InterpretedConditionsEvalEngine(deferredEval, conditionsTreeAnalyzer); + var sut = new InterpretedConditionsEvalEngine(deferredEval, conditionsTreeAnalyzer); // Act var notSupportedException = Assert.Throws(() => sut.Eval(composedConditionNode, conditions, evaluationOptions)); @@ -106,28 +106,28 @@ public void Eval_GivenComposedConditionNodeWithAndOperatorWithExactMatch_EvalsAn notSupportedException.Should().NotBeNull(); notSupportedException.Message.Should().Be("Unsupported logical operator: 'Eval'."); Mock.Get(deferredEval) - .Verify(x => x.GetDeferredEvalFor(It.IsAny>(), It.Is(mm => mm == MatchModes.Exact)), Times.Never()); + .Verify(x => x.GetDeferredEvalFor(It.IsAny(), It.Is(mm => mm == MatchModes.Exact)), Times.Never()); } [Fact] public void Eval_GivenComposedConditionNodeWithEvalOperator_ThrowsNotSupportedException() { // Arrange - var condition1 = new ValueConditionNode(DataTypes.Boolean, ConditionType.IsVip, Operators.Equal, true); - var condition2 = new ValueConditionNode(DataTypes.String, ConditionType.IsoCurrency, Operators.NotEqual, "SGD"); + var condition1 = new ValueConditionNode(DataTypes.Boolean, ConditionType.IsVip.ToString(), Operators.Equal, true); + var condition2 = new ValueConditionNode(DataTypes.String, ConditionType.IsoCurrency.ToString(), Operators.NotEqual, "SGD"); - var composedConditionNode = new ComposedConditionNode( + var composedConditionNode = new ComposedConditionNode( LogicalOperators.Eval, - new IConditionNode[] { condition1, condition2 }); + new IConditionNode[] { condition1, condition2 }); - var conditions = new Dictionary + var conditions = new Dictionary { { - ConditionType.IsoCurrency, + ConditionType.IsoCurrency.ToString(), "SGD" }, { - ConditionType.IsVip, + ConditionType.IsVip.ToString(), true } }; @@ -138,9 +138,9 @@ public void Eval_GivenComposedConditionNodeWithEvalOperator_ThrowsNotSupportedEx }; var deferredEval = Mock.Of(); - var conditionsTreeAnalyzer = Mock.Of>(); + var conditionsTreeAnalyzer = Mock.Of(); - var sut = new InterpretedConditionsEvalEngine(deferredEval, conditionsTreeAnalyzer); + var sut = new InterpretedConditionsEvalEngine(deferredEval, conditionsTreeAnalyzer); // Act var notSupportedException = Assert.Throws(() => sut.Eval(composedConditionNode, conditions, evaluationOptions)); @@ -149,28 +149,28 @@ public void Eval_GivenComposedConditionNodeWithEvalOperator_ThrowsNotSupportedEx notSupportedException.Should().NotBeNull(); notSupportedException.Message.Should().Be("Unsupported logical operator: 'Eval'."); Mock.Get(deferredEval) - .Verify(x => x.GetDeferredEvalFor(It.IsAny>(), It.Is(mm => mm == MatchModes.Exact)), Times.Never()); + .Verify(x => x.GetDeferredEvalFor(It.IsAny(), It.Is(mm => mm == MatchModes.Exact)), Times.Never()); } [Fact] public void Eval_GivenComposedConditionNodeWithOrOperatorWithExactMatch_EvalsAndReturnsResult() { // Arrange - var condition1 = new ValueConditionNode(DataTypes.Boolean, ConditionType.IsVip, Operators.Equal, true); - var condition2 = new ValueConditionNode(DataTypes.String, ConditionType.IsoCurrency, Operators.NotEqual, "SGD"); + var condition1 = new ValueConditionNode(DataTypes.Boolean, ConditionType.IsVip.ToString(), Operators.Equal, true); + var condition2 = new ValueConditionNode(DataTypes.String, ConditionType.IsoCurrency.ToString(), Operators.NotEqual, "SGD"); - var composedConditionNode = new ComposedConditionNode( + var composedConditionNode = new ComposedConditionNode( LogicalOperators.Or, - new IConditionNode[] { condition1, condition2 }); + new IConditionNode[] { condition1, condition2 }); - var conditions = new Dictionary + var conditions = new Dictionary { { - ConditionType.IsoCurrency, + ConditionType.IsoCurrency.ToString(), "SGD" }, { - ConditionType.IsVip, + ConditionType.IsVip.ToString(), true } }; @@ -182,7 +182,7 @@ public void Eval_GivenComposedConditionNodeWithOrOperatorWithExactMatch_EvalsAnd var deferredEval = Mock.Of(); Mock.Get(deferredEval) - .SetupSequence(x => x.GetDeferredEvalFor(It.IsAny>(), It.Is(mm => mm == MatchModes.Exact))) + .SetupSequence(x => x.GetDeferredEvalFor(It.IsAny(), It.Is(mm => mm == MatchModes.Exact))) .Returns(() => { return (_) => true; @@ -192,9 +192,9 @@ public void Eval_GivenComposedConditionNodeWithOrOperatorWithExactMatch_EvalsAnd return (_) => true; }) .Throws(new NotImplementedException("Shouldn't have gotten any more deferred evals.")); - var conditionsTreeAnalyzer = Mock.Of>(); + var conditionsTreeAnalyzer = Mock.Of(); - var sut = new InterpretedConditionsEvalEngine(deferredEval, conditionsTreeAnalyzer); + var sut = new InterpretedConditionsEvalEngine(deferredEval, conditionsTreeAnalyzer); // Act var actual = sut.Eval(composedConditionNode, conditions, evaluationOptions); @@ -203,7 +203,7 @@ public void Eval_GivenComposedConditionNodeWithOrOperatorWithExactMatch_EvalsAnd actual.Should().BeTrue(); Mock.Get(deferredEval) - .Verify(x => x.GetDeferredEvalFor(It.IsAny>(), It.Is(mm => mm == MatchModes.Exact)), Times.Exactly(2)); + .Verify(x => x.GetDeferredEvalFor(It.IsAny(), It.Is(mm => mm == MatchModes.Exact)), Times.Exactly(2)); } } } \ No newline at end of file diff --git a/tests/Rules.Framework.Tests/Evaluation/Interpreted/ValueEvaluation/Dispatchers/ManyToManyConditionEvalDispatcherTests.cs b/tests/Rules.Framework.Tests/Evaluation/Interpreted/ValueEvaluation/Dispatchers/ManyToManyConditionEvalDispatcherTests.cs index 489c3be2..26d4a4e5 100644 --- a/tests/Rules.Framework.Tests/Evaluation/Interpreted/ValueEvaluation/Dispatchers/ManyToManyConditionEvalDispatcherTests.cs +++ b/tests/Rules.Framework.Tests/Evaluation/Interpreted/ValueEvaluation/Dispatchers/ManyToManyConditionEvalDispatcherTests.cs @@ -5,7 +5,7 @@ namespace Rules.Framework.Tests.Evaluation.ValueEvaluation.Dispatchers using System.Collections.Generic; using FluentAssertions; using Moq; - using Rules.Framework.Core; + using Rules.Framework; using Rules.Framework.Evaluation; using Rules.Framework.Evaluation.Interpreted.ValueEvaluation; using Rules.Framework.Evaluation.Interpreted.ValueEvaluation.Dispatchers; diff --git a/tests/Rules.Framework.Tests/Evaluation/Interpreted/ValueEvaluation/Dispatchers/ManyToOneConditionEvalDispatcherTests.cs b/tests/Rules.Framework.Tests/Evaluation/Interpreted/ValueEvaluation/Dispatchers/ManyToOneConditionEvalDispatcherTests.cs index 71f07e9d..aba0cbed 100644 --- a/tests/Rules.Framework.Tests/Evaluation/Interpreted/ValueEvaluation/Dispatchers/ManyToOneConditionEvalDispatcherTests.cs +++ b/tests/Rules.Framework.Tests/Evaluation/Interpreted/ValueEvaluation/Dispatchers/ManyToOneConditionEvalDispatcherTests.cs @@ -5,7 +5,7 @@ namespace Rules.Framework.Tests.Evaluation.ValueEvaluation.Dispatchers using System.Collections.Generic; using FluentAssertions; using Moq; - using Rules.Framework.Core; + using Rules.Framework; using Rules.Framework.Evaluation; using Rules.Framework.Evaluation.Interpreted.ValueEvaluation; using Rules.Framework.Evaluation.Interpreted.ValueEvaluation.Dispatchers; diff --git a/tests/Rules.Framework.Tests/Evaluation/Interpreted/ValueEvaluation/Dispatchers/OneToManyConditionEvalDispatcherTests.cs b/tests/Rules.Framework.Tests/Evaluation/Interpreted/ValueEvaluation/Dispatchers/OneToManyConditionEvalDispatcherTests.cs index 28dacd55..61e7b177 100644 --- a/tests/Rules.Framework.Tests/Evaluation/Interpreted/ValueEvaluation/Dispatchers/OneToManyConditionEvalDispatcherTests.cs +++ b/tests/Rules.Framework.Tests/Evaluation/Interpreted/ValueEvaluation/Dispatchers/OneToManyConditionEvalDispatcherTests.cs @@ -4,7 +4,7 @@ namespace Rules.Framework.Tests.Evaluation.ValueEvaluation.Dispatchers using System.Collections.Generic; using FluentAssertions; using Moq; - using Rules.Framework.Core; + using Rules.Framework; using Rules.Framework.Evaluation; using Rules.Framework.Evaluation.Interpreted.ValueEvaluation; using Rules.Framework.Evaluation.Interpreted.ValueEvaluation.Dispatchers; diff --git a/tests/Rules.Framework.Tests/Evaluation/Interpreted/ValueEvaluation/Dispatchers/OneToOneConditionEvalDispatcherTests.cs b/tests/Rules.Framework.Tests/Evaluation/Interpreted/ValueEvaluation/Dispatchers/OneToOneConditionEvalDispatcherTests.cs index 57f9cddd..efb3c831 100644 --- a/tests/Rules.Framework.Tests/Evaluation/Interpreted/ValueEvaluation/Dispatchers/OneToOneConditionEvalDispatcherTests.cs +++ b/tests/Rules.Framework.Tests/Evaluation/Interpreted/ValueEvaluation/Dispatchers/OneToOneConditionEvalDispatcherTests.cs @@ -3,7 +3,7 @@ namespace Rules.Framework.Tests.Evaluation.ValueEvaluation.Dispatchers using System; using FluentAssertions; using Moq; - using Rules.Framework.Core; + using Rules.Framework; using Rules.Framework.Evaluation; using Rules.Framework.Evaluation.Interpreted.ValueEvaluation; using Rules.Framework.Evaluation.Interpreted.ValueEvaluation.Dispatchers; diff --git a/tests/Rules.Framework.Tests/Evaluation/Interpreted/ValueEvaluation/OperatorEvalStrategyFactoryTests.cs b/tests/Rules.Framework.Tests/Evaluation/Interpreted/ValueEvaluation/OperatorEvalStrategyFactoryTests.cs index 24c6877c..f2353333 100644 --- a/tests/Rules.Framework.Tests/Evaluation/Interpreted/ValueEvaluation/OperatorEvalStrategyFactoryTests.cs +++ b/tests/Rules.Framework.Tests/Evaluation/Interpreted/ValueEvaluation/OperatorEvalStrategyFactoryTests.cs @@ -2,7 +2,7 @@ namespace Rules.Framework.Tests.Evaluation.Interpreted.ValueEvaluation { using System; using FluentAssertions; - using Rules.Framework.Core; + using Rules.Framework; using Rules.Framework.Evaluation.Interpreted.ValueEvaluation; using Xunit; diff --git a/tests/Rules.Framework.Tests/Evaluation/MultiplicityEvaluatorTests.cs b/tests/Rules.Framework.Tests/Evaluation/MultiplicityEvaluatorTests.cs index f257bc22..94970fcc 100644 --- a/tests/Rules.Framework.Tests/Evaluation/MultiplicityEvaluatorTests.cs +++ b/tests/Rules.Framework.Tests/Evaluation/MultiplicityEvaluatorTests.cs @@ -3,7 +3,7 @@ namespace Rules.Framework.Tests.Evaluation using System; using System.Collections.Generic; using FluentAssertions; - using Rules.Framework.Core; + using Rules.Framework; using Rules.Framework.Evaluation; using Xunit; diff --git a/tests/Rules.Framework.Tests/Evaluation/OperatorMetadataTests.cs b/tests/Rules.Framework.Tests/Evaluation/OperatorMetadataTests.cs index 75fc98d0..40857b6d 100644 --- a/tests/Rules.Framework.Tests/Evaluation/OperatorMetadataTests.cs +++ b/tests/Rules.Framework.Tests/Evaluation/OperatorMetadataTests.cs @@ -2,7 +2,7 @@ namespace Rules.Framework.Tests.Evaluation { using System.Linq; using FluentAssertions; - using Rules.Framework.Core; + using Rules.Framework; using Rules.Framework.Evaluation; using Xunit; diff --git a/tests/Rules.Framework.Tests/Evaluation/StubConditionNode.cs b/tests/Rules.Framework.Tests/Evaluation/StubConditionNode.cs index 967d6acc..4914a91e 100644 --- a/tests/Rules.Framework.Tests/Evaluation/StubConditionNode.cs +++ b/tests/Rules.Framework.Tests/Evaluation/StubConditionNode.cs @@ -2,14 +2,14 @@ namespace Rules.Framework.Tests.Evaluation { using System; using System.Collections.Generic; - using Rules.Framework.Core; + using Rules.Framework; - internal class StubConditionNode : IConditionNode + internal class StubConditionNode : IConditionNode { public LogicalOperators LogicalOperator => throw new NotImplementedException(); public IDictionary Properties => throw new NotImplementedException(); - public IConditionNode Clone() => throw new NotImplementedException(); + public IConditionNode Clone() => throw new NotImplementedException(); } } \ No newline at end of file diff --git a/tests/Rules.Framework.Tests/Extensions/GenericRuleExtensionsTests.cs b/tests/Rules.Framework.Tests/Extensions/GenericRuleExtensionsTests.cs index 90f66e09..a988c569 100644 --- a/tests/Rules.Framework.Tests/Extensions/GenericRuleExtensionsTests.cs +++ b/tests/Rules.Framework.Tests/Extensions/GenericRuleExtensionsTests.cs @@ -3,11 +3,9 @@ namespace Rules.Framework.Tests.Extensions using System; using System.Collections.Generic; using FluentAssertions; - using Rules.Framework.Builder; - using Rules.Framework.Core; - using Rules.Framework.Core.ConditionNodes; - using Rules.Framework.Extensions; - using Rules.Framework.Generics; + using Rules.Framework; + using Rules.Framework.Generic; + using Rules.Framework.Generic.ConditionNodes; using Rules.Framework.Tests.Stubs; using Xunit; @@ -18,33 +16,33 @@ public void GenericRuleExtensions_ToGenericRule_WithComposedCondition_Success() { var expectedRuleContent = "Type1"; - var expectedRootCondition = new GenericComposedConditionNode + var expectedRootCondition = new { - ChildConditionNodes = new List + ChildConditionNodes = new List { - new GenericValueConditionNode + new { - ConditionTypeName = ConditionType.IsVip.ToString(), + ConditionType = ConditionType.IsVip, DataType = DataTypes.Boolean, LogicalOperator = LogicalOperators.Eval, Operand = true, Operator = Operators.Equal }, - new GenericComposedConditionNode + new { - ChildConditionNodes = new List + ChildConditionNodes = new List { - new GenericValueConditionNode + new { - ConditionTypeName = ConditionType.IsoCurrency.ToString(), + ConditionType = ConditionType.IsoCurrency, DataType = DataTypes.String, LogicalOperator = LogicalOperators.Eval, Operand = "EUR", Operator = Operators.Equal }, - new GenericValueConditionNode + new { - ConditionTypeName = ConditionType.IsoCurrency.ToString(), + ConditionType = ConditionType.IsoCurrency, DataType = DataTypes.String, LogicalOperator = LogicalOperators.Eval, Operand = "USD", @@ -57,36 +55,37 @@ public void GenericRuleExtensions_ToGenericRule_WithComposedCondition_Success() LogicalOperator = LogicalOperators.And }; - var rootComposedCondition = new RootConditionNodeBuilder() - .And(a => a - .Value(ConditionType.IsVip, Operators.Equal, true) - .Or(o => o - .Value(ConditionType.IsoCurrency, Operators.Equal, "EUR") - .Value(ConditionType.IsoCurrency, Operators.Equal, "USD") - ) - ); - - var ruleBuilderResult = RuleBuilder.NewRule() + var ruleBuilderResult = Rule.New() .WithName("Dummy Rule") .WithDateBegin(DateTime.Parse("2018-01-01")) .WithContent(ContentType.Type1, expectedRuleContent) - .WithCondition(rootComposedCondition) + .WithCondition(b => b + .And(a => a + .Value(ConditionType.IsVip, Operators.Equal, true) + .Or(o => o + .Value(ConditionType.IsoCurrency, Operators.Equal, "EUR") + .Value(ConditionType.IsoCurrency, Operators.Equal, "USD") + ) + ) + ) .Build(); - var rule = ruleBuilderResult.Rule; + var rule = (Rule)ruleBuilderResult.Rule; // Act - var genericRule = rule.ToGenericRule(); + var genericRule = rule.ToGenericRule(); // Assert genericRule.Should().BeEquivalentTo(rule, config => config .Excluding(r => r.ContentContainer) - .Excluding(r => r.RootCondition)); - genericRule.Content.Should().BeOfType(); - genericRule.Content.Should().Be(expectedRuleContent); - genericRule.RootCondition.Should().BeOfType(); - - var genericComposedRootCondition = genericRule.RootCondition as GenericComposedConditionNode; + .Excluding(r => r.RootCondition) + .Excluding(r => r.ContentType)); + var content = genericRule.ContentContainer.GetContentAs(); + content.Should().BeOfType(); + content.Should().Be(expectedRuleContent); + genericRule.RootCondition.Should().BeOfType>(); + + var genericComposedRootCondition = genericRule.RootCondition as ComposedConditionNode; genericComposedRootCondition.Should().BeEquivalentTo(expectedRootCondition, config => config.IncludingAllRuntimeProperties()); } @@ -95,21 +94,24 @@ public void GenericRuleExtensions_ToGenericRule_WithoutConditions_Success() { var expectedRuleContent = "Type2"; - var ruleBuilderResult = RuleBuilder.NewRule() + var ruleBuilderResult = Rule.New() .WithName("Dummy Rule") .WithDateBegin(DateTime.Parse("2018-01-01")) .WithContent(ContentType.Type2, expectedRuleContent) .Build(); - var rule = ruleBuilderResult.Rule; + var rule = (Rule)ruleBuilderResult.Rule; // Act - var genericRule = rule.ToGenericRule(); + var genericRule = rule.ToGenericRule(); // Assert - genericRule.Should().BeEquivalentTo(rule, config => config.Excluding(r => r.ContentContainer)); - genericRule.Content.Should().BeOfType(); - genericRule.Content.Should().Be(expectedRuleContent); + genericRule.Should().BeEquivalentTo(rule, config => config + .Excluding(r => r.ContentContainer) + .Excluding(r => r.ContentType)); + var content = genericRule.ContentContainer.GetContentAs(); + content.Should().BeOfType(); + content.Should().Be(expectedRuleContent); genericRule.RootCondition.Should().BeNull(); } @@ -117,30 +119,39 @@ public void GenericRuleExtensions_ToGenericRule_WithoutConditions_Success() public void GenericRuleExtensions_ToGenericRule_WithValueCondition_Success() { var expectedRuleContent = "Type1"; - var expectedRootCondition = new ValueConditionNode(DataTypes.Integer, ConditionType.NumberOfSales, Operators.GreaterThan, 1000); + var expectedRootCondition = new + { + ConditionType = ConditionType.NumberOfSales, + DataType = DataTypes.Integer, + LogicalOperator = LogicalOperators.Eval, + Operator = Operators.GreaterThan, + Operand = 1000 + }; - var ruleBuilderResult = RuleBuilder.NewRule() + var ruleBuilderResult = Rule.New() .WithName("Dummy Rule") .WithDateBegin(DateTime.Parse("2018-01-01")) .WithContent(ContentType.Type1, expectedRuleContent) - .WithCondition(expectedRootCondition) + .WithCondition(ConditionType.NumberOfSales, Operators.GreaterThan, 1000) .Build(); - var rule = ruleBuilderResult.Rule; + var rule = (Rule)ruleBuilderResult.Rule; // Act - var genericRule = rule.ToGenericRule(); + var genericRule = rule.ToGenericRule(); // Assert genericRule.Should().BeEquivalentTo(rule, config => config .Excluding(r => r.ContentContainer) - .Excluding(r => r.RootCondition)); - genericRule.Content.Should().BeOfType(); - genericRule.Content.Should().Be(expectedRuleContent); - genericRule.RootCondition.Should().BeOfType(); - - var genericValueRootCondition = genericRule.RootCondition as GenericValueConditionNode; - genericValueRootCondition.ConditionTypeName.Should().Be(expectedRootCondition.ConditionType.ToString()); + .Excluding(r => r.RootCondition) + .Excluding(r => r.ContentType)); + var content = genericRule.ContentContainer.GetContentAs(); + content.Should().BeOfType(); + content.Should().Be(expectedRuleContent); + genericRule.RootCondition.Should().BeOfType>(); + + var genericValueRootCondition = genericRule.RootCondition as ValueConditionNode; + genericValueRootCondition.ConditionType.Should().Be(expectedRootCondition.ConditionType); genericValueRootCondition.DataType.Should().Be(expectedRootCondition.DataType); genericValueRootCondition.LogicalOperator.Should().Be(expectedRootCondition.LogicalOperator); genericValueRootCondition.Operand.Should().Be(expectedRootCondition.Operand); diff --git a/tests/Rules.Framework.Tests/Extensions/GenericSearchArgsExtensionsTests.cs b/tests/Rules.Framework.Tests/Extensions/GenericSearchArgsExtensionsTests.cs deleted file mode 100644 index a23f5549..00000000 --- a/tests/Rules.Framework.Tests/Extensions/GenericSearchArgsExtensionsTests.cs +++ /dev/null @@ -1,91 +0,0 @@ -namespace Rules.Framework.Tests.Extensions -{ - using System; - using System.Collections.Generic; - using FluentAssertions; - using Rules.Framework.Extensions; - using Rules.Framework.Generics; - using Rules.Framework.Tests.Stubs; - using Xunit; - - public class GenericSearchArgsExtensionsTests - { - [Fact] - public void GenericSearchArgsExtensions_ToSearchArgs_WithConditions_Success() - { - //Arrange - var contentType = ContentType.Type1; - var dateBegin = new DateTime(2018, 01, 01); - var dateEnd = new DateTime(2020, 12, 31); - var pluviosityRate = 132000.00m; - var countryCode = "USA"; - - var expectedSearchArgs = new SearchArgs(contentType, dateBegin, dateEnd) - { - Conditions = new List> - { - new Condition(ConditionType.PluviosityRate, pluviosityRate), - new Condition(ConditionType.IsoCountryCode, countryCode) - }, - ExcludeRulesWithoutSearchConditions = true - }; - - var contentTypeCode = "Type1"; - - var genericSearchArgs = new SearchArgs( - new GenericContentType { Identifier = contentTypeCode }, dateBegin, dateEnd - ) - { - Conditions = new List> - { - new Condition(new GenericConditionType { Identifier = "PluviosityRate" }, pluviosityRate), - new Condition(new GenericConditionType { Identifier = "IsoCountryCode" }, countryCode) - }, - ExcludeRulesWithoutSearchConditions = true - }; - - // Act - var convertedSearchArgs = genericSearchArgs.ToSearchArgs(); - - // Assert - convertedSearchArgs.Should().BeEquivalentTo(expectedSearchArgs); - } - - [Fact] - public void GenericSearchArgsExtensions_ToSearchArgs_WithInvalidType_ThrowsException() - { - //Arrange - var contentTypeCode = "Type1"; - var dateBegin = new DateTime(2018, 01, 01); - var dateEnd = new DateTime(2020, 12, 31); - - var genericSearchArgs = new SearchArgs( - new GenericContentType { Identifier = contentTypeCode }, dateBegin, dateEnd - ); - - // Act and Assert - Assert.Throws(() => genericSearchArgs.ToSearchArgs()); - } - - [Fact] - public void GenericSearchArgsExtensions_ToSearchArgs_WithoutConditions_Success() - { - //Arrange - var contentTypeCode = "Type1"; - var contentType = ContentType.Type1; - var dateBegin = new DateTime(2018, 01, 01); - var dateEnd = new DateTime(2020, 12, 31); - - var expectedSearchArgs = new SearchArgs(contentType, dateBegin, dateEnd, active: true); - - var genericSearchArgs = new SearchArgs( - new GenericContentType { Identifier = contentTypeCode }, dateBegin, dateEnd, active: true); - - // Act - var convertedSearchArgs = genericSearchArgs.ToSearchArgs(); - - // Assert - convertedSearchArgs.Should().BeEquivalentTo(expectedSearchArgs); - } - } -} \ No newline at end of file diff --git a/tests/Rules.Framework.Tests/Extensions/RulesEngineExtensionsTests.cs b/tests/Rules.Framework.Tests/Extensions/RulesEngineExtensionsTests.cs index 051c2eb0..a9b543be 100644 --- a/tests/Rules.Framework.Tests/Extensions/RulesEngineExtensionsTests.cs +++ b/tests/Rules.Framework.Tests/Extensions/RulesEngineExtensionsTests.cs @@ -3,8 +3,7 @@ namespace Rules.Framework.Tests.Extensions using FluentAssertions; using Moq; using Rules.Framework.Evaluation; - using Rules.Framework.Extension; - using Rules.Framework.Generics; + using Rules.Framework.Generic; using Rules.Framework.Source; using Rules.Framework.Tests.Stubs; using Rules.Framework.Validation; @@ -13,23 +12,22 @@ namespace Rules.Framework.Tests.Extensions public class RulesEngineExtensionsTests { [Fact] - public void RulesEngineExtensions_ToGenericEngine_Success() + public void RulesEngineExtensions_MakeGeneric_ReturnsGenericRulesEngine() { // Arrange - var rulesEngine = new RulesEngine( - Mock.Of>(), - Mock.Of>(), + var rulesEngine = new RulesEngine( + Mock.Of(), + Mock.Of(), Mock.Of(), RulesEngineOptions.NewWithDefaults(), - Mock.Of>() - ); + Mock.Of()); - //Act - var genericEngine = rulesEngine.CreateGenericEngine(); + // Act + var genericEngine = rulesEngine.MakeGeneric(); - //Arrange + // Assert genericEngine.Should().NotBeNull(); - genericEngine.GetType().Should().Be(typeof(GenericRulesEngine)); + genericEngine.GetType().Should().Be(typeof(RulesEngine)); } } } \ No newline at end of file diff --git a/tests/Rules.Framework.Tests/Generic/RulesEngineTests.cs b/tests/Rules.Framework.Tests/Generic/RulesEngineTests.cs new file mode 100644 index 00000000..4136c2bc --- /dev/null +++ b/tests/Rules.Framework.Tests/Generic/RulesEngineTests.cs @@ -0,0 +1,196 @@ +namespace Rules.Framework.Tests.Generic +{ + using System; + using System.Collections.Generic; + using System.Linq; + using System.Threading.Tasks; + using FluentAssertions; + using Moq; + using Rules.Framework; + using Rules.Framework.Generic; + using Rules.Framework.Tests.Stubs; + using Xunit; + + public class RulesEngineTests + { + private readonly IRulesEngine rulesEngineMock; + + public RulesEngineTests() + { + this.rulesEngineMock = Mock.Of(); + } + + [Fact] + public async Task GetContentTypes_NoConditionsGiven_ReturnsContentTypes() + { + // Arrange + var expectedGenericContentTypes = new List + { + ContentType.Type1, + ContentType.Type2, + }; + + var contentTypes = new[] { "Type1", "Type2" }; + Mock.Get(this.rulesEngineMock).Setup(x => x.GetContentTypesAsync()) + .ReturnsAsync(contentTypes); + + var genericRulesEngine = new RulesEngine(this.rulesEngineMock); + + // Act + var genericContentTypes = await genericRulesEngine.GetContentTypesAsync(); + + // Assert + genericContentTypes.Should().BeEquivalentTo(expectedGenericContentTypes); + } + + [Fact] + public async Task GetContentTypes_WithEmptyContentType_Success() + { + // Arrange + var mockRulesEngineEmptyContentType = new Mock(); + + var genericRulesEngine = new RulesEngine(mockRulesEngineEmptyContentType.Object); + + // Act + var genericContentTypes = await genericRulesEngine.GetContentTypesAsync(); + + // Assert + genericContentTypes.Should().BeEmpty(); + } + + [Fact] + public async Task GetUniqueConditionTypes_GivenContentTypeAndDatesInterval_ReturnsConditionTypes() + { + // Arrange + Mock.Get(this.rulesEngineMock) + .Setup(x => x.GetUniqueConditionTypesAsync(It.IsAny(), It.IsAny(), It.IsAny())) + .ReturnsAsync(new[] { nameof(ConditionType.NumberOfSales), nameof(ConditionType.IsVip), }); + + var genericRulesEngine = new RulesEngine(rulesEngineMock); + + // Act + var genericContentTypes = await genericRulesEngine.GetUniqueConditionTypesAsync(ContentType.Type1, DateTime.MinValue, DateTime.MaxValue); + + // Assert + genericContentTypes.Should().NotBeNullOrEmpty() + .And.Contain(ConditionType.NumberOfSales) + .And.Contain(ConditionType.IsVip); + } + + [Fact] + public void Options_PropertyGet_ReturnsRulesEngineOptions() + { + // Arrange + var options = RulesEngineOptions.NewWithDefaults(); + Mock.Get(this.rulesEngineMock) + .SetupGet(x => x.Options) + .Returns(options); + + var genericRulesEngine = new RulesEngine(this.rulesEngineMock); + + // Act + var actual = genericRulesEngine.Options; + + // Assert + actual.Should().BeSameAs(options); + } + + [Fact] + public async Task SearchAsync_GivenContentTypeAndDatesIntervalAndNoConditions_ReturnsRules() + { + // Arrange + var expectedRule = Rule.New() + .WithName("Test rule") + .WithDatesInterval(new DateTime(2018, 01, 01), new DateTime(2019, 01, 01)) + .WithContent(ContentType.Type1, new object()) + .WithCondition(ConditionType.IsoCountryCode, Operators.Equal, "USA") + .Build().Rule; + expectedRule.Priority = 3; + + var dateBegin = new DateTime(2022, 01, 01); + var dateEnd = new DateTime(2022, 12, 01); + var genericContentType = ContentType.Type1; + + var genericSearchArgs = new SearchArgs(genericContentType, dateBegin, dateEnd); + + var testRule = Rule.New() + .WithName("Test rule") + .WithDatesInterval(new DateTime(2018, 01, 01), new DateTime(2019, 01, 01)) + .WithContent(ContentType.Type1, new object()) + .WithCondition(ConditionType.IsoCountryCode, Operators.Equal, "USA") + .Build().Rule; + testRule.Priority = 3; + var testRules = new List + { + testRule + }; + + Mock.Get(this.rulesEngineMock) + .Setup(m => m.SearchAsync(It.IsAny>())) + .ReturnsAsync(testRules); + + var genericRulesEngine = new RulesEngine(this.rulesEngineMock); + + // Act + var genericRules = await genericRulesEngine.SearchAsync(genericSearchArgs); + + // Assert + var actualRule = genericRules.First(); + actualRule.Should().BeEquivalentTo(expectedRule); + Mock.Get(this.rulesEngineMock) + .Verify(m => m.SearchAsync(It.IsAny>()), Times.Once); + } + + [Theory] + [InlineData(nameof(RulesEngine.ActivateRuleAsync), "rule", typeof(ArgumentNullException))] + [InlineData(nameof(RulesEngine.AddRuleAsync), "rule", typeof(ArgumentNullException))] + [InlineData(nameof(RulesEngine.DeactivateRuleAsync), "rule", typeof(ArgumentNullException))] + [InlineData(nameof(RulesEngine.SearchAsync), "searchArgs", typeof(ArgumentNullException))] + [InlineData(nameof(RulesEngine.UpdateRuleAsync), "rule", typeof(ArgumentNullException))] + public async Task VerifyParameters_GivenNullParameter_ThrowsArgumentNullException(string methodName, string parameterName, Type exceptionType) + { + // Arrange + var sut = new RulesEngine(this.rulesEngineMock); + + // Act + var actual = await Assert.ThrowsAsync(exceptionType, async () => + { + switch (methodName) + { + case nameof(RulesEngine.ActivateRuleAsync): + _ = await sut.ActivateRuleAsync(null); + break; + + case nameof(RulesEngine.AddRuleAsync): + _ = await sut.AddRuleAsync(null, RuleAddPriorityOption.AtTop); + break; + + case nameof(RulesEngine.DeactivateRuleAsync): + _ = await sut.DeactivateRuleAsync(null); + break; + + case nameof(RulesEngine.SearchAsync): + _ = await sut.SearchAsync(null); + break; + + case nameof(RulesEngine.UpdateRuleAsync): + _ = await sut.UpdateRuleAsync(null); + break; + + default: + Assert.Fail("Test scenario not supported, please review test implementation to support it."); + break; + } + }); + + // Assert + actual.Should().NotBeNull() + .And.BeOfType(exceptionType); + if (actual is ArgumentException argumentException) + { + argumentException.Message.Should().Contain(parameterName); + argumentException.ParamName.Should().Be(parameterName); + } + } + } +} \ No newline at end of file diff --git a/tests/Rules.Framework.Tests/Generics/GenericRulesEngineTests.cs b/tests/Rules.Framework.Tests/Generics/GenericRulesEngineTests.cs deleted file mode 100644 index df107552..00000000 --- a/tests/Rules.Framework.Tests/Generics/GenericRulesEngineTests.cs +++ /dev/null @@ -1,146 +0,0 @@ -namespace Rules.Framework.Tests.Generics -{ - using System; - using System.Collections.Generic; - using System.Threading.Tasks; - using FluentAssertions; - using Moq; - using Rules.Framework.Core; - using Rules.Framework.Core.ConditionNodes; - using Rules.Framework.Generics; - using Rules.Framework.Tests.Stubs; - using Xunit; - - public class GenericRulesEngineTests - { - private readonly Mock> mockRulesEngine; - - public GenericRulesEngineTests() - { - this.mockRulesEngine = new Mock>(); - } - - [Fact] - public void GenericRulesEngine_GetContentTypes_Success() - { - // Arrange - var expectedGenericContentTypes = new List - { - new GenericContentType { Identifier = "Type1" }, - new GenericContentType { Identifier = "Type2" }, - }; - - var genericRulesEngine = new GenericRulesEngine(this.mockRulesEngine.Object); - - // Act - var genericContentTypes = genericRulesEngine.GetContentTypes(); - - // Assert - genericContentTypes.Should().BeEquivalentTo(expectedGenericContentTypes); - } - - [Fact] - public void GenericRulesEngine_GetContentTypes_WithClassContentType_ThrowsException() - { - // Arrange - var mockRulesEngineContentTypeClass = new Mock>(); - - var genericRulesEngine = new GenericRulesEngine(mockRulesEngineContentTypeClass.Object); - - // Act and Assert - Assert.Throws(() => genericRulesEngine.GetContentTypes()); - } - - [Fact] - public void GenericRulesEngine_GetContentTypes_WithEmptyContentType_Success() - { - // Arrange - var mockRulesEngineEmptyContentType = new Mock>(); - - var genericRulesEngine = new GenericRulesEngine(mockRulesEngineEmptyContentType.Object); - - // Act - var genericContentTypes = genericRulesEngine.GetContentTypes(); - - // Assert - genericContentTypes.Should().BeEmpty(); - } - - [Fact] - public void GenericRulesEngine_GetPriorityCriterias_CallsRulesEngineMethod() - { - // Arrange - var expectedPriorityCriteria = PriorityCriterias.TopmostRuleWins; - - this.mockRulesEngine.Setup(m => m.GetPriorityCriteria()).Returns(expectedPriorityCriteria); - - var genericRulesEngine = new GenericRulesEngine(this.mockRulesEngine.Object); - - // Act - var priorityCriteria = genericRulesEngine.GetPriorityCriteria(); - - // Assert - priorityCriteria.Should().Be(expectedPriorityCriteria); - this.mockRulesEngine.Verify(m => m.GetPriorityCriteria(), Times.Once); - } - - [Fact] - public async Task GenericRulesEngine_SearchAsync_Success() - { - // Arrange - var expectedGenericRules = new List - { - new GenericRule - { - Content = new ContentContainer(ContentType.Type1, (_) => new object()).GetContentAs(), - DateBegin = new DateTime(2018, 01, 01), - DateEnd = new DateTime(2019, 01, 01), - Name = "Test rule", - Priority = 3, - Active = true, - RootCondition = new GenericValueConditionNode - { - ConditionTypeName = ConditionType.IsoCountryCode.ToString(), - DataType = DataTypes.String, - LogicalOperator = LogicalOperators.Eval, - Operator = Operators.Equal, - Operand = "USA" - } - } - }; - - var dateBegin = new DateTime(2022, 01, 01); - var dateEnd = new DateTime(2022, 12, 01); - var genericContentType = new GenericContentType { Identifier = "Type1" }; - - var genericSearchArgs = new SearchArgs(genericContentType, dateBegin, dateEnd); - - var testRules = new List> - { - new Rule - { - ContentContainer = new ContentContainer(ContentType.Type1, (_) => new object()), - DateBegin = new DateTime(2018, 01, 01), - DateEnd = new DateTime(2019, 01, 01), - Name = "Test rule", - Priority = 3, - RootCondition = new ValueConditionNode(DataTypes.String, ConditionType.IsoCountryCode, Operators.Equal, "USA") - } - }; - - this.mockRulesEngine - .Setup(m => m.SearchAsync(It.IsAny>())) - .ReturnsAsync(testRules); - - var genericRulesEngine = new GenericRulesEngine(this.mockRulesEngine.Object); - - // Act - var genericRules = await genericRulesEngine.SearchAsync(genericSearchArgs).ConfigureAwait(false); - - // Assert - genericRules.Should().BeEquivalentTo(expectedGenericRules); - this.mockRulesEngine - .Verify(m => m.SearchAsync(It.IsAny>()), Times.Once); - } - } -} \ No newline at end of file diff --git a/tests/Rules.Framework.Tests/Providers/InMemory/InMemoryProviderRulesDataSourceSelectorExtensionsTests.cs b/tests/Rules.Framework.Tests/Providers/InMemory/InMemoryProviderRulesDataSourceSelectorExtensionsTests.cs index 8e912d53..1dbcad32 100644 --- a/tests/Rules.Framework.Tests/Providers/InMemory/InMemoryProviderRulesDataSourceSelectorExtensionsTests.cs +++ b/tests/Rules.Framework.Tests/Providers/InMemory/InMemoryProviderRulesDataSourceSelectorExtensionsTests.cs @@ -6,7 +6,6 @@ namespace Rules.Framework.Tests.Providers.InMemory using Moq; using Rules.Framework.Builder; using Rules.Framework.Providers.InMemory; - using Rules.Framework.Tests.Providers.InMemory.TestStubs; using Xunit; public class InMemoryProviderRulesDataSourceSelectorExtensionsTests @@ -15,7 +14,7 @@ public class InMemoryProviderRulesDataSourceSelectorExtensionsTests public void SetInMemoryDataSource_GivenNullRulesDataSourceSelector_ThrowsArgumentNullException() { // Arrange - IRulesDataSourceSelector rulesDataSourceSelector = null; + IRulesDataSourceSelector rulesDataSourceSelector = null; // Act var actual = Assert.Throws(() => rulesDataSourceSelector.SetInMemoryDataSource()); @@ -31,7 +30,7 @@ public void SetInMemoryDataSource_GivenNullServiceProvider_ThrowsArgumentNullExc // Arrange IServiceProvider serviceProvider = null; - var rulesDataSourceSelector = Mock.Of>(); + var rulesDataSourceSelector = Mock.Of(); // Act var actual = Assert.Throws(() => rulesDataSourceSelector.SetInMemoryDataSource(serviceProvider)); @@ -45,18 +44,18 @@ public void SetInMemoryDataSource_GivenNullServiceProvider_ThrowsArgumentNullExc public void SetInMemoryDataSource_GivenServiceProvider_RequestsInMemoryRulesStorageAndSetsOnSelector() { // Arrange - IInMemoryRulesStorage inMemoryRulesStorage = new InMemoryRulesStorage(); + var inMemoryRulesStorage = new InMemoryRulesStorage(); var serviceDescriptors = new ServiceCollection(); - serviceDescriptors.AddSingleton(inMemoryRulesStorage); + serviceDescriptors.AddSingleton(inMemoryRulesStorage); var serviceProvider = serviceDescriptors.BuildServiceProvider(); - var rulesDataSourceSelector = Mock.Of>(); + var rulesDataSourceSelector = Mock.Of(); - IRulesDataSource actualRulesDataSource = null; + IRulesDataSource actualRulesDataSource = null; Mock.Get(rulesDataSourceSelector) - .Setup(x => x.SetDataSource(It.IsAny>())) - .Callback>((rds) => + .Setup(x => x.SetDataSource(It.IsAny())) + .Callback((rds) => { actualRulesDataSource = rds; }); @@ -66,7 +65,7 @@ public void SetInMemoryDataSource_GivenServiceProvider_RequestsInMemoryRulesStor // Assert actualRulesDataSource.Should().NotBeNull(); - actualRulesDataSource.Should().BeOfType>(); + actualRulesDataSource.Should().BeOfType(); Mock.Get(rulesDataSourceSelector) .Verify(); } @@ -75,12 +74,12 @@ public void SetInMemoryDataSource_GivenServiceProvider_RequestsInMemoryRulesStor public void SetInMemoryDataSource_NoParametersGiven_CreatesTransientInMemoryRulesStorageAndSetsOnSelector() { // Arrange - var rulesDataSourceSelector = Mock.Of>(); + var rulesDataSourceSelector = Mock.Of(); - IRulesDataSource actualRulesDataSource = null; + IRulesDataSource actualRulesDataSource = null; Mock.Get(rulesDataSourceSelector) - .Setup(x => x.SetDataSource(It.IsAny>())) - .Callback>((rds) => + .Setup(x => x.SetDataSource(It.IsAny())) + .Callback((rds) => { actualRulesDataSource = rds; }); @@ -90,7 +89,7 @@ public void SetInMemoryDataSource_NoParametersGiven_CreatesTransientInMemoryRule // Assert actualRulesDataSource.Should().NotBeNull(); - actualRulesDataSource.Should().BeOfType>(); + actualRulesDataSource.Should().BeOfType(); Mock.Get(rulesDataSourceSelector) .Verify(); } diff --git a/tests/Rules.Framework.Tests/Providers/InMemory/InMemoryProviderRulesDataSourceTests.cs b/tests/Rules.Framework.Tests/Providers/InMemory/InMemoryProviderRulesDataSourceTests.cs index 1aea4c8e..2b970c7c 100644 --- a/tests/Rules.Framework.Tests/Providers/InMemory/InMemoryProviderRulesDataSourceTests.cs +++ b/tests/Rules.Framework.Tests/Providers/InMemory/InMemoryProviderRulesDataSourceTests.cs @@ -5,10 +5,8 @@ namespace Rules.Framework.Tests.Providers.InMemory using System.Threading.Tasks; using FluentAssertions; using Moq; - using Rules.Framework.Core; using Rules.Framework.Providers.InMemory; using Rules.Framework.Providers.InMemory.DataModel; - using Rules.Framework.Tests.Providers.InMemory.TestStubs; using Xunit; public class InMemoryProviderRulesDataSourceTests @@ -16,33 +14,32 @@ public class InMemoryProviderRulesDataSourceTests public static IEnumerable CtorArguments { get; } = new[] { new object[] { null, null }, - new object[] { Mock.Of>(), null } + new object[] { Mock.Of(), null } }; [Fact] public async Task AddRuleAsync_GivenNullRule_ThrowsArgumentNullException() { // Arrange - Rule rule = null; + Rule rule = null; - var inMemoryRulesStorage = Mock.Of>(); - var ruleFactory = Mock.Of>(); + var inMemoryRulesStorage = Mock.Of(); + var ruleFactory = Mock.Of(); Mock.Get(ruleFactory) .Setup(x => x.CreateRule(rule)) .Verifiable(); Mock.Get(inMemoryRulesStorage) - .Setup(x => x.AddRule(It.IsAny>())) + .Setup(x => x.AddRule(It.IsAny())) .Verifiable(); var inMemoryProviderRulesDataSource - = new InMemoryProviderRulesDataSource(inMemoryRulesStorage, ruleFactory); + = new InMemoryProviderRulesDataSource(inMemoryRulesStorage, ruleFactory); // Act var argumentNullException = await Assert.ThrowsAsync(async () => - await inMemoryProviderRulesDataSource.AddRuleAsync(rule).ConfigureAwait(false) - ).ConfigureAwait(false); + await inMemoryProviderRulesDataSource.AddRuleAsync(rule)); // Assert argumentNullException.Should().NotBeNull(); @@ -53,11 +50,11 @@ await inMemoryProviderRulesDataSource.AddRuleAsync(rule).ConfigureAwait(false) public async Task AddRuleAsync_GivenRule_ConvertsToRuleDataModelAndAddsToDataSource() { // Arrange - var rule = new Rule(); - var ruleDataModel = new RuleDataModel(); + var rule = new Rule(); + var ruleDataModel = new RuleDataModel(); - var inMemoryRulesStorage = Mock.Of>(); - var ruleFactory = Mock.Of>(); + var inMemoryRulesStorage = Mock.Of(); + var ruleFactory = Mock.Of(); Mock.Get(ruleFactory) .Setup(x => x.CreateRule(rule)) @@ -69,10 +66,10 @@ public async Task AddRuleAsync_GivenRule_ConvertsToRuleDataModelAndAddsToDataSou .Verifiable(); var inMemoryProviderRulesDataSource - = new InMemoryProviderRulesDataSource(inMemoryRulesStorage, ruleFactory); + = new InMemoryProviderRulesDataSource(inMemoryRulesStorage, ruleFactory); // Act - await inMemoryProviderRulesDataSource.AddRuleAsync(rule).ConfigureAwait(false); + await inMemoryProviderRulesDataSource.AddRuleAsync(rule); // Assert Mock.VerifyAll(Mock.Get(inMemoryRulesStorage), Mock.Get(ruleFactory)); @@ -83,11 +80,11 @@ var inMemoryProviderRulesDataSource public void Ctor_GivenNullParameters_ThrowsArgumentNullException(object param1, object param2) { // Arrange - var inMemoryRulesStorage = param1 as IInMemoryRulesStorage; - var ruleFactory = param2 as IRuleFactory; + var inMemoryRulesStorage = param1 as IInMemoryRulesStorage; + var ruleFactory = param2 as IRuleFactory; // Act - var argumentNullException = Assert.Throws(() => new InMemoryProviderRulesDataSource(inMemoryRulesStorage, ruleFactory)); + var argumentNullException = Assert.Throws(() => new InMemoryProviderRulesDataSource(inMemoryRulesStorage, ruleFactory)); //Assert argumentNullException.Should().NotBeNull(); @@ -98,26 +95,25 @@ public void Ctor_GivenNullParameters_ThrowsArgumentNullException(object param1, public async Task UpdateRuleAsync_GivenNullRule_ThrowsArgumentNullException() { // Arrange - Rule rule = null; + Rule rule = null; - var inMemoryRulesStorage = Mock.Of>(); - var ruleFactory = Mock.Of>(); + var inMemoryRulesStorage = Mock.Of(); + var ruleFactory = Mock.Of(); Mock.Get(ruleFactory) .Setup(x => x.CreateRule(rule)) .Verifiable(); Mock.Get(inMemoryRulesStorage) - .Setup(x => x.UpdateRule(It.IsAny>())) + .Setup(x => x.UpdateRule(It.IsAny())) .Verifiable(); var inMemoryProviderRulesDataSource - = new InMemoryProviderRulesDataSource(inMemoryRulesStorage, ruleFactory); + = new InMemoryProviderRulesDataSource(inMemoryRulesStorage, ruleFactory); // Act var argumentNullException = await Assert.ThrowsAsync(async () => - await inMemoryProviderRulesDataSource.UpdateRuleAsync(rule).ConfigureAwait(false) - ).ConfigureAwait(false); + await inMemoryProviderRulesDataSource.UpdateRuleAsync(rule)); // Assert argumentNullException.Should().NotBeNull(); @@ -128,11 +124,11 @@ await inMemoryProviderRulesDataSource.UpdateRuleAsync(rule).ConfigureAwait(false public async Task UpdateRuleAsync_GivenRule_ConvertsToRuleDataModelAndUpdatesOnDataSource() { // Arrange - var rule = new Rule(); - var ruleDataModel = new RuleDataModel(); + var rule = new Rule(); + var ruleDataModel = new RuleDataModel(); - var inMemoryRulesStorage = Mock.Of>(); - var ruleFactory = Mock.Of>(); + var inMemoryRulesStorage = Mock.Of(); + var ruleFactory = Mock.Of(); Mock.Get(ruleFactory) .Setup(x => x.CreateRule(rule)) @@ -144,10 +140,10 @@ public async Task UpdateRuleAsync_GivenRule_ConvertsToRuleDataModelAndUpdatesOnD .Verifiable(); var inMemoryProviderRulesDataSource - = new InMemoryProviderRulesDataSource(inMemoryRulesStorage, ruleFactory); + = new InMemoryProviderRulesDataSource(inMemoryRulesStorage, ruleFactory); // Act - await inMemoryProviderRulesDataSource.UpdateRuleAsync(rule).ConfigureAwait(false); + await inMemoryProviderRulesDataSource.UpdateRuleAsync(rule); // Assert Mock.VerifyAll(Mock.Get(inMemoryRulesStorage), Mock.Get(ruleFactory)); diff --git a/tests/Rules.Framework.Tests/Providers/InMemory/RuleFactoryTests.cs b/tests/Rules.Framework.Tests/Providers/InMemory/RuleFactoryTests.cs index fe48b85c..551f09cc 100644 --- a/tests/Rules.Framework.Tests/Providers/InMemory/RuleFactoryTests.cs +++ b/tests/Rules.Framework.Tests/Providers/InMemory/RuleFactoryTests.cs @@ -4,9 +4,10 @@ namespace Rules.Framework.Tests.Providers.InMemory using System.Dynamic; using System.Linq; using FluentAssertions; + using Rules.Framework; using Rules.Framework.Builder; + using Rules.Framework.ConditionNodes; using Rules.Framework.Core; - using Rules.Framework.Core.ConditionNodes; using Rules.Framework.Providers.InMemory; using Rules.Framework.Providers.InMemory.DataModel; using Rules.Framework.Tests.Providers.InMemory.TestStubs; @@ -18,9 +19,9 @@ public class RuleFactoryTests public void CreateRule_GivenNullRule_ThrowsArgumentNullException() { // Arrange - Rule rule = null; + Rule rule = null; - var ruleFactory = new RuleFactory(); + var ruleFactory = new RuleFactory(); // Act var argumentNullException = Assert.Throws(() => ruleFactory.CreateRule(rule)); @@ -34,9 +35,9 @@ public void CreateRule_GivenNullRule_ThrowsArgumentNullException() public void CreateRule_GivenNullRuleDataModel_ThrowsArgumentNullException() { // Arrange - RuleDataModel ruleDataModel = null; + RuleDataModel ruleDataModel = null; - var ruleFactory = new RuleFactory(); + var ruleFactory = new RuleFactory(); // Act var argumentNullException = Assert.Throws(() => ruleFactory.CreateRule(ruleDataModel)); @@ -55,9 +56,9 @@ public void CreateRule_GivenRuleDataModelWithComposedNodeAndChildNodesOfEachData content.Prop2 = "Sample string"; content.Prop3 = 500.34m; - var integerConditionNodeDataModel = new ValueConditionNodeDataModel + var integerConditionNodeDataModel = new ValueConditionNodeDataModel { - ConditionType = ConditionType.SampleIntegerCondition, + ConditionType = ConditionType.SampleIntegerCondition.ToString(), DataType = DataTypes.Integer, LogicalOperator = LogicalOperators.Eval, Operand = 20, @@ -65,9 +66,9 @@ public void CreateRule_GivenRuleDataModelWithComposedNodeAndChildNodesOfEachData Properties = new PropertiesDictionary(2), }; - var stringConditionNodeDataModel = new ValueConditionNodeDataModel + var stringConditionNodeDataModel = new ValueConditionNodeDataModel { - ConditionType = ConditionType.SampleStringCondition, + ConditionType = ConditionType.SampleStringCondition.ToString(), DataType = DataTypes.String, LogicalOperator = LogicalOperators.Eval, Operand = "TEST", @@ -75,9 +76,9 @@ public void CreateRule_GivenRuleDataModelWithComposedNodeAndChildNodesOfEachData Properties = new PropertiesDictionary(2), }; - var decimalConditionNodeDataModel = new ValueConditionNodeDataModel + var decimalConditionNodeDataModel = new ValueConditionNodeDataModel { - ConditionType = ConditionType.SampleDecimalCondition, + ConditionType = ConditionType.SampleDecimalCondition.ToString(), DataType = DataTypes.Decimal, LogicalOperator = LogicalOperators.Eval, Operand = 50.3m, @@ -85,9 +86,9 @@ public void CreateRule_GivenRuleDataModelWithComposedNodeAndChildNodesOfEachData Properties = new PropertiesDictionary(2), }; - var booleanConditionNodeDataModel = new ValueConditionNodeDataModel + var booleanConditionNodeDataModel = new ValueConditionNodeDataModel { - ConditionType = ConditionType.SampleBooleanCondition, + ConditionType = ConditionType.SampleBooleanCondition.ToString(), DataType = DataTypes.Boolean, LogicalOperator = LogicalOperators.Eval, Operand = true, @@ -95,18 +96,18 @@ public void CreateRule_GivenRuleDataModelWithComposedNodeAndChildNodesOfEachData Properties = new PropertiesDictionary(2), }; - var ruleDataModel = new RuleDataModel + var ruleDataModel = new RuleDataModel { Content = content, - ContentType = ContentType.ContentTypeSample, + ContentType = ContentType.ContentTypeSample.ToString(), DateBegin = new System.DateTime(2020, 1, 1), DateEnd = null, Name = "My rule used for testing purposes", Priority = 1, - RootCondition = new ComposedConditionNodeDataModel + RootCondition = new ComposedConditionNodeDataModel { LogicalOperator = LogicalOperators.And, - ChildConditionNodes = new ConditionNodeDataModel[] + ChildConditionNodes = new ConditionNodeDataModel[] { integerConditionNodeDataModel, stringConditionNodeDataModel, @@ -117,7 +118,7 @@ public void CreateRule_GivenRuleDataModelWithComposedNodeAndChildNodesOfEachData } }; - var ruleFactory = new RuleFactory(); + var ruleFactory = new RuleFactory(); // Act var rule = ruleFactory.CreateRule(ruleDataModel); @@ -125,18 +126,18 @@ public void CreateRule_GivenRuleDataModelWithComposedNodeAndChildNodesOfEachData // Assert rule.Should().NotBeNull(); rule.ContentContainer.Should().NotBeNull() - .And.BeOfType>(); + .And.BeOfType(); rule.DateBegin.Should().Be(ruleDataModel.DateBegin); rule.DateEnd.Should().BeNull(); rule.Name.Should().Be(ruleDataModel.Name); rule.Priority.Should().Be(ruleDataModel.Priority); - rule.RootCondition.Should().BeOfType>(); + rule.RootCondition.Should().BeOfType(); - var composedConditionNode = rule.RootCondition.As>(); + var composedConditionNode = rule.RootCondition.As(); composedConditionNode.LogicalOperator.Should().Be(LogicalOperators.And); composedConditionNode.ChildConditionNodes.Should().HaveCount(4); - var valueConditionNodes = composedConditionNode.ChildConditionNodes.OfType>(); + var valueConditionNodes = composedConditionNode.ChildConditionNodes.OfType(); valueConditionNodes.Should().HaveCount(4); var integerConditionNode = valueConditionNodes.First(x => x.DataType == DataTypes.Integer); integerConditionNode.Should().NotBeNull(); @@ -181,15 +182,15 @@ public void CreateRule_GivenRuleWithComposedNodeAndChildNodesOfEachDataType_Retu content.Prop3 = 500.34m; var booleanConditionNode = ConditionNodeFactory - .CreateValueNode(ConditionType.SampleBooleanCondition, Operators.NotEqual, true) as ValueConditionNode; + .CreateValueNode(ConditionType.SampleBooleanCondition.ToString(), Operators.NotEqual, true) as ValueConditionNode; var decimalConditionNode = ConditionNodeFactory - .CreateValueNode(ConditionType.SampleDecimalCondition, Operators.LesserThanOrEqual, 50.3m) as ValueConditionNode; + .CreateValueNode(ConditionType.SampleDecimalCondition.ToString(), Operators.LesserThanOrEqual, 50.3m) as ValueConditionNode; var integerConditionNode = ConditionNodeFactory - .CreateValueNode(ConditionType.SampleIntegerCondition, Operators.GreaterThan, 20) as ValueConditionNode; + .CreateValueNode(ConditionType.SampleIntegerCondition.ToString(), Operators.GreaterThan, 20) as ValueConditionNode; var stringConditionNode = ConditionNodeFactory - .CreateValueNode(ConditionType.SampleStringCondition, Operators.Equal, "TEST") as ValueConditionNode; + .CreateValueNode(ConditionType.SampleStringCondition.ToString(), Operators.Equal, "TEST") as ValueConditionNode; - var rule1 = RuleBuilder.NewRule() + var rule1 = Rule.New() .WithName("My rule used for testing purposes") .WithDateBegin(new DateTime(2020, 1, 1)) .WithContent(ContentType.ContentTypeSample, (object)content) @@ -202,7 +203,7 @@ public void CreateRule_GivenRuleWithComposedNodeAndChildNodesOfEachDataType_Retu )) .Build().Rule; - var ruleFactory = new RuleFactory(); + var ruleFactory = new RuleFactory(); // Act var rule = ruleFactory.CreateRule(rule1); @@ -216,13 +217,13 @@ public void CreateRule_GivenRuleWithComposedNodeAndChildNodesOfEachDataType_Retu rule.DateEnd.Should().BeNull(); rule.Name.Should().Be(rule.Name); rule.Priority.Should().Be(rule.Priority); - rule.RootCondition.Should().BeOfType>(); + rule.RootCondition.Should().BeOfType(); - var composedConditionNodeDataModel = rule.RootCondition.As>(); + var composedConditionNodeDataModel = rule.RootCondition.As(); composedConditionNodeDataModel.LogicalOperator.Should().Be(LogicalOperators.And); composedConditionNodeDataModel.ChildConditionNodes.Should().HaveCount(4); - var valueConditionNodeDataModels = composedConditionNodeDataModel.ChildConditionNodes.OfType>(); + var valueConditionNodeDataModels = composedConditionNodeDataModel.ChildConditionNodes.OfType(); valueConditionNodeDataModels.Should().HaveCount(4); var integerConditionNodeDataModel = valueConditionNodeDataModels.First(v => v.DataType == DataTypes.Integer); integerConditionNodeDataModel.Should().NotBeNull(); diff --git a/tests/Rules.Framework.Tests/Providers/InMemory/ServiceCollectionExtensionsTests.cs b/tests/Rules.Framework.Tests/Providers/InMemory/ServiceCollectionExtensionsTests.cs index 01e093dc..16ccf276 100644 --- a/tests/Rules.Framework.Tests/Providers/InMemory/ServiceCollectionExtensionsTests.cs +++ b/tests/Rules.Framework.Tests/Providers/InMemory/ServiceCollectionExtensionsTests.cs @@ -3,7 +3,6 @@ namespace Rules.Framework.Tests.Providers.InMemory using FluentAssertions; using Microsoft.Extensions.DependencyInjection; using Moq; - using Rules.Framework.Tests.Providers.InMemory.TestStubs; using Xunit; public class ServiceCollectionExtensionsTests @@ -24,7 +23,7 @@ public void AddInMemoryRulesDataSource_GivenSingletonLifetimeOption_AddsServiceD }); // Act - var actual = services.AddInMemoryRulesDataSource(serviceLifetime); + var actual = services.AddInMemoryRulesDataSource(serviceLifetime); // Assert actual.Should().NotBeNull(); diff --git a/tests/Rules.Framework.Tests/RuleOperationResultTests.cs b/tests/Rules.Framework.Tests/RuleOperationResultTests.cs index e1e5e159..01c56a19 100644 --- a/tests/Rules.Framework.Tests/RuleOperationResultTests.cs +++ b/tests/Rules.Framework.Tests/RuleOperationResultTests.cs @@ -8,13 +8,13 @@ namespace Rules.Framework.Tests public class RuleOperationResultTests { [Fact] - public void Error_GivenCollectionOfErrors_ReturnsRuleOperationResultWithErrorsAndNoSuccess() + public void Failure_GivenCollectionOfErrors_ReturnsRuleOperationResultWithErrorsAndNoSuccess() { // Arrange IEnumerable errors = new[] { "Error1", "Error2" }; // Act - RuleOperationResult ruleOperationResult = RuleOperationResult.Error(errors); + var ruleOperationResult = OperationResult.Failure(errors); // Assert ruleOperationResult.Should().NotBeNull(); @@ -23,13 +23,13 @@ public void Error_GivenCollectionOfErrors_ReturnsRuleOperationResultWithErrorsAn } [Fact] - public void Error_GivenNullCollectionOfErrors_ThrowsArgumentNullException() + public void Failure_GivenNullCollectionOfErrors_ThrowsArgumentNullException() { // Arrange IEnumerable errors = null; // Act - ArgumentNullException argumentNullException = Assert.Throws(() => RuleOperationResult.Error(errors)); + var argumentNullException = Assert.Throws(() => OperationResult.Failure(errors)); // Assert argumentNullException.Should().NotBeNull(); @@ -40,7 +40,7 @@ public void Error_GivenNullCollectionOfErrors_ThrowsArgumentNullException() public void Success_NoConditionGiven_ReturnsRuleOperationResultWithoutErrorsAndSuccess() { // Act - RuleOperationResult ruleOperationResult = RuleOperationResult.Success(); + var ruleOperationResult = OperationResult.Success(); // Assert ruleOperationResult.Should().NotBeNull(); diff --git a/tests/Rules.Framework.Tests/Core/RuleTests.cs b/tests/Rules.Framework.Tests/RuleTests.cs similarity index 74% rename from tests/Rules.Framework.Tests/Core/RuleTests.cs rename to tests/Rules.Framework.Tests/RuleTests.cs index 536005bc..ad09485d 100644 --- a/tests/Rules.Framework.Tests/Core/RuleTests.cs +++ b/tests/Rules.Framework.Tests/RuleTests.cs @@ -1,10 +1,10 @@ -namespace Rules.Framework.Tests.Core +namespace Rules.Framework.Tests { using System; using FluentAssertions; using Moq; - using Rules.Framework.Core; - using Rules.Framework.Core.ConditionNodes; + using Rules.Framework; + using Rules.Framework.ConditionNodes; using Rules.Framework.Tests.Stubs; using Xunit; @@ -14,9 +14,9 @@ public class RuleTests public void Clone_WithRuleWithoutRootCondition_ReturnsCopy() { // Arrange - var rule = new Rule + var rule = new Rule { - ContentContainer = new ContentContainer(ContentType.Type1, _ => new object()), + ContentContainer = new ContentContainer(_ => new object()), DateBegin = DateTime.UtcNow.AddDays(-1), DateEnd = DateTime.UtcNow.AddDays(1), Priority = 1, @@ -35,14 +35,14 @@ public void Clone_WithRuleWithoutRootCondition_ReturnsCopy() public void Clone_WithRuleWithRootCondition_ReturnsCopy() { // Arrange - var rule = new Rule + var rule = new Rule { - ContentContainer = new ContentContainer(ContentType.Type1, _ => new object()), + ContentContainer = new ContentContainer(_ => new object()), DateBegin = DateTime.UtcNow.AddDays(-1), DateEnd = DateTime.UtcNow.AddDays(1), Priority = 1, Name = "Name", - RootCondition = new ValueConditionNode(DataTypes.Decimal, ConditionType.PluviosityRate, Operators.GreaterThanOrEqual, 80.0d), + RootCondition = new ValueConditionNode(DataTypes.Decimal, ConditionType.PluviosityRate.ToString(), Operators.GreaterThanOrEqual, 80.0d), }; rule.RootCondition.Properties["key1"] = "value1"; rule.RootCondition.Properties["key2"] = new object(); @@ -58,9 +58,9 @@ public void Clone_WithRuleWithRootCondition_ReturnsCopy() public void ContentContainer_HavingSettedInstance_ReturnsProvidedInstance() { // Arrange - var expected = new ContentContainer(ContentType.Type1, (_) => null); + var expected = new ContentContainer((_) => null); - var sut = new Rule + var sut = new Rule { ContentContainer = expected }; @@ -78,7 +78,7 @@ public void DateBegin_HavingSettedValue_ReturnsProvidedValue() // Arrange var expected = new DateTime(2018, 07, 19); - var sut = new Rule + var sut = new Rule { DateBegin = expected }; @@ -96,7 +96,7 @@ public void DateEnd_HavingSettedValue_ReturnsProvidedValue() // Arrange var expected = new DateTime(2018, 07, 19); - var sut = new Rule + var sut = new Rule { DateEnd = expected }; @@ -112,7 +112,7 @@ public void DateEnd_HavingSettedValue_ReturnsProvidedValue() public void DateEnd_NotHavingSettedValue_ReturnsNull() { // Arrange - var sut = new Rule(); + var sut = new Rule(); // Act var actual = sut.DateEnd; @@ -125,9 +125,9 @@ public void DateEnd_NotHavingSettedValue_ReturnsNull() public void Name_HavingSettedValue_ReturnsProvidedValue() { // Arrange - string expected = "My awesome name"; + var expected = "My awesome name"; - var sut = new Rule + var sut = new Rule { Name = expected }; @@ -145,7 +145,7 @@ public void Priority_HavingSettedValue_ReturnsProvidedValue() // Arrange var expected = 123; - var sut = new Rule + var sut = new Rule { Priority = expected }; @@ -161,10 +161,10 @@ public void Priority_HavingSettedValue_ReturnsProvidedValue() public void RootCondition_HavingSettedInstance_ReturnsProvidedInstance() { // Arrange - var mockConditionNode = new Mock>(); + var mockConditionNode = new Mock(); var expected = mockConditionNode.Object; - var sut = new Rule + var sut = new Rule { RootCondition = expected }; diff --git a/tests/Rules.Framework.Tests/RulesEngineTests.cs b/tests/Rules.Framework.Tests/RulesEngineTests.cs index fe302417..1a4e7adf 100644 --- a/tests/Rules.Framework.Tests/RulesEngineTests.cs +++ b/tests/Rules.Framework.Tests/RulesEngineTests.cs @@ -2,6 +2,7 @@ namespace Rules.Framework.Tests { using System; using System.Collections.Generic; + using System.Globalization; using System.Linq; using System.Threading; using System.Threading.Tasks; @@ -9,8 +10,8 @@ namespace Rules.Framework.Tests using FluentValidation; using FluentValidation.Results; using Moq; - using Rules.Framework.Core; - using Rules.Framework.Core.ConditionNodes; + using Rules.Framework; + using Rules.Framework.ConditionNodes; using Rules.Framework.Evaluation; using Rules.Framework.Source; using Rules.Framework.Tests.Stubs; @@ -19,90 +20,159 @@ namespace Rules.Framework.Tests public class RulesEngineTests { - private readonly Mock> mockConditionsEvalEngine; - private readonly Mock> mockCondtionTypeExtractor; - private readonly Mock> mockRulesSource; + private readonly IConditionsEvalEngine conditionsEvalEngineMock; + private readonly IConditionTypeExtractor conditionTypeExtractorMock; + private readonly IRulesSource rulesSourceMock; + private readonly IValidatorProvider validatorProviderMock; public RulesEngineTests() { - this.mockRulesSource = new Mock>(); - this.mockCondtionTypeExtractor = new Mock>(); - this.mockConditionsEvalEngine = new Mock>(); + this.rulesSourceMock = Mock.Of(); + this.conditionTypeExtractorMock = Mock.Of(); + this.conditionsEvalEngineMock = Mock.Of(); + this.validatorProviderMock = Mock.Of(); } [Fact] public async Task ActivateRuleAsync_GivenEmptyRuleDataSource_ActivatesRuleSuccessfully() { // Arrange - var contentType = ContentType.Type1; - - var testRule = new Rule + var testRule = new Rule { - ContentContainer = new ContentContainer(contentType, (t) => new object()), + ContentContainer = new ContentContainer(_ => new object()), DateBegin = new DateTime(2018, 01, 01), DateEnd = new DateTime(2019, 01, 01), Name = "Update test rule", Priority = 3, Active = false, - RootCondition = new ValueConditionNode(DataTypes.String, ConditionType.IsoCountryCode, Operators.Equal, "USA") + RootCondition = new ValueConditionNode(DataTypes.String, ConditionType.IsoCountryCode.ToString(), Operators.Equal, "USA") }; - var evaluationOptions = new EvaluationOptions + Mock.Get(rulesSourceMock) + .Setup(s => s.GetRulesFilteredAsync(It.IsAny())) + .ReturnsAsync(new List { testRule }); + + var validatorProvider = Mock.Of(); + var rulesEngineOptions = RulesEngineOptions.NewWithDefaults(); + + var sut = new RulesEngine(conditionsEvalEngineMock, rulesSourceMock, validatorProvider, rulesEngineOptions, conditionTypeExtractorMock); + + // Act + var actual = await sut.ActivateRuleAsync(testRule); + + // Assert + actual.IsSuccess.Should().BeTrue(); + actual.Errors.Should().BeEmpty(); + + Mock.Get(rulesSourceMock).Verify(x => x.GetRulesFilteredAsync(It.IsAny()), Times.Once()); + Mock.Get(conditionsEvalEngineMock).VerifyNoOtherCalls(); + } + + [Fact] + public async Task AddRuleAsync_GivenEmptyRuleDataSourceAndExistentContentType_AddsRuleSuccessfully() + { + // Arrange + var contentType = ContentType.Type1.ToString(); + + var testRule = new Rule { - MatchMode = MatchModes.Exact + ContentType = contentType, + ContentContainer = new ContentContainer(_ => new object()), + DateBegin = new DateTime(2018, 01, 01), + DateEnd = new DateTime(2019, 01, 01), + Name = "Test rule", + Priority = 3, + RootCondition = new ValueConditionNode(DataTypes.String, ConditionType.IsoCountryCode.ToString(), Operators.Equal, "USA") }; - mockRulesSource.Setup(s => s.GetRulesFilteredAsync(It.IsAny>())) - .ReturnsAsync(new List> { testRule }); + Mock.Get(rulesSourceMock) + .Setup(x => x.GetContentTypesAsync(It.IsAny())) + .ReturnsAsync(new[] { contentType }); - var validatorProvider = Mock.Of(); var rulesEngineOptions = RulesEngineOptions.NewWithDefaults(); - var sut = new RulesEngine(mockConditionsEvalEngine.Object, mockRulesSource.Object, validatorProvider, rulesEngineOptions, mockCondtionTypeExtractor.Object); + rulesEngineOptions.PriorityCriteria = PriorityCriterias.BottommostRuleWins; + + var sut = new RulesEngine(conditionsEvalEngineMock, rulesSourceMock, validatorProviderMock, rulesEngineOptions, conditionTypeExtractorMock); // Act - var actual = await sut.ActivateRuleAsync(testRule).ConfigureAwait(false); + var actual = await sut.AddRuleAsync(testRule, RuleAddPriorityOption.AtBottom); // Assert actual.IsSuccess.Should().BeTrue(); actual.Errors.Should().BeEmpty(); - mockRulesSource.Verify(x => x.GetRulesFilteredAsync(It.IsAny>()), Times.Once()); - mockConditionsEvalEngine.Verify(x => x.Eval( - It.IsAny>(), - It.IsAny>(), - It.Is(eo => eo == evaluationOptions)), Times.Never()); + Mock.Get(rulesSourceMock).Verify(x => x.GetRulesFilteredAsync(It.IsAny()), Times.Once()); + Mock.Get(conditionsEvalEngineMock).VerifyNoOtherCalls(); } [Fact] - public async Task AddRuleAsync_GivenEmptyRuleDataSource_AddsRuleSuccesfully() + public async Task AddRuleAsync_GivenEmptyRuleDataSourceAndNonExistentContentTypeAndAutoCreateContentTypeDisabled_DoesNotAddRuleAndReportsError() { // Arrange - var contentType = ContentType.Type1; + var contentType = ContentType.Type1.ToString(); - var testRule = new Rule + var testRule = new Rule { - ContentContainer = new ContentContainer(contentType, (t) => new object()), + ContentType = contentType, + ContentContainer = new ContentContainer(_ => new object()), DateBegin = new DateTime(2018, 01, 01), DateEnd = new DateTime(2019, 01, 01), Name = "Test rule", Priority = 3, - RootCondition = new ValueConditionNode(DataTypes.String, ConditionType.IsoCountryCode, Operators.Equal, "USA") + RootCondition = new ValueConditionNode(DataTypes.String, ConditionType.IsoCountryCode.ToString(), Operators.Equal, "USA") }; - EvaluationOptions evaluationOptions = new() + Mock.Get(rulesSourceMock) + .Setup(x => x.GetContentTypesAsync(It.IsAny())) + .ReturnsAsync(Array.Empty()); + + var rulesEngineOptions = RulesEngineOptions.NewWithDefaults(); + + rulesEngineOptions.PriorityCriteria = PriorityCriterias.BottommostRuleWins; + + var sut = new RulesEngine(conditionsEvalEngineMock, rulesSourceMock, validatorProviderMock, rulesEngineOptions, conditionTypeExtractorMock); + + // Act + var actual = await sut.AddRuleAsync(testRule, RuleAddPriorityOption.AtBottom); + + // Assert + actual.IsSuccess.Should().BeFalse(); + actual.Errors.Should().HaveCount(1); + + Mock.Get(rulesSourceMock).Verify(x => x.GetRulesFilteredAsync(It.IsAny()), Times.Never()); + Mock.Get(conditionsEvalEngineMock).VerifyNoOtherCalls(); + } + + [Fact] + public async Task AddRuleAsync_GivenEmptyRuleDataSourceAndNonExistentContentTypeAndAutoCreateContentTypeEnabled_CreatesContentTypeAndAddsRuleSuccessfully() + { + // Arrange + var contentType = ContentType.Type1.ToString(); + + var testRule = new Rule { - MatchMode = MatchModes.Exact + ContentType = contentType, + ContentContainer = new ContentContainer(_ => new object()), + DateBegin = new DateTime(2018, 01, 01), + DateEnd = new DateTime(2019, 01, 01), + Name = "Test rule", + Priority = 3, + RootCondition = new ValueConditionNode(DataTypes.String, ConditionType.IsoCountryCode.ToString(), Operators.Equal, "USA") }; - this.SetupMockForConditionsEvalEngine(true, evaluationOptions); + Mock.Get(this.rulesSourceMock) + .Setup(x => x.GetContentTypesAsync(It.IsAny())) + .ReturnsAsync(Array.Empty()); + Mock.Get(this.rulesSourceMock) + .Setup(x => x.CreateContentTypeAsync(It.IsAny())) + .Returns(Task.CompletedTask); - var validatorProvider = Mock.Of(); var rulesEngineOptions = RulesEngineOptions.NewWithDefaults(); - rulesEngineOptions.PriorityCriteria = PriorityCriterias.BottommostRuleWins; + rulesEngineOptions.AutoCreateContentTypes = true; - var sut = new RulesEngine(mockConditionsEvalEngine.Object, mockRulesSource.Object, validatorProvider, rulesEngineOptions, mockCondtionTypeExtractor.Object); + var sut = new RulesEngine(conditionsEvalEngineMock, rulesSourceMock, validatorProviderMock, rulesEngineOptions, conditionTypeExtractorMock); // Act var actual = await sut.AddRuleAsync(testRule, RuleAddPriorityOption.AtBottom); @@ -111,27 +181,87 @@ public async Task AddRuleAsync_GivenEmptyRuleDataSource_AddsRuleSuccesfully() actual.IsSuccess.Should().BeTrue(); actual.Errors.Should().BeEmpty(); - mockRulesSource.Verify(x => x.GetRulesAsync(It.IsAny>()), Times.Never()); - mockConditionsEvalEngine.Verify(x => x.Eval( - It.IsAny>(), - It.IsAny>(), - It.Is(eo => eo == evaluationOptions)), Times.Never()); + Mock.Get(rulesSourceMock).Verify(x => x.GetContentTypesAsync(It.IsAny()), Times.Once()); + Mock.Get(rulesSourceMock).Verify(x => x.CreateContentTypeAsync(It.IsAny()), Times.Once()); + Mock.Get(rulesSourceMock).Verify(x => x.GetRulesFilteredAsync(It.IsAny()), Times.Once()); + Mock.Get(conditionsEvalEngineMock).VerifyNoOtherCalls(); } [Fact] - public async Task DeactivateRuleAsync_GivenEmptyRuleDataSource_DeactivatesRuleSuccessfully() + public async Task CreateContentTypeAsync_GivenExistentContentTypeName_DoesNotAddContentTypeToRulesSource() { // Arrange - var contentType = ContentType.Type1; + var contentType = ContentType.Type1.ToString(); + + Mock.Get(this.rulesSourceMock) + .Setup(x => x.GetContentTypesAsync(It.IsAny())) + .ReturnsAsync(new[] { nameof(ContentType.Type1), }); + + var rulesEngineOptions = RulesEngineOptions.NewWithDefaults(); + + rulesEngineOptions.PriorityCriteria = PriorityCriterias.BottommostRuleWins; + + var sut = new RulesEngine(conditionsEvalEngineMock, rulesSourceMock, validatorProviderMock, rulesEngineOptions, conditionTypeExtractorMock); + + // Act + var operationResult = await sut.CreateContentTypeAsync(contentType); + + // Assert + operationResult.Should().NotBeNull(); + operationResult.IsSuccess.Should().BeFalse(); + operationResult.Errors.Should().NotBeNull() + .And.HaveCount(1); + + Mock.Get(rulesSourceMock).Verify(x => x.GetContentTypesAsync(It.IsAny()), Times.Once()); + Mock.Get(rulesSourceMock).Verify(x => x.CreateContentTypeAsync(It.Is(x => string.Equals(x.Name, contentType))), Times.Never()); + Mock.Get(conditionsEvalEngineMock).VerifyNoOtherCalls(); + } + + [Fact] + public async Task CreateContentTypeAsync_GivenNonExistentContentTypeName_AddsContentTypeToRulesSource() + { + // Arrange + var contentType = ContentType.Type1.ToString(); + + Mock.Get(this.rulesSourceMock) + .Setup(x => x.GetContentTypesAsync(It.IsAny())) + .ReturnsAsync(Array.Empty()); + Mock.Get(rulesSourceMock) + .Setup(x => x.CreateContentTypeAsync(It.Is(x => string.Equals(x.Name, contentType)))) + .Returns(Task.CompletedTask); + + var rulesEngineOptions = RulesEngineOptions.NewWithDefaults(); + + rulesEngineOptions.PriorityCriteria = PriorityCriterias.BottommostRuleWins; + + var sut = new RulesEngine(conditionsEvalEngineMock, rulesSourceMock, validatorProviderMock, rulesEngineOptions, conditionTypeExtractorMock); + + // Act + var operationResult = await sut.CreateContentTypeAsync(contentType); - var testRule = new Rule + // Assert + operationResult.Should().NotBeNull(); + operationResult.IsSuccess.Should().BeTrue(); + operationResult.Errors.Should().NotBeNull() + .And.BeEmpty(); + + Mock.Get(rulesSourceMock).Verify(x => x.GetContentTypesAsync(It.IsAny()), Times.Once()); + Mock.Get(rulesSourceMock).Verify(x => x.CreateContentTypeAsync(It.Is(x => string.Equals(x.Name, contentType))), Times.Once()); + Mock.Get(conditionsEvalEngineMock).VerifyNoOtherCalls(); + } + + [Fact] + public async Task DeactivateRuleAsync_GivenEmptyRuleDataSource_DeactivatesRuleSuccessfully() + { + // Arrange + var testRule = new Rule { - ContentContainer = new ContentContainer(contentType, (t) => new object()), + ContentContainer = new ContentContainer(_ => new object()), DateBegin = new DateTime(2018, 01, 01), DateEnd = new DateTime(2019, 01, 01), Name = "Update test rule", Priority = 3, - RootCondition = new ValueConditionNode(DataTypes.String, ConditionType.IsoCountryCode, Operators.Equal, "USA") + RootCondition = new ValueConditionNode(DataTypes.String, ConditionType.IsoCountryCode.ToString(), Operators.Equal, "USA") }; var evaluationOptions = new EvaluationOptions @@ -139,45 +269,52 @@ public async Task DeactivateRuleAsync_GivenEmptyRuleDataSource_DeactivatesRuleSu MatchMode = MatchModes.Exact }; - mockRulesSource.Setup(s => s.GetRulesFilteredAsync(It.IsAny>())) - .ReturnsAsync(new List> { testRule }); + Mock.Get(rulesSourceMock).Setup(s => s.GetRulesFilteredAsync(It.IsAny())) + .ReturnsAsync(new List { testRule }); var validatorProvider = Mock.Of(); var rulesEngineOptions = RulesEngineOptions.NewWithDefaults(); - var sut = new RulesEngine(mockConditionsEvalEngine.Object, mockRulesSource.Object, validatorProvider, rulesEngineOptions, mockCondtionTypeExtractor.Object); + var sut = new RulesEngine(conditionsEvalEngineMock, rulesSourceMock, validatorProvider, rulesEngineOptions, conditionTypeExtractorMock); // Act - var actual = await sut.DeactivateRuleAsync(testRule).ConfigureAwait(false); + var actual = await sut.DeactivateRuleAsync(testRule); // Assert actual.IsSuccess.Should().BeTrue(); actual.Errors.Should().BeEmpty(); - mockRulesSource.Verify(x => x.GetRulesFilteredAsync(It.IsAny>()), Times.Once()); - mockConditionsEvalEngine.Verify(x => x.Eval( - It.IsAny>(), - It.IsAny>(), + Mock.Get(rulesSourceMock).Verify(x => x.GetRulesFilteredAsync(It.IsAny()), Times.Once()); + Mock.Get(conditionsEvalEngineMock).Verify(x => x.Eval( + It.IsAny(), + It.IsAny>(), It.Is(eo => eo == evaluationOptions)), Times.Never()); } [Fact] - public void GetPriorityCriterias_GivenRulesEngineOptionsNewWithDefaults_ReturnsTopMostRuleWins() + public async Task GetContentTypesAsync_NoConditionsGiven_ReturnsContentTypesFromRulesSource() { // Arrange - var rulesEngine = new RulesEngine( - Mock.Of>(), - Mock.Of>(), - Mock.Of(), - RulesEngineOptions.NewWithDefaults(), - Mock.Of>() - ); - - //Act - var priorityCriterias = rulesEngine.GetPriorityCriteria(); - - //Arrange - priorityCriterias.Should().Be(PriorityCriterias.TopmostRuleWins); + Mock.Get(this.rulesSourceMock) + .Setup(x => x.GetContentTypesAsync(It.IsAny())) + .ReturnsAsync(new[] { nameof(ContentType.Type1), nameof(ContentType.Type2), }); + var rulesEngineOptions = RulesEngineOptions.NewWithDefaults(); + + rulesEngineOptions.PriorityCriteria = PriorityCriterias.BottommostRuleWins; + + var sut = new RulesEngine(conditionsEvalEngineMock, rulesSourceMock, validatorProviderMock, rulesEngineOptions, conditionTypeExtractorMock); + + // Act + var contentTypes = await sut.GetContentTypesAsync(); + + // Assert + contentTypes.Should().NotBeNull() + .And.HaveCount(2) + .And.Contain(nameof(ContentType.Type1)) + .And.Contain(nameof(ContentType.Type2)); + + Mock.Get(rulesSourceMock).Verify(x => x.GetContentTypesAsync(It.IsAny()), Times.Once()); + Mock.Get(conditionsEvalEngineMock).VerifyNoOtherCalls(); } [Fact] @@ -193,31 +330,24 @@ public async Task GetUniqueConditionTypesAsync_GivenThereAreRulesInDataSource_Re MatchMode = MatchModes.Exact }; - var expectedCondtionTypes = new List { ConditionType.IsoCountryCode }; + var expectedCondtionTypes = new List { ConditionType.IsoCountryCode.ToString() }; - mockCondtionTypeExtractor.Setup(x => x.GetConditionTypes(It.IsAny>>())) + Mock.Get(conditionTypeExtractorMock) + .Setup(x => x.GetConditionTypes(It.IsAny>())) .Returns(expectedCondtionTypes); - this.SetupMockForConditionsEvalEngine((rootConditionNode, _, _) => - { - switch (rootConditionNode) - { - case ValueConditionNode stringConditionNode: - return stringConditionNode.Operand.ToString() == "USA"; - - default: - return false; - } - }, evaluationOptions); + this.SetupMockForConditionsEvalEngine( + (rootConditionNode, _, _) => rootConditionNode is ValueConditionNode stringConditionNode && stringConditionNode.Operand.ToString() == "USA", + evaluationOptions); var validatorProvider = Mock.Of(); var rulesEngineOptions = RulesEngineOptions.NewWithDefaults(); - var sut = new RulesEngine(mockConditionsEvalEngine.Object, mockRulesSource.Object, validatorProvider, rulesEngineOptions, mockCondtionTypeExtractor.Object); + var sut = new RulesEngine(conditionsEvalEngineMock, rulesSourceMock, validatorProvider, rulesEngineOptions, conditionTypeExtractorMock); // Act - var actual = await sut.GetUniqueConditionTypesAsync(ContentType.Type1, dateBegin, dateEnd); + var actual = await sut.GetUniqueConditionTypesAsync(ContentType.Type1.ToString(), dateBegin, dateEnd); // Assert actual.Should().NotBeNull(); @@ -230,41 +360,41 @@ public async Task MatchManyAsync_GivenContentTypeDateAndConditions_FetchesRulesF { // Arrange var matchDateTime = new DateTime(2018, 07, 01, 18, 19, 30); - var contentType = ContentType.Type1; + var contentType = ContentType.Type1.ToString(); var conditions = new[] { - new Condition(ConditionType.IsoCountryCode, "USA"), - new Condition(ConditionType.IsoCurrency, "USD") + new Condition(ConditionType.IsoCountryCode.ToString(), "USA"), + new Condition(ConditionType.IsoCurrency.ToString(), "USD") }; - var expected1 = new Rule + var expected1 = new Rule { - ContentContainer = new ContentContainer(contentType, (t) => new object()), + ContentContainer = new ContentContainer(_ => new object()), DateBegin = new DateTime(2018, 01, 01), DateEnd = new DateTime(2019, 01, 01), Name = "Expected rule 1", Priority = 3, - RootCondition = new ValueConditionNode(DataTypes.String, ConditionType.IsoCountryCode, Operators.Equal, "USA") + RootCondition = new ValueConditionNode(DataTypes.String, ConditionType.IsoCountryCode.ToString(), Operators.Equal, "USA") }; - var expected2 = new Rule + var expected2 = new Rule { - ContentContainer = new ContentContainer(contentType, (t) => new object()), + ContentContainer = new ContentContainer(_ => new object()), DateBegin = new DateTime(2010, 01, 01), DateEnd = new DateTime(2021, 01, 01), Name = "Expected rule 2", Priority = 200, - RootCondition = new ValueConditionNode(DataTypes.String, ConditionType.IsoCountryCode, Operators.Equal, "USA") + RootCondition = new ValueConditionNode(DataTypes.String, ConditionType.IsoCountryCode.ToString(), Operators.Equal, "USA") }; - var notExpected = new Rule + var notExpected = new Rule { - ContentContainer = new ContentContainer(contentType, (t) => new object()), + ContentContainer = new ContentContainer(_ => new object()), DateBegin = new DateTime(2018, 01, 01), DateEnd = new DateTime(2019, 01, 01), Name = "Not expected rule", Priority = 1, // Topmost rule, should be the one that wins if options are set to topmost wins. - RootCondition = new ValueConditionNode(DataTypes.String, ConditionType.IsoCountryCode, Operators.Equal, "CHE") + RootCondition = new ValueConditionNode(DataTypes.String, ConditionType.IsoCountryCode.ToString(), Operators.Equal, "CHE") }; var rules = new[] @@ -282,26 +412,26 @@ public async Task MatchManyAsync_GivenContentTypeDateAndConditions_FetchesRulesF this.SetupMockForConditionsEvalEngine((rootConditionNode, _, _) => { - return rootConditionNode is ValueConditionNode stringConditionNode && stringConditionNode.Operand.ToString() == "USA"; + return rootConditionNode is ValueConditionNode stringConditionNode && stringConditionNode.Operand.ToString() == "USA"; }, evaluationOptions); var validatorProvider = Mock.Of(); var rulesEngineOptions = RulesEngineOptions.NewWithDefaults(); - var sut = new RulesEngine(mockConditionsEvalEngine.Object, mockRulesSource.Object, validatorProvider, rulesEngineOptions, mockCondtionTypeExtractor.Object); + var sut = new RulesEngine(conditionsEvalEngineMock, rulesSourceMock, validatorProvider, rulesEngineOptions, conditionTypeExtractorMock); // Act - var actual = await sut.MatchManyAsync(contentType, matchDateTime, conditions).ConfigureAwait(false); + var actual = await sut.MatchManyAsync(contentType, matchDateTime, conditions); // Assert actual.Should().Contain(expected1) .And.Contain(expected2) .And.NotContain(notExpected); - mockRulesSource.Verify(x => x.GetRulesAsync(It.IsAny>()), Times.Once()); - mockConditionsEvalEngine.Verify(x => x.Eval( - It.IsAny>(), - It.IsAny>(), + Mock.Get(rulesSourceMock).Verify(x => x.GetRulesAsync(It.IsAny()), Times.Once()); + Mock.Get(conditionsEvalEngineMock).Verify(x => x.Eval( + It.IsAny(), + It.IsAny>(), It.Is(eo => eo == evaluationOptions)), Times.AtLeastOnce()); } @@ -310,31 +440,31 @@ public async Task MatchOneAsync_GivenContentTypeDateAndConditions_FetchesRulesFo { // Arrange var matchDateTime = new DateTime(2018, 07, 01, 18, 19, 30); - var contentType = ContentType.Type1; + var contentType = ContentType.Type1.ToString(); var conditions = new[] { - new Condition(ConditionType.IsoCountryCode, "USA"), - new Condition(ConditionType.IsoCurrency, "USD") + new Condition(ConditionType.IsoCountryCode.ToString(), "USA"), + new Condition(ConditionType.IsoCurrency.ToString(), "USD") }; - var other = new Rule + var other = new Rule { - ContentContainer = new ContentContainer(contentType, (t) => new object()), + ContentContainer = new ContentContainer(_ => new object()), DateBegin = new DateTime(2018, 01, 01), DateEnd = new DateTime(2019, 01, 01), Name = "Expected rule", Priority = 3, - RootCondition = new ValueConditionNode(DataTypes.String, ConditionType.IsoCountryCode, Operators.Equal, "USA") + RootCondition = new ValueConditionNode(DataTypes.String, ConditionType.IsoCountryCode.ToString(), Operators.Equal, "USA") }; - var expected = new Rule + var expected = new Rule { - ContentContainer = new ContentContainer(contentType, (t) => new object()), + ContentContainer = new ContentContainer(_ => new object()), DateBegin = new DateTime(2010, 01, 01), DateEnd = new DateTime(2021, 01, 01), Name = "Expected rule", Priority = 200, - RootCondition = new ValueConditionNode(DataTypes.String, ConditionType.IsoCountryCode, Operators.Equal, "USA") + RootCondition = new ValueConditionNode(DataTypes.String, ConditionType.IsoCountryCode.ToString(), Operators.Equal, "USA") }; var rules = new[] @@ -357,17 +487,17 @@ public async Task MatchOneAsync_GivenContentTypeDateAndConditions_FetchesRulesFo rulesEngineOptions.PriorityCriteria = PriorityCriterias.BottommostRuleWins; - var sut = new RulesEngine(mockConditionsEvalEngine.Object, mockRulesSource.Object, validatorProvider, rulesEngineOptions, mockCondtionTypeExtractor.Object); + var sut = new RulesEngine(conditionsEvalEngineMock, rulesSourceMock, validatorProvider, rulesEngineOptions, conditionTypeExtractorMock); // Act var actual = await sut.MatchOneAsync(contentType, matchDateTime, conditions); // Assert actual.Should().BeSameAs(expected); - mockRulesSource.Verify(x => x.GetRulesAsync(It.IsAny>()), Times.Once()); - mockConditionsEvalEngine.Verify(x => x.Eval( - It.IsAny>(), - It.IsAny>(), + Mock.Get(rulesSourceMock).Verify(x => x.GetRulesAsync(It.IsAny()), Times.Once()); + Mock.Get(conditionsEvalEngineMock).Verify(x => x.Eval( + It.IsAny(), + It.IsAny>(), It.Is(eo => eo == evaluationOptions)), Times.AtLeastOnce()); } @@ -376,31 +506,31 @@ public async Task MatchOneAsync_GivenContentTypeDateAndConditions_FetchesRulesFo { // Arrange var matchDateTime = new DateTime(2018, 07, 01, 18, 19, 30); - var contentType = ContentType.Type1; + var contentType = ContentType.Type1.ToString(); var conditions = new[] { - new Condition(ConditionType.IsoCountryCode, "USA"), - new Condition(ConditionType.IsoCurrency, "USD") + new Condition(ConditionType.IsoCountryCode.ToString(), "USA"), + new Condition(ConditionType.IsoCurrency.ToString(), "USD") }; - var expected = new Rule + var expected = new Rule { - ContentContainer = new ContentContainer(contentType, (t) => new object()), + ContentContainer = new ContentContainer(_ => new object()), DateBegin = new DateTime(2018, 01, 01), DateEnd = new DateTime(2019, 01, 01), Name = "Expected rule", Priority = 3, - RootCondition = new ValueConditionNode(DataTypes.String, ConditionType.IsoCountryCode, Operators.Equal, "USA") + RootCondition = new ValueConditionNode(DataTypes.String, ConditionType.IsoCountryCode.ToString(), Operators.Equal, "USA") }; - var other = new Rule + var other = new Rule { - ContentContainer = new ContentContainer(contentType, (t) => new object()), + ContentContainer = new ContentContainer(_ => new object()), DateBegin = new DateTime(2010, 01, 01), DateEnd = new DateTime(2021, 01, 01), Name = "Expected rule", Priority = 200, - RootCondition = new ValueConditionNode(DataTypes.String, ConditionType.IsoCountryCode, Operators.Equal, "USA") + RootCondition = new ValueConditionNode(DataTypes.String, ConditionType.IsoCountryCode.ToString(), Operators.Equal, "USA") }; var rules = new[] @@ -421,17 +551,17 @@ public async Task MatchOneAsync_GivenContentTypeDateAndConditions_FetchesRulesFo var validatorProvider = Mock.Of(); var rulesEngineOptions = RulesEngineOptions.NewWithDefaults(); - var sut = new RulesEngine(mockConditionsEvalEngine.Object, mockRulesSource.Object, validatorProvider, rulesEngineOptions, mockCondtionTypeExtractor.Object); + var sut = new RulesEngine(conditionsEvalEngineMock, rulesSourceMock, validatorProvider, rulesEngineOptions, conditionTypeExtractorMock); // Act var actual = await sut.MatchOneAsync(contentType, matchDateTime, conditions); // Assert actual.Should().BeSameAs(expected); - mockRulesSource.Verify(x => x.GetRulesAsync(It.IsAny>()), Times.Once()); - mockConditionsEvalEngine.Verify(x => x.Eval( - It.IsAny>(), - It.IsAny>(), + Mock.Get(rulesSourceMock).Verify(x => x.GetRulesAsync(It.IsAny()), Times.Once()); + Mock.Get(conditionsEvalEngineMock).Verify(x => x.Eval( + It.IsAny(), + It.IsAny>(), It.Is(eo => eo == evaluationOptions)), Times.AtLeastOnce()); } @@ -440,32 +570,32 @@ public async Task MatchOneAsync_GivenContentTypeDateAndConditions_FetchesRulesFo { // Arrange var matchDateTime = new DateTime(2018, 07, 01, 18, 19, 30); - var contentType = ContentType.Type1; + var contentType = ContentType.Type1.ToString(); var conditions = new[] { - new Condition(ConditionType.IsoCountryCode, "USA"), - new Condition(ConditionType.IsoCurrency, "USD") + new Condition(ConditionType.IsoCountryCode.ToString(), "USA"), + new Condition(ConditionType.IsoCurrency.ToString(), "USD") }; var rules = new[] { - new Rule + new Rule { - ContentContainer = new ContentContainer(contentType, (t) => new object()), + ContentContainer = new ContentContainer(_ => new object()), DateBegin = new DateTime(2018, 01, 01), DateEnd = new DateTime(2019, 01, 01), Name = "Expected rule", Priority = 3, - RootCondition = new ValueConditionNode(DataTypes.String,ConditionType.IsoCountryCode, Operators.Equal, "USA") + RootCondition = new ValueConditionNode(DataTypes.String,ConditionType.IsoCountryCode.ToString(), Operators.Equal, "USA") }, - new Rule + new Rule { - ContentContainer = new ContentContainer(contentType, (t) => new object()), + ContentContainer = new ContentContainer(_ => new object()), DateBegin = new DateTime(2010, 01, 01), DateEnd = new DateTime(2021, 01, 01), Name = "Expected rule", Priority = 200, - RootCondition = new ValueConditionNode(DataTypes.String,ConditionType.IsoCountryCode, Operators.Equal, "USA") + RootCondition = new ValueConditionNode(DataTypes.String,ConditionType.IsoCountryCode.ToString(), Operators.Equal, "USA") } }; @@ -481,48 +611,32 @@ public async Task MatchOneAsync_GivenContentTypeDateAndConditions_FetchesRulesFo var validatorProvider = Mock.Of(); var rulesEngineOptions = RulesEngineOptions.NewWithDefaults(); - var sut = new RulesEngine(mockConditionsEvalEngine.Object, mockRulesSource.Object, validatorProvider, rulesEngineOptions, mockCondtionTypeExtractor.Object); + var sut = new RulesEngine(conditionsEvalEngineMock, rulesSourceMock, validatorProvider, rulesEngineOptions, conditionTypeExtractorMock); // Act var actual = await sut.MatchOneAsync(contentType, matchDateTime, conditions); // Assert actual.Should().BeNull(); - mockRulesSource.Verify(x => x.GetRulesAsync(It.IsAny>()), Times.Once()); - mockConditionsEvalEngine.Verify(x => x.Eval( - It.IsAny>(), - It.IsAny>(), + Mock.Get(rulesSourceMock).Verify(x => x.GetRulesAsync(It.IsAny()), Times.Once()); + Mock.Get(conditionsEvalEngineMock).Verify(x => x.Eval( + It.IsAny(), + It.IsAny>(), It.Is(eo => eo == evaluationOptions)), Times.AtLeastOnce()); } [Fact] - public async Task SearchAsync_GivenInvalidSearchArgs_ThrowsArgumentException() + public async Task UpdateRuleAsync_GivenEmptyRuleDataSource_UpdatesRuleSuccesfully() { - // Arrange - var contentType = ContentType.Type1; - var matchDateTime = new DateTime(2018, 07, 01, 18, 19, 30); - var searchArgs = new SearchArgs(contentType, matchDateTime, matchDateTime); - - var rules = new[] + // Arrange« + var testRule = new Rule { - new Rule - { - ContentContainer = new ContentContainer(contentType, (t) => new object()), - DateBegin = new DateTime(2018, 01, 01), - DateEnd = new DateTime(2019, 01, 01), - Name = "Expected rule", - Priority = 3, - RootCondition = new ValueConditionNode(DataTypes.String,ConditionType.IsoCountryCode, Operators.Equal, "USA") - }, - new Rule - { - ContentContainer = new ContentContainer(contentType, (t) => new object()), - DateBegin = new DateTime(2010, 01, 01), - DateEnd = new DateTime(2021, 01, 01), - Name = "Expected rule", - Priority = 200, - RootCondition = new ValueConditionNode(DataTypes.String,ConditionType.IsoCountryCode, Operators.Equal, "USA") - } + ContentContainer = new ContentContainer(_ => new object()), + DateBegin = new DateTime(2018, 01, 01), + DateEnd = new DateTime(2019, 01, 01), + Name = "Update test rule", + Priority = 3, + RootCondition = new ValueConditionNode(DataTypes.String, ConditionType.IsoCountryCode.ToString(), Operators.Equal, "USA") }; var evaluationOptions = new EvaluationOptions @@ -530,96 +644,43 @@ public async Task SearchAsync_GivenInvalidSearchArgs_ThrowsArgumentException() MatchMode = MatchModes.Exact }; - this.SetupMockForRulesDataSource(rules); - - this.SetupMockForConditionsEvalEngine(false, evaluationOptions); - - var validator = Mock.Of>>(); - Mock.Get(validator) - .Setup(x => x.ValidateAsync(It.IsAny>(), It.IsAny())) - .ReturnsAsync(new ValidationResult(new[] { new ValidationFailure("Prop1", "Sample error message") })); + Mock.Get(rulesSourceMock).Setup(s => s.GetRulesFilteredAsync(It.IsAny())) + .ReturnsAsync(new List { testRule }); var validatorProvider = Mock.Of(); - Mock.Get(validatorProvider) - .Setup(x => x.GetValidatorFor>()) - .Returns(validator); var rulesEngineOptions = RulesEngineOptions.NewWithDefaults(); - var sut = new RulesEngine(mockConditionsEvalEngine.Object, mockRulesSource.Object, validatorProvider, rulesEngineOptions, mockCondtionTypeExtractor.Object); - - // Act - var argumentException = await Assert.ThrowsAsync(() => sut.SearchAsync(searchArgs)).ConfigureAwait(false); - - // Assert - argumentException.Should().NotBeNull(); - argumentException.ParamName.Should().Be(nameof(searchArgs)); - argumentException.Message.Should().StartWith($"Specified '{nameof(searchArgs)}' with invalid search values:"); - } - - [Fact] - public async Task SearchAsync_GivenNullSearchArgs_ThrowsArgumentNullException() - { - // Arrange - SearchArgs searchArgs = null; - var contentType = ContentType.Type1; - - var rules = new[] - { - new Rule - { - ContentContainer = new ContentContainer(contentType, (t) => new object()), - DateBegin = new DateTime(2018, 01, 01), - DateEnd = new DateTime(2019, 01, 01), - Name = "Expected rule", - Priority = 3, - RootCondition = new ValueConditionNode(DataTypes.String,ConditionType.IsoCountryCode, Operators.Equal, "USA") - }, - new Rule - { - ContentContainer = new ContentContainer(contentType, (t) => new object()), - DateBegin = new DateTime(2010, 01, 01), - DateEnd = new DateTime(2021, 01, 01), - Name = "Expected rule", - Priority = 200, - RootCondition = new ValueConditionNode(DataTypes.String,ConditionType.IsoCountryCode, Operators.Equal, "USA") - } - }; - - var evaluationOptions = new EvaluationOptions - { - MatchMode = MatchModes.Exact - }; - - this.SetupMockForRulesDataSource(rules); - - this.SetupMockForConditionsEvalEngine(false, evaluationOptions); - var validatorProvider = Mock.Of(); - var rulesEngineOptions = RulesEngineOptions.NewWithDefaults(); + var sut = new RulesEngine(conditionsEvalEngineMock, rulesSourceMock, validatorProvider, rulesEngineOptions, conditionTypeExtractorMock); - var sut = new RulesEngine(mockConditionsEvalEngine.Object, mockRulesSource.Object, validatorProvider, rulesEngineOptions, mockCondtionTypeExtractor.Object); + testRule.DateEnd = new DateTime(2019, 01, 02); + testRule.Priority = 1; // Act - var argumentNullException = await Assert.ThrowsAsync(() => sut.SearchAsync(searchArgs)).ConfigureAwait(false); + var actual = await sut.UpdateRuleAsync(testRule); // Assert - argumentNullException.Should().NotBeNull(); - argumentNullException.ParamName.Should().Be(nameof(searchArgs)); + actual.IsSuccess.Should().BeTrue(); + actual.Errors.Should().BeEmpty(); + + Mock.Get(rulesSourceMock).Verify(x => x.GetRulesFilteredAsync(It.IsAny()), Times.Once()); + Mock.Get(conditionsEvalEngineMock).Verify(x => x.Eval( + It.IsAny(), + It.IsAny>(), + It.Is(eo => eo == evaluationOptions)), Times.Never()); } [Fact] - public async Task UpdateRuleAsync_GivenEmptyRuleDataSource_UpdatesRuleSuccesfully() + public async Task UpdateRuleAsync_GivenRuleWithInvalidDateEnd_UpdatesRuleFailure() { // Arrange - var contentType = ContentType.Type1; - - var testRule = new Rule + var testRule = new Rule { - ContentContainer = new ContentContainer(contentType, (t) => new object()), + ContentContainer = new ContentContainer(_ => new object()), DateBegin = new DateTime(2018, 01, 01), DateEnd = new DateTime(2019, 01, 01), Name = "Update test rule", Priority = 3, - RootCondition = new ValueConditionNode(DataTypes.String, ConditionType.IsoCountryCode, Operators.Equal, "USA") + RootCondition = new ValueConditionNode(DataTypes.String, ConditionType.IsoCountryCode.ToString(), Operators.Equal, "USA") }; var evaluationOptions = new EvaluationOptions @@ -627,98 +688,178 @@ public async Task UpdateRuleAsync_GivenEmptyRuleDataSource_UpdatesRuleSuccesfull MatchMode = MatchModes.Exact }; - mockRulesSource.Setup(s => s.GetRulesFilteredAsync(It.IsAny>())) - .ReturnsAsync(new List> { testRule }); + Mock.Get(rulesSourceMock).Setup(s => s.GetRulesFilteredAsync(It.IsAny())) + .ReturnsAsync(new List { testRule }); var validatorProvider = Mock.Of(); var rulesEngineOptions = RulesEngineOptions.NewWithDefaults(); - var sut = new RulesEngine(mockConditionsEvalEngine.Object, mockRulesSource.Object, validatorProvider, rulesEngineOptions, mockCondtionTypeExtractor.Object); + var sut = new RulesEngine(conditionsEvalEngineMock, rulesSourceMock, validatorProvider, rulesEngineOptions, conditionTypeExtractorMock); - testRule.DateEnd = new DateTime(2019, 01, 02); + testRule.DateEnd = testRule.DateBegin.AddYears(-2); testRule.Priority = 1; // Act - var actual = await sut.UpdateRuleAsync(testRule).ConfigureAwait(false); + var actual = await sut.UpdateRuleAsync(testRule); // Assert - actual.IsSuccess.Should().BeTrue(); - actual.Errors.Should().BeEmpty(); + actual.IsSuccess.Should().BeFalse(); + actual.Errors.Should().NotBeEmpty(); - mockRulesSource.Verify(x => x.GetRulesFilteredAsync(It.IsAny>()), Times.Once()); - mockConditionsEvalEngine.Verify(x => x.Eval( - It.IsAny>(), - It.IsAny>(), + Mock.Get(rulesSourceMock).Verify(x => x.GetRulesFilteredAsync(It.IsAny()), Times.Once()); + Mock.Get(conditionsEvalEngineMock).Verify(x => x.Eval( + It.IsAny(), + It.IsAny>(), It.Is(eo => eo == evaluationOptions)), Times.Never()); } - [Fact] - public async Task UpdateRuleAsync_GivenRuleWithInvalidDateEnd_UpdatesRuleFailure() + [Theory] + [InlineData(nameof(RulesEngine.ActivateRuleAsync), "rule", typeof(ArgumentNullException))] + [InlineData(nameof(RulesEngine.AddRuleAsync), "rule", typeof(ArgumentNullException))] + [InlineData(nameof(RulesEngine.AddRuleAsync), "ruleAddPriorityOption", typeof(ArgumentNullException))] + [InlineData(nameof(RulesEngine.CreateContentTypeAsync), "contentType", typeof(ArgumentNullException))] + [InlineData(nameof(RulesEngine.DeactivateRuleAsync), "rule", typeof(ArgumentNullException))] + [InlineData(nameof(RulesEngine.GetUniqueConditionTypesAsync), "contentType", typeof(ArgumentNullException))] + [InlineData(nameof(RulesEngine.MatchManyAsync), "contentType", typeof(ArgumentNullException))] + [InlineData(nameof(RulesEngine.MatchOneAsync), "contentType", typeof(ArgumentNullException))] + [InlineData(nameof(RulesEngine.SearchAsync), "searchArgs", typeof(ArgumentNullException))] + [InlineData(nameof(RulesEngine.SearchAsync), "searchArgs", typeof(ArgumentException))] + [InlineData(nameof(RulesEngine.UpdateRuleAsync), "rule", typeof(ArgumentNullException))] + public async Task VerifyParameters_GivenNullParameter_ThrowsArgumentNullException(string methodName, string parameterName, Type exceptionType) { // Arrange - var contentType = ContentType.Type1; - - var testRule = new Rule - { - ContentContainer = new ContentContainer(contentType, (t) => new object()), - DateBegin = new DateTime(2018, 01, 01), - DateEnd = new DateTime(2019, 01, 01), - Name = "Update test rule", - Priority = 3, - RootCondition = new ValueConditionNode(DataTypes.String, ConditionType.IsoCountryCode, Operators.Equal, "USA") - }; - var evaluationOptions = new EvaluationOptions { MatchMode = MatchModes.Exact }; - mockRulesSource.Setup(s => s.GetRulesFilteredAsync(It.IsAny>())) - .ReturnsAsync(new List> { testRule }); - + var validator = Mock.Of>>(); + Mock.Get(validator) + .Setup(x => x.ValidateAsync(It.IsAny>(), It.IsAny())) + .ReturnsAsync(new ValidationResult(new[] { new ValidationFailure("Prop1", "Sample error message") })); var validatorProvider = Mock.Of(); + Mock.Get(validatorProvider) + .Setup(x => x.GetValidatorFor>()) + .Returns(validator); var rulesEngineOptions = RulesEngineOptions.NewWithDefaults(); - var sut = new RulesEngine(mockConditionsEvalEngine.Object, mockRulesSource.Object, validatorProvider, rulesEngineOptions, mockCondtionTypeExtractor.Object); - - testRule.DateEnd = testRule.DateBegin.AddYears(-2); - testRule.Priority = 1; + var sut = new RulesEngine(conditionsEvalEngineMock, rulesSourceMock, validatorProvider, rulesEngineOptions, conditionTypeExtractorMock); // Act - var actual = await sut.UpdateRuleAsync(testRule).ConfigureAwait(false); + var actual = await Assert.ThrowsAsync(exceptionType, async () => + { + switch (methodName) + { + case nameof(RulesEngine.ActivateRuleAsync): + _ = await sut.ActivateRuleAsync(null); + break; + + case nameof(RulesEngine.AddRuleAsync): + switch (parameterName) + { + case "rule": + _ = await sut.AddRuleAsync(null, RuleAddPriorityOption.AtTop); + break; + + case "ruleAddPriorityOption": + _ = await sut.AddRuleAsync(CreateTestStubRule(), null); + break; + + default: + Assert.Fail("Test scenario not supported, please review test implementation to support it."); + break; + } + break; + + case nameof(RulesEngine.CreateContentTypeAsync): + await sut.CreateContentTypeAsync(null); + break; + + case nameof(RulesEngine.DeactivateRuleAsync): + _ = await sut.DeactivateRuleAsync(null); + break; + + case nameof(RulesEngine.GetUniqueConditionTypesAsync): + _ = await sut.GetUniqueConditionTypesAsync(null, DateTime.MinValue, DateTime.MaxValue); + break; + + case nameof(RulesEngine.MatchManyAsync): + _ = await sut.MatchManyAsync(null, DateTime.UtcNow, Enumerable.Empty>()); + break; + + case nameof(RulesEngine.MatchOneAsync): + _ = await sut.MatchOneAsync(null, DateTime.UtcNow, Enumerable.Empty>()); + break; + + case nameof(RulesEngine.SearchAsync): + switch (exceptionType.Name) + { + case nameof(ArgumentNullException): + _ = await sut.SearchAsync(null); + break; + + case nameof(ArgumentException): + _ = await sut.SearchAsync(new SearchArgs("test", DateTime.MinValue, DateTime.MaxValue)); + break; + + default: + Assert.Fail("Test scenario not supported, please review test implementation to support it."); + break; + } + break; + + case nameof(RulesEngine.UpdateRuleAsync): + _ = await sut.UpdateRuleAsync(null); + break; - // Assert - actual.IsSuccess.Should().BeFalse(); - actual.Errors.Should().NotBeEmpty(); + default: + Assert.Fail("Test scenario not supported, please review test implementation to support it."); + break; + } + }); - mockRulesSource.Verify(x => x.GetRulesFilteredAsync(It.IsAny>()), Times.Once()); - mockConditionsEvalEngine.Verify(x => x.Eval( - It.IsAny>(), - It.IsAny>(), - It.Is(eo => eo == evaluationOptions)), Times.Never()); + // Assert + actual.Should().NotBeNull() + .And.BeOfType(exceptionType); + if (actual is ArgumentException argumentException) + { + argumentException.Message.Should().Contain(parameterName); + argumentException.ParamName.Should().Be(parameterName); + } } - private void SetupMockForConditionsEvalEngine(Func, IDictionary, EvaluationOptions, bool> evalFunc, EvaluationOptions evaluationOptions) + private static Rule CreateTestStubRule() + => Rule.New() + .WithName("Test stub") + .WithDateBegin(DateTime.Parse("2024-08-17", CultureInfo.InvariantCulture, DateTimeStyles.AssumeUniversal)) + .WithContent("Test content type", new object()) + .Build() + .Rule; + + private void SetupMockForConditionsEvalEngine(Func, EvaluationOptions, bool> evalFunc, EvaluationOptions evaluationOptions) { - this.mockConditionsEvalEngine.Setup(x => x.Eval( - It.IsAny>(), - It.IsAny>(), + Mock.Get(this.conditionsEvalEngineMock) + .Setup(x => x.Eval( + It.IsAny(), + It.IsAny>(), It.Is(eo => eo == evaluationOptions))) .Returns(evalFunc); } private void SetupMockForConditionsEvalEngine(bool result, EvaluationOptions evaluationOptions) { - this.mockConditionsEvalEngine.Setup(x => x.Eval( - It.IsAny>(), - It.IsAny>(), + Mock.Get(this.conditionsEvalEngineMock) + .Setup(x => x.Eval( + It.IsAny(), + It.IsAny>(), It.Is(eo => eo == evaluationOptions))) .Returns(result); } - private void SetupMockForRulesDataSource(IEnumerable> rules) + private void SetupMockForRulesDataSource(IEnumerable rules) { - this.mockRulesSource.Setup(x => x.GetRulesAsync(It.IsAny>())) + Mock.Get(this.rulesSourceMock) + .Setup(x => x.GetRulesAsync(It.IsAny())) .ReturnsAsync(rules); } } diff --git a/tests/Rules.Framework.Tests/Serialization/SerializedContentContainerTests.cs b/tests/Rules.Framework.Tests/Serialization/SerializedContentContainerTests.cs index 2873b11a..efd21275 100644 --- a/tests/Rules.Framework.Tests/Serialization/SerializedContentContainerTests.cs +++ b/tests/Rules.Framework.Tests/Serialization/SerializedContentContainerTests.cs @@ -13,22 +13,22 @@ public class SerializedContentContainerTests public void Init_GivenSerializedContent_DeserializesAndReturnsWhenFetchingContent() { // Arrange - ContentType expectedContentType = ContentType.Type1; - object serializedContent = new object(); + var expectedContentType = ContentType.Type1.ToString(); + var serializedContent = new object(); object expected = 19m; - Mock mockContentSerializer = new Mock(); + var mockContentSerializer = new Mock(); mockContentSerializer.Setup(x => x.Deserialize(It.IsAny(), It.IsAny())) .Returns(expected); - Mock> mockContentSerializationProvider = new Mock>(); - mockContentSerializationProvider.Setup(x => x.GetContentSerializer(It.Is(y => y == expectedContentType))) + var mockContentSerializationProvider = new Mock(); + mockContentSerializationProvider.Setup(x => x.GetContentSerializer(It.Is(y => y == expectedContentType))) .Returns(mockContentSerializer.Object); - SerializedContentContainer sut = new SerializedContentContainer(expectedContentType, serializedContent, mockContentSerializationProvider.Object); + var sut = new SerializedContentContainer(expectedContentType, serializedContent, mockContentSerializationProvider.Object); // Act - decimal actual = sut.GetContentAs(); + var actual = sut.GetContentAs(); // Assert actual.Should().Be(expected.As()); diff --git a/tests/Rules.Framework.Tests/Source/RulesSourceTests.cs b/tests/Rules.Framework.Tests/Source/RulesSourceTests.cs index 6e9b9c4e..8987b87d 100644 --- a/tests/Rules.Framework.Tests/Source/RulesSourceTests.cs +++ b/tests/Rules.Framework.Tests/Source/RulesSourceTests.cs @@ -6,7 +6,6 @@ namespace Rules.Framework.Tests.Source using System.Threading.Tasks; using FluentAssertions; using Moq; - using Rules.Framework.Core; using Rules.Framework.Source; using Rules.Framework.Tests.Stubs; using Xunit; @@ -17,118 +16,305 @@ public class RulesSourceTests public async Task AddRuleAsync_NoMiddlewares_CallsRulesDataSource() { // Arrange - Rule rule = CreateRule(); + var rule = CreateRule(); - AddRuleArgs addRuleArgs = new() + AddRuleArgs addRuleArgs = new() { Rule = rule, }; - IEnumerable> rulesSourceMiddlewares - = Enumerable.Empty>(); + var rulesSourceMiddlewares + = Enumerable.Empty(); - IRulesDataSource rulesDataSource = Mock.Of>(); + var rulesDataSource = Mock.Of(); Mock.Get(rulesDataSource) - .Setup(x => x.AddRuleAsync(It.Is>((val, _) => object.ReferenceEquals(val, rule)))) + .Setup(x => x.AddRuleAsync(It.Is((val, _) => object.ReferenceEquals(val, rule)))) .Returns(Task.CompletedTask); - RulesSource rulesSource = new(rulesDataSource, rulesSourceMiddlewares); + RulesSource rulesSource = new(rulesDataSource, rulesSourceMiddlewares); // Act - await rulesSource.AddRuleAsync(addRuleArgs).ConfigureAwait(false); + await rulesSource.AddRuleAsync(addRuleArgs); // Assert Mock.Get(rulesDataSource) - .Verify(x => x.AddRuleAsync(It.Is>((val, _) => object.ReferenceEquals(val, rule))), Times.Once()); + .Verify(x => x.AddRuleAsync(It.Is((val, _) => object.ReferenceEquals(val, rule))), Times.Once()); } [Fact] public async Task AddRuleAsync_OneMiddleware_CallsMiddlewareAndRulesDataSourceAfter() { // Arrange - Rule rule = CreateRule(); + var rule = CreateRule(); - AddRuleArgs addRuleArgs = new() + AddRuleArgs addRuleArgs = new() { Rule = rule, }; - StubRulesSourceMiddleware middleware1 = new(nameof(middleware1), new List()); + StubRulesSourceMiddleware middleware1 = new(nameof(middleware1), new List()); - IEnumerable> rulesSourceMiddlewares = new[] { middleware1 }; + IEnumerable rulesSourceMiddlewares = new[] { middleware1 }; - IRulesDataSource rulesDataSource = Mock.Of>(); + var rulesDataSource = Mock.Of(); Mock.Get(rulesDataSource) - .Setup(x => x.AddRuleAsync(It.Is>((val, _) => object.ReferenceEquals(val, rule)))) + .Setup(x => x.AddRuleAsync(It.Is((val, _) => object.ReferenceEquals(val, rule)))) .Returns(Task.CompletedTask); - RulesSource rulesSource = new(rulesDataSource, rulesSourceMiddlewares); + RulesSource rulesSource = new(rulesDataSource, rulesSourceMiddlewares); // Act - await rulesSource.AddRuleAsync(addRuleArgs).ConfigureAwait(false); + await rulesSource.AddRuleAsync(addRuleArgs); // Assert middleware1.AddRuleCalls.Should().Be(1); Mock.Get(rulesDataSource) - .Verify(x => x.AddRuleAsync(It.Is>((val, _) => object.ReferenceEquals(val, rule))), Times.Once()); + .Verify(x => x.AddRuleAsync(It.Is((val, _) => object.ReferenceEquals(val, rule))), Times.Once()); } [Fact] public async Task AddRuleAsync_TwoMiddlewares_CallsFirstMiddlewareSecondMiddlewareAfterAndRulesDataSourceByLast() { // Arrange - Rule rule = CreateRule(); + var rule = CreateRule(); - AddRuleArgs addRuleArgs = new() + AddRuleArgs addRuleArgs = new() { Rule = rule, }; List middlewareMessages = new(); - StubRulesSourceMiddleware middleware1 = new(nameof(middleware1), middlewareMessages); - StubRulesSourceMiddleware middleware2 = new(nameof(middleware2), middlewareMessages); + StubRulesSourceMiddleware middleware1 = new(nameof(middleware1), middlewareMessages); + StubRulesSourceMiddleware middleware2 = new(nameof(middleware2), middlewareMessages); - IEnumerable> rulesSourceMiddlewares = new[] { middleware1, middleware2 }; + IEnumerable rulesSourceMiddlewares = new[] { middleware1, middleware2 }; - IRulesDataSource rulesDataSource = Mock.Of>(); + var rulesDataSource = Mock.Of(); Mock.Get(rulesDataSource) - .Setup(x => x.AddRuleAsync(It.Is>((val, _) => object.ReferenceEquals(val, rule)))) + .Setup(x => x.AddRuleAsync(It.Is((val, _) => object.ReferenceEquals(val, rule)))) .Returns(Task.CompletedTask); - RulesSource rulesSource = new(rulesDataSource, rulesSourceMiddlewares); + RulesSource rulesSource = new(rulesDataSource, rulesSourceMiddlewares); // Act - await rulesSource.AddRuleAsync(addRuleArgs).ConfigureAwait(false); + await rulesSource.AddRuleAsync(addRuleArgs); // Assert middleware1.AddRuleCalls.Should().Be(1); middleware2.AddRuleCalls.Should().Be(1); middlewareMessages.Should().ContainInOrder("Enter middleware1.", "Enter middleware2.", "Exit middleware2.", "Exit middleware1."); Mock.Get(rulesDataSource) - .Verify(x => x.AddRuleAsync(It.Is>((val, _) => object.ReferenceEquals(val, rule))), Times.Once()); + .Verify(x => x.AddRuleAsync(It.Is((val, _) => object.ReferenceEquals(val, rule))), Times.Once()); + } + + [Fact] + public async Task CreateContentTypeAsync_NoMiddlewares_CallsRulesDataSource() + { + // Arrange + var contentType = "TestContent1"; + + CreateContentTypeArgs createContentTypeArgs = new() + { + Name = contentType, + }; + + var rulesSourceMiddlewares + = Enumerable.Empty(); + + var rulesDataSource = Mock.Of(); + Mock.Get(rulesDataSource) + .Setup(x => x.CreateContentTypeAsync(It.Is((val, _) => object.Equals(val, contentType)))) + .Returns(Task.CompletedTask); + + RulesSource rulesSource = new(rulesDataSource, rulesSourceMiddlewares); + + // Act + await rulesSource.CreateContentTypeAsync(createContentTypeArgs); + + // Assert + Mock.Get(rulesDataSource) + .Verify(x => x.CreateContentTypeAsync(It.Is((val, _) => object.Equals(val, contentType))), Times.Once()); + } + + [Fact] + public async Task CreateContentTypeAsync_OneMiddleware_CallsMiddlewareAndRulesDataSourceAfter() + { + // Arrange + var contentType = "TestContent1"; + + CreateContentTypeArgs createContentTypeArgs = new() + { + Name = contentType, + }; + + StubRulesSourceMiddleware middleware1 = new(nameof(middleware1), new List()); + + IEnumerable rulesSourceMiddlewares = new[] { middleware1 }; + + var rulesDataSource = Mock.Of(); + Mock.Get(rulesDataSource) + .Setup(x => x.CreateContentTypeAsync(It.Is((val, _) => object.Equals(val, contentType)))) + .Returns(Task.CompletedTask); + + RulesSource rulesSource = new(rulesDataSource, rulesSourceMiddlewares); + + // Act + await rulesSource.CreateContentTypeAsync(createContentTypeArgs); + + // Assert + middleware1.CreateContentTypeCalls.Should().Be(1); + Mock.Get(rulesDataSource) + .Verify(x => x.CreateContentTypeAsync(It.Is((val, _) => object.Equals(val, contentType))), Times.Once()); + } + + [Fact] + public async Task CreateContentTypeAsync_TwoMiddlewares_CallsFirstMiddlewareSecondMiddlewareAfterAndRulesDataSourceByLast() + { + // Arrange + var contentType = "TestContent1"; + + CreateContentTypeArgs createContentTypeArgs = new() + { + Name = contentType, + }; + + List middlewareMessages = new(); + StubRulesSourceMiddleware middleware1 = new(nameof(middleware1), middlewareMessages); + StubRulesSourceMiddleware middleware2 = new(nameof(middleware2), middlewareMessages); + + IEnumerable rulesSourceMiddlewares = new[] { middleware1, middleware2 }; + + var rulesDataSource = Mock.Of(); + Mock.Get(rulesDataSource) + .Setup(x => x.CreateContentTypeAsync(It.Is((val, _) => object.Equals(val, contentType)))) + .Returns(Task.CompletedTask); + + RulesSource rulesSource = new(rulesDataSource, rulesSourceMiddlewares); + + // Act + await rulesSource.CreateContentTypeAsync(createContentTypeArgs); + + // Assert + middleware1.CreateContentTypeCalls.Should().Be(1); + middleware2.CreateContentTypeCalls.Should().Be(1); + middlewareMessages.Should().ContainInOrder("Enter middleware1.", "Enter middleware2.", "Exit middleware2.", "Exit middleware1."); + Mock.Get(rulesDataSource) + .Verify(x => x.CreateContentTypeAsync(It.Is((val, _) => object.Equals(val, contentType))), Times.Once()); + } + + [Fact] + public async Task GetContentTypesAsync_NoMiddlewares_CallsRulesDataSource() + { + // Arrange + var expected = new[] { "Content Type 1", "Content Type 2", }; + + var getContentTypesArgs = new GetContentTypesArgs(); + + var rulesSourceMiddlewares + = Enumerable.Empty(); + + var rulesDataSource = Mock.Of(); + Mock.Get(rulesDataSource) + .Setup(x => x.GetContentTypesAsync()) + .ReturnsAsync(expected); + + RulesSource rulesSource = new(rulesDataSource, rulesSourceMiddlewares); + + // Act + var actual = await rulesSource.GetContentTypesAsync(getContentTypesArgs); + + // Assert + actual.Should().NotBeNullOrEmpty() + .And.BeEquivalentTo(expected); + Mock.Get(rulesDataSource) + .Verify(x => x.GetContentTypesAsync(), Times.Once()); + } + + [Fact] + public async Task GetContentTypesAsync_OneMiddleware_CallsMiddlewareAndRulesDataSourceAfter() + { + // Arrange + var expected = new[] { "Content Type 1", "Content Type 2", }; + + var getContentTypesArgs = new GetContentTypesArgs(); + + StubRulesSourceMiddleware middleware1 = new(nameof(middleware1), new List()); + + IEnumerable rulesSourceMiddlewares = new[] { middleware1 }; + + var rulesDataSource = Mock.Of(); + Mock.Get(rulesDataSource) + .Setup(x => x.GetContentTypesAsync()) + .ReturnsAsync(expected); + + RulesSource rulesSource = new(rulesDataSource, rulesSourceMiddlewares); + + // Act + var actual = await rulesSource.GetContentTypesAsync(getContentTypesArgs); + + // Assert + actual.Should().NotBeNullOrEmpty() + .And.Contain(expected); + middleware1.GetContentTypesCalls.Should().Be(1); + Mock.Get(rulesDataSource) + .Verify(x => x.GetContentTypesAsync(), Times.Once()); + } + + [Fact] + public async Task GetContentTypesAsync_TwoMiddlewares_CallsFirstMiddlewareSecondMiddlewareAfterAndRulesDataSourceByLast() + { + // Arrange + var expected = new[] { "Content Type 1", "Content Type 2", }; + + var getContentTypesArgs = new GetContentTypesArgs(); + + List middlewareMessages = new(); + StubRulesSourceMiddleware middleware1 = new(nameof(middleware1), middlewareMessages); + StubRulesSourceMiddleware middleware2 = new(nameof(middleware2), middlewareMessages); + + IEnumerable rulesSourceMiddlewares = new[] { middleware1, middleware2 }; + + var rulesDataSource = Mock.Of(); + Mock.Get(rulesDataSource) + .Setup(x => x.GetContentTypesAsync()) + .ReturnsAsync(expected); + + RulesSource rulesSource = new(rulesDataSource, rulesSourceMiddlewares); + + // Act + var actual = await rulesSource.GetContentTypesAsync(getContentTypesArgs); + + // Assert + actual.Should().NotBeNullOrEmpty() + .And.Contain(expected); + middleware1.GetContentTypesCalls.Should().Be(1); + middleware2.GetContentTypesCalls.Should().Be(1); + middlewareMessages.Should().ContainInOrder("Enter middleware1.", "Enter middleware2.", "Exit middleware2.", "Exit middleware1."); + Mock.Get(rulesDataSource) + .Verify(x => x.GetContentTypesAsync(), Times.Once()); } [Fact] public async Task GetRulesAsync_NoMiddlewares_CallsRulesDataSource() { // Arrange - Rule rule = CreateRule(); + var rule = CreateRule(); var expected = new[] { rule }; - GetRulesArgs getRulesArgs = CreateGetRulesArgs(); + var getRulesArgs = CreateGetRulesArgs(); - IEnumerable> rulesSourceMiddlewares - = Enumerable.Empty>(); + var rulesSourceMiddlewares + = Enumerable.Empty(); - IRulesDataSource rulesDataSource = Mock.Of>(); + var rulesDataSource = Mock.Of(); Mock.Get(rulesDataSource) .Setup(x => x.GetRulesAsync(It.IsIn(getRulesArgs.ContentType), It.IsIn(getRulesArgs.DateBegin), It.IsIn(getRulesArgs.DateEnd))) .ReturnsAsync(expected); - RulesSource rulesSource = new(rulesDataSource, rulesSourceMiddlewares); + RulesSource rulesSource = new(rulesDataSource, rulesSourceMiddlewares); // Act - var actual = await rulesSource.GetRulesAsync(getRulesArgs).ConfigureAwait(false); + var actual = await rulesSource.GetRulesAsync(getRulesArgs); // Assert actual.Should().NotBeNullOrEmpty() @@ -141,24 +327,24 @@ IEnumerable> rulesSourceMiddl public async Task GetRulesAsync_OneMiddleware_CallsMiddlewareAndRulesDataSourceAfter() { // Arrange - Rule rule = CreateRule(); + var rule = CreateRule(); var expected = new[] { rule }; - GetRulesArgs getRulesArgs = CreateGetRulesArgs(); + var getRulesArgs = CreateGetRulesArgs(); - StubRulesSourceMiddleware middleware1 = new(nameof(middleware1), new List()); + StubRulesSourceMiddleware middleware1 = new(nameof(middleware1), new List()); - IEnumerable> rulesSourceMiddlewares = new[] { middleware1 }; + IEnumerable rulesSourceMiddlewares = new[] { middleware1 }; - IRulesDataSource rulesDataSource = Mock.Of>(); + var rulesDataSource = Mock.Of(); Mock.Get(rulesDataSource) .Setup(x => x.GetRulesAsync(It.IsIn(getRulesArgs.ContentType), It.IsIn(getRulesArgs.DateBegin), It.IsIn(getRulesArgs.DateEnd))) .ReturnsAsync(expected); - RulesSource rulesSource = new(rulesDataSource, rulesSourceMiddlewares); + RulesSource rulesSource = new(rulesDataSource, rulesSourceMiddlewares); // Act - var actual = await rulesSource.GetRulesAsync(getRulesArgs).ConfigureAwait(false); + var actual = await rulesSource.GetRulesAsync(getRulesArgs); // Assert actual.Should().NotBeNullOrEmpty() @@ -172,26 +358,26 @@ public async Task GetRulesAsync_OneMiddleware_CallsMiddlewareAndRulesDataSourceA public async Task GetRulesAsync_TwoMiddlewares_CallsFirstMiddlewareSecondMiddlewareAfterAndRulesDataSourceByLast() { // Arrange - Rule rule = CreateRule(); + var rule = CreateRule(); var expected = new[] { rule }; - GetRulesArgs getRulesArgs = CreateGetRulesArgs(); + var getRulesArgs = CreateGetRulesArgs(); List middlewareMessages = new(); - StubRulesSourceMiddleware middleware1 = new(nameof(middleware1), middlewareMessages); - StubRulesSourceMiddleware middleware2 = new(nameof(middleware2), middlewareMessages); + StubRulesSourceMiddleware middleware1 = new(nameof(middleware1), middlewareMessages); + StubRulesSourceMiddleware middleware2 = new(nameof(middleware2), middlewareMessages); - IEnumerable> rulesSourceMiddlewares = new[] { middleware1, middleware2 }; + IEnumerable rulesSourceMiddlewares = new[] { middleware1, middleware2 }; - IRulesDataSource rulesDataSource = Mock.Of>(); + var rulesDataSource = Mock.Of(); Mock.Get(rulesDataSource) .Setup(x => x.GetRulesAsync(It.IsIn(getRulesArgs.ContentType), It.IsIn(getRulesArgs.DateBegin), It.IsIn(getRulesArgs.DateEnd))) .ReturnsAsync(expected); - RulesSource rulesSource = new(rulesDataSource, rulesSourceMiddlewares); + RulesSource rulesSource = new(rulesDataSource, rulesSourceMiddlewares); // Act - var actual = await rulesSource.GetRulesAsync(getRulesArgs).ConfigureAwait(false); + var actual = await rulesSource.GetRulesAsync(getRulesArgs); // Assert actual.Should().NotBeNullOrEmpty() @@ -207,30 +393,30 @@ public async Task GetRulesAsync_TwoMiddlewares_CallsFirstMiddlewareSecondMiddlew public async Task GetRulesFilteredAsync_NoMiddlewares_CallsRulesDataSource() { // Arrange - Rule rule = CreateRule(); + var rule = CreateRule(); var expected = new[] { rule }; - GetRulesFilteredArgs getRulesFilteredArgs = CreateGetRulesFilteredArgs(); + var getRulesFilteredArgs = CreateGetRulesFilteredArgs(); - IEnumerable> rulesSourceMiddlewares - = Enumerable.Empty>(); + var rulesSourceMiddlewares + = Enumerable.Empty(); - IRulesDataSource rulesDataSource = Mock.Of>(); + var rulesDataSource = Mock.Of(); Mock.Get(rulesDataSource) - .Setup(x => x.GetRulesByAsync(It.Is>( + .Setup(x => x.GetRulesByAsync(It.Is( (val) => string.Equals(val.Name, getRulesFilteredArgs.Name) && val.ContentType == getRulesFilteredArgs.ContentType && val.Priority == getRulesFilteredArgs.Priority))) .ReturnsAsync(expected); - RulesSource rulesSource = new(rulesDataSource, rulesSourceMiddlewares); + RulesSource rulesSource = new(rulesDataSource, rulesSourceMiddlewares); // Act - var actual = await rulesSource.GetRulesFilteredAsync(getRulesFilteredArgs).ConfigureAwait(false); + var actual = await rulesSource.GetRulesFilteredAsync(getRulesFilteredArgs); // Assert actual.Should().NotBeNullOrEmpty() .And.BeEquivalentTo(expected); Mock.Get(rulesDataSource) - .Verify(x => x.GetRulesByAsync(It.Is>( + .Verify(x => x.GetRulesByAsync(It.Is( (val) => string.Equals(val.Name, getRulesFilteredArgs.Name) && val.ContentType == getRulesFilteredArgs.ContentType && val.Priority == getRulesFilteredArgs.Priority)), Times.Once()); } @@ -238,32 +424,32 @@ IEnumerable> rulesSourceMiddl public async Task GetRulesFilteredAsync_OneMiddleware_CallsMiddlewareAndRulesDataSourceAfter() { // Arrange - Rule rule = CreateRule(); + var rule = CreateRule(); var expected = new[] { rule }; - GetRulesFilteredArgs getRulesFilteredArgs = CreateGetRulesFilteredArgs(); + var getRulesFilteredArgs = CreateGetRulesFilteredArgs(); - StubRulesSourceMiddleware middleware1 = new(nameof(middleware1), new List()); + StubRulesSourceMiddleware middleware1 = new(nameof(middleware1), new List()); - IEnumerable> rulesSourceMiddlewares = new[] { middleware1 }; + IEnumerable rulesSourceMiddlewares = new[] { middleware1 }; - IRulesDataSource rulesDataSource = Mock.Of>(); + var rulesDataSource = Mock.Of(); Mock.Get(rulesDataSource) - .Setup(x => x.GetRulesByAsync(It.Is>( + .Setup(x => x.GetRulesByAsync(It.Is( (val) => string.Equals(val.Name, getRulesFilteredArgs.Name) && val.ContentType == getRulesFilteredArgs.ContentType && val.Priority == getRulesFilteredArgs.Priority))) .ReturnsAsync(expected); - RulesSource rulesSource = new(rulesDataSource, rulesSourceMiddlewares); + RulesSource rulesSource = new(rulesDataSource, rulesSourceMiddlewares); // Act - var actual = await rulesSource.GetRulesFilteredAsync(getRulesFilteredArgs).ConfigureAwait(false); + var actual = await rulesSource.GetRulesFilteredAsync(getRulesFilteredArgs); // Assert actual.Should().NotBeNullOrEmpty() .And.Contain(expected); middleware1.GetRulesFilteredCalls.Should().Be(1); Mock.Get(rulesDataSource) - .Verify(x => x.GetRulesByAsync(It.Is>( + .Verify(x => x.GetRulesByAsync(It.Is( (val) => string.Equals(val.Name, getRulesFilteredArgs.Name) && val.ContentType == getRulesFilteredArgs.ContentType && val.Priority == getRulesFilteredArgs.Priority)), Times.Once()); } @@ -271,27 +457,27 @@ public async Task GetRulesFilteredAsync_OneMiddleware_CallsMiddlewareAndRulesDat public async Task GetRulesFilteredAsync_TwoMiddlewares_CallsFirstMiddlewareSecondMiddlewareAfterAndRulesDataSourceByLast() { // Arrange - Rule rule = CreateRule(); + var rule = CreateRule(); var expected = new[] { rule }; - GetRulesFilteredArgs getRulesFilteredArgs = CreateGetRulesFilteredArgs(); + var getRulesFilteredArgs = CreateGetRulesFilteredArgs(); List middlewareMessages = new(); - StubRulesSourceMiddleware middleware1 = new(nameof(middleware1), middlewareMessages); - StubRulesSourceMiddleware middleware2 = new(nameof(middleware2), middlewareMessages); + StubRulesSourceMiddleware middleware1 = new(nameof(middleware1), middlewareMessages); + StubRulesSourceMiddleware middleware2 = new(nameof(middleware2), middlewareMessages); - IEnumerable> rulesSourceMiddlewares = new[] { middleware1, middleware2 }; + IEnumerable rulesSourceMiddlewares = new[] { middleware1, middleware2 }; - IRulesDataSource rulesDataSource = Mock.Of>(); + var rulesDataSource = Mock.Of(); Mock.Get(rulesDataSource) - .Setup(x => x.GetRulesByAsync(It.Is>( + .Setup(x => x.GetRulesByAsync(It.Is( (val) => string.Equals(val.Name, getRulesFilteredArgs.Name) && val.ContentType == getRulesFilteredArgs.ContentType && val.Priority == getRulesFilteredArgs.Priority))) .ReturnsAsync(expected); - RulesSource rulesSource = new(rulesDataSource, rulesSourceMiddlewares); + RulesSource rulesSource = new(rulesDataSource, rulesSourceMiddlewares); // Act - var actual = await rulesSource.GetRulesFilteredAsync(getRulesFilteredArgs).ConfigureAwait(false); + var actual = await rulesSource.GetRulesFilteredAsync(getRulesFilteredArgs); // Assert actual.Should().NotBeNullOrEmpty() @@ -300,7 +486,7 @@ public async Task GetRulesFilteredAsync_TwoMiddlewares_CallsFirstMiddlewareSecon middleware2.GetRulesFilteredCalls.Should().Be(1); middlewareMessages.Should().ContainInOrder("Enter middleware1.", "Enter middleware2.", "Exit middleware2.", "Exit middleware1."); Mock.Get(rulesDataSource) - .Verify(x => x.GetRulesByAsync(It.Is>( + .Verify(x => x.GetRulesByAsync(It.Is( (val) => string.Equals(val.Name, getRulesFilteredArgs.Name) && val.ContentType == getRulesFilteredArgs.ContentType && val.Priority == getRulesFilteredArgs.Priority)), Times.Once()); } @@ -308,116 +494,116 @@ public async Task GetRulesFilteredAsync_TwoMiddlewares_CallsFirstMiddlewareSecon public async Task UpdateRuleAsync_NoMiddlewares_CallsRulesDataSource() { // Arrange - Rule rule = CreateRule(); + var rule = CreateRule(); - UpdateRuleArgs updateRuleArgs = new() + UpdateRuleArgs updateRuleArgs = new() { Rule = rule, }; - IEnumerable> rulesSourceMiddlewares - = Enumerable.Empty>(); + var rulesSourceMiddlewares + = Enumerable.Empty(); - IRulesDataSource rulesDataSource = Mock.Of>(); + var rulesDataSource = Mock.Of(); Mock.Get(rulesDataSource) - .Setup(x => x.UpdateRuleAsync(It.Is>((val, _) => object.ReferenceEquals(val, rule)))) + .Setup(x => x.UpdateRuleAsync(It.Is((val, _) => object.ReferenceEquals(val, rule)))) .Returns(Task.CompletedTask); - RulesSource rulesSource = new(rulesDataSource, rulesSourceMiddlewares); + RulesSource rulesSource = new(rulesDataSource, rulesSourceMiddlewares); // Act - await rulesSource.UpdateRuleAsync(updateRuleArgs).ConfigureAwait(false); + await rulesSource.UpdateRuleAsync(updateRuleArgs); // Assert Mock.Get(rulesDataSource) - .Verify(x => x.UpdateRuleAsync(It.Is>((val, _) => object.ReferenceEquals(val, rule))), Times.Once()); + .Verify(x => x.UpdateRuleAsync(It.Is((val, _) => object.ReferenceEquals(val, rule))), Times.Once()); } [Fact] public async Task UpdateRuleAsync_OneMiddleware_CallsMiddlewareAndRulesDataSourceAfter() { // Arrange - Rule rule = CreateRule(); + var rule = CreateRule(); - UpdateRuleArgs updateRuleArgs = new() + UpdateRuleArgs updateRuleArgs = new() { Rule = rule, }; - StubRulesSourceMiddleware middleware1 = new(nameof(middleware1), new List()); + StubRulesSourceMiddleware middleware1 = new(nameof(middleware1), new List()); - IEnumerable> rulesSourceMiddlewares = new[] { middleware1 }; + IEnumerable rulesSourceMiddlewares = new[] { middleware1 }; - IRulesDataSource rulesDataSource = Mock.Of>(); + var rulesDataSource = Mock.Of(); Mock.Get(rulesDataSource) - .Setup(x => x.UpdateRuleAsync(It.Is>((val, _) => object.ReferenceEquals(val, rule)))) + .Setup(x => x.UpdateRuleAsync(It.Is((val, _) => object.ReferenceEquals(val, rule)))) .Returns(Task.CompletedTask); - RulesSource rulesSource = new(rulesDataSource, rulesSourceMiddlewares); + RulesSource rulesSource = new(rulesDataSource, rulesSourceMiddlewares); // Act - await rulesSource.UpdateRuleAsync(updateRuleArgs).ConfigureAwait(false); + await rulesSource.UpdateRuleAsync(updateRuleArgs); // Assert middleware1.UpdateRulesCalls.Should().Be(1); Mock.Get(rulesDataSource) - .Verify(x => x.UpdateRuleAsync(It.Is>((val, _) => object.ReferenceEquals(val, rule))), Times.Once()); + .Verify(x => x.UpdateRuleAsync(It.Is((val, _) => object.ReferenceEquals(val, rule))), Times.Once()); } [Fact] public async Task UpdateRuleAsync_TwoMiddlewares_CallsFirstMiddlewareSecondMiddlewareAfterAndRulesDataSourceByLast() { // Arrange - Rule rule = CreateRule(); + var rule = CreateRule(); - UpdateRuleArgs updateRuleArgs = new() + UpdateRuleArgs updateRuleArgs = new() { Rule = rule, }; List middlewareMessages = new(); - StubRulesSourceMiddleware middleware1 = new(nameof(middleware1), middlewareMessages); - StubRulesSourceMiddleware middleware2 = new(nameof(middleware2), middlewareMessages); + StubRulesSourceMiddleware middleware1 = new(nameof(middleware1), middlewareMessages); + StubRulesSourceMiddleware middleware2 = new(nameof(middleware2), middlewareMessages); - IEnumerable> rulesSourceMiddlewares = new[] { middleware1, middleware2 }; + IEnumerable rulesSourceMiddlewares = new[] { middleware1, middleware2 }; - IRulesDataSource rulesDataSource = Mock.Of>(); + var rulesDataSource = Mock.Of(); Mock.Get(rulesDataSource) - .Setup(x => x.UpdateRuleAsync(It.Is>((val, _) => object.ReferenceEquals(val, rule)))) + .Setup(x => x.UpdateRuleAsync(It.Is((val, _) => object.ReferenceEquals(val, rule)))) .Returns(Task.CompletedTask); - RulesSource rulesSource = new(rulesDataSource, rulesSourceMiddlewares); + RulesSource rulesSource = new(rulesDataSource, rulesSourceMiddlewares); // Act - await rulesSource.UpdateRuleAsync(updateRuleArgs).ConfigureAwait(false); + await rulesSource.UpdateRuleAsync(updateRuleArgs); // Assert middleware1.UpdateRulesCalls.Should().Be(1); middleware2.UpdateRulesCalls.Should().Be(1); middlewareMessages.Should().ContainInOrder("Enter middleware1.", "Enter middleware2.", "Exit middleware2.", "Exit middleware1."); Mock.Get(rulesDataSource) - .Verify(x => x.UpdateRuleAsync(It.Is>((val, _) => object.ReferenceEquals(val, rule))), Times.Once()); + .Verify(x => x.UpdateRuleAsync(It.Is((val, _) => object.ReferenceEquals(val, rule))), Times.Once()); } - private static GetRulesArgs CreateGetRulesArgs() => new() + private static GetRulesArgs CreateGetRulesArgs() => new() { - ContentType = ContentType.Type1, + ContentType = ContentType.Type1.ToString(), DateBegin = DateTime.Parse("2022-01-01Z"), DateEnd = DateTime.Parse("2023-01-01Z"), }; - private static GetRulesFilteredArgs CreateGetRulesFilteredArgs() => new() + private static GetRulesFilteredArgs CreateGetRulesFilteredArgs() => new() { - ContentType = ContentType.Type1, + ContentType = ContentType.Type1.ToString(), Name = "test", Priority = 1, }; - private static Rule CreateRule() => - RuleBuilder.NewRule() + private static Rule CreateRule() => + Rule.New() .WithName("Test rule") .WithDateBegin(DateTime.Parse("2022-11-27Z")) - .WithContent(ContentType.Type1, "test") + .WithContent(ContentType.Type1.ToString(), "test") .Build() .Rule; } diff --git a/tests/Rules.Framework.Tests/Source/StubRulesSourceMiddleware.cs b/tests/Rules.Framework.Tests/Source/StubRulesSourceMiddleware.cs index d2e7037c..a185ff67 100644 --- a/tests/Rules.Framework.Tests/Source/StubRulesSourceMiddleware.cs +++ b/tests/Rules.Framework.Tests/Source/StubRulesSourceMiddleware.cs @@ -1,32 +1,30 @@ namespace Rules.Framework.Tests.Source { - using Rules.Framework.Core; - using Rules.Framework.Source; - using System; using System.Collections.Generic; - using System.Linq; - using System.Text; using System.Threading.Tasks; + using Rules.Framework.Source; - internal class StubRulesSourceMiddleware : IRulesSourceMiddleware + internal class StubRulesSourceMiddleware : IRulesSourceMiddleware { private readonly List middlewareMessages; - public int AddRuleCalls { get; private set; } - public int GetRulesCalls { get; private set; } - public int GetRulesFilteredCalls { get; private set; } - public int UpdateRulesCalls { get; private set; } - public string Name { get; } - public StubRulesSourceMiddleware(string name, List middlewareMessages) { this.Name = name; this.middlewareMessages = middlewareMessages; } + public int AddRuleCalls { get; private set; } + public int CreateContentTypeCalls { get; private set; } + public int GetContentTypesCalls { get; private set; } + public int GetRulesCalls { get; private set; } + public int GetRulesFilteredCalls { get; private set; } + public string Name { get; } + public int UpdateRulesCalls { get; private set; } + public async Task HandleAddRuleAsync( - AddRuleArgs args, - AddRuleDelegate next) + AddRuleArgs args, + AddRuleDelegate next) { this.AddRuleCalls++; this.middlewareMessages.Add($"Enter {this.Name}."); @@ -34,9 +32,28 @@ public async Task HandleAddRuleAsync( this.middlewareMessages.Add($"Exit {this.Name}."); } - public async Task>> HandleGetRulesAsync( - GetRulesArgs args, - GetRulesDelegate next) + public async Task HandleCreateContentTypeAsync( + CreateContentTypeArgs args, + CreateContentTypeDelegate next) + { + this.CreateContentTypeCalls++; + this.middlewareMessages.Add($"Enter {this.Name}."); + await next.Invoke(args).ConfigureAwait(false); + this.middlewareMessages.Add($"Exit {this.Name}."); + } + + public async Task> HandleGetContentTypesAsync(GetContentTypesArgs args, GetContentTypesDelegate next) + { + this.GetContentTypesCalls++; + this.middlewareMessages.Add($"Enter {this.Name}."); + var contentTypes = await next.Invoke(args).ConfigureAwait(false); + this.middlewareMessages.Add($"Exit {this.Name}."); + return contentTypes; + } + + public async Task> HandleGetRulesAsync( + GetRulesArgs args, + GetRulesDelegate next) { this.GetRulesCalls++; this.middlewareMessages.Add($"Enter {this.Name}."); @@ -45,9 +62,9 @@ public async Task>> HandleGetRule return rules; } - public async Task>> HandleGetRulesFilteredAsync( - GetRulesFilteredArgs args, - GetRulesFilteredDelegate next) + public async Task> HandleGetRulesFilteredAsync( + GetRulesFilteredArgs args, + GetRulesFilteredDelegate next) { this.GetRulesFilteredCalls++; this.middlewareMessages.Add($"Enter {this.Name}."); @@ -57,8 +74,8 @@ public async Task>> HandleGetRule } public async Task HandleUpdateRuleAsync( - UpdateRuleArgs args, - UpdateRuleDelegate next) + UpdateRuleArgs args, + UpdateRuleDelegate next) { this.UpdateRulesCalls++; this.middlewareMessages.Add($"Enter {this.Name}."); @@ -66,4 +83,4 @@ public async Task HandleUpdateRuleAsync( this.middlewareMessages.Add($"Exit {this.Name}."); } } -} +} \ No newline at end of file diff --git a/tests/Rules.Framework.WebUI.Tests/Extensions/RuleDtoExtensionsTests.cs b/tests/Rules.Framework.WebUI.Tests/Extensions/RuleDtoExtensionsTests.cs index ef9c4343..9bf2b206 100644 --- a/tests/Rules.Framework.WebUI.Tests/Extensions/RuleDtoExtensionsTests.cs +++ b/tests/Rules.Framework.WebUI.Tests/Extensions/RuleDtoExtensionsTests.cs @@ -1,7 +1,7 @@ namespace Rules.Framework.WebUI.Tests.Extensions { + using System; using FluentAssertions; - using Rules.Framework.Generics; using Rules.Framework.WebUI.Dto; using Rules.Framework.WebUI.Extensions; using Xunit; @@ -19,7 +19,11 @@ public RuleDtoExtensionsTests() public void RuleDtoExtensions_ToRuleDto_Success() { // Arrange - var genericRule = new GenericRule(); + var genericRule = Rule.New() + .WithName("Rule #1") + .WithDateBegin(new DateTime(2024, 6, 1)) + .WithContent("Type #1", new object()) + .Build().Rule; var contentType = "contentType"; // Act var ruleDto = genericRule.ToRuleDto(contentType, this.ruleStatusDtoAnalyzer); @@ -29,4 +33,4 @@ public void RuleDtoExtensions_ToRuleDto_Success() ruleDto.Should().BeOfType(); } } -} +} \ No newline at end of file diff --git a/tests/Rules.Framework.WebUI.Tests/Handlers/GetConfigurationsHandlerTests.cs b/tests/Rules.Framework.WebUI.Tests/Handlers/GetConfigurationsHandlerTests.cs index 9d6a9772..24fd791f 100644 --- a/tests/Rules.Framework.WebUI.Tests/Handlers/GetConfigurationsHandlerTests.cs +++ b/tests/Rules.Framework.WebUI.Tests/Handlers/GetConfigurationsHandlerTests.cs @@ -6,7 +6,6 @@ namespace Rules.Framework.WebUI.Tests.Handlers using FluentAssertions; using Microsoft.AspNetCore.Http; using Moq; - using Rules.Framework.Generics; using Rules.Framework.WebUI.Handlers; using Rules.Framework.WebUI.Tests.Utilities; using Xunit; @@ -14,11 +13,14 @@ namespace Rules.Framework.WebUI.Tests.Handlers public class GetConfigurationsHandlerTests { private readonly GetConfigurationsHandler handler; - private readonly Mock rulesEngine; + private readonly Mock rulesEngine; public GetConfigurationsHandlerTests() { - this.rulesEngine = new Mock(); + this.rulesEngine = new Mock(); + this.rulesEngine + .SetupGet(x => x.Options) + .Returns(RulesEngineOptions.NewWithDefaults()); this.handler = new GetConfigurationsHandler(rulesEngine.Object, new WebUIOptions()); } @@ -34,9 +36,7 @@ public async Task HandleRequestAsync_Validation(string httpMethod, string resour RequestDelegate next = (HttpContext _) => Task.CompletedTask; //Act - var result = await this.handler - .HandleAsync(httpContext.Request, httpContext.Response, next) - .ConfigureAwait(false); + var result = await this.handler.HandleAsync(httpContext.Request, httpContext.Response, next); //Assert result.Should().Be(expectedResult); @@ -45,19 +45,19 @@ public async Task HandleRequestAsync_Validation(string httpMethod, string resour httpContext.Response.Should().NotBeNull(); httpContext.Response.StatusCode.Should().Be((int)HttpStatusCode.OK); httpContext.Response.ContentType.Should().Be("application/json"); - string body = string.Empty; + var body = string.Empty; using (var reader = new StreamReader(httpContext.Response.Body)) { httpContext.Response.Body.Seek(0, SeekOrigin.Begin); - body = await reader.ReadToEndAsync().ConfigureAwait(false); + body = await reader.ReadToEndAsync(); } body.Should().NotBeNullOrWhiteSpace(); httpContext.Response.ContentLength.Should().Be(body.Length); - this.rulesEngine.Verify(s => s.GetPriorityCriteria(), Times.Once); + this.rulesEngine.Verify(s => s.Options, Times.AtLeastOnce()); } else { - this.rulesEngine.Verify(s => s.GetPriorityCriteria(), Times.Never); + this.rulesEngine.Verify(s => s.Options, Times.Never()); } } } diff --git a/tests/Rules.Framework.WebUI.Tests/Handlers/GetContentTypeHandlerTests.cs b/tests/Rules.Framework.WebUI.Tests/Handlers/GetContentTypeHandlerTests.cs index 4b2a6fe0..6a4e2057 100644 --- a/tests/Rules.Framework.WebUI.Tests/Handlers/GetContentTypeHandlerTests.cs +++ b/tests/Rules.Framework.WebUI.Tests/Handlers/GetContentTypeHandlerTests.cs @@ -6,7 +6,6 @@ namespace Rules.Framework.WebUI.Tests.Handlers using FluentAssertions; using Microsoft.AspNetCore.Http; using Moq; - using Rules.Framework.Generics; using Rules.Framework.WebUI.Dto; using Rules.Framework.WebUI.Handlers; using Rules.Framework.WebUI.Tests.Utilities; @@ -15,12 +14,12 @@ namespace Rules.Framework.WebUI.Tests.Handlers public class GetContentTypeHandlerTests { private readonly GetContentTypeHandler handler; - private readonly Mock rulesEngine; + private readonly Mock rulesEngine; public GetContentTypeHandlerTests() { var ruleStatusDtoAnalyzer = new RuleStatusDtoAnalyzer(); - this.rulesEngine = new Mock(); + this.rulesEngine = new Mock(); this.handler = new GetContentTypeHandler(rulesEngine.Object, ruleStatusDtoAnalyzer, new WebUIOptions()); } @@ -35,9 +34,7 @@ public async Task HandleRequestAsync_Validation(string httpMethod, string resour var httpContext = HttpContextHelper.CreateHttpContext(httpMethod, resourcePath); RequestDelegate next = (HttpContext _) => Task.CompletedTask; //Act - var result = await this.handler - .HandleAsync(httpContext.Request, httpContext.Response, next) - .ConfigureAwait(false); + var result = await this.handler.HandleAsync(httpContext.Request, httpContext.Response, next); //Assert result.Should().Be(expectedResult); @@ -46,7 +43,7 @@ public async Task HandleRequestAsync_Validation(string httpMethod, string resour httpContext.Response.Should().NotBeNull(); httpContext.Response.StatusCode.Should().Be((int)HttpStatusCode.OK); httpContext.Response.ContentType.Should().Be("application/json"); - string body = string.Empty; + var body = string.Empty; using (var reader = new StreamReader(httpContext.Response.Body)) { httpContext.Response.Body.Seek(0, SeekOrigin.Begin); @@ -54,11 +51,11 @@ public async Task HandleRequestAsync_Validation(string httpMethod, string resour } body.Should().NotBeNullOrWhiteSpace(); httpContext.Response.ContentLength.Should().Be(body.Length); - this.rulesEngine.Verify(s => s.GetContentTypes(), Times.Once); + this.rulesEngine.Verify(s => s.GetContentTypesAsync(), Times.Once); } else { - this.rulesEngine.Verify(s => s.GetContentTypes(), Times.Never); + this.rulesEngine.Verify(s => s.GetContentTypesAsync(), Times.Never); } } } diff --git a/tests/Rules.Framework.WebUI.Tests/Handlers/GetRulesHandlerTests.cs b/tests/Rules.Framework.WebUI.Tests/Handlers/GetRulesHandlerTests.cs index 973c1f2b..5e1ee3d2 100644 --- a/tests/Rules.Framework.WebUI.Tests/Handlers/GetRulesHandlerTests.cs +++ b/tests/Rules.Framework.WebUI.Tests/Handlers/GetRulesHandlerTests.cs @@ -8,7 +8,6 @@ namespace Rules.Framework.WebUI.Tests.Handlers using FluentAssertions; using Microsoft.AspNetCore.Http; using Moq; - using Rules.Framework.Generics; using Rules.Framework.WebUI.Dto; using Rules.Framework.WebUI.Handlers; using Rules.Framework.WebUI.Tests.Utilities; @@ -17,11 +16,13 @@ namespace Rules.Framework.WebUI.Tests.Handlers public class GetRulesHandlerTests { private readonly GetRulesHandler handler; - private readonly Mock rulesEngine; + private readonly Mock rulesEngine; public GetRulesHandlerTests() { - this.rulesEngine = new Mock(); + this.rulesEngine = new Mock(); + this.rulesEngine.SetupGet(x => x.Options) + .Returns(RulesEngineOptions.NewWithDefaults()); var ruleStatusDtoAnalyzer = new RuleStatusDtoAnalyzer(); this.handler = new GetRulesHandler(rulesEngine.Object, ruleStatusDtoAnalyzer, new WebUIOptions()); } @@ -36,7 +37,7 @@ public async Task HandleRequestAsync_Validation(string httpMethod, string resour { //Arrange var httpContext = HttpContextHelper.CreateHttpContext(httpMethod, resourcePath); - var genericRule = new List(); + var genericRule = new List(); var verifySearchAsync = false; if (statusCode == HttpStatusCode.OK || statusCode == HttpStatusCode.InternalServerError) @@ -47,13 +48,13 @@ public async Task HandleRequestAsync_Validation(string httpMethod, string resour if (statusCode == HttpStatusCode.OK) { - this.rulesEngine.Setup(d => d.SearchAsync(It.IsAny>())) + this.rulesEngine.Setup(d => d.SearchAsync(It.IsAny>())) .ReturnsAsync(genericRule); } if (statusCode == HttpStatusCode.InternalServerError) { - this.rulesEngine.Setup(d => d.SearchAsync(It.IsAny>())) + this.rulesEngine.Setup(d => d.SearchAsync(It.IsAny>())) .Throws(new Exception("message", new Exception("inner"))); } } @@ -64,9 +65,7 @@ public async Task HandleRequestAsync_Validation(string httpMethod, string resour RequestDelegate next = (HttpContext _) => Task.CompletedTask; //Act - var result = await this.handler - .HandleAsync(httpContext.Request, httpContext.Response, next) - .ConfigureAwait(false); + var result = await this.handler.HandleAsync(httpContext.Request, httpContext.Response, next); //Assert result.Should().Be(expectedResult); @@ -75,7 +74,7 @@ public async Task HandleRequestAsync_Validation(string httpMethod, string resour httpContext.Response.Should().NotBeNull(); httpContext.Response.StatusCode.Should().Be((int)statusCode); httpContext.Response.ContentType.Should().Be("application/json"); - string body = string.Empty; + var body = string.Empty; using (var reader = new StreamReader(httpContext.Response.Body)) { httpContext.Response.Body.Seek(0, SeekOrigin.Begin); @@ -88,13 +87,13 @@ public async Task HandleRequestAsync_Validation(string httpMethod, string resour if (verifySearchAsync) { this.rulesEngine - .Verify(s => s.SearchAsync(It.IsAny>()), Times.Once); + .Verify(s => s.SearchAsync(It.IsAny>()), Times.Once); } else { this.rulesEngine - .Verify(s => s.SearchAsync(It.IsAny>()), Times.Never); + .Verify(s => s.SearchAsync(It.IsAny>()), Times.Never); } } } -} +} \ No newline at end of file From 5555311755bd67caa4ebc69b491a7073c54a169c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Lu=C3=ADs=20Garc=C3=AAs?= Date: Sat, 5 Oct 2024 19:17:09 +0100 Subject: [PATCH 4/6] refactor!: Rename content type to ruleset (#171) * refactor!: rename content type/ruleset and condition type/condition * chore: code review changes --- ...ypes.cs => IRuleSpecificationsProvider.cs} | 4 +- .../Engine/RuleSpecification.cs | 2 +- .../Engine/RulesBuilder.cs | 13 +- .../Engine/RulesService.cs | 18 +- .../{ConditionTypes.cs => ConditionNames.cs} | 12 +- .../{ContentTypes.cs => RulesetNames.cs} | 4 +- .../Program.cs | 22 +- .../Rules/TestNumberRules.cs | 50 +- ...ypes.cs => IRuleSpecificationsProvider.cs} | 4 +- .../Engine/RuleSpecification.cs | 4 +- .../Engine/RulesBuilder.cs | 12 +- .../{ConditionTypes.cs => ConditionNames.cs} | 12 +- .../{ContentTypes.cs => RulesetNames.cs} | 4 +- .../Rules.Framework.WebUI.Sample/Program.cs | 3 +- ...onditionType.cs => BasicConditionNames.cs} | 2 +- .../ReadmeExample/BasicRulesEngineExample.cs | 58 +- ...sicContentType.cs => BasicRulesetNames.cs} | 2 +- .../Rules/RulesRandomFactory.cs | 61 +- .../DataModel/RuleDataModel.cs | 6 +- ...ntTypeDataModel.cs => RulesetDataModel.cs} | 2 +- .../DataModel/ValueConditionNodeDataModel.cs | 10 +- .../MongoDbProviderRulesDataSource.cs | 77 ++- .../MongoDbProviderSettings.cs | 16 +- .../MongoDbRulesDataSourceInitializer.cs | 60 +- ...ongoDbRulesDataSourceSelectorExtensions.cs | 2 - .../RuleFactory.cs | 21 +- src/Rules.Framework.WebUI/Dto/RuleDto.cs | 4 +- .../Dto/{FilterDto.cs => RulesFilterDto.cs} | 4 +- .../Dto/{ContentTypeDto.cs => RulesetDto.cs} | 2 +- .../Dto/ValueConditionNodeDto.cs | 4 +- .../Extensions/RuleDtoExtensions.cs | 12 +- .../Handlers/GetRulesHandler.cs | 22 +- ...ntTypeHandler.cs => GetRulesetsHandler.cs} | 26 +- .../WebUIApplicationBuilderExtensions.cs | 50 +- src/Rules.Framework.WebUI/index.html | 126 ++-- .../Builder/ConditionNodeFactory.cs | 42 +- .../Builder/ConfiguredRulesEngineBuilder.cs | 4 +- .../IFluentComposedConditionNodeBuilder.cs | 50 -- .../Generic/IRootConditionNodeBuilder.cs | 45 -- .../Builder/Generic/IRuleBuilder.cs | 96 --- .../Generic/RootConditionNodeBuilder.cs | 33 - .../Builder/Generic/RuleBuilder.cs | 112 --- .../FluentConditionNodeBuilder.cs} | 29 +- .../IFluentConditionNodeBuilder.cs | 49 ++ .../IRootConditionNodeBuilder.cs | 13 +- .../Generic/RulesBuilder/IRuleBuilder.cs | 51 ++ .../RulesBuilder/IRuleConfigureContent.cs | 27 + .../RulesBuilder/IRuleConfigureDateBegin.cs | 19 + .../RulesBuilder/IRuleConfigureDateEnd.cs | 19 + .../IRuleConfigureDateEndOptional.cs | 13 + .../RulesBuilder/IRuleConfigureRuleset.cs | 17 + .../RulesBuilder/RootConditionNodeBuilder.cs | 32 + .../Generic/RulesBuilder/RuleBuilder.cs | 102 +++ .../IFluentComposedConditionNodeBuilder.cs | 48 -- src/Rules.Framework/Builder/IRuleBuilder.cs | 92 --- .../FluentConditionNodeBuilder.cs} | 27 +- .../IFluentConditionNodeBuilder.cs | 46 ++ .../RulesBuilder/IRootConditionNodeBuilder.cs | 40 ++ .../Builder/RulesBuilder/IRuleBuilder.cs | 49 ++ .../RulesBuilder/IRuleConfigureContent.cs | 25 + .../RulesBuilder/IRuleConfigureDateBegin.cs | 17 + .../RulesBuilder/IRuleConfigureDateEnd.cs | 17 + .../IRuleConfigureDateEndOptional.cs | 9 + .../RulesBuilder/IRuleConfigureRuleset.cs | 15 + .../RootConditionNodeBuilder.cs | 15 +- .../Builder/{ => RulesBuilder}/RuleBuilder.cs | 117 ++-- .../ConditionNodeValidationExtensions.cs | 10 +- .../GenericComposedConditionNodeValidator.cs | 11 +- .../GenericValueConditionNodeValidator.cs | 6 +- .../Builder/Validation/RuleValidator.cs | 1 + .../Validation/ValueConditionNodeValidator.cs | 3 +- .../ConditionNodes/ComposedConditionNode.cs | 22 +- .../ConditionNodes/IValueConditionNode.cs | 6 +- .../ConditionNodes/ValueConditionNode.cs | 59 +- src/Rules.Framework/ConditionTypeExtractor.cs | 70 -- .../CompilationRulesSourceMiddleware.cs | 6 +- .../RuleConditionsExpressionBuilder.cs | 4 +- .../Evaluation/ConditionsTreeAnalyzer.cs | 4 +- .../Evaluation/Interpreted/DeferredEval.cs | 2 +- .../Extensions/RuleBuilderExtensions.cs | 215 ++++++ .../Extensions/RulesEngineExtensions.cs | 8 +- .../ConditionNodes/ComposedConditionNode.cs | 21 +- .../ConditionNodes/IValueConditionNode.cs | 10 +- .../ConditionNodes/ValueConditionNode.cs | 49 +- .../Generic/GenericConversions.cs | 2 - src/Rules.Framework/Generic/IConditionNode.cs | 6 +- src/Rules.Framework/Generic/IRulesEngine.cs | 71 +- src/Rules.Framework/Generic/Rule.cs | 42 +- src/Rules.Framework/Generic/RuleExtensions.cs | 9 +- src/Rules.Framework/Generic/RulesEngine.cs | 80 ++- src/Rules.Framework/Generic/Ruleset.cs | 30 + .../IConditionTypeExtractor.cs | 25 - .../IRuleConditionsExtractor.cs | 17 + src/Rules.Framework/IRulesDataSource.cs | 18 +- src/Rules.Framework/IRulesEngine.cs | 51 +- src/Rules.Framework/IRulesEngineOptions.cs | 17 +- .../InMemory/DataModel/RuleDataModel.cs | 4 +- .../InMemory/DataModel/RulesetDataModel.cs | 14 + .../DataModel/ValueConditionNodeDataModel.cs | 2 +- .../InMemory/IInMemoryRulesStorage.cs | 6 +- .../InMemoryProviderRulesDataSource.cs | 64 +- .../InMemory/InMemoryRulesStorage.cs | 40 +- .../Providers/InMemory/RuleFactory.cs | 8 +- src/Rules.Framework/Rule.cs | 34 +- .../RuleConditionsExtractor.cs | 59 ++ src/Rules.Framework/RulesEngine.cs | 76 +-- src/Rules.Framework/RulesEngineOptions.cs | 35 +- src/Rules.Framework/RulesFilterArgs.cs | 14 +- src/Rules.Framework/Ruleset.cs | 28 + src/Rules.Framework/SearchArgs.cs | 42 +- .../Source/CreateContentTypeDelegate.cs | 6 - ...ontentTypeArgs.cs => CreateRulesetArgs.cs} | 2 +- .../Source/CreateRulesetDelegate.cs | 6 + .../Source/GetRulesFilteredArgs.cs | 2 +- ...ContentTypesArgs.cs => GetRulesetsArgs.cs} | 2 +- ...ypesDelegate.cs => GetRulesetsDelegate.cs} | 2 +- src/Rules.Framework/Source/IRulesSource.cs | 6 +- .../Source/IRulesSourceMiddleware.cs | 14 +- src/Rules.Framework/Source/RulesSource.cs | 34 +- .../Validation/SearchArgsValidator.cs | 8 +- .../Tests/Benchmark1/Benchmark1.cs | 8 +- .../Tests/Benchmark2/Benchmark2.cs | 8 +- .../Tests/Benchmark3/Benchmark3.cs | 8 +- .../Features/RuleSpecification.cs | 4 +- .../Features/Stubs/ConditionNames.cs | 11 + .../Features/Stubs/ConditionType.cs | 11 - .../Features/Stubs/ContentType.cs | 9 - .../Features/Stubs/RulesetNames.cs | 9 + .../Scenarios/IScenarioData.cs | 6 +- ...ionTypes.cs => Scenario1ConditionNames.cs} | 2 +- ...ntentTypes.cs => Scenario1RulesetNames.cs} | 2 +- ...work-tests.body-mass-index.datasource.json | 2 +- ...Types.cs => CarInsuranceConditionNames.cs} | 2 +- ...ntTypes.cs => CarInsuranceRulesetNames.cs} | 2 +- ...framework-tests.car-insurance-advisor.json | 20 +- ...ork-tests.security-system-actionables.json | 32 +- .../{ConditionTypes.cs => ConditionNames.cs} | 2 +- .../{ContentTypes.cs => Rulesets.cs} | 4 +- .../Scenarios/Scenario6/Scenario6Data.cs | 20 +- .../{ConditionTypes.cs => ConditionNames.cs} | 2 +- .../{ContentTypes.cs => Rulesets.cs} | 2 +- .../Scenarios/Scenario7/Scenario7Data.cs | 52 +- .../{ConditionTypes.cs => PokerConditions.cs} | 2 +- .../{ContentTypes.cs => PokerRulesets.cs} | 2 +- .../Scenario8/Scenario8Data.Flush.cs | 45 +- .../Scenario8/Scenario8Data.FourOfAKind.cs | 135 ++-- .../Scenario8/Scenario8Data.HighCard.cs | 135 ++-- .../Scenarios/Scenario8/Scenario8Data.Pair.cs | 135 ++-- .../Scenario8/Scenario8Data.RoyalFlush.cs | 85 ++- .../Scenario8/Scenario8Data.Straight.cs | 189 +++-- .../Scenario8/Scenario8Data.StraightFlush.cs | 645 +++++++++--------- .../Scenario8/Scenario8Data.ThreeOfAKind.cs | 135 ++-- .../Scenarios/Scenario8/Scenario8Data.cs | 28 +- .../Scenarios/ScenarioLoader.cs | 10 +- .../DataSource/ConditionNodeDataModel.cs | 2 +- .../DataSource/RuleDataModel.cs | 7 +- .../RulesFromJsonFile.cs | 71 +- .../Scenarios/Scenario1/BodyMassIndexTests.cs | 66 +- .../Scenario2/CarInsuranceAdvisorTests.cs | 71 +- .../Scenario4/DiscountCampaignTests.cs | 90 +-- .../Scenarios/Scenario5/BestServerTests.cs | 48 +- ...TexasHoldEmPokerSingleCombinationsTests.cs | 24 +- .../RulesEngine/RulesEngineTestsBase.cs | 32 +- .../OperatorContainsManyToOneTests.cs | 28 +- .../RulesDeactivateAndActivateTests.cs | 27 +- .../RulesMatching/RulesInSequenceTests.cs | 28 +- .../RulesMatching/RulesUpdateDateEndTests.cs | 28 +- .../Scenarios/BaseScenarioTests.cs | 14 +- .../Scenario2/CarInsuranceAdvisorTests.cs | 42 +- .../Scenarios/Scenario5/BestServerTests.cs | 25 +- .../RulesEngine/RulesEngineTestsBase.cs | 20 +- .../RulesDeactivateAndActivateTests.cs | 32 +- .../RulesMatching/RulesInSequenceTests.cs | 32 +- .../RulesMatching/RulesUpdateDateEndTests.cs | 30 +- .../Scenario2/CarInsuranceAdvisorTests.cs | 38 +- ...framework-tests.car-insurance-advisor.json | 136 ++-- .../BuildingSecuritySystemControlTests.cs | 24 +- ...ork-tests.security-system-actionables.json | 352 +++++----- .../Scenarios/Scenario5/BestServerTests.cs | 27 +- .../MongoDbProviderRulesDataSourceTests.cs | 49 +- .../RuleFactoryTests.cs | 56 +- ...ngTypeContentSerializationProviderTests.cs | 2 +- ...namicToStrongTypeContentSerializerTests.cs | 136 ++-- .../{ConditionType.cs => ConditionNames.cs} | 2 +- .../TestStubs/ContentStub.cs | 2 +- .../{ContentType.cs => RulesetNames.cs} | 4 +- .../Builder/RuleBuilderTests.cs | 101 +-- .../ConditionNodes/ValueConditionNodeTests.cs | 32 +- tests/Rules.Framework.Tests/ConditionTests.cs | 4 +- .../CompilationRulesSourceMiddlewareTests.cs | 24 +- .../CompiledConditionsEvalEngineTests.cs | 10 +- .../ConditionsValueLookupExtensionTests.cs | 6 +- .../RuleConditionsExpressionBuilderTests.cs | 40 +- .../Evaluation/ConditionsTreeAnalyzerTests.cs | 24 +- .../Interpreted/DeferredEvalTests.cs | 24 +- .../InterpretedConditionsEvalEngineTests.cs | 32 +- .../Extensions/GenericRuleExtensionsTests.cs | 64 +- .../Extensions/RulesEngineExtensionsTests.cs | 6 +- .../Generic/RulesEngineTests.cs | 100 +-- .../Providers/InMemory/RuleFactoryTests.cs | 49 +- .../{ConditionType.cs => ConditionNames.cs} | 2 +- .../InMemory/TestStubs/ContentStub.cs | 2 +- .../{ContentType.cs => RulesetNames.cs} | 2 +- ...sts.cs => RuleConditionsExtractorTests.cs} | 34 +- tests/Rules.Framework.Tests/RuleTests.cs | 2 +- .../Rules.Framework.Tests/RulesEngineTests.cs | 205 +++--- .../SerializedContentContainerTests.cs | 2 +- .../Source/RulesSourceTests.cs | 174 ++--- .../Source/StubRulesSourceMiddleware.cs | 30 +- ...{ContentTypeClass.cs => ConditionClass.cs} | 2 +- .../{ConditionType.cs => ConditionNames.cs} | 2 +- ...ptyContentType.cs => EmptyRulesetNames.cs} | 2 +- ...{ConditionTypeClass.cs => RulesetClass.cs} | 2 +- .../{ContentType.cs => RulesetNames.cs} | 2 +- .../Validation/SearchArgsValidatorTests.cs | 69 +- .../Extensions/RuleDtoExtensionsTests.cs | 12 +- .../Handlers/GetConfigurationsHandlerTests.cs | 2 +- .../Handlers/GetRulesHandlerTests.cs | 4 +- ...lerTests.cs => GetRulesetsHandlerTests.cs} | 16 +- 219 files changed, 4073 insertions(+), 3702 deletions(-) rename samples/Rules.Framework.InMemory.Sample/Engine/{IContentTypes.cs => IRuleSpecificationsProvider.cs} (71%) rename samples/Rules.Framework.InMemory.Sample/Enums/{ConditionTypes.cs => ConditionNames.cs} (57%) rename samples/Rules.Framework.InMemory.Sample/Enums/{ContentTypes.cs => RulesetNames.cs} (57%) rename samples/Rules.Framework.WebUI.Sample/Engine/{IContentTypes.cs => IRuleSpecificationsProvider.cs} (70%) rename samples/Rules.Framework.WebUI.Sample/Enums/{ConditionTypes.cs => ConditionNames.cs} (57%) rename samples/Rules.Framework.WebUI.Sample/Enums/{ContentTypes.cs => RulesetNames.cs} (89%) rename samples/Rules.Framework.WebUI.Sample/ReadmeExample/{BasicConditionType.cs => BasicConditionNames.cs} (75%) rename samples/Rules.Framework.WebUI.Sample/ReadmeExample/{BasicContentType.cs => BasicRulesetNames.cs} (77%) rename src/Rules.Framework.Providers.MongoDb/DataModel/{ContentTypeDataModel.cs => RulesetDataModel.cs} (90%) rename src/Rules.Framework.WebUI/Dto/{FilterDto.cs => RulesFilterDto.cs} (87%) rename src/Rules.Framework.WebUI/Dto/{ContentTypeDto.cs => RulesetDto.cs} (86%) rename src/Rules.Framework.WebUI/Handlers/{GetContentTypeHandler.cs => GetRulesetsHandler.cs} (67%) delete mode 100644 src/Rules.Framework/Builder/Generic/IFluentComposedConditionNodeBuilder.cs delete mode 100644 src/Rules.Framework/Builder/Generic/IRootConditionNodeBuilder.cs delete mode 100644 src/Rules.Framework/Builder/Generic/IRuleBuilder.cs delete mode 100644 src/Rules.Framework/Builder/Generic/RootConditionNodeBuilder.cs delete mode 100644 src/Rules.Framework/Builder/Generic/RuleBuilder.cs rename src/Rules.Framework/Builder/Generic/{FluentComposedConditionNodeBuilder.cs => RulesBuilder/FluentConditionNodeBuilder.cs} (55%) create mode 100644 src/Rules.Framework/Builder/Generic/RulesBuilder/IFluentConditionNodeBuilder.cs rename src/Rules.Framework/Builder/{ => Generic/RulesBuilder}/IRootConditionNodeBuilder.cs (67%) create mode 100644 src/Rules.Framework/Builder/Generic/RulesBuilder/IRuleBuilder.cs create mode 100644 src/Rules.Framework/Builder/Generic/RulesBuilder/IRuleConfigureContent.cs create mode 100644 src/Rules.Framework/Builder/Generic/RulesBuilder/IRuleConfigureDateBegin.cs create mode 100644 src/Rules.Framework/Builder/Generic/RulesBuilder/IRuleConfigureDateEnd.cs create mode 100644 src/Rules.Framework/Builder/Generic/RulesBuilder/IRuleConfigureDateEndOptional.cs create mode 100644 src/Rules.Framework/Builder/Generic/RulesBuilder/IRuleConfigureRuleset.cs create mode 100644 src/Rules.Framework/Builder/Generic/RulesBuilder/RootConditionNodeBuilder.cs create mode 100644 src/Rules.Framework/Builder/Generic/RulesBuilder/RuleBuilder.cs delete mode 100644 src/Rules.Framework/Builder/IFluentComposedConditionNodeBuilder.cs delete mode 100644 src/Rules.Framework/Builder/IRuleBuilder.cs rename src/Rules.Framework/Builder/{FluentComposedConditionNodeBuilder.cs => RulesBuilder/FluentConditionNodeBuilder.cs} (64%) create mode 100644 src/Rules.Framework/Builder/RulesBuilder/IFluentConditionNodeBuilder.cs create mode 100644 src/Rules.Framework/Builder/RulesBuilder/IRootConditionNodeBuilder.cs create mode 100644 src/Rules.Framework/Builder/RulesBuilder/IRuleBuilder.cs create mode 100644 src/Rules.Framework/Builder/RulesBuilder/IRuleConfigureContent.cs create mode 100644 src/Rules.Framework/Builder/RulesBuilder/IRuleConfigureDateBegin.cs create mode 100644 src/Rules.Framework/Builder/RulesBuilder/IRuleConfigureDateEnd.cs create mode 100644 src/Rules.Framework/Builder/RulesBuilder/IRuleConfigureDateEndOptional.cs create mode 100644 src/Rules.Framework/Builder/RulesBuilder/IRuleConfigureRuleset.cs rename src/Rules.Framework/Builder/{ => RulesBuilder}/RootConditionNodeBuilder.cs (52%) rename src/Rules.Framework/Builder/{ => RulesBuilder}/RuleBuilder.cs (57%) delete mode 100644 src/Rules.Framework/ConditionTypeExtractor.cs create mode 100644 src/Rules.Framework/Extensions/RuleBuilderExtensions.cs create mode 100644 src/Rules.Framework/Generic/Ruleset.cs delete mode 100644 src/Rules.Framework/IConditionTypeExtractor.cs create mode 100644 src/Rules.Framework/IRuleConditionsExtractor.cs create mode 100644 src/Rules.Framework/Providers/InMemory/DataModel/RulesetDataModel.cs create mode 100644 src/Rules.Framework/RuleConditionsExtractor.cs create mode 100644 src/Rules.Framework/Ruleset.cs delete mode 100644 src/Rules.Framework/Source/CreateContentTypeDelegate.cs rename src/Rules.Framework/Source/{CreateContentTypeArgs.cs => CreateRulesetArgs.cs} (64%) create mode 100644 src/Rules.Framework/Source/CreateRulesetDelegate.cs rename src/Rules.Framework/Source/{GetContentTypesArgs.cs => GetRulesetsArgs.cs} (51%) rename src/Rules.Framework/Source/{GetContentTypesDelegate.cs => GetRulesetsDelegate.cs} (52%) create mode 100644 tests/Rules.Framework.IntegrationTests.Common/Features/Stubs/ConditionNames.cs delete mode 100644 tests/Rules.Framework.IntegrationTests.Common/Features/Stubs/ConditionType.cs delete mode 100644 tests/Rules.Framework.IntegrationTests.Common/Features/Stubs/ContentType.cs create mode 100644 tests/Rules.Framework.IntegrationTests.Common/Features/Stubs/RulesetNames.cs rename tests/Rules.Framework.IntegrationTests.Common/Scenarios/Scenario1/{ConditionTypes.cs => Scenario1ConditionNames.cs} (71%) rename tests/Rules.Framework.IntegrationTests.Common/Scenarios/Scenario1/{ContentTypes.cs => Scenario1RulesetNames.cs} (75%) rename tests/Rules.Framework.IntegrationTests.Common/Scenarios/Scenario2/{ConditionTypes.cs => CarInsuranceConditionNames.cs} (83%) rename tests/Rules.Framework.IntegrationTests.Common/Scenarios/Scenario2/{ContentTypes.cs => CarInsuranceRulesetNames.cs} (73%) rename tests/Rules.Framework.IntegrationTests.Common/Scenarios/Scenario6/{ConditionTypes.cs => ConditionNames.cs} (86%) rename tests/Rules.Framework.IntegrationTests.Common/Scenarios/Scenario6/{ContentTypes.cs => Rulesets.cs} (57%) rename tests/Rules.Framework.IntegrationTests.Common/Scenarios/Scenario7/{ConditionTypes.cs => ConditionNames.cs} (81%) rename tests/Rules.Framework.IntegrationTests.Common/Scenarios/Scenario7/{ContentTypes.cs => Rulesets.cs} (76%) rename tests/Rules.Framework.IntegrationTests.Common/Scenarios/Scenario8/{ConditionTypes.cs => PokerConditions.cs} (98%) rename tests/Rules.Framework.IntegrationTests.Common/Scenarios/Scenario8/{ContentTypes.cs => PokerRulesets.cs} (80%) rename tests/Rules.Framework.Providers.MongoDb.Tests/TestStubs/{ConditionType.cs => ConditionNames.cs} (86%) rename tests/Rules.Framework.Providers.MongoDb.Tests/TestStubs/{ContentType.cs => RulesetNames.cs} (55%) rename tests/Rules.Framework.Tests/Providers/InMemory/TestStubs/{ConditionType.cs => ConditionNames.cs} (87%) rename tests/Rules.Framework.Tests/Providers/InMemory/TestStubs/{ContentType.cs => RulesetNames.cs} (77%) rename tests/Rules.Framework.Tests/{ConditionTypeExtractorTests.cs => RuleConditionsExtractorTests.cs} (77%) rename tests/Rules.Framework.Tests/TestStubs/{ContentTypeClass.cs => ConditionClass.cs} (78%) rename tests/Rules.Framework.Tests/TestStubs/{ConditionType.cs => ConditionNames.cs} (84%) rename tests/Rules.Framework.Tests/TestStubs/{EmptyContentType.cs => EmptyRulesetNames.cs} (59%) rename tests/Rules.Framework.Tests/TestStubs/{ConditionTypeClass.cs => RulesetClass.cs} (77%) rename tests/Rules.Framework.Tests/TestStubs/{ContentType.cs => RulesetNames.cs} (74%) rename tests/Rules.Framework.WebUI.Tests/Handlers/{GetContentTypeHandlerTests.cs => GetRulesetsHandlerTests.cs} (77%) diff --git a/samples/Rules.Framework.InMemory.Sample/Engine/IContentTypes.cs b/samples/Rules.Framework.InMemory.Sample/Engine/IRuleSpecificationsProvider.cs similarity index 71% rename from samples/Rules.Framework.InMemory.Sample/Engine/IContentTypes.cs rename to samples/Rules.Framework.InMemory.Sample/Engine/IRuleSpecificationsProvider.cs index 4983e7ea..1306bacc 100644 --- a/samples/Rules.Framework.InMemory.Sample/Engine/IContentTypes.cs +++ b/samples/Rules.Framework.InMemory.Sample/Engine/IRuleSpecificationsProvider.cs @@ -3,9 +3,9 @@ namespace Rules.Framework.InMemory.Sample.Engine using System.Collections.Generic; using global::Rules.Framework.InMemory.Sample.Enums; - internal interface IContentTypes + internal interface IRuleSpecificationsProvider { - ContentTypes ContentType { get; } + RulesetNames[] Rulesets { get; } IEnumerable GetRulesSpecifications(); } diff --git a/samples/Rules.Framework.InMemory.Sample/Engine/RuleSpecification.cs b/samples/Rules.Framework.InMemory.Sample/Engine/RuleSpecification.cs index 5bae5f93..c569d868 100644 --- a/samples/Rules.Framework.InMemory.Sample/Engine/RuleSpecification.cs +++ b/samples/Rules.Framework.InMemory.Sample/Engine/RuleSpecification.cs @@ -8,6 +8,6 @@ internal class RuleSpecification { public RuleAddPriorityOption RuleAddPriorityOption { get; set; } - public RuleBuilderResult RuleBuilderResult { get; set; } + public RuleBuilderResult RuleBuilderResult { get; set; } } } \ No newline at end of file diff --git a/samples/Rules.Framework.InMemory.Sample/Engine/RulesBuilder.cs b/samples/Rules.Framework.InMemory.Sample/Engine/RulesBuilder.cs index 82d8bca7..2a0e6725 100644 --- a/samples/Rules.Framework.InMemory.Sample/Engine/RulesBuilder.cs +++ b/samples/Rules.Framework.InMemory.Sample/Engine/RulesBuilder.cs @@ -6,17 +6,20 @@ namespace Rules.Framework.InMemory.Sample.Engine internal class RulesBuilder { - private readonly IEnumerable contentTypes; + private readonly IEnumerable ruleSpecificationsRegistrars; - public RulesBuilder(IEnumerable contentTypes) => this.contentTypes = contentTypes; + public RulesBuilder(IEnumerable ruleSpecificationsProviders) => this.ruleSpecificationsRegistrars = ruleSpecificationsProviders; public async Task BuildAsync(IRulesEngine rulesEngine) { - foreach (var contentType in contentTypes) + foreach (var ruleSpecificationsProvider in ruleSpecificationsRegistrars) { - await rulesEngine.CreateContentTypeAsync(contentType.ContentType.ToString()); + foreach (var ruleset in ruleSpecificationsProvider.Rulesets) + { + await rulesEngine.CreateRulesetAsync(ruleset.ToString()); + } - var rulesSpecifications = contentType.GetRulesSpecifications(); + var rulesSpecifications = ruleSpecificationsProvider.GetRulesSpecifications(); foreach (var ruleSpecification in rulesSpecifications) { diff --git a/samples/Rules.Framework.InMemory.Sample/Engine/RulesService.cs b/samples/Rules.Framework.InMemory.Sample/Engine/RulesService.cs index f55db187..ce9d58f2 100644 --- a/samples/Rules.Framework.InMemory.Sample/Engine/RulesService.cs +++ b/samples/Rules.Framework.InMemory.Sample/Engine/RulesService.cs @@ -11,18 +11,18 @@ internal class RulesService { private readonly RulesEngineProvider rulesEngineProvider; - public RulesService(IEnumerable contentTypes) + public RulesService(IEnumerable ruleSpecificationsProviders) { - this.rulesEngineProvider = new RulesEngineProvider(new RulesBuilder(contentTypes)); + this.rulesEngineProvider = new RulesEngineProvider(new RulesBuilder(ruleSpecificationsProviders)); } public async Task MatchOneAsync( - ContentTypes contentType, + RulesetNames ruleset, DateTime dateTime, - IDictionary conditions) + IDictionary conditions) { - var rulesConditions = (conditions is null) ? new Condition[] { } : - conditions.Select(x => new Condition(x.Key, x.Value)) + var rulesConditions = (conditions is null) ? new Condition[] { } : + conditions.Select(x => new Condition(x.Key, x.Value)) .ToArray(); var rulesEngine = await @@ -31,13 +31,13 @@ public async Task MatchOneAsync( .ConfigureAwait(false); var match = await rulesEngine - .MakeGeneric() - .MatchOneAsync(contentType, dateTime, rulesConditions) + .MakeGeneric() + .MatchOneAsync(ruleset, dateTime, rulesConditions) .ConfigureAwait(false); if (match is null) { - var message = $"Error trying to match one rule. No rule was found {contentType} {dateTime} {string.Join(", ", conditions)}."; + var message = $"Error trying to match one rule. No rule was found {ruleset} {dateTime} {string.Join(", ", conditions)}."; throw new RulesNotFoundException(message); } diff --git a/samples/Rules.Framework.InMemory.Sample/Enums/ConditionTypes.cs b/samples/Rules.Framework.InMemory.Sample/Enums/ConditionNames.cs similarity index 57% rename from samples/Rules.Framework.InMemory.Sample/Enums/ConditionTypes.cs rename to samples/Rules.Framework.InMemory.Sample/Enums/ConditionNames.cs index cd020a5c..13110543 100644 --- a/samples/Rules.Framework.InMemory.Sample/Enums/ConditionTypes.cs +++ b/samples/Rules.Framework.InMemory.Sample/Enums/ConditionNames.cs @@ -1,29 +1,29 @@ namespace Rules.Framework.InMemory.Sample.Enums { - internal enum ConditionTypes + internal enum ConditionNames { /// - /// no condition type defined + /// no condition defined /// None = 0, /// - /// condition type to filter by royal numbers + /// condition to filter by royal numbers /// RoyalNumber = 1, /// - /// condition type to filter if the number can be divided by 3 + /// condition to filter if the number can be divided by 3 /// CanNumberBeDividedBy3 = 2, /// - /// condition type to filter if the number is prime + /// condition to filter if the number is prime /// IsPrimeNumber = 3, /// - /// condition type to filter number sums + /// condition to filter number sums /// SumAll = 4 } diff --git a/samples/Rules.Framework.InMemory.Sample/Enums/ContentTypes.cs b/samples/Rules.Framework.InMemory.Sample/Enums/RulesetNames.cs similarity index 57% rename from samples/Rules.Framework.InMemory.Sample/Enums/ContentTypes.cs rename to samples/Rules.Framework.InMemory.Sample/Enums/RulesetNames.cs index 4b4ee73c..b34981ee 100644 --- a/samples/Rules.Framework.InMemory.Sample/Enums/ContentTypes.cs +++ b/samples/Rules.Framework.InMemory.Sample/Enums/RulesetNames.cs @@ -1,11 +1,11 @@ namespace Rules.Framework.InMemory.Sample.Enums { - internal enum ContentTypes + internal enum RulesetNames { None = 0, /// - /// this content verifies if number is cool or not + /// this ruleset contains rules that verify if a number is cool or not /// TestNumber = 1, } diff --git a/samples/Rules.Framework.InMemory.Sample/Program.cs b/samples/Rules.Framework.InMemory.Sample/Program.cs index 7dced43a..002caeb8 100644 --- a/samples/Rules.Framework.InMemory.Sample/Program.cs +++ b/samples/Rules.Framework.InMemory.Sample/Program.cs @@ -3,6 +3,7 @@ namespace Rules.Framework.InMemory.Sample using System; using System.Collections.Generic; using System.Globalization; + using System.Threading.Tasks; using global::Rules.Framework.InMemory.Sample.Engine; using global::Rules.Framework.InMemory.Sample.Enums; using global::Rules.Framework.InMemory.Sample.Helper; @@ -10,9 +11,9 @@ namespace Rules.Framework.InMemory.Sample internal class Program { - private static void Main(string[] args) + private static async Task Main(string[] args) { - var rulesService = new RulesService(new List() + var rulesService = new RulesService(new List() { new TestNumberRules() }); @@ -31,18 +32,15 @@ private static void Main(string[] args) break; } - var conditions = new Dictionary { - { ConditionTypes.IsPrimeNumber, value.IsPrime() }, - { ConditionTypes.CanNumberBeDividedBy3, value.CanNumberBeDividedBy3() }, - { ConditionTypes.SumAll, value.SumAll() }, - { ConditionTypes.RoyalNumber, value } + var conditions = new Dictionary { + { ConditionNames.IsPrimeNumber, value.IsPrime() }, + { ConditionNames.CanNumberBeDividedBy3, value.CanNumberBeDividedBy3() }, + { ConditionNames.SumAll, value.SumAll() }, + { ConditionNames.RoyalNumber, value } }; - var result = rulesService - .MatchOneAsync(ContentTypes.TestNumber, targetDate, conditions) - .ConfigureAwait(false) - .GetAwaiter() - .GetResult(); + var result = await rulesService + .MatchOneAsync(RulesetNames.TestNumber, targetDate, conditions); Console.WriteLine($"The result is: {result}"); } diff --git a/samples/Rules.Framework.InMemory.Sample/Rules/TestNumberRules.cs b/samples/Rules.Framework.InMemory.Sample/Rules/TestNumberRules.cs index 5409f683..797b4377 100644 --- a/samples/Rules.Framework.InMemory.Sample/Rules/TestNumberRules.cs +++ b/samples/Rules.Framework.InMemory.Sample/Rules/TestNumberRules.cs @@ -6,7 +6,7 @@ namespace Rules.Framework.InMemory.Sample.Rules using global::Rules.Framework.InMemory.Sample.Engine; using global::Rules.Framework.InMemory.Sample.Enums; - internal class TestNumberRules : IContentTypes + internal class TestNumberRules : IRuleSpecificationsProvider { public readonly List rulesSpecifications; @@ -15,7 +15,7 @@ public TestNumberRules() this.rulesSpecifications = new List(); } - public ContentTypes ContentType => ContentTypes.TestNumber; + public RulesetNames[] Rulesets => new[] { RulesetNames.TestNumber, }; public IEnumerable GetRulesSpecifications() { @@ -27,7 +27,7 @@ public IEnumerable GetRulesSpecifications() } private void Add( - RuleBuilderResult rule, + RuleBuilderResult rule, RuleAddPriorityOption ruleAddPriorityOption) => rulesSpecifications.Add( new RuleSpecification { @@ -35,33 +35,33 @@ private void Add( RuleAddPriorityOption = ruleAddPriorityOption, }); - private RuleBuilderResult CreateDefaultRule() => Rule.New() - .WithName("Default rule for test number") - .WithContent(ContentTypes.TestNumber, ":| default nothing special about this number") - .WithDateBegin(new DateTime(2019, 01, 01)) + private RuleBuilderResult CreateDefaultRule() => Rule.Create("Default rule for test number") + .InRuleset(RulesetNames.TestNumber) + .SetContent(":| default nothing special about this number") + .Since(new DateTime(2019, 01, 01)) .Build(); - private RuleBuilderResult CreateRuleForCoolNumbers() => Rule.New() - .WithName("Rule for cool numbers") - .WithContent(ContentTypes.TestNumber, ":D this number is so COOL!") - .WithDateBegin(new DateTime(2019, 01, 01)) - .WithCondition(c => c - .Or(o => o - .Value(ConditionTypes.RoyalNumber, Operators.Equal, 7) - .And(a => a - .Value(ConditionTypes.IsPrimeNumber, Operators.Equal, 7) - .Value(ConditionTypes.SumAll, Operators.StartsWith, "5")))) + private RuleBuilderResult CreateRuleForCoolNumbers() => Rule.Create("Rule for cool numbers") + .InRuleset(RulesetNames.TestNumber) + .SetContent(":D this number is so COOL!") + .Since(new DateTime(2019, 01, 01)) + .ApplyWhen(c => c + .Or(o => o + .Value(ConditionNames.RoyalNumber, Operators.Equal, 7) + .And(a => a + .Value(ConditionNames.IsPrimeNumber, Operators.Equal, 7) + .Value(ConditionNames.SumAll, Operators.StartsWith, "5")))) .Build(); - private RuleBuilderResult CreateRuleForSosoNumbers() => Rule.New() - .WithName("Rule for so so numbers") - .WithContent(ContentTypes.TestNumber, ":) this number is so so") - .WithDateBegin(new DateTime(2019, 01, 01)) - .WithCondition(c => c + private RuleBuilderResult CreateRuleForSosoNumbers() => Rule.Create("Rule for so so numbers") + .InRuleset(RulesetNames.TestNumber) + .SetContent(":) this number is so so") + .Since(new DateTime(2019, 01, 01)) + .ApplyWhen(c => c .Or(o => o - .Value(ConditionTypes.CanNumberBeDividedBy3, Operators.Equal, true) - .Value(ConditionTypes.IsPrimeNumber, Operators.Equal, false) - .Value(ConditionTypes.SumAll, Operators.StartsWith, "9"))) + .Value(ConditionNames.CanNumberBeDividedBy3, Operators.Equal, true) + .Value(ConditionNames.IsPrimeNumber, Operators.Equal, false) + .Value(ConditionNames.SumAll, Operators.StartsWith, "9"))) .Build(); } } \ No newline at end of file diff --git a/samples/Rules.Framework.WebUI.Sample/Engine/IContentTypes.cs b/samples/Rules.Framework.WebUI.Sample/Engine/IRuleSpecificationsProvider.cs similarity index 70% rename from samples/Rules.Framework.WebUI.Sample/Engine/IContentTypes.cs rename to samples/Rules.Framework.WebUI.Sample/Engine/IRuleSpecificationsProvider.cs index 2d4f988f..bddfce3d 100644 --- a/samples/Rules.Framework.WebUI.Sample/Engine/IContentTypes.cs +++ b/samples/Rules.Framework.WebUI.Sample/Engine/IRuleSpecificationsProvider.cs @@ -3,9 +3,9 @@ namespace Rules.Framework.WebUI.Sample.Engine using System.Collections.Generic; using global::Rules.Framework.WebUI.Sample.Enums; - internal interface IContentTypes + internal interface IRuleSpecificationsProvider { - ContentTypes[] ContentTypes { get; } + RulesetNames[] Rulesets { get; } IEnumerable GetRulesSpecifications(); } diff --git a/samples/Rules.Framework.WebUI.Sample/Engine/RuleSpecification.cs b/samples/Rules.Framework.WebUI.Sample/Engine/RuleSpecification.cs index 84749d4b..b39d330d 100644 --- a/samples/Rules.Framework.WebUI.Sample/Engine/RuleSpecification.cs +++ b/samples/Rules.Framework.WebUI.Sample/Engine/RuleSpecification.cs @@ -4,10 +4,10 @@ namespace Rules.Framework.WebUI.Sample.Engine using global::Rules.Framework.Builder.Generic; using global::Rules.Framework.WebUI.Sample.Enums; - internal sealed class RuleSpecification : RuleSpecificationBase + internal sealed class RuleSpecification : RuleSpecificationBase { public RuleSpecification( - RuleBuilderResult ruleBuilderResult, + RuleBuilderResult ruleBuilderResult, RuleAddPriorityOption ruleAddPriorityOption) : base(ruleBuilderResult, ruleAddPriorityOption) { diff --git a/samples/Rules.Framework.WebUI.Sample/Engine/RulesBuilder.cs b/samples/Rules.Framework.WebUI.Sample/Engine/RulesBuilder.cs index d0587bdd..daba8249 100644 --- a/samples/Rules.Framework.WebUI.Sample/Engine/RulesBuilder.cs +++ b/samples/Rules.Framework.WebUI.Sample/Engine/RulesBuilder.cs @@ -6,20 +6,20 @@ namespace Rules.Framework.WebUI.Sample.Engine internal class RulesBuilder { - private readonly IEnumerable contentTypes; + private readonly IEnumerable ruleSpecificationsProviders; - public RulesBuilder(IEnumerable contentTypes) => this.contentTypes = contentTypes; + public RulesBuilder(IEnumerable ruleSpecificationsProviders) => this.ruleSpecificationsProviders = ruleSpecificationsProviders; public async Task BuildAsync(IRulesEngine rulesEngine) { - foreach (var contentType in contentTypes) + foreach (var ruleSpecificationsProvider in ruleSpecificationsProviders) { - foreach (var contentTypeValue in contentType.ContentTypes) + foreach (var ruleset in ruleSpecificationsProvider.Rulesets) { - await rulesEngine.CreateContentTypeAsync(contentTypeValue.ToString()); + await rulesEngine.CreateRulesetAsync(ruleset.ToString()); } - var rulesSpecifications = contentType.GetRulesSpecifications(); + var rulesSpecifications = ruleSpecificationsProvider.GetRulesSpecifications(); foreach (var ruleSpecification in rulesSpecifications) { diff --git a/samples/Rules.Framework.WebUI.Sample/Enums/ConditionTypes.cs b/samples/Rules.Framework.WebUI.Sample/Enums/ConditionNames.cs similarity index 57% rename from samples/Rules.Framework.WebUI.Sample/Enums/ConditionTypes.cs rename to samples/Rules.Framework.WebUI.Sample/Enums/ConditionNames.cs index 46b77fd0..0809506b 100644 --- a/samples/Rules.Framework.WebUI.Sample/Enums/ConditionTypes.cs +++ b/samples/Rules.Framework.WebUI.Sample/Enums/ConditionNames.cs @@ -1,29 +1,29 @@ namespace Rules.Framework.WebUI.Sample.Enums { - public enum ConditionTypes + public enum ConditionNames { /// - /// no condition type defined + /// no condition defined /// None = 0, /// - /// condition type to filter by royal numbers + /// condition to filter by royal numbers /// RoyalNumber = 1, /// - /// condition type to filter if the number can be divided by 3 + /// condition to filter if the number can be divided by 3 /// CanNumberBeDividedBy3 = 2, /// - /// condition type to filter if the number is prime + /// condition to filter if the number is prime /// IsPrimeNumber = 3, /// - /// condition type to filter number sums + /// condition to filter number sums /// SumAll = 4 } diff --git a/samples/Rules.Framework.WebUI.Sample/Enums/ContentTypes.cs b/samples/Rules.Framework.WebUI.Sample/Enums/RulesetNames.cs similarity index 89% rename from samples/Rules.Framework.WebUI.Sample/Enums/ContentTypes.cs rename to samples/Rules.Framework.WebUI.Sample/Enums/RulesetNames.cs index 78d10b65..f9df938b 100644 --- a/samples/Rules.Framework.WebUI.Sample/Enums/ContentTypes.cs +++ b/samples/Rules.Framework.WebUI.Sample/Enums/RulesetNames.cs @@ -1,6 +1,6 @@ namespace Rules.Framework.WebUI.Sample.Enums { - public enum ContentTypes + public enum RulesetNames { TestNumber = 0, @@ -18,4 +18,4 @@ public enum ContentTypes TestBlob = 7 } -} +} \ No newline at end of file diff --git a/samples/Rules.Framework.WebUI.Sample/Program.cs b/samples/Rules.Framework.WebUI.Sample/Program.cs index 7ccd9f3d..36e947dd 100644 --- a/samples/Rules.Framework.WebUI.Sample/Program.cs +++ b/samples/Rules.Framework.WebUI.Sample/Program.cs @@ -50,14 +50,13 @@ private static void AddRulesFrameworkUI(IApplicationBuilder app, bool useReadmeE return; } - var rulesProvider = new RulesEngineProvider(new RulesBuilder(new List() + var rulesProvider = new RulesEngineProvider(new RulesBuilder(new List() { new RulesRandomFactory() })); var rulesEngine = rulesProvider .GetRulesEngineAsync() - .ConfigureAwait(false) .GetAwaiter() .GetResult(); diff --git a/samples/Rules.Framework.WebUI.Sample/ReadmeExample/BasicConditionType.cs b/samples/Rules.Framework.WebUI.Sample/ReadmeExample/BasicConditionNames.cs similarity index 75% rename from samples/Rules.Framework.WebUI.Sample/ReadmeExample/BasicConditionType.cs rename to samples/Rules.Framework.WebUI.Sample/ReadmeExample/BasicConditionNames.cs index 34e83242..9adf2580 100644 --- a/samples/Rules.Framework.WebUI.Sample/ReadmeExample/BasicConditionType.cs +++ b/samples/Rules.Framework.WebUI.Sample/ReadmeExample/BasicConditionNames.cs @@ -1,6 +1,6 @@ namespace Rules.Framework.WebUI.Sample.ReadmeExample { - public enum BasicConditionType + public enum BasicConditionNames { ClientType = 1, Country = 2 diff --git a/samples/Rules.Framework.WebUI.Sample/ReadmeExample/BasicRulesEngineExample.cs b/samples/Rules.Framework.WebUI.Sample/ReadmeExample/BasicRulesEngineExample.cs index 47f0f912..38a8ae4f 100644 --- a/samples/Rules.Framework.WebUI.Sample/ReadmeExample/BasicRulesEngineExample.cs +++ b/samples/Rules.Framework.WebUI.Sample/ReadmeExample/BasicRulesEngineExample.cs @@ -2,6 +2,7 @@ namespace Rules.Framework.WebUI.Sample.ReadmeExample { using System; using global::Rules.Framework.WebUI.Sample.Engine; + using global::Rules.Framework.WebUI.Sample.Enums; internal class BasicRulesEngineExample { @@ -13,6 +14,8 @@ public BasicRulesEngineExample() .Configure(c => c.PriorityCriteria = PriorityCriterias.TopmostRuleWins) .Build(); + this.CreateRulesets(); + var rules = this.CreateRules(); this.AddRules(rules); @@ -20,47 +23,58 @@ public BasicRulesEngineExample() public IRulesEngine RulesEngine { get; } - protected void AddRules(IEnumerable> ruleSpecifications) + protected void AddRules(IEnumerable> ruleSpecifications) { foreach (var ruleSpecification in ruleSpecifications) { this.RulesEngine.AddRuleAsync(ruleSpecification.RuleBuilderResult.Rule, ruleSpecification.RuleAddPriorityOption) - .ConfigureAwait(false) .GetAwaiter() .GetResult(); } } - private IEnumerable> CreateRules() + protected void CreateRulesets() + { + foreach (var rulesetName in Enum.GetValues()) + { + this.RulesEngine.CreateRulesetAsync(rulesetName.ToString()) + .GetAwaiter() + .GetResult(); + } + } + + private IEnumerable> CreateRules() { - var ruleForPremiumFreeSampleJanuary = Rule.New() - .WithName("Rule for January sample for premium clients.") - .WithContent(BasicContentType.FreeSample, "SmallPerfumeSample") - .WithCondition(BasicConditionType.ClientType, Operators.Equal, "Premium") - .WithDatesInterval(new DateTime(2023, 01, 01), new DateTime(2023, 02, 01)) + var ruleForPremiumFreeSampleJanuary = Rule.Create("Rule for January sample for premium clients.") + .InRuleset(BasicRulesetNames.FreeSample) + .SetContent("SmallPerfumeSample") + .Since(new DateTime(2023, 01, 01)) + .Until(new DateTime(2023, 02, 01)) + .ApplyWhen(BasicConditionNames.ClientType, Operators.Equal, "Premium") .Build(); - var ruleForPremiumFreeSampleApril = Rule.New() - .WithName("Rule for April sample for premium clients.") - .WithContent(BasicContentType.FreeSample, "ShampooSample") - .WithCondition(BasicConditionType.ClientType, Operators.Equal, "Premium") - .WithDatesInterval(new DateTime(2023, 04, 01), new DateTime(2023, 05, 01)) + var ruleForPremiumFreeSampleApril = Rule.Create("Rule for April sample for premium clients.") + .InRuleset(BasicRulesetNames.FreeSample) + .SetContent("ShampooSample") + .Since(new DateTime(2023, 04, 01)) + .Until(new DateTime(2023, 05, 01)) + .ApplyWhen(BasicConditionNames.ClientType, Operators.Equal, "Premium") .Build(); - var ruleForPremiumFreeSampleSeptember = Rule.New() - .WithName("Rule for September sample for premium clients.") - .WithContent(BasicContentType.FreeSample, "ConditionerSample") - .WithCondition(BasicConditionType.ClientType, Operators.Equal, "Premium") - .WithDatesInterval(new DateTime(2023, 09, 01), new DateTime(2023, 10, 01)) + var ruleForPremiumFreeSampleSeptember = Rule.Create("Rule for September sample for premium clients.") + .InRuleset(BasicRulesetNames.FreeSample) + .SetContent("ConditionerSample") + .Since(new DateTime(2023, 09, 01)).Until(new DateTime(2023, 10, 01)) + .ApplyWhen(BasicConditionNames.ClientType, Operators.Equal, "Premium") .Build(); - return new List>() + return new List>() { - new RuleSpecificationBase( + new RuleSpecificationBase( ruleForPremiumFreeSampleJanuary, RuleAddPriorityOption.ByPriorityNumber(1)), - new RuleSpecificationBase( + new RuleSpecificationBase( ruleForPremiumFreeSampleApril, RuleAddPriorityOption.ByPriorityNumber(2)), - new RuleSpecificationBase( + new RuleSpecificationBase( ruleForPremiumFreeSampleSeptember, RuleAddPriorityOption.ByPriorityNumber(3)) }; } diff --git a/samples/Rules.Framework.WebUI.Sample/ReadmeExample/BasicContentType.cs b/samples/Rules.Framework.WebUI.Sample/ReadmeExample/BasicRulesetNames.cs similarity index 77% rename from samples/Rules.Framework.WebUI.Sample/ReadmeExample/BasicContentType.cs rename to samples/Rules.Framework.WebUI.Sample/ReadmeExample/BasicRulesetNames.cs index 891e6bec..495c47d7 100644 --- a/samples/Rules.Framework.WebUI.Sample/ReadmeExample/BasicContentType.cs +++ b/samples/Rules.Framework.WebUI.Sample/ReadmeExample/BasicRulesetNames.cs @@ -1,6 +1,6 @@ namespace Rules.Framework.WebUI.Sample.ReadmeExample { - public enum BasicContentType + public enum BasicRulesetNames { FreeSample = 1, ShippingCost = 2 diff --git a/samples/Rules.Framework.WebUI.Sample/Rules/RulesRandomFactory.cs b/samples/Rules.Framework.WebUI.Sample/Rules/RulesRandomFactory.cs index de6c24c0..7e41098b 100644 --- a/samples/Rules.Framework.WebUI.Sample/Rules/RulesRandomFactory.cs +++ b/samples/Rules.Framework.WebUI.Sample/Rules/RulesRandomFactory.cs @@ -6,7 +6,7 @@ namespace Rules.Framework.WebUI.Sample.Rules using global::Rules.Framework.WebUI.Sample.Engine; using global::Rules.Framework.WebUI.Sample.Enums; - internal class RulesRandomFactory : IContentTypes + internal class RulesRandomFactory : IRuleSpecificationsProvider { private readonly int finalNumber = 50; private readonly int intialNumber = 10; @@ -17,16 +17,16 @@ public RulesRandomFactory() this.random = new Random(); } - public ContentTypes[] ContentTypes => new[] + public RulesetNames[] Rulesets => new[] { - Enums.ContentTypes.TestDateTime, - Enums.ContentTypes.TestDecimal, - Enums.ContentTypes.TestLong, - Enums.ContentTypes.TestBoolean, - Enums.ContentTypes.TestShort, - Enums.ContentTypes.TestNumber, - Enums.ContentTypes.TestString, - Enums.ContentTypes.TestBlob, + RulesetNames.TestDateTime, + RulesetNames.TestDecimal, + RulesetNames.TestLong, + RulesetNames.TestBoolean, + RulesetNames.TestShort, + RulesetNames.TestNumber, + RulesetNames.TestString, + RulesetNames.TestBlob, }; public IEnumerable GetRulesSpecifications() @@ -34,20 +34,20 @@ public IEnumerable GetRulesSpecifications() var currentYear = DateTime.UtcNow.Year; var rulesSpecifications = new List(); - foreach (var contentType in Enum.GetValues(typeof(ContentTypes))) + foreach (var ruleset in Enum.GetValues(typeof(RulesetNames)).Cast()) { for (var i = 1; i < random.Next(intialNumber, finalNumber); i++) { var dateBegin = CreateRandomDateBegin(currentYear); - Add(CreateMultipleRule((ContentTypes)contentType, i, dateBegin, CreateRandomDateEnd(dateBegin)), + Add(CreateMultipleRule(ruleset, i, dateBegin, CreateRandomDateEnd(dateBegin)), RuleAddPriorityOption.ByPriorityNumber(i), rulesSpecifications); } var deactiveDateBegin = CreateRandomDateBegin(currentYear); - Add(CreateMultipleRule((ContentTypes)contentType, finalNumber, deactiveDateBegin, CreateRandomDateEnd(deactiveDateBegin), isActive: false), + Add(CreateMultipleRule(ruleset, finalNumber, deactiveDateBegin, CreateRandomDateEnd(deactiveDateBegin), isActive: false), RuleAddPriorityOption.ByPriorityNumber(finalNumber), rulesSpecifications); } @@ -55,37 +55,38 @@ public IEnumerable GetRulesSpecifications() return rulesSpecifications; } - private static RuleBuilderResult CreateMultipleRule( - ContentTypes contentTypes, + private static RuleBuilderResult CreateMultipleRule( + RulesetNames ruleset, int value, DateTime dateBegin, DateTime? dateEnd, - bool isActive = true) => Rule.New() - .WithName($"Multi rule for test {contentTypes} {value}") - .WithContent(contentTypes, new { Value = value }) - .WithDatesInterval(dateBegin, dateEnd) + bool isActive = true) => Rule.Create($"Multi rule for test {ruleset} {value}") + .InRuleset(ruleset) + .SetContent(new { Value = value }) + .Since(dateBegin) + .Until(dateEnd) .WithActive(isActive) - .WithCondition(rootCond => rootCond + .ApplyWhen(rootCond => rootCond .Or(o => o - .Value(ConditionTypes.RoyalNumber, Operators.Equal, 7) - .Value(ConditionTypes.SumAll, Operators.In, new int[] { 9, 8, 6 }) + .Value(ConditionNames.RoyalNumber, Operators.Equal, 7) + .Value(ConditionNames.SumAll, Operators.In, new int[] { 9, 8, 6 }) .And(a => a - .Value(ConditionTypes.IsPrimeNumber, Operators.Equal, false) - .Value(ConditionTypes.SumAll, Operators.StartsWith, "15") + .Value(ConditionNames.IsPrimeNumber, Operators.Equal, false) + .Value(ConditionNames.SumAll, Operators.StartsWith, "15") ) .And(a => a - .Value(ConditionTypes.CanNumberBeDividedBy3, Operators.Equal, false) - .Value(ConditionTypes.SumAll, Operators.NotEqual, string.Empty) + .Value(ConditionNames.CanNumberBeDividedBy3, Operators.Equal, false) + .Value(ConditionNames.SumAll, Operators.NotEqual, string.Empty) ) .And(a => a - .Value(ConditionTypes.IsPrimeNumber, Operators.Equal, true) - .Value(ConditionTypes.SumAll, Operators.StartsWith, "5") - .Value(ConditionTypes.CanNumberBeDividedBy3, Operators.Equal, false) + .Value(ConditionNames.IsPrimeNumber, Operators.Equal, true) + .Value(ConditionNames.SumAll, Operators.StartsWith, "5") + .Value(ConditionNames.CanNumberBeDividedBy3, Operators.Equal, false) ))) .Build(); private void Add( - RuleBuilderResult rule, + RuleBuilderResult rule, RuleAddPriorityOption ruleAddPriorityOption, List rulesSpecifications) => rulesSpecifications.Add(new RuleSpecification(rule, ruleAddPriorityOption)); diff --git a/src/Rules.Framework.Providers.MongoDb/DataModel/RuleDataModel.cs b/src/Rules.Framework.Providers.MongoDb/DataModel/RuleDataModel.cs index 25f4078b..6042d3c5 100644 --- a/src/Rules.Framework.Providers.MongoDb/DataModel/RuleDataModel.cs +++ b/src/Rules.Framework.Providers.MongoDb/DataModel/RuleDataModel.cs @@ -11,9 +11,6 @@ internal sealed class RuleDataModel [BsonElement(Order = 7)] public dynamic Content { get; set; } - [BsonElement(Order = 2)] - public string ContentType { get; set; } - [BsonElement(Order = 3)] public DateTime DateBegin { get; set; } @@ -28,5 +25,8 @@ internal sealed class RuleDataModel [BsonElement(Order = 6)] public ConditionNodeDataModel RootCondition { get; set; } + + [BsonElement(Order = 2)] + public string Ruleset { get; set; } } } \ No newline at end of file diff --git a/src/Rules.Framework.Providers.MongoDb/DataModel/ContentTypeDataModel.cs b/src/Rules.Framework.Providers.MongoDb/DataModel/RulesetDataModel.cs similarity index 90% rename from src/Rules.Framework.Providers.MongoDb/DataModel/ContentTypeDataModel.cs rename to src/Rules.Framework.Providers.MongoDb/DataModel/RulesetDataModel.cs index b185b3c6..3e300b81 100644 --- a/src/Rules.Framework.Providers.MongoDb/DataModel/ContentTypeDataModel.cs +++ b/src/Rules.Framework.Providers.MongoDb/DataModel/RulesetDataModel.cs @@ -3,7 +3,7 @@ namespace Rules.Framework.Providers.MongoDb.DataModel using System; using MongoDB.Bson.Serialization.Attributes; - internal class ContentTypeDataModel + internal class RulesetDataModel { [BsonElement("creation", Order = 3)] public DateTime Creation { get; set; } diff --git a/src/Rules.Framework.Providers.MongoDb/DataModel/ValueConditionNodeDataModel.cs b/src/Rules.Framework.Providers.MongoDb/DataModel/ValueConditionNodeDataModel.cs index 05853a12..84b4c683 100644 --- a/src/Rules.Framework.Providers.MongoDb/DataModel/ValueConditionNodeDataModel.cs +++ b/src/Rules.Framework.Providers.MongoDb/DataModel/ValueConditionNodeDataModel.cs @@ -7,17 +7,17 @@ namespace Rules.Framework.Providers.MongoDb.DataModel internal sealed class ValueConditionNodeDataModel : ConditionNodeDataModel { [BsonElement(Order = 1)] - public string ConditionType { get; set; } + public string Condition { get; set; } [BsonElement(Order = 2)] [BsonRepresentation(MongoDB.Bson.BsonType.String)] public DataTypes DataType { get; set; } - - [BsonElement(Order = 3)] - [BsonRepresentation(MongoDB.Bson.BsonType.String)] - public Operators Operator { get; set; } [BsonElement(Order = 4)] public object Operand { get; set; } + + [BsonElement(Order = 3)] + [BsonRepresentation(MongoDB.Bson.BsonType.String)] + public Operators Operator { get; set; } } } \ No newline at end of file diff --git a/src/Rules.Framework.Providers.MongoDb/MongoDbProviderRulesDataSource.cs b/src/Rules.Framework.Providers.MongoDb/MongoDbProviderRulesDataSource.cs index f027618f..a69eb0c3 100644 --- a/src/Rules.Framework.Providers.MongoDb/MongoDbProviderRulesDataSource.cs +++ b/src/Rules.Framework.Providers.MongoDb/MongoDbProviderRulesDataSource.cs @@ -46,55 +46,37 @@ public async Task AddRuleAsync(Rule rule) } /// - /// Creates a new content type on the data source. + /// Creates a new ruleset on the data source. /// /// Type of the content. - public async Task CreateContentTypeAsync(string contentType) + public async Task CreateRulesetAsync(string contentType) { - var contentTypesCollection = this.mongoDatabase.GetCollection(this.mongoDbProviderSettings.ContentTypesCollectionName); + var rulesetsCollection = this.mongoDatabase.GetCollection(this.mongoDbProviderSettings.RulesetsCollectionName); - var contentTypeDataModel = new ContentTypeDataModel + var rulesetDataModel = new RulesetDataModel { Creation = DateTime.UtcNow, Id = Guid.NewGuid(), Name = contentType, }; - await contentTypesCollection.InsertOneAsync(contentTypeDataModel).ConfigureAwait(false); + await rulesetsCollection.InsertOneAsync(rulesetDataModel).ConfigureAwait(false); } /// - /// Gets the content types from the data source. - /// - /// - public async Task> GetContentTypesAsync() - { - var contentTypesCollection = this.mongoDatabase.GetCollection(this.mongoDbProviderSettings.ContentTypesCollectionName); - - var findAllFilterDefinition = FilterDefinition.Empty; - var findOptions = new FindOptions - { - Projection = Builders.Projection.Expression(x => x.Name), - }; - - var resultsCursor = await contentTypesCollection.FindAsync(findAllFilterDefinition, findOptions).ConfigureAwait(false); - return await resultsCursor.ToListAsync().ConfigureAwait(false); - } - - /// - /// Gets the rules categorized with specified between - /// and . + /// Gets the rules categorized with specified between and . /// - /// the content type categorization. + /// the ruleset name. /// the filtering begin date. /// the filtering end date. /// - public async Task> GetRulesAsync(string contentType, DateTime dateBegin, DateTime dateEnd) + public async Task> GetRulesAsync(string ruleset, DateTime dateBegin, DateTime dateEnd) { - var getRulesByContentTypeAndDatesInterval = MongoDbProviderRulesDataSource - .BuildFilterByContentTypeAndDatesInterval(contentType, dateBegin, dateEnd); + var getRulesByRulesetAndDatesInterval = MongoDbProviderRulesDataSource + .BuildFilterByContentTypeAndDatesInterval(ruleset, dateBegin, dateEnd); - return await this.GetRulesAsync(getRulesByContentTypeAndDatesInterval).ConfigureAwait(false); + return await this.GetRulesAsync(getRulesByRulesetAndDatesInterval).ConfigureAwait(false); } /// @@ -115,6 +97,29 @@ public Task> GetRulesByAsync(RulesFilterArgs rulesFilterArgs) return this.GetRulesAsync(filterDefinition); } + /// + /// Gets the content types from the data source. + /// + /// + public async Task> GetRulesetsAsync() + { + var rulesetsCollection = this.mongoDatabase.GetCollection(this.mongoDbProviderSettings.RulesetsCollectionName); + + var findAllFilterDefinition = FilterDefinition.Empty; + + var resultsCursor = await rulesetsCollection.FindAsync(findAllFilterDefinition).ConfigureAwait(false); + var rulesets = new List(); + while (await resultsCursor.MoveNextAsync().ConfigureAwait(false)) + { + foreach (var rulesetDataModel in resultsCursor.Current) + { + rulesets.Add(new Ruleset(rulesetDataModel.Name, rulesetDataModel.Creation)); + } + } + + return rulesets; + } + /// /// Updates the existent rule on data source. /// @@ -130,7 +135,7 @@ public async Task UpdateRuleAsync(Rule rule) var updateDefinitions = new UpdateDefinition[] { Builders.Update.Set(contentField, (object)ruleDataModel.Content), - Builders.Update.Set(r => r.ContentType, ruleDataModel.ContentType), + Builders.Update.Set(r => r.Ruleset, ruleDataModel.Ruleset), Builders.Update.Set(r => r.DateBegin, ruleDataModel.DateBegin), Builders.Update.Set(r => r.DateEnd, ruleDataModel.DateEnd), Builders.Update.Set(r => r.Name, ruleDataModel.Name), @@ -144,9 +149,9 @@ public async Task UpdateRuleAsync(Rule rule) await rulesCollection.UpdateOneAsync(filterDefinition, updateDefinition).ConfigureAwait(false); } - private static FilterDefinition BuildFilterByContentTypeAndDatesInterval(string contentType, DateTime dateBegin, DateTime dateEnd) + private static FilterDefinition BuildFilterByContentTypeAndDatesInterval(string ruleset, DateTime dateBegin, DateTime dateEnd) { - var contentTypeFilter = Builders.Filter.Eq(x => x.ContentType, contentType); + var rulesetFilter = Builders.Filter.Eq(x => x.Ruleset, ruleset); var datesFilter = Builders.Filter.And( Builders.Filter.Lte(rule => rule.DateBegin, dateEnd), @@ -155,16 +160,16 @@ private static FilterDefinition BuildFilterByContentTypeAndDatesI Builders.Filter.Eq(rule => rule.DateEnd, null)) ); - return Builders.Filter.And(contentTypeFilter, datesFilter); + return Builders.Filter.And(rulesetFilter, datesFilter); } private static FilterDefinition BuildFilterFromRulesFilterArgs(RulesFilterArgs rulesFilterArgs) { var filtersToApply = new List>(3); - if (!object.Equals(rulesFilterArgs.ContentType, default(string))) + if (!object.Equals(rulesFilterArgs.Ruleset, default(string))) { - filtersToApply.Add(Builders.Filter.Eq(x => x.ContentType, rulesFilterArgs.ContentType)); + filtersToApply.Add(Builders.Filter.Eq(x => x.Ruleset, rulesFilterArgs.Ruleset)); } if (!string.IsNullOrWhiteSpace(rulesFilterArgs.Name)) diff --git a/src/Rules.Framework.Providers.MongoDb/MongoDbProviderSettings.cs b/src/Rules.Framework.Providers.MongoDb/MongoDbProviderSettings.cs index 4d4075e8..1a0be271 100644 --- a/src/Rules.Framework.Providers.MongoDb/MongoDbProviderSettings.cs +++ b/src/Rules.Framework.Providers.MongoDb/MongoDbProviderSettings.cs @@ -5,22 +5,16 @@ namespace Rules.Framework.Providers.MongoDb /// public class MongoDbProviderSettings { - private const string DefaultContentTypesCollectionName = "content_types"; + private const string DefaultRulesetsCollectionName = "rulesets"; /// /// Initializes a new instance of the class. /// public MongoDbProviderSettings() { - this.ContentTypesCollectionName = DefaultContentTypesCollectionName; + this.RulesetsCollectionName = DefaultRulesetsCollectionName; } - /// - /// Gets or sets the name of the content types collection. - /// - /// The name of the content types collection. - public string ContentTypesCollectionName { get; set; } - /// /// Gets or sets the name of the database. /// @@ -32,5 +26,11 @@ public MongoDbProviderSettings() /// /// The name of the rules collection. public string RulesCollectionName { get; set; } + + /// + /// Gets or sets the name of the rulesets collection. + /// + /// The name of the content types collection. + public string RulesetsCollectionName { get; set; } } } \ No newline at end of file diff --git a/src/Rules.Framework.Providers.MongoDb/MongoDbRulesDataSourceInitializer.cs b/src/Rules.Framework.Providers.MongoDb/MongoDbRulesDataSourceInitializer.cs index 5850611f..1fb83f7a 100644 --- a/src/Rules.Framework.Providers.MongoDb/MongoDbRulesDataSourceInitializer.cs +++ b/src/Rules.Framework.Providers.MongoDb/MongoDbRulesDataSourceInitializer.cs @@ -34,27 +34,49 @@ public static async Task InitializeAsync(IMongoClient mongoClient, MongoDbProvid WriteConcern = WriteConcern.Acknowledged, }); - await CreateRulesCollectionIfNotExists(mongoDatabase, mongoDbProviderSettings).ConfigureAwait(false); - - var rulesCollection = mongoDatabase.GetCollection(mongoDbProviderSettings.RulesCollectionName); - - await CreateIndexesIfNotExists(rulesCollection, mongoDbProviderSettings).ConfigureAwait(false); + await CreateCollectionsIfNotExists(mongoDatabase, mongoDbProviderSettings).ConfigureAwait(false); + await CreateIndexesIfNotExists(mongoDatabase, mongoDbProviderSettings).ConfigureAwait(false); // Mark as initialized as this initialization code is never run anymore throughout the // app lifecycle. isInitialized = true; } - private static async Task CreateIndexesIfNotExists(IMongoCollection rulesCollection, MongoDbProviderSettings mongoDbProviderSettings) + private static async Task CreateCollectionsIfNotExists(IMongoDatabase mongoDatabase, MongoDbProviderSettings mongoDbProviderSettings) { - var getRulesIndex = $"ix_{mongoDbProviderSettings.RulesCollectionName.ToLower(CultureInfo.InvariantCulture)}_get_rules"; - var getRulesIndexKeysDefinition = Builders.IndexKeys - .Ascending("ContentType").Ascending("DateBegin").Ascending("DateEnd"); - await CreateIndexOnBackgroundAsync(rulesCollection, getRulesIndex, getRulesIndexKeysDefinition).ConfigureAwait(false); - var getRulesByIndex = $"ix_{mongoDbProviderSettings.RulesCollectionName.ToLower(CultureInfo.InvariantCulture)}_get_rules_by"; - var getRulesByIndexKeysDefinition = Builders.IndexKeys - .Ascending("ContentType").Ascending("Name").Ascending("Priority"); - await CreateIndexOnBackgroundAsync(rulesCollection, getRulesByIndex, getRulesByIndexKeysDefinition).ConfigureAwait(false); + var collectionsCursor = await mongoDatabase.ListCollectionNamesAsync().ConfigureAwait(false); + var collections = await collectionsCursor.ToListAsync().ConfigureAwait(false); + + if (!collections.Contains(mongoDbProviderSettings.RulesetsCollectionName)) + { + await mongoDatabase.CreateCollectionAsync(mongoDbProviderSettings.RulesetsCollectionName).ConfigureAwait(false); + } + + if (!collections.Contains(mongoDbProviderSettings.RulesCollectionName)) + { + await mongoDatabase.CreateCollectionAsync(mongoDbProviderSettings.RulesCollectionName).ConfigureAwait(false); + } + } + + private static async Task CreateIndexesIfNotExists(IMongoDatabase mongoDatabase, MongoDbProviderSettings mongoDbProviderSettings) + { + var rulesetsCollection = mongoDatabase.GetCollection(mongoDbProviderSettings.RulesetsCollectionName); + var rulesCollection = mongoDatabase.GetCollection(mongoDbProviderSettings.RulesCollectionName); + + var rulesetsByNameIndexName = $"ix_{mongoDbProviderSettings.RulesetsCollectionName.ToLower(CultureInfo.InvariantCulture)}_rulesets_by_name"; + var rulesetsByNameIndexKeys = Builders.IndexKeys + .Ascending(x => x.Name); + await CreateIndexOnBackgroundAsync(rulesetsCollection, rulesetsByNameIndexName, rulesetsByNameIndexKeys).ConfigureAwait(false); + + var rulesByRulesetAndDatesIndexName = $"ix_{mongoDbProviderSettings.RulesCollectionName.ToLower(CultureInfo.InvariantCulture)}_rules_by_ruleset_and_dates"; + var rulesByRulesetAndDatesIndexKeys = Builders.IndexKeys + .Ascending(x => x.Ruleset).Ascending(x => x.DateBegin).Ascending(x => x.DateEnd); + await CreateIndexOnBackgroundAsync(rulesCollection, rulesByRulesetAndDatesIndexName, rulesByRulesetAndDatesIndexKeys).ConfigureAwait(false); + + var rulesByRulesetNamePriorityIndexName = $"ix_{mongoDbProviderSettings.RulesCollectionName.ToLower(CultureInfo.InvariantCulture)}_rules_by_ruleset_name_priority"; + var rulesByRulesetNamePriorityIndexKeys = Builders.IndexKeys + .Ascending(x => x.Ruleset).Ascending(x => x.Name).Ascending(x => x.Priority); + await CreateIndexOnBackgroundAsync(rulesCollection, rulesByRulesetNamePriorityIndexName, rulesByRulesetNamePriorityIndexKeys).ConfigureAwait(false); } private static async Task CreateIndexOnBackgroundAsync(IMongoCollection mongoCollection, string indexName, IndexKeysDefinition indexKeysDefinition) @@ -67,15 +89,5 @@ private static async Task CreateIndexOnBackgroundAsync(IMongoCollection mo var createIndexModel = new CreateIndexModel(indexKeysDefinition, createIndexOptions); _ = await mongoCollection.Indexes.CreateOneAsync(createIndexModel).ConfigureAwait(false); } - - private static async Task CreateRulesCollectionIfNotExists(IMongoDatabase mongoDatabase, MongoDbProviderSettings mongoDbProviderSettings) - { - var collectionsCursor = await mongoDatabase.ListCollectionNamesAsync().ConfigureAwait(false); - var collections = await collectionsCursor.ToListAsync().ConfigureAwait(false); - if (!collections.Contains(mongoDbProviderSettings.RulesCollectionName)) - { - await mongoDatabase.CreateCollectionAsync(mongoDbProviderSettings.RulesCollectionName).ConfigureAwait(false); - } - } } } \ No newline at end of file diff --git a/src/Rules.Framework.Providers.MongoDb/MongoDbRulesDataSourceSelectorExtensions.cs b/src/Rules.Framework.Providers.MongoDb/MongoDbRulesDataSourceSelectorExtensions.cs index 4a2c0a2c..641b59f6 100644 --- a/src/Rules.Framework.Providers.MongoDb/MongoDbRulesDataSourceSelectorExtensions.cs +++ b/src/Rules.Framework.Providers.MongoDb/MongoDbRulesDataSourceSelectorExtensions.cs @@ -14,8 +14,6 @@ public static class MongoDbRulesDataSourceSelectorExtensions /// /// Sets the rules engine data source from a Mongo DB database. /// - /// The type of the content type. - /// The type of the condition type. /// The rules data source selector. /// The mongo client. /// The mongo database provider settings. diff --git a/src/Rules.Framework.Providers.MongoDb/RuleFactory.cs b/src/Rules.Framework.Providers.MongoDb/RuleFactory.cs index d6e6f94b..6083aa5f 100644 --- a/src/Rules.Framework.Providers.MongoDb/RuleFactory.cs +++ b/src/Rules.Framework.Providers.MongoDb/RuleFactory.cs @@ -24,12 +24,13 @@ public Rule CreateRule(RuleDataModel ruleDataModel) throw new ArgumentNullException(nameof(ruleDataModel)); } - var ruleBuilderResult = Rule.New() - .WithName(ruleDataModel.Name) - .WithDatesInterval(ruleDataModel.DateBegin, ruleDataModel.DateEnd) + var ruleBuilderResult = Rule.Create(ruleDataModel.Name) + .InRuleset(ruleDataModel.Ruleset) + .SetContent((object)ruleDataModel.Content, this.contentSerializationProvider) + .Since(ruleDataModel.DateBegin) + .Until(ruleDataModel.DateEnd) .WithActive(ruleDataModel.Active ?? true) - .WithCondition(_ => ruleDataModel.RootCondition is { } ? ConvertConditionNode(ruleDataModel.RootCondition) : null) - .WithSerializedContent(ruleDataModel.ContentType, (object)ruleDataModel.Content, this.contentSerializationProvider) + .ApplyWhen(_ => ruleDataModel.RootCondition is { } ? ConvertConditionNode(ruleDataModel.RootCondition) : null) .Build(); if (!ruleBuilderResult.IsSuccess) @@ -57,18 +58,18 @@ public RuleDataModel CreateRule(Rule rule) } var content = rule.ContentContainer.GetContentAs(); - var serializedContent = this.contentSerializationProvider.GetContentSerializer(rule.ContentType).Serialize(content); + var serializedContent = this.contentSerializationProvider.GetContentSerializer(rule.Ruleset).Serialize(content); var ruleDataModel = new RuleDataModel { + Active = rule.Active, Content = serializedContent, - ContentType = rule.ContentType, DateBegin = rule.DateBegin, DateEnd = rule.DateEnd, Name = rule.Name, Priority = rule.Priority, - Active = rule.Active, RootCondition = rule.RootCondition is { } ? ConvertConditionNode(rule.RootCondition) : null, + Ruleset = rule.Ruleset, }; return ruleDataModel; @@ -107,7 +108,7 @@ private static ValueConditionNodeDataModel ConvertValueConditionNode(ValueCondit return new ValueConditionNodeDataModel { - ConditionType = Convert.ToString(valueConditionNode.ConditionType, CultureInfo.InvariantCulture), + Condition = Convert.ToString(valueConditionNode.Condition, CultureInfo.InvariantCulture), LogicalOperator = LogicalOperators.Eval, DataType = valueConditionNode.DataType, Operand = valueConditionNode.Operand, @@ -130,7 +131,7 @@ private static ValueConditionNode CreateValueConditionNode(ValueConditionNodeDat var valueConditionNode = new ValueConditionNode( conditionNodeDataModel.DataType, - conditionNodeDataModel.ConditionType, + conditionNodeDataModel.Condition, conditionNodeDataModel.Operator, operand); diff --git a/src/Rules.Framework.WebUI/Dto/RuleDto.cs b/src/Rules.Framework.WebUI/Dto/RuleDto.cs index 24ae31c6..a122b80b 100644 --- a/src/Rules.Framework.WebUI/Dto/RuleDto.cs +++ b/src/Rules.Framework.WebUI/Dto/RuleDto.cs @@ -3,12 +3,12 @@ namespace Rules.Framework.WebUI.Dto internal sealed class RuleDto { public ConditionNodeDto Conditions { get; internal set; } - public string ContentType { get; internal set; } public string DateBegin { get; internal set; } public string DateEnd { get; internal set; } public string Name { get; internal set; } public int? Priority { get; internal set; } + public string Ruleset { get; internal set; } public string Status { get; internal set; } public object Value { get; internal set; } } -} +} \ No newline at end of file diff --git a/src/Rules.Framework.WebUI/Dto/FilterDto.cs b/src/Rules.Framework.WebUI/Dto/RulesFilterDto.cs similarity index 87% rename from src/Rules.Framework.WebUI/Dto/FilterDto.cs rename to src/Rules.Framework.WebUI/Dto/RulesFilterDto.cs index f90eb976..98fbed29 100644 --- a/src/Rules.Framework.WebUI/Dto/FilterDto.cs +++ b/src/Rules.Framework.WebUI/Dto/RulesFilterDto.cs @@ -5,10 +5,10 @@ namespace Rules.Framework.WebUI.Dto internal sealed class RulesFilterDto { public string Content { get; set; } - public string ContentType { get; set; } public DateTime? DateBegin { get; set; } public DateTime? DateEnd { get; set; } public string Name { get; set; } + public string Ruleset { get; set; } public RuleStatusDto? Status { get; set; } } -} +} \ No newline at end of file diff --git a/src/Rules.Framework.WebUI/Dto/ContentTypeDto.cs b/src/Rules.Framework.WebUI/Dto/RulesetDto.cs similarity index 86% rename from src/Rules.Framework.WebUI/Dto/ContentTypeDto.cs rename to src/Rules.Framework.WebUI/Dto/RulesetDto.cs index 6b4af554..d92ea633 100644 --- a/src/Rules.Framework.WebUI/Dto/ContentTypeDto.cs +++ b/src/Rules.Framework.WebUI/Dto/RulesetDto.cs @@ -1,6 +1,6 @@ namespace Rules.Framework.WebUI.Dto { - internal sealed class ContentTypeDto + internal sealed class RulesetDto { public int Index { get; internal set; } public int ActiveRulesCount { get; internal set; } diff --git a/src/Rules.Framework.WebUI/Dto/ValueConditionNodeDto.cs b/src/Rules.Framework.WebUI/Dto/ValueConditionNodeDto.cs index 7c9e3f8d..46d67539 100644 --- a/src/Rules.Framework.WebUI/Dto/ValueConditionNodeDto.cs +++ b/src/Rules.Framework.WebUI/Dto/ValueConditionNodeDto.cs @@ -2,7 +2,7 @@ namespace Rules.Framework.WebUI.Dto { internal sealed class ValueConditionNodeDto : ConditionNodeDto { - public string ConditionTypeName { get; internal set; } + public string Condition { get; internal set; } public string DataType { get; internal set; } @@ -10,4 +10,4 @@ internal sealed class ValueConditionNodeDto : ConditionNodeDto public string Operator { get; internal set; } } -} +} \ No newline at end of file diff --git a/src/Rules.Framework.WebUI/Extensions/RuleDtoExtensions.cs b/src/Rules.Framework.WebUI/Extensions/RuleDtoExtensions.cs index eeee5cc8..0bfabeb3 100644 --- a/src/Rules.Framework.WebUI/Extensions/RuleDtoExtensions.cs +++ b/src/Rules.Framework.WebUI/Extensions/RuleDtoExtensions.cs @@ -18,7 +18,7 @@ public static ConditionNodeDto ToConditionNodeDto(this IConditionNode rootCondit return new ValueConditionNodeDto { - ConditionTypeName = condition.ConditionType, + Condition = condition.Condition, DataType = condition.DataType.ToString(), Operand = condition.Operand, Operator = condition.Operator.ToString(), @@ -41,18 +41,18 @@ public static ConditionNodeDto ToConditionNodeDto(this IConditionNode rootCondit }; } - public static RuleDto ToRuleDto(this Rule rule, string ContentType, IRuleStatusDtoAnalyzer ruleStatusDtoAnalyzer) + public static RuleDto ToRuleDto(this Rule rule, IRuleStatusDtoAnalyzer ruleStatusDtoAnalyzer) { return new RuleDto { Conditions = rule.RootCondition?.ToConditionNodeDto(), - ContentType = ContentType, - Priority = rule.Priority, - Name = rule.Name, - Value = rule.ContentContainer.GetContentAs(), DateEnd = !rule.DateEnd.HasValue ? null : rule.DateEnd.Value.ToString(dateFormat), DateBegin = rule.DateBegin.ToString(dateFormat), + Name = rule.Name, + Priority = rule.Priority, + Ruleset = rule.Ruleset, Status = !rule.Active ? RuleStatusDto.Deactivated.ToString() : ruleStatusDtoAnalyzer.Analyze(rule.DateBegin, rule.DateEnd).ToString(), + Value = rule.ContentContainer.GetContentAs(), }; } } diff --git a/src/Rules.Framework.WebUI/Handlers/GetRulesHandler.cs b/src/Rules.Framework.WebUI/Handlers/GetRulesHandler.cs index 020e354e..4999cbc7 100644 --- a/src/Rules.Framework.WebUI/Handlers/GetRulesHandler.cs +++ b/src/Rules.Framework.WebUI/Handlers/GetRulesHandler.cs @@ -43,20 +43,20 @@ protected override async Task HandleRequestAsync(HttpRequest httpRequest, { var rules = new List(); - if (rulesFilter.ContentType.Equals("all")) + if (rulesFilter.Ruleset.Equals("all")) { - var contents = await this.rulesEngine.GetContentTypesAsync(); + var rulesets = await this.rulesEngine.GetRulesetsAsync(); - foreach (var identifier in contents) + foreach (var ruleset in rulesets) { - var rulesForContentType = await this.GetRulesForContentyType(identifier, rulesFilter).ConfigureAwait(false); - rules.AddRange(rulesForContentType); + var rulesForRuleset = await this.GetRulesForRuleset(ruleset.Name, rulesFilter).ConfigureAwait(false); + rules.AddRange(rulesForRuleset); } } else { - var rulesForContentType = await this.GetRulesForContentyType(rulesFilter.ContentType, rulesFilter).ConfigureAwait(false); - rules.AddRange(rulesForContentType); + var rulesForRuleset = await this.GetRulesForRuleset(rulesFilter.Ruleset, rulesFilter).ConfigureAwait(false); + rules.AddRange(rulesForRuleset); } await this.WriteResponseAsync(httpResponse, rules, (int)HttpStatusCode.OK).ConfigureAwait(false); @@ -117,7 +117,7 @@ private RulesFilterDto GetRulesFilterFromRequest(HttpRequest httpRequest) var rulesFilterAsString = JsonSerializer.Serialize(parseQueryString.Cast().ToDictionary(k => k, v => string.IsNullOrWhiteSpace(parseQueryString[v]) ? null : parseQueryString[v])); var rulesFilter = JsonSerializer.Deserialize(rulesFilterAsString, this.SerializerOptions); - rulesFilter.ContentType = string.IsNullOrWhiteSpace(rulesFilter.ContentType) ? "all" : rulesFilter.ContentType; + rulesFilter.Ruleset = string.IsNullOrWhiteSpace(rulesFilter.Ruleset) ? "all" : rulesFilter.Ruleset; rulesFilter.DateEnd ??= DateTime.MaxValue; @@ -126,11 +126,11 @@ private RulesFilterDto GetRulesFilterFromRequest(HttpRequest httpRequest) return rulesFilter; } - private async Task> GetRulesForContentyType(string identifier, RulesFilterDto rulesFilter) + private async Task> GetRulesForRuleset(string ruleset, RulesFilterDto rulesFilter) { var genericRules = await this.rulesEngine.SearchAsync( new SearchArgs( - identifier, + ruleset, rulesFilter.DateBegin.Value, rulesFilter.DateEnd.Value)) .ConfigureAwait(false); @@ -148,7 +148,7 @@ private async Task> GetRulesForContentyType(string identifi genericRules = genericRules.OrderBy(r => r.Priority); } - var genericRulesDto = this.ApplyFilters(rulesFilter, genericRules.Select(g => g.ToRuleDto(identifier, this.ruleStatusDtoAnalyzer))); + var genericRulesDto = this.ApplyFilters(rulesFilter, genericRules.Select(g => g.ToRuleDto(this.ruleStatusDtoAnalyzer))); return genericRulesDto; } diff --git a/src/Rules.Framework.WebUI/Handlers/GetContentTypeHandler.cs b/src/Rules.Framework.WebUI/Handlers/GetRulesetsHandler.cs similarity index 67% rename from src/Rules.Framework.WebUI/Handlers/GetContentTypeHandler.cs rename to src/Rules.Framework.WebUI/Handlers/GetRulesetsHandler.cs index 96303f4e..dbd1bd6a 100644 --- a/src/Rules.Framework.WebUI/Handlers/GetContentTypeHandler.cs +++ b/src/Rules.Framework.WebUI/Handlers/GetRulesetsHandler.cs @@ -8,14 +8,14 @@ namespace Rules.Framework.WebUI.Handlers using Microsoft.AspNetCore.Http; using Rules.Framework.WebUI.Dto; - internal sealed class GetContentTypeHandler : WebUIRequestHandlerBase + internal sealed class GetRulesetsHandler : WebUIRequestHandlerBase { - private static readonly string[] resourcePath = new[] { "/{0}/api/v1/contentTypes" }; + private static readonly string[] resourcePath = new[] { "/{0}/api/v1/rulesets" }; private readonly IRulesEngine rulesEngine; private readonly IRuleStatusDtoAnalyzer ruleStatusDtoAnalyzer; - public GetContentTypeHandler(IRulesEngine rulesEngine, + public GetRulesetsHandler(IRulesEngine rulesEngine, IRuleStatusDtoAnalyzer ruleStatusDtoAnalyzer, WebUIOptions webUIOptions) : base(resourcePath, webUIOptions) { @@ -29,29 +29,29 @@ protected override async Task HandleRequestAsync(HttpRequest httpRequest, HttpRe { try { - var contents = await this.rulesEngine.GetContentTypesAsync().ConfigureAwait(false); + var rulesets = await this.rulesEngine.GetRulesetsAsync().ConfigureAwait(false); - var contentTypes = new List(); + var rulesetDtos = new List(); var index = 0; - foreach (var identifier in contents) + foreach (var ruleset in rulesets) { - var genericRules = await this.rulesEngine - .SearchAsync(new SearchArgs(identifier, + var rules = await this.rulesEngine + .SearchAsync(new SearchArgs(ruleset.Name, DateTime.MinValue, DateTime.MaxValue)) .ConfigureAwait(false); - contentTypes.Add(new ContentTypeDto + rulesetDtos.Add(new RulesetDto { Index = index, - Name = identifier, - ActiveRulesCount = genericRules.Count(IsActive), - RulesCount = genericRules.Count() + Name = ruleset.Name, + ActiveRulesCount = rules.Count(IsActive), + RulesCount = rules.Count() }); index++; } - await this.WriteResponseAsync(httpResponse, contentTypes, (int)HttpStatusCode.OK).ConfigureAwait(false); + await this.WriteResponseAsync(httpResponse, rulesetDtos, (int)HttpStatusCode.OK).ConfigureAwait(false); } catch (Exception ex) { diff --git a/src/Rules.Framework.WebUI/WebUIApplicationBuilderExtensions.cs b/src/Rules.Framework.WebUI/WebUIApplicationBuilderExtensions.cs index 4e8bcea3..1cbc5455 100644 --- a/src/Rules.Framework.WebUI/WebUIApplicationBuilderExtensions.cs +++ b/src/Rules.Framework.WebUI/WebUIApplicationBuilderExtensions.cs @@ -9,7 +9,7 @@ namespace Rules.Framework.WebUI using Rules.Framework.WebUI.Handlers; /// - /// IApplicationBuilder extension for Rules Framework Web UI + /// extension for Rules Framework Web UI /// public static class WebUIApplicationBuilderExtensions { @@ -17,14 +17,15 @@ public static class WebUIApplicationBuilderExtensions /// Uses the rules framework web UI. /// /// The application. - /// The generic rules engine factory. + /// The rules engine factory. /// The web UI options action. /// - public static IApplicationBuilder UseRulesFrameworkWebUI(this IApplicationBuilder app, - Func genericRulesEngineFactory, + public static IApplicationBuilder UseRulesFrameworkWebUI( + this IApplicationBuilder app, + Func rulesEngineFactory, Action webUIOptionsAction) { - var genericRulesEngine = genericRulesEngineFactory.Invoke(app.ApplicationServices); + var genericRulesEngine = rulesEngineFactory.Invoke(app.ApplicationServices); return app.UseRulesFrameworkWebUI(genericRulesEngine, webUIOptionsAction); } @@ -32,35 +33,38 @@ public static IApplicationBuilder UseRulesFrameworkWebUI(this IApplicationBuilde /// Uses the rules framework web UI. /// /// The application. - /// The generic rules engine factory. + /// The rules engine factory. /// - public static IApplicationBuilder UseRulesFrameworkWebUI(this IApplicationBuilder app, - Func genericRulesEngineFactory) + public static IApplicationBuilder UseRulesFrameworkWebUI( + this IApplicationBuilder app, + Func rulesEngineFactory) { - return app.UseRulesFrameworkWebUI(genericRulesEngineFactory, null); + return app.UseRulesFrameworkWebUI(rulesEngineFactory, null); } /// /// Uses the rules framework web UI. /// /// The application. - /// The generic rules engine. + /// The rules engine. /// - public static IApplicationBuilder UseRulesFrameworkWebUI(this IApplicationBuilder app, - IRulesEngine genericRulesEngine) + public static IApplicationBuilder UseRulesFrameworkWebUI( + this IApplicationBuilder app, + IRulesEngine rulesEngine) { - return app.UseRulesFrameworkWebUI(genericRulesEngine, new WebUIOptions()); + return app.UseRulesFrameworkWebUI(rulesEngine, new WebUIOptions()); } /// /// Uses the rules framework web UI. /// /// The application. - /// The generic rules engine. + /// The rules engine. /// The web UI options action. /// - public static IApplicationBuilder UseRulesFrameworkWebUI(this IApplicationBuilder app, - IRulesEngine genericRulesEngine, + public static IApplicationBuilder UseRulesFrameworkWebUI( + this IApplicationBuilder app, + IRulesEngine rulesEngine, Action webUIOptionsAction) { WebUIOptions webUIOptions; @@ -71,17 +75,19 @@ public static IApplicationBuilder UseRulesFrameworkWebUI(this IApplicationBuilde webUIOptionsAction?.Invoke(webUIOptions); } - return app.UseRulesFrameworkWebUI(genericRulesEngine, webUIOptions); + return app.UseRulesFrameworkWebUI(rulesEngine, webUIOptions); } /// /// Uses the rules framework web UI. /// /// The application. - /// The generic rules engine. + /// The rules engine. /// The web UI options. /// - private static IApplicationBuilder UseRulesFrameworkWebUI(this IApplicationBuilder app, IRulesEngine genericRulesEngine, + private static IApplicationBuilder UseRulesFrameworkWebUI( + this IApplicationBuilder app, + IRulesEngine rulesEngine, WebUIOptions webUIOptions) { var ruleStatusDtoAnalyzer = new RuleStatusDtoAnalyzer(); @@ -90,9 +96,9 @@ private static IApplicationBuilder UseRulesFrameworkWebUI(this IApplicationBuild new List { new GetIndexPageHandler(webUIOptions), - new GetConfigurationsHandler(genericRulesEngine, webUIOptions), - new GetContentTypeHandler(genericRulesEngine, ruleStatusDtoAnalyzer, webUIOptions), - new GetRulesHandler(genericRulesEngine, ruleStatusDtoAnalyzer, webUIOptions) + new GetConfigurationsHandler(rulesEngine, webUIOptions), + new GetRulesetsHandler(rulesEngine, ruleStatusDtoAnalyzer, webUIOptions), + new GetRulesHandler(rulesEngine, ruleStatusDtoAnalyzer, webUIOptions) }, webUIOptions); diff --git a/src/Rules.Framework.WebUI/index.html b/src/Rules.Framework.WebUI/index.html index 13fe9a1d..76b8b047 100644 --- a/src/Rules.Framework.WebUI/index.html +++ b/src/Rules.Framework.WebUI/index.html @@ -73,8 +73,8 @@