diff --git a/.dockerignore b/.dockerignore
new file mode 100644
index 0000000..93e08a5
--- /dev/null
+++ b/.dockerignore
@@ -0,0 +1,10 @@
+*/bin
+*/obj
+.dockerignore
+.env
+.git
+.gitignore
+.vs
+.vscode
+**/.toolstarget
+.idea
\ No newline at end of file
diff --git a/.editorconfig b/.editorconfig
new file mode 100644
index 0000000..fa9f08c
--- /dev/null
+++ b/.editorconfig
@@ -0,0 +1,19 @@
+[*.cs]
+
+# CA1031: Do not catch general exception types
+dotnet_diagnostic.CA1031.severity = suggestion
+
+# CA1303: Do not pass literals as localized parameters
+dotnet_diagnostic.CA1303.severity = none
+
+# CA1707: Identifiers should not contain underscores
+dotnet_diagnostic.CA1707.severity = none
+
+# CA2235: Mark all non-serializable fields
+dotnet_diagnostic.CA2235.severity = none
+
+# CA2227: Collection properties should be read only
+dotnet_diagnostic.CA2227.severity = none
+
+# CA5364: Do Not Use Deprecated Security Protocols
+dotnet_diagnostic.CA5364.severity = silent
diff --git a/.gitignore b/.gitignore
index ec0538f..be9e777 100644
--- a/.gitignore
+++ b/.gitignore
@@ -1,199 +1,10 @@
-## Ignore Visual Studio temporary files, build results, and
-## files generated by popular Visual Studio add-ons.
-
-# User-specific files
-*.suo
-*.user
-*.userosscache
-*.sln.docstates
-
-# User-specific files (MonoDevelop/Xamarin Studio)
-*.userprefs
-
-# Build results
-[Dd]ebug/
-[Dd]ebugPublic/
-[Rr]elease/
-[Rr]eleases/
-x64/
-x86/
-build/
-bld/
[Bb]in/
[Oo]bj/
+*.userprefs
+.vs
+.vscode
+.DS_Store
+*.nuget.props
+*.nuget.targets
+*.user
-# Visual Studo 2015 cache/options directory
-.vs/
-
-# MSTest test Results
-[Tt]est[Rr]esult*/
-[Bb]uild[Ll]og.*
-
-# NUNIT
-*.VisualState.xml
-TestResult.xml
-
-# Build Results of an ATL Project
-[Dd]ebugPS/
-[Rr]eleasePS/
-dlldata.c
-
-*_i.c
-*_p.c
-*_i.h
-*.ilk
-*.meta
-*.obj
-*.pch
-*.pdb
-*.pgc
-*.pgd
-*.rsp
-*.sbr
-*.tlb
-*.tli
-*.tlh
-*.tmp
-*.tmp_proj
-*.log
-*.vspscc
-*.vssscc
-.builds
-*.pidb
-*.svclog
-*.scc
-
-# Chutzpah Test files
-_Chutzpah*
-
-# Visual C++ cache files
-ipch/
-*.aps
-*.ncb
-*.opensdf
-*.sdf
-*.cachefile
-
-# Visual Studio profiler
-*.psess
-*.vsp
-*.vspx
-
-# TFS 2012 Local Workspace
-$tf/
-
-# Guidance Automation Toolkit
-*.gpState
-
-# ReSharper is a .NET coding add-in
-_ReSharper*/
-*.[Rr]e[Ss]harper
-*.DotSettings.user
-
-# JustCode is a .NET coding addin-in
-.JustCode
-
-# TeamCity is a build add-in
-_TeamCity*
-
-# DotCover is a Code Coverage Tool
-*.dotCover
-
-# NCrunch
-_NCrunch_*
-.*crunch*.local.xml
-
-# MightyMoose
-*.mm.*
-AutoTest.Net/
-
-# Web workbench (sass)
-.sass-cache/
-
-# Installshield output folder
-[Ee]xpress/
-
-# DocProject is a documentation generator add-in
-DocProject/buildhelp/
-DocProject/Help/*.HxT
-DocProject/Help/*.HxC
-DocProject/Help/*.hhc
-DocProject/Help/*.hhk
-DocProject/Help/*.hhp
-DocProject/Help/Html2
-DocProject/Help/html
-
-# Click-Once directory
-publish/
-
-# Publish Web Output
-*.[Pp]ublish.xml
-*.azurePubxml
-# TODO: Comment the next line if you want to checkin your web deploy settings
-# but database connection strings (with potential passwords) will be unencrypted
-*.pubxml
-*.publishproj
-
-# NuGet Packages
-*.nupkg
-# The packages folder can be ignored because of Package Restore
-**/packages/*
-# except build/, which is used as an MSBuild target.
-!**/packages/build/
-# Uncomment if necessary however generally it will be regenerated when needed
-#!**/packages/repositories.config
-
-# Windows Azure Build Output
-csx/
-*.build.csdef
-
-# Windows Store app package directory
-AppPackages/
-
-# Others
-*.[Cc]ache
-ClientBin/
-[Ss]tyle[Cc]op.*
-~$*
-*~
-*.dbmdl
-*.dbproj.schemaview
-*.pfx
-*.publishsettings
-node_modules/
-bower_components/
-
-# RIA/Silverlight projects
-Generated_Code/
-
-# Backup & report files from converting an old project file
-# to a newer Visual Studio version. Backup files are not needed,
-# because we have git ;-)
-_UpgradeReport_Files/
-Backup*/
-UpgradeLog*.XML
-UpgradeLog*.htm
-
-# SQL Server files
-*.mdf
-*.ldf
-
-# Business Intelligence projects
-*.rdl.data
-*.bim.layout
-*.bim_*.settings
-
-# Microsoft Fakes
-FakesAssemblies/
-
-# Node.js Tools for Visual Studio
-.ntvs_analysis.dat
-
-# Visual Studio 6 build log
-*.plg
-
-# Visual Studio 6 workspace options file
-*.opt
-
-# Plugin build result
-[Pp]lugin/
\ No newline at end of file
diff --git a/.travis.yml b/.travis.yml
new file mode 100644
index 0000000..5fd817a
--- /dev/null
+++ b/.travis.yml
@@ -0,0 +1,16 @@
+language: csharp
+solution: SpecFlow.RetryCore.sln
+mono: none
+dist: bionic
+before_install:
+ - wget https://packages.microsoft.com/config/ubuntu/18.04/packages-microsoft-prod.deb -O packages-microsoft-prod.deb
+ - sudo dpkg -i packages-microsoft-prod.deb
+ - sudo apt-get update
+ - sudo apt-get install -y apt-transport-https
+ - sudo apt-get update
+ - sudo apt-get install -y dotnet-sdk-3.1
+ - sudo apt-get install -y aspnetcore-runtime-3.1
+script:
+- dotnet test --filter "Category=MockTests"
+- dotnet build -c Release
+- dotnet pack -c Release
diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md
new file mode 100644
index 0000000..3d3366b
--- /dev/null
+++ b/CONTRIBUTING.md
@@ -0,0 +1,22 @@
+# Contributing
+
+GitHub is the tool used for managing reviews and pull requests of SpecFlow.RetryCore (SpecFlow.RetryCore for .NET).
+
+## Issues and Pull Requests
+
+When opening an issue pull request, please make sure to address to the [maintainers of this repository](MAINTAINERS.md). The description must contain a clear explanation of what the change is about.
+
+To submit a change, first look for an existing issue on the matter. If none is found, please open an issue explaining the goal and motivation.
+
+## Development Guidelines
+
+- Commit messages must be concise and clear, explaining the change
+- The commit messages should reference the associated issue
+- Each commit must have a well-defined scope, preferably with a small change
+- Code must be kept as much clear and simple as possible
+- The general spacing, alignment and naming conventions of the project must be respected
+- Changes must be covered with tests
+- Tests must succeed for each individual commit
+- Binaries, packages or development auxiliary files (e.g. IDE metadata) must not be pushed to the repository
+- If `.gitignore` is not considering files that must not be present in the repository, it should be edited before the commit
+- Breaking changes shall be avoided
diff --git a/Directory.Build.props b/Directory.Build.props
new file mode 100644
index 0000000..7d842dc
--- /dev/null
+++ b/Directory.Build.props
@@ -0,0 +1,29 @@
+
+
+
+
+ all
+
+
+ stylecop.json
+
+
+
+
+
+
+ all
+
+
+
+
+
+ Calrom Ltd
+ 1.0.0
+ $(MSBuildThisFileDirectory)SpeckFlow.RetryCore.ruleset
+ true
+ disable
+ CS8600;CS8602;CS8603
+ 8.0
+
+
diff --git a/LICENSE.md b/LICENSE.md
new file mode 100644
index 0000000..d115a37
--- /dev/null
+++ b/LICENSE.md
@@ -0,0 +1,7 @@
+Copyright 2021 CalromLTD
+
+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.
diff --git a/MAINTAINERS.md b/MAINTAINERS.md
new file mode 100644
index 0000000..0266436
--- /dev/null
+++ b/MAINTAINERS.md
@@ -0,0 +1,4 @@
+### Maintainers
+
+* calrom-jtejero
+
diff --git a/NOTICES_3RD_PARTY.md b/NOTICES_3RD_PARTY.md
new file mode 100644
index 0000000..d40e821
--- /dev/null
+++ b/NOTICES_3RD_PARTY.md
@@ -0,0 +1,191 @@
+This project, DotNetMockServerClient, is based on parts of the material from
+ the project(s) identified below. The owner of DotNetMockServerClient is not
+ the original author of any of the listed third-party projects.
+
+In the eventual case a required license or notice is missing, please bring
+ it to the owner's attention by raising an issue.
+
+----
+
+Mock-Server
+
+https://github.com/mock-server/mockserver
+
+http://www.apache.org/licenses/LICENSE-2.0
+
+ Apache License
+ Version 2.0, January 2004
+ http://www.apache.org/licenses/
+
+ TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
+
+ 1. Definitions.
+
+ "License" shall mean the terms and conditions for use, reproduction,
+ and distribution as defined by Sections 1 through 9 of this document.
+
+ "Licensor" shall mean the copyright owner or entity authorized by
+ the copyright owner that is granting the License.
+
+ "Legal Entity" shall mean the union of the acting entity and all
+ other entities that control, are controlled by, or are under common
+ control with that entity. For the purposes of this definition,
+ "control" means (i) the power, direct or indirect, to cause the
+ direction or management of such entity, whether by contract or
+ otherwise, or (ii) ownership of fifty percent (50%) or more of the
+ outstanding shares, or (iii) beneficial ownership of such entity.
+
+ "You" (or "Your") shall mean an individual or Legal Entity
+ exercising permissions granted by this License.
+
+ "Source" form shall mean the preferred form for making modifications,
+ including but not limited to software source code, documentation
+ source, and configuration files.
+
+ "Object" form shall mean any form resulting from mechanical
+ transformation or translation of a Source form, including but
+ not limited to compiled object code, generated documentation,
+ and conversions to other media types.
+
+ "Work" shall mean the work of authorship, whether in Source or
+ Object form, made available under the License, as indicated by a
+ copyright notice that is included in or attached to the work
+ (an example is provided in the Appendix below).
+
+ "Derivative Works" shall mean any work, whether in Source or Object
+ form, that is based on (or derived from) the Work and for which the
+ editorial revisions, annotations, elaborations, or other modifications
+ represent, as a whole, an original work of authorship. For the purposes
+ of this License, Derivative Works shall not include works that remain
+ separable from, or merely link (or bind by name) to the interfaces of,
+ the Work and Derivative Works thereof.
+
+ "Contribution" shall mean any work of authorship, including
+ the original version of the Work and any modifications or additions
+ to that Work or Derivative Works thereof, that is intentionally
+ submitted to Licensor for inclusion in the Work by the copyright owner
+ or by an individual or Legal Entity authorized to submit on behalf of
+ the copyright owner. For the purposes of this definition, "submitted"
+ means any form of electronic, verbal, or written communication sent
+ to the Licensor or its representatives, including but not limited to
+ communication on electronic mailing lists, source code control systems,
+ and issue tracking systems that are managed by, or on behalf of, the
+ Licensor for the purpose of discussing and improving the Work, but
+ excluding communication that is conspicuously marked or otherwise
+ designated in writing by the copyright owner as "Not a Contribution."
+
+ "Contributor" shall mean Licensor and any individual or Legal Entity
+ on behalf of whom a Contribution has been received by Licensor and
+ subsequently incorporated within the Work.
+
+ 2. Grant of Copyright License. Subject to the terms and conditions of
+ this License, each Contributor hereby grants to You a perpetual,
+ worldwide, non-exclusive, no-charge, royalty-free, irrevocable
+ copyright license to reproduce, prepare Derivative Works of,
+ publicly display, publicly perform, sublicense, and distribute the
+ Work and such Derivative Works in Source or Object form.
+
+ 3. Grant of Patent License. Subject to the terms and conditions of
+ this License, each Contributor hereby grants to You a perpetual,
+ worldwide, non-exclusive, no-charge, royalty-free, irrevocable
+ (except as stated in this section) patent license to make, have made,
+ use, offer to sell, sell, import, and otherwise transfer the Work,
+ where such license applies only to those patent claims licensable
+ by such Contributor that are necessarily infringed by their
+ Contribution(s) alone or by combination of their Contribution(s)
+ with the Work to which such Contribution(s) was submitted. If You
+ institute patent litigation against any entity (including a
+ cross-claim or counterclaim in a lawsuit) alleging that the Work
+ or a Contribution incorporated within the Work constitutes direct
+ or contributory patent infringement, then any patent licenses
+ granted to You under this License for that Work shall terminate
+ as of the date such litigation is filed.
+
+ 4. Redistribution. You may reproduce and distribute copies of the
+ Work or Derivative Works thereof in any medium, with or without
+ modifications, and in Source or Object form, provided that You
+ meet the following conditions:
+
+ (a) You must give any other recipients of the Work or
+ Derivative Works a copy of this License; and
+
+ (b) You must cause any modified files to carry prominent notices
+ stating that You changed the files; and
+
+ (c) You must retain, in the Source form of any Derivative Works
+ that You distribute, all copyright, patent, trademark, and
+ attribution notices from the Source form of the Work,
+ excluding those notices that do not pertain to any part of
+ the Derivative Works; and
+
+ (d) If the Work includes a "NOTICE" text file as part of its
+ distribution, then any Derivative Works that You distribute must
+ include a readable copy of the attribution notices contained
+ within such NOTICE file, excluding those notices that do not
+ pertain to any part of the Derivative Works, in at least one
+ of the following places: within a NOTICE text file distributed
+ as part of the Derivative Works; within the Source form or
+ documentation, if provided along with the Derivative Works; or,
+ within a display generated by the Derivative Works, if and
+ wherever such third-party notices normally appear. The contents
+ of the NOTICE file are for informational purposes only and
+ do not modify the License. You may add Your own attribution
+ notices within Derivative Works that You distribute, alongside
+ or as an addendum to the NOTICE text from the Work, provided
+ that such additional attribution notices cannot be construed
+ as modifying the License.
+
+ You may add Your own copyright statement to Your modifications and
+ may provide additional or different license terms and conditions
+ for use, reproduction, or distribution of Your modifications, or
+ for any such Derivative Works as a whole, provided Your use,
+ reproduction, and distribution of the Work otherwise complies with
+ the conditions stated in this License.
+
+ 5. Submission of Contributions. Unless You explicitly state otherwise,
+ any Contribution intentionally submitted for inclusion in the Work
+ by You to the Licensor shall be under the terms and conditions of
+ this License, without any additional terms or conditions.
+ Notwithstanding the above, nothing herein shall supersede or modify
+ the terms of any separate license agreement you may have executed
+ with Licensor regarding such Contributions.
+
+ 6. Trademarks. This License does not grant permission to use the trade
+ names, trademarks, service marks, or product names of the Licensor,
+ except as required for reasonable and customary use in describing the
+ origin of the Work and reproducing the content of the NOTICE file.
+
+ 7. Disclaimer of Warranty. Unless required by applicable law or
+ agreed to in writing, Licensor provides the Work (and each
+ Contributor provides its Contributions) on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
+ implied, including, without limitation, any warranties or conditions
+ of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
+ PARTICULAR PURPOSE. You are solely responsible for determining the
+ appropriateness of using or redistributing the Work and assume any
+ risks associated with Your exercise of permissions under this License.
+
+ 8. Limitation of Liability. In no event and under no legal theory,
+ whether in tort (including negligence), contract, or otherwise,
+ unless required by applicable law (such as deliberate and grossly
+ negligent acts) or agreed to in writing, shall any Contributor be
+ liable to You for damages, including any direct, indirect, special,
+ incidental, or consequential damages of any character arising as a
+ result of this License or out of the use or inability to use the
+ Work (including but not limited to damages for loss of goodwill,
+ work stoppage, computer failure or malfunction, or any and all
+ other commercial damages or losses), even if such Contributor
+ has been advised of the possibility of such damages.
+
+ 9. Accepting Warranty or Additional Liability. While redistributing
+ the Work or Derivative Works thereof, You may choose to offer,
+ and charge a fee for, acceptance of support, warranty, indemnity,
+ or other liability obligations and/or rights consistent with this
+ License. However, in accepting such obligations, You may act only
+ on Your own behalf and on Your sole responsibility, not on behalf
+ of any other Contributor, and only if You agree to indemnify,
+ defend, and hold each Contributor harmless for any liability
+ incurred by, or claims asserted against, such Contributor by reason
+ of your accepting any such warranty or additional liability.
+
+ END OF TERMS AND CONDITIONS
diff --git a/src/SpecFlow.Retry.Sample/SampleFeature.feature b/README.md
similarity index 51%
rename from src/SpecFlow.Retry.Sample/SampleFeature.feature
rename to README.md
index 55b0098..a17d3f3 100644
--- a/src/SpecFlow.Retry.Sample/SampleFeature.feature
+++ b/README.md
@@ -1,38 +1,43 @@
-@retry:1
+# specflow-retry
+SpecFlow generator plugin that adds ability to retry tests on failure for MSTest/[NUnit](http://nunit.org/).
+
+## Versions
+"SpecFlow.RetryCore" version="2.3.0" (dependency on "SpecFlow" version="2.4.8")
+
+## Setup
+
+Add the nuget package and the SpecFlow.CustomPlugin
+
+## Usage
+
+Adding a retry at the feature level will re-try any failing scenario:
+
+```
+@retry:1
Feature: SampleFeature
In order to avoid silly mistakes
As a math idiot
I want to be told the sum of two numbers
-@retry:2
-Scenario: Random number generator test
- Given I have random number generator
- When it generates number
- Then I'll be lucky if it will be greater then 0.3
-
-Scenario: Scenario contextisolation
- Given by default scenario context stored value is 0
- When I increment scenario context stored value
- Then scenario context stored value should be 1
- And scenario should be run 2 times
-
Scenario: Tag on feature should be applied
Then scenario should be run 2 times
-@retry:2
-Scenario: Tag on scenario is preffered
- Then scenario should be run 3 times
-
-@retryExcept:SpecFlow.Retry.Sample.CriticalException
-@criticalException
-Scenario: On except exception should not retry
- When "SpecFlow.Retry.Sample.CriticalException" thrown
- Then nothing
-
Scenario Outline: Tag on feature should be applied to outlined scenario
Then scenario "" should be run 2 times
Examples:
| example |
| first |
| second |
+```
+
+Adding a retry at the scenario level will re-try the failing scenario:
+
+```
+@retry:2
+Scenario: Random number generator test
+ Given I have random number generator
+ When it generates number
+ Then I'll be lucky if it will be greater then 0.3
+```
+## Build status
diff --git a/appveyor.yml b/appveyor.yml
new file mode 100644
index 0000000..5456a67
--- /dev/null
+++ b/appveyor.yml
@@ -0,0 +1,9 @@
+configuration: Release
+
+before_build:
+ - nuget restore src\SpecFlow.Retry.sln
+
+build:
+ project: src\SpecFlow.Retry.sln
+ verbosity: normal
+
diff --git a/nuget.config b/nuget.config
new file mode 100644
index 0000000..5034e22
--- /dev/null
+++ b/nuget.config
@@ -0,0 +1,9 @@
+
+
+
+
+
+
+
+
+
diff --git a/src/SpecFlow.Retry.Sample/App.config b/src/SpecFlow.Retry.Sample/App.config
deleted file mode 100644
index 8f56313..0000000
--- a/src/SpecFlow.Retry.Sample/App.config
+++ /dev/null
@@ -1,24 +0,0 @@
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
\ No newline at end of file
diff --git a/src/SpecFlow.Retry.Sample/CriticalException.cs b/src/SpecFlow.Retry.Sample/CriticalException.cs
deleted file mode 100644
index 16ad86c..0000000
--- a/src/SpecFlow.Retry.Sample/CriticalException.cs
+++ /dev/null
@@ -1,31 +0,0 @@
-using System;
-using System.Collections.Generic;
-using System.Linq;
-using System.Runtime.Serialization;
-using System.Text;
-using System.Threading.Tasks;
-
-namespace SpecFlow.Retry.Sample
-{
- [Serializable]
- public class CriticalException : Exception
- {
- public CriticalException()
- {
- }
-
- public CriticalException(string message) : base(message)
- {
- }
-
- public CriticalException(string message, Exception inner) : base(message, inner)
- {
- }
-
- protected CriticalException(
- SerializationInfo info,
- StreamingContext context) : base(info, context)
- {
- }
- }
-}
diff --git a/src/SpecFlow.Retry.Sample/Properties/AssemblyInfo.cs b/src/SpecFlow.Retry.Sample/Properties/AssemblyInfo.cs
deleted file mode 100644
index c89311e..0000000
--- a/src/SpecFlow.Retry.Sample/Properties/AssemblyInfo.cs
+++ /dev/null
@@ -1,36 +0,0 @@
-using System.Reflection;
-using System.Runtime.CompilerServices;
-using System.Runtime.InteropServices;
-
-// General Information about an assembly is controlled through the following
-// set of attributes. Change these attribute values to modify the information
-// associated with an assembly.
-[assembly: AssemblyTitle("SpecFlow.Retry.Sample")]
-[assembly: AssemblyDescription("")]
-[assembly: AssemblyConfiguration("")]
-[assembly: AssemblyCompany("")]
-[assembly: AssemblyProduct("SpecFlow.Retry.Sample")]
-[assembly: AssemblyCopyright("Copyright © 2015")]
-[assembly: AssemblyTrademark("")]
-[assembly: AssemblyCulture("")]
-
-// Setting ComVisible to false makes the types in this assembly not visible
-// to COM components. If you need to access a type in this assembly from
-// COM, set the ComVisible attribute to true on that type.
-[assembly: ComVisible(false)]
-
-// The following GUID is for the ID of the typelib if this project is exposed to COM
-[assembly: Guid("abbe918c-ac74-42f7-a03a-63a5aa88947a")]
-
-// Version information for an assembly consists of the following four values:
-//
-// Major Version
-// Minor Version
-// Build Number
-// Revision
-//
-// You can specify all the values or you can default the Build and Revision Numbers
-// by using the '*' as shown below:
-// [assembly: AssemblyVersion("1.0.*")]
-[assembly: AssemblyVersion("0.1.0.0")]
-[assembly: AssemblyFileVersion("0.1.0.0")]
diff --git a/src/SpecFlow.Retry.Sample/SampleFeature.feature.cs b/src/SpecFlow.Retry.Sample/SampleFeature.feature.cs
deleted file mode 100644
index 8ec2a86..0000000
--- a/src/SpecFlow.Retry.Sample/SampleFeature.feature.cs
+++ /dev/null
@@ -1,326 +0,0 @@
-// ------------------------------------------------------------------------------
-//
-// This code was generated by SpecFlow (http://www.specflow.org/).
-// SpecFlow Version:1.9.0.77
-// SpecFlow Generator Version:1.9.0.0
-// Runtime Version:4.0.30319.0
-//
-// Changes to this file may cause incorrect behavior and will be lost if
-// the code is regenerated.
-//
-// ------------------------------------------------------------------------------
-#region Designer generated code
-#pragma warning disable
-namespace SpecFlow.Retry.Sample
-{
- using TechTalk.SpecFlow;
-
-
- [System.CodeDom.Compiler.GeneratedCodeAttribute("TechTalk.SpecFlow", "1.9.0.77")]
- [System.Runtime.CompilerServices.CompilerGeneratedAttribute()]
- [Microsoft.VisualStudio.TestTools.UnitTesting.TestClassAttribute()]
- public partial class SampleFeatureFeature
- {
-
- private static TechTalk.SpecFlow.ITestRunner testRunner;
-
- [Microsoft.VisualStudio.TestTools.UnitTesting.ClassInitializeAttribute()]
- public static void FeatureSetup(Microsoft.VisualStudio.TestTools.UnitTesting.TestContext testContext)
- {
- testRunner = TechTalk.SpecFlow.TestRunnerManager.GetTestRunner();
- TechTalk.SpecFlow.FeatureInfo featureInfo = new TechTalk.SpecFlow.FeatureInfo(new System.Globalization.CultureInfo("en-US"), "SampleFeature", " In order to avoid silly mistakes\r\n As a math idiot\r\n I want to be told the su" +
- "m of two numbers", ProgrammingLanguage.CSharp, new string[] {
- "retry:1"});
- testRunner.OnFeatureStart(featureInfo);
- }
-
- [Microsoft.VisualStudio.TestTools.UnitTesting.ClassCleanupAttribute()]
- public static void FeatureTearDown()
- {
- testRunner.OnFeatureEnd();
- testRunner = null;
- }
-
- [Microsoft.VisualStudio.TestTools.UnitTesting.TestInitializeAttribute()]
- public virtual void TestInitialize()
- {
- if (((TechTalk.SpecFlow.FeatureContext.Current != null)
- && (TechTalk.SpecFlow.FeatureContext.Current.FeatureInfo.Title != "SampleFeature")))
- {
- SpecFlow.Retry.Sample.SampleFeatureFeature.FeatureSetup(null);
- }
- }
-
- [Microsoft.VisualStudio.TestTools.UnitTesting.TestCleanupAttribute()]
- public virtual void ScenarioTearDown()
- {
- testRunner.OnScenarioEnd();
- }
-
- public virtual void ScenarioSetup(TechTalk.SpecFlow.ScenarioInfo scenarioInfo)
- {
- testRunner.OnScenarioStart(scenarioInfo);
- }
-
- public virtual void ScenarioCleanup()
- {
- testRunner.CollectScenarioErrors();
- }
-
- [Microsoft.VisualStudio.TestTools.UnitTesting.TestMethodAttribute()]
- [Microsoft.VisualStudio.TestTools.UnitTesting.DescriptionAttribute("Random number generator test")]
- [Microsoft.VisualStudio.TestTools.UnitTesting.TestPropertyAttribute("FeatureTitle", "SampleFeature")]
- public virtual void RandomNumberGeneratorTest()
- {
- System.Exception lastException = null;
- for (int i = 0; (i <= 2); i = (i + 1))
- {
- try
- {
- this.RandomNumberGeneratorTestInternal();
- return;
- }
- catch (System.Exception exc)
- {
- lastException = exc;
- }
- if (((i + 1)
- <= 2))
- {
- testRunner.OnScenarioEnd();
- }
- }
- if ((lastException != null))
- {
- throw lastException;
- }
- }
-
- private void RandomNumberGeneratorTestInternal()
- {
- TechTalk.SpecFlow.ScenarioInfo scenarioInfo = new TechTalk.SpecFlow.ScenarioInfo("Random number generator test", new string[] {
- "retry:2"});
- this.ScenarioSetup(scenarioInfo);
- testRunner.Given("I have random number generator", ((string)(null)), ((TechTalk.SpecFlow.Table)(null)), "Given ");
- testRunner.When("it generates number", ((string)(null)), ((TechTalk.SpecFlow.Table)(null)), "When ");
- testRunner.Then("I\'ll be lucky if it will be greater then 0.3", ((string)(null)), ((TechTalk.SpecFlow.Table)(null)), "Then ");
- this.ScenarioCleanup();
- }
-
- [Microsoft.VisualStudio.TestTools.UnitTesting.TestMethodAttribute()]
- [Microsoft.VisualStudio.TestTools.UnitTesting.DescriptionAttribute("Scenario contextisolation")]
- [Microsoft.VisualStudio.TestTools.UnitTesting.TestPropertyAttribute("FeatureTitle", "SampleFeature")]
- public virtual void ScenarioContextisolation()
- {
- System.Exception lastException = null;
- for (int i = 0; (i <= 1); i = (i + 1))
- {
- try
- {
- this.ScenarioContextisolationInternal();
- return;
- }
- catch (System.Exception exc)
- {
- lastException = exc;
- }
- if (((i + 1)
- <= 1))
- {
- testRunner.OnScenarioEnd();
- }
- }
- if ((lastException != null))
- {
- throw lastException;
- }
- }
-
- private void ScenarioContextisolationInternal()
- {
- TechTalk.SpecFlow.ScenarioInfo scenarioInfo = new TechTalk.SpecFlow.ScenarioInfo("Scenario contextisolation", ((string[])(null)));
- this.ScenarioSetup(scenarioInfo);
- testRunner.Given("by default scenario context stored value is 0", ((string)(null)), ((TechTalk.SpecFlow.Table)(null)), "Given ");
- testRunner.When("I increment scenario context stored value", ((string)(null)), ((TechTalk.SpecFlow.Table)(null)), "When ");
- testRunner.Then("scenario context stored value should be 1", ((string)(null)), ((TechTalk.SpecFlow.Table)(null)), "Then ");
- testRunner.And("scenario should be run 2 times", ((string)(null)), ((TechTalk.SpecFlow.Table)(null)), "And ");
- this.ScenarioCleanup();
- }
-
- [Microsoft.VisualStudio.TestTools.UnitTesting.TestMethodAttribute()]
- [Microsoft.VisualStudio.TestTools.UnitTesting.DescriptionAttribute("Tag on feature should be applied")]
- [Microsoft.VisualStudio.TestTools.UnitTesting.TestPropertyAttribute("FeatureTitle", "SampleFeature")]
- public virtual void TagOnFeatureShouldBeApplied()
- {
- System.Exception lastException = null;
- for (int i = 0; (i <= 1); i = (i + 1))
- {
- try
- {
- this.TagOnFeatureShouldBeAppliedInternal();
- return;
- }
- catch (System.Exception exc)
- {
- lastException = exc;
- }
- if (((i + 1)
- <= 1))
- {
- testRunner.OnScenarioEnd();
- }
- }
- if ((lastException != null))
- {
- throw lastException;
- }
- }
-
- private void TagOnFeatureShouldBeAppliedInternal()
- {
- TechTalk.SpecFlow.ScenarioInfo scenarioInfo = new TechTalk.SpecFlow.ScenarioInfo("Tag on feature should be applied", ((string[])(null)));
- this.ScenarioSetup(scenarioInfo);
- testRunner.Then("scenario should be run 2 times", ((string)(null)), ((TechTalk.SpecFlow.Table)(null)), "Then ");
- this.ScenarioCleanup();
- }
-
- [Microsoft.VisualStudio.TestTools.UnitTesting.TestMethodAttribute()]
- [Microsoft.VisualStudio.TestTools.UnitTesting.DescriptionAttribute("Tag on scenario is preffered")]
- [Microsoft.VisualStudio.TestTools.UnitTesting.TestPropertyAttribute("FeatureTitle", "SampleFeature")]
- public virtual void TagOnScenarioIsPreffered()
- {
- System.Exception lastException = null;
- for (int i = 0; (i <= 2); i = (i + 1))
- {
- try
- {
- this.TagOnScenarioIsPrefferedInternal();
- return;
- }
- catch (System.Exception exc)
- {
- lastException = exc;
- }
- if (((i + 1)
- <= 2))
- {
- testRunner.OnScenarioEnd();
- }
- }
- if ((lastException != null))
- {
- throw lastException;
- }
- }
-
- private void TagOnScenarioIsPrefferedInternal()
- {
- TechTalk.SpecFlow.ScenarioInfo scenarioInfo = new TechTalk.SpecFlow.ScenarioInfo("Tag on scenario is preffered", new string[] {
- "retry:2"});
- this.ScenarioSetup(scenarioInfo);
- testRunner.Then("scenario should be run 3 times", ((string)(null)), ((TechTalk.SpecFlow.Table)(null)), "Then ");
- this.ScenarioCleanup();
- }
-
- [Microsoft.VisualStudio.TestTools.UnitTesting.TestMethodAttribute()]
- [Microsoft.VisualStudio.TestTools.UnitTesting.DescriptionAttribute("On except exception should not retry")]
- [Microsoft.VisualStudio.TestTools.UnitTesting.TestPropertyAttribute("FeatureTitle", "SampleFeature")]
- [Microsoft.VisualStudio.TestTools.UnitTesting.TestCategoryAttribute("criticalException")]
- public virtual void OnExceptExceptionShouldNotRetry()
- {
- System.Exception lastException = null;
- for (int i = 0; (i <= 1); i = (i + 1))
- {
- try
- {
- this.OnExceptExceptionShouldNotRetryInternal();
- return;
- }
- catch (SpecFlow.Retry.Sample.CriticalException exc)
- {
- throw;
- }
- catch (System.Exception exc)
- {
- lastException = exc;
- }
- if (((i + 1)
- <= 1))
- {
- testRunner.OnScenarioEnd();
- }
- }
- if ((lastException != null))
- {
- throw lastException;
- }
- }
-
- private void OnExceptExceptionShouldNotRetryInternal()
- {
- TechTalk.SpecFlow.ScenarioInfo scenarioInfo = new TechTalk.SpecFlow.ScenarioInfo("On except exception should not retry", new string[] {
- "retryExcept:SpecFlow.Retry.Sample.CriticalException",
- "criticalException"});
- this.ScenarioSetup(scenarioInfo);
- testRunner.When("\"SpecFlow.Retry.Sample.CriticalException\" thrown", ((string)(null)), ((TechTalk.SpecFlow.Table)(null)), "When ");
- testRunner.Then("nothing", ((string)(null)), ((TechTalk.SpecFlow.Table)(null)), "Then ");
- this.ScenarioCleanup();
- }
-
- public virtual void TagOnFeatureShouldBeAppliedToOutlinedScenario(string example, string[] exampleTags)
- {
- System.Exception lastException = null;
- for (int i = 0; (i <= 1); i = (i + 1))
- {
- try
- {
- this.TagOnFeatureShouldBeAppliedToOutlinedScenarioInternal(example, exampleTags);
- return;
- }
- catch (System.Exception exc)
- {
- lastException = exc;
- }
- if (((i + 1)
- <= 1))
- {
- testRunner.OnScenarioEnd();
- }
- }
- if ((lastException != null))
- {
- throw lastException;
- }
- }
-
- [Microsoft.VisualStudio.TestTools.UnitTesting.TestMethodAttribute()]
- [Microsoft.VisualStudio.TestTools.UnitTesting.DescriptionAttribute("Tag on feature should be applied to outlined scenario")]
- [Microsoft.VisualStudio.TestTools.UnitTesting.TestPropertyAttribute("FeatureTitle", "SampleFeature")]
- [Microsoft.VisualStudio.TestTools.UnitTesting.TestPropertyAttribute("VariantName", "first")]
- [Microsoft.VisualStudio.TestTools.UnitTesting.TestPropertyAttribute("Parameter:example", "first")]
- public virtual void TagOnFeatureShouldBeAppliedToOutlinedScenario_First()
- {
- this.TagOnFeatureShouldBeAppliedToOutlinedScenario("first", ((string[])(null)));
- }
-
- [Microsoft.VisualStudio.TestTools.UnitTesting.TestMethodAttribute()]
- [Microsoft.VisualStudio.TestTools.UnitTesting.DescriptionAttribute("Tag on feature should be applied to outlined scenario")]
- [Microsoft.VisualStudio.TestTools.UnitTesting.TestPropertyAttribute("FeatureTitle", "SampleFeature")]
- [Microsoft.VisualStudio.TestTools.UnitTesting.TestPropertyAttribute("VariantName", "second")]
- [Microsoft.VisualStudio.TestTools.UnitTesting.TestPropertyAttribute("Parameter:example", "second")]
- public virtual void TagOnFeatureShouldBeAppliedToOutlinedScenario_Second()
- {
- this.TagOnFeatureShouldBeAppliedToOutlinedScenario("second", ((string[])(null)));
- }
-
- private void TagOnFeatureShouldBeAppliedToOutlinedScenarioInternal(string example, string[] exampleTags)
- {
- TechTalk.SpecFlow.ScenarioInfo scenarioInfo = new TechTalk.SpecFlow.ScenarioInfo("Tag on feature should be applied to outlined scenario", exampleTags);
- this.ScenarioSetup(scenarioInfo);
- testRunner.Then(string.Format("scenario \"{0}\" should be run 2 times", example), ((string)(null)), ((TechTalk.SpecFlow.Table)(null)), "Then ");
- this.ScenarioCleanup();
- }
- }
-}
-#pragma warning restore
-#endregion
diff --git a/src/SpecFlow.Retry.Sample/SpecFlow.Retry.Sample.csproj b/src/SpecFlow.Retry.Sample/SpecFlow.Retry.Sample.csproj
deleted file mode 100644
index 26e4c44..0000000
--- a/src/SpecFlow.Retry.Sample/SpecFlow.Retry.Sample.csproj
+++ /dev/null
@@ -1,108 +0,0 @@
-
-
-
- Debug
- AnyCPU
- {AD8D3C92-19C5-48A7-9D7A-0D0460509C67}
- Library
- Properties
- SpecFlow.Retry.Sample
- SpecFlow.Retry.Sample
- v4.5
- 512
- {3AC096D0-A1C2-E12C-1390-A8335801FDAB};{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}
- 10.0
- $(MSBuildExtensionsPath32)\Microsoft\VisualStudio\v$(VisualStudioVersion)
- $(ProgramFiles)\Common Files\microsoft shared\VSTT\$(VisualStudioVersion)\UITestExtensionPackages
- False
- UnitTest
-
-
- true
- full
- false
- bin\Debug\
- DEBUG;TRACE
- prompt
- 4
-
-
- pdbonly
- true
- bin\Release\
- TRACE
- prompt
- 4
-
-
-
-
- ..\SpecFlow.Retry\packages\SpecFlow.1.9.0\lib\net35\TechTalk.SpecFlow.dll
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- True
- True
- SampleFeature.feature
-
-
-
-
-
-
-
- SpecFlowSingleFileGenerator
- SampleFeature.feature.cs
-
-
-
-
-
- {09f75ced-6c8a-457b-ad23-9df3384fe5b3}
- SpecFlow.Retry
- False
-
-
-
-
-
-
- False
-
-
- False
-
-
- False
-
-
- False
-
-
-
-
-
-
-
-
\ No newline at end of file
diff --git a/src/SpecFlow.Retry.Sample/StepDefinitions.cs b/src/SpecFlow.Retry.Sample/StepDefinitions.cs
deleted file mode 100644
index 005d761..0000000
--- a/src/SpecFlow.Retry.Sample/StepDefinitions.cs
+++ /dev/null
@@ -1,107 +0,0 @@
-using System;
-using System.Collections.Generic;
-using System.Linq;
-using System.Reflection;
-using System.Text;
-using Microsoft.VisualStudio.TestTools.UnitTesting;
-using TechTalk.SpecFlow;
-using TechTalk.SpecFlow.Infrastructure;
-
-namespace SpecFlow.Retry.Sample
-{
- [Binding]
- public class StepDefinitions
- {
- private Random random;
- private double generatedNumber;
-
- [Given(@"I have random number generator")]
- public void GivenIHaveRandomNumberGenerator()
- {
- random = new Random();
- }
-
- [When(@"it generates number")]
- public void WhenItGeneratesNumber()
- {
- generatedNumber = random.NextDouble();
- }
-
- [Then(@"I'll be lucky if it will be greater then (.*)")]
- public void ThenILlBeLuckyIfItWillBeGreaterThen(double limit)
- {
- Assert.IsTrue(generatedNumber > limit, "generatedNumber({0}) > limit({1})", generatedNumber, limit);
- }
-
-
- [Given(@"by default scenario context stored value is (.*)")]
- public void GivenByDefaultScenarioContextStoredValueIs(int initialValue)
- {
- if (!ScenarioContext.Current.ContainsKey("SCSV"))
- {
- ScenarioContext.Current["SCSV"] = initialValue;
- }
- }
-
- [When(@"I increment scenario context stored value")]
- public void WhenIIncrementScenarioContextStoredValue()
- {
- ScenarioContext.Current["SCSV"] = ScenarioContext.Current.Get("SCSV")+1;
- }
-
- [Then(@"scenario context stored value should be (.*)")]
- public void ThenScenarioContextStoredValueShouldBe(int p0)
- {
- Assert.AreEqual(p0, ScenarioContext.Current.Get("SCSV"));
- }
-
- [Then(@"scenario should be run (\d*) times")]
- public void ThenScenarioShouldBeRunTimes(int expectedRunTimes)
- {
- int actualRunTimes;
- var key = ScenarioContext.Current.ScenarioInfo.Title + "__RunTimes";
- if (!FeatureContext.Current.TryGetValue(key, out actualRunTimes))
- {
- FeatureContext.Current[key] = actualRunTimes = 1;
- }
- else
- {
- FeatureContext.Current[key] = ++actualRunTimes;
- }
-
- Assert.AreEqual(expectedRunTimes, actualRunTimes);
- }
-
- [Then(@"scenario ""(.*)"" should be run (\d*) times")]
- public void ThenScenarioShouldBeRunTimes(string scenarioName, int expectedRunTimes)
- {
- int actualRunTimes;
- var key = ScenarioContext.Current.ScenarioInfo.Title + "__" + scenarioName + "__RunTimes";
- if (!FeatureContext.Current.TryGetValue(key, out actualRunTimes))
- {
- FeatureContext.Current[key] = actualRunTimes = 1;
- }
- else
- {
- FeatureContext.Current[key] = ++actualRunTimes;
- }
-
- Assert.AreEqual(expectedRunTimes, actualRunTimes);
- }
-
- [When(@"""(.*)"" thrown")]
- public void WhenSpecFlow_Retry_Sample_CriticalExceptionThrown(string exceptionType)
- {
- var type = Type.GetType(exceptionType);
-
- throw (Exception)Activator.CreateInstance(type);
- }
-
- [Then(@"nothing")]
- public void ThenNothing()
- {
- Assert.Fail("Exception wasn't excepted");
- }
-
- }
-}
diff --git a/src/SpecFlow.Retry.Sample/packages.config b/src/SpecFlow.Retry.Sample/packages.config
deleted file mode 100644
index c665805..0000000
--- a/src/SpecFlow.Retry.Sample/packages.config
+++ /dev/null
@@ -1,4 +0,0 @@
-
-
-
-
\ No newline at end of file
diff --git a/src/SpecFlow.Retry.sln b/src/SpecFlow.Retry.sln
deleted file mode 100644
index 792ae1b..0000000
--- a/src/SpecFlow.Retry.sln
+++ /dev/null
@@ -1,30 +0,0 @@
-
-Microsoft Visual Studio Solution File, Format Version 12.00
-# Visual Studio 2013
-VisualStudioVersion = 12.0.31101.0
-MinimumVisualStudioVersion = 10.0.40219.1
-Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "SpecFlow.Retry", "SpecFlow.Retry\SpecFlow.Retry.csproj", "{09F75CED-6C8A-457B-AD23-9DF3384FE5B3}"
-EndProject
-Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "SpecFlow.Retry.Sample", "SpecFlow.Retry.Sample\SpecFlow.Retry.Sample.csproj", "{AD8D3C92-19C5-48A7-9D7A-0D0460509C67}"
-EndProject
-Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Solution Items", "Solution Items", "{730526D2-88B3-477B-ABE2-18531CEB3B20}"
-EndProject
-Global
- GlobalSection(SolutionConfigurationPlatforms) = preSolution
- Debug|Any CPU = Debug|Any CPU
- Release|Any CPU = Release|Any CPU
- EndGlobalSection
- GlobalSection(ProjectConfigurationPlatforms) = postSolution
- {09F75CED-6C8A-457B-AD23-9DF3384FE5B3}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
- {09F75CED-6C8A-457B-AD23-9DF3384FE5B3}.Debug|Any CPU.Build.0 = Debug|Any CPU
- {09F75CED-6C8A-457B-AD23-9DF3384FE5B3}.Release|Any CPU.ActiveCfg = Release|Any CPU
- {09F75CED-6C8A-457B-AD23-9DF3384FE5B3}.Release|Any CPU.Build.0 = Release|Any CPU
- {AD8D3C92-19C5-48A7-9D7A-0D0460509C67}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
- {AD8D3C92-19C5-48A7-9D7A-0D0460509C67}.Debug|Any CPU.Build.0 = Debug|Any CPU
- {AD8D3C92-19C5-48A7-9D7A-0D0460509C67}.Release|Any CPU.ActiveCfg = Release|Any CPU
- {AD8D3C92-19C5-48A7-9D7A-0D0460509C67}.Release|Any CPU.Build.0 = Release|Any CPU
- EndGlobalSection
- GlobalSection(SolutionProperties) = preSolution
- HideSolutionNode = FALSE
- EndGlobalSection
-EndGlobal
diff --git a/src/SpecFlow.Retry/App.config b/src/SpecFlow.Retry/App.config
deleted file mode 100644
index 8f6a4f7..0000000
--- a/src/SpecFlow.Retry/App.config
+++ /dev/null
@@ -1,9 +0,0 @@
-
-
-
-
-
-
-
-
-
\ No newline at end of file
diff --git a/src/SpecFlow.Retry/Properties/AssemblyInfo.cs b/src/SpecFlow.Retry/Properties/AssemblyInfo.cs
deleted file mode 100644
index c8f9399..0000000
--- a/src/SpecFlow.Retry/Properties/AssemblyInfo.cs
+++ /dev/null
@@ -1,36 +0,0 @@
-using System.Reflection;
-using System.Runtime.CompilerServices;
-using System.Runtime.InteropServices;
-
-// General Information about an assembly is controlled through the following
-// set of attributes. Change these attribute values to modify the information
-// associated with an assembly.
-[assembly: AssemblyTitle("SpecFlow.Retry")]
-[assembly: AssemblyDescription("")]
-[assembly: AssemblyConfiguration("")]
-[assembly: AssemblyCompany("")]
-[assembly: AssemblyProduct("SpecFlow.Retry")]
-[assembly: AssemblyCopyright("Copyright © 2015")]
-[assembly: AssemblyTrademark("")]
-[assembly: AssemblyCulture("")]
-
-// Setting ComVisible to false makes the types in this assembly not visible
-// to COM components. If you need to access a type in this assembly from
-// COM, set the ComVisible attribute to true on that type.
-[assembly: ComVisible(false)]
-
-// The following GUID is for the ID of the typelib if this project is exposed to COM
-[assembly: Guid("7d1d0b7f-91e8-4729-89e2-a294077fe809")]
-
-// Version information for an assembly consists of the following four values:
-//
-// Major Version
-// Minor Version
-// Build Number
-// Revision
-//
-// You can specify all the values or you can default the Build and Revision Numbers
-// by using the '*' as shown below:
-// [assembly: AssemblyVersion("1.0.*")]
-[assembly: AssemblyVersion("0.1.0.0")]
-[assembly: AssemblyFileVersion("0.1.0.0")]
diff --git a/src/SpecFlow.Retry/RemoveRetryTagFromCategoriesDecarator.cs b/src/SpecFlow.Retry/RemoveRetryTagFromCategoriesDecarator.cs
deleted file mode 100644
index 1f96815..0000000
--- a/src/SpecFlow.Retry/RemoveRetryTagFromCategoriesDecarator.cs
+++ /dev/null
@@ -1,78 +0,0 @@
-using System;
-using System.CodeDom;
-using System.Collections.Generic;
-using System.Linq;
-using System.Text;
-using System.Threading.Tasks;
-using TechTalk.SpecFlow.Generator;
-using TechTalk.SpecFlow.Generator.UnitTestConverter;
-
-namespace SpecFlow.Retry
-{
- public class RemoveRetryTagFromCategoriesDecarator : ITestClassTagDecorator, ITestMethodTagDecorator
- {
- private readonly ITagFilterMatcher tagFilterMatcher;
-
- public RemoveRetryTagFromCategoriesDecarator(ITagFilterMatcher tagFilterMatcher)
- {
- this.tagFilterMatcher = tagFilterMatcher;
- }
-
- private bool CanDecorateFrom(string tagName)
- {
- var tagNames = new string[] {tagName};
- return tagFilterMatcher.MatchPrefix(TagsRepository.RETRY_TAG, tagNames)
- || tagFilterMatcher.MatchPrefix(TagsRepository.RETRY_EXCEPT_TAG, tagNames);
- }
-
- public bool CanDecorateFrom(string tagName, TestClassGenerationContext generationContext)
- {
- return CanDecorateFrom(tagName);
- }
-
- public void DecorateFrom(string tagName, TestClassGenerationContext generationContext)
- {
-
- }
-
- public bool CanDecorateFrom(string tagName, TestClassGenerationContext generationContext, CodeMemberMethod testMethod)
- {
- return CanDecorateFrom(tagName);
- }
-
- public void DecorateFrom(string tagName, TestClassGenerationContext generationContext, CodeMemberMethod testMethod)
- {
-
- }
-
- int ITestMethodTagDecorator.Priority
- {
- get { return PriorityValues.High; }
- }
-
- bool ITestMethodTagDecorator.RemoveProcessedTags
- {
- get { return true; }
- }
-
- bool ITestMethodTagDecorator.ApplyOtherDecoratorsForProcessedTags
- {
- get { return true; }
- }
-
- int ITestClassTagDecorator.Priority
- {
- get { return PriorityValues.High; }
- }
-
- bool ITestClassTagDecorator.RemoveProcessedTags
- {
- get { return true; }
- }
-
- bool ITestClassTagDecorator.ApplyOtherDecoratorsForProcessedTags
- {
- get { return true; }
- }
- }
-}
diff --git a/src/SpecFlow.Retry/RetryPlugin.cs b/src/SpecFlow.Retry/RetryPlugin.cs
deleted file mode 100644
index 9cf4975..0000000
--- a/src/SpecFlow.Retry/RetryPlugin.cs
+++ /dev/null
@@ -1,31 +0,0 @@
-using BoDi;
-using SpecFlow.Retry;
-using TechTalk.SpecFlow.Generator.Configuration;
-using TechTalk.SpecFlow.Generator.Plugins;
-using TechTalk.SpecFlow.Generator.UnitTestConverter;
-using TechTalk.SpecFlow.Infrastructure;
-
-[assembly: GeneratorPlugin(typeof(GeneratorPlugin))]
-namespace SpecFlow.Retry
-{
- public class GeneratorPlugin : IGeneratorPlugin
- {
- public void RegisterDependencies(ObjectContainer container)
- {
- container.RegisterTypeAs();
- container.RegisterTypeAs("retry");
- }
-
- public void RegisterCustomizations(ObjectContainer container, SpecFlowProjectConfiguration generatorConfiguration)
- {
- container.RegisterTypeAs("retry");
- container.RegisterTypeAs("retry");
- }
-
- public void RegisterConfigurationDefaults(SpecFlowProjectConfiguration specFlowConfiguration)
- {
-
- }
- }
-}
-
diff --git a/src/SpecFlow.Retry/SpecFlow.Retry.csproj b/src/SpecFlow.Retry/SpecFlow.Retry.csproj
deleted file mode 100644
index 4254e09..0000000
--- a/src/SpecFlow.Retry/SpecFlow.Retry.csproj
+++ /dev/null
@@ -1,78 +0,0 @@
-
-
-
-
- Debug
- AnyCPU
- {09F75CED-6C8A-457B-AD23-9DF3384FE5B3}
- Library
- Properties
- SpecFlow.Retry
- SpecFlow.Retry.Generator.SpecFlowPlugin
- v4.5
- 512
-
-
- true
- full
- false
- bin\Debug\
- DEBUG;TRACE
- prompt
- 4
-
-
- pdbonly
- true
- bin\Release\
- TRACE
- prompt
- 4
-
-
-
-
-
-
-
-
-
-
- packages\SpecFlow.1.9.0\lib\net35\TechTalk.SpecFlow.dll
-
-
- packages\SpecFlow.CustomPlugin.1.9.0\lib\net40\TechTalk.SpecFlow.Generator.dll
-
-
- packages\SpecFlow.CustomPlugin.1.9.0\lib\net40\TechTalk.SpecFlow.Parser.dll
-
-
- packages\SpecFlow.CustomPlugin.1.9.0\lib\net40\TechTalk.SpecFlow.Utils.dll
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
\ No newline at end of file
diff --git a/src/SpecFlow.Retry/TagsRepository.cs b/src/SpecFlow.Retry/TagsRepository.cs
deleted file mode 100644
index 06d9c6d..0000000
--- a/src/SpecFlow.Retry/TagsRepository.cs
+++ /dev/null
@@ -1,14 +0,0 @@
-using System;
-using System.Collections.Generic;
-using System.Linq;
-using System.Text;
-using System.Threading.Tasks;
-
-namespace SpecFlow.Retry
-{
- internal static class TagsRepository
- {
- public const string RETRY_TAG = "Retry";
- public const string RETRY_EXCEPT_TAG = "RetryExcept";
- }
-}
diff --git a/src/SpecFlow.Retry/UnitTestFeatureGenerator.cs b/src/SpecFlow.Retry/UnitTestFeatureGenerator.cs
deleted file mode 100644
index 20f4829..0000000
--- a/src/SpecFlow.Retry/UnitTestFeatureGenerator.cs
+++ /dev/null
@@ -1,900 +0,0 @@
-using System;
-using System.CodeDom;
-using System.Collections.Generic;
-using System.Globalization;
-using System.IO;
-using System.Linq;
-using System.Reflection;
-using System.Text;
-using System.Text.RegularExpressions;
-using System.Threading.Tasks;
-using TechTalk.SpecFlow;
-using TechTalk.SpecFlow.Generator;
-using TechTalk.SpecFlow.Generator.Configuration;
-using TechTalk.SpecFlow.Generator.UnitTestConverter;
-using TechTalk.SpecFlow.Generator.UnitTestProvider;
-using TechTalk.SpecFlow.Parser.SyntaxElements;
-using TechTalk.SpecFlow.Tracing;
-using TechTalk.SpecFlow.Utils;
-
-namespace SpecFlow.Retry
-{
- public class RetryUnitTestFeatureGenerator : IFeatureGenerator
- {
- private const string DEFAULT_NAMESPACE = "SpecFlowTests";
- const string TESTCLASS_NAME_FORMAT = "{0}Feature";
- const string TEST_NAME_FORMAT = "{0}";
- private const string IGNORE_TAG = "Ignore";
-
- private const string SCENARIO_INITIALIZE_NAME = "ScenarioSetup";
- private const string SCENARIO_CLEANUP_NAME = "ScenarioCleanup";
- private const string TEST_INITIALIZE_NAME = "TestInitialize";
- private const string TEST_CLEANUP_NAME = "ScenarioTearDown";
- private const string TESTCLASS_INITIALIZE_NAME = "FeatureSetup";
- private const string TESTCLASS_CLEANUP_NAME = "FeatureTearDown";
- private const string BACKGROUND_NAME = "FeatureBackground";
- private const string TESTRUNNER_FIELD = "testRunner";
- private const string SPECFLOW_NAMESPACE = "TechTalk.SpecFlow";
- private const string SCENARIO_OUTLINE_EXAMPLE_TAGS_PARAMETER = "exampleTags";
-
-
- private readonly IUnitTestGeneratorProvider testGeneratorProvider;
- private readonly CodeDomHelper codeDomHelper;
- private readonly GeneratorConfiguration generatorConfiguration;
- private readonly IDecoratorRegistry decoratorRegistry;
- private readonly ITagFilterMatcher tagFilterMatcher;
-
- public RetryUnitTestFeatureGenerator(IUnitTestGeneratorProvider testGeneratorProvider, CodeDomHelper codeDomHelper, GeneratorConfiguration generatorConfiguration, IDecoratorRegistry decoratorRegistry, ITagFilterMatcher tagFilterMatcher)
- {
- this.testGeneratorProvider = testGeneratorProvider;
- this.codeDomHelper = codeDomHelper;
- this.generatorConfiguration = generatorConfiguration;
- this.decoratorRegistry = decoratorRegistry;
- this.tagFilterMatcher = tagFilterMatcher;
- }
-
- private CodeMemberMethod CreateMethod(CodeTypeDeclaration type)
- {
- CodeMemberMethod method = new CodeMemberMethod();
- type.Members.Add(method);
- return method;
- }
-
- private static bool HasFeatureBackground(Feature feature)
- {
- return feature.Background != null;
- }
-
- private TestClassGenerationContext CreateTestClassStructure(CodeNamespace codeNamespace, string testClassName, Feature feature)
- {
- var testClass = codeDomHelper.CreateGeneratedTypeDeclaration(testClassName);
- codeNamespace.Types.Add(testClass);
-
- return new TestClassGenerationContext(
- testGeneratorProvider,
- feature,
- codeNamespace,
- testClass,
- CreateMethod(testClass),
- CreateMethod(testClass),
- CreateMethod(testClass),
- CreateMethod(testClass),
- CreateMethod(testClass),
- CreateMethod(testClass),
- HasFeatureBackground(feature) ? CreateMethod(testClass) : null,
- generateRowTests: testGeneratorProvider.SupportsRowTests && generatorConfiguration.AllowRowTests,
- generateAsynchTests: generatorConfiguration.GenerateAsyncTests && testGeneratorProvider.SupportsAsyncTests);
- }
-
- private CodeNamespace CreateNamespace(string targetNamespace)
- {
- targetNamespace = targetNamespace ?? DEFAULT_NAMESPACE;
-
- CodeNamespace codeNamespace = new CodeNamespace(targetNamespace);
-
- codeNamespace.Imports.Add(new CodeNamespaceImport(SPECFLOW_NAMESPACE));
- return codeNamespace;
- }
-
- public CodeNamespace GenerateUnitTestFixture(Feature feature, string testClassName, string targetNamespace)
- {
- CodeNamespace codeNamespace = CreateNamespace(targetNamespace);
-
- testClassName = testClassName ?? string.Format(TESTCLASS_NAME_FORMAT, feature.Title.ToIdentifier());
- var generationContext = CreateTestClassStructure(codeNamespace, testClassName, feature);
-
- SetupTestClass(generationContext);
- SetupTestClassInitializeMethod(generationContext);
- SetupTestClassCleanupMethod(generationContext);
-
- SetupScenarioInitializeMethod(generationContext);
- SetupFeatureBackground(generationContext);
- SetupScenarioCleanupMethod(generationContext);
-
- SetupTestInitializeMethod(generationContext);
- SetupTestCleanupMethod(generationContext);
-
-
- foreach (var scenario in feature.Scenarios)
- {
- if (string.IsNullOrEmpty(scenario.Title))
- throw new TestGeneratorException("The scenario must have a title specified.");
-
- var scenarioOutline = scenario as ScenarioOutline;
- if (scenarioOutline != null)
- GenerateScenarioOutlineTest(generationContext, scenarioOutline);
- else
- GenerateTest(generationContext, scenario);
- }
-
- //before return the generated code, call generate provider's method in case the provider want to customerize the generated code
- testGeneratorProvider.FinalizeTestClass(generationContext);
- return codeNamespace;
- }
-
- private void SetupScenarioCleanupMethod(TestClassGenerationContext generationContext)
- {
- CodeMemberMethod scenarioCleanupMethod = generationContext.ScenarioCleanupMethod;
-
- scenarioCleanupMethod.Attributes = MemberAttributes.Public;
- scenarioCleanupMethod.Name = SCENARIO_CLEANUP_NAME;
-
- // call collect errors
- var testRunnerField = GetTestRunnerExpression();
- //testRunner.CollectScenarioErrors();
- scenarioCleanupMethod.Statements.Add(
- new CodeMethodInvokeExpression(
- testRunnerField,
- "CollectScenarioErrors"));
- }
-
- private void SetupTestClass(TestClassGenerationContext generationContext)
- {
- generationContext.TestClass.IsPartial = true;
- generationContext.TestClass.TypeAttributes |= TypeAttributes.Public;
-
- AddLinePragmaInitial(generationContext.TestClass, generationContext.Feature.SourceFile);
-
- testGeneratorProvider.SetTestClass(generationContext, generationContext.Feature.Title, generationContext.Feature.Description);
-
- List featureCategories;
- decoratorRegistry.DecorateTestClass(generationContext, out featureCategories);
-
- if (featureCategories.Any())
- testGeneratorProvider.SetTestClassCategories(generationContext, featureCategories);
-
- DeclareTestRunnerMember(generationContext);
- }
-
- private void DeclareTestRunnerMember(TestClassGenerationContext generationContext)
- {
- CodeMemberField testRunnerField = new CodeMemberField(typeof(ITestRunner), TESTRUNNER_FIELD);
- testRunnerField.Attributes |= MemberAttributes.Static;
- generationContext.TestClass.Members.Add(testRunnerField);
- }
-
- private CodeExpression GetTestRunnerExpression()
- {
- return new CodeVariableReferenceExpression(TESTRUNNER_FIELD);
- }
-
- private IEnumerable GetNonIgnoreTags(IEnumerable tags)
- {
- if (tags == null)
- return new string[0];
- return tags.Where(t => !t.Name.Equals(IGNORE_TAG, StringComparison.InvariantCultureIgnoreCase)).Select(t => t.Name);
- }
-
- private bool HasIgnoreTag(IEnumerable tags)
- {
- if (tags == null)
- return false;
- return tags.Any(t => t.Name.Equals(IGNORE_TAG, StringComparison.InvariantCultureIgnoreCase));
- }
-
- private void SetupTestClassInitializeMethod(TestClassGenerationContext generationContext)
- {
- var testClassInitializeMethod = generationContext.TestClassInitializeMethod;
-
- testClassInitializeMethod.Attributes = MemberAttributes.Public;
- testClassInitializeMethod.Name = TESTCLASS_INITIALIZE_NAME;
-
- testGeneratorProvider.SetTestClassInitializeMethod(generationContext);
-
- //testRunner = TestRunnerManager.GetTestRunner();
- var testRunnerField = GetTestRunnerExpression();
- var methodName = generationContext.GenerateAsynchTests ? "GetAsyncTestRunner" : "GetTestRunner";
- testClassInitializeMethod.Statements.Add(
- new CodeAssignStatement(
- testRunnerField,
- new CodeMethodInvokeExpression(
- new CodeTypeReferenceExpression(typeof(TestRunnerManager)),
- methodName)));
-
- //FeatureInfo featureInfo = new FeatureInfo("xxxx");
- testClassInitializeMethod.Statements.Add(
- new CodeVariableDeclarationStatement(typeof(FeatureInfo), "featureInfo",
- new CodeObjectCreateExpression(typeof(FeatureInfo),
- new CodeObjectCreateExpression(typeof(CultureInfo),
- new CodePrimitiveExpression(generationContext.Feature.Language)),
- new CodePrimitiveExpression(generationContext.Feature.Title),
- new CodePrimitiveExpression(generationContext.Feature.Description),
- new CodeFieldReferenceExpression(
- new CodeTypeReferenceExpression("ProgrammingLanguage"),
- codeDomHelper.TargetLanguage.ToString()),
- GetStringArrayExpression(generationContext.Feature.Tags))));
-
- //testRunner.OnFeatureStart(featureInfo);
- testClassInitializeMethod.Statements.Add(
- new CodeMethodInvokeExpression(
- testRunnerField,
- "OnFeatureStart",
- new CodeVariableReferenceExpression("featureInfo")));
- }
-
- private CodeExpression GetStringArrayExpression(Tags tags)
- {
- if (tags == null || tags.Count == 0)
- return new CodeCastExpression(typeof(string[]), new CodePrimitiveExpression(null));
-
- return new CodeArrayCreateExpression(typeof(string[]), tags.Select(tag => new CodePrimitiveExpression(tag.Name)).Cast().ToArray());
- }
-
- private CodeExpression GetStringArrayExpression(IEnumerable items, ParameterSubstitution paramToIdentifier)
- {
- return new CodeArrayCreateExpression(typeof(string[]), items.Select(item => GetSubstitutedString(item, paramToIdentifier)).ToArray());
- }
-
- private void SetupTestClassCleanupMethod(TestClassGenerationContext generationContext)
- {
- CodeMemberMethod testClassCleanupMethod = generationContext.TestClassCleanupMethod;
-
- testClassCleanupMethod.Attributes = MemberAttributes.Public;
- testClassCleanupMethod.Name = TESTCLASS_CLEANUP_NAME;
-
- testGeneratorProvider.SetTestClassCleanupMethod(generationContext);
-
- var testRunnerField = GetTestRunnerExpression();
- // testRunner.OnFeatureEnd();
- testClassCleanupMethod.Statements.Add(
- new CodeMethodInvokeExpression(
- testRunnerField,
- "OnFeatureEnd"));
- // testRunner = null;
- testClassCleanupMethod.Statements.Add(
- new CodeAssignStatement(
- testRunnerField,
- new CodePrimitiveExpression(null)));
- }
-
- private void SetupTestInitializeMethod(TestClassGenerationContext generationContext)
- {
- CodeMemberMethod testInitializeMethod = generationContext.TestInitializeMethod;
-
- testInitializeMethod.Attributes = MemberAttributes.Public;
- testInitializeMethod.Name = TEST_INITIALIZE_NAME;
-
- testGeneratorProvider.SetTestInitializeMethod(generationContext);
- }
-
- private void SetupTestCleanupMethod(TestClassGenerationContext generationContext)
- {
- CodeMemberMethod testCleanupMethod = generationContext.TestCleanupMethod;
-
- testCleanupMethod.Attributes = MemberAttributes.Public;
- testCleanupMethod.Name = TEST_CLEANUP_NAME;
-
- testGeneratorProvider.SetTestCleanupMethod(generationContext);
-
- var testRunnerField = GetTestRunnerExpression();
- //testRunner.OnScenarioEnd();
- testCleanupMethod.Statements.Add(
- new CodeMethodInvokeExpression(
- testRunnerField,
- "OnScenarioEnd"));
- }
-
- private void SetupScenarioInitializeMethod(TestClassGenerationContext generationContext)
- {
- CodeMemberMethod scenarioInitializeMethod = generationContext.ScenarioInitializeMethod;
-
- scenarioInitializeMethod.Attributes = MemberAttributes.Public;
- scenarioInitializeMethod.Name = SCENARIO_INITIALIZE_NAME;
- scenarioInitializeMethod.Parameters.Add(
- new CodeParameterDeclarationExpression(typeof(ScenarioInfo), "scenarioInfo"));
-
- //testRunner.OnScenarioStart(scenarioInfo);
- var testRunnerField = GetTestRunnerExpression();
- scenarioInitializeMethod.Statements.Add(
- new CodeMethodInvokeExpression(
- testRunnerField,
- "OnScenarioStart",
- new CodeVariableReferenceExpression("scenarioInfo")));
- }
-
- private void SetupFeatureBackground(TestClassGenerationContext generationContext)
- {
- if (!HasFeatureBackground(generationContext.Feature))
- return;
-
- var background = generationContext.Feature.Background;
-
- CodeMemberMethod backgroundMethod = generationContext.FeatureBackgroundMethod;
-
- backgroundMethod.Attributes = MemberAttributes.Public;
- backgroundMethod.Name = BACKGROUND_NAME;
-
- AddLineDirective(backgroundMethod.Statements, background);
-
- foreach (var given in background.Steps)
- GenerateStep(backgroundMethod, given, null);
-
- AddLineDirectiveHidden(backgroundMethod.Statements);
- }
-
- private class ParameterSubstitution : List>
- {
- public void Add(string parameter, string identifier)
- {
- Add(new KeyValuePair(parameter.Trim(), identifier));
- }
-
- public bool TryGetIdentifier(string param, out string id)
- {
- param = param.Trim();
- foreach (var pair in this)
- {
- if (pair.Key.Equals(param))
- {
- id = pair.Value;
- return true;
- }
- }
- id = null;
- return false;
- }
- }
-
- private void GenerateScenarioOutlineTest(TestClassGenerationContext generationContext, ScenarioOutline scenarioOutline)
- {
- ValidateExampleSetConsistency(scenarioOutline);
-
- ParameterSubstitution paramToIdentifier = CreateParamToIdentifierMapping(scenarioOutline);
-
- var scenatioOutlineTestMethod = CreateScenatioOutlineTestMethod(generationContext, scenarioOutline, paramToIdentifier);
- var exampleTagsParam = new CodeVariableReferenceExpression(SCENARIO_OUTLINE_EXAMPLE_TAGS_PARAMETER);
-
- if (generationContext.GenerateRowTests)
- {
- GenerateScenarioOutlineExamplesAsRowTests(generationContext, scenarioOutline, scenatioOutlineTestMethod);
- }
- else
- {
- GenerateScenarioOutlineExamplesAsIndividualMethods(scenarioOutline, generationContext, scenatioOutlineTestMethod, paramToIdentifier);
- }
-
- int retryValue;
- if (GetTagValue(generationContext, scenarioOutline, TagsRepository.RETRY_TAG, Int32.TryParse, out retryValue))
- {
- string retryExceptExceptionName;
-
- GetTagValue(generationContext, scenarioOutline, TagsRepository.RETRY_EXCEPT_TAG, out retryExceptExceptionName);
-
- scenatioOutlineTestMethod = GenerateRetryStatementAndUnwrap(generationContext, scenatioOutlineTestMethod, retryValue, retryExceptExceptionName);
- }
-
- GenerateTestBody(generationContext, scenarioOutline, scenatioOutlineTestMethod, exampleTagsParam, paramToIdentifier);
- }
-
- private void GenerateScenarioOutlineExamplesAsIndividualMethods(ScenarioOutline scenarioOutline, TestClassGenerationContext generationContext, CodeMemberMethod scenatioOutlineTestMethod, ParameterSubstitution paramToIdentifier)
- {
- int exampleSetIndex = 0;
- foreach (var exampleSet in scenarioOutline.Examples.ExampleSets)
- {
- bool useFirstColumnAsName = CanUseFirstColumnAsName(exampleSet.Table);
- string exampleSetIdentifier = string.IsNullOrEmpty(exampleSet.Title)
- ? scenarioOutline.Examples.ExampleSets.Count(es => string.IsNullOrEmpty(es.Title)) > 1
- ? string.Format("ExampleSet {0}", exampleSetIndex).ToIdentifier()
- : null
- : exampleSet.Title.ToIdentifier();
-
- for (int rowIndex = 0; rowIndex < exampleSet.Table.Body.Length; rowIndex++)
- {
- var row = exampleSet.Table.Body[rowIndex];
-
- string variantName = useFirstColumnAsName ? row.Cells[0].Value : string.Format("Variant {0}", rowIndex);
- GenerateScenarioOutlineTestVariant(generationContext, scenarioOutline, scenatioOutlineTestMethod, paramToIdentifier, exampleSet.Title ?? "", exampleSetIdentifier, row, exampleSet.Tags, variantName);
- }
- exampleSetIndex++;
- }
- }
-
- private void GenerateScenarioOutlineExamplesAsRowTests(TestClassGenerationContext generationContext, ScenarioOutline scenarioOutline, CodeMemberMethod scenatioOutlineTestMethod)
- {
- SetupTestMethod(generationContext, scenatioOutlineTestMethod, scenarioOutline, null, rowTest: true);
-
- foreach (var exampleSet in scenarioOutline.Examples.ExampleSets)
- {
- foreach (var row in exampleSet.Table.Body)
- {
- var arguments = row.Cells.Select(c => c.Value);
- testGeneratorProvider.SetRow(generationContext, scenatioOutlineTestMethod, arguments, GetNonIgnoreTags(exampleSet.Tags), HasIgnoreTag(exampleSet.Tags));
- }
- }
- }
-
- private ParameterSubstitution CreateParamToIdentifierMapping(ScenarioOutline scenarioOutline)
- {
- ParameterSubstitution paramToIdentifier = new ParameterSubstitution();
- foreach (var param in scenarioOutline.Examples.ExampleSets[0].Table.Header.Cells)
- paramToIdentifier.Add(param.Value, param.Value.ToIdentifierCamelCase());
- return paramToIdentifier;
- }
-
- private void ValidateExampleSetConsistency(ScenarioOutline scenarioOutline)
- {
- if (scenarioOutline.Examples.ExampleSets.Length <= 1)
- return;
-
- var firstExampleSetHeader =
- scenarioOutline.Examples.ExampleSets[0].Table.Header.Cells.Select(c => c.Value).ToArray();
-
- //check params
- if (scenarioOutline.Examples.ExampleSets.Skip(1)
- .Select(exampleSet => exampleSet.Table.Header.Cells.Select(c => c.Value))
- .Any(paramNames => !paramNames.SequenceEqual(firstExampleSetHeader)))
- {
- throw new TestGeneratorException("The example sets must provide the same parameters.");
- }
- }
-
- private bool CanUseFirstColumnAsName(GherkinTable table)
- {
- if (table.Header.Cells.Length == 0)
- return false;
-
- return table.Body.Select(r => r.Cells[0].Value.ToIdentifier()).Distinct().Count() == table.Body.Length;
- }
-
- private CodeMemberMethod CreateScenatioOutlineTestMethod(TestClassGenerationContext generationContext, ScenarioOutline scenarioOutline, ParameterSubstitution paramToIdentifier)
- {
- CodeMemberMethod testMethod = CreateMethod(generationContext.TestClass);
-
- testMethod.Attributes = MemberAttributes.Public;
- testMethod.Name = string.Format(TEST_NAME_FORMAT, scenarioOutline.Title.ToIdentifier());
-
- foreach (var pair in paramToIdentifier)
- {
- testMethod.Parameters.Add(new CodeParameterDeclarationExpression(typeof(string), pair.Value));
- }
-
- testMethod.Parameters.Add(new CodeParameterDeclarationExpression(typeof(string[]), SCENARIO_OUTLINE_EXAMPLE_TAGS_PARAMETER));
- return testMethod;
- }
-
- private void GenerateScenarioOutlineTestVariant(TestClassGenerationContext generationContext, ScenarioOutline scenarioOutline, CodeMemberMethod scenatioOutlineTestMethod,
- IEnumerable> paramToIdentifier, string exampleSetTitle, string exampleSetIdentifier,
- GherkinTableRow row, Tags exampleSetTags, string variantName)
- {
- var variantNameIdentifier = variantName.ToIdentifier().TrimStart('_');
-
- CodeMemberMethod testMethod = CreateTestMethod(generationContext, scenarioOutline, exampleSetTags);
- testMethod.Name = string.IsNullOrEmpty(exampleSetIdentifier)
- ? string.Format("{0}_{1}", testMethod.Name, variantNameIdentifier)
- : string.Format("{0}_{1}_{2}", testMethod.Name, exampleSetIdentifier, variantNameIdentifier);
-
- //call test implementation with the params
- List argumentExpressions = row.Cells.Select(paramCell => new CodePrimitiveExpression(paramCell.Value)).Cast().ToList();
-
- argumentExpressions.Add(GetStringArrayExpression(exampleSetTags));
-
- testMethod.Statements.Add(
- new CodeMethodInvokeExpression(
- new CodeThisReferenceExpression(),
- scenatioOutlineTestMethod.Name,
- argumentExpressions.ToArray()));
-
- var arguments = paramToIdentifier.Select((p2i, paramIndex) => new KeyValuePair(p2i.Key, row.Cells[paramIndex].Value)).ToList();
- testGeneratorProvider.SetTestMethodAsRow(generationContext, testMethod, scenarioOutline.Title, exampleSetTitle, variantName, arguments);
- }
-
- private void GenerateTest(TestClassGenerationContext generationContext, Scenario scenario)
- {
- CodeMemberMethod testMethod = CreateTestMethod(generationContext, scenario, null);
-
- int retryValue;
- if (GetTagValue(generationContext, scenario, TagsRepository.RETRY_TAG, Int32.TryParse, out retryValue))
- {
- string retryExceptExceptionName;
-
- GetTagValue(generationContext, scenario, TagsRepository.RETRY_EXCEPT_TAG, out retryExceptExceptionName);
-
- testMethod = GenerateRetryStatementAndUnwrap(generationContext, testMethod, retryValue, retryExceptExceptionName);
- }
-
- GenerateTestBody(generationContext, scenario, testMethod);
- }
-
- private delegate bool TryParseDelegate(string value, out T parsedValue);
-
- private bool GetTagValue(TestClassGenerationContext generationContext, Scenario scenario, string retryTag, out string value)
- {
- return GetTagValue(generationContext, scenario, retryTag, delegate(string v, out string p) { p = v; return v != null; }, out value);
- }
-
- private bool GetTagValue(TestClassGenerationContext generationContext, Scenario scenario, string retryTag, TryParseDelegate parser, out T value)
- {
- value = default(T);
- var tagNames = scenario.Tags != null ? scenario.Tags.Select(_ => _.Name) : new string[0];
- string retryCountValue;
- return tagFilterMatcher.GetTagValue(retryTag, tagNames, out retryCountValue)
- && parser(retryCountValue, out value) ||
- tagFilterMatcher.GetTagValue(retryTag, generationContext.Feature, out retryCountValue)
- && parser(retryCountValue, out value);
- }
-
-
- private CodeMemberMethod GenerateRetryStatementAndUnwrap(TestClassGenerationContext generationContext, CodeMemberMethod testMethod, int retryCount, string retryExceptExceptionName)
- {
- var method = CreateMethod(generationContext.TestClass);
-
- method.Name = testMethod.Name + "Internal";
-
- foreach (CodeParameterDeclarationExpression parameter in testMethod.Parameters)
- {
- method.Parameters.Add(new CodeParameterDeclarationExpression(parameter.Type, parameter.Name));
- }
-
- testMethod.Statements.Add(new CodeVariableDeclarationStatement(typeof (Exception), "lastException", new CodePrimitiveExpression(null)));
-
- var codeCatchClauses = new List();
-
- if (!String.IsNullOrEmpty(retryExceptExceptionName))
- {
- codeCatchClauses.Add(new CodeCatchClause(
- "exc",
- new CodeTypeReference(new CodeTypeParameter(retryExceptExceptionName)),
- new CodeThrowExceptionStatement()
- ));
- }
-
- codeCatchClauses.Add(new CodeCatchClause(
- "exc",
- new CodeTypeReference(typeof(Exception)),
- /* lastException = exc; */
- new CodeAssignStatement(
- new CodeVariableReferenceExpression("lastException"),
- new CodeVariableReferenceExpression("exc"))));
-
- testMethod.Statements.Add(
- new CodeIterationStatement(
- /* for(var i = 0; i < retryCount; i++)*/
- initStatement:
- new CodeVariableDeclarationStatement(typeof (int), "i", new CodePrimitiveExpression(0)),
- testExpression: new CodeBinaryOperatorExpression(
- new CodeVariableReferenceExpression("i"),
- CodeBinaryOperatorType.LessThanOrEqual,
- new CodePrimitiveExpression(retryCount)
- ),
- incrementStatement: new CodeAssignStatement(
- new CodeVariableReferenceExpression("i"),
- new CodeBinaryOperatorExpression(
- new CodeVariableReferenceExpression("i"),
- CodeBinaryOperatorType.Add,
- new CodePrimitiveExpression(1))),
- statements: new CodeStatement[]
- {
- /* try */
- new CodeTryCatchFinallyStatement(
- tryStatements: new CodeStatement[]
- {
- /* { */
- /* this.TestInternal(); */
- new CodeExpressionStatement(new CodeMethodInvokeExpression(
- new CodeThisReferenceExpression(), method.Name,
- method.Parameters
- .Cast()
- .Select(_=>new CodeVariableReferenceExpression(_.Name))
- .Cast()
- .ToArray())),
- /* return; */
- new CodeMethodReturnStatement(),
- /* } */
- },
- catchClauses: codeCatchClauses.ToArray()
- ),
- new CodeConditionStatement(
- /* if ( (i+1) >= retryCount) */
- new CodeBinaryOperatorExpression(
- new CodeBinaryOperatorExpression(new CodeVariableReferenceExpression("i"), CodeBinaryOperatorType.Add, new CodePrimitiveExpression(1)),
- CodeBinaryOperatorType.LessThanOrEqual,
- new CodePrimitiveExpression(retryCount)
- ),
- /* { */
- /* testRunner.OnScenarioEnd();*/
- new CodeExpressionStatement(
- new CodeMethodInvokeExpression(
- GetTestRunnerExpression(),
- "OnScenarioEnd"
- )))
- /* } */
- })
- );
- testMethod.Statements.Add(new CodeConditionStatement(
- condition: new CodeBinaryOperatorExpression(
- new CodeVariableReferenceExpression("lastException"),
- CodeBinaryOperatorType.IdentityInequality,
- new CodePrimitiveExpression(null)),
- trueStatements: new CodeThrowExceptionStatement(new CodeVariableReferenceExpression("lastException"))));
-
- return method;
- }
-
- private void GenerateTestBody(TestClassGenerationContext generationContext, Scenario scenario, CodeMemberMethod testMethod, CodeExpression additionalTagsExpression = null, ParameterSubstitution paramToIdentifier = null)
- {
- //call test setup
- //ScenarioInfo scenarioInfo = new ScenarioInfo("xxxx", tags...);
- CodeExpression tagsExpression;
- if (additionalTagsExpression == null)
- tagsExpression = GetStringArrayExpression(scenario.Tags);
- else if (scenario.Tags == null)
- tagsExpression = additionalTagsExpression;
- else
- {
- // merge tags list
- // var tags = tags1
- // if (tags2 != null)
- // tags = Enumerable.ToArray(Enumerable.Concat(tags1, tags1));
- testMethod.Statements.Add(
- new CodeVariableDeclarationStatement(typeof(string[]), "__tags", GetStringArrayExpression(scenario.Tags)));
- tagsExpression = new CodeVariableReferenceExpression("__tags");
- testMethod.Statements.Add(
- new CodeConditionStatement(
- new CodeBinaryOperatorExpression(
- additionalTagsExpression,
- CodeBinaryOperatorType.IdentityInequality,
- new CodePrimitiveExpression(null)),
- new CodeAssignStatement(
- tagsExpression,
- new CodeMethodInvokeExpression(
- new CodeTypeReferenceExpression(typeof(Enumerable)),
- "ToArray",
- new CodeMethodInvokeExpression(
- new CodeTypeReferenceExpression(typeof(Enumerable)),
- "Concat",
- tagsExpression,
- additionalTagsExpression)))));
- }
- testMethod.Statements.Add(
- new CodeVariableDeclarationStatement(typeof(ScenarioInfo), "scenarioInfo",
- new CodeObjectCreateExpression(typeof(ScenarioInfo),
- new CodePrimitiveExpression(scenario.Title),
- tagsExpression)));
-
- AddLineDirective(testMethod.Statements, scenario);
- testMethod.Statements.Add(
- new CodeMethodInvokeExpression(
- new CodeThisReferenceExpression(),
- generationContext.ScenarioInitializeMethod.Name,
- new CodeVariableReferenceExpression("scenarioInfo")));
-
- if (HasFeatureBackground(generationContext.Feature))
- {
- AddLineDirective(testMethod.Statements, generationContext.Feature.Background);
- testMethod.Statements.Add(
- new CodeMethodInvokeExpression(
- new CodeThisReferenceExpression(),
- generationContext.FeatureBackgroundMethod.Name));
- }
-
- foreach (var scenarioStep in scenario.Steps)
- {
- GenerateStep(testMethod, scenarioStep, paramToIdentifier);
- }
-
- AddLineDirectiveHidden(testMethod.Statements);
-
- // call scenario cleanup
- testMethod.Statements.Add(
- new CodeMethodInvokeExpression(
- new CodeThisReferenceExpression(),
- generationContext.ScenarioCleanupMethod.Name));
- }
-
- private CodeMemberMethod CreateTestMethod(TestClassGenerationContext generationContext, Scenario scenario, Tags additionalTags)
- {
- CodeMemberMethod testMethod = CreateMethod(generationContext.TestClass);
-
- SetupTestMethod(generationContext, testMethod, scenario, additionalTags);
-
- return testMethod;
- }
-
- private void SetupTestMethod(TestClassGenerationContext generationContext, CodeMemberMethod testMethod, Scenario scenario, Tags additionalTags, bool rowTest = false)
- {
- testMethod.Attributes = MemberAttributes.Public;
- testMethod.Name = string.Format(TEST_NAME_FORMAT, scenario.Title.ToIdentifier());
-
- if (rowTest)
- testGeneratorProvider.SetRowTest(generationContext, testMethod, scenario.Title);
- else
- testGeneratorProvider.SetTestMethod(generationContext, testMethod, scenario.Title);
-
- List scenarioCategories;
- decoratorRegistry.DecorateTestMethod(generationContext, testMethod, ConcatTags(scenario.Tags, additionalTags), out scenarioCategories);
-
- if (scenarioCategories.Any())
- testGeneratorProvider.SetTestMethodCategories(generationContext, testMethod, scenarioCategories);
- }
-
- private IEnumerable ConcatTags(params Tags[] tagLists)
- {
- return tagLists.Where(tagList => tagList != null).SelectMany(tagList => tagList);
- }
-
- private CodeExpression GetSubstitutedString(string text, ParameterSubstitution paramToIdentifier)
- {
- if (text == null)
- return new CodeCastExpression(typeof(string), new CodePrimitiveExpression(null));
- if (paramToIdentifier == null)
- return new CodePrimitiveExpression(text);
-
- Regex paramRe = new Regex(@"\<(?[^\>]+)\>");
- string formatText = text.Replace("{", "{{").Replace("}", "}}");
- List arguments = new List();
-
- formatText = paramRe.Replace(formatText, match =>
- {
- string param = match.Groups["param"].Value;
- string id;
- if (!paramToIdentifier.TryGetIdentifier(param, out id))
- return match.Value;
- int argIndex = arguments.IndexOf(id);
- if (argIndex < 0)
- {
- argIndex = arguments.Count;
- arguments.Add(id);
- }
- return "{" + argIndex + "}";
- });
-
- if (arguments.Count == 0)
- return new CodePrimitiveExpression(text);
-
- List formatArguments = new List();
- formatArguments.Add(new CodePrimitiveExpression(formatText));
- formatArguments.AddRange(arguments.Select(id => new CodeVariableReferenceExpression(id)).Cast());
-
- return new CodeMethodInvokeExpression(
- new CodeTypeReferenceExpression(typeof(string)),
- "Format",
- formatArguments.ToArray());
- }
-
- private void GenerateStep(CodeMemberMethod testMethod, ScenarioStep scenarioStep, ParameterSubstitution paramToIdentifier)
- {
- var testRunnerField = GetTestRunnerExpression();
-
- //testRunner.Given("something");
- List arguments = new List();
- arguments.Add(
- GetSubstitutedString(scenarioStep.Text, paramToIdentifier));
- if (scenarioStep.MultiLineTextArgument != null || scenarioStep.TableArg != null)
- AddLineDirectiveHidden(testMethod.Statements);
- arguments.Add(
- GetMultilineTextArgExpression(scenarioStep.MultiLineTextArgument, paramToIdentifier));
- arguments.Add(
- GetTableArgExpression(scenarioStep.TableArg, testMethod.Statements, paramToIdentifier));
- arguments.Add(new CodePrimitiveExpression(scenarioStep.Keyword));
-
- AddLineDirective(testMethod.Statements, scenarioStep);
- testMethod.Statements.Add(
- new CodeMethodInvokeExpression(
- testRunnerField,
- scenarioStep.GetType().Name,
- arguments.ToArray()));
- }
-
- private int tableCounter = 0;
- private CodeExpression GetTableArgExpression(GherkinTable tableArg, CodeStatementCollection statements, ParameterSubstitution paramToIdentifier)
- {
- if (tableArg == null)
- return new CodeCastExpression(typeof(Table), new CodePrimitiveExpression(null));
-
- tableCounter++;
-
- //Table table0 = new Table(header...);
- var tableVar = new CodeVariableReferenceExpression("table" + tableCounter);
- statements.Add(
- new CodeVariableDeclarationStatement(typeof(Table), tableVar.VariableName,
- new CodeObjectCreateExpression(
- typeof(Table),
- GetStringArrayExpression(tableArg.Header.Cells.Select(c => c.Value), paramToIdentifier))));
-
- foreach (var row in tableArg.Body)
- {
- //table0.AddRow(cells...);
- statements.Add(
- new CodeMethodInvokeExpression(
- tableVar,
- "AddRow",
- GetStringArrayExpression(row.Cells.Select(c => c.Value), paramToIdentifier)));
- }
- return tableVar;
- }
-
- private CodeExpression GetMultilineTextArgExpression(string multiLineTextArgument, ParameterSubstitution paramToIdentifier)
- {
- return GetSubstitutedString(multiLineTextArgument, paramToIdentifier);
- }
-
- #region Line pragma handling
-
- private void AddLinePragmaInitial(CodeTypeDeclaration testType, string sourceFile)
- {
- if (generatorConfiguration.AllowDebugGeneratedFiles)
- return;
-
- codeDomHelper.BindTypeToSourceFile(testType, Path.GetFileName(sourceFile));
- }
-
- private void AddLineDirectiveHidden(CodeStatementCollection statements)
- {
- if (generatorConfiguration.AllowDebugGeneratedFiles)
- return;
-
- codeDomHelper.AddDisableSourceLinePragmaStatement(statements);
- }
-
- private void AddLineDirective(CodeStatementCollection statements, Background background)
- {
- AddLineDirective(statements, background.FilePosition);
- }
-
- private void AddLineDirective(CodeStatementCollection statements, Scenario scenario)
- {
- AddLineDirective(statements, scenario.FilePosition);
- }
-
- private void AddLineDirective(CodeStatementCollection statements, ScenarioStep step)
- {
- AddLineDirective(statements, step.FilePosition);
- }
-
- private void AddLineDirective(CodeStatementCollection statements, FilePosition filePosition)
- {
- if (filePosition == null || generatorConfiguration.AllowDebugGeneratedFiles)
- return;
-
- codeDomHelper.AddSourceLinePragmaStatement(statements, filePosition.Line, filePosition.Column);
- }
-
- #endregion
- }
-
-
- public class RetryUnitTestFeatureGeneratorProvider : IFeatureGeneratorProvider
- {
- private readonly RetryUnitTestFeatureGenerator unitTestFeatureGenerator;
-
- public RetryUnitTestFeatureGeneratorProvider(RetryUnitTestFeatureGenerator unitTestFeatureGenerator)
- {
- this.unitTestFeatureGenerator = unitTestFeatureGenerator;
- }
-
- public int Priority
- {
- get { return PriorityValues.Normal; }
- }
-
- public bool CanGenerate(Feature feature)
- {
- return true;
- }
-
- public IFeatureGenerator CreateGenerator(Feature feature)
- {
- return unitTestFeatureGenerator;
- }
- }
-}
diff --git a/src/SpecFlow.Retry/packages.config b/src/SpecFlow.Retry/packages.config
deleted file mode 100644
index c8e8c76..0000000
--- a/src/SpecFlow.Retry/packages.config
+++ /dev/null
@@ -1,5 +0,0 @@
-
-
-
-
-
\ No newline at end of file
diff --git a/src/SpecFlow.RetryCore.sln b/src/SpecFlow.RetryCore.sln
new file mode 100644
index 0000000..d2497b3
--- /dev/null
+++ b/src/SpecFlow.RetryCore.sln
@@ -0,0 +1,42 @@
+
+Microsoft Visual Studio Solution File, Format Version 12.00
+# Visual Studio Version 16
+VisualStudioVersion = 16.0.31025.194
+MinimumVisualStudioVersion = 10.0.40219.1
+Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "SpecFlow.RetryCore", "SpecFlow.RetryCore\SpecFlow.RetryCore.csproj", "{408B99E8-4158-4552-A89D-C9D38C92CD51}"
+EndProject
+Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Solution Items", "Solution Items", "{4C5AAF7B-F055-43CA-81D9-EDB735390D30}"
+ ProjectSection(SolutionItems) = preProject
+ ..\.dockerignore = ..\.dockerignore
+ ..\.editorconfig = ..\.editorconfig
+ ..\.gitignore = ..\.gitignore
+ ..\.travis.yml = ..\.travis.yml
+ ..\appveyor.yml = ..\appveyor.yml
+ ..\CONTRIBUTING.md = ..\CONTRIBUTING.md
+ ..\Directory.Build.props = ..\Directory.Build.props
+ ..\LICENSE = ..\LICENSE
+ ..\LICENSE.md = ..\LICENSE.md
+ ..\MAINTAINERS.md = ..\MAINTAINERS.md
+ ..\NOTICES_3RD_PARTY.md = ..\NOTICES_3RD_PARTY.md
+ ..\nuget.config = ..\nuget.config
+ ..\README.md = ..\README.md
+ EndProjectSection
+EndProject
+Global
+ GlobalSection(SolutionConfigurationPlatforms) = preSolution
+ Debug|Any CPU = Debug|Any CPU
+ Release|Any CPU = Release|Any CPU
+ EndGlobalSection
+ GlobalSection(ProjectConfigurationPlatforms) = postSolution
+ {408B99E8-4158-4552-A89D-C9D38C92CD51}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+ {408B99E8-4158-4552-A89D-C9D38C92CD51}.Debug|Any CPU.Build.0 = Debug|Any CPU
+ {408B99E8-4158-4552-A89D-C9D38C92CD51}.Release|Any CPU.ActiveCfg = Release|Any CPU
+ {408B99E8-4158-4552-A89D-C9D38C92CD51}.Release|Any CPU.Build.0 = Release|Any CPU
+ EndGlobalSection
+ GlobalSection(SolutionProperties) = preSolution
+ HideSolutionNode = FALSE
+ EndGlobalSection
+ GlobalSection(ExtensibilityGlobals) = postSolution
+ SolutionGuid = {3C4F4A4A-503E-40F2-9918-DDE9D1D1C7AC}
+ EndGlobalSection
+EndGlobal
diff --git a/src/SpecFlow.RetryCore/RemoveRetryTagFromCategoriesDecorator.cs b/src/SpecFlow.RetryCore/RemoveRetryTagFromCategoriesDecorator.cs
new file mode 100644
index 0000000..6e3d5c0
--- /dev/null
+++ b/src/SpecFlow.RetryCore/RemoveRetryTagFromCategoriesDecorator.cs
@@ -0,0 +1,55 @@
+namespace SpecFlow.RetryCore
+{
+ using System.CodeDom;
+ using TechTalk.SpecFlow.Generator;
+ using TechTalk.SpecFlow.Generator.UnitTestConverter;
+
+ public class RemoveRetryTagFromCategoriesDecorator : ITestClassTagDecorator, ITestMethodTagDecorator
+ {
+ private readonly ITagFilterMatcher _tagFilterMatcher;
+
+ public RemoveRetryTagFromCategoriesDecorator(ITagFilterMatcher tagFilterMatcher)
+ {
+ this._tagFilterMatcher = tagFilterMatcher;
+ }
+
+ private bool CanDecorateFrom(string tagName)
+ {
+ var tagNames = new[] { tagName };
+ return this._tagFilterMatcher.MatchPrefix(TagsRepository.RetryTag, tagNames) ||
+ this._tagFilterMatcher.MatchPrefix(TagsRepository.RetryExceptTag, tagNames);
+ }
+
+ public bool CanDecorateFrom(string tagName, TestClassGenerationContext generationContext)
+ {
+ return this.CanDecorateFrom(tagName);
+ }
+
+ public bool CanDecorateFrom(string tagName, TestClassGenerationContext generationContext, CodeMemberMethod testMethod)
+ {
+ return this.CanDecorateFrom(tagName);
+ }
+
+ public void DecorateFrom(string tagName, TestClassGenerationContext generationContext)
+ {
+ // Method intentionally left empty.
+ }
+
+ public void DecorateFrom(string tagName, TestClassGenerationContext generationContext, CodeMemberMethod testMethod)
+ {
+ // Method intentionally left empty.
+ }
+
+ int ITestMethodTagDecorator.Priority => PriorityValues.High;
+
+ bool ITestMethodTagDecorator.RemoveProcessedTags => true;
+
+ bool ITestMethodTagDecorator.ApplyOtherDecoratorsForProcessedTags => true;
+
+ int ITestClassTagDecorator.Priority => PriorityValues.High;
+
+ bool ITestClassTagDecorator.RemoveProcessedTags => true;
+
+ bool ITestClassTagDecorator.ApplyOtherDecoratorsForProcessedTags => true;
+ }
+}
diff --git a/src/SpecFlow.RetryCore/RetryCore.nuspec b/src/SpecFlow.RetryCore/RetryCore.nuspec
new file mode 100644
index 0000000..411dccf
--- /dev/null
+++ b/src/SpecFlow.RetryCore/RetryCore.nuspec
@@ -0,0 +1,23 @@
+
+
+ SpecFlow.RetryCore
+ 1.0.0
+ SpecFlow.RetryCore
+ Julio C. Tejero
+ Calrom Ltd.
+ Retry for SpecFlow
+
+ en-UK
+ false
+ specflow
+
+
+
+
+
+
+ l
+
+
+
+
\ No newline at end of file
diff --git a/src/SpecFlow.RetryCore/RetryPlugin.cs b/src/SpecFlow.RetryCore/RetryPlugin.cs
new file mode 100644
index 0000000..efa5470
--- /dev/null
+++ b/src/SpecFlow.RetryCore/RetryPlugin.cs
@@ -0,0 +1,25 @@
+using SpecFlow.RetryCore;
+using TechTalk.SpecFlow.Generator.Plugins;
+using TechTalk.SpecFlow.Generator.UnitTestConverter;
+using TechTalk.SpecFlow.Infrastructure;
+using TechTalk.SpecFlow.UnitTestProvider;
+
+[assembly: GeneratorPlugin(typeof(GeneratorPlugin))]
+namespace SpecFlow.RetryCore
+{
+ public class GeneratorPlugin : IGeneratorPlugin
+ {
+ public void Initialize(GeneratorPluginEvents generatorPluginEvents, GeneratorPluginParameters generatorPluginParameters,
+ UnitTestProviderConfiguration unitTestProviderConfiguration)
+ {
+ generatorPluginEvents.RegisterDependencies += (sender, args) =>
+ {
+ args.ObjectContainer.RegisterTypeAs();
+ args.ObjectContainer.RegisterTypeAs("retry");
+ args.ObjectContainer.RegisterTypeAs("retry");
+ args.ObjectContainer.RegisterTypeAs("retry");
+ };
+ }
+ }
+}
+
diff --git a/src/SpecFlow.RetryCore/RetryUnitTestFeatureGenerator.cs b/src/SpecFlow.RetryCore/RetryUnitTestFeatureGenerator.cs
new file mode 100644
index 0000000..66bcd14
--- /dev/null
+++ b/src/SpecFlow.RetryCore/RetryUnitTestFeatureGenerator.cs
@@ -0,0 +1,843 @@
+namespace SpecFlow.RetryCore
+{
+ using System;
+ using System.CodeDom;
+ using System.Collections.Generic;
+ using System.Globalization;
+ using System.IO;
+ using System.Linq;
+ using System.Reflection;
+ using System.Text.RegularExpressions;
+ using Gherkin.Ast;
+ using TechTalk.SpecFlow;
+ using TechTalk.SpecFlow.Configuration;
+ using TechTalk.SpecFlow.Generator;
+ using TechTalk.SpecFlow.Generator.CodeDom;
+ using TechTalk.SpecFlow.Generator.UnitTestConverter;
+ using TechTalk.SpecFlow.Generator.UnitTestProvider;
+ using TechTalk.SpecFlow.Parser;
+ using TechTalk.SpecFlow.Tracing;
+
+ public class RetryUnitTestFeatureGenerator : IFeatureGenerator
+ {
+ private const string DEFAULT_NAMESPACE = "SpecFlowTests";
+ private const string TESTCLASS_NAME_FORMAT = "{0}Feature";
+ private const string TEST_NAME_FORMAT = "{0}";
+ private const string IGNORE_TAG = "@Ignore";
+ private const string SCENARIO_INITIALIZE_NAME = "ScenarioSetup";
+ private const string SCENARIO_CLEANUP_NAME = "ScenarioCleanup";
+ private const string TEST_INITIALIZE_NAME = "TestInitialize";
+ private const string TEST_CLEANUP_NAME = "ScenarioTearDown";
+ private const string TESTCLASS_INITIALIZE_NAME = "FeatureSetup";
+ private const string TESTCLASS_CLEANUP_NAME = "FeatureTearDown";
+ private const string BACKGROUND_NAME = "FeatureBackground";
+ private const string TESTRUNNER_FIELD = "testRunner";
+ private const string SPECFLOW_NAMESPACE = "TechTalk.SpecFlow";
+
+ private readonly IUnitTestGeneratorProvider _testGeneratorProvider;
+ private readonly SpecFlowConfiguration _specFlowConfiguration;
+ private readonly CodeDomHelper _codeDomHelper;
+ private readonly IDecoratorRegistry _decoratorRegistry;
+ private readonly ITagFilterMatcher _tagFilterMatcher;
+
+ public RetryUnitTestFeatureGenerator(IUnitTestGeneratorProvider testGeneratorProvider,
+ CodeDomHelper codeDomHelper, SpecFlowConfiguration specFlowConfiguration,
+ IDecoratorRegistry decoratorRegistry, ITagFilterMatcher tagFilterMatcher)
+ {
+ this._testGeneratorProvider = testGeneratorProvider;
+ this._specFlowConfiguration = specFlowConfiguration;
+ this._codeDomHelper = codeDomHelper;
+ this._decoratorRegistry = decoratorRegistry;
+ this._tagFilterMatcher = tagFilterMatcher;
+ }
+
+ private CodeMemberMethod CreateMethod(CodeTypeDeclaration type)
+ {
+ CodeMemberMethod method = new CodeMemberMethod();
+ type.Members.Add(method);
+ return method;
+ }
+
+ private static bool HasFeatureBackground(SpecFlowFeature feature)
+ {
+ return feature.Background != null;
+ }
+
+ private TestClassGenerationContext CreateTestClassStructure(CodeNamespace codeNamespace, string testClassName,
+ SpecFlowDocument document)
+ {
+ var testClass = this._codeDomHelper.CreateGeneratedTypeDeclaration(testClassName);
+ codeNamespace.Types.Add(testClass);
+
+ return new TestClassGenerationContext(
+ this._testGeneratorProvider,
+ document,
+ codeNamespace,
+ testClass,
+ this.DeclareTestRunnerMember(testClass),
+ this.CreateMethod(testClass),
+ this.CreateMethod(testClass),
+ this.CreateMethod(testClass),
+ this.CreateMethod(testClass),
+ this.CreateMethod(testClass),
+ this.CreateMethod(testClass),
+ this.CreateMethod(testClass),
+ HasFeatureBackground(document.SpecFlowFeature) ? this.CreateMethod(testClass) : null,
+ generateRowTests: this._testGeneratorProvider.GetTraits().HasFlag(UnitTestGeneratorTraits.RowTests) &&
+ this._specFlowConfiguration.AllowRowTests);
+ }
+
+ private CodeNamespace CreateNamespace(string targetNamespace)
+ {
+ targetNamespace = targetNamespace ?? DEFAULT_NAMESPACE;
+
+ CodeNamespace codeNamespace = new CodeNamespace(targetNamespace);
+
+ codeNamespace.Imports.Add(new CodeNamespaceImport(SPECFLOW_NAMESPACE));
+ return codeNamespace;
+ }
+
+ public CodeNamespace GenerateUnitTestFixture(SpecFlowDocument document, string testClassName,
+ string targetNamespace)
+ {
+ CodeNamespace codeNamespace = this.CreateNamespace(targetNamespace);
+ var feature = document.SpecFlowFeature;
+
+ testClassName = testClassName ?? string.Format(TESTCLASS_NAME_FORMAT, feature.Name.ToIdentifier());
+ var generationContext = this.CreateTestClassStructure(codeNamespace, testClassName, document);
+
+ this.SetupTestClass(generationContext);
+ this.SetupTestClassInitializeMethod(generationContext);
+ this.SetupTestClassCleanupMethod(generationContext);
+
+ this.SetupScenarioInitializeMethod(generationContext);
+ this.SetupFeatureBackground(generationContext);
+ this.SetupScenarioCleanupMethod(generationContext);
+
+ this.SetupTestInitializeMethod(generationContext);
+ this.SetupTestCleanupMethod(generationContext);
+
+ foreach (var scenarioDefinition in feature.ScenarioDefinitions)
+ {
+ if (string.IsNullOrEmpty(scenarioDefinition.Name))
+ {
+ throw new TestGeneratorException("The scenario must have a title specified.");
+ }
+
+ var scenarioOutline = scenarioDefinition as ScenarioOutline;
+
+ this.GenerateTest(generationContext, (Scenario)scenarioDefinition);
+ }
+
+ //before return the generated code, call generate provider's method in case the provider want to customerize the generated code
+ this._testGeneratorProvider.FinalizeTestClass(generationContext);
+ return codeNamespace;
+ }
+
+ private void SetupScenarioCleanupMethod(TestClassGenerationContext generationContext)
+ {
+ CodeMemberMethod scenarioCleanupMethod = generationContext.ScenarioCleanupMethod;
+
+ scenarioCleanupMethod.Attributes = MemberAttributes.Public;
+ scenarioCleanupMethod.Name = SCENARIO_CLEANUP_NAME;
+
+ // call collect errors
+ var testRunnerField = this.GetTestRunnerExpression();
+ //testRunner.CollectScenarioErrors();
+ scenarioCleanupMethod.Statements.Add(
+ new CodeMethodInvokeExpression(
+ testRunnerField,
+ "CollectScenarioErrors"));
+ }
+
+ private void SetupTestClass(TestClassGenerationContext generationContext)
+ {
+ generationContext.TestClass.IsPartial = true;
+ generationContext.TestClass.TypeAttributes |= TypeAttributes.Public;
+
+ this.AddLinePragmaInitial(generationContext.TestClass, generationContext.Document.SourceFilePath);
+
+ this._testGeneratorProvider.SetTestClass(generationContext, generationContext.Feature.Name,
+ generationContext.Feature.Description);
+
+ List featureCategories;
+ this._decoratorRegistry.DecorateTestClass(generationContext, out featureCategories);
+
+ if (featureCategories.Any())
+ {
+ this._testGeneratorProvider.SetTestClassCategories(generationContext, featureCategories);
+ }
+ }
+
+ private CodeMemberField DeclareTestRunnerMember(CodeTypeDeclaration type)
+ {
+ CodeMemberField testRunnerField = new CodeMemberField(typeof(ITestRunner), TESTRUNNER_FIELD);
+ type.Members.Add(testRunnerField);
+ return testRunnerField;
+ }
+
+ private CodeExpression GetTestRunnerExpression()
+ {
+ return new CodeVariableReferenceExpression(TESTRUNNER_FIELD);
+ }
+
+ private IEnumerable GetNonIgnoreTags(IEnumerable tags)
+ {
+ return tags.Where(t => !t.Name.Equals(IGNORE_TAG, StringComparison.InvariantCultureIgnoreCase))
+ .Select(t => t.GetNameWithoutAt());
+ }
+
+ private bool HasIgnoreTag(IEnumerable tags)
+ {
+ return tags.Any(t => t.Name.Equals(IGNORE_TAG, StringComparison.InvariantCultureIgnoreCase));
+ }
+
+ private void SetupTestClassInitializeMethod(TestClassGenerationContext generationContext)
+ {
+ var testClassInitializeMethod = generationContext.TestClassInitializeMethod;
+
+ testClassInitializeMethod.Attributes = MemberAttributes.Public;
+ testClassInitializeMethod.Name = TESTCLASS_INITIALIZE_NAME;
+
+ this._testGeneratorProvider.SetTestClassInitializeMethod(generationContext);
+
+ //testRunner = TestRunnerManager.GetTestRunner(); if UnitTestGeneratorTraits.ParallelExecution
+ //testRunner = TestRunnerManager.GetTestRunner(null, 0); if not UnitTestGeneratorTraits.ParallelExecution
+ var testRunnerField = this.GetTestRunnerExpression();
+
+ var testRunnerParameters =
+ this._testGeneratorProvider.GetTraits().HasFlag(UnitTestGeneratorTraits.ParallelExecution)
+ ? new CodeExpression[] { }
+ : new[] { new CodePrimitiveExpression(null), new CodePrimitiveExpression(0) };
+
+ testClassInitializeMethod.Statements.Add(
+ new CodeAssignStatement(
+ testRunnerField,
+ new CodeMethodInvokeExpression(
+ new CodeTypeReferenceExpression(typeof(TestRunnerManager)),
+ "GetTestRunner", testRunnerParameters)));
+
+ //FeatureInfo featureInfo = new FeatureInfo("xxxx");
+ testClassInitializeMethod.Statements.Add(
+ new CodeVariableDeclarationStatement(typeof(FeatureInfo), "featureInfo",
+ new CodeObjectCreateExpression(typeof(FeatureInfo),
+ new CodeObjectCreateExpression(typeof(CultureInfo),
+ new CodePrimitiveExpression(generationContext.Feature.Language)),
+ new CodePrimitiveExpression(generationContext.Feature.Name),
+ new CodePrimitiveExpression(generationContext.Feature.Description),
+ new CodeFieldReferenceExpression(
+ new CodeTypeReferenceExpression("ProgrammingLanguage"),
+ this._codeDomHelper.TargetLanguage.ToString()),
+ this.GetStringArrayExpression(generationContext.Feature.Tags))));
+
+ //testRunner.OnFeatureStart(featureInfo);
+ testClassInitializeMethod.Statements.Add(
+ new CodeMethodInvokeExpression(
+ testRunnerField,
+ "OnFeatureStart",
+ new CodeVariableReferenceExpression("featureInfo")));
+ }
+
+ private CodeExpression GetStringArrayExpression(IEnumerable tags)
+ {
+ var enumerable = tags as Tag[] ?? tags.ToArray();
+ if (!enumerable.Any())
+ {
+ return new CodeCastExpression(typeof(string[]), new CodePrimitiveExpression(null));
+ }
+
+ return new CodeArrayCreateExpression(typeof(string[]),
+ enumerable.Select(tag => new CodePrimitiveExpression(tag.GetNameWithoutAt())).Cast()
+ .ToArray());
+ }
+
+ private CodeExpression GetStringArrayExpression(IEnumerable items,
+ ParameterSubstitution paramToIdentifier)
+ {
+ return new CodeArrayCreateExpression(typeof(string[]),
+ items.Select(item => this.GetSubstitutedString(item, paramToIdentifier)).ToArray());
+ }
+
+ private void SetupTestClassCleanupMethod(TestClassGenerationContext generationContext)
+ {
+ CodeMemberMethod testClassCleanupMethod = generationContext.TestClassCleanupMethod;
+
+ testClassCleanupMethod.Attributes = MemberAttributes.Public;
+ testClassCleanupMethod.Name = TESTCLASS_CLEANUP_NAME;
+
+ this._testGeneratorProvider.SetTestClassCleanupMethod(generationContext);
+
+ var testRunnerField = this.GetTestRunnerExpression();
+ // testRunner.OnFeatureEnd();
+ testClassCleanupMethod.Statements.Add(
+ new CodeMethodInvokeExpression(
+ testRunnerField,
+ "OnFeatureEnd"));
+ // testRunner = null;
+ testClassCleanupMethod.Statements.Add(
+ new CodeAssignStatement(
+ testRunnerField,
+ new CodePrimitiveExpression(null)));
+ }
+
+ private void SetupTestInitializeMethod(TestClassGenerationContext generationContext)
+ {
+ CodeMemberMethod testInitializeMethod = generationContext.TestInitializeMethod;
+
+ testInitializeMethod.Attributes = MemberAttributes.Public;
+ testInitializeMethod.Name = TEST_INITIALIZE_NAME;
+
+ this._testGeneratorProvider.SetTestInitializeMethod(generationContext);
+ }
+
+ private void SetupTestCleanupMethod(TestClassGenerationContext generationContext)
+ {
+ CodeMemberMethod testCleanupMethod = generationContext.TestCleanupMethod;
+
+ testCleanupMethod.Attributes = MemberAttributes.Public;
+ testCleanupMethod.Name = TEST_CLEANUP_NAME;
+
+ this._testGeneratorProvider.SetTestCleanupMethod(generationContext);
+
+ var testRunnerField = this.GetTestRunnerExpression();
+ //testRunner.OnScenarioEnd();
+ testCleanupMethod.Statements.Add(
+ new CodeMethodInvokeExpression(
+ testRunnerField,
+ "OnScenarioEnd"));
+ }
+
+ private void SetupScenarioInitializeMethod(TestClassGenerationContext generationContext)
+ {
+ CodeMemberMethod scenarioInitializeMethod = generationContext.ScenarioInitializeMethod;
+
+ scenarioInitializeMethod.Attributes = MemberAttributes.Public;
+ scenarioInitializeMethod.Name = SCENARIO_INITIALIZE_NAME;
+ scenarioInitializeMethod.Parameters.Add(
+ new CodeParameterDeclarationExpression(typeof(ScenarioInfo), "scenarioInfo"));
+
+ //testRunner.OnScenarioStart(scenarioInfo);
+ var testRunnerField = this.GetTestRunnerExpression();
+ scenarioInitializeMethod.Statements.Add(
+ new CodeMethodInvokeExpression(
+ testRunnerField,
+ "OnScenarioStart",
+ new CodeVariableReferenceExpression("scenarioInfo")));
+ }
+
+ private void SetupFeatureBackground(TestClassGenerationContext generationContext)
+ {
+ if (!HasFeatureBackground(generationContext.Feature))
+ {
+ return;
+ }
+
+ var background = generationContext.Feature.Background;
+
+ CodeMemberMethod backgroundMethod = generationContext.FeatureBackgroundMethod;
+
+ backgroundMethod.Attributes = MemberAttributes.Public;
+ backgroundMethod.Name = BACKGROUND_NAME;
+
+ this.AddLineDirective(backgroundMethod.Statements, background);
+
+ foreach (var step in background.Steps)
+ {
+ this.GenerateStep(backgroundMethod, step, null);
+ }
+
+ this.AddLineDirectiveHidden(backgroundMethod.Statements);
+ }
+
+ private class ParameterSubstitution : List>
+ {
+ public void Add(string parameter, string identifier)
+ {
+ this.Add(new KeyValuePair(parameter.Trim(), identifier));
+ }
+
+ public bool TryGetIdentifier(string param, out string id)
+ {
+ param = param.Trim();
+ foreach (var pair in this)
+ {
+ if (pair.Key.Equals(param))
+ {
+ id = pair.Value;
+ return true;
+ }
+ }
+
+ id = null;
+ return false;
+ }
+ }
+
+ private CodeMemberMethod CreateTestMethod(TestClassGenerationContext generationContext,
+ Scenario scenario, IEnumerable additionalTags, string variantName = null,
+ string exampleSetIdentifier = null)
+ {
+ CodeMemberMethod testMethod = this.CreateMethod(generationContext.TestClass);
+
+ this.SetupTestMethod(generationContext, testMethod, scenario, additionalTags, variantName, exampleSetIdentifier);
+
+ return testMethod;
+ }
+
+ private void GenerateTest(TestClassGenerationContext generationContext, Scenario scenario)
+ {
+ CodeMemberMethod testMethod = this.CreateTestMethod(generationContext, scenario, null);
+
+ int retryValue;
+
+ if (this.GetTagValue(generationContext, scenario, TagsRepository.RetryTag, int.TryParse, out retryValue))
+ {
+ string retryExceptExceptionName;
+
+ this.GetTagValue(generationContext, scenario, TagsRepository.RetryExceptTag, out retryExceptExceptionName);
+
+ testMethod = this.GenerateRetryStatementAndUnwrap(generationContext, testMethod, retryValue,
+ retryExceptExceptionName);
+ }
+
+ this.GenerateTestBody(generationContext, scenario, testMethod);
+ }
+
+ private delegate bool TryParseDelegate(string value, out T parsedValue);
+
+ private bool GetTagValue(TestClassGenerationContext generationContext, Scenario scenario, string retryTag,
+ out string value)
+ {
+ return this.GetTagValue(generationContext, scenario, retryTag, delegate (string v, out string p)
+ {
+ p = v;
+ return v != null;
+ }, out value);
+ }
+
+ private bool GetTagValue(TestClassGenerationContext generationContext, Scenario scenario, string retryTag,
+ TryParseDelegate parser, out T value)
+ {
+ value = default(T);
+
+ var tagNames = scenario.Tags?.Select(_ => _.GetNameWithoutAt()) ?? new string[0];
+ tagNames = tagNames.ToList();
+ string retryCountValue;
+ return this._tagFilterMatcher.GetTagValue(retryTag, tagNames, out retryCountValue)
+ && parser(retryCountValue, out value) ||
+ this._tagFilterMatcher.GetTagValue(retryTag, generationContext.Document, out retryCountValue)
+ && parser(retryCountValue, out value);
+ }
+
+ private CodeMemberMethod GenerateRetryStatementAndUnwrap(TestClassGenerationContext generationContext,
+ CodeMemberMethod testMethod, int retryCount, string retryExceptExceptionName)
+ {
+ var method = this.CreateMethod(generationContext.TestClass);
+
+ method.Name = testMethod.Name + "Internal";
+
+ foreach (CodeParameterDeclarationExpression parameter in testMethod.Parameters)
+ {
+ method.Parameters.Add(new CodeParameterDeclarationExpression(parameter.Type, parameter.Name));
+ }
+
+ testMethod.Statements.Add(new CodeVariableDeclarationStatement(typeof(Exception), "lastException",
+ new CodePrimitiveExpression(null)));
+
+ var codeCatchClauses = new List();
+
+ if (!string.IsNullOrEmpty(retryExceptExceptionName))
+ {
+ codeCatchClauses.Add(new CodeCatchClause(
+ "exc",
+ new CodeTypeReference(new CodeTypeParameter(retryExceptExceptionName)),
+ new CodeThrowExceptionStatement()
+ ));
+ }
+
+ codeCatchClauses.Add(new CodeCatchClause(
+ "exc",
+ new CodeTypeReference(typeof(Exception)),
+ /* lastException = exc; */
+ new CodeAssignStatement(
+ new CodeVariableReferenceExpression("lastException"),
+ new CodeVariableReferenceExpression("exc"))));
+
+ testMethod.Statements.Add(
+ new CodeIterationStatement(
+ /* for(var i = 0; i < retryCount; i++)*/
+ initStatement:
+ new CodeVariableDeclarationStatement(typeof(int), "i", new CodePrimitiveExpression(0)),
+ testExpression: new CodeBinaryOperatorExpression(
+ new CodeVariableReferenceExpression("i"),
+ CodeBinaryOperatorType.LessThanOrEqual,
+ new CodePrimitiveExpression(retryCount)
+ ),
+ incrementStatement: new CodeAssignStatement(
+ new CodeVariableReferenceExpression("i"),
+ new CodeBinaryOperatorExpression(
+ new CodeVariableReferenceExpression("i"),
+ CodeBinaryOperatorType.Add,
+ new CodePrimitiveExpression(1))),
+ statements: new CodeStatement[]
+ {
+ /* try */
+ new CodeTryCatchFinallyStatement(
+ tryStatements: new CodeStatement[]
+ {
+ /* { */
+ /* this.TestInternal(); */
+ new CodeExpressionStatement(new CodeMethodInvokeExpression(
+ new CodeThisReferenceExpression(), method.Name,
+ method.Parameters
+ .Cast()
+ .Select(_ => new CodeVariableReferenceExpression(_.Name))
+ .Cast()
+ .ToArray())),
+ /* return; */
+ new CodeMethodReturnStatement(),
+ /* } */
+ },
+ catchClauses: codeCatchClauses.ToArray()
+ ),
+ new CodeConditionStatement(
+ /* if ( (i+1) >= retryCount) */
+ new CodeBinaryOperatorExpression(
+ new CodeBinaryOperatorExpression(new CodeVariableReferenceExpression("i"),
+ CodeBinaryOperatorType.Add, new CodePrimitiveExpression(1)),
+ CodeBinaryOperatorType.LessThanOrEqual,
+ new CodePrimitiveExpression(retryCount)
+ ),
+ /* { */
+ /* testRunner.OnScenarioEnd();*/
+ new CodeExpressionStatement(
+ new CodeMethodInvokeExpression(
+ this.GetTestRunnerExpression(),
+ "OnScenarioEnd"
+ )))
+ /* } */
+ })
+ );
+ testMethod.Statements.Add(new CodeConditionStatement(
+ condition: new CodeBinaryOperatorExpression(
+ new CodeVariableReferenceExpression("lastException"),
+ CodeBinaryOperatorType.IdentityInequality,
+ new CodePrimitiveExpression(null)),
+ trueStatements: new CodeThrowExceptionStatement(new CodeVariableReferenceExpression("lastException"))));
+
+ return method;
+ }
+
+ private void GenerateTestBody(TestClassGenerationContext generationContext, Scenario scenario,
+ CodeMemberMethod testMethod, CodeExpression additionalTagsExpression = null,
+ ParameterSubstitution paramToIdentifier = null)
+ {
+ //// call test setup
+ //// ScenarioInfo scenarioInfo = new ScenarioInfo("xxxx", tags...);
+ CodeExpression tagsExpression;
+
+ if (additionalTagsExpression == null)
+ {
+ tagsExpression = this.GetStringArrayExpression(scenario.GetTags());
+ }
+ else if (!((StepsContainer)scenario).HasTags())
+ {
+ tagsExpression = additionalTagsExpression;
+ }
+ else
+ {
+ //// merge tags list
+ //// var tags = tags1
+ //// if (tags2 != null)
+ //// tags = Enumerable.ToArray(Enumerable.Concat(tags1, tags1));
+ testMethod.Statements.Add(
+ new CodeVariableDeclarationStatement(typeof(string[]), "__tags",
+ this.GetStringArrayExpression(scenario.GetTags())));
+ tagsExpression = new CodeVariableReferenceExpression("__tags");
+ testMethod.Statements.Add(
+ new CodeConditionStatement(
+ new CodeBinaryOperatorExpression(
+ additionalTagsExpression,
+ CodeBinaryOperatorType.IdentityInequality,
+ new CodePrimitiveExpression(null)),
+ new CodeAssignStatement(
+ tagsExpression,
+ new CodeMethodInvokeExpression(
+ new CodeTypeReferenceExpression(typeof(Enumerable)),
+ "ToArray",
+ new CodeMethodInvokeExpression(
+ new CodeTypeReferenceExpression(typeof(Enumerable)),
+ "Concat",
+ tagsExpression,
+ additionalTagsExpression)))));
+ }
+
+ testMethod.Statements.Add(
+ new CodeVariableDeclarationStatement(typeof(ScenarioInfo), "scenarioInfo",
+ new CodeObjectCreateExpression(typeof(ScenarioInfo),
+ new CodePrimitiveExpression(scenario.Name),
+ tagsExpression)));
+
+ this.AddLineDirective(testMethod.Statements, scenario);
+ testMethod.Statements.Add(
+ new CodeMethodInvokeExpression(
+ new CodeThisReferenceExpression(),
+ generationContext.ScenarioInitializeMethod.Name,
+ new CodeVariableReferenceExpression("scenarioInfo")));
+
+ if (HasFeatureBackground(generationContext.Feature))
+ {
+ this.AddLineDirective(testMethod.Statements, generationContext.Feature.Background);
+ testMethod.Statements.Add(
+ new CodeMethodInvokeExpression(
+ new CodeThisReferenceExpression(),
+ generationContext.FeatureBackgroundMethod.Name));
+ }
+
+ foreach (var scenarioStep in scenario.Steps)
+ {
+ this.GenerateStep(testMethod, scenarioStep, paramToIdentifier);
+ }
+
+ this.AddLineDirectiveHidden(testMethod.Statements);
+
+ // call scenario cleanup
+ testMethod.Statements.Add(
+ new CodeMethodInvokeExpression(
+ new CodeThisReferenceExpression(),
+ generationContext.ScenarioCleanupMethod.Name));
+ }
+
+ private void SetupTestMethod(TestClassGenerationContext generationContext, CodeMemberMethod testMethod,
+ Scenario scenarioDefinition, IEnumerable additionalTags, string variantName,
+ string exampleSetIdentifier, bool rowTest = false)
+ {
+ testMethod.Attributes = MemberAttributes.Public;
+ testMethod.Name = GetTestMethodName(scenarioDefinition, variantName, exampleSetIdentifier);
+
+ var friendlyTestName = scenarioDefinition.Name;
+
+ if (variantName != null)
+ {
+ friendlyTestName = string.Format("{0}: {1}", scenarioDefinition.Name, variantName);
+ }
+
+ if (rowTest)
+ {
+ this._testGeneratorProvider.SetRowTest(generationContext, testMethod, friendlyTestName);
+ }
+ else
+ {
+ this._testGeneratorProvider.SetTestMethod(generationContext, testMethod, friendlyTestName);
+ }
+
+ List scenarioCategories;
+ this._decoratorRegistry.DecorateTestMethod(generationContext, testMethod,
+ this.ConcatTags(scenarioDefinition.GetTags(), additionalTags), out scenarioCategories);
+
+ if (scenarioCategories.Any())
+ {
+ this._testGeneratorProvider.SetTestMethodCategories(generationContext, testMethod, scenarioCategories);
+ }
+ }
+
+ private static string GetTestMethodName(Scenario scenario, string variantName,
+ string exampleSetIdentifier)
+ {
+ var methodName = string.Format(TEST_NAME_FORMAT, scenario.Name.ToIdentifier());
+
+ if (variantName != null)
+ {
+ var variantNameIdentifier = variantName.ToIdentifier().TrimStart('_');
+ methodName = string.IsNullOrEmpty(exampleSetIdentifier)
+ ? string.Format("{0}_{1}", methodName, variantNameIdentifier)
+ : string.Format("{0}_{1}_{2}", methodName, exampleSetIdentifier, variantNameIdentifier);
+ }
+
+ return methodName;
+ }
+
+ private IEnumerable ConcatTags(params IEnumerable[] tagLists)
+ {
+ return tagLists.Where(tagList => tagList != null).SelectMany(tagList => tagList);
+ }
+
+ private CodeExpression GetSubstitutedString(string text, ParameterSubstitution paramToIdentifier)
+ {
+ if (text == null)
+ {
+ return new CodeCastExpression(typeof(string), new CodePrimitiveExpression(null));
+ }
+
+ if (paramToIdentifier == null)
+ {
+ return new CodePrimitiveExpression(text);
+ }
+
+ Regex paramRe = new Regex(@"\<(?[^\>]+)\>");
+ string formatText = text.Replace("{", "{{").Replace("}", "}}");
+ List arguments = new List();
+
+ formatText = paramRe.Replace(formatText, match =>
+ {
+ string param = match.Groups["param"].Value;
+ string id;
+
+ if (!paramToIdentifier.TryGetIdentifier(param, out id))
+ {
+ return match.Value;
+ }
+
+ int argIndex = arguments.IndexOf(id);
+
+ if (argIndex < 0)
+ {
+ argIndex = arguments.Count;
+ arguments.Add(id);
+ }
+
+ return "{" + argIndex + "}";
+ });
+
+ if (arguments.Count == 0)
+ {
+ return new CodePrimitiveExpression(text);
+ }
+
+ var formatArguments = new List { new CodePrimitiveExpression(formatText) };
+ formatArguments.AddRange(arguments.Select(id => new CodeVariableReferenceExpression(id))
+ .Cast());
+
+ return new CodeMethodInvokeExpression(
+ new CodeTypeReferenceExpression(typeof(string)),
+ "Format",
+ formatArguments.ToArray());
+ }
+
+ private void GenerateStep(CodeMemberMethod testMethod, Step gherkinStep,
+ ParameterSubstitution paramToIdentifier)
+ {
+ var testRunnerField = this.GetTestRunnerExpression();
+ var scenarioStep = this.AsSpecFlowStep(gherkinStep);
+
+ //// testRunner.Given("something");
+ var arguments =
+ new List { this.GetSubstitutedString(scenarioStep.Text, paramToIdentifier) };
+ if (scenarioStep.Argument != null)
+ {
+ this.AddLineDirectiveHidden(testMethod.Statements);
+ }
+
+ arguments.Add(
+ this.GetDocStringArgExpression(scenarioStep.Argument as DocString, paramToIdentifier));
+ arguments.Add(
+ this.GetTableArgExpression(scenarioStep.Argument as DataTable, testMethod.Statements, paramToIdentifier));
+ arguments.Add(new CodePrimitiveExpression(scenarioStep.Keyword));
+
+ this.AddLineDirective(testMethod.Statements, scenarioStep);
+ testMethod.Statements.Add(
+ new CodeMethodInvokeExpression(
+ testRunnerField,
+ scenarioStep.StepKeyword.ToString(),
+ arguments.ToArray()));
+ }
+
+ private SpecFlowStep AsSpecFlowStep(Step step)
+ {
+ var specFlowStep = step as SpecFlowStep;
+ if (specFlowStep == null)
+ {
+ throw new TestGeneratorException("The step must be a SpecFlowStep.");
+ }
+
+ return specFlowStep;
+ }
+
+ private int _tableCounter = 0;
+
+ private CodeExpression GetTableArgExpression(DataTable tableArg, CodeStatementCollection statements,
+ ParameterSubstitution paramToIdentifier)
+ {
+ if (tableArg == null)
+ {
+ return new CodeCastExpression(typeof(Table), new CodePrimitiveExpression(null));
+ }
+
+ this._tableCounter++;
+
+ //TODO[Gherkin3]: remove dependency on having the first row as header
+ var header = tableArg.Rows.First();
+ var body = tableArg.Rows.Skip(1).ToArray();
+
+ //Table table0 = new Table(header...);
+ var tableVar = new CodeVariableReferenceExpression("table" + this._tableCounter);
+ statements.Add(
+ new CodeVariableDeclarationStatement(typeof(Table), tableVar.VariableName,
+ new CodeObjectCreateExpression(
+ typeof(Table),
+ this.GetStringArrayExpression(header.Cells.Select(c => c.Value), paramToIdentifier))));
+
+ foreach (var row in body)
+ {
+ //table0.AddRow(cells...);
+ statements.Add(
+ new CodeMethodInvokeExpression(
+ tableVar,
+ "AddRow",
+ this.GetStringArrayExpression(row.Cells.Select(c => c.Value), paramToIdentifier)));
+ }
+
+ return tableVar;
+ }
+
+ private CodeExpression GetDocStringArgExpression(DocString docString, ParameterSubstitution paramToIdentifier)
+ {
+ return this.GetSubstitutedString(docString?.Content, paramToIdentifier);
+ }
+
+ #region Line pragma handling
+
+ private void AddLinePragmaInitial(CodeTypeDeclaration testType, string sourceFile)
+ {
+ if (this._specFlowConfiguration.AllowDebugGeneratedFiles)
+ {
+ return;
+ }
+
+ this._codeDomHelper.BindTypeToSourceFile(testType, Path.GetFileName(sourceFile));
+ }
+
+ private void AddLineDirectiveHidden(CodeStatementCollection statements)
+ {
+ //// if (_specFlowConfiguration.AllowDebugGeneratedFiles)
+ return;
+
+ ///// _codeDomHelper.CreateSourceLinePragmaStatement(statements);
+ }
+
+ private void AddLineDirective(CodeStatementCollection statements, Background background)
+ {
+ this.AddLineDirective(statements, background.Location);
+ }
+
+ private void AddLineDirective(CodeStatementCollection statements, Scenario scenarioDefinition)
+ {
+ this.AddLineDirective(statements, scenarioDefinition.Location);
+ }
+
+ private void AddLineDirective(CodeStatementCollection statements, Step step)
+ {
+ this.AddLineDirective(statements, step.Location);
+ }
+
+ private void AddLineDirective(CodeStatementCollection statements, Location location)
+ {
+ //// if (location == null || _specFlowConfiguration.AllowDebugGeneratedFiles)
+ return;
+
+ //// _codeDomHelper.AddSourceLinePragmaStatement(statements, location.Line, location.Column);
+ }
+
+ #endregion
+ }
+}
\ No newline at end of file
diff --git a/src/SpecFlow.RetryCore/RetryUnitTestFeatureGeneratorProvider.cs b/src/SpecFlow.RetryCore/RetryUnitTestFeatureGeneratorProvider.cs
new file mode 100644
index 0000000..a9c3909
--- /dev/null
+++ b/src/SpecFlow.RetryCore/RetryUnitTestFeatureGeneratorProvider.cs
@@ -0,0 +1,27 @@
+namespace SpecFlow.RetryCore
+{
+ using TechTalk.SpecFlow.Generator.UnitTestConverter;
+ using TechTalk.SpecFlow.Parser;
+
+ public class RetryUnitTestFeatureGeneratorProvider : IFeatureGeneratorProvider
+ {
+ private readonly RetryUnitTestFeatureGenerator _unitTestFeatureGenerator;
+
+ public RetryUnitTestFeatureGeneratorProvider(RetryUnitTestFeatureGenerator unitTestFeatureGenerator)
+ {
+ this._unitTestFeatureGenerator = unitTestFeatureGenerator;
+ }
+
+ public bool CanGenerate(SpecFlowDocument document)
+ {
+ return true;
+ }
+
+ public IFeatureGenerator CreateGenerator(SpecFlowDocument document)
+ {
+ return this._unitTestFeatureGenerator;
+ }
+
+ public int Priority => PriorityValues.Normal;
+ }
+}
\ No newline at end of file
diff --git a/src/SpecFlow.RetryCore/SpecFlow.RetryCore.csproj b/src/SpecFlow.RetryCore/SpecFlow.RetryCore.csproj
new file mode 100644
index 0000000..8a09a6a
--- /dev/null
+++ b/src/SpecFlow.RetryCore/SpecFlow.RetryCore.csproj
@@ -0,0 +1,12 @@
+
+
+
+ net471;netcoreapp3.1
+
+
+
+
+
+
+
+
diff --git a/src/SpecFlow.RetryCore/TagsRepository.cs b/src/SpecFlow.RetryCore/TagsRepository.cs
new file mode 100644
index 0000000..abc98db
--- /dev/null
+++ b/src/SpecFlow.RetryCore/TagsRepository.cs
@@ -0,0 +1,8 @@
+namespace SpecFlow.RetryCore
+{
+ internal static class TagsRepository
+ {
+ public const string RetryTag = "Retry";
+ public const string RetryExceptTag = "RetryExcept";
+ }
+}
diff --git a/src/SpecFlow.RetryCore/build/SpecFlow.SamplePlugin.props b/src/SpecFlow.RetryCore/build/SpecFlow.SamplePlugin.props
new file mode 100644
index 0000000..cf282f9
--- /dev/null
+++ b/src/SpecFlow.RetryCore/build/SpecFlow.SamplePlugin.props
@@ -0,0 +1,7 @@
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/src/SpecFlow.RetryCore/build/SpecFlow.SamplePlugin.targets b/src/SpecFlow.RetryCore/build/SpecFlow.SamplePlugin.targets
new file mode 100644
index 0000000..6607f66
--- /dev/null
+++ b/src/SpecFlow.RetryCore/build/SpecFlow.SamplePlugin.targets
@@ -0,0 +1,9 @@
+
+
+ <_SampleGeneratorPluginFramework Condition=" '$(MSBuildRuntimeType)' == 'Core'">netcoreapp3.1
+ <_SampleGeneratorPluginFramework Condition=" '$(MSBuildRuntimeType)' != 'Core'">net471
+
+ <_SampleGeneratorPluginPath>$(MSBuildThisFileDirectory)\$(_SampleGeneratorPluginFramework)\SampleGeneratorPlugin.SpecFlowPlugin.dll
+
+
+
\ No newline at end of file
diff --git a/stylecop.json b/stylecop.json
new file mode 100644
index 0000000..4bd3154
--- /dev/null
+++ b/stylecop.json
@@ -0,0 +1,14 @@
+{
+ "$schema": "https://raw.githubusercontent.com/DotNetAnalyzers/StyleCopAnalyzers/master/StyleCop.Analyzers/StyleCop.Analyzers/Settings/stylecop.schema.json",
+ "settings": {
+ "documentationRules": {
+ "companyName": "Calrom Ltd.",
+ "headerDecoration": "-----------------------------------------------------------------------",
+ "documentationCulture": "en-GB",
+ "copyrightText": "Under MIT license"
+ },
+ "layoutRules": {
+ "newlineAtEndOfFile": "require"
+ }
+ }
+}