Skip to content

Commit 90ad369

Browse files
author
Dale Ragan
committed
Pulled and merged latest from TechTalk.
2 parents 22b7be1 + 36506cc commit 90ad369

File tree

214 files changed

+5447
-26606
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

214 files changed

+5447
-26606
lines changed

.gitignore

+2
Original file line numberDiff line numberDiff line change
@@ -12,3 +12,5 @@ _ReSharper*/
1212
[Tt]est[Rr]esult*
1313
*.pidb
1414
*.userprefs
15+
*.resharper
16+
*.cache

Documentation/SpecFlow Guide.docx

38.5 KB
Binary file not shown.

Generator/CodeDomHelper.cs

+162
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,162 @@
1+
using System;
2+
using System.CodeDom;
3+
using System.CodeDom.Compiler;
4+
using System.Globalization;
5+
using System.Reflection;
6+
using System.Runtime.CompilerServices;
7+
8+
namespace TechTalk.SpecFlow.Generator
9+
{
10+
public enum GenerationTargetLanguage
11+
{
12+
CSharp,
13+
VB,
14+
Other
15+
}
16+
17+
public interface ICodeDomHelperRequired
18+
{
19+
CodeDomHelper CodeDomHelper { get; set; }
20+
}
21+
22+
public class CodeDomHelper
23+
{
24+
public GenerationTargetLanguage TargetLanguage { get; private set; }
25+
26+
public CodeDomHelper(CodeDomProvider codeComProvider)
27+
{
28+
switch (codeComProvider.FileExtension.ToLower(CultureInfo.InvariantCulture))
29+
{
30+
case "cs":
31+
TargetLanguage = GenerationTargetLanguage.CSharp;
32+
break;
33+
case "vb":
34+
TargetLanguage = GenerationTargetLanguage.VB;
35+
break;
36+
default:
37+
TargetLanguage = GenerationTargetLanguage.Other;
38+
break;
39+
}
40+
}
41+
42+
public CodeDomHelper(GenerationTargetLanguage targetLanguage)
43+
{
44+
TargetLanguage = targetLanguage;
45+
}
46+
47+
public CodeTypeReference CreateNestedTypeReference(CodeTypeDeclaration baseTypeDeclaration, string nestedTypeName)
48+
{
49+
return new CodeTypeReference(baseTypeDeclaration.Name + "." + nestedTypeName);
50+
}
51+
52+
public void SetTypeReferenceAsInterface(CodeTypeReference typeReference)
53+
{
54+
// this hack is necessary for VB.NET code generation
55+
56+
if (TargetLanguage == GenerationTargetLanguage.VB)
57+
{
58+
var isInterfaceField = typeReference.GetType().GetField("isInterface",
59+
BindingFlags.Instance | BindingFlags.NonPublic);
60+
if (isInterfaceField == null)
61+
throw new InvalidOperationException("CodeDom version does not support VB.NET generation.");
62+
63+
isInterfaceField.SetValue(typeReference, true);
64+
}
65+
}
66+
67+
public void InjectIfRequired(object target)
68+
{
69+
ICodeDomHelperRequired codeDomHelperRequired = target as ICodeDomHelperRequired;
70+
if (codeDomHelperRequired != null)
71+
codeDomHelperRequired.CodeDomHelper = this;
72+
}
73+
74+
public void AddCommentStatement(CodeStatementCollection statements, string comment)
75+
{
76+
switch (TargetLanguage)
77+
{
78+
case GenerationTargetLanguage.CSharp:
79+
statements.Add(new CodeSnippetStatement("//" + comment));
80+
break;
81+
case GenerationTargetLanguage.VB:
82+
statements.Add(new CodeSnippetStatement("'" + comment));
83+
break;
84+
}
85+
}
86+
87+
public void BindTypeToSourceFile(CodeTypeDeclaration typeDeclaration, string fileName)
88+
{
89+
switch (TargetLanguage)
90+
{
91+
case GenerationTargetLanguage.CSharp:
92+
typeDeclaration.Members.Add(new CodeSnippetTypeMember(string.Format("#line 1 \"{0}\"", fileName)));
93+
typeDeclaration.Members.Add(new CodeSnippetTypeMember("#line hidden"));
94+
break;
95+
}
96+
}
97+
98+
public void AddSourceLinePragmaStatement(CodeStatementCollection statements, int lineNo, int colNo)
99+
{
100+
switch (TargetLanguage)
101+
{
102+
case GenerationTargetLanguage.CSharp:
103+
statements.Add(new CodeSnippetStatement(string.Format("#line {0}", lineNo)));
104+
AddCommentStatement(statements, string.Format("#indentnext {0}", colNo - 1));
105+
break;
106+
}
107+
}
108+
109+
public void AddDisableSourceLinePragmaStatement(CodeStatementCollection statements)
110+
{
111+
switch (TargetLanguage)
112+
{
113+
case GenerationTargetLanguage.CSharp:
114+
statements.Add(new CodeSnippetStatement("#line hidden"));
115+
break;
116+
}
117+
}
118+
119+
public CodeStatement GetStartRegionStatement(string regionText)
120+
{
121+
switch (TargetLanguage)
122+
{
123+
case GenerationTargetLanguage.CSharp:
124+
return new CodeSnippetStatement("#region " + regionText);
125+
case GenerationTargetLanguage.VB:
126+
return new CodeSnippetStatement("#Region \"" + regionText + "\"");
127+
}
128+
return new CodeCommentStatement("#region " + regionText);
129+
}
130+
131+
public CodeStatement GetEndRegionStatement()
132+
{
133+
switch (TargetLanguage)
134+
{
135+
case GenerationTargetLanguage.CSharp:
136+
return new CodeSnippetStatement("#endregion");
137+
case GenerationTargetLanguage.VB:
138+
return new CodeSnippetStatement("#End Region");
139+
}
140+
return new CodeCommentStatement("#endregion");
141+
}
142+
143+
private Version GetCurrentSpecFlowVersion()
144+
{
145+
return Assembly.GetExecutingAssembly().GetName().Version;
146+
}
147+
148+
public CodeTypeDeclaration CreateGeneratedTypeDeclaration(string className)
149+
{
150+
var result = new CodeTypeDeclaration(className);
151+
result.CustomAttributes.Add(
152+
new CodeAttributeDeclaration(
153+
new CodeTypeReference(typeof(GeneratedCodeAttribute)),
154+
new CodeAttributeArgument(new CodePrimitiveExpression("TechTalk.SpecFlow")),
155+
new CodeAttributeArgument(new CodePrimitiveExpression(GetCurrentSpecFlowVersion().ToString()))));
156+
result.CustomAttributes.Add(
157+
new CodeAttributeDeclaration(
158+
new CodeTypeReference(typeof(CompilerGeneratedAttribute))));
159+
return result;
160+
}
161+
}
162+
}

Generator/Configuration/GeneratorConfiguration.cs

+8-7
Original file line numberDiff line numberDiff line change
@@ -17,13 +17,12 @@ public class GeneratorConfiguration
1717

1818
// generator settings
1919
public bool AllowDebugGeneratedFiles { get; set; }
20-
20+
2121
public GeneratorConfiguration()
2222
{
2323
FeatureLanguage = CultureInfo.GetCultureInfo(ConfigDefaults.FeatureLanguage);
24-
ToolLanguage = string.IsNullOrEmpty(ConfigDefaults.ToolLanguage) ?
25-
FeatureLanguage :
26-
CultureInfo.GetCultureInfo(ConfigDefaults.ToolLanguage);
24+
ToolLanguage = string.IsNullOrEmpty(ConfigDefaults.ToolLanguage) ? FeatureLanguage :
25+
CultureInfo.GetCultureInfo(ConfigDefaults.ToolLanguage);
2726

2827
SetUnitTestDefaultsByName(ConfigDefaults.UnitTestProviderName);
2928

@@ -37,9 +36,8 @@ internal void UpdateFromConfigFile(ConfigurationSectionHandler configSection)
3736
if (configSection.Language != null)
3837
{
3938
FeatureLanguage = CultureInfo.GetCultureInfo(configSection.Language.Feature);
40-
ToolLanguage = string.IsNullOrEmpty(configSection.Language.Tool) ?
41-
FeatureLanguage :
42-
CultureInfo.GetCultureInfo(configSection.Language.Tool);
39+
ToolLanguage = string.IsNullOrEmpty(configSection.Language.Tool) ? FeatureLanguage :
40+
CultureInfo.GetCultureInfo(configSection.Language.Tool);
4341
}
4442

4543
if (configSection.UnitTestProvider != null)
@@ -71,6 +69,9 @@ private void SetUnitTestDefaultsByName(string name)
7169
case "nunit":
7270
GeneratorUnitTestProviderType = typeof(NUnitTestConverter);
7371
break;
72+
case "xunit":
73+
GeneratorUnitTestProviderType = typeof(XUnitTestGeneratorProvider);
74+
break;
7475
case "mstest":
7576
GeneratorUnitTestProviderType = typeof(MsTestGeneratorProvider);
7677
break;

Generator/SpecFlowGenerator.cs

+18-6
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@
1010
using Microsoft.CSharp;
1111
using TechTalk.SpecFlow.Configuration;
1212
using TechTalk.SpecFlow.Generator.Configuration;
13+
using TechTalk.SpecFlow.Generator.UnitTestConverter;
1314
using TechTalk.SpecFlow.Generator.UnitTestProvider;
1415
using TechTalk.SpecFlow.Parser;
1516
using TechTalk.SpecFlow.Parser.SyntaxElements;
@@ -77,7 +78,7 @@ public override Encoding Encoding
7778
get { return innerWriter.Encoding; }
7879
}
7980

80-
static public readonly Regex indentNextRe = new Regex(@"^[\s\/\']*#indentnext (?<ind>\d+)\s*$");
81+
static private readonly Regex indentNextRe = new Regex(@"^[\s\/\']*#indentnext (?<ind>\d+)\s*$");
8182

8283
public override void WriteLine(string text)
8384
{
@@ -114,27 +115,31 @@ public void GenerateTestFile(SpecFlowFeatureFile featureFile, CodeDomProvider co
114115
{
115116
outputWriter = new HackedWriter(outputWriter);
116117

117-
var codeNamespace = GenerateTestFileCode(featureFile, inputReader);
118+
CodeDomHelper codeDomHelper = new CodeDomHelper(codeProvider);
119+
120+
var codeNamespace = GenerateTestFileCode(featureFile, inputReader, codeProvider, codeDomHelper);
118121
var options = new CodeGeneratorOptions
119122
{
120123
BracingStyle = "C"
121124
};
122125

123-
AddSpecFlowHeader(codeProvider, outputWriter);
126+
AddSpecFlowHeader(codeProvider, outputWriter, codeDomHelper);
124127
codeProvider.GenerateCodeFromNamespace(codeNamespace, outputWriter, options);
128+
AddSpecFlowFooter(codeProvider, outputWriter, codeDomHelper);
125129
outputWriter.Flush();
126130
}
127131

128-
public CodeNamespace GenerateTestFileCode(SpecFlowFeatureFile featureFile, TextReader inputReader)
132+
public CodeNamespace GenerateTestFileCode(SpecFlowFeatureFile featureFile, TextReader inputReader, CodeDomProvider codeProvider, CodeDomHelper codeDomHelper)
129133
{
130134
string targetNamespace = GetTargetNamespace(featureFile);
131135

132136
SpecFlowLangParser parser = new SpecFlowLangParser(project.GeneratorConfiguration.FeatureLanguage);
133137
Feature feature = parser.Parse(inputReader, featureFile.GetFullPath(project));
134138

135139
IUnitTestGeneratorProvider generatorProvider = ConfigurationServices.CreateInstance<IUnitTestGeneratorProvider>(project.GeneratorConfiguration.GeneratorUnitTestProviderType);
140+
codeDomHelper.InjectIfRequired(generatorProvider);
136141

137-
SpecFlowUnitTestConverter testConverter = new SpecFlowUnitTestConverter(generatorProvider, project.GeneratorConfiguration.AllowDebugGeneratedFiles);
142+
ISpecFlowUnitTestConverter testConverter = new SpecFlowUnitTestConverter(generatorProvider, codeDomHelper, project.GeneratorConfiguration.AllowDebugGeneratedFiles);
138143

139144
var codeNamespace = testConverter.GenerateUnitTestFixture(feature, null, targetNamespace);
140145
return codeNamespace;
@@ -164,7 +169,7 @@ private string GetTargetNamespace(SpecFlowFeatureFile featureFile)
164169
return targetNamespace;
165170
}
166171

167-
private void AddSpecFlowHeader(CodeDomProvider codeProvider, TextWriter outputWriter)
172+
private void AddSpecFlowHeader(CodeDomProvider codeProvider, TextWriter outputWriter, CodeDomHelper codeDomHelper)
168173
{
169174
var specFlowHeaderTemplate = @"------------------------------------------------------------------------------
170175
<auto-generated>
@@ -187,6 +192,13 @@ the code is regenerated.
187192
{
188193
codeProvider.GenerateCodeFromStatement(new CodeCommentStatement(line), outputWriter, null);
189194
}
195+
196+
codeProvider.GenerateCodeFromStatement(codeDomHelper.GetStartRegionStatement("Designer generated code"), outputWriter, null);
197+
}
198+
199+
private void AddSpecFlowFooter(CodeDomProvider codeProvider, TextWriter outputWriter, CodeDomHelper codeDomHelper)
200+
{
201+
codeProvider.GenerateCodeFromStatement(codeDomHelper.GetEndRegionStatement(), outputWriter, null);
190202
}
191203

192204
public Version GetCurrentSpecFlowVersion()

0 commit comments

Comments
 (0)