Skip to content

Commit b82519e

Browse files
committed
Feat: spinning off of CodeOfChaos.Testing
1 parent 6400d58 commit b82519e

14 files changed

+380
-167
lines changed

CodeOfChaos.Testing.TUnit.sln

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,8 @@ Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "tools", "tools", "{AF1A203C
1212
EndProject
1313
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Tools.CodeOfChaos.Testing.TUnit", "src\Tools.CodeOfChaos.Testing.TUnit\Tools.CodeOfChaos.Testing.TUnit.csproj", "{ADEADD97-0AFA-4D9E-970B-9FFB932949B3}"
1414
EndProject
15+
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "CodeOfChaos.Testing", "src\CodeOfChaos.Testing\CodeOfChaos.Testing.csproj", "{AADC19E6-F488-4691-97FF-D6CD37B78848}"
16+
EndProject
1517
Global
1618
GlobalSection(SolutionConfigurationPlatforms) = preSolution
1719
Debug|Any CPU = Debug|Any CPU
@@ -30,10 +32,15 @@ Global
3032
{ADEADD97-0AFA-4D9E-970B-9FFB932949B3}.Debug|Any CPU.Build.0 = Debug|Any CPU
3133
{ADEADD97-0AFA-4D9E-970B-9FFB932949B3}.Release|Any CPU.ActiveCfg = Release|Any CPU
3234
{ADEADD97-0AFA-4D9E-970B-9FFB932949B3}.Release|Any CPU.Build.0 = Release|Any CPU
35+
{AADC19E6-F488-4691-97FF-D6CD37B78848}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
36+
{AADC19E6-F488-4691-97FF-D6CD37B78848}.Debug|Any CPU.Build.0 = Debug|Any CPU
37+
{AADC19E6-F488-4691-97FF-D6CD37B78848}.Release|Any CPU.ActiveCfg = Release|Any CPU
38+
{AADC19E6-F488-4691-97FF-D6CD37B78848}.Release|Any CPU.Build.0 = Release|Any CPU
3339
EndGlobalSection
3440
GlobalSection(NestedProjects) = preSolution
3541
{26284571-0E09-4BAF-8C2B-DF87DCC1BA0B} = {8DD280D4-1E14-4D5E-AFE6-58DD8F079DCC}
3642
{64B26DED-68C3-47FF-B409-1C8FAD4F9176} = {197E72AD-DEAB-4350-AFC3-A3BB38720BF5}
3743
{ADEADD97-0AFA-4D9E-970B-9FFB932949B3} = {AF1A203C-6EF1-440E-BB3C-55B1DBFE9C19}
44+
{AADC19E6-F488-4691-97FF-D6CD37B78848} = {197E72AD-DEAB-4350-AFC3-A3BB38720BF5}
3845
EndGlobalSection
3946
EndGlobal

src/CodeOfChaos.Testing.TUnit/CodeOfChaos.Testing.TUnit.csproj

Lines changed: 10 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -23,19 +23,19 @@
2323
</PropertyGroup>
2424

2525
<ItemGroup>
26-
<None Include="../../LICENSE" Pack="true" PackagePath="" Visible="false" />
27-
<None Include="../../README.md" Pack="true" PackagePath="" Visible="false" />
28-
<None Include="../../assets/icon.png" Pack="true" PackagePath="" Visible="false" />
26+
<None Include="../../LICENSE" Pack="true" PackagePath="" Visible="false"/>
27+
<None Include="../../README.md" Pack="true" PackagePath="" Visible="false"/>
28+
<None Include="../../assets/icon.png" Pack="true" PackagePath="" Visible="false"/>
2929
</ItemGroup>
3030

3131
<ItemGroup>
32-
<PackageReference Include="JetBrains.Annotations" Version="2024.3.0" />
33-
<PackageReference Include="Microsoft.CodeAnalysis.Analyzers" Version="3.11.0" />
34-
<PackageReference Include="Microsoft.CodeAnalysis.Common" Version="4.12.0" />
35-
<PackageReference Include="Microsoft.CodeAnalysis.CSharp" Version="4.12.0" />
36-
<PackageReference Include="Microsoft.CodeAnalysis.CSharp.Workspaces" Version="4.12.0" />
37-
<PackageReference Include="TUnit.Assertions" Version="0.12.14" />
38-
<PackageReference Include="TUnit.Core" Version="0.12.14" />
32+
<PackageReference Include="JetBrains.Annotations" Version="2024.3.0"/>
33+
<PackageReference Include="TUnit.Assertions" Version="0.12.14"/>
34+
<PackageReference Include="TUnit.Core" Version="0.12.14"/>
35+
</ItemGroup>
36+
37+
<ItemGroup>
38+
<ProjectReference Include="..\CodeOfChaos.Testing\CodeOfChaos.Testing.csproj"/>
3939
</ItemGroup>
4040

4141
</Project>
Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
1-
<wpf:ResourceDictionary xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" xmlns:s="clr-namespace:System;assembly=mscorlib"
1+
<wpf:ResourceDictionary xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
2+
xmlns:s="clr-namespace:System;assembly=mscorlib"
23
xmlns:wpf="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
34
xml:space="preserve">
45
<s:Boolean x:Key="/Default/CodeInspection/NamespaceProvider/NamespaceFoldersToSkip/=extensions/@EntryIndexedValue">True</s:Boolean></wpf:ResourceDictionary>

src/CodeOfChaos.Testing.TUnit/Conditions/GeneratorDriverRunResultHasSourceTextEqualToCondition.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -34,6 +34,6 @@ protected override async Task<AssertionResult> GetResult(GeneratorDriverRunResul
3434
if (withTrimming) stringEqualsAssertCondition.WithTrimming();
3535
if (ignoreWhiteSpace) stringEqualsAssertCondition.IgnoringWhitespace();
3636

37-
return await stringEqualsAssertCondition.GetAssertionResult(sourceTextString,null, assertionMetadata);
37+
return await stringEqualsAssertCondition.GetAssertionResult(sourceTextString, null, assertionMetadata);
3838
}
3939
}

src/CodeOfChaos.Testing.TUnit/Conditions/Library/ContainsDiagnosticAssertCondition.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,7 @@ public class ContainsDiagnosticAssertCondition<T>(Func<T, ValueTask<ImmutableArr
1414
// Methods
1515
// -----------------------------------------------------------------------------------------------------------------
1616
protected override string GetExpectation() => $"to have a diagnostic with Id \"{expectedId}\"";
17-
17+
1818
protected override async Task<AssertionResult> GetResult(T? actualValue, Exception? exception, AssertionMetadata assertionMetadata) {
1919
if (actualValue is null) return AssertionResult.Fail($"{nameof(T)} is null");
2020

src/CodeOfChaos.Testing.TUnit/Conditions/Library/DoesNotContainDiagnosticAssertCondition.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -21,7 +21,7 @@ protected override async Task<AssertionResult> GetResult(T? actualValue, Excepti
2121

2222
ImmutableArray<Diagnostic> diagnostics = await getDiagnosticsAction(actualValue);
2323

24-
return diagnostics.Any(d => d.Id == expectedId)
24+
return diagnostics.Any(d => d.Id == expectedId)
2525
? FailWithMessage("Diagnostic with Id")
2626
: AssertionResult.Passed;
2727
}

src/CodeOfChaos.Testing.TUnit/RoslynGeneratorRunner.cs

Lines changed: 0 additions & 27 deletions
This file was deleted.
Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
<Project Sdk="Microsoft.NET.Sdk">
2+
3+
<PropertyGroup>
4+
<TargetFramework>net9.0</TargetFramework>
5+
<ImplicitUsings>enable</ImplicitUsings>
6+
<Nullable>enable</Nullable>
7+
</PropertyGroup>
8+
9+
<ItemGroup>
10+
<PackageReference Include="JetBrains.Annotations" Version="2024.3.0"/>
11+
<PackageReference Include="Microsoft.CodeAnalysis.CSharp" Version="4.12.0"/>
12+
<PackageReference Include="Microsoft.CodeAnalysis.Workspaces.Common" Version="4.12.0"/>
13+
</ItemGroup>
14+
15+
</Project>
Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
// ---------------------------------------------------------------------------------------------------------------------
2+
// Imports
3+
// ---------------------------------------------------------------------------------------------------------------------
4+
using Microsoft.CodeAnalysis;
5+
using System.Reflection;
6+
7+
namespace CodeOfChaos.Testing;
8+
// ---------------------------------------------------------------------------------------------------------------------
9+
// Code
10+
// ---------------------------------------------------------------------------------------------------------------------
11+
public static class Extensions {
12+
public static PortableExecutableReference GetPortableExecutableReference(this Assembly assembly) => MetadataReference.CreateFromFile(assembly.Location);
13+
public static PortableExecutableReference GetPortableExecutableReference(this Type type) => MetadataReference.CreateFromFile(type.Assembly.Location);
14+
}
Lines changed: 118 additions & 124 deletions
Original file line numberDiff line numberDiff line change
@@ -1,124 +1,118 @@
1-
// ---------------------------------------------------------------------------------------------------------------------
2-
// Imports
3-
// ---------------------------------------------------------------------------------------------------------------------
4-
using JetBrains.Annotations;
5-
using Microsoft.CodeAnalysis;
6-
using Microsoft.CodeAnalysis.CSharp;
7-
using Microsoft.CodeAnalysis.Diagnostics;
8-
using System.Collections.Concurrent;
9-
using System.Collections.Immutable;
10-
using System.Reflection;
11-
using System.Text;
12-
13-
namespace CodeOfChaos.Testing.TUnit;
14-
// ---------------------------------------------------------------------------------------------------------------------
15-
// Code
16-
// ---------------------------------------------------------------------------------------------------------------------
17-
public class RoslynCompilationRunner(string? name = null, LanguageVersion languageVersion = LanguageVersion.Latest) : IDisposable {
18-
19-
private readonly ConcurrentBag<MetadataReference> _assemblyReferences = [
20-
// Some default assemblies
21-
GetMetadataReference(typeof(string).Assembly),
22-
GetMetadataReference(typeof(object).Assembly)
23-
];
24-
private readonly ConcurrentBag<(string Name, StringBuilder Source)> _documents = new();
25-
26-
private Project? _project;
27-
private string Name { get; } = name ?? $"TestProject_{Guid.NewGuid()}";
28-
private Lazy<AdhocWorkspace> Workspace { get; } = new(() => new AdhocWorkspace());
29-
private Project Project {
30-
get => _project ??= Workspace.Value.CurrentSolution
31-
.AddProject(Name, $"{Name}.dll", "C#")
32-
.WithCompilationOptions(new CSharpCompilationOptions(OutputKind.DynamicallyLinkedLibrary).WithPlatform(Platform.AnyCpu))
33-
.WithParseOptions(new CSharpParseOptions(languageVersion));
34-
set => _project = value;
35-
}
36-
37-
public void Dispose() {
38-
if (Workspace.IsValueCreated) {
39-
Workspace.Value.Dispose();
40-
}
41-
42-
GC.SuppressFinalize(this);
43-
}
44-
45-
// -----------------------------------------------------------------------------------------------------------------
46-
// Methods
47-
// -----------------------------------------------------------------------------------------------------------------
48-
#region Add Documents
49-
public RoslynCompilationRunner AddDocument(string name, [LanguageInjection("CSharp")] string source) {
50-
_documents.Add((name, new StringBuilder(source)));
51-
return this;
52-
}
53-
#endregion
54-
55-
public async ValueTask<RoslynGeneratorRunner> GetGeneratorRunnerAsync() {
56-
Compilation compilation = await GetCompilationAsync();
57-
return new RoslynGeneratorRunner(languageVersion) {
58-
Compilation = compilation
59-
};
60-
}
61-
62-
public async ValueTask<Compilation> GetCompilationAsync() {
63-
// Resolve all assemblies
64-
Project = _assemblyReferences.Aggregate(Project, func: (current, reference) => current.AddMetadataReference(reference));
65-
66-
// Add All documents
67-
foreach ((string name, StringBuilder source) in _documents) {
68-
Project = Project.AddDocument(name, source.ToString()).Project;
69-
}
70-
71-
// Compile the project
72-
Compilation? compilation = await Project.GetCompilationAsync();
73-
74-
await Assert.That(compilation).IsNotNull();
75-
76-
return compilation!;
77-
}
78-
79-
public async ValueTask<CompilationWithAnalyzers> GetCompilationWithAnalyzersAsync() {
80-
// Resolve all assemblies
81-
Project = _assemblyReferences.Aggregate(Project, func: (current, reference) => current.AddMetadataReference(reference));
82-
83-
// Add All documents
84-
foreach ((string name, StringBuilder source) in _documents) {
85-
Project = Project.AddDocument(name, source.ToString()).Project;
86-
}
87-
88-
// Add Analyzers to the compilation phase
89-
ImmutableArray<DiagnosticAnalyzer> analyzers = Project.AnalyzerReferences
90-
.OfType<AnalyzerImageReference>()// Ensures we only get valid analyzers
91-
.SelectMany(reference => reference.GetAnalyzers(LanguageNames.CSharp))
92-
.ToImmutableArray();
93-
94-
// Compile the project
95-
Compilation? compilation = await Project.GetCompilationAsync();
96-
await Assert.That(compilation).IsNotNull();
97-
98-
return compilation!.WithAnalyzers(analyzers);
99-
}
100-
101-
102-
public RoslynCompilationRunner AddDiagnosticAnalyzer<T>() where T : DiagnosticAnalyzer, new() {
103-
IReadOnlyList<AnalyzerReference> currentAnalyzers = Project.AnalyzerReferences;
104-
AnalyzerReference[] newAnalyzers = [new AnalyzerImageReference([new T()])];
105-
106-
Project = Project.WithAnalyzerReferences(currentAnalyzers.Concat(newAnalyzers));
107-
108-
return this;
109-
}
110-
#region Add Assembly references
111-
public RoslynCompilationRunner AddReferences(params Span<Assembly> assemblies) {
112-
foreach (Assembly assembly in assemblies) _assemblyReferences.Add(GetMetadataReference(assembly));
113-
return this;
114-
}
115-
116-
public RoslynCompilationRunner AddReferences(params Span<Type> types) {
117-
foreach (Type type in types) _assemblyReferences.Add(GetMetadataReference(type));
118-
return this;
119-
}
120-
121-
private static PortableExecutableReference GetMetadataReference(Assembly assembly) => MetadataReference.CreateFromFile(assembly.Location);
122-
private static PortableExecutableReference GetMetadataReference(Type type) => GetMetadataReference(type.Assembly);
123-
#endregion
124-
}
1+
// ---------------------------------------------------------------------------------------------------------------------
2+
// Imports
3+
// ---------------------------------------------------------------------------------------------------------------------
4+
using JetBrains.Annotations;
5+
using Microsoft.CodeAnalysis;
6+
using Microsoft.CodeAnalysis.CSharp;
7+
using Microsoft.CodeAnalysis.Diagnostics;
8+
using System.Collections.Concurrent;
9+
using System.Collections.Immutable;
10+
using System.Reflection;
11+
using System.Text;
12+
13+
namespace CodeOfChaos.Testing;
14+
// ---------------------------------------------------------------------------------------------------------------------
15+
// Code
16+
// ---------------------------------------------------------------------------------------------------------------------
17+
public class RoslynCompilationRunner(string? name = null, LanguageVersion languageVersion = LanguageVersion.Latest) : IDisposable {
18+
19+
private readonly ConcurrentBag<MetadataReference> _assemblyReferences = [
20+
// Some default assemblies
21+
typeof(string).GetPortableExecutableReference(),
22+
typeof(object).GetPortableExecutableReference()
23+
];
24+
private readonly ConcurrentBag<(string Name, StringBuilder Source)> _documents = new();
25+
26+
private Project? _project;
27+
28+
private string Name { get; } = name ?? $"TestProject_{Guid.NewGuid()}";
29+
private Lazy<AdhocWorkspace> Workspace { get; } = new(() => new AdhocWorkspace());
30+
private Project Project {
31+
get => _project ??= Workspace.Value.CurrentSolution
32+
.AddProject(Name, $"{Name}.dll", "C#")
33+
.WithCompilationOptions(new CSharpCompilationOptions(OutputKind.DynamicallyLinkedLibrary).WithPlatform(Platform.AnyCpu))
34+
.WithParseOptions(new CSharpParseOptions(languageVersion));
35+
set => _project = value;
36+
}
37+
38+
public void Dispose() {
39+
if (Workspace.IsValueCreated) {
40+
Workspace.Value.Dispose();
41+
}
42+
43+
GC.SuppressFinalize(this);
44+
}
45+
46+
// -----------------------------------------------------------------------------------------------------------------
47+
// Methods
48+
// -----------------------------------------------------------------------------------------------------------------
49+
public RoslynCompilationRunner AddDocument(string name, [LanguageInjection("CSharp")] string source) {
50+
_documents.Add((name, new StringBuilder(source)));
51+
return this;
52+
}
53+
54+
public async ValueTask<RoslynGeneratorRunner> GetGeneratorRunnerAsync() {
55+
Compilation compilation = await GetCompilationAsync();
56+
return new RoslynGeneratorRunner(languageVersion) {
57+
Compilation = compilation
58+
};
59+
}
60+
61+
public async ValueTask<Compilation> GetCompilationAsync() {
62+
// Resolve all assemblies
63+
Project = _assemblyReferences.Aggregate(Project, func: (current, reference) => current.AddMetadataReference(reference));
64+
65+
// Add All documents
66+
foreach ((string name, StringBuilder source) in _documents) {
67+
Project = Project.AddDocument(name, source.ToString()).Project;
68+
}
69+
70+
// Compile the project
71+
Compilation? compilation = await Project.GetCompilationAsync();
72+
if (compilation is null) throw new InvalidOperationException("Compilation is null");
73+
74+
return compilation;
75+
}
76+
77+
public async ValueTask<CompilationWithAnalyzers> GetCompilationWithAnalyzersAsync() {
78+
// Resolve all assemblies
79+
Project = _assemblyReferences.Aggregate(Project, func: (current, reference) => current.AddMetadataReference(reference));
80+
81+
// Add All documents
82+
foreach ((string name, StringBuilder source) in _documents) {
83+
Project = Project.AddDocument(name, source.ToString()).Project;
84+
}
85+
86+
// Add Analyzers to the compilation phase
87+
ImmutableArray<DiagnosticAnalyzer> analyzers = Project.AnalyzerReferences
88+
.OfType<AnalyzerImageReference>()// Ensures we only get valid analyzers
89+
.SelectMany(reference => reference.GetAnalyzers(LanguageNames.CSharp))
90+
.ToImmutableArray();
91+
92+
// Compile the project
93+
Compilation? compilation = await Project.GetCompilationAsync();
94+
if (compilation is null) throw new InvalidOperationException("Compilation is null");
95+
96+
return compilation.WithAnalyzers(analyzers);
97+
}
98+
99+
public RoslynCompilationRunner AddDiagnosticAnalyzer<T>() where T : DiagnosticAnalyzer, new() {
100+
IReadOnlyList<AnalyzerReference> currentAnalyzers = Project.AnalyzerReferences;
101+
AnalyzerReference[] newAnalyzers = [new AnalyzerImageReference([new T()])];
102+
103+
Project = Project.WithAnalyzerReferences(currentAnalyzers.Concat(newAnalyzers));
104+
105+
return this;
106+
}
107+
#region Add Assembly references
108+
public RoslynCompilationRunner AddReferences(params Span<Assembly> assemblies) {
109+
foreach (Assembly assembly in assemblies) _assemblyReferences.Add(assembly.GetPortableExecutableReference());
110+
return this;
111+
}
112+
113+
public RoslynCompilationRunner AddReferences(params Span<Type> types) {
114+
foreach (Type type in types) _assemblyReferences.Add(type.GetPortableExecutableReference());
115+
return this;
116+
}
117+
#endregion
118+
}

0 commit comments

Comments
 (0)