diff --git a/Gauge.CSharp.Lib.UnitTests/DataStoreFactoryTests.cs b/Gauge.CSharp.Lib.UnitTests/DataStoreFactoryTests.cs deleted file mode 100644 index 63eef78..0000000 --- a/Gauge.CSharp.Lib.UnitTests/DataStoreFactoryTests.cs +++ /dev/null @@ -1,59 +0,0 @@ -/*---------------------------------------------------------------- - * Copyright (c) ThoughtWorks, Inc. - * Licensed under the Apache License, Version 2.0 - * See LICENSE.txt in the project root for license information. - *----------------------------------------------------------------*/ -namespace Gauge.CSharp.Lib.UnitTests; - -[TestFixture] -public class DataStoreFactoryTests -{ - [SetUp] - public void Setup() - { - DataStoreFactory.ClearAllDataStores(); - } - - [Test] - public void AddDataStore_ShouldSetTheSuiteDataStore_WhenCalledForSuiteDataStoreType() - { - DataStoreFactory.AddDataStore(1, DataStoreType.Suite); - Assert.That(DataStoreFactory.SuiteDataStore, Is.Not.Null); - } - - [Test] - public void AddDataStore_ShouldNotOverwriteTheSuiteDataStore_WhenCalledForSuiteDataStoreTypeMoreThanOnce() - { - DataStoreFactory.AddDataStore(1, DataStoreType.Suite); - var dataStore = DataStoreFactory.SuiteDataStore; - DataStoreFactory.AddDataStore(1, DataStoreType.Suite); - Assert.That(dataStore, Is.SameAs(DataStoreFactory.SuiteDataStore)); - } - - [Test] - public void AddDataStore_ShouldSetTheSpecDataStore_WhenCalledForSpecDataStoreType() - { - DataStoreFactory.AddDataStore(1, DataStoreType.Spec); - Assert.That(DataStoreFactory.GetDataStoresByStream(1)[DataStoreType.Spec], Is.Not.Null); - } - - [Test] - public void AddDataStore_ShouldSetTheScenaroDataStore_WhenCalledForScenarioDataStoreType() - { - DataStoreFactory.AddDataStore(1, DataStoreType.Scenario); - Assert.That(DataStoreFactory.GetDataStoresByStream(1)[DataStoreType.Scenario], Is.Not.Null); - } - - [Test] - public void AddDataStore_ShouldKeepSeparateDataStores_WhenCalledForDifferentStreams() - { - DataStoreFactory.AddDataStore(1, DataStoreType.Scenario); - DataStoreFactory.AddDataStore(2, DataStoreType.Scenario); - var dict1 = DataStoreFactory.GetDataStoresByStream(1)[DataStoreType.Scenario]; - var dict2 = DataStoreFactory.GetDataStoresByStream(2)[DataStoreType.Scenario]; - - Assert.That(dict1, Is.Not.SameAs(dict2)); - dict1.Add("mykey", new object()); - Assert.That(dict2.Get("mykey"), Is.Null); - } -} \ No newline at end of file diff --git a/Gauge.CSharp.Lib.UnitTests/DefaultClassInstanceManagerTests.cs b/Gauge.CSharp.Lib.UnitTests/DefaultClassInstanceManagerTests.cs index cbab723..4a7e143 100644 --- a/Gauge.CSharp.Lib.UnitTests/DefaultClassInstanceManagerTests.cs +++ b/Gauge.CSharp.Lib.UnitTests/DefaultClassInstanceManagerTests.cs @@ -9,12 +9,6 @@ namespace Gauge.CSharp.Lib.UnitTests; [TestFixture] public class DefaultClassInstanceManagerTests { - [SetUp] - public void SetUp() - { - DataStoreFactory.ClearAllDataStores(); - } - [Test] public void ShouldGetInstanceForType() { @@ -39,11 +33,12 @@ public void ShouldGetMemoizedInstanceForType() [Test] public async Task InvokeMethod_ShouldCreateInstanceAndInvokeMethod_WhenInstanceIsNotCached() { + var context = new ExecutionContext(); var instanceManager = new DefaultClassInstanceManager(); var methodInfo = typeof(MethodInvokeTests).GetMethod(nameof(MethodInvokeTests.InvokeMethod1)); MethodInvokeTests.InvokeMethod1Called = false; - await instanceManager.InvokeMethod(methodInfo, 1); + await instanceManager.InvokeMethod(methodInfo, context); Assert.That(MethodInvokeTests.InvokeMethod1Called); } @@ -52,13 +47,14 @@ public async Task InvokeMethod_ShouldCreateInstanceAndInvokeMethod_WhenInstanceI public async Task InvokeMethod_ShouldSetDataStores_WhenDataStoresAreInitialized() { var instanceManager = new DefaultClassInstanceManager(); - DataStoreFactory.AddDataStore(1, DataStoreType.Suite); - DataStoreFactory.AddDataStore(1, DataStoreType.Spec); - DataStoreFactory.AddDataStore(1, DataStoreType.Scenario); + var context = new ExecutionContext(); + context.DataStores.SuiteDataStore = new DataStore(); + context.DataStores.SpecDataStore = new DataStore(); + context.DataStores.ScenarioDataStore = new DataStore(); var methodInfo = typeof(MethodInvokeTests).GetMethod(nameof(MethodInvokeTests.InvokeMethod2)); MethodInvokeTests.InvokeMethod2Called = false; - await instanceManager.InvokeMethod(methodInfo, 1); + await instanceManager.InvokeMethod(methodInfo, context); Assert.That(MethodInvokeTests.InvokeMethod2Called); } @@ -67,10 +63,11 @@ public async Task InvokeMethod_ShouldSetDataStores_WhenDataStoresAreInitialized( public async Task InvokeMethod_ShouldNotFail_WhenMethodInvokedIsNotAsync() { var instanceManager = new DefaultClassInstanceManager(); + var context = new ExecutionContext(); var methodInfo = typeof(MethodInvokeTests).GetMethod(nameof(MethodInvokeTests.InvokeMethod3)); MethodInvokeTests.InvokeMethod3Called = false; - await instanceManager.InvokeMethod(methodInfo, 1); + await instanceManager.InvokeMethod(methodInfo, context); Assert.That(MethodInvokeTests.InvokeMethod3Called); } diff --git a/Gauge.CSharp.Lib/DataStoreFactory.cs b/Gauge.CSharp.Lib/DataStoreFactory.cs deleted file mode 100644 index 5293ea0..0000000 --- a/Gauge.CSharp.Lib/DataStoreFactory.cs +++ /dev/null @@ -1,92 +0,0 @@ -/*---------------------------------------------------------------- - * Copyright (c) ThoughtWorks, Inc. - * Licensed under the Apache License, Version 2.0 - * See LICENSE.txt in the project root for license information. - *----------------------------------------------------------------*/ -using System.Collections.Concurrent; - -namespace Gauge.CSharp.Lib; - -/// -/// -/// FOR GAUGE INTERNAL USE ONLY. -/// -/// -public static class DataStoreFactory -{ - private static DataStore _suiteDataStore = null; - private static readonly object _suiteDataStoreLock = new(); - private static readonly ConcurrentDictionary> _dataStores = new(); - - internal static DataStore SuiteDataStore - { - get - { - lock (_suiteDataStoreLock) - { - return _suiteDataStore; - } - } - private set - { - lock (_suiteDataStoreLock) - { - _suiteDataStore ??= value; - } - } - } - - /// - /// - /// FOR GAUGE INTERNAL USE ONLY. - /// - /// Gets a datastore by stream number. - /// - internal static IReadOnlyDictionary GetDataStoresByStream(int streamId) - { - return _dataStores.GetValueOrDefault(streamId, new()); - } - - /// - /// - /// FOR GAUGE INTERNAL USE ONLY. - /// - /// Adds a datastore by stream number. - /// - internal static void AddDataStore(int stream, DataStoreType storeType) - { - var dataStore = new DataStore(); - switch (storeType) - { - case DataStoreType.Suite: SuiteDataStore = dataStore; break; - case DataStoreType.Spec: - case DataStoreType.Scenario: SetStreamDataStore(stream, storeType, dataStore); break; - } - } - - /// - /// - /// FOR GAUGE INTERNAL USE ONLY. - /// - /// Gets a datastore by stream number. - /// - internal static void ClearAllDataStores() - { - lock (_suiteDataStoreLock) - { - _suiteDataStore = null; - } - _dataStores.Clear(); - } - - private static void SetStreamDataStore(int stream, DataStoreType storeType, DataStore dataStore) - { - if (!_dataStores.TryGetValue(stream, out ConcurrentDictionary value)) - { - value = new ConcurrentDictionary(); - _dataStores[stream] = value; - } - - value[storeType] = dataStore; - } -} \ No newline at end of file diff --git a/Gauge.CSharp.Lib/DefaultClassInstanceManager.cs b/Gauge.CSharp.Lib/DefaultClassInstanceManager.cs index 2abe15d..27f40a2 100644 --- a/Gauge.CSharp.Lib/DefaultClassInstanceManager.cs +++ b/Gauge.CSharp.Lib/DefaultClassInstanceManager.cs @@ -27,9 +27,9 @@ public object Get(Type declaringType) return instance; } - public async Task InvokeMethod(MethodInfo method, int stream, params object[] parameters) + public async Task InvokeMethod(MethodInfo method, ExecutionContext context, params object[] parameters) { - SetDataStores(stream); + SetDataStores(context.DataStores); var instance = Get(method.DeclaringType); var response = method.Invoke(instance, parameters); if (response is Task task) @@ -38,20 +38,19 @@ public async Task InvokeMethod(MethodInfo method, int stream, params object[] pa } } - private static void SetDataStores(int stream) + private static void SetDataStores(ExecutionContext.CurrentDataStores dataStores) { - var dataStore = DataStoreFactory.GetDataStoresByStream(stream); lock (SuiteDataStore.Store) { - SuiteDataStore.Store.Value = DataStoreFactory.SuiteDataStore; + SuiteDataStore.Store.Value = dataStores.SuiteDataStore; } lock (SpecDataStore.Store) { - SpecDataStore.Store.Value = dataStore.GetValueOrDefault(DataStoreType.Spec, null); + SpecDataStore.Store.Value = dataStores.SpecDataStore; } lock (ScenarioDataStore.Store) { - ScenarioDataStore.Store.Value = dataStore.GetValueOrDefault(DataStoreType.Scenario, null); + ScenarioDataStore.Store.Value = dataStores.ScenarioDataStore; } } diff --git a/Gauge.CSharp.Lib/ExecutionContext.cs b/Gauge.CSharp.Lib/ExecutionContext.cs index d4c12f9..7b1847a 100644 --- a/Gauge.CSharp.Lib/ExecutionContext.cs +++ b/Gauge.CSharp.Lib/ExecutionContext.cs @@ -5,27 +5,30 @@ *----------------------------------------------------------------*/ -using System; -using System.Collections.Generic; - /** * Gives the information about the current execution at runtime - spec, scenario, step that is running. */ -namespace Gauge.CSharp.Lib { +namespace Gauge.CSharp.Lib +{ [Serializable()] - public class ExecutionContext { - public ExecutionContext(Specification specification, Scenario scenario, StepDetails stepDetails) { + public class ExecutionContext + { + public ExecutionContext(Specification specification, Scenario scenario, StepDetails stepDetails, CurrentDataStores dataStores) + { this.CurrentSpecification = specification; this.CurrentScenario = scenario; this.CurrentStep = stepDetails; + this.DataStores = dataStores; } - public ExecutionContext() { + public ExecutionContext() + { this.CurrentSpecification = new Specification(); this.CurrentScenario = new Scenario(); this.CurrentStep = new StepDetails(); + DataStores = new CurrentDataStores(); } /** @@ -46,27 +49,35 @@ public ExecutionContext() { */ public StepDetails CurrentStep { get; } + /// Gets the DataStores for the current context + internal CurrentDataStores DataStores { get; private init; } + /** * @return - All the valid tags (including scenario and spec tags) at the execution level. */ - public List GetAllTags() { + public List GetAllTags() + { HashSet specTags = new HashSet(CurrentSpecification.Tags); - foreach (var tag in CurrentScenario.Tags){ - specTags.Add(tag); + foreach (var tag in CurrentScenario.Tags) + { + specTags.Add(tag); } return new List(specTags); } [Serializable()] - public class Specification { - public Specification(String name, String fileName, bool isFailing, IEnumerable tags) { + public class Specification + { + public Specification(String name, String fileName, bool isFailing, IEnumerable tags) + { this.Name = name; this.FileName = fileName; this.IsFailing = isFailing; this.Tags = tags; } - public Specification() { + public Specification() + { Tags = new List(); } @@ -90,11 +101,13 @@ public Specification() { */ public String Name { get; } = ""; } - + [Serializable()] - public class StepDetails { - public StepDetails(String text, bool isFailing, string stackTrace, string errorMessage, - List> parameters) { + public class StepDetails + { + public StepDetails(String text, bool isFailing, string stackTrace, string errorMessage, + List> parameters) + { this.Text = text; this.StackTrace = stackTrace; this.ErrorMessage = errorMessage; @@ -102,7 +115,8 @@ public StepDetails(String text, bool isFailing, string stackTrace, string errorM this.Parameters = parameters; } - public StepDetails(String text, bool isFailing, string stackTrace, string errorMessage) { + public StepDetails(String text, bool isFailing, string stackTrace, string errorMessage) + { this.Text = text; this.StackTrace = stackTrace; this.ErrorMessage = errorMessage; @@ -110,7 +124,7 @@ public StepDetails(String text, bool isFailing, string stackTrace, string errorM this.Parameters = null; } - public StepDetails() {} + public StepDetails() { } /** * @return True if the current spec or scenario or step is failing due to error. @@ -139,15 +153,18 @@ public StepDetails() {} } [Serializable] - public class Scenario { - public Scenario(String name, bool isFailing, IEnumerable tags, int maxRetries, int currentRetry) { + public class Scenario + { + public Scenario(String name, bool isFailing, IEnumerable tags, int maxRetries, int currentRetry) + { this.Name = name; this.IsFailing = isFailing; this.Tags = tags; this.Retries = new RetriesInfo(maxRetries: maxRetries, curruntRetry: currentRetry); } - public Scenario() { + public Scenario() + { Tags = new List(); Retries = new RetriesInfo(); } @@ -174,13 +191,15 @@ public Scenario() { } [Serializable] - public class RetriesInfo { - public RetriesInfo(int maxRetries, int curruntRetry) { + public class RetriesInfo + { + public RetriesInfo(int maxRetries, int curruntRetry) + { this.MaxRetries = maxRetries; this.CurrentRetry = curruntRetry; } - public RetriesInfo() {} + public RetriesInfo() { } /** * @return the count of maximum execution retries @@ -190,7 +209,18 @@ public RetriesInfo() {} /** * @return the count of the current execution retry */ - public int CurrentRetry{ get; } = 0; + public int CurrentRetry { get; } = 0; + } + + [Serializable] + public class CurrentDataStores() + { + /// Gets the Suite DataStore for this context + public DataStore SuiteDataStore { get; set; } + /// Gets the Spec DataStore for this context + public DataStore SpecDataStore { get; set; } + /// Gets the Scenario DataStore for this context + public DataStore ScenarioDataStore { get; set; } } } } \ No newline at end of file diff --git a/Gauge.CSharp.Lib/GaugeScreenshots.cs b/Gauge.CSharp.Lib/GaugeScreenshots.cs index 0e87a82..e058ea7 100644 --- a/Gauge.CSharp.Lib/GaugeScreenshots.cs +++ b/Gauge.CSharp.Lib/GaugeScreenshots.cs @@ -21,26 +21,25 @@ public static void Capture() ScreenshotFiles.Add(screenshotWriter.TakeScreenShot()); } - public static void CaptureByStream(int streamId) + public static void CaptureWithDataStores(DataStore suiteDataStore, DataStore specDataStore, DataStore scenarioDataStore) { - SetDataStores(streamId); - ScreenshotFiles.Add(screenshotWriter.TakeScreenShot()); + SetDataStores(suiteDataStore, specDataStore, scenarioDataStore); + Capture(); } - private static void SetDataStores(int streamId) + private static void SetDataStores(DataStore suiteDataStore, DataStore specDataStore, DataStore scenarioDataStore) { - var dataStore = DataStoreFactory.GetDataStoresByStream(streamId); lock (SuiteDataStore.Store) { - SuiteDataStore.Store.Value = DataStoreFactory.SuiteDataStore; + SuiteDataStore.Store.Value = suiteDataStore; } lock (SpecDataStore.Store) { - SpecDataStore.Store.Value = dataStore.GetValueOrDefault(DataStoreType.Spec, null); + SpecDataStore.Store.Value = specDataStore; } lock (ScenarioDataStore.Store) { - ScenarioDataStore.Store.Value = dataStore.GetValueOrDefault(DataStoreType.Scenario, null); + ScenarioDataStore.Store.Value = scenarioDataStore; } } } \ No newline at end of file diff --git a/Gauge.CSharp.Lib/IClassInstanceManager.cs b/Gauge.CSharp.Lib/IClassInstanceManager.cs index 39b38b9..11384b2 100644 --- a/Gauge.CSharp.Lib/IClassInstanceManager.cs +++ b/Gauge.CSharp.Lib/IClassInstanceManager.cs @@ -14,7 +14,7 @@ public interface IClassInstanceManager object Get(Type declaringType); - Task InvokeMethod(MethodInfo method, int stream, params object[] parameters); + Task InvokeMethod(MethodInfo method, ExecutionContext context, params object[] parameters); void StartScope(string tag);