diff --git a/.gitignore b/.gitignore
index c4d97504..bf807ea3 100644
--- a/.gitignore
+++ b/.gitignore
@@ -244,3 +244,4 @@ ModelManifest.xml
OptimizelySDK.Package/nuget.exe
OptimizelySDK.Package/content
OptimizelySDK.Package/lib
+
diff --git a/OptimizelySDK.Net35/OptimizelySDK.Net35.csproj b/OptimizelySDK.Net35/OptimizelySDK.Net35.csproj
index 8dc64e4e..9d3d441d 100644
--- a/OptimizelySDK.Net35/OptimizelySDK.Net35.csproj
+++ b/OptimizelySDK.Net35/OptimizelySDK.Net35.csproj
@@ -46,28 +46,28 @@
-
+
AudienceConditions\AndCondition.cs
-
+
AudienceConditions\AudienceIdCondition.cs
-
+
AudienceConditions\BaseCondition.cs
-
+
AudienceConditions\SemanticVersion.cs
-
+
AudienceConditions\EmptyCondition.cs
-
+
AudienceConditions\ICondition.cs
-
+
AudienceConditions\NotCondition.cs
-
+
AudienceConditions\OrCondition.cs
@@ -100,7 +100,7 @@
Entity\IdKeyEntity.cs
-
+
OptimizelyJSON.cs
@@ -139,7 +139,7 @@
Event\LogEvent.cs
-
+
Event\ForwardingEventProcessor.cs
@@ -178,19 +178,19 @@
Utils\ControlAttributes.cs
-
+
Utils\ExceptionExtensions.cs
-
+
Utils\ConditionParser.cs
-
+
Utils\AttributeMatchTypes.cs
-
+
Utils\DecisionInfoTypes.cs
-
+
Utils\DateTimeUtils.cs
@@ -227,108 +227,117 @@
Entity\Rollout
-
+
ProjectConfig
-
+
Config\DatafileProjectConfig
-
+
Config\ProjectConfigManager
-
- Config\FallbackProjectConfigManager.cs
-
-
- Event\Entity\ConversionEvent.cs
-
-
- Event\Entity\Decision.cs
-
-
- Event\Entity\EventBatch.cs
-
-
- Event\Entity\EventContext.cs
-
-
- Event\Entity\ImpressionEvent.cs
-
-
- Event\Entity\Snapshot.cs
-
-
- Event\Entity\SnapshotEvent.cs
-
-
- Event\Entity\UserEvent.cs
-
-
- Event\Entity\Visitor.cs
-
-
- Event\Entity\DecisionMetadata.cs
-
-
- Event\Entity\VisitorAttribute.cs
-
-
- Event\EventFactory.cs
-
-
- Event\UserEventFactory.cs
-
-
- Event\EventProcessor.cs
-
-
- OptlyConfig\OptimizelyConfig.cs
-
-
- OptlyConfig\OptimizelyAttribute.cs
-
-
- OptlyConfig\OptimizelyEvent.cs
-
-
- OptlyConfig\OptimizelyExperiment.cs
-
-
- OptlyConfig\OptimizelyAudience.cs
-
-
- OptlyConfig\OptimizelyFeature.cs
-
-
- OptlyConfig\OptimizelyVariable.cs
-
-
- OptlyConfig\OptimizelyVariation.cs
-
-
- OptlyConfig\OptimizelyConfigService.cs
-
-
- OptlyConfig\IOptimizelyConfigManager.cs
-
-
+
+ Config\FallbackProjectConfigManager.cs
+
+
+ Event\Entity\ConversionEvent.cs
+
+
+ Event\Entity\Decision.cs
+
+
+ Event\Entity\EventBatch.cs
+
+
+ Event\Entity\EventContext.cs
+
+
+ Event\Entity\ImpressionEvent.cs
+
+
+ Event\Entity\Snapshot.cs
+
+
+ Event\Entity\SnapshotEvent.cs
+
+
+ Event\Entity\UserEvent.cs
+
+
+ Event\Entity\Visitor.cs
+
+
+ Event\Entity\DecisionMetadata.cs
+
+
+ Event\Entity\VisitorAttribute.cs
+
+
+ Event\EventFactory.cs
+
+
+ Event\UserEventFactory.cs
+
+
+ Event\EventProcessor.cs
+
+
+ OptlyConfig\OptimizelyConfig.cs
+
+
+ OptlyConfig\OptimizelyAttribute.cs
+
+
+ OptlyConfig\OptimizelyEvent.cs
+
+
+ OptlyConfig\OptimizelyExperiment.cs
+
+
+ OptlyConfig\OptimizelyAudience.cs
+
+
+ OptlyConfig\OptimizelyFeature.cs
+
+
+ OptlyConfig\OptimizelyVariable.cs
+
+
+ OptlyConfig\OptimizelyVariation.cs
+
+
+ OptlyConfig\OptimizelyConfigService.cs
+
+
+ OptlyConfig\IOptimizelyConfigManager.cs
+
+
OptimizelyDecisions\DecisionMessage.cs
-
+
OptimizelyDecisions\OptimizelyDecideOption.cs
-
+
OptimizelyDecisions\OptimizelyDecision.cs
-
+
+ OptimizelyDecisionContext.cs
+
+
+ ForcedDecisionsStore.cs
+
+
+ OptimizelyForcedDecision.cs
+
+
OptimizelyUserContext.cs
-
- Entity\Result.cs
-
-
- OptimizelyDecisions\DecisionReasons.cs
-
+
+ Entity\Result.cs
+
+
+ OptimizelyDecisions\DecisionReasons.cs
+
diff --git a/OptimizelySDK.Net40/OptimizelySDK.Net40.csproj b/OptimizelySDK.Net40/OptimizelySDK.Net40.csproj
index e5c64c6c..3dfdfbc9 100644
--- a/OptimizelySDK.Net40/OptimizelySDK.Net40.csproj
+++ b/OptimizelySDK.Net40/OptimizelySDK.Net40.csproj
@@ -48,28 +48,28 @@
-
+
AudienceConditions\AndCondition.cs
-
+
AudienceConditions\AudienceIdCondition.cs
-
+
AudienceConditions\BaseCondition.cs
-
+
AudienceConditions\SemanticVersion.cs
-
+
AudienceConditions\EmptyCondition.cs
-
+
AudienceConditions\ICondition.cs
-
+
AudienceConditions\NotCondition.cs
-
+
AudienceConditions\OrCondition.cs
@@ -102,7 +102,7 @@
Entity\IdKeyEntity.cs
-
+
OptimizelyJSON.cs
@@ -165,7 +165,7 @@
Utils\ConfigParser.cs
-
+
Utils\ConditionParser.cs
@@ -180,16 +180,16 @@
Utils\ControlAttributes.cs
-
+
Utils\ExceptionExtensions.cs
-
+
Utils\AttributeMatchTypes.cs
-
+
Utils\DecisionInfoTypes.cs
-
+
Utils\DateTimeUtils.cs
@@ -226,126 +226,135 @@
Entity\Rollout
-
+
ProjectConfig
-
+
Config\DatafileProjectConfig
-
+
Config\ProjectConfigManager
-
+
Config\PollingProjectConfigManager
-
+
ClientConfigHandler
-
+
Config\HttpProjectConfigManager
-
- Config\FallbackProjectConfigManager.cs
-
-
- OptimizelyFactory.cs
-
-
- Event\Entity\ConversionEvent.cs
-
-
- Event\Entity\Decision.cs
-
-
- Event\Entity\EventBatch.cs
-
-
- Event\Entity\EventContext.cs
-
-
- Event\Entity\ImpressionEvent.cs
-
-
- Event\Entity\Snapshot.cs
-
-
- Event\Entity\SnapshotEvent.cs
-
-
- Event\Entity\UserEvent.cs
-
-
- Event\Entity\Visitor.cs
-
-
- Event\Entity\VisitorAttribute.cs
-
-
- Event\Entity\DecisionMetadata.cs
-
-
- Event\EventFactory.cs
-
-
- Event\UserEventFactory.cs
-
-
- Event\BatchEventProcessor.cs
-
-
- Event\EventProcessor.cs
-
-
+
+ Config\FallbackProjectConfigManager.cs
+
+
+ OptimizelyFactory.cs
+
+
+ Event\Entity\ConversionEvent.cs
+
+
+ Event\Entity\Decision.cs
+
+
+ Event\Entity\EventBatch.cs
+
+
+ Event\Entity\EventContext.cs
+
+
+ Event\Entity\ImpressionEvent.cs
+
+
+ Event\Entity\Snapshot.cs
+
+
+ Event\Entity\SnapshotEvent.cs
+
+
+ Event\Entity\UserEvent.cs
+
+
+ Event\Entity\Visitor.cs
+
+
+ Event\Entity\VisitorAttribute.cs
+
+
+ Event\Entity\DecisionMetadata.cs
+
+
+ Event\EventFactory.cs
+
+
+ Event\UserEventFactory.cs
+
+
+ Event\BatchEventProcessor.cs
+
+
+ Event\EventProcessor.cs
+
+
Event\ForwardingEventProcessor.cs
-
+
OptlyConfig\OptimizelyConfig.cs
-
+
OptlyConfig\OptimizelyAttribute.cs
-
+
OptlyConfig\OptimizelyEvent.cs
-
+
OptlyConfig\OptimizelyExperiment.cs
-
+
OptlyConfig\OptimizelyFeature.cs
-
+
OptlyConfig\OptimizelyVariable.cs
-
+
OptlyConfig\OptimizelyVariation.cs
-
+
OptlyConfig\OptimizelyAudience.cs
-
+
OptlyConfig\OptimizelyConfigService.cs
-
+
OptlyConfig\IOptimizelyConfigManager.cs
-
+
OptimizelyDecisions\DecisionMessage.cs
-
+
OptimizelyDecisions\DecisionReasons.cs
-
+
OptimizelyDecisions\OptimizelyDecideOption.cs
-
+
OptimizelyDecisions\OptimizelyDecision.cs
-
+
OptimizelyUserContext.cs
-
- Entity\Result.cs
-
+
+ OptimizelyDecisionContext.cs
+
+
+ ForcedDecisionsStore.cs
+
+
+ OptimizelyForcedDecision.cs
+
+
+ Entity\Result.cs
+
diff --git a/OptimizelySDK.NetStandard16/OptimizelySDK.NetStandard16.csproj b/OptimizelySDK.NetStandard16/OptimizelySDK.NetStandard16.csproj
index 7d5e7c81..740e5d4d 100644
--- a/OptimizelySDK.NetStandard16/OptimizelySDK.NetStandard16.csproj
+++ b/OptimizelySDK.NetStandard16/OptimizelySDK.NetStandard16.csproj
@@ -1,152 +1,153 @@
-
-
- netstandard1.6
- 1.2.1
- ..\keypair.snk
- false
-
-
-
-
+
+ netstandard1.6
+ 1.2.1
+ ..\keypair.snk
+ false
+
+
+
;$(DefineConstants);NetStandardIdentifier
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- AtomicProjectConfigManager.cs
-
-
- OptimizelyFactory.cs
-
-
- ConversionEvent.cs
-
-
- EventBatch.cs
-
-
- EventContext.cs
-
-
- ImpressionEvent.cs
-
-
- Snapshot.cs
-
-
- SnapshotEvent.cs
-
-
- UserEvent.cs
-
-
- Visitor.cs
-
-
- VisitorAttribute.cs
-
-
- DecisionMetadata.cs
-
-
- DecisionEvent.cs
-
-
- EventFactory.cs
-
-
- UserEventFactory.cs
-
-
- EventProcessor.cs
-
-
- Result.cs
-
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ OptimizelyForcedDecision.cs
+
+
+ OptimizelyFactory.cs
+
+
+ ConversionEvent.cs
+
+
+ EventBatch.cs
+
+
+ EventContext.cs
+
+
+ ImpressionEvent.cs
+
+
+ Snapshot.cs
+
+
+ SnapshotEvent.cs
+
+
+ UserEvent.cs
+
+
+ Visitor.cs
+
+
+ VisitorAttribute.cs
+
+
+ DecisionMetadata.cs
+
+
+ DecisionEvent.cs
+
+
+ EventFactory.cs
+
+
+ UserEventFactory.cs
+
+
+ EventProcessor.cs
+
+
+ Result.cs
+
diff --git a/OptimizelySDK.NetStandard20/OptimizelySDK.NetStandard20.csproj b/OptimizelySDK.NetStandard20/OptimizelySDK.NetStandard20.csproj
index b43a21cb..0202fe84 100644
--- a/OptimizelySDK.NetStandard20/OptimizelySDK.NetStandard20.csproj
+++ b/OptimizelySDK.NetStandard20/OptimizelySDK.NetStandard20.csproj
@@ -304,6 +304,15 @@
OptimizelyUserContext.cs
+
+ OptimizelyDecisionContext.cs
+
+
+ ForcedDecisionsStore.cs
+
+
+ OptimizelyForcedDecision.cs
+
Entity\Result.cs
diff --git a/OptimizelySDK.Tests/Assertions.cs b/OptimizelySDK.Tests/Assertions.cs
new file mode 100644
index 00000000..3f95e42b
--- /dev/null
+++ b/OptimizelySDK.Tests/Assertions.cs
@@ -0,0 +1,728 @@
+/*
+ * Copyright 2017, 2019-2021, Optimizely
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+using NUnit.Framework;
+using OptimizelySDK.Entity;
+using OptimizelySDK.OptimizelyDecisions;
+using OptimizelySDK.OptlyConfig;
+using System;
+using System.Collections.Generic;
+using System.Diagnostics.CodeAnalysis;
+using System.Linq;
+using System.Text;
+using System.Threading.Tasks;
+
+namespace OptimizelySDK.Tests
+{
+ ///
+ /// Simplifies assertions and provides more insight into which particular piece is failing for a value.
+ /// Especially helpful for Test Driven Development
+ ///
+ [ExcludeFromCodeCoverage]
+ public class Assertions
+ {
+ #region Basic asserts
+
+ public static bool HasItems(IEnumerable
+
@@ -92,6 +93,7 @@
+
@@ -134,6 +136,7 @@
OptimizelySDK
+
@@ -143,9 +146,7 @@
-
-
-
+