From 1895ebea718284adad099bbe759ad2960ea512d8 Mon Sep 17 00:00:00 2001 From: Craig Fowler Date: Sat, 14 Sep 2024 20:33:51 +0100 Subject: [PATCH] Further work on SpecFlow plugin --- .../ScenarioAndFeatureContextKey.cs | 50 +++++++ CSF.Screenplay.SpecFlow/ScreenplayBinding.cs | 59 ++++++++ CSF.Screenplay.SpecFlow/ScreenplayPlugin.cs | 88 +++++++++++- CSF.Screenplay.SpecFlow/ScreenplaySteps.cs | 32 +++++ .../BoDiContainerProxy.cs | 95 ------------ .../CSF.Screenplay.SpecFlow.csproj_old | 88 ------------ .../CSF.Screenplay.SpecFlow.nuspec | 26 ---- .../FlexDiTestObjectResolver.cs | 25 ---- .../IntegrationProvider.cs | 49 ------- .../Properties/AssemblyInfo.cs | 26 ---- .../Resources/ExceptionFormats.Designer.cs | 56 -------- .../Resources/ExceptionFormats.resx | 18 --- .../ScenarioAdapter.cs | 95 ------------ .../ScenarioAndFeatureKey.cs | 83 ----------- .../ScreenplayAssemblyAttribute.cs | 47 ------ .../ScreenplayBinding.cs | 82 ----------- .../ScreenplayDependencyInjectionBuilder.cs | 135 ------------------ .../ScreenplayPlugin.cs | 77 ---------- .../ScreenplaySteps.cs | 58 -------- CSF.Screenplay.SpecFlow_old/packages.config | 7 - CSF.Screenplay.SpecFlow_old/readme.txt | 37 ----- 21 files changed, 225 insertions(+), 1008 deletions(-) create mode 100644 CSF.Screenplay.SpecFlow/ScenarioAndFeatureContextKey.cs create mode 100644 CSF.Screenplay.SpecFlow/ScreenplayBinding.cs create mode 100644 CSF.Screenplay.SpecFlow/ScreenplaySteps.cs delete mode 100644 CSF.Screenplay.SpecFlow_old/BoDiContainerProxy.cs delete mode 100644 CSF.Screenplay.SpecFlow_old/CSF.Screenplay.SpecFlow.csproj_old delete mode 100644 CSF.Screenplay.SpecFlow_old/CSF.Screenplay.SpecFlow.nuspec delete mode 100644 CSF.Screenplay.SpecFlow_old/FlexDiTestObjectResolver.cs delete mode 100644 CSF.Screenplay.SpecFlow_old/IntegrationProvider.cs delete mode 100644 CSF.Screenplay.SpecFlow_old/Properties/AssemblyInfo.cs delete mode 100644 CSF.Screenplay.SpecFlow_old/Resources/ExceptionFormats.Designer.cs delete mode 100644 CSF.Screenplay.SpecFlow_old/Resources/ExceptionFormats.resx delete mode 100644 CSF.Screenplay.SpecFlow_old/ScenarioAdapter.cs delete mode 100644 CSF.Screenplay.SpecFlow_old/ScenarioAndFeatureKey.cs delete mode 100644 CSF.Screenplay.SpecFlow_old/ScreenplayAssemblyAttribute.cs delete mode 100644 CSF.Screenplay.SpecFlow_old/ScreenplayBinding.cs delete mode 100644 CSF.Screenplay.SpecFlow_old/ScreenplayDependencyInjectionBuilder.cs delete mode 100644 CSF.Screenplay.SpecFlow_old/ScreenplayPlugin.cs delete mode 100644 CSF.Screenplay.SpecFlow_old/ScreenplaySteps.cs delete mode 100644 CSF.Screenplay.SpecFlow_old/packages.config delete mode 100644 CSF.Screenplay.SpecFlow_old/readme.txt diff --git a/CSF.Screenplay.SpecFlow/ScenarioAndFeatureContextKey.cs b/CSF.Screenplay.SpecFlow/ScenarioAndFeatureContextKey.cs new file mode 100644 index 00000000..0f580858 --- /dev/null +++ b/CSF.Screenplay.SpecFlow/ScenarioAndFeatureContextKey.cs @@ -0,0 +1,50 @@ +using System; +using TechTalk.SpecFlow; + +namespace CSF.Screenplay +{ + /// + /// Simple key class for a combination of Scenario & Feature contexts. + /// + internal sealed class ScenarioAndFeatureContextKey : IEquatable + { + readonly int cachedHashCode; + + /// Gets the scenario + public ScenarioContext Scenario { get; } + + /// Gets the feature + public FeatureContext Feature { get; } + + /// + public override bool Equals(object obj) => Equals(obj as ScenarioAndFeatureContextKey); + + /// + public bool Equals(ScenarioAndFeatureContextKey other) + { + if(ReferenceEquals(this, other)) return true; + if(ReferenceEquals(null, other)) return false; + + return ReferenceEquals(Scenario, other.Scenario) && ReferenceEquals(Feature, other.Feature); + } + + /// + public override int GetHashCode() => cachedHashCode; + + /// + /// Initializes a new instance of . + /// + /// The scenario + /// The feature + /// If either parameter is . + public ScenarioAndFeatureContextKey(ScenarioContext scenario, FeatureContext feature) + { + if(scenario is null) throw new ArgumentNullException(nameof(scenario)); + if(feature is null) throw new ArgumentNullException(nameof(feature)); + + Scenario = scenario; + Feature = feature; + cachedHashCode = scenario.GetHashCode() ^ feature.GetHashCode(); + } + } +} diff --git a/CSF.Screenplay.SpecFlow/ScreenplayBinding.cs b/CSF.Screenplay.SpecFlow/ScreenplayBinding.cs new file mode 100644 index 00000000..77caaa50 --- /dev/null +++ b/CSF.Screenplay.SpecFlow/ScreenplayBinding.cs @@ -0,0 +1,59 @@ +using System; +using Microsoft.Extensions.DependencyInjection; +using TechTalk.SpecFlow; + +namespace CSF.Screenplay +{ + /// + /// SpecFlow binding which uses hooks to coordinate the relevant & event invokers. + /// + [Binding] + public class ScreenplayBinding + { + readonly IServiceProvider serviceProvider; + + /// + /// Executed before each scenario. + /// + [BeforeScenario] + public void BeforeScenario() + { + var performance = serviceProvider.GetRequiredService(); + performance.BeginPerformance(); + } + + /// + /// Executed after each scenario. + /// + [AfterScenario] + public void AfterScenario() + { + var performance = serviceProvider.GetRequiredService(); + var scenarioContext = serviceProvider.GetRequiredService(); + var success = scenarioContext.TestError is null; + performance.FinishPerformance(success); + } + + /// + /// Executed before a test run. + /// + [BeforeTestRun] + public static void BeforeTestRun() => ScreenplayPlugin.Screenplay.BeginScreenplay(); + + /// + /// Executed after a test run. + /// + [AfterTestRun] + public static void AfterTestRun() => ScreenplayPlugin.Screenplay.CompleteScreenplay(); + + /// + /// Initialises a new instance of . + /// + /// The service provider + /// If the is . + public ScreenplayBinding(IServiceProvider serviceProvider) + { + this.serviceProvider = serviceProvider ?? throw new ArgumentNullException(nameof(serviceProvider)); + } + } +} \ No newline at end of file diff --git a/CSF.Screenplay.SpecFlow/ScreenplayPlugin.cs b/CSF.Screenplay.SpecFlow/ScreenplayPlugin.cs index 099d236b..2400aada 100644 --- a/CSF.Screenplay.SpecFlow/ScreenplayPlugin.cs +++ b/CSF.Screenplay.SpecFlow/ScreenplayPlugin.cs @@ -1,5 +1,11 @@ using System; +using System.Collections.Concurrent; +using System.Reflection; using System.Threading; +using BoDi; +using CSF.Screenplay.Actors; +using CSF.Screenplay.Performances; +using TechTalk.SpecFlow; using TechTalk.SpecFlow.Plugins; using TechTalk.SpecFlow.UnitTestProvider; @@ -34,28 +40,64 @@ namespace CSF.Screenplay public class ScreenplayPlugin : IRuntimePlugin { readonly ReaderWriterLockSlim syncRoot = new ReaderWriterLockSlim(); + readonly ConcurrentDictionary featureContextIds = new ConcurrentDictionary(); + readonly ConcurrentDictionary scenarioContextIds = new ConcurrentDictionary(); + bool initialised; + /// + /// Provides static access to the Screenplay instance. + /// + /// + /// + /// This is required because the bindings for beginning/ending the Screenplay in must be static: + /// . + /// + /// + static internal Screenplay Screenplay { get; private set; } + /// public void Initialize(RuntimePluginEvents runtimePluginEvents, RuntimePluginParameters runtimePluginParameters, UnitTestProviderConfiguration unitTestProviderConfiguration) { runtimePluginEvents.CustomizeGlobalDependencies += OnCustomizeGlobalDependencies; - throw new NotImplementedException(); + runtimePluginEvents.CustomizeScenarioDependencies += OnCustomizeScenarioDependencies; + runtimePluginEvents.ConfigurationDefaults += OnConfigurationDefaults; + } + + private void OnConfigurationDefaults(object sender, ConfigurationDefaultsEventArgs e) + { + e.SpecFlowConfiguration.AdditionalStepAssemblies.Add(Assembly.GetExecutingAssembly().FullName); } + /// + /// Event handler for the CustomizeGlobalDependencies runtime plugin event. + /// + /// + /// + /// It is a known/documented issue that this event may be triggered more than once in a single run of SpecFlow: + /// . + /// Thus, to prevent double-initialisation, this method occurs in a thread-safe manner which ensures that even if it + /// is executed more than once, there is no adverse consequence. + /// + /// + /// The event sender + /// Event args to customize the global dependencies void OnCustomizeGlobalDependencies(object sender, CustomizeGlobalDependenciesEventArgs args) { try { syncRoot.EnterUpgradeableReadLock(); if (initialised) return; - syncRoot.EnterWriteLock(); - var serviceCollection = new ServiceCollectionAdapter(args.ObjectContainer); + if (initialised) return; + + var container = args.ObjectContainer; + var serviceCollection = new ServiceCollectionAdapter(container); serviceCollection.AddScreenplay(); - args.ObjectContainer.RegisterFactoryAs(container => new ServiceProviderAdapter(container)); + container.RegisterFactoryAs(c => new ServiceProviderAdapter(c)); + Screenplay = container.Resolve(); initialised = true; } finally @@ -66,5 +108,43 @@ void OnCustomizeGlobalDependencies(object sender, CustomizeGlobalDependenciesEve syncRoot.ExitUpgradeableReadLock(); } } + + void OnCustomizeScenarioDependencies(object sender, CustomizeScenarioDependenciesEventArgs args) + { + var container = args.ObjectContainer; + var services = new ServiceProviderAdapter(container); + container.RegisterInstanceAs(services); + + var performanceFactory = container.Resolve(); + var performance = performanceFactory.CreatePerformance(); + performance.NamingHierarchy.Add(GetFeatureIdAndName(container)); + performance.NamingHierarchy.Add(GetScenarioIdAndName(container)); + + container.RegisterInstanceAs(performance); + container.RegisterFactoryAs(c => new Cast(c.Resolve(), c.Resolve().PerformanceIdentity)); + container.RegisterTypeAs(); + } + + IdentifierAndName GetFeatureIdAndName(IObjectContainer container) + { + var featureContext = container.Resolve(); + return new IdentifierAndName(GetFeatureId(featureContext).ToString(), + featureContext.FeatureInfo.Title, + true); + } + + Guid GetFeatureId(FeatureContext featureContext) => featureContextIds.GetOrAdd(featureContext, _ => Guid.NewGuid()); + + IdentifierAndName GetScenarioIdAndName(IObjectContainer container) + { + var featureContext = container.Resolve(); + var scenarioContext = container.Resolve(); + return new IdentifierAndName(GetScenarioId(featureContext, scenarioContext).ToString(), + scenarioContext.ScenarioInfo.Title, + true); + } + + Guid GetScenarioId(FeatureContext featureContext, ScenarioContext scenarioContext) + => scenarioContextIds.GetOrAdd(new ScenarioAndFeatureContextKey(scenarioContext, featureContext), _ => Guid.NewGuid()); } } \ No newline at end of file diff --git a/CSF.Screenplay.SpecFlow/ScreenplaySteps.cs b/CSF.Screenplay.SpecFlow/ScreenplaySteps.cs new file mode 100644 index 00000000..cc622487 --- /dev/null +++ b/CSF.Screenplay.SpecFlow/ScreenplaySteps.cs @@ -0,0 +1,32 @@ +using CSF.Screenplay.Actors; +using TechTalk.SpecFlow; + +namespace CSF.Screenplay +{ + /// + /// Convenience subclass of TechTalk.SpecFlow.Steps making it possible to call Given, When & Then + /// methods without conflicting with the built-in methods of the same names. + /// + public class ScreenplaySteps : Steps + { + /// + /// Returns the actor instance, as an , in order to perform precondition actions. + /// + /// The actor. + public ICanPerformGiven Given(Actor actor) => PerformanceStarter.Given(actor); + + /// + /// Returns the actor instance, as an , in order to perform actions which exercise the + /// system under test. + /// + /// The actor. + public ICanPerformWhen When(Actor actor) => PerformanceStarter.When(actor); + + /// + /// Returns the actor instance, as an , in order to get information which are required to + /// make assertions that the scenario has completed successfully. + /// + /// The actor. + public ICanPerformThen Then(Actor actor) => PerformanceStarter.Then(actor); + } +} diff --git a/CSF.Screenplay.SpecFlow_old/BoDiContainerProxy.cs b/CSF.Screenplay.SpecFlow_old/BoDiContainerProxy.cs deleted file mode 100644 index 6140f79e..00000000 --- a/CSF.Screenplay.SpecFlow_old/BoDiContainerProxy.cs +++ /dev/null @@ -1,95 +0,0 @@ -// -// BoDiContainerProxy.cs -// -// Author: -// Craig Fowler -// -// Copyright (c) 2018 Craig Fowler -// -// Permission is hereby granted, free of charge, to any person obtaining a copy -// of this software and associated documentation files (the "Software"), to deal -// in the Software without restriction, including without limitation the rights -// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -// copies of the Software, and to permit persons to whom the Software is -// furnished to do so, subject to the following conditions: -// -// The above copyright notice and this permission notice shall be included in -// all copies or substantial portions of the Software. -// -// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN -// THE SOFTWARE. -using System; -using System.Collections.Generic; -using BoDi; -using CSF.FlexDi.Registration; - -namespace CSF.Screenplay.SpecFlow -{ - class BoDiContainerProxy : IObjectContainer - { - readonly FlexDi.IContainer proxiedContainer; - - public event Action ObjectCreated; - - public void Dispose() - { - proxiedContainer.Dispose(); - } - - public bool IsRegistered() => proxiedContainer.HasRegistration(); - - public bool IsRegistered(string name) => proxiedContainer.HasRegistration(name); - - public void RegisterFactoryAs(Func factoryDelegate, string name = null) - { - proxiedContainer.AddRegistrations(r => r.RegisterFactory(factoryDelegate, typeof(TInterface)).WithName(name)); - } - - public void RegisterInstanceAs(object instance, Type interfaceType, string name = null, bool dispose = false) - { - proxiedContainer.AddRegistrations(r => r.RegisterInstance(instance).As(interfaceType).WithName(name).DisposeWithContainer(dispose)); - } - - public void RegisterInstanceAs(TInterface instance, string name = null, bool dispose = false) where TInterface : class - { - proxiedContainer.AddRegistrations(r => r.RegisterInstance(instance).As().WithName(name).DisposeWithContainer(dispose)); - } - - public void RegisterTypeAs(string name = null) where TType : class, TInterface - { - proxiedContainer.AddRegistrations(r => r.RegisterType(typeof(TType)).As(typeof(TInterface)).WithName(name)); - } - - public object Resolve(Type typeToResolve, string name = null) => proxiedContainer.Resolve(typeToResolve, name); - - public T Resolve() => proxiedContainer.Resolve(); - - public T Resolve(string name) => proxiedContainer.Resolve(name); - - public IEnumerable ResolveAll() where T : class => proxiedContainer.ResolveAll(); - - void InvokeObjectCreated(object created) - { - ObjectCreated?.Invoke(created); - } - - public BoDiContainerProxy(FlexDi.IContainer proxiedContainer) - { - if(proxiedContainer == null) - throw new ArgumentNullException(nameof(proxiedContainer)); - this.proxiedContainer = proxiedContainer; - - proxiedContainer.AddRegistrations(r => r.RegisterInstance(this).As()); - - proxiedContainer.ServiceResolved += (sender, e) => { - if(e.Registration is TypeRegistration) - InvokeObjectCreated(e.Instance); - }; - } - } -} diff --git a/CSF.Screenplay.SpecFlow_old/CSF.Screenplay.SpecFlow.csproj_old b/CSF.Screenplay.SpecFlow_old/CSF.Screenplay.SpecFlow.csproj_old deleted file mode 100644 index 1df48c91..00000000 --- a/CSF.Screenplay.SpecFlow_old/CSF.Screenplay.SpecFlow.csproj_old +++ /dev/null @@ -1,88 +0,0 @@ - - - - Debug - AnyCPU - {5FC41182-AE52-4324-BA3B-456DA91FE30C} - Library - CSF.Screenplay.SpecFlow - CSF.Screenplay.SpecFlowPlugin - v4.5 - 1.0.0 - true - ..\CSF-Software-OSS.snk - - - true - full - false - bin\Debug - DEBUG; - prompt - 4 - bin\Debug\CSF.Screenplay.SpecFlowPlugin.xml - false - - - true - bin\Release - prompt - 4 - bin\Release\CSF.Screenplay.SpecFlowPlugin.xml - false - - - - - ..\packages\SpecFlow.2.2.0\lib\net45\TechTalk.SpecFlow.dll - - - - ..\packages\CSF.Configuration.1.1.2\lib\net45\CSF.Configuration.dll - - - ..\packages\CSF.FlexDi.1.0.2\lib\net45\CSF.FlexDi.dll - - - ..\packages\Newtonsoft.Json.12.0.1\lib\net45\Newtonsoft.Json.dll - - - - - - - - - - - - - ExceptionFormats.resx - - - - - - - - - - - - - {46E6DEAA-E6D5-4EE6-A552-17376BEA80DC} - CSF.Screenplay - - - - - - - - ResXFileCodeGenerator - ExceptionFormats.resources - ExceptionFormats.Designer.cs - - - - \ No newline at end of file diff --git a/CSF.Screenplay.SpecFlow_old/CSF.Screenplay.SpecFlow.nuspec b/CSF.Screenplay.SpecFlow_old/CSF.Screenplay.SpecFlow.nuspec deleted file mode 100644 index 0a784c76..00000000 --- a/CSF.Screenplay.SpecFlow_old/CSF.Screenplay.SpecFlow.nuspec +++ /dev/null @@ -1,26 +0,0 @@ - - - - CSF.Screenplay.SpecFlow - 1.0.0 - CSF.Screenplay.SpecFlow - CSF Software Ltd - MIT - https://github.com/csf-dev/CSF.Screenplay - false - Bindings and types for making use of CSF.Screenplay with the SpecFlow BDD framework - Copyright 2017 - - - - - - - - - - - - - - \ No newline at end of file diff --git a/CSF.Screenplay.SpecFlow_old/FlexDiTestObjectResolver.cs b/CSF.Screenplay.SpecFlow_old/FlexDiTestObjectResolver.cs deleted file mode 100644 index cdf7a0ba..00000000 --- a/CSF.Screenplay.SpecFlow_old/FlexDiTestObjectResolver.cs +++ /dev/null @@ -1,25 +0,0 @@ -using System; -using BoDi; -using TechTalk.SpecFlow.Infrastructure; - -namespace CSF.Screenplay.SpecFlow -{ - /// - /// An implementation of TechTalk.SpecFlow.Infrastructure.ITestObjectResolver which makes use of a - /// FlexDi container. - /// - public class FlexDiTestObjectResolver : ITestObjectResolver - { - /// - /// Resolves (instantiates) an instance of a type which is decorated with the TechTalk.SpecFlow.BindingAttribute. - /// - /// The binding instance. - /// The type of the binding instance to resolve. - /// The BoDi container for the current SpecFlow scenario. - public object ResolveBindingInstance(Type bindingType, IObjectContainer scenarioContainer) - { - var flexDiContainer = scenarioContainer.Resolve(); - return flexDiContainer.Resolve(bindingType); - } - } -} diff --git a/CSF.Screenplay.SpecFlow_old/IntegrationProvider.cs b/CSF.Screenplay.SpecFlow_old/IntegrationProvider.cs deleted file mode 100644 index 241fd286..00000000 --- a/CSF.Screenplay.SpecFlow_old/IntegrationProvider.cs +++ /dev/null @@ -1,49 +0,0 @@ -using System; -using System.Linq; -using System.Reflection; -using CSF.Screenplay.Integration; - -namespace CSF.Screenplay.SpecFlow -{ - /// - /// Helper which encapsulates the logic required to create a new . - /// - public class IntegrationProvider - { - /// - /// Gets the integration (via lazy-initialisation). - /// - /// The integration. - public Lazy GetIntegration() - { - return new Lazy(CreateIntegration); - } - - IScreenplayIntegration CreateIntegration() - { - var integration = GetScreenplayAssemblyAttribute()?.Integration; - - if(integration == null) - { - var message = String.Format(Resources.ExceptionFormats.ScreenplayAssemblyAttributeRequired, - nameof(ScreenplayAssemblyAttribute)); - throw new InvalidOperationException(message); - } - - return integration; - } - - ScreenplayAssemblyAttribute GetScreenplayAssemblyAttribute() - { - var appDomain = AppDomain.CurrentDomain; - var assemblies = appDomain.GetAssemblies(); - - return (from assembly in assemblies - where !assembly.IsDynamic - let attrib = assembly.GetCustomAttribute() - where attrib != null - select attrib) - .FirstOrDefault(); - } - } -} diff --git a/CSF.Screenplay.SpecFlow_old/Properties/AssemblyInfo.cs b/CSF.Screenplay.SpecFlow_old/Properties/AssemblyInfo.cs deleted file mode 100644 index bd3a6de4..00000000 --- a/CSF.Screenplay.SpecFlow_old/Properties/AssemblyInfo.cs +++ /dev/null @@ -1,26 +0,0 @@ -using System.Reflection; -using System.Runtime.CompilerServices; - -// Information about this assembly is defined by the following attributes. -// Change them to the values specific to your project. - -[assembly: AssemblyTitle("CSF.Screenplay.SpecFlow")] -[assembly: AssemblyDescription("")] -[assembly: AssemblyConfiguration("")] -[assembly: AssemblyCompany("CSF Software Limited")] -[assembly: AssemblyProduct("")] -[assembly: AssemblyCopyright("Craig Fowler")] -[assembly: AssemblyTrademark("")] -[assembly: AssemblyCulture("")] - -// The assembly version has the format "{Major}.{Minor}.{Build}.{Revision}". -// The form "{Major}.{Minor}.*" will automatically update the build and revision, -// and "{Major}.{Minor}.{Build}.*" will update just the revision. - -[assembly: AssemblyVersion("1.0.*")] - -// The following attributes are used to specify the signing key for the assembly, -// if desired. See the Mono documentation for more information about signing. - -//[assembly: AssemblyDelaySign(false)] -//[assembly: AssemblyKeyFile("")] diff --git a/CSF.Screenplay.SpecFlow_old/Resources/ExceptionFormats.Designer.cs b/CSF.Screenplay.SpecFlow_old/Resources/ExceptionFormats.Designer.cs deleted file mode 100644 index b0846596..00000000 --- a/CSF.Screenplay.SpecFlow_old/Resources/ExceptionFormats.Designer.cs +++ /dev/null @@ -1,56 +0,0 @@ -// ------------------------------------------------------------------------------ -// -// This code was generated by a tool. -// Mono Runtime Version: 4.0.30319.42000 -// -// Changes to this file may cause incorrect behavior and will be lost if -// the code is regenerated. -// -// ------------------------------------------------------------------------------ - -namespace CSF.Screenplay.SpecFlow.Resources { - using System; - using System.Reflection; - - - [System.CodeDom.Compiler.GeneratedCodeAttribute("System.Resources.Tools.StronglyTypedResourceBuilder", "4.0.0.0")] - [System.Diagnostics.DebuggerNonUserCodeAttribute()] - [System.Runtime.CompilerServices.CompilerGeneratedAttribute()] - internal class ExceptionFormats { - - private static System.Resources.ResourceManager resourceMan; - - private static System.Globalization.CultureInfo resourceCulture; - - [System.Diagnostics.CodeAnalysis.SuppressMessageAttribute("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")] - internal ExceptionFormats() { - } - - [System.ComponentModel.EditorBrowsableAttribute(System.ComponentModel.EditorBrowsableState.Advanced)] - internal static System.Resources.ResourceManager ResourceManager { - get { - if (object.Equals(null, resourceMan)) { - System.Resources.ResourceManager temp = new System.Resources.ResourceManager("ExceptionFormats", typeof(ExceptionFormats).Assembly); - resourceMan = temp; - } - return resourceMan; - } - } - - [System.ComponentModel.EditorBrowsableAttribute(System.ComponentModel.EditorBrowsableState.Advanced)] - internal static System.Globalization.CultureInfo Culture { - get { - return resourceCulture; - } - set { - resourceCulture = value; - } - } - - internal static string ScreenplayAssemblyAttributeRequired { - get { - return ResourceManager.GetString("ScreenplayAssemblyAttributeRequired", resourceCulture); - } - } - } -} diff --git a/CSF.Screenplay.SpecFlow_old/Resources/ExceptionFormats.resx b/CSF.Screenplay.SpecFlow_old/Resources/ExceptionFormats.resx deleted file mode 100644 index 81dce710..00000000 --- a/CSF.Screenplay.SpecFlow_old/Resources/ExceptionFormats.resx +++ /dev/null @@ -1,18 +0,0 @@ - - - - text/microsoft-resx - - - 2.0 - - - System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 - - - System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 - - - An assembly is required, decorated with `{0}', stating the location to the Screenplay integration configuration class. - - diff --git a/CSF.Screenplay.SpecFlow_old/ScenarioAdapter.cs b/CSF.Screenplay.SpecFlow_old/ScenarioAdapter.cs deleted file mode 100644 index 195d749c..00000000 --- a/CSF.Screenplay.SpecFlow_old/ScenarioAdapter.cs +++ /dev/null @@ -1,95 +0,0 @@ -using System; -using System.Collections.Concurrent; -using System.Collections.Generic; -using CSF.Screenplay.Integration; -using CSF.Screenplay.Scenarios; -using TechTalk.SpecFlow; - -namespace CSF.Screenplay.SpecFlow -{ - /// - /// Helper type which encapsulates the mappings/relationships between a Screenplay scenario and SpecFlow - /// contexts. - /// - public class ScenarioAdapter - { - static IDictionary scenarioIds; - static IDictionary featureIds; - - readonly ScenarioContext scenarioContext; - readonly FeatureContext featureContext; - readonly IScreenplayIntegration integration; - - /// - /// Creates a Screenplay scenario. - /// - /// The scenario. - public IScenario CreateScenario() - { - var factory = integration.GetScenarioFactory(); - return factory.GetScenario(FeatureIdAndName, ScenarioIdAndName); - } - - IdAndName FeatureIdAndName - => new IdAndName(GetFeatureId(featureContext).ToString(), featureContext.FeatureInfo.Title, true); - - IdAndName ScenarioIdAndName - => new IdAndName(GetScenarioId(scenarioContext, featureContext).ToString(), scenarioContext.ScenarioInfo.Title, true); - - Guid GetFeatureId(FeatureContext feature) - { - if(!featureIds.ContainsKey(feature)) - featureIds.Add(feature, Guid.NewGuid()); - - return featureIds[feature]; - } - - Guid GetScenarioId(ScenarioContext scenario, FeatureContext feature) - { - var key = new ScenarioAndFeatureKey(scenario, feature); - - if(!scenarioIds.ContainsKey(key)) - scenarioIds.Add(key, Guid.NewGuid()); - - return scenarioIds[key]; - } - - /// - /// Initializes a new instance of the class. - /// - /// Scenario context. - /// Feature context. - /// Integration. - public ScenarioAdapter(ScenarioContext scenarioContext, - FeatureContext featureContext, - IScreenplayIntegration integration) - { - if(integration == null) - throw new ArgumentNullException(nameof(integration)); - if(featureContext == null) - throw new ArgumentNullException(nameof(featureContext)); - if(scenarioContext == null) - throw new ArgumentNullException(nameof(scenarioContext)); - - this.integration = integration; - this.featureContext = featureContext; - this.scenarioContext = scenarioContext; - } - - /// - /// Initializes the class. - /// - static ScenarioAdapter() - { - scenarioIds = new ConcurrentDictionary(); - featureIds = new ConcurrentDictionary(); - } - - /// - /// Gets a value which indicates whether or not a given scenario was a success or not. - /// - /// true, if the scenario was a success, false otherwise. - /// Scenario. - public static bool GetScenarioSuccess(ScenarioContext scenario) => scenario.TestError == null; - } -} diff --git a/CSF.Screenplay.SpecFlow_old/ScenarioAndFeatureKey.cs b/CSF.Screenplay.SpecFlow_old/ScenarioAndFeatureKey.cs deleted file mode 100644 index 4de55941..00000000 --- a/CSF.Screenplay.SpecFlow_old/ScenarioAndFeatureKey.cs +++ /dev/null @@ -1,83 +0,0 @@ -using System; -using TechTalk.SpecFlow; - -namespace CSF.Screenplay.SpecFlow -{ - /// - /// Describes a Feature and Scenario combination, uniquely identifying a scenario. - /// - public class ScenarioAndFeatureKey : IEquatable - { - readonly int cachedHashCode; - readonly ScenarioContext scenario; - readonly FeatureContext feature; - - /// - /// Gets the scenario. - /// - /// The scenario. - public virtual ScenarioContext Scenario => scenario; - - /// - /// Gets the feature. - /// - /// The feature. - public virtual FeatureContext Feature => feature; - - /// - /// Determines whether the specified is equal to the current . - /// - /// The to compare with the current . - /// true if the specified is equal to the current - /// ; otherwise, false. - public override bool Equals(object obj) - { - return Equals(obj as ScenarioAndFeatureKey); - } - - /// - /// Determines whether the specified is equal to the - /// current . - /// - /// The to compare with the current . - /// true if the specified is equal to the current - /// ; otherwise, false. - public bool Equals(ScenarioAndFeatureKey other) - { - if(ReferenceEquals(this, other)) - return true; - if(ReferenceEquals(null, other)) - return false; - - return ReferenceEquals(Scenario, other.Scenario) && ReferenceEquals(Feature, other.Feature); - } - - /// - /// Serves as a hash function for a object. - /// - /// A hash code for this instance that is suitable for use in hashing algorithms and data structures such as a hash table. - public override int GetHashCode() - { - return cachedHashCode; - } - - /// - /// Initializes a new instance of the class. - /// - /// Scenario. - /// Feature. - public ScenarioAndFeatureKey(ScenarioContext scenario, FeatureContext feature) - { - if(scenario == null) - throw new ArgumentNullException(nameof(scenario)); - if(feature == null) - throw new ArgumentNullException(nameof(feature)); - - this.scenario = scenario; - this.feature = feature; - - cachedHashCode = (scenario.ScenarioInfo.Title.GetHashCode() - ^ feature.FeatureInfo.Title.GetHashCode()); - } - } -} diff --git a/CSF.Screenplay.SpecFlow_old/ScreenplayAssemblyAttribute.cs b/CSF.Screenplay.SpecFlow_old/ScreenplayAssemblyAttribute.cs deleted file mode 100644 index 78f4fd36..00000000 --- a/CSF.Screenplay.SpecFlow_old/ScreenplayAssemblyAttribute.cs +++ /dev/null @@ -1,47 +0,0 @@ -using System; -using CSF.Screenplay.Integration; - -namespace CSF.Screenplay.SpecFlow -{ - /// - /// Indicates that the assembly contains Screenplay tests. - /// - [AttributeUsage(AttributeTargets.Assembly, AllowMultiple = false)] - public class ScreenplayAssemblyAttribute : Attribute - { - static Lazy integration; - - /// - /// Gets the current Screenplay integration. - /// - /// The integration. - public IScreenplayIntegration Integration => integration.Value; - - /// - /// Initializes a new instance of the class. - /// - /// Integration type. - public ScreenplayAssemblyAttribute(Type configType) - { - integration = integration?? new Lazy(() => CreateIntegration(configType)); - } - - IScreenplayIntegration CreateIntegration(Type configType) - { - var rootContainer = FlexDi.Container - .CreateBuilder() - .DoNotMakeAllResolutionOptional() - .ResolveUnregisteredTypes() - .SelfRegisterAResolver() - .SelfRegisterTheRegistry() - .SupportResolvingLazyInstances() - .DoNotSupportResolvingNamedInstanceDictionaries() - .ThrowOnCircularDependencies() - .UseInstanceCache() - .DoNotUseNonPublicConstructors() - .Build(); - - return new IntegrationFactory().Create(configType, rootContainer); - } - } -} diff --git a/CSF.Screenplay.SpecFlow_old/ScreenplayBinding.cs b/CSF.Screenplay.SpecFlow_old/ScreenplayBinding.cs deleted file mode 100644 index 23c47cfc..00000000 --- a/CSF.Screenplay.SpecFlow_old/ScreenplayBinding.cs +++ /dev/null @@ -1,82 +0,0 @@ -using System; -using BoDi; -using CSF.Screenplay.Integration; -using CSF.Screenplay.Scenarios; -using TechTalk.SpecFlow; - -namespace CSF.Screenplay.SpecFlow -{ - /// - /// Binding type for the SpecFlow/Screenplay integration. - /// - [Binding] - public class ScreenplayBinding - { - static Lazy integration; - - internal static IScreenplayIntegration Integration - => integration.Value; - - internal static ScenarioAdapter GetScenarioAdapter(ScenarioContext sContext, FeatureContext fContext) - => new ScenarioAdapter(sContext, fContext, Integration); - - readonly FlexDi.IContainer container; - - /// - /// Executed before each scenario. - /// - [Before] - public void BeforeScenario() - { - var scenario = container.Resolve(); - Integration.BeforeScenario(scenario); - } - - /// - /// Executed after each scenario. - /// - [After] - public void AfterScenario() - { - var scenario = container.Resolve(); - var success = ScenarioAdapter.GetScenarioSuccess(container.Resolve()); - Integration.AfterScenario(scenario, success); - } - - /// - /// Executed before a test run. - /// - [BeforeTestRun] - public static void BeforeTestRun() - { - Integration.BeforeExecutingFirstScenario(); - } - - /// - /// Executed after a test run. - /// - [AfterTestRun] - public static void AfterTestRun() - { - Integration.AfterExecutedLastScenario(); - } - - /// - /// Initializes a new instance of the class. - /// - /// Container. - public ScreenplayBinding(FlexDi.IContainer container) - { - this.container = container; - } - - /// - /// Initializes the class. - /// - static ScreenplayBinding() - { - var provider = new IntegrationProvider(); - integration = provider.GetIntegration(); - } - } -} diff --git a/CSF.Screenplay.SpecFlow_old/ScreenplayDependencyInjectionBuilder.cs b/CSF.Screenplay.SpecFlow_old/ScreenplayDependencyInjectionBuilder.cs deleted file mode 100644 index d4dde85b..00000000 --- a/CSF.Screenplay.SpecFlow_old/ScreenplayDependencyInjectionBuilder.cs +++ /dev/null @@ -1,135 +0,0 @@ -// -// ScreenplayDependencyInjectionBuilder.cs -// -// Author: -// Craig Fowler -// -// Copyright (c) 2018 Craig Fowler -// -// Permission is hereby granted, free of charge, to any person obtaining a copy -// of this software and associated documentation files (the "Software"), to deal -// in the Software without restriction, including without limitation the rights -// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -// copies of the Software, and to permit persons to whom the Software is -// furnished to do so, subject to the following conditions: -// -// The above copyright notice and this permission notice shall be included in -// all copies or substantial portions of the Software. -// -// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN -// THE SOFTWARE. -using System; -using BoDi; -using TechTalk.SpecFlow; - -namespace CSF.Screenplay.SpecFlow -{ - /// - /// A builder which propagates the SpecFlow standard dependencies into the FlexDi container. - /// - public class ScreenplayDependencyInjectionBuilder - { - readonly IObjectContainer specflowContainer; - readonly FlexDi.IContainer screenplayContainer; - - /// - /// Re-registers the SpecFlow standard dependencies into the FlexDi container. - /// - public void ReRegisterSpecFlowDependencies() - { - RegisterSpecFlowDefaultDependencies(); - ConfigureContainerDependentObjects(); - } - - void RegisterSpecFlowDefaultDependencies() - { - /* Taken from a combination of: - * TechTalk.SpecFlow.Infrastructure.DefaultDependencyProvider - * TechTalk.SpecFlow.Infrastructure.ContainerBuilder - */ - TryRegisterInstance(); - TryRegisterInstance(); - TryRegisterInstance(); - TryRegisterInstance(); - TryRegisterInstance(); - TryRegisterInstance(); - - TryRegisterInstance(); - TryRegisterInstance(); - TryRegisterInstance(); - TryRegisterInstance(); - TryRegisterInstance(); - TryRegisterInstance(); - TryRegisterInstance(); - TryRegisterInstance(); - TryRegisterInstance(); - TryRegisterInstance(); - TryRegisterInstance(); - TryRegisterInstance(); - TryRegisterInstance(); - TryRegisterInstance(); - TryRegisterInstance(); - TryRegisterInstance(); - TryRegisterInstance(); - TryRegisterInstance(); - TryRegisterInstance(); - TryRegisterInstance(); - - TryRegisterInstance(); - TryRegisterInstance(); - TryRegisterInstance(); - TryRegisterInstance(); - TryRegisterInstance(); - } - - void TryRegisterInstance() where T : class - { - Func accessor = c => c.Resolve(); - try - { - var instance = accessor(specflowContainer); - screenplayContainer.AddRegistrations(b => b.RegisterInstance(instance)); - } - catch(ObjectContainerException) { } - } - - IObjectContainer CreateObjectContainerProxy() - { - return new BoDiContainerProxy(screenplayContainer); - } - - void ConfigureContainerDependentObjects() - { - var containerProxy = CreateObjectContainerProxy(); - screenplayContainer.AddRegistrations(r => r.RegisterInstance(containerProxy).As()); - containerProxy.ObjectCreated += obj => { - var containerDependentObject = obj as TechTalk.SpecFlow.Infrastructure.IContainerDependentObject; - if(containerDependentObject == null) return; - - containerDependentObject.SetObjectContainer(containerProxy); - }; - } - - /// - /// Initializes a new instance of the class. - /// - /// Specflow container. - /// Screenplay container. - public ScreenplayDependencyInjectionBuilder(IObjectContainer specflowContainer, - FlexDi.IContainer screenplayContainer) - { - if(screenplayContainer == null) - throw new ArgumentNullException(nameof(screenplayContainer)); - if(specflowContainer == null) - throw new ArgumentNullException(nameof(specflowContainer)); - - this.screenplayContainer = screenplayContainer; - this.specflowContainer = specflowContainer; - } - } -} diff --git a/CSF.Screenplay.SpecFlow_old/ScreenplayPlugin.cs b/CSF.Screenplay.SpecFlow_old/ScreenplayPlugin.cs deleted file mode 100644 index e4f75100..00000000 --- a/CSF.Screenplay.SpecFlow_old/ScreenplayPlugin.cs +++ /dev/null @@ -1,77 +0,0 @@ -using System; -using System.Reflection; -using CSF.Screenplay.Scenarios; -using TechTalk.SpecFlow; -using TechTalk.SpecFlow.Bindings; -using TechTalk.SpecFlow.Infrastructure; -using TechTalk.SpecFlow.Plugins; - -[assembly: RuntimePlugin(typeof(CSF.Screenplay.SpecFlow.ScreenplayPlugin))] - -namespace CSF.Screenplay.SpecFlow -{ - /// - /// SpecFlow plugin type for Screenplay - /// - public class ScreenplayPlugin : IRuntimePlugin - { - readonly object syncRoot = new object(); - - /// - /// The entry-point for an . This initialises the plugin to provide Screenplay - /// capabilities to the SpecFlow tests. - /// - /// Runtime plugin events. - /// Runtime plugin parameters. - public void Initialize(RuntimePluginEvents runtimePluginEvents, - RuntimePluginParameters runtimePluginParameters) - { - AddPluginStepsAssemblies(runtimePluginEvents); - ConfigureFlexDiDependencyInjection(runtimePluginEvents); - } - - void AddPluginStepsAssemblies(RuntimePluginEvents runtimePluginEvents) - { - runtimePluginEvents.ConfigurationDefaults += (sender, e) => { - e.SpecFlowConfiguration.AdditionalStepAssemblies.Add(ThisAssembly.FullName); - }; - } - - void ConfigureFlexDiDependencyInjection(RuntimePluginEvents runtimePluginEvents) - { - runtimePluginEvents.CustomizeGlobalDependencies += (sender, e) => { - lock(syncRoot) - { - // Apparently this can end up being called multiple times: https://github.com/techtalk/SpecFlow/issues/948 - // So, I'm protecting it from performing registration more than once - if(e.ObjectContainer.IsRegistered()) - return; - - e.ObjectContainer.RegisterTypeAs(); - } - }; - - runtimePluginEvents.CustomizeScenarioDependencies += (sender, e) => { - var container = e.ObjectContainer; - var scenarioContext = container.Resolve(); - var featureContext = container.Resolve(); - - var adapter = ScreenplayBinding.GetScenarioAdapter(scenarioContext, featureContext); - var scenario = adapter.CreateScenario(); - - container.RegisterInstanceAs(scenario.DiContainer); - - scenario.DiContainer.AddRegistrations(r => { - r.RegisterInstance(scenarioContext); - r.RegisterInstance(featureContext); - r.RegisterInstance(scenario).As(); - }); - - var diBuilder = new ScreenplayDependencyInjectionBuilder(e.ObjectContainer, scenario.DiContainer); - diBuilder.ReRegisterSpecFlowDependencies(); - }; - } - - Assembly ThisAssembly => Assembly.GetExecutingAssembly(); - } -} diff --git a/CSF.Screenplay.SpecFlow_old/ScreenplaySteps.cs b/CSF.Screenplay.SpecFlow_old/ScreenplaySteps.cs deleted file mode 100644 index 08bd3ba6..00000000 --- a/CSF.Screenplay.SpecFlow_old/ScreenplaySteps.cs +++ /dev/null @@ -1,58 +0,0 @@ -// -// ScreenplaySteps.cs -// -// Author: -// Craig Fowler -// -// Copyright (c) 2018 Craig Fowler -// -// Permission is hereby granted, free of charge, to any person obtaining a copy -// of this software and associated documentation files (the "Software"), to deal -// in the Software without restriction, including without limitation the rights -// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -// copies of the Software, and to permit persons to whom the Software is -// furnished to do so, subject to the following conditions: -// -// The above copyright notice and this permission notice shall be included in -// all copies or substantial portions of the Software. -// -// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN -// THE SOFTWARE. -using System; -using CSF.Screenplay.Actors; -using TechTalk.SpecFlow; - -namespace CSF.Screenplay.SpecFlow -{ - /// - /// Convenience subclass of TechTalk.SpecFlow.Steps making it possible to call Given, When & Then - /// methods without conflicting with the built-in methods of the same names. - /// - public class ScreenplaySteps : Steps - { - /// - /// Returns the actor instance, as an , in order to perform precondition actions. - /// - /// The actor. - public IGivenActor Given(IActor actor) => StepComposer.Given(actor); - - /// - /// Returns the actor instance, as an , in order to perform actions which exercise the - /// application. - /// - /// The actor. - public IWhenActor When(IActor actor) => StepComposer.When(actor); - - /// - /// Returns the actor instance, as an , in order to perform actions which asserts that - /// the desired outcome has come about. - /// - /// The actor. - public IThenActor Then(IActor actor) => StepComposer.Then(actor); - } -} diff --git a/CSF.Screenplay.SpecFlow_old/packages.config b/CSF.Screenplay.SpecFlow_old/packages.config deleted file mode 100644 index bfb3b435..00000000 --- a/CSF.Screenplay.SpecFlow_old/packages.config +++ /dev/null @@ -1,7 +0,0 @@ - - - - - - - \ No newline at end of file diff --git a/CSF.Screenplay.SpecFlow_old/readme.txt b/CSF.Screenplay.SpecFlow_old/readme.txt deleted file mode 100644 index 146827b3..00000000 --- a/CSF.Screenplay.SpecFlow_old/readme.txt +++ /dev/null @@ -1,37 +0,0 @@ - -Screenplay for SpecFlow : README --------------------------------- - -The first step in setting up a Screenplay integration is to create a "Screenplay integration -config" class in your test project. This class must also be referenced by a -ScreenplayAssembly attribute, which simply tells Screenplay where to find your config. - -This integration config class is used to set up the optional components of Screenplay. These -optional components might be: - -* Reporting -* Additional abilities -* Dependency services - -Here is a template/empty integration config class (including the required attribute) which you -may use as the basis for your own: - -// -- START OF TEMPLATE -- - -[assembly: CSF.Screenplay.SpecFlow.ScreenplayAssembly(typeof(YourNamespace.ScreenplayIntegrationConfig))] -namespace YourNamespace -{ - public class ScreenplayIntegrationConfig : CSF.Screenplay.Integration.IIntegrationConfig - { - public void Configure(CSF.Screenplay.Integration.IIntegrationConfigBuilder builder) - { - - } - } -} - -// -- END OF TEMPLATE -- - -For more information about what may be placed in the Configure method, please refer to: - - https://github.com/csf-dev/CSF.Screenplay/wiki/ConfiguringIntegrations \ No newline at end of file