Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
40 commits
Select commit Hold shift + click to select a range
9a57c06
Add source generator for assertion methods and related tests
thomhurst Oct 12, 2025
c230bf6
Refactor assertion method generator to use core assertion classes and…
thomhurst Oct 12, 2025
91647e6
Add custom expectation message support to assertion attributes and ge…
thomhurst Oct 12, 2025
5c55681
Refactor assertions to use source-generated methods
thomhurst Oct 12, 2025
b244e9d
Migrate assertions to source-generated methods and remove legacy code
thomhurst Oct 12, 2025
241ca90
Refactor assertion infrastructure: update CheckAsync methods for asyn…
thomhurst Oct 12, 2025
0e3937d
Implement source-generated assertion extensions for CultureInfo, Enco…
thomhurst Oct 12, 2025
ea841cc
Add source-generated assertion extensions for Assembly and DateTime t…
thomhurst Oct 12, 2025
125ffd6
Implement source-generated assertion extensions for CancellationToken…
thomhurst Oct 12, 2025
456b7b2
Implement source-generated assertion extensions for Assembly and Canc…
thomhurst Oct 12, 2025
5779fba
Add source-generated assertion extensions for Guid, Stream, Task, Thr…
thomhurst Oct 12, 2025
7a17e68
Refactor source-generated assertion extensions for various types to u…
thomhurst Oct 12, 2025
270f6e9
Implement source-generated assertion extensions for CultureInfo, Date…
thomhurst Oct 12, 2025
5241c87
Add source-generated assertion extensions for DateTimeOffset, IPAddre…
thomhurst Oct 12, 2025
3a9f74d
Add source-generated assertion extensions for Array, Index, Range, an…
thomhurst Oct 12, 2025
349c2ad
Add source-generated assertion extensions for DateOnly, DirectoryInfo…
thomhurst Oct 12, 2025
f7488c2
Add source-generated assertion extensions for FileInfo, DirectoryInfo…
thomhurst Oct 12, 2025
06d4aaf
Refactor assertion extension classes to be partial and update project…
thomhurst Oct 12, 2025
f27edee
Add assertion tests for Guid, Lazy, StringBuilder, Task, and TimeSpan
thomhurst Oct 12, 2025
3efb326
Add EditorBrowsable attribute to assertion extension methods for bett…
thomhurst Oct 12, 2025
69507d2
Add EditorBrowsable attribute to source-generated assertion methods a…
thomhurst Oct 12, 2025
cceced9
Add assertion tests for Boolean, Char, DateTime, DateTimeOffset, and …
thomhurst Oct 12, 2025
0fb3319
Add assertion extensions for collection membership checks and update …
thomhurst Oct 12, 2025
6381ecb
Add comprehensive assertion tests for assembly, cancellation token, I…
thomhurst Oct 12, 2025
3e0f0eb
Add comprehensive assertion tests for various types and functionalities
thomhurst Oct 12, 2025
08ef10f
Add missing using directives for TUnit.Assertions.Extensions in vario…
thomhurst Oct 12, 2025
5c4547a
Add assertion generator tests for various types and conditions
thomhurst Oct 12, 2025
6af4911
Refactor assertion generator test classes to remove specific generato…
thomhurst Oct 12, 2025
5a8209c
Rename assertion classes and update method signatures to include type…
thomhurst Oct 12, 2025
4a4adae
Merge branch 'main' into feature/enhance-assertion-source-gen
thomhurst Oct 13, 2025
9621915
Add diagnostic messages to assertion extension generator tests
thomhurst Oct 13, 2025
5987f0a
Refactor assertion generator tests and remove diagnostic source gener…
thomhurst Oct 13, 2025
b11ffd4
Update assertion generator tests to expect zero generated files
thomhurst Oct 13, 2025
5d65398
Enhance assertion messages by adding ExpectationMessage attributes fo…
thomhurst Oct 13, 2025
d10d8f6
Update MethodAssertionGenerator to always generate extension methods …
thomhurst Oct 13, 2025
31b82a6
Refactor assertion namespaces and enhance task assertions
thomhurst Oct 13, 2025
27618ef
Refactor AsyncDelegateAssertion and TaskAssertion to avoid awaiting t…
thomhurst Oct 13, 2025
de89714
Refactor assertion tests to improve clarity and reliability by addres…
thomhurst Oct 13, 2025
8848571
Remove CleanGenerated target from SourceGenerationDebug.props to stre…
thomhurst Oct 13, 2025
3b068f6
Add RunOn attribute for Windows to relevant file and directory tests
thomhurst Oct 13, 2025
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
9 changes: 2 additions & 7 deletions SourceGenerationDebug.props
Original file line number Diff line number Diff line change
@@ -1,13 +1,8 @@
<Project>
<Target Name="CleanGenerated" BeforeTargets="PreBuildEvent" Condition="Exists('$(ProjectDir)SourceGeneratedViewer')">
<Message Text="Removing SourceGeneratedViewer directory..." Importance="high" />
<RemoveDir Directories="$(ProjectDir)SourceGeneratedViewer" ContinueOnError="true" />
</Target>

<!-- <PropertyGroup>
<PropertyGroup>
<EmitCompilerGeneratedFiles>true</EmitCompilerGeneratedFiles>
<CompilerGeneratedFilesOutputPath>SourceGeneratedViewer</CompilerGeneratedFilesOutputPath>
</PropertyGroup> -->
</PropertyGroup>

<ItemGroup>
<Compile Remove="SourceGeneratedViewer\**" />
Expand Down
272 changes: 272 additions & 0 deletions TUnit.Assertions.Analyzers.Tests/GenerateAssertionAnalyzerTests.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,272 @@
using Verifier = TUnit.Assertions.Analyzers.Tests.Verifiers.CSharpAnalyzerVerifier<TUnit.Assertions.Analyzers.GenerateAssertionAnalyzer>;

namespace TUnit.Assertions.Analyzers.Tests;

public class GenerateAssertionAnalyzerTests
{
[Test]
public async Task Valid_Bool_Extension_Method_No_Error()
{
await Verifier
.VerifyAnalyzerAsync(
"""
using TUnit.Assertions.Attributes;

public static class MyAssertions
{
[GenerateAssertion]
public static bool IsPositive(this int value)
{
return value > 0;
}
}
"""
);
}

[Test]
public async Task Valid_AssertionResult_Extension_Method_No_Error()
{
await Verifier
.VerifyAnalyzerAsync(
"""
using TUnit.Assertions.Attributes;
using TUnit.Assertions.Core;

public static class MyAssertions
{
[GenerateAssertion]
public static AssertionResult IsEven(this int value)
{
return value % 2 == 0 ? AssertionResult.Passed : AssertionResult.Failed("odd");
}
}
"""
);
}

[Test]
public async Task Valid_Task_Bool_Extension_Method_No_Error()
{
await Verifier
.VerifyAnalyzerAsync(
"""
using System.Threading.Tasks;
using TUnit.Assertions.Attributes;

public static class MyAssertions
{
[GenerateAssertion]
public static async Task<bool> IsPositiveAsync(this int value)
{
await Task.Delay(1);
return value > 0;
}
}
"""
);
}

[Test]
public async Task Valid_Task_AssertionResult_Extension_Method_No_Error()
{
await Verifier
.VerifyAnalyzerAsync(
"""
using System.Threading.Tasks;
using TUnit.Assertions.Attributes;
using TUnit.Assertions.Core;

public static class MyAssertions
{
[GenerateAssertion]
public static async Task<AssertionResult> IsEvenAsync(this int value)
{
await Task.Delay(1);
return value % 2 == 0 ? AssertionResult.Passed : AssertionResult.Failed("odd");
}
}
"""
);
}

[Test]
public async Task Non_Static_Method_Flagged()
{
await Verifier
.VerifyAnalyzerAsync(
"""
using TUnit.Assertions.Attributes;

public class MyAssertions
{
[GenerateAssertion]
public bool {|#0:IsPositive|}(int value)
{
return value > 0;
}
}
""",

Verifier.Diagnostic(Rules.GenerateAssertionMethodMustBeStatic)
.WithLocation(0)
.WithArguments("IsPositive"),
Verifier.Diagnostic(Rules.GenerateAssertionShouldBeExtensionMethod)
.WithLocation(0)
.WithArguments("IsPositive")
);
}

[Test]
public async Task Method_Without_Parameters_Flagged()
{
await Verifier
.VerifyAnalyzerAsync(
"""
using TUnit.Assertions.Attributes;

public static class MyAssertions
{
[GenerateAssertion]
public static bool {|#0:AlwaysTrue|}()
{
return true;
}
}
""",

Verifier.Diagnostic(Rules.GenerateAssertionMethodMustHaveParameter)
.WithLocation(0)
.WithArguments("AlwaysTrue")
);
}

[Test]
public async Task Invalid_Return_Type_Void_Flagged()
{
await Verifier
.VerifyAnalyzerAsync(
"""
using TUnit.Assertions.Attributes;

public static class MyAssertions
{
[GenerateAssertion]
public static void {|#0:DoNothing|}(int value)
{
}
}
""",

Verifier.Diagnostic(Rules.GenerateAssertionInvalidReturnType)
.WithLocation(0)
.WithArguments("DoNothing"),
Verifier.Diagnostic(Rules.GenerateAssertionShouldBeExtensionMethod)
.WithLocation(0)
.WithArguments("DoNothing")
);
}

[Test]
public async Task Invalid_Return_Type_String_Flagged()
{
await Verifier
.VerifyAnalyzerAsync(
"""
using TUnit.Assertions.Attributes;

public static class MyAssertions
{
[GenerateAssertion]
public static string {|#0:GetValue|}(int value)
{
return value.ToString();
}
}
""",

Verifier.Diagnostic(Rules.GenerateAssertionInvalidReturnType)
.WithLocation(0)
.WithArguments("GetValue"),
Verifier.Diagnostic(Rules.GenerateAssertionShouldBeExtensionMethod)
.WithLocation(0)
.WithArguments("GetValue")
);
}

[Test]
public async Task Non_Extension_Method_Shows_Warning()
{
await Verifier
.VerifyAnalyzerAsync(
"""
using TUnit.Assertions.Attributes;

public static class MyAssertions
{
[GenerateAssertion]
public static bool {|#0:IsPositive|}(int value)
{
return value > 0;
}
}
""",

Verifier.Diagnostic(Rules.GenerateAssertionShouldBeExtensionMethod)
.WithLocation(0)
.WithArguments("IsPositive")
);
}

[Test]
public async Task Multiple_Errors_All_Reported()
{
await Verifier
.VerifyAnalyzerAsync(
"""
using TUnit.Assertions.Attributes;

public class MyAssertions
{
[GenerateAssertion]
public void {|#0:Invalid|}()
{
}
}
""",

// Non-static
Verifier.Diagnostic(Rules.GenerateAssertionMethodMustBeStatic)
.WithLocation(0)
.WithArguments("Invalid"),
// No parameters
Verifier.Diagnostic(Rules.GenerateAssertionMethodMustHaveParameter)
.WithLocation(0)
.WithArguments("Invalid"),
// Invalid return type
Verifier.Diagnostic(Rules.GenerateAssertionInvalidReturnType)
.WithLocation(0)
.WithArguments("Invalid")
);
}

[Test]
public async Task Method_With_Multiple_Parameters_No_Error()
{
await Verifier
.VerifyAnalyzerAsync(
"""
using TUnit.Assertions.Attributes;

public static class MyAssertions
{
[GenerateAssertion]
public static bool IsBetween(this int value, int min, int max)
{
return value >= min && value <= max;
}
}
"""
);
}
}
Loading
Loading