Skip to content

Commit

Permalink
Finished hooking up the custom tool to call into the SpecFlow Generat…
Browse files Browse the repository at this point in the history
…or. When a feature file is created or saved, it creates the feature code file. The MonoDevelop add-in is complete. The only difference between it and the Visual Studio one is VB support.
  • Loading branch information
dragan committed Jun 2, 2010
1 parent 8eb3ae4 commit b33dcd2
Show file tree
Hide file tree
Showing 3 changed files with 138 additions and 4 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -69,6 +69,7 @@
</ItemGroup>
<ItemGroup>
<Compile Include="SingleFeatureFileGenerator.cs" />
<Compile Include="MonoDevelopProjectReader.cs" />
</ItemGroup>
<ItemGroup>
<ProjectReference Include="..\..\Generator\TechTalk.SpecFlow.Generator.csproj">
Expand Down
69 changes: 69 additions & 0 deletions IdeIntegration/MonoDevelopIntegration/MonoDevelopProjectReader.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,69 @@
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;

foreach (SolutionItemConfiguration configuration in project.Configurations)
{
MonoDevelop.Core.LoggingService.LogInfo(configuration.Name);
}

// 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);
}
}
}
Original file line number Diff line number Diff line change
@@ -1,25 +1,89 @@
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 outputFile = file.FilePath.ChangeExtension(".feature.cs");
string content = @"// {0} was generated successfully";
File.WriteAllText(outputFile, String.Format(content, outputFile.FileName), Encoding.UTF8);
result.GeneratedFilePath = outputFile;

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
Expand Down

0 comments on commit b33dcd2

Please sign in to comment.