Skip to content

Commit bb13ec7

Browse files
authored
Integrated two new UnitTests using Roslyn and ThorAnalyzer to validate the generated code.
Integrated two new UnitTests using Roslyn and ThorAnalyzer to validate the generated code.
2 parents 3692ba6 + e0db9ab commit bb13ec7

14 files changed

+615
-49
lines changed
Lines changed: 178 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,178 @@
1+
using System;
2+
using System.Collections.Generic;
3+
using System.Diagnostics.Tracing;
4+
using System.IO;
5+
using System.Linq;
6+
using System.Reflection;
7+
using Microsoft.CodeAnalysis;
8+
using Microsoft.CodeAnalysis.CSharp;
9+
using Microsoft.CodeAnalysis.Emit;
10+
using Microsoft.CodeAnalysis.Host;
11+
using Thor.Analyzer;
12+
using Thor.Generator.Properties;
13+
using Thor.Generator.Templates;
14+
using Xunit;
15+
16+
namespace Thor.Generator
17+
{
18+
public class CompilationTests
19+
{
20+
[Fact]
21+
public void AnalyzeCsharpComplexEventSource()
22+
{
23+
// arrange
24+
TemplateStorage templateStorage = new TemplateStorage();
25+
Template template = templateStorage.GetCustomTemplate("Defaults\\CSharpWithComplexLight");
26+
27+
EventSourceDefinitionVisitor eventSourceDefinitionVisitor = new EventSourceDefinitionVisitor();
28+
SyntaxTree syntaxTree = CSharpSyntaxTree.ParseText(Resources.EventSourceWithComplexTypeThatBuilds);
29+
eventSourceDefinitionVisitor.Visit(syntaxTree.GetRoot());
30+
31+
CodeEventAnalyzer analyzer = new CodeEventAnalyzer(new[]
32+
{
33+
MetadataReference.CreateFromFile(typeof(Core.Application).GetTypeInfo().Assembly.Location),
34+
MetadataReference.CreateFromFile(typeof(Core.Abstractions.EventSourceBase).GetTypeInfo().Assembly.Location),
35+
});
36+
37+
// act
38+
EventSourceTemplateEngine templateEngine = new EventSourceTemplateEngine(template);
39+
string eventSourceCode = templateEngine.Generate(eventSourceDefinitionVisitor.EventSource);
40+
Report report = analyzer.CompileAndAnalyze(eventSourceCode, "EventSources.FooEventSource");
41+
42+
// assert
43+
Assert.NotNull(report);
44+
Assert.False(report.HasErrors);
45+
}
46+
47+
[Fact]
48+
public void AnalyzeCsharpSimpleEventSource()
49+
{
50+
// arrange
51+
TemplateStorage templateStorage = new TemplateStorage();
52+
Template template = templateStorage.GetCustomTemplate("Defaults\\CSharpLight");
53+
54+
EventSourceDefinitionVisitor eventSourceDefinitionVisitor = new EventSourceDefinitionVisitor();
55+
SyntaxTree syntaxTree = CSharpSyntaxTree.ParseText(Resources.EventSourceThatBuilds);
56+
eventSourceDefinitionVisitor.Visit(syntaxTree.GetRoot());
57+
58+
CodeEventAnalyzer analyzer = new CodeEventAnalyzer();
59+
60+
// act
61+
EventSourceTemplateEngine templateEngine = new EventSourceTemplateEngine(template);
62+
string eventSourceCode = templateEngine.Generate(eventSourceDefinitionVisitor.EventSource);
63+
Report report = analyzer.CompileAndAnalyze(eventSourceCode, "EventSources.BarEventSource");
64+
65+
// assert
66+
Assert.NotNull(report);
67+
Assert.False(report.HasErrors);
68+
}
69+
}
70+
71+
public class CodeEventAnalyzer
72+
{
73+
private IReadOnlyCollection<MetadataReference> _references;
74+
75+
76+
public CodeEventAnalyzer()
77+
{
78+
_references = GetBaseAssemblies();
79+
}
80+
81+
public CodeEventAnalyzer(ICollection<PortableExecutableReference> references)
82+
{
83+
_references = GetBaseAssemblies().Union(references).ToList();
84+
}
85+
86+
public Report CompileAndAnalyze(string code, string className)
87+
{
88+
Assembly assembly = CreateAssemblyDefinition(code);
89+
90+
Type type = assembly.GetType(className);
91+
EventSource eventSource = (EventSource) type.GetMethod("CreateInstance").Invoke(null, null);
92+
93+
return Analyze(eventSource);
94+
}
95+
96+
private Report Analyze(EventSource eventSource)
97+
{
98+
EventSourceAnalyzer analyzer = new EventSourceAnalyzer();
99+
return analyzer.Inspect(eventSource);
100+
}
101+
102+
private Assembly CreateAssemblyDefinition(string code)
103+
{
104+
CSharpLanguage sourceLanguage = new CSharpLanguage();
105+
SyntaxTree syntaxTree = sourceLanguage.ParseText(code, SourceCodeKind.Regular);
106+
107+
Compilation compilation = sourceLanguage
108+
.CreateLibraryCompilation(assemblyName: "InMemoryAssembly", enableOptimisations: false)
109+
.AddReferences(_references)
110+
.AddSyntaxTrees(syntaxTree);
111+
112+
MemoryStream stream = new MemoryStream();
113+
EmitResult emitResult = compilation.Emit(stream);
114+
115+
if (emitResult.Success)
116+
{
117+
stream.Seek(0, SeekOrigin.Begin);
118+
119+
using (stream)
120+
{
121+
byte[] data = new byte[stream.Length];
122+
stream.Read(data, 0, data.Length);
123+
return Assembly.Load(data);
124+
}
125+
}
126+
127+
return null;
128+
}
129+
130+
private List<PortableExecutableReference> GetBaseAssemblies()
131+
{
132+
string[] trustedAssembliesPaths = ((string)AppContext.GetData("TRUSTED_PLATFORM_ASSEMBLIES")).Split(Path.PathSeparator);
133+
List<PortableExecutableReference> references = trustedAssembliesPaths
134+
.Select(p => MetadataReference.CreateFromFile(p))
135+
.ToList();
136+
137+
references.AddRange(new[]
138+
{
139+
MetadataReference.CreateFromFile(typeof(EventSource).GetTypeInfo().Assembly.Location),
140+
});
141+
142+
return references;
143+
}
144+
}
145+
146+
public class CSharpLanguage : ILanguageService
147+
{
148+
private readonly IReadOnlyCollection<MetadataReference> _references = new[]
149+
{
150+
MetadataReference.CreateFromFile(typeof(Binder).GetTypeInfo().Assembly.Location),
151+
MetadataReference.CreateFromFile(typeof(ValueTuple<>).GetTypeInfo().Assembly.Location)
152+
};
153+
154+
private readonly LanguageVersion _maxLanguageVersion = Enum
155+
.GetValues(typeof(LanguageVersion))
156+
.Cast<LanguageVersion>()
157+
.Max();
158+
159+
public SyntaxTree ParseText(string sourceCode, SourceCodeKind kind)
160+
{
161+
CSharpParseOptions options = new CSharpParseOptions(kind: kind, languageVersion: _maxLanguageVersion);
162+
163+
// Return a syntax tree of our source code
164+
return CSharpSyntaxTree.ParseText(sourceCode, options);
165+
}
166+
167+
168+
public Compilation CreateLibraryCompilation(string assemblyName, bool enableOptimisations)
169+
{
170+
CSharpCompilationOptions options = new CSharpCompilationOptions(
171+
OutputKind.DynamicallyLinkedLibrary,
172+
optimizationLevel: enableOptimisations ? OptimizationLevel.Release : OptimizationLevel.Debug,
173+
allowUnsafe: true);
174+
175+
return CSharpCompilation.Create(assemblyName, options: options, references: _references);
176+
}
177+
}
178+
}

src/Generator.Tests/Generator.Tests.csproj

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,9 @@
1414
<PackageReference Include="Microsoft.CodeCoverage" Version="1.0.3" />
1515
<PackageReference Include="moq" Version="4.7.99" />
1616
<PackageReference Include="OpenCover" Version="4.6.519" />
17+
<PackageReference Include="Thor.Analyzer" Version="1.0.4" />
18+
<PackageReference Include="Thor.Core" Version="1.0.0-preview2" />
19+
<PackageReference Include="Thor.Core.Abstractions" Version="1.0.0-preview2" />
1720
<PackageReference Include="xunit" Version="2.3.1" />
1821
<PackageReference Include="xunit.runner.visualstudio" Version="2.3.1" />
1922
</ItemGroup>

src/Generator.Tests/Properties/Resources.Designer.cs

Lines changed: 50 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

src/Generator.Tests/Properties/Resources.resx

Lines changed: 50 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -117,6 +117,31 @@
117117
<resheader name="writer">
118118
<value>System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
119119
</resheader>
120+
<data name="EventSourceThatBuilds" xml:space="preserve">
121+
<value>using System;
122+
using System.Diagnostics.Tracing;
123+
using Thor.Core.Abstractions;
124+
125+
namespace EventSources
126+
{
127+
[EventSourceDefinition(Name = "BarEventSource")]
128+
public interface IBarEventSource
129+
{
130+
[Event(1,
131+
Level = EventLevel.Verbose,
132+
Message = "Sent message {correlationId}/{messageType} to {to}.",
133+
Version = 1)]
134+
void One(string ex, Guid correlationId, string messageType, string from, string to);
135+
136+
[Event(2,
137+
Level = EventLevel.Verbose,
138+
Message = "Sent message {correlationId}/{messageType} to {to}.",
139+
Version = 1)]
140+
void Two(Guid messageId, Guid correlationId, string messageType, string from, string to);
141+
}
142+
}
143+
</value>
144+
</data>
120145
<data name="EventSourceWithComplexType" xml:space="preserve">
121146
<value>using System;
122147
using System.Linq;
@@ -145,6 +170,31 @@ namespace EventSources
145170
void Two(Guid messageId, Guid correlationId, string messageType, string from, string to);
146171
}
147172
}
173+
</value>
174+
</data>
175+
<data name="EventSourceWithComplexTypeThatBuilds" xml:space="preserve">
176+
<value>using System;
177+
using System.Diagnostics.Tracing;
178+
using Thor.Core.Abstractions;
179+
180+
namespace EventSources
181+
{
182+
[EventSourceDefinition(Name = "FooEventSource")]
183+
public interface IFooEventSource
184+
{
185+
[Event(3,
186+
Level = EventLevel.Verbose,
187+
Message = "Sent message {correlationId}/{messageType} to {to}.",
188+
Version = 1)]
189+
void Three(Exception ex, Guid correlationId, string messageType, string from, string to);
190+
191+
[Event(4,
192+
Level = EventLevel.Verbose,
193+
Message = "Sent message {correlationId}/{messageType} to {to}.",
194+
Version = 1)]
195+
void Four(Guid messageId, Guid correlationId, string messageType, string from, string to);
196+
}
197+
}
148198
</value>
149199
</data>
150200
<data name="EventSourceWithConstant" xml:space="preserve">

src/Generator/Generator.csproj

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,8 @@
1818
<ItemGroup>
1919
<PackageReference Include="Newtonsoft.Json" Version="10.0.3" />
2020
<PackageReference Include="nustache.core" Version="1.0.0-alfa2" />
21+
<PackageReference Include="Thor.Core" Version="1.0.0-preview1" />
22+
<PackageReference Include="Thor.Core.Abstractions" Version="1.0.0-preview1" />
2123
</ItemGroup>
2224

2325
<ItemGroup>
@@ -41,12 +43,24 @@
4143
</ItemGroup>
4244

4345
<ItemGroup>
46+
<None Update="Templates\Defaults\CSharpLight.json">
47+
<CopyToOutputDirectory>Always</CopyToOutputDirectory>
48+
</None>
49+
<None Update="Templates\Defaults\CSharpLight.mustache">
50+
<CopyToOutputDirectory>Always</CopyToOutputDirectory>
51+
</None>
4452
<None Update="Templates\Defaults\CSharp.json">
4553
<CopyToOutputDirectory>Always</CopyToOutputDirectory>
4654
</None>
4755
<None Update="Templates\Defaults\CSharp.mustache">
4856
<CopyToOutputDirectory>Always</CopyToOutputDirectory>
4957
</None>
58+
<None Update="Templates\Defaults\CSharpWithComplexLight.json">
59+
<CopyToOutputDirectory>Always</CopyToOutputDirectory>
60+
</None>
61+
<None Update="Templates\Defaults\CSharpWithComplexLight.mustache">
62+
<CopyToOutputDirectory>Always</CopyToOutputDirectory>
63+
</None>
5064
<None Update="Templates\Defaults\CSharpWithComplex.json">
5165
<CopyToOutputDirectory>Always</CopyToOutputDirectory>
5266
</None>
Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
{
2+
"defaultPayloads": 0,
3+
"baseWriteMethods": [
4+
[]
5+
],
6+
"packageDependencies": [
7+
{
8+
"id": "Thor.Core",
9+
"version": "1.0.0-preview2"
10+
},
11+
{
12+
"id": "Thor.Core.Abstractions",
13+
"version": "1.0.0-preview2"
14+
}
15+
],
16+
"Usings": [
17+
{
18+
"namespace": "Thor.Core"
19+
},
20+
{
21+
"namespace": "Thor.Core.Abstractions"
22+
},
23+
{
24+
"namespace": "System.Collections.Generic"
25+
}
26+
]
27+
}

0 commit comments

Comments
 (0)