From 2b4cbf2a81c95d70eb6ab42d635559dfc50831d7 Mon Sep 17 00:00:00 2001 From: Luis Garces Date: Fri, 19 Jul 2024 19:48:39 +0100 Subject: [PATCH 1/5] refactor!: create non-generic rules engine --- .../Engine/RuleSpecification.cs | 2 +- .../Engine/RulesBuilder.cs | 3 +- .../Engine/RulesEngineProvider.cs | 10 +- .../Engine/RulesService.cs | 1 + .../Rules/TestNumberRules.cs | 15 +- .../Engine/RuleSpecification.cs | 2 +- .../Engine/RuleSpecificationBase.cs | 2 +- .../Engine/RulesBuilder.cs | 3 +- .../Engine/RulesEngineProvider.cs | 9 +- .../Rules.Framework.WebUI.Sample/Program.cs | 5 +- .../ReadmeExample/BasicRulesEngineExample.cs | 15 +- .../Rules/RulesRandomFactory.cs | 6 +- .../DataModel/ConditionNodeDataModel.cs | 2 +- .../DataModel/ValueConditionNodeDataModel.cs | 2 +- .../IRuleFactory.cs | 7 +- .../MongoDbProviderRulesDataSource.cs | 37 +- ...ongoDbRulesDataSourceSelectorExtensions.cs | 12 +- .../RuleFactory.cs | 50 ++- ...oStrongTypeContentSerializationProvider.cs | 9 +- .../Extensions/RuleDtoExtensions.cs | 25 +- .../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 | 128 +++++++ .../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 | 60 ++-- .../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 +- src/Rules.Framework/ContentContainer.cs | 49 +++ .../{Core => }/ContentTypeException.cs | 13 +- src/Rules.Framework/Core/ContentContainer.cs | 6 +- .../Core/PropertiesDictionary.cs | 1 + src/Rules.Framework/{Core => }/DataTypes.cs | 2 +- .../BuildValueConditionNodeExpressionArgs.cs | 2 +- .../CompilationRulesSourceMiddleware.cs | 32 +- .../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 | 33 ++ src/Rules.Framework/Generic/Rule.cs | 134 +++++++ src/Rules.Framework/Generic/RuleExtensions.cs | 25 ++ src/Rules.Framework/Generic/RulesEngine.cs | 224 ++++++++++++ .../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 | 19 +- src/Rules.Framework/IRulesEngine.cs | 27 +- src/Rules.Framework/IRulesEngineOptions.cs | 1 - .../{Core => }/LogicalOperators.cs | 2 +- .../Management/IManagementOperation.cs | 4 +- .../Management/ManagementOperations.cs | 14 +- .../ManagementOperationsController.cs | 49 ++- .../Operations/AddRuleManagementOperation.cs | 17 +- ...ilterPrioritiesRangeManagementOperation.cs | 8 +- .../MovePriorityManagementOperation.cs | 6 +- .../SetRuleForUpdateManagementOperation.cs | 10 +- .../UpdateRulesManagementOperation.cs | 13 +- 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 | 12 +- .../Providers/InMemory/IRuleFactory.cs | 7 +- .../InMemoryProviderRulesDataSource.cs | 37 +- ...oviderRulesDataSourceSelectorExtensions.cs | 28 +- .../InMemory/InMemoryRulesStorage.cs | 29 +- .../Providers/InMemory/RuleFactory.cs | 47 +-- .../InMemory/ServiceCollectionExtensions.cs | 8 +- src/Rules.Framework/{Core => }/Rule.cs | 38 +- src/Rules.Framework/RuleBuilder.cs | 19 - src/Rules.Framework/RulesEngine.cs | 124 ++++--- src/Rules.Framework/RulesEngineBuilder.cs | 4 +- src/Rules.Framework/RulesEngineOptions.cs | 1 - src/Rules.Framework/RulesFilterArgs.cs | 17 +- .../IContentSerializationProvider.cs | 10 +- .../SerializedContentContainer.cs | 14 +- src/Rules.Framework/Source/AddRuleArgs.cs | 6 +- src/Rules.Framework/Source/AddRuleDelegate.cs | 5 +- 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 | 15 +- .../Source/IRulesSourceMiddleware.cs | 25 +- src/Rules.Framework/Source/RulesSource.cs | 62 ++-- src/Rules.Framework/Source/UpdateRuleArgs.cs | 6 +- .../Source/UpdateRuleDelegate.cs | 5 +- .../Tests/Benchmark1/Benchmark1.cs | 11 +- .../Tests/Benchmark2/Benchmark2.cs | 11 +- .../Tests/Benchmark3/Benchmark3.cs | 11 +- .../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 | 2 +- .../DataSource/RuleDataModel.cs | 4 +- .../JsonContentSerializationProvider.cs | 4 +- .../RulesFromJsonFile.cs | 16 +- .../Scenarios/Scenario1/BodyMassIndexTests.cs | 79 ++--- .../Scenario2/CarInsuranceAdvisorTests.cs | 78 ++-- .../BuildingSecuritySystemControlTests.cs | 27 +- .../Scenario4/DiscountCampaignTests.cs | 77 ++-- .../Scenarios/Scenario5/BestServerTests.cs | 41 +-- ...TexasHoldEmPokerSingleCombinationsTests.cs | 5 +- .../RulesEngine/RulesEngineTestsBase.cs | 17 +- .../OperatorContainsManyToOneTests.cs | 7 +- .../RulesDeactivateAndActivateTests.cs | 9 +- .../RulesMatching/RulesInSequenceTests.cs | 8 +- .../RulesMatching/RulesUpdateDateEndTests.cs | 9 +- .../Scenarios/BaseScenarioTests.cs | 33 +- .../Scenario2/CarInsuranceAdvisorTests.cs | 43 ++- .../BuildingSecuritySystemControlTests.cs | 40 +-- .../Scenarios/Scenario5/BestServerTests.cs | 20 +- .../RulesEngine/RulesEngineTestsBase.cs | 16 +- .../RulesDeactivateAndActivateTests.cs | 10 +- .../RulesMatching/RulesInSequenceTests.cs | 13 +- .../RulesMatching/RulesUpdateDateEndTests.cs | 14 +- .../Scenario2/CarInsuranceAdvisorTests.cs | 52 ++- .../BuildingSecuritySystemControlTests.cs | 32 +- .../Scenarios/Scenario5/BestServerTests.cs | 25 +- .../MongoDbProviderRulesDataSourceTests.cs | 27 +- .../RuleFactoryTests.cs | 58 +-- ...ngTypeContentSerializationProviderTests.cs | 5 +- .../ConfiguredRulesEngineBuilderTests.cs | 13 +- .../Builder/RuleBuilderResultTests.cs | 14 +- .../Builder/RuleBuilderTests.cs | 38 +- .../RuleEngineOptionsValidatorTests.cs | 2 +- .../Builder/SelectorsTests.cs | 36 +- .../ComposedConditionNodeTests.cs | 23 +- .../ConditionNodes/ValueConditionNodeTests.cs | 238 +++++++++++++ .../ConditionTypeExtractorTests.cs | 82 ++--- .../BooleanConditionNodeTests.cs | 68 ---- .../DecimalConditionNodeTests.cs | 68 ---- .../IntegerConditionNodeTests.cs | 68 ---- .../StringConditionNodeTests.cs | 68 ---- .../Core/ContentContainerTests.cs | 1 + .../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 | 101 +++--- .../GenericSearchArgsExtensionsTests.cs | 91 ----- .../Extensions/RulesEngineExtensionsTests.cs | 22 +- .../Generic/RulesEngineTests.cs | 111 ++++++ .../Generics/GenericRulesEngineTests.cs | 146 -------- ...rRulesDataSourceSelectorExtensionsTests.cs | 29 +- .../InMemoryProviderRulesDataSourceTests.cs | 60 ++-- .../Providers/InMemory/RuleFactoryTests.cs | 63 ++-- .../ServiceCollectionExtensionsTests.cs | 3 +- .../{Core => }/RuleTests.cs | 36 +- .../Rules.Framework.Tests/RulesEngineTests.cs | 333 ++++++++---------- .../SerializedContentContainerTests.cs | 14 +- .../Source/RulesSourceTests.cs | 227 ++++++------ .../Source/StubRulesSourceMiddleware.cs | 36 +- .../Extensions/RuleDtoExtensionsTests.cs | 10 +- .../Handlers/GetConfigurationsHandlerTests.cs | 20 +- .../Handlers/GetContentTypeHandlerTests.cs | 15 +- .../Handlers/GetRulesHandlerTests.cs | 25 +- 296 files changed, 4236 insertions(+), 3605 deletions(-) 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%) create mode 100644 src/Rules.Framework/ContentContainer.cs rename src/Rules.Framework/{Core => }/ContentTypeException.cs (81%) 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%) rename src/Rules.Framework/{Core => }/Operators.cs (98%) rename src/Rules.Framework/{Core => }/Rule.cs (60%) delete mode 100644 src/Rules.Framework/RuleBuilder.cs rename tests/Rules.Framework.Tests/{Core => }/ConditionNodes/ComposedConditionNodeTests.cs (70%) create mode 100644 tests/Rules.Framework.Tests/ConditionNodes/ValueConditionNodeTests.cs 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/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..7204d987 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,7 +10,7 @@ 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) { 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..417fff83 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; @@ -34,17 +33,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 +51,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/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..6b1596a2 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,7 +10,7 @@ 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) { 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..750a8998 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; @@ -49,8 +48,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/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..28fdddee 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,8 @@ public async Task AddRuleAsync(Rule rule) await rulesCollection.InsertOneAsync(ruleDataModel).ConfigureAwait(false); } + public Task> GetContentTypesAsync() => throw new NotImplementedException(); + /// /// Gets the rules categorized with specified between /// and . @@ -56,9 +55,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 +68,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 +85,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,7 +110,7 @@ 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()); @@ -125,11 +124,11 @@ 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())); } @@ -147,7 +146,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,7 +157,7 @@ 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]; + var result = new Rule[fetchedRules.Count]; for (int i = 0; i < result.Length; i++) { result[i] = this.ruleFactory.CreateRule(fetchedRules[i]); @@ -167,4 +166,4 @@ private async Task>> GetRulesAsyn return result; } } -} +} \ 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..a354a078 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) { @@ -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]; + var childConditionNodes = new IConditionNode[count]; for (int 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..53d39994 100644 --- a/src/Rules.Framework.WebUI/Extensions/RuleDtoExtensions.cs +++ b/src/Rules.Framework.WebUI/Extensions/RuleDtoExtensions.cs @@ -2,30 +2,37 @@ namespace Rules.Framework.WebUI.Extensions { using System.Collections.Generic; using System.Linq; - using Rules.Framework.Generics; + using Rules.Framework.ConditionNodes; + using Rules.Framework.Generic; 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 || + /* Unmerged change from project 'Rules.Framework.WebUI (netstandard2.0)' + Before: + if (rootCondition.LogicalOperator == Core.LogicalOperators.Eval || + After: + if (rootCondition.LogicalOperator == 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 +48,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 +56,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..36599dc9 --- /dev/null +++ b/src/Rules.Framework/Builder/Generic/RuleBuilder.cs @@ -0,0 +1,128 @@ +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 RuleValidator ruleValidator = RuleValidator.Instance; + private bool? active; + private ContentContainer contentContainer; + private DateTime dateBegin; + private DateTime? dateEnd; + private string name; + private IConditionNode rootCondition; + + public RuleBuilderResult Build() + { + var rule = new Rule + { + ContentContainer = this.contentContainer, + DateBegin = this.dateBegin, + DateEnd = this.dateEnd, + Name = this.name, + RootCondition = this.rootCondition, + Active = this.active ?? true, + }; + + var validationResult = this.ruleValidator.Validate(rule); + + if (validationResult.IsValid) + { + var genericRule = new Rule(rule); + validationResult = this.genericRuleValidator.Validate(genericRule); + if (validationResult.IsValid) + { + return RuleBuilderResult.Success(genericRule); + } + } + + return RuleBuilderResult.Failure(validationResult.Errors.Select(ve => ve.ErrorMessage).ToList()); + } + + public IRuleBuilder WithActive(bool active) + { + this.active = active; + + return this; + } + + public IRuleBuilder WithCondition(IConditionNode condition) + { + this.rootCondition = 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) + { + var contentTypeAsString = GenericConversions.Convert(contentType); + this.contentContainer = new ContentContainer(contentTypeAsString, _ => content); + + return this; + } + + public IRuleBuilder WithDateBegin(DateTime dateBegin) + { + this.dateBegin = dateBegin; + + return this; + } + + public IRuleBuilder WithDatesInterval(DateTime dateBegin, DateTime? dateEnd) + { + this.dateBegin = dateBegin; + this.dateEnd = dateEnd; + + return this; + } + + public IRuleBuilder WithName(string name) + { + this.name = name; + + return this; + } + + public IRuleBuilder WithSerializedContent( + TContentType contentType, + object serializedContent, + IContentSerializationProvider contentSerializationProvider) + { + if (contentSerializationProvider is null) + { + throw new ArgumentNullException(nameof(contentSerializationProvider)); + } + + var contentTypeAsString = GenericConversions.Convert(contentType); + this.contentContainer = new SerializedContentContainer(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..e9118276 100644 --- a/src/Rules.Framework/Builder/RuleBuilder.cs +++ b/src/Rules.Framework/Builder/RuleBuilder.cs @@ -3,22 +3,28 @@ namespace Rules.Framework.Builder using System; using System.Linq; using Rules.Framework.Builder.Validation; - using Rules.Framework.Core; + using Rules.Framework.Generic; 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 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, DateBegin = this.dateBegin, @@ -35,58 +41,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); + var contentTypeAsString = GenericConversions.Convert(contentType); + this.contentContainer = new ContentContainer(contentTypeAsString, _ => 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 +100,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); + var contentTypeAsString = GenericConversions.Convert(contentType); + this.contentContainer = new SerializedContentContainer(contentTypeAsString, 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/ContentContainer.cs b/src/Rules.Framework/ContentContainer.cs new file mode 100644 index 00000000..d44f58a9 --- /dev/null +++ b/src/Rules.Framework/ContentContainer.cs @@ -0,0 +1,49 @@ +namespace Rules.Framework +{ + using System; + + /// + /// Defines a content container with lazily loaded content. + /// + public class ContentContainer + { + private readonly Func getContentFunc; + + /// + /// Creates a new . + /// + /// the content type. + /// + /// the function used to fetch content casted to provided type. + /// + public ContentContainer(string contentType, Func getContentFunc) + { + this.ContentType = contentType; + this.getContentFunc = getContentFunc; + } + + /// + /// Gets the content type. + /// + public string ContentType { get; } + + internal Func ContentFunc => this.getContentFunc; + + /// + /// Gets the content from container casted/converted to specified . + /// + /// the type to convert/cast content. + /// the converted/casted content. + public TContent GetContentAs() + { + try + { + return (TContent)this.getContentFunc.Invoke(typeof(TContent)); + } + catch (InvalidCastException ice) + { + throw new ContentTypeException($"Cannot cast content to provided type as {nameof(TContent)}: {typeof(TContent).FullName}", ice); + } + } + } +} \ No newline at end of file diff --git a/src/Rules.Framework/Core/ContentTypeException.cs b/src/Rules.Framework/ContentTypeException.cs similarity index 81% rename from src/Rules.Framework/Core/ContentTypeException.cs rename to src/Rules.Framework/ContentTypeException.cs index b33ac389..3383453c 100644 --- a/src/Rules.Framework/Core/ContentTypeException.cs +++ b/src/Rules.Framework/ContentTypeException.cs @@ -1,7 +1,18 @@ -namespace Rules.Framework.Core +namespace Rules.Framework { using System; using System.Diagnostics.CodeAnalysis; + + /* Unmerged change from project 'Rules.Framework (netstandard2.0)' + Before: + using System.Runtime.Serialization; + After: + using System.Runtime.Serialization; + using Rules; + using Rules.Framework; + using Rules.Framework; + using Rules.Framework.Core; + */ using System.Runtime.Serialization; /// diff --git a/src/Rules.Framework/Core/ContentContainer.cs b/src/Rules.Framework/Core/ContentContainer.cs index b45cbee5..64c0321c 100644 --- a/src/Rules.Framework/Core/ContentContainer.cs +++ b/src/Rules.Framework/Core/ContentContainer.cs @@ -14,7 +14,9 @@ public class ContentContainer /// Creates a new . /// /// the content type. - /// the function used to fetch content casted to provided type. + /// + /// the function used to fetch content casted to provided type. + /// public ContentContainer(TContentType contentType, Func getContentFunc) { this.ContentType = contentType; @@ -26,6 +28,8 @@ public ContentContainer(TContentType contentType, Func getContentF /// public TContentType ContentType { get; } + internal Func ContentFunc => this.getContentFunc; + /// /// Gets the content from container casted/converted to specified . /// 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/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..f9688df3 100644 --- a/src/Rules.Framework/Evaluation/Compiled/CompilationRulesSourceMiddleware.cs +++ b/src/Rules.Framework/Evaluation/Compiled/CompilationRulesSourceMiddleware.cs @@ -5,31 +5,31 @@ 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 async Task> HandleGetRulesAsync( + GetRulesArgs args, + GetRulesDelegate next) { var rules = await next.Invoke(args).ConfigureAwait(false); @@ -47,9 +47,9 @@ 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); @@ -68,15 +68,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..4ee3f392 --- /dev/null +++ b/src/Rules.Framework/Generic/IRulesEngine.cs @@ -0,0 +1,33 @@ +namespace Rules.Framework.Generic +{ + using System; + using System.Collections.Generic; + using System.Threading.Tasks; + + public interface IRulesEngine + { + IRulesEngineOptions Options { get; } + + Task ActivateRuleAsync(Rule rule); + + Task AddRuleAsync(Rule rule, RuleAddPriorityOption ruleAddPriorityOption); + + Task DeactivateRuleAsync(Rule rule); + + /// + /// Gets the content types. + /// + /// List of content types + Task> GetContentTypesAsync(); + + Task> GetUniqueConditionTypesAsync(TContentType contentType, DateTime dateBegin, DateTime dateEnd); + + Task>> MatchManyAsync(TContentType contentType, DateTime matchDateTime, IEnumerable> conditions); + + Task> MatchOneAsync(TContentType contentType, DateTime matchDateTime, IEnumerable> conditions); + + Task>> SearchAsync(SearchArgs searchArgs); + + 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..a6e4a823 --- /dev/null +++ b/src/Rules.Framework/Generic/Rule.cs @@ -0,0 +1,134 @@ +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 static readonly Type stringType = typeof(string); + + private readonly Rule wrappedRule; + private ContentContainer? contentContainer; + private IConditionNode? rootCondition; + + internal Rule() + : this(new Rule()) + { + } + + internal Rule(Rule wrappedRule) + { + var typeForContentType = typeof(TContentType); + if (!typeForContentType.IsEnum && typeForContentType != stringType) + { + throw new NotSupportedException($"Only enum types or string are supported as {nameof(TContentType)}."); + } + + var typeForConditionType = typeof(TConditionType); + if (!typeForConditionType.IsEnum && typeForConditionType != stringType) + { + throw new NotSupportedException($"Only enum types or string are supported as {nameof(TConditionType)}."); + } + + this.wrappedRule = wrappedRule ?? throw new ArgumentNullException(nameof(wrappedRule)); + } + + /// + /// Gets and sets the if the rules is active. + /// + public bool Active + { + get => this.wrappedRule.Active; + internal set => this.wrappedRule.Active = value; + } + + /// + /// Gets the content container which contains the rule content. + /// + public ContentContainer ContentContainer + { + get + { + this.contentContainer ??= new ContentContainer( + GenericConversions.Convert(this.wrappedRule.ContentContainer.ContentType), + this.wrappedRule.ContentContainer.ContentFunc); + + return this.contentContainer; + } + internal set + { + this.contentContainer = value; + this.wrappedRule.ContentContainer = new ContentContainer(GenericConversions.Convert(value.ContentType), value.ContentFunc); + } + } + + /// + /// Gets the date from which the rule begins being applicable. + /// + public DateTime DateBegin + { + get => this.wrappedRule.DateBegin; + internal set => this.wrappedRule.DateBegin = value; + } + + /// + /// 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 + { + get => this.wrappedRule.Name; + internal set => this.wrappedRule.Name = value; + } + + /// + /// 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..2dd045e9 --- /dev/null +++ b/src/Rules.Framework/Generic/RulesEngine.cs @@ -0,0 +1,224 @@ +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; + + /// + /// Activates the specified existing rule. + /// + /// The rule. + /// + /// rule + public Task ActivateRuleAsync(Rule rule) + { + if (rule is null) + { + throw new ArgumentNullException(nameof(rule)); + } + + return this.wrappedRulesEngine.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) + { + if (rule is null) + { + throw new ArgumentNullException(nameof(rule)); + } + + if (ruleAddPriorityOption is null) + { + throw new ArgumentNullException(nameof(rule)); + } + + return this.wrappedRulesEngine.AddRuleAsync(rule, ruleAddPriorityOption); + } + + /// + /// Deactivates the specified existing rule. + /// + /// The rule. + /// + /// rule + public Task DeactivateRuleAsync(Rule rule) + { + if (rule is null) + { + throw new ArgumentNullException(nameof(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(); + } + + /// + /// 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) + { + var contentTypeAsString = GenericConversions.Convert(contentType); + var conditionTypes = await this.wrappedRulesEngine.GetUniqueConditionTypesAsync(contentTypeAsString, dateBegin, dateEnd).ConfigureAwait(false); + return conditionTypes.Select(t => GenericConversions.Convert(t)).ToArray(); + } + + /// + /// 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, + 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(); + } + + /// + /// 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, + 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()!; + } + + /// + /// 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) + { + 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(); + } + + /// + /// Updates the specified existing rule. + /// + /// The rule. + /// + /// rule + public Task UpdateRuleAsync(Rule rule) + { + if (rule is null) + { + throw new ArgumentNullException(nameof(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..a8b22eaa 100644 --- a/src/Rules.Framework/IRulesDataSource.cs +++ b/src/Rules.Framework/IRulesDataSource.cs @@ -6,40 +6,41 @@ namespace Rules.Framework 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); + + Task> GetContentTypesAsync(); /// - /// Gets the rules categorized with specified between and . + /// 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..2bbde3ec 100644 --- a/src/Rules.Framework/IRulesEngine.cs +++ b/src/Rules.Framework/IRulesEngine.cs @@ -3,22 +3,31 @@ namespace Rules.Framework using System; using System.Collections.Generic; using System.Threading.Tasks; - using Rules.Framework.Core; - internal interface IRulesEngine + public interface IRulesEngine { - Task AddRuleAsync(Rule rule, RuleAddPriorityOption ruleAddPriorityOption); + IRulesEngineOptions Options { get; } - PriorityCriterias GetPriorityCriteria(); + Task ActivateRuleAsync(Rule rule); - Task> GetUniqueConditionTypesAsync(TContentType contentType, DateTime dateBegin, DateTime dateEnd); + Task AddRuleAsync(Rule rule, RuleAddPriorityOption ruleAddPriorityOption); - Task>> MatchManyAsync(TContentType contentType, DateTime matchDateTime, IEnumerable> conditions); + Task DeactivateRuleAsync(Rule rule); - Task> MatchOneAsync(TContentType contentType, DateTime matchDateTime, IEnumerable> conditions); + /// + /// Gets the content types. + /// + /// List of content types + Task> GetContentTypesAsync(); - Task>> SearchAsync(SearchArgs searchArgs); + Task> GetUniqueConditionTypesAsync(string contentType, DateTime dateBegin, DateTime dateEnd); - Task UpdateRuleAsync(Rule rule); + Task> MatchManyAsync(string contentType, DateTime matchDateTime, IEnumerable> conditions); + + Task MatchOneAsync(string contentType, DateTime matchDateTime, IEnumerable> conditions); + + Task> SearchAsync(SearchArgs searchArgs); + + 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..1b5182e8 100644 --- a/src/Rules.Framework/IRulesEngineOptions.cs +++ b/src/Rules.Framework/IRulesEngineOptions.cs @@ -2,7 +2,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. 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..b4a7b802 100644 --- a/src/Rules.Framework/Management/Operations/AddRuleManagementOperation.cs +++ b/src/Rules.Framework/Management/Operations/AddRuleManagementOperation.cs @@ -5,30 +5,27 @@ namespace Rules.Framework.Management.Operations 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..f8f57886 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 (Rule existentRule in rules) { - UpdateRuleArgs updateRuleArgs = new() + var updateRuleArgs = new UpdateRuleArgs() { Rule = existentRule, }; 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..f860fce7 100644 --- a/src/Rules.Framework/Providers/InMemory/IInMemoryRulesStorage.cs +++ b/src/Rules.Framework/Providers/InMemory/IInMemoryRulesStorage.cs @@ -3,14 +3,16 @@ 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(); + IReadOnlyCollection GetAllRules(); - IReadOnlyCollection> GetRulesBy(TContentType contentType); + IReadOnlyCollection GetContentTypes(); - void UpdateRule(RuleDataModel ruleDataModel); + 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..10d84b53 100644 --- a/src/Rules.Framework/Providers/InMemory/InMemoryProviderRulesDataSource.cs +++ b/src/Rules.Framework/Providers/InMemory/InMemoryProviderRulesDataSource.cs @@ -8,17 +8,15 @@ namespace Rules.Framework.Providers.InMemory /// /// 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,9 @@ public Task AddRuleAsync(Rule rule) return Task.CompletedTask; } + public Task> GetContentTypesAsync() + => Task.FromResult>(this.inMemoryRulesStorage.GetContentTypes()); + /// /// Gets the rules categorized with specified between /// and . @@ -52,11 +53,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 +73,7 @@ public Task>> GetRulesAsync(TCont Array.Resize(ref filteredRules, i); } - return Task.FromResult>>(filteredRules); + return Task.FromResult>(filteredRules); } /// @@ -81,7 +82,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 +91,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 +122,7 @@ public Task>> GetRulesByAsync(Rul Array.Resize(ref filteredRules, i); } - return Task.FromResult>>(filteredRules); + return Task.FromResult>(filteredRules); } /// @@ -130,7 +131,7 @@ public Task>> GetRulesByAsync(Rul /// The rule. /// /// rule - public Task UpdateRuleAsync(Rule rule) + public Task UpdateRuleAsync(Rule rule) { if (rule is null) { @@ -144,4 +145,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..63758d93 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); + List contentTypeRules = GetRulesCollectionByContentType(ruleDataModel.ContentType); lock (contentTypeRules) { @@ -30,23 +30,26 @@ public void AddRule(RuleDataModel ruleDataModel) } } - public IReadOnlyCollection> GetAllRules() + 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); + List contentTypeRules = GetRulesCollectionByContentType(contentType); return contentTypeRules.AsReadOnly(); } - public void UpdateRule(RuleDataModel ruleDataModel) + public void UpdateRule(RuleDataModel ruleDataModel) { - List> contentTypeRules = GetRulesCollectionByContentType(ruleDataModel.ContentType); + List contentTypeRules = GetRulesCollectionByContentType(ruleDataModel.ContentType); lock (contentTypeRules) { - RuleDataModel existent = contentTypeRules.Find(r => string.Equals(r.Name, ruleDataModel.Name, StringComparison.Ordinal)); + RuleDataModel 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 +60,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, (ct) => 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..89e7bc2f 100644 --- a/src/Rules.Framework/Providers/InMemory/RuleFactory.cs +++ b/src/Rules.Framework/Providers/InMemory/RuleFactory.cs @@ -3,22 +3,23 @@ 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.ContentType, (_) => ruleDataModel.Content); - var rule = new Rule + var rule = new Rule { Active = ruleDataModel.Active, ContentContainer = contentContainer, @@ -32,7 +33,7 @@ public Rule CreateRule(RuleDataModel CreateRule(Rule rule) + public RuleDataModel CreateRule(Rule rule) { if (rule is null) { @@ -41,7 +42,7 @@ public RuleDataModel CreateRule(Rule(); - var ruleDataModel = new RuleDataModel + var ruleDataModel = new RuleDataModel { Content = content, ContentType = rule.ContentContainer.ContentType, @@ -56,17 +57,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 +75,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 +96,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 +107,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 (IConditionNode child in composedConditionNode.ChildConditionNodes) { conditionNodeDataModels[i++] = ConvertConditionNode(child); } - return new ComposedConditionNodeDataModel + return new ComposedConditionNodeDataModel { ChildConditionNodes = conditionNodeDataModels, LogicalOperator = composedConditionNode.LogicalOperator, @@ -124,14 +125,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..5b6b5332 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(), + typeof(IInMemoryRulesStorage), + (sp) => new InMemoryRulesStorage(), serviceLifetime); serviceDescriptors.Add(item); diff --git a/src/Rules.Framework/Core/Rule.cs b/src/Rules.Framework/Rule.cs similarity index 60% rename from src/Rules.Framework/Core/Rule.cs rename to src/Rules.Framework/Rule.cs index 31f8009b..0000e63e 100644 --- a/src/Rules.Framework/Core/Rule.cs +++ b/src/Rules.Framework/Rule.cs @@ -1,25 +1,23 @@ -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 date from which the rule begins being applicable. @@ -44,14 +42,30 @@ 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 { ContentContainer = this.ContentContainer, DateBegin = this.DateBegin, @@ -62,4 +76,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/RulesEngine.cs b/src/Rules.Framework/RulesEngine.cs index f6af512a..9c97d211 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,41 @@ 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; } + /// + /// Gets the rules engine options. + /// + /// The rules engine options. + public IRulesEngineOptions Options { get; } + /// /// Activates the specified existing rule. /// /// The rule. /// /// rule - public Task ActivateRuleAsync(Rule rule) + public Task ActivateRuleAsync(Rule rule) { if (rule is null) { @@ -73,7 +73,7 @@ public Task ActivateRuleAsync(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) { @@ -94,7 +94,7 @@ public Task AddRuleAsync(Rule /// The rule. /// /// rule - public Task DeactivateRuleAsync(Rule rule) + public Task DeactivateRuleAsync(Rule rule) { if (rule is null) { @@ -106,13 +106,9 @@ 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(); } /// @@ -129,9 +125,9 @@ public PriorityCriterias GetPriorityCriteria() /// 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 + var getRulesArgs = new GetRulesArgs { ContentType = contentType, DateBegin = dateBegin, @@ -158,10 +154,10 @@ public async Task> GetUniqueConditionTypesAsync(TCon /// 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) { var evaluationOptions = new EvaluationOptions { @@ -169,7 +165,7 @@ public async Task>> MatchManyAsyn MatchMode = MatchModes.Exact, }; - var getRulesArgs = new GetRulesArgs + var getRulesArgs = new GetRulesArgs { ContentType = contentType, DateBegin = matchDateTime, @@ -199,10 +195,10 @@ public async Task>> MatchManyAsyn /// /// /// the matched rule; otherwise, null. - public async Task> MatchOneAsync( - TContentType contentType, + public async Task MatchOneAsync( + string contentType, DateTime matchDateTime, - IEnumerable> conditions) + IEnumerable> conditions) { var evaluationOptions = new EvaluationOptions { @@ -210,7 +206,7 @@ public async Task> MatchOneAsync( MatchMode = MatchModes.Exact, }; - var getRulesArgs = new GetRulesArgs + var getRulesArgs = new GetRulesArgs { ContentType = contentType, DateBegin = matchDateTime, @@ -219,7 +215,7 @@ 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); } @@ -235,14 +231,14 @@ public async Task> MatchOneAsync( /// /// /// 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 +261,7 @@ public async Task>> SearchAsync(S MatchMode = MatchModes.Search, }; - var getRulesArgs = new GetRulesArgs + var getRulesArgs = new GetRulesArgs { ContentType = searchArgs.ContentType, DateBegin = searchArgs.DateBegin, @@ -283,7 +279,7 @@ public async Task>> SearchAsync(S /// The rule. /// /// rule - public Task UpdateRuleAsync(Rule rule) + public Task UpdateRuleAsync(Rule rule) { if (rule is null) { @@ -293,10 +289,10 @@ 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 rulesFilterArgs = new GetRulesFilteredArgs { ContentType = rule.ContentContainer.ContentType, }; @@ -349,7 +345,7 @@ private async Task 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 +356,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 +377,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 +394,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 +407,15 @@ await ManagementOperations.Manage(existentRules) .ConfigureAwait(false); } - private IEnumerable> EvalAll( - List> orderedRules, + 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 +427,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 +447,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 +469,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 +489,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,9 +503,9 @@ 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, }; 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..b77300b5 100644 --- a/src/Rules.Framework/RulesEngineOptions.cs +++ b/src/Rules.Framework/RulesEngineOptions.cs @@ -2,7 +2,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. 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..928a7179 100644 --- a/src/Rules.Framework/Serialization/SerializedContentContainer.cs +++ b/src/Rules.Framework/Serialization/SerializedContentContainer.cs @@ -1,23 +1,21 @@ 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) + IContentSerializationProvider contentSerializationProvider) : base(contentType, (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/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..5d743996 100644 --- a/src/Rules.Framework/Source/IRulesSource.cs +++ b/src/Rules.Framework/Source/IRulesSource.cs @@ -1,17 +1,18 @@ 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> GetContentTypesAsync(); - Task>> GetRulesFilteredAsync(GetRulesFilteredArgs args); + Task> GetRulesAsync(GetRulesArgs args); - Task UpdateRuleAsync(UpdateRuleArgs 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..ce8d6340 100644 --- a/src/Rules.Framework/Source/IRulesSourceMiddleware.cs +++ b/src/Rules.Framework/Source/IRulesSourceMiddleware.cs @@ -1,25 +1,24 @@ 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> HandleGetRulesAsync( + GetRulesArgs args, + GetRulesDelegate next); - Task>> HandleGetRulesFilteredAsync( - GetRulesFilteredArgs args, - GetRulesFilteredDelegate 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..b5f6128e 100644 --- a/src/Rules.Framework/Source/RulesSource.cs +++ b/src/Rules.Framework/Source/RulesSource.cs @@ -4,49 +4,53 @@ namespace Rules.Framework.Source 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 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.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 Task> GetContentTypesAsync() => this.rulesDataSource.GetContentTypesAsync(); + + 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 +70,14 @@ private static AddRuleDelegate CreateAddRulePipeli return action; } - private static GetRulesFilteredDelegate CreateGetRulesFilteredPipelineDelegate( - IRulesDataSource rulesDataSource, - LinkedList> middlewares) + 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 +105,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 +131,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/Tests/Benchmark1/Benchmark1.cs b/tests/Rules.Framework.BenchmarkTests/Tests/Benchmark1/Benchmark1.cs index b7d87530..a3eca07f 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? rulesEngine; [ParamsAllValues] public bool EnableCompilation { get; set; } @@ -24,9 +25,7 @@ public async Task RunAsync() [GlobalSetup] public async Task SetUpAsync() { - this.rulesEngine = RulesEngineBuilder.CreateRulesEngine() - .WithContentType() - .WithConditionType() + var rulesEngine = RulesEngineBuilder.CreateRulesEngine() .SetDataSourceForBenchmark(this.Provider!, nameof(Benchmark1)) .Configure(options => { @@ -36,8 +35,10 @@ public async Task SetUpAsync() 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.rulesEngine = rulesEngine.MakeGeneric(); } [GlobalCleanup] diff --git a/tests/Rules.Framework.BenchmarkTests/Tests/Benchmark2/Benchmark2.cs b/tests/Rules.Framework.BenchmarkTests/Tests/Benchmark2/Benchmark2.cs index 66444194..e309f343 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? rulesEngine; [ParamsAllValues] public bool EnableCompilation { get; set; } @@ -24,9 +25,7 @@ public async Task RunAsync() [GlobalSetup] public async Task SetUpAsync() { - this.rulesEngine = RulesEngineBuilder.CreateRulesEngine() - .WithContentType() - .WithConditionType() + var rulesEngine = RulesEngineBuilder.CreateRulesEngine() .SetDataSourceForBenchmark(this.Provider!, nameof(Benchmark2)) .Configure(options => { @@ -36,8 +35,10 @@ public async Task SetUpAsync() 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.rulesEngine = rulesEngine.MakeGeneric(); } [GlobalCleanup] diff --git a/tests/Rules.Framework.BenchmarkTests/Tests/Benchmark3/Benchmark3.cs b/tests/Rules.Framework.BenchmarkTests/Tests/Benchmark3/Benchmark3.cs index 900f0e91..4c196286 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? rulesEngine; [ParamsAllValues] public bool EnableCompilation { get; set; } @@ -24,9 +25,7 @@ public async Task RunAsync() [GlobalSetup] public async Task SetUpAsync() { - this.rulesEngine = RulesEngineBuilder.CreateRulesEngine() - .WithContentType() - .WithConditionType() + var rulesEngine = RulesEngineBuilder.CreateRulesEngine() .SetDataSourceForBenchmark(this.Provider!, nameof(Benchmark3)) .Configure(options => { @@ -36,8 +35,10 @@ public async Task SetUpAsync() 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.rulesEngine = rulesEngine.MakeGeneric(); } [GlobalCleanup] 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..879fac62 100644 --- a/tests/Rules.Framework.IntegrationTests.Common/Scenarios/ScenarioLoader.cs +++ b/tests/Rules.Framework.IntegrationTests.Common/Scenarios/ScenarioLoader.cs @@ -5,7 +5,7 @@ namespace Rules.Framework.IntegrationTests.Common.Scenarios public static class ScenarioLoader { public static async Task LoadScenarioAsync( - RulesEngine rulesEngine, + IRulesEngine rulesEngine, IScenarioData scenarioData) { foreach (var rule in scenarioData.Rules) 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..07d5ddd5 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)) @@ -29,7 +31,7 @@ public async Task FromJsonFileAsync(RulesEngine(ruleDataModel.ContentTypeCode); - var ruleBuilder = RuleBuilder.NewRule() + var ruleBuilder = Rule.New() .WithName(ruleDataModel.Name) .WithDatesInterval(ruleDataModel.DateBegin, ruleDataModel.DateEnd); @@ -101,7 +103,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 +140,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 +149,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..4f1dc241 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,19 @@ 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() + 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 +46,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 +60,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 +70,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 +86,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 +115,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 +129,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 +139,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 +155,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 +188,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 +208,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 +240,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..d5b6d3c3 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,20 @@ 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.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 +58,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 +72,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 +86,20 @@ 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.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 +118,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 +133,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 +147,20 @@ 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.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 +176,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 +189,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 +203,20 @@ 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.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 +232,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 +245,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 +259,20 @@ 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.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 +288,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 +298,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 +311,20 @@ 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.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 +340,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 +353,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..cddca5c3 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,16 @@ 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(); // 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 +48,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 +68,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 +84,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 +110,16 @@ 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(); // 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 +142,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 +162,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 +178,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 +186,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..25b5d266 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,19 +25,20 @@ protected RulesEngineTestsBase(ContentType testContentType) c.PriorityCriteria = PriorityCriterias.TopmostRuleWins; }) .Build(); + this.CompiledRulesEngine = compiledRulesEngine.MakeGeneric(); - this.InterpretedRulesEngine = RulesEngineBuilder + var interpretedRulesEngine = RulesEngineBuilder .CreateRulesEngine() - .WithContentType() - .WithConditionType() .SetInMemoryDataSource() .Configure(c => c.PriorityCriteria = PriorityCriterias.TopmostRuleWins) .Build(); + + this.InterpretedRulesEngine = interpretedRulesEngine.MakeGeneric(); } - protected RulesEngine CompiledRulesEngine { get; } + protected IRulesEngine CompiledRulesEngine { get; } - protected RulesEngine InterpretedRulesEngine { get; } + protected IRulesEngine InterpretedRulesEngine { get; } protected async Task ActivateRuleAsync(Rule rule, bool 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..18a633a6 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 @@ -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..94531993 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 Condition[] { 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 Condition[] { 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 Condition[] { 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..31a11526 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,12 @@ public async Task BestServer_InEvaluation(IEnumerable() - .WithConditionType() .SetInMemoryDataSource() .Build(); + var genericRulesEngine = rulesEngine.MakeGeneric(); // 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 +73,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 +81,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 +92,12 @@ public async Task BestServer_InEvaluation(IEnumerable() - .WithConditionType() .SetMongoDbDataSource(this.mongoClient, this.mongoDbProviderSettings) .Configure(c => c.PriorityCriteria = PriorityCriterias.TopmostRuleWins) .Build(); + + this.RulesEngine = rulesEngine.MakeGeneric(); } - protected RulesEngine RulesEngine { get; } + protected IRulesEngine RulesEngine { get; } public void Dispose() { @@ -47,7 +47,6 @@ protected void AddRules(IEnumerable ruleSpecifications) this.RulesEngine.AddRuleAsync( ruleSpecification.Rule, ruleSpecification.RuleAddPriorityOption) - .ConfigureAwait(false) .GetAwaiter() .GetResult(); } @@ -58,12 +57,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..e5b335ec 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,7 +61,7 @@ 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); @@ -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..cb3647f5 100644 --- a/tests/Rules.Framework.Providers.MongoDb.IntegrationTests/Scenarios/Scenario2/CarInsuranceAdvisorTests.cs +++ b/tests/Rules.Framework.Providers.MongoDb.IntegrationTests/Scenarios/Scenario2/CarInsuranceAdvisorTests.cs @@ -30,15 +30,15 @@ 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 }); @@ -80,8 +80,6 @@ public async Task GetCarInsuranceAdvice_RepairCostsNotWorthIt_ReturnsRefusePayme }; var rulesEngine = RulesEngineBuilder.CreateRulesEngine() - .WithContentType() - .WithConditionType() .SetMongoDbDataSource(this.mongoClient, this.mongoDbProviderSettings) .Configure(opt => { @@ -89,9 +87,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 +113,6 @@ public async Task GetCarInsuranceAdvice_UpdatesRuleAndAddsNewOneAndEvaluates_Ret }; var rulesEngine = RulesEngineBuilder.CreateRulesEngine() - .WithContentType() - .WithConditionType() .SetMongoDbDataSource(this.mongoClient, this.mongoDbProviderSettings) .Configure(opt => { @@ -123,29 +120,30 @@ public async Task GetCarInsuranceAdvice_UpdatesRuleAndAddsNewOneAndEvaluates_Ret opt.PriorityCriteria = PriorityCriterias.BottommostRuleWins; }) .Build(); + var genericRulesEngine = rulesEngine.MakeGeneric(); 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 +170,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 +196,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,13 +244,13 @@ private static MongoClient CreateMongoClient() return new MongoClient(settings); } - private static IRulesDataSource CreateRulesDataSourceTest( + private static IRulesDataSource 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); 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..8c6ce74a 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 { @@ -74,17 +75,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 +92,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 +129,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 +167,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(); @@ -197,10 +195,10 @@ public void Dispose() 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..426d9337 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,16 @@ public async Task BestServer_InEvaluation(IEnumerable() - .WithConditionType() .SetMongoDbDataSource(this.mongoClient, this.mongoDbProviderSettings) .Configure(opt => { opt.EnableCompilation = enableCompilation; }) .Build(); + var genericRulesEngine = rulesEngine.MakeGeneric(); // 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 +78,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 +86,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 +97,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..b33088a7 100644 --- a/tests/Rules.Framework.Providers.MongoDb.Tests/MongoDbProviderRulesDataSourceTests.cs +++ b/tests/Rules.Framework.Providers.MongoDb.Tests/MongoDbProviderRulesDataSourceTests.cs @@ -6,7 +6,6 @@ namespace Rules.Framework.Providers.MongoDb.Tests 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; @@ -17,11 +16,11 @@ public class MongoDbProviderRulesDataSourceTests 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 +32,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 +43,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..7dab97ac 100644 --- a/tests/Rules.Framework.Tests/Builder/RuleBuilderTests.cs +++ b/tests/Rules.Framework.Tests/Builder/RuleBuilderTests.cs @@ -5,9 +5,8 @@ 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 +17,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 +89,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 +118,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 +129,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 +141,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 +163,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,23 +179,23 @@ 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) @@ -204,8 +203,7 @@ public void NewRule_WithSerializedContent_SetsContentAsSerializedContent() // Assert var ruleContent = ruleBuilderResult.Rule.ContentContainer; - ruleContent.Should().NotBeNull(); - ruleContent.Should().NotBeNull().And.BeOfType>(); + ruleContent.Should().NotBeNull().And.BeOfType>(); ruleContent.ContentType.Should().Be(contentType); 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..03d444a4 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,52 @@ public void GetConditionTypes_ReturnsCorrectExtraction() var dateBegin = new DateTime(2018, 01, 01); var dateEnd = new DateTime(2019, 01, 01); - var contentType = ContentType.Type1; + var contentType = ContentType.Type1.ToString(); - var rule1 = new Rule + var rule1 = new Rule { - ContentContainer = new ContentContainer(contentType, _ => new object()), + ContentContainer = new ContentContainer(contentType, _ => 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(contentType, _ => 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(contentType, _ => 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(contentType, _ => 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 +76,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 +98,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 +119,24 @@ public void GetConditionTypes_WithNullRootCondition_ReturnsEmptyListConditionTyp var dateBegin = new DateTime(2018, 01, 01); var dateEnd = new DateTime(2019, 01, 01); - var contentType = ContentType.Type1; + var contentType = ContentType.Type1.ToString(); - var matchRules = new List> + var matchRules = new List { - new Rule - { - ContentContainer = new ContentContainer(contentType, _ => new object()), - DateBegin = dateBegin, - DateEnd = dateEnd, - Name = "Rule 3", - Priority = 1, - RootCondition = null - } + new Rule + { + ContentContainer = new ContentContainer(contentType, _ => 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/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/Core/ContentContainerTests.cs b/tests/Rules.Framework.Tests/Core/ContentContainerTests.cs index 9bbb9338..f2ea8110 100644 --- a/tests/Rules.Framework.Tests/Core/ContentContainerTests.cs +++ b/tests/Rules.Framework.Tests/Core/ContentContainerTests.cs @@ -2,6 +2,7 @@ namespace Rules.Framework.Tests.Core { using System; using FluentAssertions; + using Rules.Framework; using Rules.Framework.Core; using Rules.Framework.Tests.Stubs; using Xunit; 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..b23dc002 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,36 @@ 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 content = genericRule.ContentContainer.GetContentAs(); + content.Should().BeOfType(); + content.Should().Be(expectedRuleContent); + genericRule.RootCondition.Should().BeOfType>(); - var genericComposedRootCondition = genericRule.RootCondition as GenericComposedConditionNode; + var genericComposedRootCondition = genericRule.RootCondition as ComposedConditionNode; genericComposedRootCondition.Should().BeEquivalentTo(expectedRootCondition, config => config.IncludingAllRuntimeProperties()); } @@ -95,21 +93,22 @@ 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); + var content = genericRule.ContentContainer.GetContentAs(); + content.Should().BeOfType(); + content.Should().Be(expectedRuleContent); genericRule.RootCondition.Should().BeNull(); } @@ -117,30 +116,38 @@ 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 content = genericRule.ContentContainer.GetContentAs(); + content.Should().BeOfType(); + content.Should().Be(expectedRuleContent); + genericRule.RootCondition.Should().BeOfType>(); - var genericValueRootCondition = genericRule.RootCondition as GenericValueConditionNode; - genericValueRootCondition.ConditionTypeName.Should().Be(expectedRootCondition.ConditionType.ToString()); + 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..c36c4760 --- /dev/null +++ b/tests/Rules.Framework.Tests/Generic/RulesEngineTests.cs @@ -0,0 +1,111 @@ +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 Mock mockRulesEngine; + + public RulesEngineTests() + { + this.mockRulesEngine = new Mock(); + } + + [Fact] + public async Task GenericRulesEngine_GetContentTypes_Success() + { + // Arrange + var expectedGenericContentTypes = new List + { + ContentType.Type1, + ContentType.Type2, + }; + + var contentTypes = new[] { "Type1", "Type2" }; + this.mockRulesEngine.Setup(x => x.GetContentTypesAsync()) + .ReturnsAsync(contentTypes); + + var genericRulesEngine = new RulesEngine(this.mockRulesEngine.Object); + + // Act + var genericContentTypes = await genericRulesEngine.GetContentTypesAsync(); + + // Assert + genericContentTypes.Should().BeEquivalentTo(expectedGenericContentTypes); + } + + [Fact] + public async Task GenericRulesEngine_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 GenericRulesEngine_SearchAsync_Success() + { + // 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 expectedGenericRules = new List + { + expectedRule, + }; + + 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 + }; + + this.mockRulesEngine + .Setup(m => m.SearchAsync(It.IsAny>())) + .ReturnsAsync(testRules); + + var genericRulesEngine = new RulesEngine(this.mockRulesEngine.Object); + + // Act + var genericRules = await genericRulesEngine.SearchAsync(genericSearchArgs); + + // Assert + var actualRule = genericRules.First(); + actualRule.Should().BeEquivalentTo(expectedRule); + this.mockRulesEngine + .Verify(m => m.SearchAsync(It.IsAny>()), Times.Once); + } + } +} \ 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/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..fd0c383a 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(ContentType.Type1.ToString(), _ => 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(ContentType.Type1.ToString(), _ => 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(ContentType.Type1.ToString(), (_) => 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..47f042d8 100644 --- a/tests/Rules.Framework.Tests/RulesEngineTests.cs +++ b/tests/Rules.Framework.Tests/RulesEngineTests.cs @@ -9,8 +9,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,32 +19,32 @@ namespace Rules.Framework.Tests public class RulesEngineTests { - private readonly Mock> mockConditionsEvalEngine; - private readonly Mock> mockCondtionTypeExtractor; - private readonly Mock> mockRulesSource; + private readonly Mock mockConditionsEvalEngine; + private readonly Mock mockConditionTypeExtractor; + private readonly Mock mockRulesSource; public RulesEngineTests() { - this.mockRulesSource = new Mock>(); - this.mockCondtionTypeExtractor = new Mock>(); - this.mockConditionsEvalEngine = new Mock>(); + this.mockRulesSource = new Mock(); + this.mockConditionTypeExtractor = new Mock(); + this.mockConditionsEvalEngine = new Mock(); } [Fact] public async Task ActivateRuleAsync_GivenEmptyRuleDataSource_ActivatesRuleSuccessfully() { // 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()), + 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, 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 @@ -52,25 +52,25 @@ public async Task ActivateRuleAsync_GivenEmptyRuleDataSource_ActivatesRuleSucces MatchMode = MatchModes.Exact }; - mockRulesSource.Setup(s => s.GetRulesFilteredAsync(It.IsAny>())) - .ReturnsAsync(new List> { testRule }); + mockRulesSource.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(mockConditionsEvalEngine.Object, mockRulesSource.Object, validatorProvider, rulesEngineOptions, mockConditionTypeExtractor.Object); // Act - var actual = await sut.ActivateRuleAsync(testRule).ConfigureAwait(false); + var actual = await sut.ActivateRuleAsync(testRule); // Assert actual.IsSuccess.Should().BeTrue(); actual.Errors.Should().BeEmpty(); - mockRulesSource.Verify(x => x.GetRulesFilteredAsync(It.IsAny>()), Times.Once()); + mockRulesSource.Verify(x => x.GetRulesFilteredAsync(It.IsAny()), Times.Once()); mockConditionsEvalEngine.Verify(x => x.Eval( - It.IsAny>(), - It.IsAny>(), + It.IsAny(), + It.IsAny>(), It.Is(eo => eo == evaluationOptions)), Times.Never()); } @@ -78,16 +78,16 @@ public async Task ActivateRuleAsync_GivenEmptyRuleDataSource_ActivatesRuleSucces public async Task AddRuleAsync_GivenEmptyRuleDataSource_AddsRuleSuccesfully() { // 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()), + ContentContainer = new ContentContainer(contentType, (t) => 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() @@ -102,7 +102,7 @@ public async Task AddRuleAsync_GivenEmptyRuleDataSource_AddsRuleSuccesfully() rulesEngineOptions.PriorityCriteria = PriorityCriterias.BottommostRuleWins; - var sut = new RulesEngine(mockConditionsEvalEngine.Object, mockRulesSource.Object, validatorProvider, rulesEngineOptions, mockCondtionTypeExtractor.Object); + var sut = new RulesEngine(mockConditionsEvalEngine.Object, mockRulesSource.Object, validatorProvider, rulesEngineOptions, mockConditionTypeExtractor.Object); // Act var actual = await sut.AddRuleAsync(testRule, RuleAddPriorityOption.AtBottom); @@ -111,10 +111,10 @@ public async Task AddRuleAsync_GivenEmptyRuleDataSource_AddsRuleSuccesfully() actual.IsSuccess.Should().BeTrue(); actual.Errors.Should().BeEmpty(); - mockRulesSource.Verify(x => x.GetRulesAsync(It.IsAny>()), Times.Never()); + mockRulesSource.Verify(x => x.GetRulesAsync(It.IsAny()), Times.Never()); mockConditionsEvalEngine.Verify(x => x.Eval( - It.IsAny>(), - It.IsAny>(), + It.IsAny(), + It.IsAny>(), It.Is(eo => eo == evaluationOptions)), Times.Never()); } @@ -122,16 +122,16 @@ public async Task AddRuleAsync_GivenEmptyRuleDataSource_AddsRuleSuccesfully() public async Task DeactivateRuleAsync_GivenEmptyRuleDataSource_DeactivatesRuleSuccessfully() { // 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()), + 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") + RootCondition = new ValueConditionNode(DataTypes.String, ConditionType.IsoCountryCode.ToString(), Operators.Equal, "USA") }; var evaluationOptions = new EvaluationOptions @@ -139,47 +139,28 @@ public async Task DeactivateRuleAsync_GivenEmptyRuleDataSource_DeactivatesRuleSu MatchMode = MatchModes.Exact }; - mockRulesSource.Setup(s => s.GetRulesFilteredAsync(It.IsAny>())) - .ReturnsAsync(new List> { testRule }); + mockRulesSource.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(mockConditionsEvalEngine.Object, mockRulesSource.Object, validatorProvider, rulesEngineOptions, mockConditionTypeExtractor.Object); // 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()); + mockRulesSource.Verify(x => x.GetRulesFilteredAsync(It.IsAny()), Times.Once()); mockConditionsEvalEngine.Verify(x => x.Eval( - It.IsAny>(), - It.IsAny>(), + It.IsAny(), + It.IsAny>(), It.Is(eo => eo == evaluationOptions)), Times.Never()); } - [Fact] - public void GetPriorityCriterias_GivenRulesEngineOptionsNewWithDefaults_ReturnsTopMostRuleWins() - { - // 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); - } - [Fact] public async Task GetUniqueConditionTypesAsync_GivenThereAreRulesInDataSource_ReturnsAllRequiredConditionTypes() { @@ -193,31 +174,25 @@ 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>>())) + mockConditionTypeExtractor.Setup(x => x.GetConditionTypes(It.IsAny>())) .Returns(expectedCondtionTypes); - this.SetupMockForConditionsEvalEngine((rootConditionNode, _, _) => + this.SetupMockForConditionsEvalEngine((rootConditionNode, _, _) => rootConditionNode switch { - switch (rootConditionNode) - { - case ValueConditionNode stringConditionNode: - return stringConditionNode.Operand.ToString() == "USA"; - - default: - return false; - } + ValueConditionNode stringConditionNode => stringConditionNode.Operand.ToString() == "USA", + _ => false, }, 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(mockConditionsEvalEngine.Object, mockRulesSource.Object, validatorProvider, rulesEngineOptions, mockConditionTypeExtractor.Object); // 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 +205,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(contentType, (t) => 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(contentType, (t) => 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(contentType, (t) => 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 +257,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(mockConditionsEvalEngine.Object, mockRulesSource.Object, validatorProvider, rulesEngineOptions, mockConditionTypeExtractor.Object); // 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()); + mockRulesSource.Verify(x => x.GetRulesAsync(It.IsAny()), Times.Once()); mockConditionsEvalEngine.Verify(x => x.Eval( - It.IsAny>(), - It.IsAny>(), + It.IsAny(), + It.IsAny>(), It.Is(eo => eo == evaluationOptions)), Times.AtLeastOnce()); } @@ -310,31 +285,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(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") + 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(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") + RootCondition = new ValueConditionNode(DataTypes.String, ConditionType.IsoCountryCode.ToString(), Operators.Equal, "USA") }; var rules = new[] @@ -357,17 +332,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(mockConditionsEvalEngine.Object, mockRulesSource.Object, validatorProvider, rulesEngineOptions, mockConditionTypeExtractor.Object); // Act var actual = await sut.MatchOneAsync(contentType, matchDateTime, conditions); // Assert actual.Should().BeSameAs(expected); - mockRulesSource.Verify(x => x.GetRulesAsync(It.IsAny>()), Times.Once()); + mockRulesSource.Verify(x => x.GetRulesAsync(It.IsAny()), Times.Once()); mockConditionsEvalEngine.Verify(x => x.Eval( - It.IsAny>(), - It.IsAny>(), + It.IsAny(), + It.IsAny>(), It.Is(eo => eo == evaluationOptions)), Times.AtLeastOnce()); } @@ -376,31 +351,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(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") + 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(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") + RootCondition = new ValueConditionNode(DataTypes.String, ConditionType.IsoCountryCode.ToString(), Operators.Equal, "USA") }; var rules = new[] @@ -421,17 +396,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(mockConditionsEvalEngine.Object, mockRulesSource.Object, validatorProvider, rulesEngineOptions, mockConditionTypeExtractor.Object); // Act var actual = await sut.MatchOneAsync(contentType, matchDateTime, conditions); // Assert actual.Should().BeSameAs(expected); - mockRulesSource.Verify(x => x.GetRulesAsync(It.IsAny>()), Times.Once()); + mockRulesSource.Verify(x => x.GetRulesAsync(It.IsAny()), Times.Once()); mockConditionsEvalEngine.Verify(x => x.Eval( - It.IsAny>(), - It.IsAny>(), + It.IsAny(), + It.IsAny>(), It.Is(eo => eo == evaluationOptions)), Times.AtLeastOnce()); } @@ -440,32 +415,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(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") + 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(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") + RootCondition = new ValueConditionNode(DataTypes.String,ConditionType.IsoCountryCode.ToString(), Operators.Equal, "USA") } }; @@ -481,17 +456,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(mockConditionsEvalEngine.Object, mockRulesSource.Object, validatorProvider, rulesEngineOptions, mockConditionTypeExtractor.Object); // Act var actual = await sut.MatchOneAsync(contentType, matchDateTime, conditions); // Assert actual.Should().BeNull(); - mockRulesSource.Verify(x => x.GetRulesAsync(It.IsAny>()), Times.Once()); + mockRulesSource.Verify(x => x.GetRulesAsync(It.IsAny()), Times.Once()); mockConditionsEvalEngine.Verify(x => x.Eval( - It.IsAny>(), - It.IsAny>(), + It.IsAny(), + It.IsAny>(), It.Is(eo => eo == evaluationOptions)), Times.AtLeastOnce()); } @@ -499,29 +474,29 @@ public async Task MatchOneAsync_GivenContentTypeDateAndConditions_FetchesRulesFo public async Task SearchAsync_GivenInvalidSearchArgs_ThrowsArgumentException() { // Arrange - var contentType = ContentType.Type1; + var contentType = ContentType.Type1.ToString(); var matchDateTime = new DateTime(2018, 07, 01, 18, 19, 30); - var searchArgs = new SearchArgs(contentType, matchDateTime, matchDateTime); + var searchArgs = new SearchArgs(contentType, matchDateTime, matchDateTime); var rules = new[] { - new Rule + new Rule { - ContentContainer = new ContentContainer(contentType, (t) => new object()), + 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") + 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(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") + RootCondition = new ValueConditionNode(DataTypes.String, ConditionType.IsoCountryCode.ToString(), Operators.Equal, "USA") } }; @@ -534,21 +509,21 @@ public async Task SearchAsync_GivenInvalidSearchArgs_ThrowsArgumentException() this.SetupMockForConditionsEvalEngine(false, evaluationOptions); - var validator = Mock.Of>>(); + var validator = Mock.Of>>(); Mock.Get(validator) - .Setup(x => x.ValidateAsync(It.IsAny>(), It.IsAny())) + .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>()) + .Setup(x => x.GetValidatorFor>()) .Returns(validator); var rulesEngineOptions = RulesEngineOptions.NewWithDefaults(); - var sut = new RulesEngine(mockConditionsEvalEngine.Object, mockRulesSource.Object, validatorProvider, rulesEngineOptions, mockCondtionTypeExtractor.Object); + var sut = new RulesEngine(mockConditionsEvalEngine.Object, mockRulesSource.Object, validatorProvider, rulesEngineOptions, mockConditionTypeExtractor.Object); // Act - var argumentException = await Assert.ThrowsAsync(() => sut.SearchAsync(searchArgs)).ConfigureAwait(false); + var argumentException = await Assert.ThrowsAsync(() => sut.SearchAsync(searchArgs)); // Assert argumentException.Should().NotBeNull(); @@ -560,28 +535,28 @@ public async Task SearchAsync_GivenInvalidSearchArgs_ThrowsArgumentException() public async Task SearchAsync_GivenNullSearchArgs_ThrowsArgumentNullException() { // Arrange - SearchArgs searchArgs = null; - var contentType = ContentType.Type1; + SearchArgs searchArgs = null; + var contentType = ContentType.Type1.ToString(); var rules = new[] { - new Rule + new Rule { - ContentContainer = new ContentContainer(contentType, (t) => new object()), + 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") + 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(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") + RootCondition = new ValueConditionNode(DataTypes.String, ConditionType.IsoCountryCode.ToString(), Operators.Equal, "USA") } }; @@ -596,10 +571,10 @@ public async Task SearchAsync_GivenNullSearchArgs_ThrowsArgumentNullException() var validatorProvider = Mock.Of(); var rulesEngineOptions = RulesEngineOptions.NewWithDefaults(); - var sut = new RulesEngine(mockConditionsEvalEngine.Object, mockRulesSource.Object, validatorProvider, rulesEngineOptions, mockCondtionTypeExtractor.Object); + var sut = new RulesEngine(mockConditionsEvalEngine.Object, mockRulesSource.Object, validatorProvider, rulesEngineOptions, mockConditionTypeExtractor.Object); // Act - var argumentNullException = await Assert.ThrowsAsync(() => sut.SearchAsync(searchArgs)).ConfigureAwait(false); + var argumentNullException = await Assert.ThrowsAsync(() => sut.SearchAsync(searchArgs)); // Assert argumentNullException.Should().NotBeNull(); @@ -610,16 +585,16 @@ public async Task SearchAsync_GivenNullSearchArgs_ThrowsArgumentNullException() public async Task UpdateRuleAsync_GivenEmptyRuleDataSource_UpdatesRuleSuccesfully() { // 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()), + 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") + RootCondition = new ValueConditionNode(DataTypes.String, ConditionType.IsoCountryCode.ToString(), Operators.Equal, "USA") }; var evaluationOptions = new EvaluationOptions @@ -627,28 +602,28 @@ public async Task UpdateRuleAsync_GivenEmptyRuleDataSource_UpdatesRuleSuccesfull MatchMode = MatchModes.Exact }; - mockRulesSource.Setup(s => s.GetRulesFilteredAsync(It.IsAny>())) - .ReturnsAsync(new List> { testRule }); + mockRulesSource.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(mockConditionsEvalEngine.Object, mockRulesSource.Object, validatorProvider, rulesEngineOptions, mockConditionTypeExtractor.Object); testRule.DateEnd = new DateTime(2019, 01, 02); 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(); - mockRulesSource.Verify(x => x.GetRulesFilteredAsync(It.IsAny>()), Times.Once()); + mockRulesSource.Verify(x => x.GetRulesFilteredAsync(It.IsAny()), Times.Once()); mockConditionsEvalEngine.Verify(x => x.Eval( - It.IsAny>(), - It.IsAny>(), + It.IsAny(), + It.IsAny>(), It.Is(eo => eo == evaluationOptions)), Times.Never()); } @@ -656,16 +631,16 @@ public async Task UpdateRuleAsync_GivenEmptyRuleDataSource_UpdatesRuleSuccesfull public async Task UpdateRuleAsync_GivenRuleWithInvalidDateEnd_UpdatesRuleFailure() { // 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()), + 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") + RootCondition = new ValueConditionNode(DataTypes.String, ConditionType.IsoCountryCode.ToString(), Operators.Equal, "USA") }; var evaluationOptions = new EvaluationOptions @@ -673,36 +648,36 @@ public async Task UpdateRuleAsync_GivenRuleWithInvalidDateEnd_UpdatesRuleFailure MatchMode = MatchModes.Exact }; - mockRulesSource.Setup(s => s.GetRulesFilteredAsync(It.IsAny>())) - .ReturnsAsync(new List> { testRule }); + mockRulesSource.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(mockConditionsEvalEngine.Object, mockRulesSource.Object, validatorProvider, rulesEngineOptions, mockConditionTypeExtractor.Object); 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().BeFalse(); actual.Errors.Should().NotBeEmpty(); - mockRulesSource.Verify(x => x.GetRulesFilteredAsync(It.IsAny>()), Times.Once()); + mockRulesSource.Verify(x => x.GetRulesFilteredAsync(It.IsAny()), Times.Once()); mockConditionsEvalEngine.Verify(x => x.Eval( - It.IsAny>(), - It.IsAny>(), + It.IsAny(), + It.IsAny>(), It.Is(eo => eo == evaluationOptions)), Times.Never()); } - private void SetupMockForConditionsEvalEngine(Func, IDictionary, EvaluationOptions, bool> evalFunc, EvaluationOptions evaluationOptions) + private void SetupMockForConditionsEvalEngine(Func, EvaluationOptions, bool> evalFunc, EvaluationOptions evaluationOptions) { this.mockConditionsEvalEngine.Setup(x => x.Eval( - It.IsAny>(), - It.IsAny>(), + It.IsAny(), + It.IsAny>(), It.Is(eo => eo == evaluationOptions))) .Returns(evalFunc); } @@ -710,15 +685,15 @@ private void SetupMockForConditionsEvalEngine(Func private void SetupMockForConditionsEvalEngine(bool result, EvaluationOptions evaluationOptions) { this.mockConditionsEvalEngine.Setup(x => x.Eval( - It.IsAny>(), - It.IsAny>(), + 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>())) + this.mockRulesSource.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..5cae9479 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,118 @@ public class RulesSourceTests public async Task AddRuleAsync_NoMiddlewares_CallsRulesDataSource() { // Arrange - Rule rule = CreateRule(); + Rule rule = CreateRule(); - AddRuleArgs addRuleArgs = new() + AddRuleArgs addRuleArgs = new() { Rule = rule, }; - IEnumerable> rulesSourceMiddlewares - = Enumerable.Empty>(); + IEnumerable rulesSourceMiddlewares + = Enumerable.Empty(); - IRulesDataSource rulesDataSource = Mock.Of>(); + IRulesDataSource 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(); + Rule 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>(); + IRulesDataSource 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(); + Rule 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>(); + IRulesDataSource 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 GetRulesAsync_NoMiddlewares_CallsRulesDataSource() { // Arrange - Rule rule = CreateRule(); + Rule rule = CreateRule(); var expected = new[] { rule }; - GetRulesArgs getRulesArgs = CreateGetRulesArgs(); + GetRulesArgs getRulesArgs = CreateGetRulesArgs(); - IEnumerable> rulesSourceMiddlewares - = Enumerable.Empty>(); + IEnumerable rulesSourceMiddlewares + = Enumerable.Empty(); - IRulesDataSource rulesDataSource = Mock.Of>(); + IRulesDataSource 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 +140,24 @@ IEnumerable> rulesSourceMiddl public async Task GetRulesAsync_OneMiddleware_CallsMiddlewareAndRulesDataSourceAfter() { // Arrange - Rule rule = CreateRule(); + Rule rule = CreateRule(); var expected = new[] { rule }; - GetRulesArgs getRulesArgs = CreateGetRulesArgs(); + GetRulesArgs 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>(); + IRulesDataSource 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 +171,26 @@ public async Task GetRulesAsync_OneMiddleware_CallsMiddlewareAndRulesDataSourceA public async Task GetRulesAsync_TwoMiddlewares_CallsFirstMiddlewareSecondMiddlewareAfterAndRulesDataSourceByLast() { // Arrange - Rule rule = CreateRule(); + Rule rule = CreateRule(); var expected = new[] { rule }; - GetRulesArgs getRulesArgs = CreateGetRulesArgs(); + GetRulesArgs 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>(); + IRulesDataSource 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 +206,30 @@ public async Task GetRulesAsync_TwoMiddlewares_CallsFirstMiddlewareSecondMiddlew public async Task GetRulesFilteredAsync_NoMiddlewares_CallsRulesDataSource() { // Arrange - Rule rule = CreateRule(); + Rule rule = CreateRule(); var expected = new[] { rule }; - GetRulesFilteredArgs getRulesFilteredArgs = CreateGetRulesFilteredArgs(); + GetRulesFilteredArgs getRulesFilteredArgs = CreateGetRulesFilteredArgs(); - IEnumerable> rulesSourceMiddlewares - = Enumerable.Empty>(); + IEnumerable rulesSourceMiddlewares + = Enumerable.Empty(); - IRulesDataSource rulesDataSource = Mock.Of>(); + IRulesDataSource 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 +237,32 @@ IEnumerable> rulesSourceMiddl public async Task GetRulesFilteredAsync_OneMiddleware_CallsMiddlewareAndRulesDataSourceAfter() { // Arrange - Rule rule = CreateRule(); + Rule rule = CreateRule(); var expected = new[] { rule }; - GetRulesFilteredArgs getRulesFilteredArgs = CreateGetRulesFilteredArgs(); + GetRulesFilteredArgs 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>(); + IRulesDataSource 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 +270,27 @@ public async Task GetRulesFilteredAsync_OneMiddleware_CallsMiddlewareAndRulesDat public async Task GetRulesFilteredAsync_TwoMiddlewares_CallsFirstMiddlewareSecondMiddlewareAfterAndRulesDataSourceByLast() { // Arrange - Rule rule = CreateRule(); + Rule rule = CreateRule(); var expected = new[] { rule }; - GetRulesFilteredArgs getRulesFilteredArgs = CreateGetRulesFilteredArgs(); + GetRulesFilteredArgs 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>(); + IRulesDataSource 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 +299,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 +307,116 @@ public async Task GetRulesFilteredAsync_TwoMiddlewares_CallsFirstMiddlewareSecon public async Task UpdateRuleAsync_NoMiddlewares_CallsRulesDataSource() { // Arrange - Rule rule = CreateRule(); + Rule rule = CreateRule(); - UpdateRuleArgs updateRuleArgs = new() + UpdateRuleArgs updateRuleArgs = new() { Rule = rule, }; - IEnumerable> rulesSourceMiddlewares - = Enumerable.Empty>(); + IEnumerable rulesSourceMiddlewares + = Enumerable.Empty(); - IRulesDataSource rulesDataSource = Mock.Of>(); + IRulesDataSource 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(); + Rule 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>(); + IRulesDataSource 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(); + Rule 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>(); + IRulesDataSource 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..20238275 100644 --- a/tests/Rules.Framework.Tests/Source/StubRulesSourceMiddleware.cs +++ b/tests/Rules.Framework.Tests/Source/StubRulesSourceMiddleware.cs @@ -8,25 +8,25 @@ namespace Rules.Framework.Tests.Source using System.Text; using System.Threading.Tasks; - 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 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 +34,9 @@ public async Task HandleAddRuleAsync( this.middlewareMessages.Add($"Exit {this.Name}."); } - public async Task>> HandleGetRulesAsync( - GetRulesArgs args, - GetRulesDelegate next) + public async Task> HandleGetRulesAsync( + GetRulesArgs args, + GetRulesDelegate next) { this.GetRulesCalls++; this.middlewareMessages.Add($"Enter {this.Name}."); @@ -45,9 +45,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 +57,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 +66,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 4fc5d7bae42311656d292d20549e6c33d90354ef Mon Sep 17 00:00:00 2001 From: Luis Garces Date: Fri, 19 Jul 2024 19:49:40 +0100 Subject: [PATCH 2/5] chore: change var style rules for C# --- .editorconfig | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) 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 From 04ec3aec5a1b083088a75e2aee9309e61f22968a Mon Sep 17 00:00:00 2001 From: Luis Garces Date: Sun, 18 Aug 2024 15:20:41 +0100 Subject: [PATCH 3/5] feat!: add APIs to create content types --- .../Engine/IContentTypes.cs | 3 + .../Engine/RulesBuilder.cs | 4 +- .../Rules/TestNumberRules.cs | 2 + .../Engine/IContentTypes.cs | 3 + .../Engine/RulesBuilder.cs | 7 +- .../Rules/RulesRandomFactory.cs | 12 + .../DataModel/ContentTypeDataModel.cs | 17 + .../MongoDbProviderRulesDataSource.cs | 42 +- .../MongoDbProviderSettings.cs | 24 +- .../RuleFactory.cs | 6 +- .../Builder/Generic/RuleBuilder.cs | 56 +- src/Rules.Framework/Builder/RuleBuilder.cs | 12 +- src/Rules.Framework/ContentContainer.cs | 11 +- src/Rules.Framework/Core/ContentContainer.cs | 50 -- .../CompilationRulesSourceMiddleware.cs | 8 +- src/Rules.Framework/Generic/IRulesEngine.cs | 120 +++- src/Rules.Framework/Generic/Rule.cs | 49 +- src/Rules.Framework/Generic/RulesEngine.cs | 120 +--- src/Rules.Framework/IRulesDataSource.cs | 12 +- src/Rules.Framework/IRulesEngine.cs | 119 +++- src/Rules.Framework/IRulesEngineOptions.cs | 12 +- src/Rules.Framework/OperationResult.cs | 49 ++ .../InMemory/IInMemoryRulesStorage.cs | 2 + .../InMemoryProviderRulesDataSource.cs | 34 +- .../InMemory/InMemoryRulesStorage.cs | 13 +- .../Providers/InMemory/RuleFactory.cs | 7 +- src/Rules.Framework/Rule.cs | 6 + src/Rules.Framework/RuleOperationResult.cs | 51 -- src/Rules.Framework/RulesEngine.cs | 186 +++--- src/Rules.Framework/RulesEngineOptions.cs | 31 +- .../SerializedContentContainer.cs | 2 +- .../Source/CreateContentTypeArgs.cs | 7 + .../Source/CreateContentTypeDelegate.cs | 6 + .../Source/GetContentTypesArgs.cs | 6 + .../Source/GetContentTypesDelegate.cs | 7 + src/Rules.Framework/Source/IRulesSource.cs | 4 +- .../Source/IRulesSourceMiddleware.cs | 8 + src/Rules.Framework/Source/RulesSource.cs | 63 +- .../Rules.Framework.BenchmarkTests/Program.cs | 2 +- .../Rules.Framework.BenchmarkTests.csproj | 4 +- .../Tests/Benchmark1/Benchmark1.cs | 4 +- .../Tests/Benchmark2/Benchmark2.cs | 2 + .../Tests/Benchmark3/Benchmark3.cs | 2 + .../Scenarios/ScenarioLoader.cs | 6 + .../RulesFromJsonFile.cs | 6 + .../Scenarios/Scenario1/BodyMassIndexTests.cs | 2 + .../Scenario4/DiscountCampaignTests.cs | 6 + .../Scenarios/Scenario5/BestServerTests.cs | 4 + .../RulesEngine/RulesEngineTestsBase.cs | 9 +- .../RulesMatching/RulesInSequenceTests.cs | 2 +- .../Scenarios/Scenario5/BestServerTests.cs | 1 + .../RulesEngine/RulesEngineTestsBase.cs | 1 + .../RulesMatching/RulesInSequenceTests.cs | 2 +- .../Scenario2/CarInsuranceAdvisorTests.cs | 20 +- .../BuildingSecuritySystemControlTests.cs | 21 +- .../Scenarios/Scenario5/BestServerTests.cs | 1 + .../MongoDbProviderRulesDataSourceTests.cs | 99 ++++ .../Builder/RuleBuilderTests.cs | 5 +- .../ConditionTypeExtractorTests.cs | 10 +- .../{Core => }/ContentContainerTests.cs | 25 +- .../Extensions/GenericRuleExtensionsTests.cs | 10 +- .../Generic/RulesEngineTests.cs | 109 +++- .../RuleOperationResultTests.cs | 6 +- tests/Rules.Framework.Tests/RuleTests.cs | 6 +- .../Rules.Framework.Tests/RulesEngineTests.cs | 542 ++++++++++++------ .../Source/RulesSourceTests.cs | 255 ++++++-- .../Source/StubRulesSourceMiddleware.cs | 27 +- 67 files changed, 1631 insertions(+), 729 deletions(-) create mode 100644 src/Rules.Framework.Providers.MongoDb/DataModel/ContentTypeDataModel.cs delete mode 100644 src/Rules.Framework/Core/ContentContainer.cs create mode 100644 src/Rules.Framework/OperationResult.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 => }/ContentContainerTests.cs (55%) 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/RulesBuilder.cs b/samples/Rules.Framework.InMemory.Sample/Engine/RulesBuilder.cs index 7204d987..82d8bca7 100644 --- a/samples/Rules.Framework.InMemory.Sample/Engine/RulesBuilder.cs +++ b/samples/Rules.Framework.InMemory.Sample/Engine/RulesBuilder.cs @@ -14,6 +14,8 @@ 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) @@ -27,7 +29,7 @@ public async Task BuildAsync(IRulesEngine rulesEngine) .AddRuleAsync( ruleSpecification.RuleBuilderResult.Rule, ruleSpecification.RuleAddPriorityOption - ).ConfigureAwait(false); + ); if (!ruleOperationResult.IsSuccess) { diff --git a/samples/Rules.Framework.InMemory.Sample/Rules/TestNumberRules.cs b/samples/Rules.Framework.InMemory.Sample/Rules/TestNumberRules.cs index 417fff83..5409f683 100644 --- a/samples/Rules.Framework.InMemory.Sample/Rules/TestNumberRules.cs +++ b/samples/Rules.Framework.InMemory.Sample/Rules/TestNumberRules.cs @@ -15,6 +15,8 @@ public TestNumberRules() this.rulesSpecifications = new List(); } + public ContentTypes ContentType => ContentTypes.TestNumber; + public IEnumerable GetRulesSpecifications() { Add(CreateRuleForCoolNumbers(), RuleAddPriorityOption.ByPriorityNumber(3)); 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/RulesBuilder.cs b/samples/Rules.Framework.WebUI.Sample/Engine/RulesBuilder.cs index 6b1596a2..d0587bdd 100644 --- a/samples/Rules.Framework.WebUI.Sample/Engine/RulesBuilder.cs +++ b/samples/Rules.Framework.WebUI.Sample/Engine/RulesBuilder.cs @@ -14,6 +14,11 @@ 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) @@ -27,7 +32,7 @@ public async Task BuildAsync(IRulesEngine rulesEngine) .AddRuleAsync( ruleSpecification.RuleBuilderResult.Rule, ruleSpecification.RuleAddPriorityOption - ).ConfigureAwait(false); + ); if (!ruleOperationResult.IsSuccess) { diff --git a/samples/Rules.Framework.WebUI.Sample/Rules/RulesRandomFactory.cs b/samples/Rules.Framework.WebUI.Sample/Rules/RulesRandomFactory.cs index 750a8998..de6c24c0 100644 --- a/samples/Rules.Framework.WebUI.Sample/Rules/RulesRandomFactory.cs +++ b/samples/Rules.Framework.WebUI.Sample/Rules/RulesRandomFactory.cs @@ -17,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; 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/MongoDbProviderRulesDataSource.cs b/src/Rules.Framework.Providers.MongoDb/MongoDbProviderRulesDataSource.cs index 28fdddee..f027618f 100644 --- a/src/Rules.Framework.Providers.MongoDb/MongoDbProviderRulesDataSource.cs +++ b/src/Rules.Framework.Providers.MongoDb/MongoDbProviderRulesDataSource.cs @@ -45,7 +45,41 @@ public async Task AddRuleAsync(Rule rule) await rulesCollection.InsertOneAsync(ruleDataModel).ConfigureAwait(false); } - public Task> GetContentTypesAsync() => throw new NotImplementedException(); + /// + /// 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 @@ -112,7 +146,7 @@ public async Task UpdateRuleAsync(Rule rule) 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), @@ -130,7 +164,7 @@ private static FilterDefinition BuildFilterFromRulesFilterArgs(Ru 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)) @@ -158,7 +192,7 @@ private async Task> GetRulesAsync(FilterDefinition 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/RuleFactory.cs b/src/Rules.Framework.Providers.MongoDb/RuleFactory.cs index a354a078..d6e6f94b 100644 --- a/src/Rules.Framework.Providers.MongoDb/RuleFactory.cs +++ b/src/Rules.Framework.Providers.MongoDb/RuleFactory.cs @@ -57,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, @@ -85,7 +85,7 @@ private static IConditionNode ConvertConditionNode(ConditionNodeDataModel condit var childConditionNodeDataModels = composedConditionNodeDataModel.ChildConditionNodes; var count = childConditionNodeDataModels.Length; var childConditionNodes = new IConditionNode[count]; - for (int i = 0; i < count; i++) + for (var i = 0; i < count; i++) { childConditionNodes[i] = ConvertConditionNode(childConditionNodeDataModels[i]); } diff --git a/src/Rules.Framework/Builder/Generic/RuleBuilder.cs b/src/Rules.Framework/Builder/Generic/RuleBuilder.cs index 36599dc9..bcda47ad 100644 --- a/src/Rules.Framework/Builder/Generic/RuleBuilder.cs +++ b/src/Rules.Framework/Builder/Generic/RuleBuilder.cs @@ -10,51 +10,42 @@ namespace Rules.Framework.Builder.Generic internal sealed class RuleBuilder : IRuleBuilder { private readonly GenericRuleValidator genericRuleValidator = GenericRuleValidator.Instance; - private readonly RuleValidator ruleValidator = RuleValidator.Instance; - private bool? active; - private ContentContainer contentContainer; - private DateTime dateBegin; - private DateTime? dateEnd; - private string name; - private IConditionNode rootCondition; + private readonly RuleBuilder ruleBuilder; - public RuleBuilderResult Build() + public RuleBuilder() { - var rule = new Rule - { - ContentContainer = this.contentContainer, - DateBegin = this.dateBegin, - DateEnd = this.dateEnd, - Name = this.name, - RootCondition = this.rootCondition, - Active = this.active ?? true, - }; + this.ruleBuilder = new RuleBuilder(); + } - var validationResult = this.ruleValidator.Validate(rule); + public RuleBuilderResult Build() + { + var ruleBuilderResult = this.ruleBuilder.Build(); - if (validationResult.IsValid) + if (ruleBuilderResult.IsSuccess) { - var genericRule = new Rule(rule); - validationResult = this.genericRuleValidator.Validate(genericRule); + 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(validationResult.Errors.Select(ve => ve.ErrorMessage).ToList()); + return RuleBuilderResult.Failure(ruleBuilderResult.Errors); } public IRuleBuilder WithActive(bool active) { - this.active = active; + this.ruleBuilder.WithActive(active); return this; } public IRuleBuilder WithCondition(IConditionNode condition) { - this.rootCondition = condition; + this.ruleBuilder.WithCondition(condition); return this; } @@ -81,30 +72,28 @@ public IRuleBuilder WithCondition( public IRuleBuilder WithContent(TContentType contentType, object content) { - var contentTypeAsString = GenericConversions.Convert(contentType); - this.contentContainer = new ContentContainer(contentTypeAsString, _ => content); + this.ruleBuilder.WithContent(GenericConversions.Convert(contentType), content); return this; } public IRuleBuilder WithDateBegin(DateTime dateBegin) { - this.dateBegin = dateBegin; + this.ruleBuilder.WithDateBegin(dateBegin); return this; } public IRuleBuilder WithDatesInterval(DateTime dateBegin, DateTime? dateEnd) { - this.dateBegin = dateBegin; - this.dateEnd = dateEnd; + this.ruleBuilder.WithDatesInterval(dateBegin, dateEnd); return this; } public IRuleBuilder WithName(string name) { - this.name = name; + this.ruleBuilder.WithName(name); return this; } @@ -114,13 +103,8 @@ public IRuleBuilder WithSerializedContent( object serializedContent, IContentSerializationProvider contentSerializationProvider) { - if (contentSerializationProvider is null) - { - throw new ArgumentNullException(nameof(contentSerializationProvider)); - } - var contentTypeAsString = GenericConversions.Convert(contentType); - this.contentContainer = new SerializedContentContainer(contentTypeAsString, serializedContent, contentSerializationProvider); + this.ruleBuilder.WithSerializedContent(contentTypeAsString, serializedContent, contentSerializationProvider); return this; } diff --git a/src/Rules.Framework/Builder/RuleBuilder.cs b/src/Rules.Framework/Builder/RuleBuilder.cs index e9118276..a687a4fd 100644 --- a/src/Rules.Framework/Builder/RuleBuilder.cs +++ b/src/Rules.Framework/Builder/RuleBuilder.cs @@ -3,7 +3,6 @@ namespace Rules.Framework.Builder using System; using System.Linq; using Rules.Framework.Builder.Validation; - using Rules.Framework.Generic; using Rules.Framework.Serialization; internal sealed class RuleBuilder : IRuleBuilder @@ -14,6 +13,8 @@ internal sealed class RuleBuilder : IRuleBuilder private ContentContainer contentContainer; + private string contentType; + private DateTime dateBegin; private DateTime? dateEnd; @@ -27,6 +28,7 @@ public RuleBuilderResult Build() var rule = new Rule { ContentContainer = this.contentContainer, + ContentType = this.contentType, DateBegin = this.dateBegin, DateEnd = this.dateEnd, Name = this.name, @@ -79,8 +81,8 @@ public IRuleBuilder WithCondition( public IRuleBuilder WithContent(string contentType, object content) { - var contentTypeAsString = GenericConversions.Convert(contentType); - this.contentContainer = new ContentContainer(contentTypeAsString, _ => content); + this.contentType = contentType; + this.contentContainer = new ContentContainer(_ => content); return this; } @@ -116,8 +118,8 @@ public IRuleBuilder WithSerializedContent( throw new ArgumentNullException(nameof(contentSerializationProvider)); } - var contentTypeAsString = GenericConversions.Convert(contentType); - this.contentContainer = new SerializedContentContainer(contentTypeAsString, serializedContent, contentSerializationProvider); + this.contentType = contentType; + this.contentContainer = new SerializedContentContainer(contentType, serializedContent, contentSerializationProvider); return this; } diff --git a/src/Rules.Framework/ContentContainer.cs b/src/Rules.Framework/ContentContainer.cs index d44f58a9..da7377cf 100644 --- a/src/Rules.Framework/ContentContainer.cs +++ b/src/Rules.Framework/ContentContainer.cs @@ -12,23 +12,14 @@ public class ContentContainer /// /// Creates a new . /// - /// the content type. /// /// the function used to fetch content casted to provided type. /// - public ContentContainer(string contentType, Func getContentFunc) + public ContentContainer(Func getContentFunc) { - this.ContentType = contentType; this.getContentFunc = getContentFunc; } - /// - /// Gets the content type. - /// - public string ContentType { get; } - - internal Func ContentFunc => this.getContentFunc; - /// /// Gets the content from container casted/converted to specified . /// diff --git a/src/Rules.Framework/Core/ContentContainer.cs b/src/Rules.Framework/Core/ContentContainer.cs deleted file mode 100644 index 64c0321c..00000000 --- a/src/Rules.Framework/Core/ContentContainer.cs +++ /dev/null @@ -1,50 +0,0 @@ -namespace Rules.Framework.Core -{ - using System; - - /// - /// Defines a content container with lazily loaded content. - /// - /// - public class ContentContainer - { - private readonly Func getContentFunc; - - /// - /// Creates a new . - /// - /// the content type. - /// - /// the function used to fetch content casted to provided type. - /// - public ContentContainer(TContentType contentType, Func getContentFunc) - { - this.ContentType = contentType; - this.getContentFunc = getContentFunc; - } - - /// - /// Gets the content type. - /// - public TContentType ContentType { get; } - - internal Func ContentFunc => this.getContentFunc; - - /// - /// Gets the content from container casted/converted to specified . - /// - /// the type to convert/cast content. - /// the converted/casted content. - public TContent GetContentAs() - { - try - { - return (TContent)this.getContentFunc.Invoke(typeof(TContent)); - } - catch (InvalidCastException ice) - { - throw new ContentTypeException($"Cannot cast content to provided type as {nameof(TContent)}: {typeof(TContent).FullName}", ice); - } - } - } -} \ No newline at end of file diff --git a/src/Rules.Framework/Evaluation/Compiled/CompilationRulesSourceMiddleware.cs b/src/Rules.Framework/Evaluation/Compiled/CompilationRulesSourceMiddleware.cs index f9688df3..15ccf81b 100644 --- a/src/Rules.Framework/Evaluation/Compiled/CompilationRulesSourceMiddleware.cs +++ b/src/Rules.Framework/Evaluation/Compiled/CompilationRulesSourceMiddleware.cs @@ -27,6 +27,10 @@ public async Task HandleAddRuleAsync( await next.Invoke(args).ConfigureAwait(false); } + 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) @@ -35,7 +39,7 @@ public async Task> HandleGetRulesAsync( 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, @@ -55,7 +59,7 @@ public async Task> HandleGetRulesFilteredAsync( 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, diff --git a/src/Rules.Framework/Generic/IRulesEngine.cs b/src/Rules.Framework/Generic/IRulesEngine.cs index 4ee3f392..ec1e679b 100644 --- a/src/Rules.Framework/Generic/IRulesEngine.cs +++ b/src/Rules.Framework/Generic/IRulesEngine.cs @@ -4,15 +4,60 @@ namespace Rules.Framework.Generic 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; } - Task ActivateRuleAsync(Rule rule); + /// + /// 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); - Task AddRuleAsync(Rule rule, RuleAddPriorityOption ruleAddPriorityOption); + /// + /// 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); - Task DeactivateRuleAsync(Rule rule); + /// + /// 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. @@ -20,14 +65,81 @@ public interface IRulesEngine /// 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); - Task UpdateRuleAsync(Rule rule); + /// + /// 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 index a6e4a823..28be4616 100644 --- a/src/Rules.Framework/Generic/Rule.cs +++ b/src/Rules.Framework/Generic/Rule.cs @@ -1,7 +1,6 @@ namespace Rules.Framework.Generic { using System; - using Rules.Framework.Core; /// /// Defines a rule. @@ -15,14 +14,8 @@ public class Rule private static readonly Type stringType = typeof(string); private readonly Rule wrappedRule; - private ContentContainer? contentContainer; private IConditionNode? rootCondition; - internal Rule() - : this(new Rule()) - { - } - internal Rule(Rule wrappedRule) { var typeForContentType = typeof(TContentType); @@ -41,42 +34,24 @@ internal Rule(Rule wrappedRule) } /// - /// Gets and sets the if the rules is active. + /// Gets if the rule is active. /// - public bool Active - { - get => this.wrappedRule.Active; - internal set => this.wrappedRule.Active = value; - } + public bool Active => this.wrappedRule.Active; /// /// Gets the content container which contains the rule content. /// - public ContentContainer ContentContainer - { - get - { - this.contentContainer ??= new ContentContainer( - GenericConversions.Convert(this.wrappedRule.ContentContainer.ContentType), - this.wrappedRule.ContentContainer.ContentFunc); + public ContentContainer ContentContainer => this.wrappedRule.ContentContainer; - return this.contentContainer; - } - internal set - { - this.contentContainer = value; - this.wrappedRule.ContentContainer = new ContentContainer(GenericConversions.Convert(value.ContentType), value.ContentFunc); - } - } + /// + /// 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 - { - get => this.wrappedRule.DateBegin; - internal set => this.wrappedRule.DateBegin = value; - } + public DateTime DateBegin => this.wrappedRule.DateBegin; /// /// Gets and sets the date from which the rule ceases to be applicable. @@ -90,11 +65,7 @@ public DateTime? DateEnd /// /// Gets the rule name. /// - public string Name - { - get => this.wrappedRule.Name; - internal set => this.wrappedRule.Name = value; - } + public string Name => this.wrappedRule.Name; /// /// Gets and sets the rule priority compared to other rules (preferably it is unique). @@ -113,7 +84,7 @@ public IConditionNode RootCondition get { this.rootCondition ??= this.wrappedRule.RootCondition?.ToGenericConditionNode(); - return this.rootCondition; + return this.rootCondition!; } } diff --git a/src/Rules.Framework/Generic/RulesEngine.cs b/src/Rules.Framework/Generic/RulesEngine.cs index 2dd045e9..f0d2b003 100644 --- a/src/Rules.Framework/Generic/RulesEngine.cs +++ b/src/Rules.Framework/Generic/RulesEngine.cs @@ -23,65 +23,53 @@ internal RulesEngine(IRulesEngine wrappedRulesEngine) this.wrappedRulesEngine = wrappedRulesEngine; } + /// public IRulesEngineOptions Options => this.wrappedRulesEngine.Options; - /// - /// Activates the specified existing rule. - /// - /// The rule. - /// - /// rule - public Task ActivateRuleAsync(Rule rule) + /// + 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); } - /// - /// 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) { throw new ArgumentNullException(nameof(rule)); } - if (ruleAddPriorityOption is null) - { - throw new ArgumentNullException(nameof(rule)); - } - + // Implicit conversion from Rule to Rule. return this.wrappedRulesEngine.AddRuleAsync(rule, ruleAddPriorityOption); } - /// - /// Deactivates the specified existing rule. - /// - /// The rule. - /// - /// rule - public Task DeactivateRuleAsync(Rule rule) + /// + 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); @@ -89,20 +77,7 @@ public async Task> GetContentTypesAsync() return contentTypes.Select(x => GenericConversions.Convert(x)).ToArray(); } - /// - /// 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) { var contentTypeAsString = GenericConversions.Convert(contentType); @@ -110,21 +85,7 @@ public async Task> GetUniqueConditionTypesAsync(TCon return conditionTypes.Select(t => GenericConversions.Convert(t)).ToArray(); } - /// - /// 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, DateTime matchDateTime, @@ -141,24 +102,7 @@ public async Task>> MatchManyAsyn return rules.Select(r => r.ToGenericRule()).ToArray(); } - /// - /// 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, DateTime matchDateTime, @@ -175,17 +119,7 @@ public async Task> MatchOneAsync( return rule?.ToGenericRule()!; } - /// - /// 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) { if (searchArgs is null) @@ -205,19 +139,15 @@ public async Task>> SearchAsync(S return rules.Select(r => r.ToGenericRule()).ToArray(); } - /// - /// Updates the specified existing rule. - /// - /// The rule. - /// - /// rule - public Task UpdateRuleAsync(Rule rule) + /// + 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); } } diff --git a/src/Rules.Framework/IRulesDataSource.cs b/src/Rules.Framework/IRulesDataSource.cs index a8b22eaa..4629f841 100644 --- a/src/Rules.Framework/IRulesDataSource.cs +++ b/src/Rules.Framework/IRulesDataSource.cs @@ -3,7 +3,6 @@ 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 content type. @@ -17,6 +16,17 @@ public interface IRulesDataSource /// Task AddRuleAsync(Rule rule); + /// + /// 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(); /// diff --git a/src/Rules.Framework/IRulesEngine.cs b/src/Rules.Framework/IRulesEngine.cs index 2bbde3ec..c2618b0b 100644 --- a/src/Rules.Framework/IRulesEngine.cs +++ b/src/Rules.Framework/IRulesEngine.cs @@ -4,15 +4,59 @@ namespace Rules.Framework using System.Collections.Generic; using System.Threading.Tasks; + /// + /// The engine that holds the logic to match and manage rules. + /// public interface IRulesEngine { + /// + /// Gets the options. + /// + /// The options. IRulesEngineOptions Options { get; } - Task ActivateRuleAsync(Rule rule); + /// + /// 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 AddRuleAsync(Rule rule, RuleAddPriorityOption ruleAddPriorityOption); + /// + /// 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 DeactivateRuleAsync(Rule rule); + /// + /// 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); + + /// + /// 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); /// /// Gets the content types. @@ -20,14 +64,81 @@ public interface IRulesEngine /// 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(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); - Task UpdateRuleAsync(Rule rule); + /// + /// 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 1b5182e8..9fbd22e9 100644 --- a/src/Rules.Framework/IRulesEngineOptions.cs +++ b/src/Rules.Framework/IRulesEngineOptions.cs @@ -1,13 +1,21 @@ namespace Rules.Framework { - using System; using System.Collections.Generic; /// - /// 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/OperationResult.cs b/src/Rules.Framework/OperationResult.cs new file mode 100644 index 00000000..7a524d7e --- /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 Error(string error) => Error(new[] { error }); + + internal static OperationResult Error(IEnumerable errors) + { + if (errors is null) + { + throw new ArgumentNullException(nameof(errors)); + } + + return new OperationResult(false, errors); + } + + internal static OperationResult Success() => new OperationResult(true, Enumerable.Empty()); + } +} \ No newline at end of file diff --git a/src/Rules.Framework/Providers/InMemory/IInMemoryRulesStorage.cs b/src/Rules.Framework/Providers/InMemory/IInMemoryRulesStorage.cs index f860fce7..2ed20e4f 100644 --- a/src/Rules.Framework/Providers/InMemory/IInMemoryRulesStorage.cs +++ b/src/Rules.Framework/Providers/InMemory/IInMemoryRulesStorage.cs @@ -7,6 +7,8 @@ internal interface IInMemoryRulesStorage { void AddRule(RuleDataModel ruleDataModel); + void CreateContentType(string contentType); + IReadOnlyCollection GetAllRules(); IReadOnlyCollection GetContentTypes(); diff --git a/src/Rules.Framework/Providers/InMemory/InMemoryProviderRulesDataSource.cs b/src/Rules.Framework/Providers/InMemory/InMemoryProviderRulesDataSource.cs index 10d84b53..0179fe16 100644 --- a/src/Rules.Framework/Providers/InMemory/InMemoryProviderRulesDataSource.cs +++ b/src/Rules.Framework/Providers/InMemory/InMemoryProviderRulesDataSource.cs @@ -2,8 +2,8 @@ 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. @@ -42,6 +42,38 @@ 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()); diff --git a/src/Rules.Framework/Providers/InMemory/InMemoryRulesStorage.cs b/src/Rules.Framework/Providers/InMemory/InMemoryRulesStorage.cs index 63758d93..01f37eeb 100644 --- a/src/Rules.Framework/Providers/InMemory/InMemoryRulesStorage.cs +++ b/src/Rules.Framework/Providers/InMemory/InMemoryRulesStorage.cs @@ -17,7 +17,7 @@ public InMemoryRulesStorage() public void AddRule(RuleDataModel ruleDataModel) { - List contentTypeRules = GetRulesCollectionByContentType(ruleDataModel.ContentType); + var contentTypeRules = GetRulesCollectionByContentType(ruleDataModel.ContentType); lock (contentTypeRules) { @@ -30,6 +30,11 @@ public void AddRule(RuleDataModel ruleDataModel) } } + public void CreateContentType(string contentType) + { + _ = this.rulesByContentType.TryAdd(contentType, new List()); + } + public IReadOnlyCollection GetAllRules() => this.rulesByContentType.SelectMany(kvp => kvp.Value).ToList().AsReadOnly(); @@ -38,18 +43,18 @@ public IReadOnlyCollection GetContentTypes() public IReadOnlyCollection GetRulesBy(string contentType) { - List contentTypeRules = GetRulesCollectionByContentType(contentType); + var contentTypeRules = GetRulesCollectionByContentType(contentType); return contentTypeRules.AsReadOnly(); } 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."); diff --git a/src/Rules.Framework/Providers/InMemory/RuleFactory.cs b/src/Rules.Framework/Providers/InMemory/RuleFactory.cs index 89e7bc2f..6e23b227 100644 --- a/src/Rules.Framework/Providers/InMemory/RuleFactory.cs +++ b/src/Rules.Framework/Providers/InMemory/RuleFactory.cs @@ -17,12 +17,13 @@ public Rule CreateRule(RuleDataModel ruleDataModel) throw new ArgumentNullException(nameof(ruleDataModel)); } - var contentContainer = new ContentContainer(ruleDataModel.ContentType, (_) => ruleDataModel.Content); + var contentContainer = new ContentContainer((_) => ruleDataModel.Content); var rule = new Rule { Active = ruleDataModel.Active, ContentContainer = contentContainer, + ContentType = ruleDataModel.ContentType, DateBegin = ruleDataModel.DateBegin, DateEnd = ruleDataModel.DateEnd, Name = ruleDataModel.Name, @@ -45,7 +46,7 @@ public RuleDataModel CreateRule(Rule rule) var ruleDataModel = new RuleDataModel { Content = content, - ContentType = rule.ContentContainer.ContentType, + ContentType = rule.ContentType, DateBegin = rule.DateBegin, DateEnd = rule.DateEnd, Name = rule.Name, @@ -112,7 +113,7 @@ private ConditionNodeDataModel ConvertComposedConditionNode(ComposedConditionNod 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); } diff --git a/src/Rules.Framework/Rule.cs b/src/Rules.Framework/Rule.cs index 0000e63e..d4db94af 100644 --- a/src/Rules.Framework/Rule.cs +++ b/src/Rules.Framework/Rule.cs @@ -19,6 +19,11 @@ public class Rule /// 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. /// @@ -67,6 +72,7 @@ public static IRuleBuilder New() public virtual Rule Clone() => new Rule { + ContentType = this.ContentType, ContentContainer = this.ContentContainer, DateBegin = this.DateBegin, DateEnd = this.DateEnd, 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 9c97d211..a8a06a62 100644 --- a/src/Rules.Framework/RulesEngine.cs +++ b/src/Rules.Framework/RulesEngine.cs @@ -39,19 +39,11 @@ internal RulesEngine( this.conditionTypeExtractor = conditionTypeExtractor; } - /// - /// Gets the rules engine options. - /// - /// The rules engine options. + /// public IRulesEngineOptions Options { get; } - /// - /// Activates the specified existing rule. - /// - /// The rule. - /// - /// rule - public Task ActivateRuleAsync(Rule rule) + /// + public Task ActivateRuleAsync(Rule rule) { if (rule is null) { @@ -63,17 +55,8 @@ public Task ActivateRuleAsync(Rule rule) return this.UpdateRuleInternalAsync(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 rule, RuleAddPriorityOption r 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.Error($"The content type '{contentType}' already exists."); + } + + return await this.CreateContentTypeInternalAsync(contentType).ConfigureAwait(false); + } + + /// + public Task DeactivateRuleAsync(Rule rule) { if (rule is null) { @@ -106,27 +102,20 @@ public Task DeactivateRuleAsync(Rule rule) return this.UpdateRuleInternalAsync(rule); } + /// public Task> GetContentTypesAsync() { - return this.rulesSource.GetContentTypesAsync(); + 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(string contentType, DateTime dateBegin, DateTime dateEnd) { + if (string.IsNullOrWhiteSpace(contentType)) + { + throw new ArgumentNullException(nameof(contentType)); + } + var getRulesArgs = new GetRulesArgs { ContentType = contentType, @@ -139,26 +128,17 @@ public async Task> GetUniqueConditionTypesAsync(string conte 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( string contentType, DateTime matchDateTime, IEnumerable> conditions) { + if (string.IsNullOrWhiteSpace(contentType)) + { + throw new ArgumentNullException(nameof(contentType)); + } + var evaluationOptions = new EvaluationOptions { ExcludeRulesWithoutSearchConditions = false, @@ -172,34 +152,22 @@ public async Task> MatchManyAsync( 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( string contentType, DateTime matchDateTime, IEnumerable> conditions) { + if (string.IsNullOrWhiteSpace(contentType)) + { + throw new ArgumentNullException(nameof(contentType)); + } + var evaluationOptions = new EvaluationOptions { ExcludeRulesWithoutSearchConditions = false, @@ -220,17 +188,7 @@ public async Task MatchOneAsync( : 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) { if (searchArgs is null) @@ -273,13 +231,8 @@ public async Task> SearchAsync(SearchArgs sear 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) { @@ -289,12 +242,26 @@ public Task UpdateRuleAsync(Rule rule) return this.UpdateRuleInternalAsync(rule); } - private async Task AddRuleInternalAsync(Rule rule, RuleAddPriorityOption ruleAddPriorityOption) + private async Task AddRuleInternalAsync(Rule rule, RuleAddPriorityOption ruleAddPriorityOption) { var errors = new List(); + var contentTypes = await this.rulesSource.GetContentTypesAsync(new GetContentTypesArgs()).ConfigureAwait(false); + + if (!contentTypes.Contains(rule.ContentType, StringComparer.Ordinal)) + { + 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.Error(errors); + } + + await this.CreateContentTypeInternalAsync(rule.ContentType).ConfigureAwait(false); + } + var rulesFilterArgs = new GetRulesFilteredArgs { - ContentType = rule.ContentContainer.ContentType, + ContentType = rule.ContentType, }; var existentRules = await this.rulesSource.GetRulesFilteredAsync(rulesFilterArgs).ConfigureAwait(false); @@ -312,7 +279,7 @@ private async Task AddRuleInternalAsync(Rule rule, RuleAddP if (errors.Any()) { - return RuleOperationResult.Error(errors); + return OperationResult.Error(errors); } switch (ruleAddPriorityOption.PriorityOption) @@ -342,7 +309,7 @@ private async Task AddRuleInternalAsync(Rule rule, RuleAddP throw new NotSupportedException($"The placement option '{ruleAddPriorityOption.PriorityOption}' is not supported."); } - return RuleOperationResult.Success(); + return OperationResult.Success(); } private async Task AddRuleInternalAtBottomAsync(Rule rule, IEnumerable existentRules) @@ -407,6 +374,13 @@ await ManagementOperations.Manage(existentRules) .ConfigureAwait(false); } + 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, @@ -503,11 +477,11 @@ private async Task> GetRulesOrderedAscendingAsync(GetRulesArgs getRul return orderedRules; } - private async Task UpdateRuleInternalAsync(Rule rule) + private async Task UpdateRuleInternalAsync(Rule rule) { var rulesFilterArgs = new GetRulesFilteredArgs { - ContentType = rule.ContentContainer.ContentType, + ContentType = rule.ContentType, }; var existentRules = await this.rulesSource.GetRulesFilteredAsync(rulesFilterArgs).ConfigureAwait(false); @@ -515,14 +489,14 @@ private async Task UpdateRuleInternalAsync(Rule rule) var existentRule = existentRules.FirstOrDefault(r => 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.Error($"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.Error(validationResult.Errors.Select(ve => ve.ErrorMessage)); } var topPriorityThreshold = Math.Min(rule.Priority, existentRule.Priority); @@ -563,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/RulesEngineOptions.cs b/src/Rules.Framework/RulesEngineOptions.cs index b77300b5..d6a9161e 100644 --- a/src/Rules.Framework/RulesEngineOptions.cs +++ b/src/Rules.Framework/RulesEngineOptions.cs @@ -1,6 +1,5 @@ namespace Rules.Framework { - using System; using System.Collections.Generic; /// @@ -13,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. /// @@ -59,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/Serialization/SerializedContentContainer.cs b/src/Rules.Framework/Serialization/SerializedContentContainer.cs index 928a7179..47d1cddb 100644 --- a/src/Rules.Framework/Serialization/SerializedContentContainer.cs +++ b/src/Rules.Framework/Serialization/SerializedContentContainer.cs @@ -16,7 +16,7 @@ public SerializedContentContainer( string contentType, object serializedContent, IContentSerializationProvider contentSerializationProvider) - : base(contentType, (t) => contentSerializationProvider.GetContentSerializer(contentType).Deserialize(serializedContent, t)) + : base((t) => contentSerializationProvider.GetContentSerializer(contentType).Deserialize(serializedContent, t)) { } } 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/IRulesSource.cs b/src/Rules.Framework/Source/IRulesSource.cs index 5d743996..dc6d3e3d 100644 --- a/src/Rules.Framework/Source/IRulesSource.cs +++ b/src/Rules.Framework/Source/IRulesSource.cs @@ -7,7 +7,9 @@ internal interface IRulesSource { Task AddRuleAsync(AddRuleArgs args); - Task> GetContentTypesAsync(); + Task CreateContentTypeAsync(CreateContentTypeArgs args); + + Task> GetContentTypesAsync(GetContentTypesArgs args); Task> GetRulesAsync(GetRulesArgs args); diff --git a/src/Rules.Framework/Source/IRulesSourceMiddleware.cs b/src/Rules.Framework/Source/IRulesSourceMiddleware.cs index ce8d6340..3c5054a8 100644 --- a/src/Rules.Framework/Source/IRulesSourceMiddleware.cs +++ b/src/Rules.Framework/Source/IRulesSourceMiddleware.cs @@ -9,6 +9,14 @@ Task HandleAddRuleAsync( AddRuleArgs args, AddRuleDelegate next); + Task HandleCreateContentTypeAsync( + CreateContentTypeArgs args, + CreateContentTypeDelegate next); + + Task> HandleGetContentTypesAsync( + GetContentTypesArgs args, + GetContentTypesDelegate next); + Task> HandleGetRulesAsync( GetRulesArgs args, GetRulesDelegate next); diff --git a/src/Rules.Framework/Source/RulesSource.cs b/src/Rules.Framework/Source/RulesSource.cs index b5f6128e..b8c81082 100644 --- a/src/Rules.Framework/Source/RulesSource.cs +++ b/src/Rules.Framework/Source/RulesSource.cs @@ -2,11 +2,12 @@ namespace Rules.Framework.Source { using System.Collections.Generic; using System.Threading.Tasks; - using Rules.Framework.Core; internal sealed class RulesSource : IRulesSource { private readonly AddRuleDelegate addRuleDelegate; + private readonly CreateContentTypeDelegate createContentTypeDelegate; + private readonly GetContentTypesDelegate getContentTypesDelegate; private readonly GetRulesDelegate getRulesDelegate; private readonly GetRulesFilteredDelegate getRulesFilteredDelegate; private readonly IRulesDataSource rulesDataSource; @@ -18,6 +19,8 @@ public RulesSource( { 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); @@ -29,7 +32,15 @@ public async Task AddRuleAsync(AddRuleArgs args) await this.addRuleDelegate.Invoke(args).ConfigureAwait(false); } - public Task> GetContentTypesAsync() => this.rulesDataSource.GetContentTypesAsync(); + 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) { @@ -70,6 +81,54 @@ private static AddRuleDelegate CreateAddRulePipelineDelegate( return action; } + 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 (args) => 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) 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 a3eca07f..58f9a536 100644 --- a/tests/Rules.Framework.BenchmarkTests/Tests/Benchmark1/Benchmark1.cs +++ b/tests/Rules.Framework.BenchmarkTests/Tests/Benchmark1/Benchmark1.cs @@ -33,9 +33,11 @@ public async Task SetUpAsync() }) .Build(); + await rulesEngine.CreateContentTypeAsync(nameof(ContentTypes.ContentType1)); + foreach (var rule in this.benchmarkData.Rules) { - await rulesEngine.AddRuleAsync(rule, RuleAddPriorityOption.AtTop).ConfigureAwait(false); + await rulesEngine.AddRuleAsync(rule, RuleAddPriorityOption.AtTop); } this.rulesEngine = rulesEngine.MakeGeneric(); diff --git a/tests/Rules.Framework.BenchmarkTests/Tests/Benchmark2/Benchmark2.cs b/tests/Rules.Framework.BenchmarkTests/Tests/Benchmark2/Benchmark2.cs index e309f343..6ceb2b91 100644 --- a/tests/Rules.Framework.BenchmarkTests/Tests/Benchmark2/Benchmark2.cs +++ b/tests/Rules.Framework.BenchmarkTests/Tests/Benchmark2/Benchmark2.cs @@ -33,6 +33,8 @@ public async Task SetUpAsync() }) .Build(); + await rulesEngine.CreateContentTypeAsync(nameof(ContentTypes.Songs)); + foreach (var rule in this.benchmarkData.Rules) { await rulesEngine.AddRuleAsync(rule, RuleAddPriorityOption.AtTop).ConfigureAwait(false); diff --git a/tests/Rules.Framework.BenchmarkTests/Tests/Benchmark3/Benchmark3.cs b/tests/Rules.Framework.BenchmarkTests/Tests/Benchmark3/Benchmark3.cs index 4c196286..f68a3fc3 100644 --- a/tests/Rules.Framework.BenchmarkTests/Tests/Benchmark3/Benchmark3.cs +++ b/tests/Rules.Framework.BenchmarkTests/Tests/Benchmark3/Benchmark3.cs @@ -33,6 +33,8 @@ public async Task SetUpAsync() }) .Build(); + await rulesEngine.CreateContentTypeAsync(nameof(ContentTypes.TexasHoldemPokerSingleCombinations)); + foreach (var rule in this.benchmarkData.Rules) { await rulesEngine.AddRuleAsync(rule, RuleAddPriorityOption.AtTop).ConfigureAwait(false); diff --git a/tests/Rules.Framework.IntegrationTests.Common/Scenarios/ScenarioLoader.cs b/tests/Rules.Framework.IntegrationTests.Common/Scenarios/ScenarioLoader.cs index 879fac62..d243586d 100644 --- a/tests/Rules.Framework.IntegrationTests.Common/Scenarios/ScenarioLoader.cs +++ b/tests/Rules.Framework.IntegrationTests.Common/Scenarios/ScenarioLoader.cs @@ -8,6 +8,12 @@ public static async Task LoadScenarioAsync( 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/RulesFromJsonFile.cs b/tests/Rules.Framework.IntegrationTests/RulesFromJsonFile.cs index 07d5ddd5..3b6c56c1 100644 --- a/tests/Rules.Framework.IntegrationTests/RulesFromJsonFile.cs +++ b/tests/Rules.Framework.IntegrationTests/RulesFromJsonFile.cs @@ -26,10 +26,16 @@ public async Task FromJsonFileAsync(IRulesEngine>(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 = Rule.New() .WithName(ruleDataModel.Name) diff --git a/tests/Rules.Framework.IntegrationTests/Scenarios/Scenario1/BodyMassIndexTests.cs b/tests/Rules.Framework.IntegrationTests/Scenarios/Scenario1/BodyMassIndexTests.cs index 4f1dc241..bcb9c850 100644 --- a/tests/Rules.Framework.IntegrationTests/Scenarios/Scenario1/BodyMassIndexTests.cs +++ b/tests/Rules.Framework.IntegrationTests/Scenarios/Scenario1/BodyMassIndexTests.cs @@ -32,6 +32,8 @@ public async Task AddRule_AddingNewRuleFromScratchWithAgeConditionAtPriority1And .Build(); var genericRulesEngine = rulesEngine.MakeGeneric(); + await genericRulesEngine.CreateContentTypeAsync(ContentTypes.BodyMassIndexFormula); + var newRuleResult1 = Rule.New() .WithName("Body Mass Index up to 18 years formula") .WithDateBegin(DateTime.Parse("2018-01-01")) diff --git a/tests/Rules.Framework.IntegrationTests/Scenarios/Scenario4/DiscountCampaignTests.cs b/tests/Rules.Framework.IntegrationTests/Scenarios/Scenario4/DiscountCampaignTests.cs index d5b6d3c3..0ca3dc62 100644 --- a/tests/Rules.Framework.IntegrationTests/Scenarios/Scenario4/DiscountCampaignTests.cs +++ b/tests/Rules.Framework.IntegrationTests/Scenarios/Scenario4/DiscountCampaignTests.cs @@ -33,6 +33,7 @@ public async Task DiscountsWeekend_Adding15PercentRulePerBrandAndEvaluatingOneOf .SetInMemoryDataSource(serviceProvider) .Configure(options => { + options.AutoCreateContentTypes = true; options.EnableCompilation = enableCompilation; }) .Build(); @@ -93,6 +94,7 @@ public async Task DiscountsWeekend_Adding20PercentRulePerProductTierAndEvaluatin .SetInMemoryDataSource(serviceProvider) .Configure(options => { + options.AutoCreateContentTypes = true; options.EnableCompilation = enableCompilation; }) .Build(); @@ -154,6 +156,7 @@ public async Task DiscountsWeekend_Adding5PercentRuleWithNotContainsTestConditio .SetInMemoryDataSource(serviceProvider) .Configure(options => { + options.AutoCreateContentTypes = true; options.EnableCompilation = enableCompilation; }) .Build(); @@ -210,6 +213,7 @@ public async Task DiscountsWeekend_AddingRuleWithNullTestConditionAndInputWithMa .SetInMemoryDataSource(serviceProvider) .Configure(options => { + options.AutoCreateContentTypes = true; options.EnableCompilation = enableCompilation; }) .Build(); @@ -266,6 +270,7 @@ public async Task DiscountsWeekend_AddingRuleWithNullTestConditionAndInputWithou .SetInMemoryDataSource(serviceProvider) .Configure(options => { + options.AutoCreateContentTypes = true; options.EnableCompilation = enableCompilation; }) .Build(); @@ -318,6 +323,7 @@ public async Task DiscountsWeekend_AddingRuleWithNullTestConditionAndInputWithou .SetInMemoryDataSource(serviceProvider) .Configure(options => { + options.AutoCreateContentTypes = true; options.EnableCompilation = enableCompilation; }) .Build(); diff --git a/tests/Rules.Framework.IntegrationTests/Scenarios/Scenario5/BestServerTests.cs b/tests/Rules.Framework.IntegrationTests/Scenarios/Scenario5/BestServerTests.cs index cddca5c3..69df85e2 100644 --- a/tests/Rules.Framework.IntegrationTests/Scenarios/Scenario5/BestServerTests.cs +++ b/tests/Rules.Framework.IntegrationTests/Scenarios/Scenario5/BestServerTests.cs @@ -24,6 +24,8 @@ public async Task BestServer_DeactivatingBestServerTop5_ReturnsBestServerDefault .Build(); var genericRulesEngine = rulesEngine.MakeGeneric(); + await genericRulesEngine.CreateContentTypeAsync(BestServerConfigurations.BestServerEvaluation); + // Act 1 - Create rule with "in" operator var ruleBuilderResult = Rule.New() .WithName("Best Server Top5") @@ -118,6 +120,8 @@ public async Task BestServer_UpdatingBestServerTop5_ReturnsBestServerDefault() .Build(); var genericRulesEngine = rulesEngine.MakeGeneric(); + await genericRulesEngine.CreateContentTypeAsync(BestServerConfigurations.BestServerEvaluation); + // Act 1 - Create rule with "in" operator var ruleBuilderResult = Rule.New() .WithName("Best Server Top5") 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 25b5d266..fa743073 100644 --- a/tests/Rules.Framework.Providers.InMemory.IntegrationTests/Features/RulesEngine/RulesEngineTestsBase.cs +++ b/tests/Rules.Framework.Providers.InMemory.IntegrationTests/Features/RulesEngine/RulesEngineTestsBase.cs @@ -26,21 +26,22 @@ protected RulesEngineTestsBase(ContentType testContentType) }) .Build(); this.CompiledRulesEngine = compiledRulesEngine.MakeGeneric(); + this.CompiledRulesEngine.CreateContentTypeAsync(testContentType).GetAwaiter().GetResult(); var interpretedRulesEngine = RulesEngineBuilder .CreateRulesEngine() .SetInMemoryDataSource() .Configure(c => c.PriorityCriteria = PriorityCriterias.TopmostRuleWins) .Build(); - this.InterpretedRulesEngine = interpretedRulesEngine.MakeGeneric(); + this.InterpretedRulesEngine.CreateContentTypeAsync(testContentType).GetAwaiter().GetResult(); } protected IRulesEngine CompiledRulesEngine { get; } protected IRulesEngine InterpretedRulesEngine { get; } - protected async Task ActivateRuleAsync(Rule rule, bool compiled) + protected async Task ActivateRuleAsync(Rule rule, bool compiled) { if (compiled) { @@ -66,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) { @@ -93,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/RulesInSequenceTests.cs b/tests/Rules.Framework.Providers.InMemory.IntegrationTests/Features/RulesEngine/RulesMatching/RulesInSequenceTests.cs index 18a633a6..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()); } 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 31a11526..0beeda79 100644 --- a/tests/Rules.Framework.Providers.InMemory.IntegrationTests/Scenarios/Scenario5/BestServerTests.cs +++ b/tests/Rules.Framework.Providers.InMemory.IntegrationTests/Scenarios/Scenario5/BestServerTests.cs @@ -56,6 +56,7 @@ public async Task BestServer_InEvaluation(IEnumerable(); + await genericRulesEngine.CreateContentTypeAsync(BestServerConfigurations.BestServerEvaluation); // Act 1 - Create rule with "in" operator var ruleBuilderResult = Rule.New() diff --git a/tests/Rules.Framework.Providers.MongoDb.IntegrationTests/Features/RulesEngine/RulesEngineTestsBase.cs b/tests/Rules.Framework.Providers.MongoDb.IntegrationTests/Features/RulesEngine/RulesEngineTestsBase.cs index 7f3569a8..38710d60 100644 --- a/tests/Rules.Framework.Providers.MongoDb.IntegrationTests/Features/RulesEngine/RulesEngineTestsBase.cs +++ b/tests/Rules.Framework.Providers.MongoDb.IntegrationTests/Features/RulesEngine/RulesEngineTestsBase.cs @@ -30,6 +30,7 @@ protected RulesEngineTestsBase(ContentType testContentType) .Build(); this.RulesEngine = rulesEngine.MakeGeneric(); + this.RulesEngine.CreateContentTypeAsync(testContentType).GetAwaiter().GetResult(); } protected IRulesEngine RulesEngine { get; } 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 e5b335ec..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 @@ -65,7 +65,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()); } 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 cb3647f5..bd32d220 100644 --- a/tests/Rules.Framework.Providers.MongoDb.IntegrationTests/Scenarios/Scenario2/CarInsuranceAdvisorTests.cs +++ b/tests/Rules.Framework.Providers.MongoDb.IntegrationTests/Scenarios/Scenario2/CarInsuranceAdvisorTests.cs @@ -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() 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 8c6ce74a..0d93f9bb 100644 --- a/tests/Rules.Framework.Providers.MongoDb.IntegrationTests/Scenarios/Scenario3/BuildingSecuritySystemControlTests.cs +++ b/tests/Rules.Framework.Providers.MongoDb.IntegrationTests/Scenarios/Scenario3/BuildingSecuritySystemControlTests.cs @@ -51,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] @@ -191,6 +205,7 @@ 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"); 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 426d9337..d26e6a69 100644 --- a/tests/Rules.Framework.Providers.MongoDb.IntegrationTests/Scenarios/Scenario5/BestServerTests.cs +++ b/tests/Rules.Framework.Providers.MongoDb.IntegrationTests/Scenarios/Scenario5/BestServerTests.cs @@ -61,6 +61,7 @@ public async Task BestServer_InEvaluation(IEnumerable(); + await genericRulesEngine.CreateContentTypeAsync(BestServerConfigurations.BestServerEvaluation); // Act 1 - Create rule with "in" operator var ruleBuilderResult = Rule.New() diff --git a/tests/Rules.Framework.Providers.MongoDb.Tests/MongoDbProviderRulesDataSourceTests.cs b/tests/Rules.Framework.Providers.MongoDb.Tests/MongoDbProviderRulesDataSourceTests.cs index b33088a7..3c909771 100644 --- a/tests/Rules.Framework.Providers.MongoDb.Tests/MongoDbProviderRulesDataSourceTests.cs +++ b/tests/Rules.Framework.Providers.MongoDb.Tests/MongoDbProviderRulesDataSourceTests.cs @@ -2,6 +2,7 @@ namespace Rules.Framework.Providers.MongoDb.Tests { using System; using System.Collections.Generic; + using System.Threading; using System.Threading.Tasks; using FluentAssertions; using MongoDB.Driver; @@ -12,6 +13,104 @@ namespace Rules.Framework.Providers.MongoDb.Tests 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, opt, t) => 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() { diff --git a/tests/Rules.Framework.Tests/Builder/RuleBuilderTests.cs b/tests/Rules.Framework.Tests/Builder/RuleBuilderTests.cs index 7dab97ac..bd3d2874 100644 --- a/tests/Rules.Framework.Tests/Builder/RuleBuilderTests.cs +++ b/tests/Rules.Framework.Tests/Builder/RuleBuilderTests.cs @@ -5,7 +5,6 @@ namespace Rules.Framework.Tests.Builder using FluentAssertions; using Moq; using Rules.Framework; - using Rules.Framework.Core; using Rules.Framework.Generic.ConditionNodes; using Rules.Framework.Serialization; using Rules.Framework.Tests.Stubs; @@ -202,9 +201,9 @@ public void NewRule_WithSerializedContent_SetsContentAsSerializedContent() .Build(); // Assert + ruleBuilderResult.Rule.ContentType.Should().Be(contentType); var ruleContent = ruleBuilderResult.Rule.ContentContainer; - 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/ConditionTypeExtractorTests.cs b/tests/Rules.Framework.Tests/ConditionTypeExtractorTests.cs index 03d444a4..7e9ce124 100644 --- a/tests/Rules.Framework.Tests/ConditionTypeExtractorTests.cs +++ b/tests/Rules.Framework.Tests/ConditionTypeExtractorTests.cs @@ -22,7 +22,7 @@ public void GetConditionTypes_ReturnsCorrectExtraction() var rule1 = new Rule { - ContentContainer = new ContentContainer(contentType, _ => new object()), + ContentContainer = new ContentContainer(_ => new object()), DateBegin = dateBegin, DateEnd = dateEnd, Name = "Rule 1", @@ -32,7 +32,7 @@ public void GetConditionTypes_ReturnsCorrectExtraction() 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", @@ -42,7 +42,7 @@ public void GetConditionTypes_ReturnsCorrectExtraction() var rule3 = new Rule { - ContentContainer = new ContentContainer(contentType, _ => new object()), + ContentContainer = new ContentContainer(_ => new object()), DateBegin = dateBegin, DateEnd = dateEnd, Name = "Rule 3", @@ -52,7 +52,7 @@ public void GetConditionTypes_ReturnsCorrectExtraction() var rule4 = new Rule { - ContentContainer = new ContentContainer(contentType, _ => new object()), + ContentContainer = new ContentContainer(_ => new object()), DateBegin = dateBegin, DateEnd = dateEnd, Name = "Rule 4", @@ -125,7 +125,7 @@ public void GetConditionTypes_WithNullRootCondition_ReturnsEmptyListConditionTyp { new Rule { - ContentContainer = new ContentContainer(contentType, _ => new object()), + ContentContainer = new ContentContainer(_ => new object()), DateBegin = dateBegin, DateEnd = dateEnd, Name = "Rule 3", 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 f2ea8110..d8bf9481 100644 --- a/tests/Rules.Framework.Tests/Core/ContentContainerTests.cs +++ b/tests/Rules.Framework.Tests/ContentContainerTests.cs @@ -1,36 +1,19 @@ -namespace Rules.Framework.Tests.Core +namespace Rules.Framework.Tests { using System; using FluentAssertions; using Rules.Framework; - using Rules.Framework.Core; - using Rules.Framework.Tests.Stubs; 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((t) => expected); // Act object actual = sut.GetContentAs(); @@ -45,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((t) => 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/Extensions/GenericRuleExtensionsTests.cs b/tests/Rules.Framework.Tests/Extensions/GenericRuleExtensionsTests.cs index b23dc002..a988c569 100644 --- a/tests/Rules.Framework.Tests/Extensions/GenericRuleExtensionsTests.cs +++ b/tests/Rules.Framework.Tests/Extensions/GenericRuleExtensionsTests.cs @@ -78,7 +78,8 @@ public void GenericRuleExtensions_ToGenericRule_WithComposedCondition_Success() // Assert genericRule.Should().BeEquivalentTo(rule, config => config .Excluding(r => r.ContentContainer) - .Excluding(r => r.RootCondition)); + .Excluding(r => r.RootCondition) + .Excluding(r => r.ContentType)); var content = genericRule.ContentContainer.GetContentAs(); content.Should().BeOfType(); content.Should().Be(expectedRuleContent); @@ -105,7 +106,9 @@ public void GenericRuleExtensions_ToGenericRule_WithoutConditions_Success() var genericRule = rule.ToGenericRule(); // Assert - genericRule.Should().BeEquivalentTo(rule, config => config.Excluding(r => r.ContentContainer)); + 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); @@ -140,7 +143,8 @@ public void GenericRuleExtensions_ToGenericRule_WithValueCondition_Success() // Assert genericRule.Should().BeEquivalentTo(rule, config => config .Excluding(r => r.ContentContainer) - .Excluding(r => r.RootCondition)); + .Excluding(r => r.RootCondition) + .Excluding(r => r.ContentType)); var content = genericRule.ContentContainer.GetContentAs(); content.Should().BeOfType(); content.Should().Be(expectedRuleContent); diff --git a/tests/Rules.Framework.Tests/Generic/RulesEngineTests.cs b/tests/Rules.Framework.Tests/Generic/RulesEngineTests.cs index c36c4760..870d2c97 100644 --- a/tests/Rules.Framework.Tests/Generic/RulesEngineTests.cs +++ b/tests/Rules.Framework.Tests/Generic/RulesEngineTests.cs @@ -13,15 +13,15 @@ namespace Rules.Framework.Tests.Generic public class RulesEngineTests { - private readonly Mock mockRulesEngine; + private readonly IRulesEngine rulesEngineMock; public RulesEngineTests() { - this.mockRulesEngine = new Mock(); + this.rulesEngineMock = Mock.Of(); } [Fact] - public async Task GenericRulesEngine_GetContentTypes_Success() + public async Task GetContentTypes_NoConditionsGiven_ReturnsContentTypes() { // Arrange var expectedGenericContentTypes = new List @@ -31,10 +31,10 @@ public async Task GenericRulesEngine_GetContentTypes_Success() }; var contentTypes = new[] { "Type1", "Type2" }; - this.mockRulesEngine.Setup(x => x.GetContentTypesAsync()) + Mock.Get(this.rulesEngineMock).Setup(x => x.GetContentTypesAsync()) .ReturnsAsync(contentTypes); - var genericRulesEngine = new RulesEngine(this.mockRulesEngine.Object); + var genericRulesEngine = new RulesEngine(this.rulesEngineMock); // Act var genericContentTypes = await genericRulesEngine.GetContentTypesAsync(); @@ -44,7 +44,7 @@ public async Task GenericRulesEngine_GetContentTypes_Success() } [Fact] - public async Task GenericRulesEngine_GetContentTypes_WithEmptyContentType_Success() + public async Task GetContentTypes_WithEmptyContentType_Success() { // Arrange var mockRulesEngineEmptyContentType = new Mock(); @@ -59,7 +59,44 @@ public async Task GenericRulesEngine_GetContentTypes_WithEmptyContentType_Succes } [Fact] - public async Task GenericRulesEngine_SearchAsync_Success() + 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() @@ -92,11 +129,11 @@ public async Task GenericRulesEngine_SearchAsync_Success() testRule }; - this.mockRulesEngine + Mock.Get(this.rulesEngineMock) .Setup(m => m.SearchAsync(It.IsAny>())) .ReturnsAsync(testRules); - var genericRulesEngine = new RulesEngine(this.mockRulesEngine.Object); + var genericRulesEngine = new RulesEngine(this.rulesEngineMock); // Act var genericRules = await genericRulesEngine.SearchAsync(genericSearchArgs); @@ -104,8 +141,60 @@ public async Task GenericRulesEngine_SearchAsync_Success() // Assert var actualRule = genericRules.First(); actualRule.Should().BeEquivalentTo(expectedRule); - this.mockRulesEngine + 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/RuleOperationResultTests.cs b/tests/Rules.Framework.Tests/RuleOperationResultTests.cs index e1e5e159..c858a89b 100644 --- a/tests/Rules.Framework.Tests/RuleOperationResultTests.cs +++ b/tests/Rules.Framework.Tests/RuleOperationResultTests.cs @@ -14,7 +14,7 @@ public void Error_GivenCollectionOfErrors_ReturnsRuleOperationResultWithErrorsAn IEnumerable errors = new[] { "Error1", "Error2" }; // Act - RuleOperationResult ruleOperationResult = RuleOperationResult.Error(errors); + var ruleOperationResult = OperationResult.Error(errors); // Assert ruleOperationResult.Should().NotBeNull(); @@ -29,7 +29,7 @@ public void Error_GivenNullCollectionOfErrors_ThrowsArgumentNullException() IEnumerable errors = null; // Act - ArgumentNullException argumentNullException = Assert.Throws(() => RuleOperationResult.Error(errors)); + var argumentNullException = Assert.Throws(() => OperationResult.Error(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/RuleTests.cs b/tests/Rules.Framework.Tests/RuleTests.cs index fd0c383a..ad09485d 100644 --- a/tests/Rules.Framework.Tests/RuleTests.cs +++ b/tests/Rules.Framework.Tests/RuleTests.cs @@ -16,7 +16,7 @@ public void Clone_WithRuleWithoutRootCondition_ReturnsCopy() // Arrange var rule = new Rule { - ContentContainer = new ContentContainer(ContentType.Type1.ToString(), _ => new object()), + ContentContainer = new ContentContainer(_ => new object()), DateBegin = DateTime.UtcNow.AddDays(-1), DateEnd = DateTime.UtcNow.AddDays(1), Priority = 1, @@ -37,7 +37,7 @@ public void Clone_WithRuleWithRootCondition_ReturnsCopy() // Arrange var rule = new Rule { - ContentContainer = new ContentContainer(ContentType.Type1.ToString(), _ => new object()), + ContentContainer = new ContentContainer(_ => new object()), DateBegin = DateTime.UtcNow.AddDays(-1), DateEnd = DateTime.UtcNow.AddDays(1), Priority = 1, @@ -58,7 +58,7 @@ public void Clone_WithRuleWithRootCondition_ReturnsCopy() public void ContentContainer_HavingSettedInstance_ReturnsProvidedInstance() { // Arrange - var expected = new ContentContainer(ContentType.Type1.ToString(), (_) => null); + var expected = new ContentContainer((_) => null); var sut = new Rule { diff --git a/tests/Rules.Framework.Tests/RulesEngineTests.cs b/tests/Rules.Framework.Tests/RulesEngineTests.cs index 47f042d8..1eb1c7e1 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; @@ -19,15 +20,17 @@ namespace Rules.Framework.Tests public class RulesEngineTests { - private readonly Mock mockConditionsEvalEngine; - private readonly Mock mockConditionTypeExtractor; - 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.mockConditionTypeExtractor = new Mock(); - this.mockConditionsEvalEngine = new Mock(); + this.rulesSourceMock = Mock.Of(); + this.conditionTypeExtractorMock = Mock.Of(); + this.conditionsEvalEngineMock = Mock.Of(); + this.validatorProviderMock = Mock.Of(); } [Fact] @@ -38,7 +41,7 @@ public async Task ActivateRuleAsync_GivenEmptyRuleDataSource_ActivatesRuleSucces var testRule = new Rule { - ContentContainer = new ContentContainer(contentType, (t) => new object()), + ContentContainer = new ContentContainer((t) => new object()), DateBegin = new DateTime(2018, 01, 01), DateEnd = new DateTime(2019, 01, 01), Name = "Update test rule", @@ -47,18 +50,14 @@ public async Task ActivateRuleAsync_GivenEmptyRuleDataSource_ActivatesRuleSucces RootCondition = new ValueConditionNode(DataTypes.String, ConditionType.IsoCountryCode.ToString(), Operators.Equal, "USA") }; - var evaluationOptions = new EvaluationOptions - { - MatchMode = MatchModes.Exact - }; - - mockRulesSource.Setup(s => s.GetRulesFilteredAsync(It.IsAny())) + 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, mockConditionTypeExtractor.Object); + var sut = new RulesEngine(conditionsEvalEngineMock, rulesSourceMock, validatorProvider, rulesEngineOptions, conditionTypeExtractorMock); // Act var actual = await sut.ActivateRuleAsync(testRule); @@ -67,22 +66,20 @@ public async Task ActivateRuleAsync_GivenEmptyRuleDataSource_ActivatesRuleSucces 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_GivenEmptyRuleDataSourceAndExistentContentType_AddsRuleSuccessfully() { // Arrange var contentType = ContentType.Type1.ToString(); var testRule = new Rule { - ContentContainer = new ContentContainer(contentType, (t) => new object()), + ContentType = contentType, + ContentContainer = new ContentContainer((t) => new object()), DateBegin = new DateTime(2018, 01, 01), DateEnd = new DateTime(2019, 01, 01), Name = "Test rule", @@ -90,19 +87,94 @@ public async Task AddRuleAsync_GivenEmptyRuleDataSource_AddsRuleSuccesfully() RootCondition = new ValueConditionNode(DataTypes.String, ConditionType.IsoCountryCode.ToString(), Operators.Equal, "USA") }; - EvaluationOptions evaluationOptions = new() + Mock.Get(rulesSourceMock) + .Setup(x => x.GetContentTypesAsync(It.IsAny())) + .ReturnsAsync(new[] { contentType }); + + 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().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_GivenEmptyRuleDataSourceAndNonExistentContentTypeAndAutoCreateContentTypeDisabled_DoesNotAddRuleAndReportsError() + { + // Arrange + var contentType = ContentType.Type1.ToString(); + + var testRule = new Rule { - MatchMode = MatchModes.Exact + ContentType = contentType, + ContentContainer = new ContentContainer((t) => 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(rulesSourceMock) + .Setup(x => x.GetContentTypesAsync(It.IsAny())) + .ReturnsAsync(Array.Empty()); - var validatorProvider = Mock.Of(); var rulesEngineOptions = RulesEngineOptions.NewWithDefaults(); rulesEngineOptions.PriorityCriteria = PriorityCriterias.BottommostRuleWins; - var sut = new RulesEngine(mockConditionsEvalEngine.Object, mockRulesSource.Object, validatorProvider, rulesEngineOptions, mockConditionTypeExtractor.Object); + 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 + { + ContentType = contentType, + ContentContainer = new ContentContainer((t) => 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") + }; + + 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 rulesEngineOptions = RulesEngineOptions.NewWithDefaults(); + rulesEngineOptions.PriorityCriteria = PriorityCriterias.BottommostRuleWins; + rulesEngineOptions.AutoCreateContentTypes = true; + + var sut = new RulesEngine(conditionsEvalEngineMock, rulesSourceMock, validatorProviderMock, rulesEngineOptions, conditionTypeExtractorMock); // Act var actual = await sut.AddRuleAsync(testRule, RuleAddPriorityOption.AtBottom); @@ -111,11 +183,73 @@ 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 CreateContentTypeAsync_GivenExistentContentTypeName_DoesNotAddContentTypeToRulesSource() + { + // Arrange + 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); + + // 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] @@ -126,7 +260,7 @@ public async Task DeactivateRuleAsync_GivenEmptyRuleDataSource_DeactivatesRuleSu var testRule = new Rule { - ContentContainer = new ContentContainer(contentType, (t) => new object()), + ContentContainer = new ContentContainer((t) => new object()), DateBegin = new DateTime(2018, 01, 01), DateEnd = new DateTime(2019, 01, 01), Name = "Update test rule", @@ -139,13 +273,13 @@ public async Task DeactivateRuleAsync_GivenEmptyRuleDataSource_DeactivatesRuleSu MatchMode = MatchModes.Exact }; - mockRulesSource.Setup(s => s.GetRulesFilteredAsync(It.IsAny())) + 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, mockConditionTypeExtractor.Object); + var sut = new RulesEngine(conditionsEvalEngineMock, rulesSourceMock, validatorProvider, rulesEngineOptions, conditionTypeExtractorMock); // Act var actual = await sut.DeactivateRuleAsync(testRule); @@ -154,13 +288,39 @@ public async Task DeactivateRuleAsync_GivenEmptyRuleDataSource_DeactivatesRuleSu actual.IsSuccess.Should().BeTrue(); actual.Errors.Should().BeEmpty(); - mockRulesSource.Verify(x => x.GetRulesFilteredAsync(It.IsAny()), Times.Once()); - mockConditionsEvalEngine.Verify(x => x.Eval( + 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 GetContentTypesAsync_NoConditionsGiven_ReturnsContentTypesFromRulesSource() + { + // Arrange + 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] public async Task GetUniqueConditionTypesAsync_GivenThereAreRulesInDataSource_ReturnsAllRequiredConditionTypes() { @@ -176,7 +336,8 @@ public async Task GetUniqueConditionTypesAsync_GivenThereAreRulesInDataSource_Re var expectedCondtionTypes = new List { ConditionType.IsoCountryCode.ToString() }; - mockConditionTypeExtractor.Setup(x => x.GetConditionTypes(It.IsAny>())) + Mock.Get(conditionTypeExtractorMock) + .Setup(x => x.GetConditionTypes(It.IsAny>())) .Returns(expectedCondtionTypes); this.SetupMockForConditionsEvalEngine((rootConditionNode, _, _) => rootConditionNode switch @@ -189,7 +350,7 @@ public async Task GetUniqueConditionTypesAsync_GivenThereAreRulesInDataSource_Re var rulesEngineOptions = RulesEngineOptions.NewWithDefaults(); - var sut = new RulesEngine(mockConditionsEvalEngine.Object, mockRulesSource.Object, validatorProvider, rulesEngineOptions, mockConditionTypeExtractor.Object); + var sut = new RulesEngine(conditionsEvalEngineMock, rulesSourceMock, validatorProvider, rulesEngineOptions, conditionTypeExtractorMock); // Act var actual = await sut.GetUniqueConditionTypesAsync(ContentType.Type1.ToString(), dateBegin, dateEnd); @@ -214,7 +375,7 @@ public async Task MatchManyAsync_GivenContentTypeDateAndConditions_FetchesRulesF var expected1 = new Rule { - ContentContainer = new ContentContainer(contentType, (t) => new object()), + ContentContainer = new ContentContainer((t) => new object()), DateBegin = new DateTime(2018, 01, 01), DateEnd = new DateTime(2019, 01, 01), Name = "Expected rule 1", @@ -224,7 +385,7 @@ public async Task MatchManyAsync_GivenContentTypeDateAndConditions_FetchesRulesF var expected2 = new Rule { - ContentContainer = new ContentContainer(contentType, (t) => new object()), + ContentContainer = new ContentContainer((t) => new object()), DateBegin = new DateTime(2010, 01, 01), DateEnd = new DateTime(2021, 01, 01), Name = "Expected rule 2", @@ -234,7 +395,7 @@ public async Task MatchManyAsync_GivenContentTypeDateAndConditions_FetchesRulesF var notExpected = new Rule { - ContentContainer = new ContentContainer(contentType, (t) => new object()), + ContentContainer = new ContentContainer((t) => new object()), DateBegin = new DateTime(2018, 01, 01), DateEnd = new DateTime(2019, 01, 01), Name = "Not expected rule", @@ -264,7 +425,7 @@ public async Task MatchManyAsync_GivenContentTypeDateAndConditions_FetchesRulesF var rulesEngineOptions = RulesEngineOptions.NewWithDefaults(); - var sut = new RulesEngine(mockConditionsEvalEngine.Object, mockRulesSource.Object, validatorProvider, rulesEngineOptions, mockConditionTypeExtractor.Object); + var sut = new RulesEngine(conditionsEvalEngineMock, rulesSourceMock, validatorProvider, rulesEngineOptions, conditionTypeExtractorMock); // Act var actual = await sut.MatchManyAsync(contentType, matchDateTime, conditions); @@ -273,8 +434,8 @@ public async Task MatchManyAsync_GivenContentTypeDateAndConditions_FetchesRulesF actual.Should().Contain(expected1) .And.Contain(expected2) .And.NotContain(notExpected); - mockRulesSource.Verify(x => x.GetRulesAsync(It.IsAny()), Times.Once()); - mockConditionsEvalEngine.Verify(x => x.Eval( + 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()); @@ -294,7 +455,7 @@ public async Task MatchOneAsync_GivenContentTypeDateAndConditions_FetchesRulesFo var other = new Rule { - ContentContainer = new ContentContainer(contentType, (t) => new object()), + ContentContainer = new ContentContainer((t) => new object()), DateBegin = new DateTime(2018, 01, 01), DateEnd = new DateTime(2019, 01, 01), Name = "Expected rule", @@ -304,7 +465,7 @@ public async Task MatchOneAsync_GivenContentTypeDateAndConditions_FetchesRulesFo var expected = new Rule { - ContentContainer = new ContentContainer(contentType, (t) => new object()), + ContentContainer = new ContentContainer((t) => new object()), DateBegin = new DateTime(2010, 01, 01), DateEnd = new DateTime(2021, 01, 01), Name = "Expected rule", @@ -332,15 +493,15 @@ public async Task MatchOneAsync_GivenContentTypeDateAndConditions_FetchesRulesFo rulesEngineOptions.PriorityCriteria = PriorityCriterias.BottommostRuleWins; - var sut = new RulesEngine(mockConditionsEvalEngine.Object, mockRulesSource.Object, validatorProvider, rulesEngineOptions, mockConditionTypeExtractor.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( + 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()); @@ -360,7 +521,7 @@ public async Task MatchOneAsync_GivenContentTypeDateAndConditions_FetchesRulesFo var expected = new Rule { - ContentContainer = new ContentContainer(contentType, (t) => new object()), + ContentContainer = new ContentContainer((t) => new object()), DateBegin = new DateTime(2018, 01, 01), DateEnd = new DateTime(2019, 01, 01), Name = "Expected rule", @@ -370,7 +531,7 @@ public async Task MatchOneAsync_GivenContentTypeDateAndConditions_FetchesRulesFo var other = new Rule { - ContentContainer = new ContentContainer(contentType, (t) => new object()), + ContentContainer = new ContentContainer((t) => new object()), DateBegin = new DateTime(2010, 01, 01), DateEnd = new DateTime(2021, 01, 01), Name = "Expected rule", @@ -396,15 +557,15 @@ public async Task MatchOneAsync_GivenContentTypeDateAndConditions_FetchesRulesFo var validatorProvider = Mock.Of(); var rulesEngineOptions = RulesEngineOptions.NewWithDefaults(); - var sut = new RulesEngine(mockConditionsEvalEngine.Object, mockRulesSource.Object, validatorProvider, rulesEngineOptions, mockConditionTypeExtractor.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( + 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()); @@ -426,7 +587,7 @@ public async Task MatchOneAsync_GivenContentTypeDateAndConditions_FetchesRulesFo { new Rule { - ContentContainer = new ContentContainer(contentType, (t) => new object()), + ContentContainer = new ContentContainer((t) => new object()), DateBegin = new DateTime(2018, 01, 01), DateEnd = new DateTime(2019, 01, 01), Name = "Expected rule", @@ -435,7 +596,7 @@ public async Task MatchOneAsync_GivenContentTypeDateAndConditions_FetchesRulesFo }, new Rule { - ContentContainer = new ContentContainer(contentType, (t) => new object()), + ContentContainer = new ContentContainer((t) => new object()), DateBegin = new DateTime(2010, 01, 01), DateEnd = new DateTime(2021, 01, 01), Name = "Expected rule", @@ -456,131 +617,20 @@ public async Task MatchOneAsync_GivenContentTypeDateAndConditions_FetchesRulesFo var validatorProvider = Mock.Of(); var rulesEngineOptions = RulesEngineOptions.NewWithDefaults(); - var sut = new RulesEngine(mockConditionsEvalEngine.Object, mockRulesSource.Object, validatorProvider, rulesEngineOptions, mockConditionTypeExtractor.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( + 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() - { - // Arrange - var contentType = ContentType.Type1.ToString(); - var matchDateTime = new DateTime(2018, 07, 01, 18, 19, 30); - var searchArgs = new SearchArgs(contentType, matchDateTime, matchDateTime); - - 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.ToString(), 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.ToString(), Operators.Equal, "USA") - } - }; - - var evaluationOptions = new EvaluationOptions - { - 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") })); - - 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, mockConditionTypeExtractor.Object); - - // Act - var argumentException = await Assert.ThrowsAsync(() => sut.SearchAsync(searchArgs)); - - // 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.ToString(); - - 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.ToString(), 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.ToString(), 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(mockConditionsEvalEngine.Object, mockRulesSource.Object, validatorProvider, rulesEngineOptions, mockConditionTypeExtractor.Object); - - // Act - var argumentNullException = await Assert.ThrowsAsync(() => sut.SearchAsync(searchArgs)); - - // Assert - argumentNullException.Should().NotBeNull(); - argumentNullException.ParamName.Should().Be(nameof(searchArgs)); - } - [Fact] public async Task UpdateRuleAsync_GivenEmptyRuleDataSource_UpdatesRuleSuccesfully() { @@ -589,7 +639,7 @@ public async Task UpdateRuleAsync_GivenEmptyRuleDataSource_UpdatesRuleSuccesfull var testRule = new Rule { - ContentContainer = new ContentContainer(contentType, (t) => new object()), + ContentContainer = new ContentContainer((t) => new object()), DateBegin = new DateTime(2018, 01, 01), DateEnd = new DateTime(2019, 01, 01), Name = "Update test rule", @@ -602,13 +652,13 @@ public async Task UpdateRuleAsync_GivenEmptyRuleDataSource_UpdatesRuleSuccesfull MatchMode = MatchModes.Exact }; - mockRulesSource.Setup(s => s.GetRulesFilteredAsync(It.IsAny())) + 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, mockConditionTypeExtractor.Object); + var sut = new RulesEngine(conditionsEvalEngineMock, rulesSourceMock, validatorProvider, rulesEngineOptions, conditionTypeExtractorMock); testRule.DateEnd = new DateTime(2019, 01, 02); testRule.Priority = 1; @@ -620,8 +670,8 @@ public async Task UpdateRuleAsync_GivenEmptyRuleDataSource_UpdatesRuleSuccesfull actual.IsSuccess.Should().BeTrue(); actual.Errors.Should().BeEmpty(); - mockRulesSource.Verify(x => x.GetRulesFilteredAsync(It.IsAny()), Times.Once()); - mockConditionsEvalEngine.Verify(x => x.Eval( + 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()); @@ -635,7 +685,7 @@ public async Task UpdateRuleAsync_GivenRuleWithInvalidDateEnd_UpdatesRuleFailure var testRule = new Rule { - ContentContainer = new ContentContainer(contentType, (t) => new object()), + ContentContainer = new ContentContainer((t) => new object()), DateBegin = new DateTime(2018, 01, 01), DateEnd = new DateTime(2019, 01, 01), Name = "Update test rule", @@ -648,13 +698,13 @@ public async Task UpdateRuleAsync_GivenRuleWithInvalidDateEnd_UpdatesRuleFailure MatchMode = MatchModes.Exact }; - mockRulesSource.Setup(s => s.GetRulesFilteredAsync(It.IsAny())) + 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, mockConditionTypeExtractor.Object); + var sut = new RulesEngine(conditionsEvalEngineMock, rulesSourceMock, validatorProvider, rulesEngineOptions, conditionTypeExtractorMock); testRule.DateEnd = testRule.DateBegin.AddYears(-2); testRule.Priority = 1; @@ -666,16 +716,140 @@ public async Task UpdateRuleAsync_GivenRuleWithInvalidDateEnd_UpdatesRuleFailure actual.IsSuccess.Should().BeFalse(); actual.Errors.Should().NotBeEmpty(); - mockRulesSource.Verify(x => x.GetRulesFilteredAsync(It.IsAny()), Times.Once()); - mockConditionsEvalEngine.Verify(x => x.Eval( + 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()); } + [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 evaluationOptions = new EvaluationOptions + { + MatchMode = MatchModes.Exact + }; + + 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(conditionsEvalEngineMock, rulesSourceMock, validatorProvider, rulesEngineOptions, conditionTypeExtractorMock); + + // Act + 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; + + 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); + } + } + + 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( + Mock.Get(this.conditionsEvalEngineMock) + .Setup(x => x.Eval( It.IsAny(), It.IsAny>(), It.Is(eo => eo == evaluationOptions))) @@ -684,7 +858,8 @@ private void SetupMockForConditionsEvalEngine(Func x.Eval( + Mock.Get(this.conditionsEvalEngineMock) + .Setup(x => x.Eval( It.IsAny(), It.IsAny>(), It.Is(eo => eo == evaluationOptions))) @@ -693,7 +868,8 @@ private void SetupMockForConditionsEvalEngine(bool result, EvaluationOptions eva 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/Source/RulesSourceTests.cs b/tests/Rules.Framework.Tests/Source/RulesSourceTests.cs index 5cae9479..8987b87d 100644 --- a/tests/Rules.Framework.Tests/Source/RulesSourceTests.cs +++ b/tests/Rules.Framework.Tests/Source/RulesSourceTests.cs @@ -16,17 +16,17 @@ public class RulesSourceTests public async Task AddRuleAsync_NoMiddlewares_CallsRulesDataSource() { // Arrange - Rule rule = CreateRule(); + var rule = CreateRule(); AddRuleArgs addRuleArgs = new() { Rule = rule, }; - IEnumerable rulesSourceMiddlewares + 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)))) .Returns(Task.CompletedTask); @@ -45,7 +45,7 @@ IEnumerable rulesSourceMiddlewares public async Task AddRuleAsync_OneMiddleware_CallsMiddlewareAndRulesDataSourceAfter() { // Arrange - Rule rule = CreateRule(); + var rule = CreateRule(); AddRuleArgs addRuleArgs = new() { @@ -56,7 +56,7 @@ public async Task AddRuleAsync_OneMiddleware_CallsMiddlewareAndRulesDataSourceAf 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)))) .Returns(Task.CompletedTask); @@ -76,7 +76,7 @@ public async Task AddRuleAsync_OneMiddleware_CallsMiddlewareAndRulesDataSourceAf public async Task AddRuleAsync_TwoMiddlewares_CallsFirstMiddlewareSecondMiddlewareAfterAndRulesDataSourceByLast() { // Arrange - Rule rule = CreateRule(); + var rule = CreateRule(); AddRuleArgs addRuleArgs = new() { @@ -89,7 +89,7 @@ public async Task AddRuleAsync_TwoMiddlewares_CallsFirstMiddlewareSecondMiddlewa 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)))) .Returns(Task.CompletedTask); @@ -107,19 +107,206 @@ public async Task AddRuleAsync_TwoMiddlewares_CallsFirstMiddlewareSecondMiddlewa .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 + 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); @@ -140,16 +327,16 @@ IEnumerable rulesSourceMiddlewares 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()); 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); @@ -171,10 +358,10 @@ 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); @@ -182,7 +369,7 @@ public async Task GetRulesAsync_TwoMiddlewares_CallsFirstMiddlewareSecondMiddlew 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); @@ -206,15 +393,15 @@ 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 + var rulesSourceMiddlewares = Enumerable.Empty(); - IRulesDataSource rulesDataSource = Mock.Of(); + var rulesDataSource = Mock.Of(); Mock.Get(rulesDataSource) .Setup(x => x.GetRulesByAsync(It.Is( (val) => string.Equals(val.Name, getRulesFilteredArgs.Name) && val.ContentType == getRulesFilteredArgs.ContentType && val.Priority == getRulesFilteredArgs.Priority))) @@ -237,16 +424,16 @@ IEnumerable rulesSourceMiddlewares 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()); IEnumerable rulesSourceMiddlewares = new[] { middleware1 }; - IRulesDataSource rulesDataSource = Mock.Of(); + var rulesDataSource = Mock.Of(); Mock.Get(rulesDataSource) .Setup(x => x.GetRulesByAsync(It.Is( (val) => string.Equals(val.Name, getRulesFilteredArgs.Name) && val.ContentType == getRulesFilteredArgs.ContentType && val.Priority == getRulesFilteredArgs.Priority))) @@ -270,10 +457,10 @@ 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); @@ -281,7 +468,7 @@ public async Task GetRulesFilteredAsync_TwoMiddlewares_CallsFirstMiddlewareSecon IEnumerable rulesSourceMiddlewares = new[] { middleware1, middleware2 }; - IRulesDataSource rulesDataSource = Mock.Of(); + var rulesDataSource = Mock.Of(); Mock.Get(rulesDataSource) .Setup(x => x.GetRulesByAsync(It.Is( (val) => string.Equals(val.Name, getRulesFilteredArgs.Name) && val.ContentType == getRulesFilteredArgs.ContentType && val.Priority == getRulesFilteredArgs.Priority))) @@ -307,17 +494,17 @@ public async Task GetRulesFilteredAsync_TwoMiddlewares_CallsFirstMiddlewareSecon public async Task UpdateRuleAsync_NoMiddlewares_CallsRulesDataSource() { // Arrange - Rule rule = CreateRule(); + var rule = CreateRule(); UpdateRuleArgs updateRuleArgs = new() { Rule = rule, }; - IEnumerable rulesSourceMiddlewares + 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)))) .Returns(Task.CompletedTask); @@ -336,7 +523,7 @@ IEnumerable rulesSourceMiddlewares public async Task UpdateRuleAsync_OneMiddleware_CallsMiddlewareAndRulesDataSourceAfter() { // Arrange - Rule rule = CreateRule(); + var rule = CreateRule(); UpdateRuleArgs updateRuleArgs = new() { @@ -347,7 +534,7 @@ public async Task UpdateRuleAsync_OneMiddleware_CallsMiddlewareAndRulesDataSourc 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)))) .Returns(Task.CompletedTask); @@ -367,7 +554,7 @@ public async Task UpdateRuleAsync_OneMiddleware_CallsMiddlewareAndRulesDataSourc public async Task UpdateRuleAsync_TwoMiddlewares_CallsFirstMiddlewareSecondMiddlewareAfterAndRulesDataSourceByLast() { // Arrange - Rule rule = CreateRule(); + var rule = CreateRule(); UpdateRuleArgs updateRuleArgs = new() { @@ -380,7 +567,7 @@ public async Task UpdateRuleAsync_TwoMiddlewares_CallsFirstMiddlewareSecondMiddl 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)))) .Returns(Task.CompletedTask); diff --git a/tests/Rules.Framework.Tests/Source/StubRulesSourceMiddleware.cs b/tests/Rules.Framework.Tests/Source/StubRulesSourceMiddleware.cs index 20238275..a185ff67 100644 --- a/tests/Rules.Framework.Tests/Source/StubRulesSourceMiddleware.cs +++ b/tests/Rules.Framework.Tests/Source/StubRulesSourceMiddleware.cs @@ -1,12 +1,8 @@ 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 { @@ -19,6 +15,8 @@ public StubRulesSourceMiddleware(string name, List 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; } @@ -34,6 +32,25 @@ public async Task HandleAddRuleAsync( this.middlewareMessages.Add($"Exit {this.Name}."); } + 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) From d7fadda703936a33315f00fbaf7930ef77a06b3a Mon Sep 17 00:00:00 2001 From: Luis Garces Date: Sun, 1 Sep 2024 11:02:59 +0100 Subject: [PATCH 4/5] chore: resolve codacy code analysis issues --- .../Extensions/RuleDtoExtensions.cs | 7 ---- src/Rules.Framework/Core/TypesCache.cs | 9 ++++ src/Rules.Framework/Generic/Rule.cs | 7 ++-- .../UpdateRulesManagementOperation.cs | 4 +- src/Rules.Framework/OperationResult.cs | 8 ++-- .../InMemory/InMemoryRulesStorage.cs | 2 +- .../InMemory/ServiceCollectionExtensions.cs | 4 +- src/Rules.Framework/RulesEngine.cs | 10 ++--- .../Tests/Benchmark1/Benchmark1.cs | 8 ++-- .../Tests/Benchmark2/Benchmark2.cs | 8 ++-- .../Tests/Benchmark3/Benchmark3.cs | 8 ++-- .../BuildingSecuritySystemControlTests.cs | 6 +-- .../Scenario2/CarInsuranceAdvisorTests.cs | 8 ++-- .../MongoDbProviderRulesDataSourceTests.cs | 2 +- .../Generic/RulesEngineTests.cs | 4 -- .../RuleOperationResultTests.cs | 8 ++-- .../Rules.Framework.Tests/RulesEngineTests.cs | 42 +++++++++---------- 17 files changed, 69 insertions(+), 76 deletions(-) create mode 100644 src/Rules.Framework/Core/TypesCache.cs diff --git a/src/Rules.Framework.WebUI/Extensions/RuleDtoExtensions.cs b/src/Rules.Framework.WebUI/Extensions/RuleDtoExtensions.cs index 53d39994..eeee5cc8 100644 --- a/src/Rules.Framework.WebUI/Extensions/RuleDtoExtensions.cs +++ b/src/Rules.Framework.WebUI/Extensions/RuleDtoExtensions.cs @@ -3,7 +3,6 @@ namespace Rules.Framework.WebUI.Extensions using System.Collections.Generic; using System.Linq; using Rules.Framework.ConditionNodes; - using Rules.Framework.Generic; using Rules.Framework.WebUI.Dto; internal static class RuleDtoExtensions @@ -12,12 +11,6 @@ internal static class RuleDtoExtensions public static ConditionNodeDto ToConditionNodeDto(this IConditionNode rootCondition) { - /* Unmerged change from project 'Rules.Framework.WebUI (netstandard2.0)' - Before: - if (rootCondition.LogicalOperator == Core.LogicalOperators.Eval || - After: - if (rootCondition.LogicalOperator == LogicalOperators.Eval || - */ if (rootCondition.LogicalOperator == Framework.LogicalOperators.Eval || rootCondition.LogicalOperator == 0) { 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/Generic/Rule.cs b/src/Rules.Framework/Generic/Rule.cs index 28be4616..2bf9ae61 100644 --- a/src/Rules.Framework/Generic/Rule.cs +++ b/src/Rules.Framework/Generic/Rule.cs @@ -1,6 +1,7 @@ namespace Rules.Framework.Generic { using System; + using Rules.Framework.Core; /// /// Defines a rule. @@ -11,21 +12,19 @@ namespace Rules.Framework.Generic /// public class Rule { - private static readonly Type stringType = typeof(string); - private readonly Rule wrappedRule; private IConditionNode? rootCondition; internal Rule(Rule wrappedRule) { var typeForContentType = typeof(TContentType); - if (!typeForContentType.IsEnum && typeForContentType != stringType) + 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 != stringType) + if (!typeForConditionType.IsEnum && typeForConditionType != TypesCache.String) { throw new NotSupportedException($"Only enum types or string are supported as {nameof(TConditionType)}."); } diff --git a/src/Rules.Framework/Management/Operations/UpdateRulesManagementOperation.cs b/src/Rules.Framework/Management/Operations/UpdateRulesManagementOperation.cs index f8f57886..49eddbcf 100644 --- a/src/Rules.Framework/Management/Operations/UpdateRulesManagementOperation.cs +++ b/src/Rules.Framework/Management/Operations/UpdateRulesManagementOperation.cs @@ -15,9 +15,9 @@ public UpdateRulesManagementOperation(IRulesSource rulesSource) public async Task> ApplyAsync(IEnumerable rules) { - foreach (Rule existentRule in rules) + foreach (var existentRule in rules) { - var updateRuleArgs = new UpdateRuleArgs() + var updateRuleArgs = new UpdateRuleArgs { Rule = existentRule, }; diff --git a/src/Rules.Framework/OperationResult.cs b/src/Rules.Framework/OperationResult.cs index 7a524d7e..4352aa34 100644 --- a/src/Rules.Framework/OperationResult.cs +++ b/src/Rules.Framework/OperationResult.cs @@ -32,18 +32,18 @@ protected OperationResult(bool isSuccess, IEnumerable errors) /// true if rule operation was successfull; otherwise, false. public bool IsSuccess { get; } - internal static OperationResult Error(string error) => Error(new[] { error }); + internal static OperationResult Failure(string error) => Failure(new[] { error }); - internal static OperationResult Error(IEnumerable errors) + internal static OperationResult Failure(IEnumerable errors) { if (errors is null) { throw new ArgumentNullException(nameof(errors)); } - return new OperationResult(false, errors); + return new OperationResult(isSuccess: false, errors: errors); } - internal static OperationResult Success() => new OperationResult(true, Enumerable.Empty()); + internal static OperationResult Success() => new(isSuccess: true, errors: Enumerable.Empty()); } } \ No newline at end of file diff --git a/src/Rules.Framework/Providers/InMemory/InMemoryRulesStorage.cs b/src/Rules.Framework/Providers/InMemory/InMemoryRulesStorage.cs index 01f37eeb..791db04c 100644 --- a/src/Rules.Framework/Providers/InMemory/InMemoryRulesStorage.cs +++ b/src/Rules.Framework/Providers/InMemory/InMemoryRulesStorage.cs @@ -66,6 +66,6 @@ public void UpdateRule(RuleDataModel ruleDataModel) } private List GetRulesCollectionByContentType(string contentType) => this.rulesByContentType - .GetOrAdd(contentType, (ct) => new List()); + .GetOrAdd(contentType, _ => new List()); } } \ 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 5b6b5332..577c57d8 100644 --- a/src/Rules.Framework/Providers/InMemory/ServiceCollectionExtensions.cs +++ b/src/Rules.Framework/Providers/InMemory/ServiceCollectionExtensions.cs @@ -15,9 +15,9 @@ public static class ServiceCollectionExtensions /// public static IServiceCollection AddInMemoryRulesDataSource(this IServiceCollection serviceDescriptors, ServiceLifetime serviceLifetime) { - ServiceDescriptor item = ServiceDescriptor.Describe( + var item = ServiceDescriptor.Describe( typeof(IInMemoryRulesStorage), - (sp) => new InMemoryRulesStorage(), + _ => new InMemoryRulesStorage(), serviceLifetime); serviceDescriptors.Add(item); diff --git a/src/Rules.Framework/RulesEngine.cs b/src/Rules.Framework/RulesEngine.cs index a8a06a62..420e4b91 100644 --- a/src/Rules.Framework/RulesEngine.cs +++ b/src/Rules.Framework/RulesEngine.cs @@ -83,7 +83,7 @@ public async Task CreateContentTypeAsync(string contentType) var existentContentTypes = await this.rulesSource.GetContentTypesAsync(getContentTypesArgs).ConfigureAwait(false); if (existentContentTypes.Contains(contentType, StringComparer.Ordinal)) { - return OperationResult.Error($"The content type '{contentType}' already exists."); + return OperationResult.Failure($"The content type '{contentType}' already exists."); } return await this.CreateContentTypeInternalAsync(contentType).ConfigureAwait(false); @@ -253,7 +253,7 @@ private async Task AddRuleInternalAsync(Rule rule, RuleAddPrior { 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.Error(errors); + return OperationResult.Failure(errors); } await this.CreateContentTypeInternalAsync(rule.ContentType).ConfigureAwait(false); @@ -279,7 +279,7 @@ private async Task AddRuleInternalAsync(Rule rule, RuleAddPrior if (errors.Any()) { - return OperationResult.Error(errors); + return OperationResult.Failure(errors); } switch (ruleAddPriorityOption.PriorityOption) @@ -489,14 +489,14 @@ private async Task UpdateRuleInternalAsync(Rule rule) var existentRule = existentRules.FirstOrDefault(r => string.Equals(r.Name, rule.Name, StringComparison.OrdinalIgnoreCase)); if (existentRule is null) { - return OperationResult.Error($"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 OperationResult.Error(validationResult.Errors.Select(ve => ve.ErrorMessage)); + return OperationResult.Failure(validationResult.Errors.Select(ve => ve.ErrorMessage)); } var topPriorityThreshold = Math.Min(rule.Priority, existentRule.Priority); diff --git a/tests/Rules.Framework.BenchmarkTests/Tests/Benchmark1/Benchmark1.cs b/tests/Rules.Framework.BenchmarkTests/Tests/Benchmark1/Benchmark1.cs index 58f9a536..5f1bc6aa 100644 --- a/tests/Rules.Framework.BenchmarkTests/Tests/Benchmark1/Benchmark1.cs +++ b/tests/Rules.Framework.BenchmarkTests/Tests/Benchmark1/Benchmark1.cs @@ -8,7 +8,7 @@ namespace Rules.Framework.BenchmarkTests.Tests.Benchmark1 public class Benchmark1 : IBenchmark { private readonly Scenario6Data benchmarkData = new Scenario6Data(); - private IRulesEngine? rulesEngine; + private IRulesEngine? genericRulesEngine; [ParamsAllValues] public bool EnableCompilation { get; set; } @@ -19,7 +19,7 @@ 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] @@ -40,14 +40,14 @@ public async Task SetUpAsync() await rulesEngine.AddRuleAsync(rule, RuleAddPriorityOption.AtTop); } - this.rulesEngine = rulesEngine.MakeGeneric(); + 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 6ceb2b91..c3d32b0f 100644 --- a/tests/Rules.Framework.BenchmarkTests/Tests/Benchmark2/Benchmark2.cs +++ b/tests/Rules.Framework.BenchmarkTests/Tests/Benchmark2/Benchmark2.cs @@ -8,7 +8,7 @@ namespace Rules.Framework.BenchmarkTests.Tests.Benchmark2 public class Benchmark2 : IBenchmark { private readonly Scenario7Data benchmarkData = new Scenario7Data(); - private IRulesEngine? rulesEngine; + private IRulesEngine? genericRulesEngine; [ParamsAllValues] public bool EnableCompilation { get; set; } @@ -19,7 +19,7 @@ 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] @@ -40,14 +40,14 @@ public async Task SetUpAsync() await rulesEngine.AddRuleAsync(rule, RuleAddPriorityOption.AtTop).ConfigureAwait(false); } - this.rulesEngine = rulesEngine.MakeGeneric(); + 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 f68a3fc3..60339bf2 100644 --- a/tests/Rules.Framework.BenchmarkTests/Tests/Benchmark3/Benchmark3.cs +++ b/tests/Rules.Framework.BenchmarkTests/Tests/Benchmark3/Benchmark3.cs @@ -8,7 +8,7 @@ namespace Rules.Framework.BenchmarkTests.Tests.Benchmark3 public class Benchmark3 : IBenchmark { private readonly Scenario8Data benchmarkData = new Scenario8Data(); - private IRulesEngine? rulesEngine; + private IRulesEngine? genericRulesEngine; [ParamsAllValues] public bool EnableCompilation { get; set; } @@ -19,7 +19,7 @@ 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] @@ -40,14 +40,14 @@ public async Task SetUpAsync() await rulesEngine.AddRuleAsync(rule, RuleAddPriorityOption.AtTop).ConfigureAwait(false); } - this.rulesEngine = rulesEngine.MakeGeneric(); + 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.Providers.InMemory.IntegrationTests/Scenarios/Scenario3/BuildingSecuritySystemControlTests.cs b/tests/Rules.Framework.Providers.InMemory.IntegrationTests/Scenarios/Scenario3/BuildingSecuritySystemControlTests.cs index 94531993..e9014fef 100644 --- a/tests/Rules.Framework.Providers.InMemory.IntegrationTests/Scenarios/Scenario3/BuildingSecuritySystemControlTests.cs +++ b/tests/Rules.Framework.Providers.InMemory.IntegrationTests/Scenarios/Scenario3/BuildingSecuritySystemControlTests.cs @@ -36,7 +36,7 @@ public async Task BuildingSecuritySystem_FireScenario_ReturnsActionsToTrigger(bo const SecuritySystemActionables securitySystemActionable = SecuritySystemActionables.FireSystem; var expectedMatchDate = new DateTime(2018, 06, 01); - var expectedConditions = new Condition[] + var expectedConditions = new[] { new Condition(SecuritySystemConditions.TemperatureCelsius, 100.0m), new Condition(SecuritySystemConditions.SmokeRate, 55.0m), @@ -79,7 +79,7 @@ public async Task BuildingSecuritySystem_PowerFailureScenario_ReturnsActionsToTr const SecuritySystemActionables securitySystemActionable = SecuritySystemActionables.PowerSystem; var expectedMatchDate = new DateTime(2018, 06, 01); - var expectedConditions = new Condition[] + var expectedConditions = new[] { new Condition(SecuritySystemConditions.TemperatureCelsius, 100.0m), new Condition(SecuritySystemConditions.SmokeRate, 55.0m), @@ -121,7 +121,7 @@ public async Task BuildingSecuritySystem_PowerShutdownScenario_ReturnsActionsToT const SecuritySystemActionables securitySystemActionable = SecuritySystemActionables.PowerSystem; var expectedMatchDate = new DateTime(2018, 06, 01); - var expectedConditions = new Condition[] + var expectedConditions = new[] { new Condition(SecuritySystemConditions.TemperatureCelsius, 100.0m), new Condition(SecuritySystemConditions.SmokeRate, 55.0m), 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 bd32d220..2f9cb019 100644 --- a/tests/Rules.Framework.Providers.MongoDb.IntegrationTests/Scenarios/Scenario2/CarInsuranceAdvisorTests.cs +++ b/tests/Rules.Framework.Providers.MongoDb.IntegrationTests/Scenarios/Scenario2/CarInsuranceAdvisorTests.cs @@ -43,7 +43,7 @@ public CarInsuranceAdvisorTests() TypeNameHandling = TypeNameHandling.All }); - rules = array.Select(t => + rules = array!.Select(t => { t.Content = t.Content as string; @@ -136,7 +136,7 @@ public async Task GetCarInsuranceAdvice_UpdatesRuleAndAddsNewOneAndEvaluates_Ret .Build(); var genericRulesEngine = rulesEngine.MakeGeneric(); - var rulesDataSource = CreateRulesDataSourceTest(this.mongoClient, this.mongoDbProviderSettings); + var rulesDataSource = CreateRulesDataSourceTest(this.mongoClient, this.mongoDbProviderSettings); var ruleBuilderResult = Rule.New() .WithName("Car Insurance Advise on self damage coverage") @@ -258,7 +258,7 @@ private static MongoClient CreateMongoClient() return new MongoClient(settings); } - private static IRulesDataSource CreateRulesDataSourceTest( + private static MongoDbProviderRulesDataSource CreateRulesDataSourceTest( IMongoClient mongoClient, MongoDbProviderSettings mongoDbProviderSettings) { @@ -270,7 +270,7 @@ private static IRulesDataSource CreateRulesDataSourceTest new MongoDbProviderSettings + private MongoDbProviderSettings CreateProviderSettings() => new() { DatabaseName = "rules-framework-tests", RulesCollectionName = "car-insurance-advisor" diff --git a/tests/Rules.Framework.Providers.MongoDb.Tests/MongoDbProviderRulesDataSourceTests.cs b/tests/Rules.Framework.Providers.MongoDb.Tests/MongoDbProviderRulesDataSourceTests.cs index 3c909771..3b41bbb2 100644 --- a/tests/Rules.Framework.Providers.MongoDb.Tests/MongoDbProviderRulesDataSourceTests.cs +++ b/tests/Rules.Framework.Providers.MongoDb.Tests/MongoDbProviderRulesDataSourceTests.cs @@ -22,7 +22,7 @@ public async Task CreateContentTypeAsync_GivenContentTypeName_InsertsContentType var contentTypesCollection = Mock.Of>(); Mock.Get(contentTypesCollection) .Setup(x => x.InsertOneAsync(It.IsAny(), It.IsAny(), It.IsAny())) - .Callback((ct, opt, t) => actual = ct); + .Callback((ct, _, __) => actual = ct); var mongoDatabase = Mock.Of(); Mock.Get(mongoDatabase) diff --git a/tests/Rules.Framework.Tests/Generic/RulesEngineTests.cs b/tests/Rules.Framework.Tests/Generic/RulesEngineTests.cs index 870d2c97..4136c2bc 100644 --- a/tests/Rules.Framework.Tests/Generic/RulesEngineTests.cs +++ b/tests/Rules.Framework.Tests/Generic/RulesEngineTests.cs @@ -106,10 +106,6 @@ public async Task SearchAsync_GivenContentTypeAndDatesIntervalAndNoConditions_Re .WithCondition(ConditionType.IsoCountryCode, Operators.Equal, "USA") .Build().Rule; expectedRule.Priority = 3; - var expectedGenericRules = new List - { - expectedRule, - }; var dateBegin = new DateTime(2022, 01, 01); var dateEnd = new DateTime(2022, 12, 01); diff --git a/tests/Rules.Framework.Tests/RuleOperationResultTests.cs b/tests/Rules.Framework.Tests/RuleOperationResultTests.cs index c858a89b..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 - var ruleOperationResult = OperationResult.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 - var argumentNullException = Assert.Throws(() => OperationResult.Error(errors)); + var argumentNullException = Assert.Throws(() => OperationResult.Failure(errors)); // Assert argumentNullException.Should().NotBeNull(); diff --git a/tests/Rules.Framework.Tests/RulesEngineTests.cs b/tests/Rules.Framework.Tests/RulesEngineTests.cs index 1eb1c7e1..283536df 100644 --- a/tests/Rules.Framework.Tests/RulesEngineTests.cs +++ b/tests/Rules.Framework.Tests/RulesEngineTests.cs @@ -37,11 +37,9 @@ public RulesEngineTests() public async Task ActivateRuleAsync_GivenEmptyRuleDataSource_ActivatesRuleSuccessfully() { // Arrange - var contentType = ContentType.Type1.ToString(); - var testRule = new Rule { - ContentContainer = new ContentContainer((t) => new object()), + ContentContainer = new ContentContainer(_ => new object()), DateBegin = new DateTime(2018, 01, 01), DateEnd = new DateTime(2019, 01, 01), Name = "Update test rule", @@ -79,7 +77,7 @@ public async Task AddRuleAsync_GivenEmptyRuleDataSourceAndExistentContentType_Ad var testRule = new Rule { ContentType = contentType, - ContentContainer = new ContentContainer((t) => new object()), + ContentContainer = new ContentContainer(_ => new object()), DateBegin = new DateTime(2018, 01, 01), DateEnd = new DateTime(2019, 01, 01), Name = "Test rule", @@ -117,7 +115,7 @@ public async Task AddRuleAsync_GivenEmptyRuleDataSourceAndNonExistentContentType var testRule = new Rule { ContentType = contentType, - ContentContainer = new ContentContainer((t) => new object()), + ContentContainer = new ContentContainer(_ => new object()), DateBegin = new DateTime(2018, 01, 01), DateEnd = new DateTime(2019, 01, 01), Name = "Test rule", @@ -155,7 +153,7 @@ public async Task AddRuleAsync_GivenEmptyRuleDataSourceAndNonExistentContentType var testRule = new Rule { ContentType = contentType, - ContentContainer = new ContentContainer((t) => new object()), + ContentContainer = new ContentContainer(_ => new object()), DateBegin = new DateTime(2018, 01, 01), DateEnd = new DateTime(2019, 01, 01), Name = "Test rule", @@ -260,7 +258,7 @@ public async Task DeactivateRuleAsync_GivenEmptyRuleDataSource_DeactivatesRuleSu var testRule = new Rule { - ContentContainer = new ContentContainer((t) => new object()), + ContentContainer = new ContentContainer(_ => new object()), DateBegin = new DateTime(2018, 01, 01), DateEnd = new DateTime(2019, 01, 01), Name = "Update test rule", @@ -340,11 +338,9 @@ public async Task GetUniqueConditionTypesAsync_GivenThereAreRulesInDataSource_Re .Setup(x => x.GetConditionTypes(It.IsAny>())) .Returns(expectedCondtionTypes); - this.SetupMockForConditionsEvalEngine((rootConditionNode, _, _) => rootConditionNode switch - { - ValueConditionNode stringConditionNode => stringConditionNode.Operand.ToString() == "USA", - _ => false, - }, evaluationOptions); + this.SetupMockForConditionsEvalEngine( + (rootConditionNode, _, _) => rootConditionNode is ValueConditionNode stringConditionNode && stringConditionNode.Operand.ToString() == "USA", + evaluationOptions); var validatorProvider = Mock.Of(); @@ -375,7 +371,7 @@ public async Task MatchManyAsync_GivenContentTypeDateAndConditions_FetchesRulesF var expected1 = new Rule { - ContentContainer = new ContentContainer((t) => new object()), + ContentContainer = new ContentContainer(_ => new object()), DateBegin = new DateTime(2018, 01, 01), DateEnd = new DateTime(2019, 01, 01), Name = "Expected rule 1", @@ -385,7 +381,7 @@ public async Task MatchManyAsync_GivenContentTypeDateAndConditions_FetchesRulesF var expected2 = new Rule { - ContentContainer = new ContentContainer((t) => new object()), + ContentContainer = new ContentContainer(_ => new object()), DateBegin = new DateTime(2010, 01, 01), DateEnd = new DateTime(2021, 01, 01), Name = "Expected rule 2", @@ -395,7 +391,7 @@ public async Task MatchManyAsync_GivenContentTypeDateAndConditions_FetchesRulesF var notExpected = new Rule { - ContentContainer = new ContentContainer((t) => new object()), + ContentContainer = new ContentContainer(_ => new object()), DateBegin = new DateTime(2018, 01, 01), DateEnd = new DateTime(2019, 01, 01), Name = "Not expected rule", @@ -455,7 +451,7 @@ public async Task MatchOneAsync_GivenContentTypeDateAndConditions_FetchesRulesFo var other = new Rule { - ContentContainer = new ContentContainer((t) => new object()), + ContentContainer = new ContentContainer(_ => new object()), DateBegin = new DateTime(2018, 01, 01), DateEnd = new DateTime(2019, 01, 01), Name = "Expected rule", @@ -465,7 +461,7 @@ public async Task MatchOneAsync_GivenContentTypeDateAndConditions_FetchesRulesFo var expected = new Rule { - ContentContainer = new ContentContainer((t) => new object()), + ContentContainer = new ContentContainer(_ => new object()), DateBegin = new DateTime(2010, 01, 01), DateEnd = new DateTime(2021, 01, 01), Name = "Expected rule", @@ -521,7 +517,7 @@ public async Task MatchOneAsync_GivenContentTypeDateAndConditions_FetchesRulesFo var expected = new Rule { - ContentContainer = new ContentContainer((t) => new object()), + ContentContainer = new ContentContainer(_ => new object()), DateBegin = new DateTime(2018, 01, 01), DateEnd = new DateTime(2019, 01, 01), Name = "Expected rule", @@ -531,7 +527,7 @@ public async Task MatchOneAsync_GivenContentTypeDateAndConditions_FetchesRulesFo var other = new Rule { - ContentContainer = new ContentContainer((t) => new object()), + ContentContainer = new ContentContainer(_ => new object()), DateBegin = new DateTime(2010, 01, 01), DateEnd = new DateTime(2021, 01, 01), Name = "Expected rule", @@ -587,7 +583,7 @@ public async Task MatchOneAsync_GivenContentTypeDateAndConditions_FetchesRulesFo { new Rule { - ContentContainer = new ContentContainer((t) => new object()), + ContentContainer = new ContentContainer(_ => new object()), DateBegin = new DateTime(2018, 01, 01), DateEnd = new DateTime(2019, 01, 01), Name = "Expected rule", @@ -596,7 +592,7 @@ public async Task MatchOneAsync_GivenContentTypeDateAndConditions_FetchesRulesFo }, new Rule { - ContentContainer = new ContentContainer((t) => new object()), + ContentContainer = new ContentContainer(_ => new object()), DateBegin = new DateTime(2010, 01, 01), DateEnd = new DateTime(2021, 01, 01), Name = "Expected rule", @@ -639,7 +635,7 @@ public async Task UpdateRuleAsync_GivenEmptyRuleDataSource_UpdatesRuleSuccesfull var testRule = new Rule { - ContentContainer = new ContentContainer((t) => new object()), + ContentContainer = new ContentContainer(_ => new object()), DateBegin = new DateTime(2018, 01, 01), DateEnd = new DateTime(2019, 01, 01), Name = "Update test rule", @@ -685,7 +681,7 @@ public async Task UpdateRuleAsync_GivenRuleWithInvalidDateEnd_UpdatesRuleFailure var testRule = new Rule { - ContentContainer = new ContentContainer((t) => new object()), + ContentContainer = new ContentContainer(_ => new object()), DateBegin = new DateTime(2018, 01, 01), DateEnd = new DateTime(2019, 01, 01), Name = "Update test rule", From dc7ce52d48f6207a09763c0abca32ee26b0c7187 Mon Sep 17 00:00:00 2001 From: Luis Garces Date: Sun, 1 Sep 2024 11:18:07 +0100 Subject: [PATCH 5/5] chore: resolve codacy code analysis issues #2 --- src/Rules.Framework/ContentTypeException.cs | 11 ----------- .../Operations/AddRuleManagementOperation.cs | 3 +-- src/Rules.Framework/Source/RulesSource.cs | 2 +- .../MongoDbProviderRulesDataSourceTests.cs | 2 +- .../ConditionTypeExtractorTests.cs | 6 +----- tests/Rules.Framework.Tests/ContentContainerTests.cs | 4 ++-- tests/Rules.Framework.Tests/RulesEngineTests.cs | 8 +------- 7 files changed, 7 insertions(+), 29 deletions(-) diff --git a/src/Rules.Framework/ContentTypeException.cs b/src/Rules.Framework/ContentTypeException.cs index 3383453c..711907eb 100644 --- a/src/Rules.Framework/ContentTypeException.cs +++ b/src/Rules.Framework/ContentTypeException.cs @@ -2,17 +2,6 @@ namespace Rules.Framework { using System; using System.Diagnostics.CodeAnalysis; - - /* Unmerged change from project 'Rules.Framework (netstandard2.0)' - Before: - using System.Runtime.Serialization; - After: - using System.Runtime.Serialization; - using Rules; - using Rules.Framework; - using Rules.Framework; - using Rules.Framework.Core; - */ using System.Runtime.Serialization; /// diff --git a/src/Rules.Framework/Management/Operations/AddRuleManagementOperation.cs b/src/Rules.Framework/Management/Operations/AddRuleManagementOperation.cs index b4a7b802..95f127c0 100644 --- a/src/Rules.Framework/Management/Operations/AddRuleManagementOperation.cs +++ b/src/Rules.Framework/Management/Operations/AddRuleManagementOperation.cs @@ -2,7 +2,6 @@ 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 @@ -18,7 +17,7 @@ public AddRuleManagementOperation(IRulesSource rulesDataSource, Rule rule) public async Task> ApplyAsync(IEnumerable rules) { - var addRuleArgs = new AddRuleArgs() + var addRuleArgs = new AddRuleArgs { Rule = this.rule, }; diff --git a/src/Rules.Framework/Source/RulesSource.cs b/src/Rules.Framework/Source/RulesSource.cs index b8c81082..2cf837b3 100644 --- a/src/Rules.Framework/Source/RulesSource.cs +++ b/src/Rules.Framework/Source/RulesSource.cs @@ -109,7 +109,7 @@ private static GetContentTypesDelegate CreateGetContentTypesPipelineDelegate( IRulesDataSource rulesDataSource, LinkedList middlewares) { - GetContentTypesDelegate action = async (args) => await rulesDataSource.GetContentTypesAsync().ConfigureAwait(false); + GetContentTypesDelegate action = async (_) => await rulesDataSource.GetContentTypesAsync().ConfigureAwait(false); if (middlewares.Count > 0) { diff --git a/tests/Rules.Framework.Providers.MongoDb.Tests/MongoDbProviderRulesDataSourceTests.cs b/tests/Rules.Framework.Providers.MongoDb.Tests/MongoDbProviderRulesDataSourceTests.cs index 3b41bbb2..d60e780f 100644 --- a/tests/Rules.Framework.Providers.MongoDb.Tests/MongoDbProviderRulesDataSourceTests.cs +++ b/tests/Rules.Framework.Providers.MongoDb.Tests/MongoDbProviderRulesDataSourceTests.cs @@ -22,7 +22,7 @@ public async Task CreateContentTypeAsync_GivenContentTypeName_InsertsContentType var contentTypesCollection = Mock.Of>(); Mock.Get(contentTypesCollection) .Setup(x => x.InsertOneAsync(It.IsAny(), It.IsAny(), It.IsAny())) - .Callback((ct, _, __) => actual = ct); + .Callback((ct, _, _) => actual = ct); var mongoDatabase = Mock.Of(); Mock.Get(mongoDatabase) diff --git a/tests/Rules.Framework.Tests/ConditionTypeExtractorTests.cs b/tests/Rules.Framework.Tests/ConditionTypeExtractorTests.cs index 7e9ce124..5f6d85f8 100644 --- a/tests/Rules.Framework.Tests/ConditionTypeExtractorTests.cs +++ b/tests/Rules.Framework.Tests/ConditionTypeExtractorTests.cs @@ -18,8 +18,6 @@ public void GetConditionTypes_ReturnsCorrectExtraction() var dateBegin = new DateTime(2018, 01, 01); var dateEnd = new DateTime(2019, 01, 01); - var contentType = ContentType.Type1.ToString(); - var rule1 = new Rule { ContentContainer = new ContentContainer(_ => new object()), @@ -119,11 +117,9 @@ public void GetConditionTypes_WithNullRootCondition_ReturnsEmptyListConditionTyp var dateBegin = new DateTime(2018, 01, 01); var dateEnd = new DateTime(2019, 01, 01); - var contentType = ContentType.Type1.ToString(); - var matchRules = new List { - new Rule + new() { ContentContainer = new ContentContainer(_ => new object()), DateBegin = dateBegin, diff --git a/tests/Rules.Framework.Tests/ContentContainerTests.cs b/tests/Rules.Framework.Tests/ContentContainerTests.cs index d8bf9481..615497df 100644 --- a/tests/Rules.Framework.Tests/ContentContainerTests.cs +++ b/tests/Rules.Framework.Tests/ContentContainerTests.cs @@ -13,7 +13,7 @@ public void ContentContainer_GetContentAs_HavingProvidedContentByCtorAndGivenCor // Arrange object expected = "Just some content"; - var sut = new ContentContainer((t) => expected); + var sut = new ContentContainer(_ => expected); // Act object actual = sut.GetContentAs(); @@ -28,7 +28,7 @@ public void ContentContainer_GetContentAs_HavingProvidedContentByCtorAndGivenWro // Arrange object expected = "Just some content"; - var sut = new ContentContainer((t) => expected); + var sut = new ContentContainer(_ => expected); // Act var contentTypeException = Assert.Throws(() => sut.GetContentAs()); diff --git a/tests/Rules.Framework.Tests/RulesEngineTests.cs b/tests/Rules.Framework.Tests/RulesEngineTests.cs index 283536df..1a4e7adf 100644 --- a/tests/Rules.Framework.Tests/RulesEngineTests.cs +++ b/tests/Rules.Framework.Tests/RulesEngineTests.cs @@ -254,8 +254,6 @@ public async Task CreateContentTypeAsync_GivenNonExistentContentTypeName_AddsCon public async Task DeactivateRuleAsync_GivenEmptyRuleDataSource_DeactivatesRuleSuccessfully() { // Arrange - var contentType = ContentType.Type1.ToString(); - var testRule = new Rule { ContentContainer = new ContentContainer(_ => new object()), @@ -630,9 +628,7 @@ public async Task MatchOneAsync_GivenContentTypeDateAndConditions_FetchesRulesFo [Fact] public async Task UpdateRuleAsync_GivenEmptyRuleDataSource_UpdatesRuleSuccesfully() { - // Arrange - var contentType = ContentType.Type1.ToString(); - + // Arrange« var testRule = new Rule { ContentContainer = new ContentContainer(_ => new object()), @@ -677,8 +673,6 @@ public async Task UpdateRuleAsync_GivenEmptyRuleDataSource_UpdatesRuleSuccesfull public async Task UpdateRuleAsync_GivenRuleWithInvalidDateEnd_UpdatesRuleFailure() { // Arrange - var contentType = ContentType.Type1.ToString(); - var testRule = new Rule { ContentContainer = new ContentContainer(_ => new object()),