diff --git a/.gitignore b/.gitignore
index 6cb5191ba..278e533ba 100644
--- a/.gitignore
+++ b/.gitignore
@@ -10,6 +10,8 @@ obj/
[Rr]elease*/
_ReSharper*/
[Tt]est[Rr]esult*
+*.pidb
+*.userprefs
*.resharper
*.cache
*.gpState
diff --git a/Documentation/SpecFlowMonoGuide.docx b/Documentation/SpecFlowMonoGuide.docx
new file mode 100644
index 000000000..ca3d78f81
Binary files /dev/null and b/Documentation/SpecFlowMonoGuide.docx differ
diff --git a/IdeIntegration/MonoDevelopIntegration/Gui/SpecFlowEventDefinitionIcon.ico b/IdeIntegration/MonoDevelopIntegration/Gui/SpecFlowEventDefinitionIcon.ico
new file mode 100644
index 000000000..7ab089ad0
Binary files /dev/null and b/IdeIntegration/MonoDevelopIntegration/Gui/SpecFlowEventDefinitionIcon.ico differ
diff --git a/IdeIntegration/MonoDevelopIntegration/Gui/SpecFlowFeatureIcon.ico b/IdeIntegration/MonoDevelopIntegration/Gui/SpecFlowFeatureIcon.ico
new file mode 100644
index 000000000..7ab089ad0
Binary files /dev/null and b/IdeIntegration/MonoDevelopIntegration/Gui/SpecFlowFeatureIcon.ico differ
diff --git a/IdeIntegration/MonoDevelopIntegration/Gui/SpecFlowStepDefinitionIcon.ico b/IdeIntegration/MonoDevelopIntegration/Gui/SpecFlowStepDefinitionIcon.ico
new file mode 100644
index 000000000..7ab089ad0
Binary files /dev/null and b/IdeIntegration/MonoDevelopIntegration/Gui/SpecFlowStepDefinitionIcon.ico differ
diff --git a/IdeIntegration/MonoDevelopIntegration/MonoDevelop.TechTalk.SpecFlow.addin.xml b/IdeIntegration/MonoDevelopIntegration/MonoDevelop.TechTalk.SpecFlow.addin.xml
new file mode 100644
index 000000000..8321e4a2e
--- /dev/null
+++ b/IdeIntegration/MonoDevelopIntegration/MonoDevelop.TechTalk.SpecFlow.addin.xml
@@ -0,0 +1,48 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/IdeIntegration/MonoDevelopIntegration/MonoDevelop.TechTalk.SpecFlow.csproj b/IdeIntegration/MonoDevelopIntegration/MonoDevelop.TechTalk.SpecFlow.csproj
new file mode 100644
index 000000000..8d81a8bcd
--- /dev/null
+++ b/IdeIntegration/MonoDevelopIntegration/MonoDevelop.TechTalk.SpecFlow.csproj
@@ -0,0 +1,89 @@
+
+
+
+ Debug
+ AnyCPU
+ 9.0.21022
+ 2.0
+ {199D2315-F5BD-463C-B16A-BE31A845792B}
+ Library
+ MonoDevelop.TechTalk.SpecFlow
+ MonoDevelop.TechTalk.SpecFlow
+ v3.5
+
+
+ true
+ full
+ false
+ bin\Debug
+ DEBUG
+ prompt
+ 4
+
+
+ none
+ false
+ bin\Release
+ prompt
+ 4
+
+
+
+
+ MonoDevelop.TechTalk.SpecFlow.addin.xml
+
+
+ SpecFlowFeature.xft.xml
+
+
+ SpecFlowFeatureIcon.ico
+
+
+ SpecFlowEventDefinitionIcon.ico
+
+
+ SpecFlowStepDefinitionIcon.ico
+
+
+ SpecFlowStepDefinition.xft.xml
+
+
+ SpecFlowEventDefinition.xft.xml
+
+
+
+
+
+
+
+
+
+ False
+ ..\..\lib\monodevelop\MonoDevelop.Ide.dll
+
+
+ False
+ ..\..\lib\monodevelop\MonoDevelop.Core.dll
+
+
+
+
+
+
+
+
+
+ VersionInfo.cs
+
+
+
+
+ {453D8014-B6CD-4E86-80A8-D59F59092334}
+ TechTalk.SpecFlow.Generator
+
+
+ {7CCEF6D6-FC17-422E-9BED-EDD752B6496F}
+ TechTalk.SpecFlow.Parser
+
+
+
diff --git a/IdeIntegration/MonoDevelopIntegration/MonoDevelopProjectReader.cs b/IdeIntegration/MonoDevelopIntegration/MonoDevelopProjectReader.cs
new file mode 100644
index 000000000..e2ff4e548
--- /dev/null
+++ b/IdeIntegration/MonoDevelopIntegration/MonoDevelopProjectReader.cs
@@ -0,0 +1,64 @@
+using System;
+using System.Collections.Generic;
+using System.IO;
+using System.Linq;
+
+using MonoDevelop.Projects;
+
+using TechTalk.SpecFlow.Generator.Configuration;
+
+namespace MonoDevelop.TechTalk.SpecFlow
+{
+ internal static class MonoDevelopProjectReader
+ {
+ public static SpecFlowProject CreateSpecFlowProjectFrom(Project project)
+ {
+ var specFlowProject = new SpecFlowProject();
+ specFlowProject.ProjectFolder = project.BaseDirectory;
+ specFlowProject.ProjectName = project.Name;
+
+ string defaultNamespace = "Namespace";
+ if (project is DotNetProject)
+ {
+ defaultNamespace = ((DotNetProject)project).GetDefaultNamespace(project.Name);
+ }
+
+ // No way to get AssemblyName right now, therefore we'll just use DefaultNamespace
+ specFlowProject.AssemblyName = defaultNamespace;
+ specFlowProject.DefaultNamespace = defaultNamespace;
+
+ // TODO: Find out if we really need to add all the feature files everytime we generate
+ foreach (ProjectFile projectFile in project.Files.Where(IsFeatureOrAppConfigFile))
+ {
+ string extension = Path.GetExtension(projectFile.Name);
+
+ if (extension.Equals(".feature", StringComparison.InvariantCultureIgnoreCase))
+ {
+ string fileName = projectFile.FilePath.ToRelative(project.BaseDirectory);
+ var featureFile = new SpecFlowFeatureFile(fileName);
+ var customToolNamespace = projectFile.CustomToolNamespace;
+
+ if (!String.IsNullOrEmpty(customToolNamespace))
+ featureFile.CustomNamespace = customToolNamespace;
+
+ specFlowProject.FeatureFiles.Add(featureFile);
+ }
+
+ if (extension.Equals(".config", StringComparison.InvariantCultureIgnoreCase))
+ {
+ string configContent = File.ReadAllText(projectFile.FilePath);
+ GeneratorConfigurationReader.UpdateConfigFromFileContent(specFlowProject.GeneratorConfiguration, configContent);
+ }
+ }
+
+ return specFlowProject;
+ }
+
+ private static bool IsFeatureOrAppConfigFile(ProjectFile projectFile)
+ {
+ string extension = Path.GetExtension(projectFile.Name);
+ return extension.Equals(".feature", StringComparison.InvariantCultureIgnoreCase)
+ || projectFile.Name.Equals("app.config", StringComparison.InvariantCultureIgnoreCase);
+ }
+ }
+}
diff --git a/IdeIntegration/MonoDevelopIntegration/Properties/AssemblyInfo.cs b/IdeIntegration/MonoDevelopIntegration/Properties/AssemblyInfo.cs
new file mode 100644
index 000000000..a9f9a529a
--- /dev/null
+++ b/IdeIntegration/MonoDevelopIntegration/Properties/AssemblyInfo.cs
@@ -0,0 +1,24 @@
+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("MonoDevelop.TechTalk.SpecFlow")]
+[assembly: AssemblyDescription("")]
+[assembly: AssemblyConfiguration("")]
+[assembly: AssemblyCompany("Microsoft")]
+[assembly: AssemblyProduct("MonoDevelop.TechTalk.SpecFlow")]
+[assembly: AssemblyCopyright("Copyright © TechTalk, SineSignal, LLC 2010")]
+[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("0ACD56A4-7A81-11DF-93DF-699DDFD72085")]
+
diff --git a/IdeIntegration/MonoDevelopIntegration/SingleFeatureFileGenerator.cs b/IdeIntegration/MonoDevelopIntegration/SingleFeatureFileGenerator.cs
new file mode 100644
index 000000000..d4fe99119
--- /dev/null
+++ b/IdeIntegration/MonoDevelopIntegration/SingleFeatureFileGenerator.cs
@@ -0,0 +1,154 @@
+using System;
+using System.CodeDom.Compiler;
+using System.IO;
+using System.Text;
+using System.Threading;
+
+using Microsoft.CSharp;
+using MonoDevelop.Core;
+using MonoDevelop.Ide.CustomTools;
+using MonoDevelop.Projects;
+
+using TechTalk.SpecFlow.Generator;
+using TechTalk.SpecFlow.Generator.Configuration;
+using TechTalk.SpecFlow.Parser;
+
+namespace MonoDevelop.TechTalk.SpecFlow
+{
+ public class SingleFeatureFileGenerator : ISingleFileCustomTool
+ {
+ public IAsyncOperation Generate(IProgressMonitor monitor, ProjectFile file, SingleFileCustomToolResult result)
+ {
+ return new ThreadAsyncOperation(() => {
+
+ FilePath codeFilePath = file.FilePath.ChangeExtension(".feature.cs");
+
+ try
+ {
+ codeFilePath = GenerateFeatureCodeFileFor(file);
+ }
+ catch (Exception ex)
+ {
+ HandleException(ex, file, result);
+ }
+
+ result.GeneratedFilePath = codeFilePath;
+
+ }, result);
+ }
+
+ private FilePath GenerateFeatureCodeFileFor(ProjectFile featureFile)
+ {
+ // TODO: We only support C# for now, later we'll add support to grab the provider based on the project
+ CodeDomProvider codeProvider = new CSharpCodeProvider();
+ FilePath outputFile = featureFile.FilePath.ChangeExtension(".feature." + codeProvider.FileExtension);
+ SpecFlowProject specFlowProject = MonoDevelopProjectReader.CreateSpecFlowProjectFrom(featureFile.Project);
+ var specFlowGenerator = new SpecFlowGenerator(specFlowProject);
+
+ using (var writer = new StringWriter(new StringBuilder()))
+ using (var reader = new StringReader(File.ReadAllText(featureFile.FilePath)))
+ {
+ SpecFlowFeatureFile specFlowFeatureFile = specFlowProject.GetOrCreateFeatureFile(featureFile.FilePath);
+ specFlowGenerator.GenerateTestFile(specFlowFeatureFile, codeProvider, reader, writer);
+ File.WriteAllText(outputFile, writer.ToString());
+ }
+
+ return outputFile;
+ }
+
+ private void HandleException(Exception ex, ProjectFile file, SingleFileCustomToolResult result)
+ {
+ if (ex is SpecFlowParserException)
+ {
+ SpecFlowParserException sfpex = (SpecFlowParserException) ex;
+
+ if (sfpex.ErrorDetails == null || sfpex.ErrorDetails.Count == 0)
+ {
+ result.UnhandledException = ex;
+ }
+ else
+ {
+ var compilerErrors = new CompilerErrorCollection();
+
+ foreach (var errorDetail in sfpex.ErrorDetails)
+ {
+ var compilerError = new CompilerError(file.Name, errorDetail.ForcedLine, errorDetail.ForcedColumn, "0", errorDetail.Message);
+ compilerErrors.Add(compilerError);
+ }
+
+ result.Errors.AddRange(compilerErrors);
+ }
+ }
+ else
+ {
+ result.UnhandledException = ex;
+ }
+ }
+ }
+
+ internal class ThreadAsyncOperation : IAsyncOperation
+ {
+ private Thread Thread { get; set; }
+ private bool Cancelled { get; set; }
+ private SingleFileCustomToolResult Result { get; set; }
+ private Action Task { get; set; }
+
+ public ThreadAsyncOperation(Action task, SingleFileCustomToolResult result)
+ {
+ if (result == null)
+ throw new ArgumentNullException("result");
+
+ Task = task;
+ Result = result;
+ Thread = new Thread(Run);
+ Thread.Start();
+ }
+
+ private void Run()
+ {
+ try
+ {
+ Task();
+ }
+ catch (ThreadAbortException ex)
+ {
+ Result.UnhandledException = ex;
+ Thread.ResetAbort();
+ }
+ catch (Exception ex)
+ {
+ Result.UnhandledException = ex;
+ }
+
+ if (Completed != null)
+ Completed(this);
+ }
+
+ public event OperationHandler Completed;
+
+ public void Cancel()
+ {
+ Thread.Abort();
+ }
+
+ public void WaitForCompleted()
+ {
+ Thread.Join();
+ }
+
+ public bool IsCompleted
+ {
+ get { return !Thread.IsAlive; }
+ }
+
+ public bool Success
+ {
+ get { return !Cancelled && Result.Success; }
+ }
+
+ public bool SuccessWithWarnings
+ {
+ get { return !Cancelled && Result.SuccessWithWarnings; }
+ }
+ }
+}
diff --git a/IdeIntegration/MonoDevelopIntegration/Templates/SpecFlowEventDefinition.xft.xml b/IdeIntegration/MonoDevelopIntegration/Templates/SpecFlowEventDefinition.xft.xml
new file mode 100644
index 000000000..5869c3e7e
--- /dev/null
+++ b/IdeIntegration/MonoDevelopIntegration/Templates/SpecFlowEventDefinition.xft.xml
@@ -0,0 +1,101 @@
+
+
+
+
+ <_Name>SpecFlow Event Definition
+ res:SpecFlowEventDefinitionIcon.ico
+ <_Category>SpecFlow
+ C#
+ <_Description>Creates a SpecFlow Event Definition file.
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/IdeIntegration/MonoDevelopIntegration/Templates/SpecFlowFeature.xft.xml b/IdeIntegration/MonoDevelopIntegration/Templates/SpecFlowFeature.xft.xml
new file mode 100644
index 000000000..ccd7506e0
--- /dev/null
+++ b/IdeIntegration/MonoDevelopIntegration/Templates/SpecFlowFeature.xft.xml
@@ -0,0 +1,29 @@
+
+
+
+
+ <_Name>SpecFlow Feature
+ res:SpecFlowFeatureIcon.ico
+ <_Category>SpecFlow
+ <_Description>Creates a SpecFlow Feature template.
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/IdeIntegration/MonoDevelopIntegration/Templates/SpecFlowStepDefinition.xft.xml b/IdeIntegration/MonoDevelopIntegration/Templates/SpecFlowStepDefinition.xft.xml
new file mode 100644
index 000000000..eb2598875
--- /dev/null
+++ b/IdeIntegration/MonoDevelopIntegration/Templates/SpecFlowStepDefinition.xft.xml
@@ -0,0 +1,61 @@
+
+
+
+
+ <_Name>SpecFlow Step Definition
+ res:SpecFlowStepDefinitionIcon.ico
+ <_Category>SpecFlow
+ C#
+ <_Description>Creates a SpecFlow Step Definition file.
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/Parser/TechTalk.SpecFlow.Parser.csproj b/Parser/TechTalk.SpecFlow.Parser.csproj
index 05968a9b7..6335caf29 100644
--- a/Parser/TechTalk.SpecFlow.Parser.csproj
+++ b/Parser/TechTalk.SpecFlow.Parser.csproj
@@ -1,4 +1,4 @@
-
+
Debug
@@ -33,34 +33,38 @@
4
-
+
+
+ 3.5
+
+
+ 3.5
+
+
+ 3.5
+
+
+
+
False
..\lib\gherkin\Gherkin.dll
-
+
False
..\lib\gherkin\IKVM.OpenJDK.Core.dll
-
+
False
..\lib\gherkin\IKVM.OpenJDK.Text.dll
-
+
False
..\lib\gherkin\IKVM.Runtime.dll
-
-
- 3.5
-
-
- 3.5
-
-
- 3.5
+
+ False
+ ..\lib\gherkin\IKVM.OpenJDK.Security.dll
-
-
@@ -105,6 +109,7 @@
+
-
\ No newline at end of file
+
diff --git a/Tests/ParserTests/ParserTests.csproj b/Tests/ParserTests/ParserTests.csproj
index 13b494008..d25894cc8 100644
--- a/Tests/ParserTests/ParserTests.csproj
+++ b/Tests/ParserTests/ParserTests.csproj
@@ -1,4 +1,4 @@
-
+
Debug
@@ -33,10 +33,6 @@
4
-
- False
- ..\..\lib\nunit\nunit.framework.dll
-
3.5
@@ -49,6 +45,10 @@
+
+ False
+ ..\..\lib\nunit\nunit.framework.dll
+
@@ -134,6 +134,7 @@
+