diff --git a/TUnit.CI.slnx b/TUnit.CI.slnx index dc649a60890..10f93a39731 100644 --- a/TUnit.CI.slnx +++ b/TUnit.CI.slnx @@ -87,6 +87,7 @@ + diff --git a/TUnit.Dev.slnx b/TUnit.Dev.slnx index 127bb8d1521..d107eb81076 100644 --- a/TUnit.Dev.slnx +++ b/TUnit.Dev.slnx @@ -7,6 +7,7 @@ + @@ -18,6 +19,7 @@ + @@ -28,6 +30,7 @@ + @@ -44,6 +47,7 @@ + @@ -54,8 +58,13 @@ + + + + + @@ -63,12 +72,16 @@ + + + + diff --git a/tests/SharedTestHelpers/DotNetCli.cs b/tests/SharedTestHelpers/DotNetCli.cs new file mode 100644 index 00000000000..c1b63e0878f --- /dev/null +++ b/tests/SharedTestHelpers/DotNetCli.cs @@ -0,0 +1,91 @@ +using System; +using System.Diagnostics; +using System.IO; +using System.Runtime.InteropServices; + +namespace TUnit.Tests.Shared; + +/// +/// Resolves the dotnet executable used to start child dotnet build/dotnet run processes. +/// +/// +/// A bare dotnet resolves through PATH, which an IDE does not necessarily share with the +/// installation it builds and runs tests with (on macOS, apps started from the Dock or Finder get a different +/// PATH than a terminal). That dotnet can lack an SDK satisfying global.json and exit with +/// 155 (SdkResolveFailure). Prefer the installation that is running the current test process, as long as it +/// resolves an SDK for this repository: a runtime-only installation, or one whose SDKs don't satisfy +/// global.json, cannot run dotnet build here, so PATH is the better bet there. +/// +internal static class DotNetCli +{ + // Resolved on first use rather than in the type initializer, so an unexpected failure surfaces as itself + // instead of a TypeInitializationException that also breaks every later use of the type + private static readonly Lazy ResolvedPath = new(Resolve); + + /// The dotnet executable to start child processes with: a full path, or dotnet to use PATH. + public static string Path => ResolvedPath.Value; + + /// + /// Prefers DOTNET_HOST_PATH, then the muxer of the installation running this process when it resolves an + /// SDK for this repository, and otherwise falls back to dotnet on PATH. + /// + private static string Resolve() + { + // Set by the .NET CLI for processes it starts (e.g. under `dotnet test`), so it already resolved an SDK. + var hostPath = Environment.GetEnvironmentVariable("DOTNET_HOST_PATH"); + if (!string.IsNullOrEmpty(hostPath) && File.Exists(hostPath)) + { + return hostPath; + } + + // /shared/Microsoft.NETCore.App// -> /dotnet + var runtimeDirectory = RuntimeEnvironment.GetRuntimeDirectory(); + var root = System.IO.Path.GetFullPath(System.IO.Path.Combine(runtimeDirectory, "..", "..", "..")); + var muxer = System.IO.Path.Combine(root, RuntimeInformation.IsOSPlatform(OSPlatform.Windows) ? "dotnet.exe" : "dotnet"); + + return File.Exists(muxer) && ResolvesSdk(muxer) ? muxer : "dotnet"; + } + + /// + /// Whether resolves an SDK from the test assembly's directory, which lies inside the + /// repository: dotnet --version applies global.json the same way the child builds do and fails, with + /// 155, exactly when they would. + /// + private static bool ResolvesSdk(string muxer) + { + try + { + using var process = Process.Start(new ProcessStartInfo(muxer, "--version") + { + WorkingDirectory = AppContext.BaseDirectory, + UseShellExecute = false, + RedirectStandardOutput = true, + RedirectStandardError = true, + CreateNoWindow = true, + }); + + if (process is null) + { + return false; + } + + // Drain and discard both streams so neither can fill up and block the process + process.OutputDataReceived += static (_, _) => { }; + process.ErrorDataReceived += static (_, _) => { }; + process.BeginOutputReadLine(); + process.BeginErrorReadLine(); + + if (!process.WaitForExit(30_000)) + { + process.Kill(entireProcessTree: true); + return false; + } + + return process.ExitCode == 0; + } + catch (Exception exception) when (exception is InvalidOperationException or System.ComponentModel.Win32Exception or IOException) + { + return false; + } + } +} diff --git a/tests/SharedTestHelpers/TestHostReferences.cs b/tests/SharedTestHelpers/TestHostReferences.cs new file mode 100644 index 00000000000..186a8d30bf0 --- /dev/null +++ b/tests/SharedTestHelpers/TestHostReferences.cs @@ -0,0 +1,64 @@ +using System; +using System.Collections.Generic; +using System.IO; +using System.Linq; +using System.Reflection; +using Microsoft.CodeAnalysis; + +namespace TUnit.Tests.Shared; + +/// +/// Paths of the assemblies that in-memory test compilations (generator and analyzer tests) reference. +/// +/// +/// AppDomain.CurrentDomain.GetAssemblies() only returns what the process has loaded so far, which depends on +/// how the test host was launched: IDE and dotnet test server-mode hosts load assemblies (e.g. System.Net.*) +/// that a plain run does not, so types such as System.Net.HttpStatusCode resolved or not and generator output +/// differed between launches. On .NET, TRUSTED_PLATFORM_ASSEMBLIES lists the app's whole deployment +/// (framework plus deps.json) up front. .NET Framework has no such list, so it keeps the loaded assemblies. +/// +/// Neither source has a defined order (the TPA order differs between Linux and macOS hosts), and generators emit +/// referenced assemblies in reference order, so the paths are sorted to keep snapshots identical on every host. +/// +/// +internal static class TestHostReferences +{ + /// The assembly paths to reference, sorted by file name and then by path. + public static IReadOnlyList AssemblyPaths { get; } = Resolve(); + + /// + /// Metadata references to , followed by . + /// + public static List CreateReferences(params Assembly[] additionalAssemblies) => + CreateReferences(static _ => true, additionalAssemblies); + + /// + /// Metadata references to the that accepts, + /// followed by . + /// + public static List CreateReferences(Func includeHostAssembly, params Assembly[] additionalAssemblies) => + AssemblyPaths + .Where(includeHostAssembly) + .Concat(additionalAssemblies.Select(assembly => assembly.Location)) + .Select(path => MetadataReference.CreateFromFile(path)) + .ToList(); + + /// + /// Reads TRUSTED_PLATFORM_ASSEMBLIES on .NET, or the loaded assemblies on .NET Framework, and sorts them. + /// + private static string[] Resolve() + { + var paths = AppContext.GetData("TRUSTED_PLATFORM_ASSEMBLIES") is string trustedPlatformAssemblies + ? trustedPlatformAssemblies.Split(new[] { Path.PathSeparator }, StringSplitOptions.RemoveEmptyEntries) + : AppDomain.CurrentDomain.GetAssemblies() + .Where(assembly => !assembly.IsDynamic && !string.IsNullOrWhiteSpace(assembly.Location)) + .Select(assembly => assembly.Location); + + // Ordinal on purpose: reference order shows up in generator output, so a culture-aware sort, or no sort, would + // reorder snapshots between hosts. A snapshot that reorders after a change here is this sort, not the generator. + return paths + .OrderBy(Path.GetFileName, StringComparer.Ordinal) + .ThenBy(path => path, StringComparer.Ordinal) + .ToArray(); + } +} diff --git a/tests/Snapshots/TUnit._.verified/std-streams/stderr.txt b/tests/Snapshots/TUnit._.verified/std-streams/stderr.txt deleted file mode 100644 index 5f282702bb0..00000000000 --- a/tests/Snapshots/TUnit._.verified/std-streams/stderr.txt +++ /dev/null @@ -1 +0,0 @@ - \ No newline at end of file diff --git a/tests/Snapshots/TUnit._.verified/std-streams/stdout.txt b/tests/Snapshots/TUnit._.verified/std-streams/stdout.txt deleted file mode 100644 index 5f282702bb0..00000000000 --- a/tests/Snapshots/TUnit._.verified/std-streams/stdout.txt +++ /dev/null @@ -1 +0,0 @@ - \ No newline at end of file diff --git a/tests/TUnit.Aspire.Tests/TUnit.Aspire.Tests.csproj b/tests/TUnit.Aspire.Tests/TUnit.Aspire.Tests.csproj index 45563f0c7d1..4fd89e03519 100644 --- a/tests/TUnit.Aspire.Tests/TUnit.Aspire.Tests.csproj +++ b/tests/TUnit.Aspire.Tests/TUnit.Aspire.Tests.csproj @@ -1,6 +1,6 @@ - + net10.0 @@ -11,17 +11,14 @@ - - - - - + + diff --git a/tests/TUnit.Assertions.Should.SourceGenerator.Tests/ShouldExtensionGeneratorTests.cs b/tests/TUnit.Assertions.Should.SourceGenerator.Tests/ShouldExtensionGeneratorTests.cs index 3d51d753678..8d5f666e10f 100644 --- a/tests/TUnit.Assertions.Should.SourceGenerator.Tests/ShouldExtensionGeneratorTests.cs +++ b/tests/TUnit.Assertions.Should.SourceGenerator.Tests/ShouldExtensionGeneratorTests.cs @@ -3,6 +3,7 @@ using Microsoft.CodeAnalysis; using Microsoft.CodeAnalysis.CSharp; using TUnit.Assertions.Core; +using TUnit.Tests.Shared; namespace TUnit.Assertions.Should.SourceGenerator.Tests; @@ -448,7 +449,7 @@ public sealed class OverloadResolutionPriorityAttribute : System.Attribute var compilation = CSharpCompilation.Create( assemblyName: "GeneratorTest", syntaxTrees: inputTrees, - references: GetReferences(), + references: References, options: new CSharpCompilationOptions(OutputKind.DynamicallyLinkedLibrary)); var driver = CSharpGeneratorDriver.Create(new ShouldExtensionGenerator()); @@ -471,25 +472,11 @@ await Verify(combined) return combined; } - private static IEnumerable GetReferences() - { - // Mirror the loaded assemblies of the test process. Works on both .NET Core - // (where TRUSTED_PLATFORM_ASSEMBLIES populates this set) and .NET Framework, - // unlike AppContext.GetData("TRUSTED_PLATFORM_ASSEMBLIES") which returns - // null on .NET Framework and would leave the in-memory compilation without BCL - // references — making symbol resolution silently fail in the generator. - foreach (var asm in AppDomain.CurrentDomain.GetAssemblies()) - { - if (asm.IsDynamic || string.IsNullOrWhiteSpace(asm.Location)) - { - continue; - } - yield return MetadataReference.CreateFromFile(asm.Location); - } - - yield return MetadataReference.CreateFromFile(typeof(Assertion<>).Assembly.Location); - yield return MetadataReference.CreateFromFile(typeof(TUnit.Assertions.Should.Core.IShouldSource).Assembly.Location); - } + // Built once: every test compiles against the same references, and each one reads its file from disk + private static readonly List References = + TestHostReferences.CreateReferences( + typeof(Assertion<>).Assembly, + typeof(TUnit.Assertions.Should.Core.IShouldSource).Assembly); private static int CountOccurrences(string value, string search) { diff --git a/tests/TUnit.Assertions.Should.SourceGenerator.Tests/TUnit.Assertions.Should.SourceGenerator.Tests.csproj b/tests/TUnit.Assertions.Should.SourceGenerator.Tests/TUnit.Assertions.Should.SourceGenerator.Tests.csproj index adf9e190815..4da6334b299 100644 --- a/tests/TUnit.Assertions.Should.SourceGenerator.Tests/TUnit.Assertions.Should.SourceGenerator.Tests.csproj +++ b/tests/TUnit.Assertions.Should.SourceGenerator.Tests/TUnit.Assertions.Should.SourceGenerator.Tests.csproj @@ -17,6 +17,10 @@ $(NoWarn);MSB3277 + + + + diff --git a/tests/TUnit.Assertions.SourceGenerator.Tests/HttpStatusCodeAssertionGeneratorTests.GeneratesHttpStatusCodeAssertions.DotNet10_0.verified.txt b/tests/TUnit.Assertions.SourceGenerator.Tests/HttpStatusCodeAssertionGeneratorTests.GeneratesHttpStatusCodeAssertions.DotNet10_0.verified.txt index 9a654aa3ff7..0229802d5bd 100644 --- a/tests/TUnit.Assertions.SourceGenerator.Tests/HttpStatusCodeAssertionGeneratorTests.GeneratesHttpStatusCodeAssertions.DotNet10_0.verified.txt +++ b/tests/TUnit.Assertions.SourceGenerator.Tests/HttpStatusCodeAssertionGeneratorTests.GeneratesHttpStatusCodeAssertions.DotNet10_0.verified.txt @@ -14,16 +14,16 @@ namespace TUnit.Assertions.Extensions; /// /// Generated assertion for IsSuccess /// -public sealed class HttpStatusCode_IsSuccess_Assertion : Assertion +public sealed class HttpStatusCode_IsSuccess_Assertion : Assertion { private static readonly Task _passedTask = Task.FromResult(AssertionResult.Passed); - public HttpStatusCode_IsSuccess_Assertion(AssertionContext context) + public HttpStatusCode_IsSuccess_Assertion(AssertionContext context) : base(context) { } - protected override Task CheckAsync(EvaluationMetadata metadata) + protected override Task CheckAsync(EvaluationMetadata metadata) { var value = metadata.Value; var exception = metadata.Exception; @@ -33,12 +33,7 @@ public sealed class HttpStatusCode_IsSuccess_Assertion : Assertion= 200 and < 300; + var result = (int)value is >= 200 and < 300; return result ? _passedTask : Task.FromResult(AssertionResult.Failed($"found {value}")); @@ -53,16 +48,16 @@ public sealed class HttpStatusCode_IsSuccess_Assertion : Assertion /// Generated assertion for IsNotSuccess /// -public sealed class HttpStatusCode_IsNotSuccess_Assertion : Assertion +public sealed class HttpStatusCode_IsNotSuccess_Assertion : Assertion { private static readonly Task _passedTask = Task.FromResult(AssertionResult.Passed); - public HttpStatusCode_IsNotSuccess_Assertion(AssertionContext context) + public HttpStatusCode_IsNotSuccess_Assertion(AssertionContext context) : base(context) { } - protected override Task CheckAsync(EvaluationMetadata metadata) + protected override Task CheckAsync(EvaluationMetadata metadata) { var value = metadata.Value; var exception = metadata.Exception; @@ -72,12 +67,7 @@ public sealed class HttpStatusCode_IsNotSuccess_Assertion : Assertion= 300; + var result = (int)value is < 200 or >= 300; return result ? _passedTask : Task.FromResult(AssertionResult.Failed($"found {value}")); @@ -92,16 +82,16 @@ public sealed class HttpStatusCode_IsNotSuccess_Assertion : Assertion /// Generated assertion for IsClientError /// -public sealed class HttpStatusCode_IsClientError_Assertion : Assertion +public sealed class HttpStatusCode_IsClientError_Assertion : Assertion { private static readonly Task _passedTask = Task.FromResult(AssertionResult.Passed); - public HttpStatusCode_IsClientError_Assertion(AssertionContext context) + public HttpStatusCode_IsClientError_Assertion(AssertionContext context) : base(context) { } - protected override Task CheckAsync(EvaluationMetadata metadata) + protected override Task CheckAsync(EvaluationMetadata metadata) { var value = metadata.Value; var exception = metadata.Exception; @@ -111,12 +101,7 @@ public sealed class HttpStatusCode_IsClientError_Assertion : Assertion= 400 and < 500; + var result = (int)value is >= 400 and < 500; return result ? _passedTask : Task.FromResult(AssertionResult.Failed($"found {value}")); @@ -131,16 +116,16 @@ public sealed class HttpStatusCode_IsClientError_Assertion : Assertion /// Generated assertion for IsServerError /// -public sealed class HttpStatusCode_IsServerError_Assertion : Assertion +public sealed class HttpStatusCode_IsServerError_Assertion : Assertion { private static readonly Task _passedTask = Task.FromResult(AssertionResult.Passed); - public HttpStatusCode_IsServerError_Assertion(AssertionContext context) + public HttpStatusCode_IsServerError_Assertion(AssertionContext context) : base(context) { } - protected override Task CheckAsync(EvaluationMetadata metadata) + protected override Task CheckAsync(EvaluationMetadata metadata) { var value = metadata.Value; var exception = metadata.Exception; @@ -150,12 +135,7 @@ public sealed class HttpStatusCode_IsServerError_Assertion : Assertion= 500 and < 600; + var result = (int)value is >= 500 and < 600; return result ? _passedTask : Task.FromResult(AssertionResult.Failed($"found {value}")); @@ -170,16 +150,16 @@ public sealed class HttpStatusCode_IsServerError_Assertion : Assertion /// Generated assertion for IsRedirection /// -public sealed class HttpStatusCode_IsRedirection_Assertion : Assertion +public sealed class HttpStatusCode_IsRedirection_Assertion : Assertion { private static readonly Task _passedTask = Task.FromResult(AssertionResult.Passed); - public HttpStatusCode_IsRedirection_Assertion(AssertionContext context) + public HttpStatusCode_IsRedirection_Assertion(AssertionContext context) : base(context) { } - protected override Task CheckAsync(EvaluationMetadata metadata) + protected override Task CheckAsync(EvaluationMetadata metadata) { var value = metadata.Value; var exception = metadata.Exception; @@ -189,12 +169,7 @@ public sealed class HttpStatusCode_IsRedirection_Assertion : Assertion= 300 and < 400; + var result = (int)value is >= 300 and < 400; return result ? _passedTask : Task.FromResult(AssertionResult.Failed($"found {value}")); @@ -209,16 +184,16 @@ public sealed class HttpStatusCode_IsRedirection_Assertion : Assertion /// Generated assertion for IsInformational /// -public sealed class HttpStatusCode_IsInformational_Assertion : Assertion +public sealed class HttpStatusCode_IsInformational_Assertion : Assertion { private static readonly Task _passedTask = Task.FromResult(AssertionResult.Passed); - public HttpStatusCode_IsInformational_Assertion(AssertionContext context) + public HttpStatusCode_IsInformational_Assertion(AssertionContext context) : base(context) { } - protected override Task CheckAsync(EvaluationMetadata metadata) + protected override Task CheckAsync(EvaluationMetadata metadata) { var value = metadata.Value; var exception = metadata.Exception; @@ -228,12 +203,7 @@ public sealed class HttpStatusCode_IsInformational_Assertion : Assertion= 100 and < 200; + var result = (int)value is >= 100 and < 200; return result ? _passedTask : Task.FromResult(AssertionResult.Failed($"found {value}")); @@ -248,16 +218,16 @@ public sealed class HttpStatusCode_IsInformational_Assertion : Assertion /// Generated assertion for IsError /// -public sealed class HttpStatusCode_IsError_Assertion : Assertion +public sealed class HttpStatusCode_IsError_Assertion : Assertion { private static readonly Task _passedTask = Task.FromResult(AssertionResult.Passed); - public HttpStatusCode_IsError_Assertion(AssertionContext context) + public HttpStatusCode_IsError_Assertion(AssertionContext context) : base(context) { } - protected override Task CheckAsync(EvaluationMetadata metadata) + protected override Task CheckAsync(EvaluationMetadata metadata) { var value = metadata.Value; var exception = metadata.Exception; @@ -267,12 +237,7 @@ public sealed class HttpStatusCode_IsError_Assertion : Assertion return Task.FromResult(AssertionResult.Failed($"threw {exception.GetType().FullName}")); } - if (value is null) - { - return Task.FromResult(AssertionResult.Failed("Actual value is null")); - } - - var result = (int)value! is >= 400 and < 600; + var result = (int)value is >= 400 and < 600; return result ? _passedTask : Task.FromResult(AssertionResult.Failed($"found {value}")); @@ -289,7 +254,7 @@ public static partial class HttpStatusCodeAssertionExtensions /// /// Generated extension method for IsSuccess /// - public static HttpStatusCode_IsSuccess_Assertion IsSuccess(this IAssertionSource source) + public static HttpStatusCode_IsSuccess_Assertion IsSuccess(this IAssertionSource source) { source.Context.ExpressionBuilder.Append(".IsSuccess()"); return new HttpStatusCode_IsSuccess_Assertion(source.Context); @@ -298,7 +263,7 @@ public static partial class HttpStatusCodeAssertionExtensions /// /// Generated extension method for IsNotSuccess /// - public static HttpStatusCode_IsNotSuccess_Assertion IsNotSuccess(this IAssertionSource source) + public static HttpStatusCode_IsNotSuccess_Assertion IsNotSuccess(this IAssertionSource source) { source.Context.ExpressionBuilder.Append(".IsNotSuccess()"); return new HttpStatusCode_IsNotSuccess_Assertion(source.Context); @@ -307,7 +272,7 @@ public static partial class HttpStatusCodeAssertionExtensions /// /// Generated extension method for IsClientError /// - public static HttpStatusCode_IsClientError_Assertion IsClientError(this IAssertionSource source) + public static HttpStatusCode_IsClientError_Assertion IsClientError(this IAssertionSource source) { source.Context.ExpressionBuilder.Append(".IsClientError()"); return new HttpStatusCode_IsClientError_Assertion(source.Context); @@ -316,7 +281,7 @@ public static partial class HttpStatusCodeAssertionExtensions /// /// Generated extension method for IsServerError /// - public static HttpStatusCode_IsServerError_Assertion IsServerError(this IAssertionSource source) + public static HttpStatusCode_IsServerError_Assertion IsServerError(this IAssertionSource source) { source.Context.ExpressionBuilder.Append(".IsServerError()"); return new HttpStatusCode_IsServerError_Assertion(source.Context); @@ -325,7 +290,7 @@ public static partial class HttpStatusCodeAssertionExtensions /// /// Generated extension method for IsRedirection /// - public static HttpStatusCode_IsRedirection_Assertion IsRedirection(this IAssertionSource source) + public static HttpStatusCode_IsRedirection_Assertion IsRedirection(this IAssertionSource source) { source.Context.ExpressionBuilder.Append(".IsRedirection()"); return new HttpStatusCode_IsRedirection_Assertion(source.Context); @@ -334,7 +299,7 @@ public static partial class HttpStatusCodeAssertionExtensions /// /// Generated extension method for IsInformational /// - public static HttpStatusCode_IsInformational_Assertion IsInformational(this IAssertionSource source) + public static HttpStatusCode_IsInformational_Assertion IsInformational(this IAssertionSource source) { source.Context.ExpressionBuilder.Append(".IsInformational()"); return new HttpStatusCode_IsInformational_Assertion(source.Context); @@ -343,7 +308,7 @@ public static partial class HttpStatusCodeAssertionExtensions /// /// Generated extension method for IsError /// - public static HttpStatusCode_IsError_Assertion IsError(this IAssertionSource source) + public static HttpStatusCode_IsError_Assertion IsError(this IAssertionSource source) { source.Context.ExpressionBuilder.Append(".IsError()"); return new HttpStatusCode_IsError_Assertion(source.Context); diff --git a/tests/TUnit.Assertions.SourceGenerator.Tests/HttpStatusCodeAssertionGeneratorTests.GeneratesHttpStatusCodeAssertions.DotNet8_0.verified.txt b/tests/TUnit.Assertions.SourceGenerator.Tests/HttpStatusCodeAssertionGeneratorTests.GeneratesHttpStatusCodeAssertions.DotNet8_0.verified.txt index 9a654aa3ff7..0229802d5bd 100644 --- a/tests/TUnit.Assertions.SourceGenerator.Tests/HttpStatusCodeAssertionGeneratorTests.GeneratesHttpStatusCodeAssertions.DotNet8_0.verified.txt +++ b/tests/TUnit.Assertions.SourceGenerator.Tests/HttpStatusCodeAssertionGeneratorTests.GeneratesHttpStatusCodeAssertions.DotNet8_0.verified.txt @@ -14,16 +14,16 @@ namespace TUnit.Assertions.Extensions; /// /// Generated assertion for IsSuccess /// -public sealed class HttpStatusCode_IsSuccess_Assertion : Assertion +public sealed class HttpStatusCode_IsSuccess_Assertion : Assertion { private static readonly Task _passedTask = Task.FromResult(AssertionResult.Passed); - public HttpStatusCode_IsSuccess_Assertion(AssertionContext context) + public HttpStatusCode_IsSuccess_Assertion(AssertionContext context) : base(context) { } - protected override Task CheckAsync(EvaluationMetadata metadata) + protected override Task CheckAsync(EvaluationMetadata metadata) { var value = metadata.Value; var exception = metadata.Exception; @@ -33,12 +33,7 @@ public sealed class HttpStatusCode_IsSuccess_Assertion : Assertion= 200 and < 300; + var result = (int)value is >= 200 and < 300; return result ? _passedTask : Task.FromResult(AssertionResult.Failed($"found {value}")); @@ -53,16 +48,16 @@ public sealed class HttpStatusCode_IsSuccess_Assertion : Assertion /// Generated assertion for IsNotSuccess /// -public sealed class HttpStatusCode_IsNotSuccess_Assertion : Assertion +public sealed class HttpStatusCode_IsNotSuccess_Assertion : Assertion { private static readonly Task _passedTask = Task.FromResult(AssertionResult.Passed); - public HttpStatusCode_IsNotSuccess_Assertion(AssertionContext context) + public HttpStatusCode_IsNotSuccess_Assertion(AssertionContext context) : base(context) { } - protected override Task CheckAsync(EvaluationMetadata metadata) + protected override Task CheckAsync(EvaluationMetadata metadata) { var value = metadata.Value; var exception = metadata.Exception; @@ -72,12 +67,7 @@ public sealed class HttpStatusCode_IsNotSuccess_Assertion : Assertion= 300; + var result = (int)value is < 200 or >= 300; return result ? _passedTask : Task.FromResult(AssertionResult.Failed($"found {value}")); @@ -92,16 +82,16 @@ public sealed class HttpStatusCode_IsNotSuccess_Assertion : Assertion /// Generated assertion for IsClientError /// -public sealed class HttpStatusCode_IsClientError_Assertion : Assertion +public sealed class HttpStatusCode_IsClientError_Assertion : Assertion { private static readonly Task _passedTask = Task.FromResult(AssertionResult.Passed); - public HttpStatusCode_IsClientError_Assertion(AssertionContext context) + public HttpStatusCode_IsClientError_Assertion(AssertionContext context) : base(context) { } - protected override Task CheckAsync(EvaluationMetadata metadata) + protected override Task CheckAsync(EvaluationMetadata metadata) { var value = metadata.Value; var exception = metadata.Exception; @@ -111,12 +101,7 @@ public sealed class HttpStatusCode_IsClientError_Assertion : Assertion= 400 and < 500; + var result = (int)value is >= 400 and < 500; return result ? _passedTask : Task.FromResult(AssertionResult.Failed($"found {value}")); @@ -131,16 +116,16 @@ public sealed class HttpStatusCode_IsClientError_Assertion : Assertion /// Generated assertion for IsServerError /// -public sealed class HttpStatusCode_IsServerError_Assertion : Assertion +public sealed class HttpStatusCode_IsServerError_Assertion : Assertion { private static readonly Task _passedTask = Task.FromResult(AssertionResult.Passed); - public HttpStatusCode_IsServerError_Assertion(AssertionContext context) + public HttpStatusCode_IsServerError_Assertion(AssertionContext context) : base(context) { } - protected override Task CheckAsync(EvaluationMetadata metadata) + protected override Task CheckAsync(EvaluationMetadata metadata) { var value = metadata.Value; var exception = metadata.Exception; @@ -150,12 +135,7 @@ public sealed class HttpStatusCode_IsServerError_Assertion : Assertion= 500 and < 600; + var result = (int)value is >= 500 and < 600; return result ? _passedTask : Task.FromResult(AssertionResult.Failed($"found {value}")); @@ -170,16 +150,16 @@ public sealed class HttpStatusCode_IsServerError_Assertion : Assertion /// Generated assertion for IsRedirection /// -public sealed class HttpStatusCode_IsRedirection_Assertion : Assertion +public sealed class HttpStatusCode_IsRedirection_Assertion : Assertion { private static readonly Task _passedTask = Task.FromResult(AssertionResult.Passed); - public HttpStatusCode_IsRedirection_Assertion(AssertionContext context) + public HttpStatusCode_IsRedirection_Assertion(AssertionContext context) : base(context) { } - protected override Task CheckAsync(EvaluationMetadata metadata) + protected override Task CheckAsync(EvaluationMetadata metadata) { var value = metadata.Value; var exception = metadata.Exception; @@ -189,12 +169,7 @@ public sealed class HttpStatusCode_IsRedirection_Assertion : Assertion= 300 and < 400; + var result = (int)value is >= 300 and < 400; return result ? _passedTask : Task.FromResult(AssertionResult.Failed($"found {value}")); @@ -209,16 +184,16 @@ public sealed class HttpStatusCode_IsRedirection_Assertion : Assertion /// Generated assertion for IsInformational /// -public sealed class HttpStatusCode_IsInformational_Assertion : Assertion +public sealed class HttpStatusCode_IsInformational_Assertion : Assertion { private static readonly Task _passedTask = Task.FromResult(AssertionResult.Passed); - public HttpStatusCode_IsInformational_Assertion(AssertionContext context) + public HttpStatusCode_IsInformational_Assertion(AssertionContext context) : base(context) { } - protected override Task CheckAsync(EvaluationMetadata metadata) + protected override Task CheckAsync(EvaluationMetadata metadata) { var value = metadata.Value; var exception = metadata.Exception; @@ -228,12 +203,7 @@ public sealed class HttpStatusCode_IsInformational_Assertion : Assertion= 100 and < 200; + var result = (int)value is >= 100 and < 200; return result ? _passedTask : Task.FromResult(AssertionResult.Failed($"found {value}")); @@ -248,16 +218,16 @@ public sealed class HttpStatusCode_IsInformational_Assertion : Assertion /// Generated assertion for IsError /// -public sealed class HttpStatusCode_IsError_Assertion : Assertion +public sealed class HttpStatusCode_IsError_Assertion : Assertion { private static readonly Task _passedTask = Task.FromResult(AssertionResult.Passed); - public HttpStatusCode_IsError_Assertion(AssertionContext context) + public HttpStatusCode_IsError_Assertion(AssertionContext context) : base(context) { } - protected override Task CheckAsync(EvaluationMetadata metadata) + protected override Task CheckAsync(EvaluationMetadata metadata) { var value = metadata.Value; var exception = metadata.Exception; @@ -267,12 +237,7 @@ public sealed class HttpStatusCode_IsError_Assertion : Assertion return Task.FromResult(AssertionResult.Failed($"threw {exception.GetType().FullName}")); } - if (value is null) - { - return Task.FromResult(AssertionResult.Failed("Actual value is null")); - } - - var result = (int)value! is >= 400 and < 600; + var result = (int)value is >= 400 and < 600; return result ? _passedTask : Task.FromResult(AssertionResult.Failed($"found {value}")); @@ -289,7 +254,7 @@ public static partial class HttpStatusCodeAssertionExtensions /// /// Generated extension method for IsSuccess /// - public static HttpStatusCode_IsSuccess_Assertion IsSuccess(this IAssertionSource source) + public static HttpStatusCode_IsSuccess_Assertion IsSuccess(this IAssertionSource source) { source.Context.ExpressionBuilder.Append(".IsSuccess()"); return new HttpStatusCode_IsSuccess_Assertion(source.Context); @@ -298,7 +263,7 @@ public static partial class HttpStatusCodeAssertionExtensions /// /// Generated extension method for IsNotSuccess /// - public static HttpStatusCode_IsNotSuccess_Assertion IsNotSuccess(this IAssertionSource source) + public static HttpStatusCode_IsNotSuccess_Assertion IsNotSuccess(this IAssertionSource source) { source.Context.ExpressionBuilder.Append(".IsNotSuccess()"); return new HttpStatusCode_IsNotSuccess_Assertion(source.Context); @@ -307,7 +272,7 @@ public static partial class HttpStatusCodeAssertionExtensions /// /// Generated extension method for IsClientError /// - public static HttpStatusCode_IsClientError_Assertion IsClientError(this IAssertionSource source) + public static HttpStatusCode_IsClientError_Assertion IsClientError(this IAssertionSource source) { source.Context.ExpressionBuilder.Append(".IsClientError()"); return new HttpStatusCode_IsClientError_Assertion(source.Context); @@ -316,7 +281,7 @@ public static partial class HttpStatusCodeAssertionExtensions /// /// Generated extension method for IsServerError /// - public static HttpStatusCode_IsServerError_Assertion IsServerError(this IAssertionSource source) + public static HttpStatusCode_IsServerError_Assertion IsServerError(this IAssertionSource source) { source.Context.ExpressionBuilder.Append(".IsServerError()"); return new HttpStatusCode_IsServerError_Assertion(source.Context); @@ -325,7 +290,7 @@ public static partial class HttpStatusCodeAssertionExtensions /// /// Generated extension method for IsRedirection /// - public static HttpStatusCode_IsRedirection_Assertion IsRedirection(this IAssertionSource source) + public static HttpStatusCode_IsRedirection_Assertion IsRedirection(this IAssertionSource source) { source.Context.ExpressionBuilder.Append(".IsRedirection()"); return new HttpStatusCode_IsRedirection_Assertion(source.Context); @@ -334,7 +299,7 @@ public static partial class HttpStatusCodeAssertionExtensions /// /// Generated extension method for IsInformational /// - public static HttpStatusCode_IsInformational_Assertion IsInformational(this IAssertionSource source) + public static HttpStatusCode_IsInformational_Assertion IsInformational(this IAssertionSource source) { source.Context.ExpressionBuilder.Append(".IsInformational()"); return new HttpStatusCode_IsInformational_Assertion(source.Context); @@ -343,7 +308,7 @@ public static partial class HttpStatusCodeAssertionExtensions /// /// Generated extension method for IsError /// - public static HttpStatusCode_IsError_Assertion IsError(this IAssertionSource source) + public static HttpStatusCode_IsError_Assertion IsError(this IAssertionSource source) { source.Context.ExpressionBuilder.Append(".IsError()"); return new HttpStatusCode_IsError_Assertion(source.Context); diff --git a/tests/TUnit.Assertions.SourceGenerator.Tests/HttpStatusCodeAssertionGeneratorTests.GeneratesHttpStatusCodeAssertions.DotNet9_0.verified.txt b/tests/TUnit.Assertions.SourceGenerator.Tests/HttpStatusCodeAssertionGeneratorTests.GeneratesHttpStatusCodeAssertions.DotNet9_0.verified.txt index 9a654aa3ff7..0229802d5bd 100644 --- a/tests/TUnit.Assertions.SourceGenerator.Tests/HttpStatusCodeAssertionGeneratorTests.GeneratesHttpStatusCodeAssertions.DotNet9_0.verified.txt +++ b/tests/TUnit.Assertions.SourceGenerator.Tests/HttpStatusCodeAssertionGeneratorTests.GeneratesHttpStatusCodeAssertions.DotNet9_0.verified.txt @@ -14,16 +14,16 @@ namespace TUnit.Assertions.Extensions; /// /// Generated assertion for IsSuccess /// -public sealed class HttpStatusCode_IsSuccess_Assertion : Assertion +public sealed class HttpStatusCode_IsSuccess_Assertion : Assertion { private static readonly Task _passedTask = Task.FromResult(AssertionResult.Passed); - public HttpStatusCode_IsSuccess_Assertion(AssertionContext context) + public HttpStatusCode_IsSuccess_Assertion(AssertionContext context) : base(context) { } - protected override Task CheckAsync(EvaluationMetadata metadata) + protected override Task CheckAsync(EvaluationMetadata metadata) { var value = metadata.Value; var exception = metadata.Exception; @@ -33,12 +33,7 @@ public sealed class HttpStatusCode_IsSuccess_Assertion : Assertion= 200 and < 300; + var result = (int)value is >= 200 and < 300; return result ? _passedTask : Task.FromResult(AssertionResult.Failed($"found {value}")); @@ -53,16 +48,16 @@ public sealed class HttpStatusCode_IsSuccess_Assertion : Assertion /// Generated assertion for IsNotSuccess /// -public sealed class HttpStatusCode_IsNotSuccess_Assertion : Assertion +public sealed class HttpStatusCode_IsNotSuccess_Assertion : Assertion { private static readonly Task _passedTask = Task.FromResult(AssertionResult.Passed); - public HttpStatusCode_IsNotSuccess_Assertion(AssertionContext context) + public HttpStatusCode_IsNotSuccess_Assertion(AssertionContext context) : base(context) { } - protected override Task CheckAsync(EvaluationMetadata metadata) + protected override Task CheckAsync(EvaluationMetadata metadata) { var value = metadata.Value; var exception = metadata.Exception; @@ -72,12 +67,7 @@ public sealed class HttpStatusCode_IsNotSuccess_Assertion : Assertion= 300; + var result = (int)value is < 200 or >= 300; return result ? _passedTask : Task.FromResult(AssertionResult.Failed($"found {value}")); @@ -92,16 +82,16 @@ public sealed class HttpStatusCode_IsNotSuccess_Assertion : Assertion /// Generated assertion for IsClientError /// -public sealed class HttpStatusCode_IsClientError_Assertion : Assertion +public sealed class HttpStatusCode_IsClientError_Assertion : Assertion { private static readonly Task _passedTask = Task.FromResult(AssertionResult.Passed); - public HttpStatusCode_IsClientError_Assertion(AssertionContext context) + public HttpStatusCode_IsClientError_Assertion(AssertionContext context) : base(context) { } - protected override Task CheckAsync(EvaluationMetadata metadata) + protected override Task CheckAsync(EvaluationMetadata metadata) { var value = metadata.Value; var exception = metadata.Exception; @@ -111,12 +101,7 @@ public sealed class HttpStatusCode_IsClientError_Assertion : Assertion= 400 and < 500; + var result = (int)value is >= 400 and < 500; return result ? _passedTask : Task.FromResult(AssertionResult.Failed($"found {value}")); @@ -131,16 +116,16 @@ public sealed class HttpStatusCode_IsClientError_Assertion : Assertion /// Generated assertion for IsServerError /// -public sealed class HttpStatusCode_IsServerError_Assertion : Assertion +public sealed class HttpStatusCode_IsServerError_Assertion : Assertion { private static readonly Task _passedTask = Task.FromResult(AssertionResult.Passed); - public HttpStatusCode_IsServerError_Assertion(AssertionContext context) + public HttpStatusCode_IsServerError_Assertion(AssertionContext context) : base(context) { } - protected override Task CheckAsync(EvaluationMetadata metadata) + protected override Task CheckAsync(EvaluationMetadata metadata) { var value = metadata.Value; var exception = metadata.Exception; @@ -150,12 +135,7 @@ public sealed class HttpStatusCode_IsServerError_Assertion : Assertion= 500 and < 600; + var result = (int)value is >= 500 and < 600; return result ? _passedTask : Task.FromResult(AssertionResult.Failed($"found {value}")); @@ -170,16 +150,16 @@ public sealed class HttpStatusCode_IsServerError_Assertion : Assertion /// Generated assertion for IsRedirection /// -public sealed class HttpStatusCode_IsRedirection_Assertion : Assertion +public sealed class HttpStatusCode_IsRedirection_Assertion : Assertion { private static readonly Task _passedTask = Task.FromResult(AssertionResult.Passed); - public HttpStatusCode_IsRedirection_Assertion(AssertionContext context) + public HttpStatusCode_IsRedirection_Assertion(AssertionContext context) : base(context) { } - protected override Task CheckAsync(EvaluationMetadata metadata) + protected override Task CheckAsync(EvaluationMetadata metadata) { var value = metadata.Value; var exception = metadata.Exception; @@ -189,12 +169,7 @@ public sealed class HttpStatusCode_IsRedirection_Assertion : Assertion= 300 and < 400; + var result = (int)value is >= 300 and < 400; return result ? _passedTask : Task.FromResult(AssertionResult.Failed($"found {value}")); @@ -209,16 +184,16 @@ public sealed class HttpStatusCode_IsRedirection_Assertion : Assertion /// Generated assertion for IsInformational /// -public sealed class HttpStatusCode_IsInformational_Assertion : Assertion +public sealed class HttpStatusCode_IsInformational_Assertion : Assertion { private static readonly Task _passedTask = Task.FromResult(AssertionResult.Passed); - public HttpStatusCode_IsInformational_Assertion(AssertionContext context) + public HttpStatusCode_IsInformational_Assertion(AssertionContext context) : base(context) { } - protected override Task CheckAsync(EvaluationMetadata metadata) + protected override Task CheckAsync(EvaluationMetadata metadata) { var value = metadata.Value; var exception = metadata.Exception; @@ -228,12 +203,7 @@ public sealed class HttpStatusCode_IsInformational_Assertion : Assertion= 100 and < 200; + var result = (int)value is >= 100 and < 200; return result ? _passedTask : Task.FromResult(AssertionResult.Failed($"found {value}")); @@ -248,16 +218,16 @@ public sealed class HttpStatusCode_IsInformational_Assertion : Assertion /// Generated assertion for IsError /// -public sealed class HttpStatusCode_IsError_Assertion : Assertion +public sealed class HttpStatusCode_IsError_Assertion : Assertion { private static readonly Task _passedTask = Task.FromResult(AssertionResult.Passed); - public HttpStatusCode_IsError_Assertion(AssertionContext context) + public HttpStatusCode_IsError_Assertion(AssertionContext context) : base(context) { } - protected override Task CheckAsync(EvaluationMetadata metadata) + protected override Task CheckAsync(EvaluationMetadata metadata) { var value = metadata.Value; var exception = metadata.Exception; @@ -267,12 +237,7 @@ public sealed class HttpStatusCode_IsError_Assertion : Assertion return Task.FromResult(AssertionResult.Failed($"threw {exception.GetType().FullName}")); } - if (value is null) - { - return Task.FromResult(AssertionResult.Failed("Actual value is null")); - } - - var result = (int)value! is >= 400 and < 600; + var result = (int)value is >= 400 and < 600; return result ? _passedTask : Task.FromResult(AssertionResult.Failed($"found {value}")); @@ -289,7 +254,7 @@ public static partial class HttpStatusCodeAssertionExtensions /// /// Generated extension method for IsSuccess /// - public static HttpStatusCode_IsSuccess_Assertion IsSuccess(this IAssertionSource source) + public static HttpStatusCode_IsSuccess_Assertion IsSuccess(this IAssertionSource source) { source.Context.ExpressionBuilder.Append(".IsSuccess()"); return new HttpStatusCode_IsSuccess_Assertion(source.Context); @@ -298,7 +263,7 @@ public static partial class HttpStatusCodeAssertionExtensions /// /// Generated extension method for IsNotSuccess /// - public static HttpStatusCode_IsNotSuccess_Assertion IsNotSuccess(this IAssertionSource source) + public static HttpStatusCode_IsNotSuccess_Assertion IsNotSuccess(this IAssertionSource source) { source.Context.ExpressionBuilder.Append(".IsNotSuccess()"); return new HttpStatusCode_IsNotSuccess_Assertion(source.Context); @@ -307,7 +272,7 @@ public static partial class HttpStatusCodeAssertionExtensions /// /// Generated extension method for IsClientError /// - public static HttpStatusCode_IsClientError_Assertion IsClientError(this IAssertionSource source) + public static HttpStatusCode_IsClientError_Assertion IsClientError(this IAssertionSource source) { source.Context.ExpressionBuilder.Append(".IsClientError()"); return new HttpStatusCode_IsClientError_Assertion(source.Context); @@ -316,7 +281,7 @@ public static partial class HttpStatusCodeAssertionExtensions /// /// Generated extension method for IsServerError /// - public static HttpStatusCode_IsServerError_Assertion IsServerError(this IAssertionSource source) + public static HttpStatusCode_IsServerError_Assertion IsServerError(this IAssertionSource source) { source.Context.ExpressionBuilder.Append(".IsServerError()"); return new HttpStatusCode_IsServerError_Assertion(source.Context); @@ -325,7 +290,7 @@ public static partial class HttpStatusCodeAssertionExtensions /// /// Generated extension method for IsRedirection /// - public static HttpStatusCode_IsRedirection_Assertion IsRedirection(this IAssertionSource source) + public static HttpStatusCode_IsRedirection_Assertion IsRedirection(this IAssertionSource source) { source.Context.ExpressionBuilder.Append(".IsRedirection()"); return new HttpStatusCode_IsRedirection_Assertion(source.Context); @@ -334,7 +299,7 @@ public static partial class HttpStatusCodeAssertionExtensions /// /// Generated extension method for IsInformational /// - public static HttpStatusCode_IsInformational_Assertion IsInformational(this IAssertionSource source) + public static HttpStatusCode_IsInformational_Assertion IsInformational(this IAssertionSource source) { source.Context.ExpressionBuilder.Append(".IsInformational()"); return new HttpStatusCode_IsInformational_Assertion(source.Context); @@ -343,7 +308,7 @@ public static partial class HttpStatusCodeAssertionExtensions /// /// Generated extension method for IsError /// - public static HttpStatusCode_IsError_Assertion IsError(this IAssertionSource source) + public static HttpStatusCode_IsError_Assertion IsError(this IAssertionSource source) { source.Context.ExpressionBuilder.Append(".IsError()"); return new HttpStatusCode_IsError_Assertion(source.Context); diff --git a/tests/TUnit.Assertions.SourceGenerator.Tests/ReferencesHelper.cs b/tests/TUnit.Assertions.SourceGenerator.Tests/ReferencesHelper.cs index b5dd459183d..f7b0c084611 100644 --- a/tests/TUnit.Assertions.SourceGenerator.Tests/ReferencesHelper.cs +++ b/tests/TUnit.Assertions.SourceGenerator.Tests/ReferencesHelper.cs @@ -1,5 +1,6 @@ using System.Diagnostics.CodeAnalysis; using Microsoft.CodeAnalysis; +using TUnit.Tests.Shared; namespace TUnit.Assertions.SourceGenerator.Tests; @@ -7,16 +8,10 @@ namespace TUnit.Assertions.SourceGenerator.Tests; internal class ReferencesHelper { public static readonly List References = - AppDomain.CurrentDomain.GetAssemblies() - .Where(x => !x.IsDynamic && !string.IsNullOrWhiteSpace(x.Location)) - .Select(x => MetadataReference.CreateFromFile(x.Location)) - .Concat([ - // add your app/lib specifics, e.g.: - MetadataReference.CreateFromFile(typeof(Attribute).Assembly.Location), - MetadataReference.CreateFromFile(typeof(Assert).Assembly.Location), - MetadataReference.CreateFromFile(typeof(Polyfill).Assembly.Location), - MetadataReference.CreateFromFile(typeof(System.Runtime.CompilerServices.CallerArgumentExpressionAttribute).Assembly.Location), - MetadataReference.CreateFromFile(typeof(Uri).Assembly.Location), - ]) - .ToList(); + TestHostReferences.CreateReferences( + typeof(Attribute).Assembly, + typeof(Assert).Assembly, + typeof(Polyfill).Assembly, + typeof(System.Runtime.CompilerServices.CallerArgumentExpressionAttribute).Assembly, + typeof(Uri).Assembly); } diff --git a/tests/TUnit.Assertions.SourceGenerator.Tests/TUnit.Assertions.SourceGenerator.Tests.csproj b/tests/TUnit.Assertions.SourceGenerator.Tests/TUnit.Assertions.SourceGenerator.Tests.csproj index 0f97d6bddcd..134fdc2ab4d 100644 --- a/tests/TUnit.Assertions.SourceGenerator.Tests/TUnit.Assertions.SourceGenerator.Tests.csproj +++ b/tests/TUnit.Assertions.SourceGenerator.Tests/TUnit.Assertions.SourceGenerator.Tests.csproj @@ -13,6 +13,10 @@ $(NoWarn);MSB3277 + + + + @@ -32,11 +36,6 @@ - - - all - runtime; build; native; contentfiles; analyzers; buildtransitive - diff --git a/tests/TUnit.Assertions.SourceGenerator.Tests/TestHostReferencesTests.cs b/tests/TUnit.Assertions.SourceGenerator.Tests/TestHostReferencesTests.cs new file mode 100644 index 00000000000..4cea025a89d --- /dev/null +++ b/tests/TUnit.Assertions.SourceGenerator.Tests/TestHostReferencesTests.cs @@ -0,0 +1,32 @@ +using TUnit.Tests.Shared; + +namespace TUnit.Assertions.SourceGenerator.Tests; + +/// +/// Pins how builds the metadata +/// references every generator test compilation uses. +/// +internal class TestHostReferencesTests +{ + [Test] + public async Task CreateReferences_Lists_The_Host_Assemblies_Then_The_Additional_Ones() + { + var additional = typeof(TestHostReferencesTests).Assembly; + + var paths = TestHostReferences.CreateReferences(additional).Select(reference => reference.FilePath).ToArray(); + + await Assert.That(paths.Take(TestHostReferences.AssemblyPaths.Count)).IsEquivalentTo(TestHostReferences.AssemblyPaths, TUnit.Assertions.Enums.CollectionOrdering.Matching); + await Assert.That(paths.Skip(TestHostReferences.AssemblyPaths.Count)).IsEquivalentTo(new[] { additional.Location }, TUnit.Assertions.Enums.CollectionOrdering.Matching); + } + + [Test] + public async Task CreateReferences_Leaves_Out_The_Host_Assemblies_The_Filter_Excludes() + { + var excluded = TestHostReferences.AssemblyPaths[0]; + + var paths = TestHostReferences.CreateReferences(path => path != excluded).Select(reference => reference.FilePath).ToArray(); + + await Assert.That(paths).DoesNotContain(excluded); + await Assert.That(paths.Length).IsEqualTo(TestHostReferences.AssemblyPaths.Count - 1); + } +} diff --git a/tests/TUnit.Assertions.Tests/AssertionGroupTests.cs b/tests/TUnit.Assertions.Tests/AssertionGroupTests.cs index bbee2b1ec6e..2744571af6c 100644 --- a/tests/TUnit.Assertions.Tests/AssertionGroupTests.cs +++ b/tests/TUnit.Assertions.Tests/AssertionGroupTests.cs @@ -32,26 +32,26 @@ await Assert.That(value) .IsEqualTo("Foo"); } - // IsNullOrEmpty is not available in current API - // These tests are commented out as they test deprecated functionality + [Test] + public async Task Complex_Or_With_Delegates() + { + // Test: "Foo" should match (IsNullOrEmpty AND EqualTo("Foo")) OR (IsNullOrEmpty OR EqualTo("Foo")) + // Second condition passes because EqualTo("Foo") is true + var value = "Foo"; - //[Test] - //public async Task Complex_Or_With_Delegates() - //{ - // // Test: "Foo" should match (IsNullOrEmpty AND EqualTo("Foo")) OR (IsNullOrEmpty OR EqualTo("Foo")) - // // Second condition passes because EqualTo("Foo") is true - // var value = "Foo"; + // Try first assertion, if it fails try second + try + { + await Assert.That(value).IsNullOrEmpty().And.IsEqualTo("Foo"); + } + catch (AssertionException) + { + await Assert.That(value).IsNullOrEmpty().Or.IsEqualTo("Foo"); + } + } - // // Try first assertion, if it fails try second - // try - // { - // await Assert.That(value).IsNullOrEmpty().And.IsEqualTo("Foo"); - // } - // catch (AssertionException) - // { - // await Assert.That(value).IsNullOrEmpty().Or.IsEqualTo("Foo"); - // } - //} + // Disabled until [AssertionFrom] custom expectation messages get their leading "to", which this message + // relies on //[Test] //public async Task And_Condition_Throws_As_Expected() diff --git a/tests/TUnit.Assertions.Tests/CollectionAssertionTests.cs b/tests/TUnit.Assertions.Tests/CollectionAssertionTests.cs index 24c21cfb101..782dea62771 100644 --- a/tests/TUnit.Assertions.Tests/CollectionAssertionTests.cs +++ b/tests/TUnit.Assertions.Tests/CollectionAssertionTests.cs @@ -323,7 +323,8 @@ await Assert.That(async () => await Assert.That(items).All(x => x > 0) ).Throws() .WithMessageContaining("index 2") - .And.WithMessageContaining("[-5]"); + // Values are formatted with the current culture (e.g. U+2212 MINUS SIGN under sv-SE). + .And.WithMessageContaining($"[{-5}]"); } [Test] @@ -347,6 +348,6 @@ await Assert.That(async () => await Assert.That(items).All(x => x > 0) ).Throws() .WithMessageContaining("index 3") - .And.WithMessageContaining("[-1]"); + .And.WithMessageContaining($"[{-1}]"); } } diff --git a/tests/TUnit.Assertions.Tests/Old/StringAssertionTests.cs b/tests/TUnit.Assertions.Tests/Old/StringAssertionTests.cs index 183c8b994a9..9dd75f47667 100644 --- a/tests/TUnit.Assertions.Tests/Old/StringAssertionTests.cs +++ b/tests/TUnit.Assertions.Tests/Old/StringAssertionTests.cs @@ -4,65 +4,6 @@ namespace TUnit.Assertions.Tests.Old; public class StringAssertionTests { - // IsNullOrEmpty and IsNullOrWhiteSpace are not available in current API - // These tests are commented out as they test deprecated functionality - - //[Test] - //public async Task NullOrEmpty_String() - //{ - // var str = "Hello"; - // await TUnitAssert.ThrowsAsync(async () => await TUnitAssert.That(str).IsNullOrEmpty()); - //} - - //[Test] - //public async Task NullOrEmpty_Whitespace() - //{ - // var str = " "; - // await TUnitAssert.ThrowsAsync(async () => await TUnitAssert.That(str).IsNullOrEmpty()); - //} - - //[Test] - //public async Task NullOrEmpty_Null() - //{ - // string? str = null; - // await TUnitAssert.That(str).IsNullOrEmpty(); - //} - - //[Test] - //public async Task NullOrEmpty_Empty() - //{ - // var str = ""; - // await TUnitAssert.That(str).IsNullOrEmpty(); - //} - - //[Test] - //public async Task NullOrWhitespace_String() - //{ - // var str = "Hello"; - // await TUnitAssert.ThrowsAsync(async () => await TUnitAssert.That(str).IsNullOrWhiteSpace()); - //} - - //[Test] - //public async Task NullOrWhitespace_Whitespace() - //{ - // var str = " "; - // await TUnitAssert.That(str).IsNullOrWhiteSpace(); - //} - - //[Test] - //public async Task NullOrWhitespace_Null() - //{ - // string? str = null; - // await TUnitAssert.That(str).IsNullOrWhiteSpace(); - //} - - //[Test] - //public async Task NullOrWhitespace_Empty() - //{ - // var str = ""; - // await TUnitAssert.That(str).IsNullOrWhiteSpace(); - //} - [Test] public async Task Null_String() { diff --git a/tests/TUnit.Assertions.Tests/RangeAssertionTests.cs b/tests/TUnit.Assertions.Tests/RangeAssertionTests.cs index 6d6ef7f7ff8..0ef3acdfb3d 100644 --- a/tests/TUnit.Assertions.Tests/RangeAssertionTests.cs +++ b/tests/TUnit.Assertions.Tests/RangeAssertionTests.cs @@ -33,35 +33,32 @@ public async Task Test_Range_HasStartFromBeginning_Mixed() await Assert.That(range).HasStartFromBeginning(); } - // Note: HasEndFromBeginning and IsAll are not yet generated by the source generator - // These tests are commented out until the .NET 6+ type generation issue is resolved - - // [Test] - // public async Task Test_Range_HasEndFromBeginning() - // { - // Range range = 0..10; // From start to index 10 - // await Assert.That(range).HasEndFromBeginning(); - // } + [Test] + public async Task Test_Range_HasEndFromBeginning() + { + Range range = 0..10; // From start to index 10 + await Assert.That(range).HasEndFromBeginning(); + } - // [Test] - // public async Task Test_Range_HasEndFromBeginning_Mixed() - // { - // Range range = ^5..10; // From 5th from end to index 10 - // await Assert.That(range).HasEndFromBeginning(); - // } + [Test] + public async Task Test_Range_HasEndFromBeginning_Mixed() + { + Range range = ^5..10; // From 5th from end to index 10 + await Assert.That(range).HasEndFromBeginning(); + } - // [Test] - // public async Task Test_Range_IsAll() - // { - // Range range = ..; // All elements - // await Assert.That(range).IsAll(); - // } + [Test] + public async Task Test_Range_IsFullRange() + { + Range range = ..; // All elements + await Assert.That(range).IsFullRange(); + } - // [Test] - // public async Task Test_Range_IsAll_Explicit() - // { - // var range = Range.All; - // await Assert.That(range).IsAll(); - // } + [Test] + public async Task Test_Range_IsFullRange_Explicit() + { + var range = Range.All; + await Assert.That(range).IsFullRange(); + } } #endif diff --git a/tests/TUnit.Core.SourceGenerator.Tests/ReferencesHelper.cs b/tests/TUnit.Core.SourceGenerator.Tests/ReferencesHelper.cs index bb6cd3706dd..ea37a8e8e01 100644 --- a/tests/TUnit.Core.SourceGenerator.Tests/ReferencesHelper.cs +++ b/tests/TUnit.Core.SourceGenerator.Tests/ReferencesHelper.cs @@ -1,5 +1,6 @@ using System.Diagnostics.CodeAnalysis; using Microsoft.CodeAnalysis; +using TUnit.Tests.Shared; namespace TUnit.Core.SourceGenerator.Tests; @@ -7,14 +8,8 @@ namespace TUnit.Core.SourceGenerator.Tests; internal class ReferencesHelper { public static readonly List References = - AppDomain.CurrentDomain.GetAssemblies() - .Where(x => !x.IsDynamic && !string.IsNullOrWhiteSpace(x.Location)) - .Select(x => MetadataReference.CreateFromFile(x.Location)) - .Concat([ - // add your app/lib specifics, e.g.: - MetadataReference.CreateFromFile(typeof(Attribute).Assembly.Location), - MetadataReference.CreateFromFile(typeof(Assert).Assembly.Location), - MetadataReference.CreateFromFile(typeof(Polyfill).Assembly.Location), - ]) - .ToList(); + TestHostReferences.CreateReferences( + typeof(Attribute).Assembly, + typeof(Assert).Assembly, + typeof(Polyfill).Assembly); } diff --git a/tests/TUnit.Core.SourceGenerator.Tests/TUnit.Core.SourceGenerator.Tests.csproj b/tests/TUnit.Core.SourceGenerator.Tests/TUnit.Core.SourceGenerator.Tests.csproj index ef364e55c2b..ac6312ae986 100644 --- a/tests/TUnit.Core.SourceGenerator.Tests/TUnit.Core.SourceGenerator.Tests.csproj +++ b/tests/TUnit.Core.SourceGenerator.Tests/TUnit.Core.SourceGenerator.Tests.csproj @@ -13,6 +13,10 @@ $(NoWarn);MSB3277 + + + + @@ -39,11 +43,6 @@ - - - all - runtime; build; native; contentfiles; analyzers; buildtransitive - diff --git a/tests/TUnit.Core.Tests/Helpers/ArgumentFormatterTests.cs b/tests/TUnit.Core.Tests/Helpers/ArgumentFormatterTests.cs deleted file mode 100644 index e0df369cf34..00000000000 --- a/tests/TUnit.Core.Tests/Helpers/ArgumentFormatterTests.cs +++ /dev/null @@ -1,96 +0,0 @@ -using TUnit.Core.Helpers; - -namespace TUnit.Core.Tests.Helpers; - -public class ArgumentFormatterTests -{ - [Test] - public void FormatDefault_ValueTuple_FormatsCorrectly() - { - var tuple = (1, "test", true); - - var result = ArgumentFormatter.Format(tuple, []); - - Assert.That(result, Is.EqualTo("(1, test, true)")); - } - - [Test] - public void FormatDefault_NestedValueTuple_FormatsCorrectly() - { - var tuple = (1, (2, "inner"), true); - - var result = ArgumentFormatter.Format(tuple, []); - - Assert.That(result, Is.EqualTo("(1, (2, inner), true)")); - } - - [Test] - public void FormatDefault_SystemTuple_FormatsCorrectly() - { - var tuple = Tuple.Create(1, "test", false); - - var result = ArgumentFormatter.Format(tuple, []); - - Assert.That(result, Is.EqualTo("(1, test, false)")); - } - - [Test] - public void FormatArguments_WithTuples_FormatsCorrectly() - { - var args = new object?[] { (1, "a"), 42, (true, 3.14) }; - - var result = ArgumentFormatter.FormatArguments(args); - - Assert.That(result, Is.EqualTo("(1, a), 42, (true, 3.14)")); - } - - [Test] - public void FormatDefault_LargeTuple_FormatsAllElements() - { - var tuple = (1, 2, 3, 4, 5, 6, 7, 8); - - var result = ArgumentFormatter.Format(tuple, []); - - Assert.That(result, Is.EqualTo("(1, 2, 3, 4, 5, 6, 7, 8)")); - } - - [Test] - public void FormatDefault_TupleWithNull_HandlesNullCorrectly() - { - var tuple = (1, null, "test"); - - var result = ArgumentFormatter.Format(tuple, []); - - Assert.That(result, Is.EqualTo("(1, null, test)")); - } - - [Test] - public void FormatDefault_StringWithDots_EscapesDotsWithMiddleDot() - { - var stringWithDots = "1.2.3"; - - var result = ArgumentFormatter.Format(stringWithDots, []); - - Assert.That(result, Is.EqualTo("1·2·3")); - } - - [Test] - public void FormatDefault_StringWithoutDots_ReturnsUnchanged() - { - var stringWithoutDots = "hello world"; - - var result = ArgumentFormatter.Format(stringWithoutDots, []); - - Assert.That(result, Is.EqualTo("hello world")); - } - - [Test] - public void FormatArguments_WithStringsContainingDots_EscapesDots() - { - var args = new object?[] { "hello", "with.dot", "1.2.3" }; - - var result = ArgumentFormatter.FormatArguments(args); - - Assert.That(result, Is.EqualTo("hello, with·dot, 1·2·3")); - } -} \ No newline at end of file diff --git a/tests/TUnit.Engine.Tests/DotNetCliTests.cs b/tests/TUnit.Engine.Tests/DotNetCliTests.cs new file mode 100644 index 00000000000..b06c68b514e --- /dev/null +++ b/tests/TUnit.Engine.Tests/DotNetCliTests.cs @@ -0,0 +1,25 @@ +using CliWrap; +using CliWrap.Buffered; +using Shouldly; +using TUnit.Tests.Shared; + +namespace TUnit.Engine.Tests; + +/// +/// Checks that , which every test here starts child builds with, resolves an SDK for this +/// repository. +/// +public class DotNetCliTests +{ + [Test] + public async Task Path_Resolves_An_Sdk_For_This_Repository() + { + var result = await Cli.Wrap(DotNetCli.Path) + .WithArguments("--version") + .WithWorkingDirectory(AppContext.BaseDirectory) + .WithValidation(CommandResultValidation.None) + .ExecuteBufferedAsync(); + + result.ExitCode.ShouldBe(0, $"'{DotNetCli.Path} --version' failed:{Environment.NewLine}{result.StandardOutput}{result.StandardError}"); + } +} diff --git a/tests/TUnit.Engine.Tests/EnvironmentVariables.cs b/tests/TUnit.Engine.Tests/EnvironmentVariables.cs index 17966a0bc1f..188f209a760 100644 --- a/tests/TUnit.Engine.Tests/EnvironmentVariables.cs +++ b/tests/TUnit.Engine.Tests/EnvironmentVariables.cs @@ -1,4 +1,6 @@ -namespace TUnit.Engine.Tests; +using System.Reflection; + +namespace TUnit.Engine.Tests; public class EnvironmentVariables { @@ -6,6 +8,11 @@ public class EnvironmentVariables public static readonly bool IsNetFramework = NetVersion?.StartsWith("net4") == true; + // The launched test applications are built as project references of this project, so they share its + // configuration: Release in CI, Debug when an IDE builds and runs the solution. + public static readonly string BuildConfiguration = + typeof(EnvironmentVariables).Assembly.GetCustomAttribute()?.Configuration ?? "Release"; + // Keep the report for the outer TUnit.Engine.Tests suite, but do not generate or upload // reports for the short-lived test applications that it launches as implementation details. public static Dictionary DisableHtmlReporterForChildProcess() => new() diff --git a/tests/TUnit.Engine.Tests/ExternalCancellationTests.cs b/tests/TUnit.Engine.Tests/ExternalCancellationTests.cs index 87c988a9879..3d0aa73120d 100644 --- a/tests/TUnit.Engine.Tests/ExternalCancellationTests.cs +++ b/tests/TUnit.Engine.Tests/ExternalCancellationTests.cs @@ -46,7 +46,7 @@ private async Task RunTestWithExternalCancellation(string filter, string markerF using var forcefulCancellationTokenSource = new CancellationTokenSource(TimeSpan.FromSeconds(25)); // Use cross-platform executable detection (Linux: no extension, Windows: .exe) - var binDir = new DirectoryInfo(Path.Combine(testProject.DirectoryName!, "bin", "Release", GetEnvironmentVariable)); + var binDir = new DirectoryInfo(Path.Combine(testProject.DirectoryName!, "bin", EnvironmentVariables.BuildConfiguration, GetEnvironmentVariable)); var file = binDir.GetFiles("TUnit.TestProject").FirstOrDefault()?.FullName ?? binDir.GetFiles("TUnit.TestProject.exe").First().FullName; diff --git a/tests/TUnit.Engine.Tests/FSharp.cs b/tests/TUnit.Engine.Tests/FSharp.cs index 3ec701c4ef2..8bbad4ce7a4 100644 --- a/tests/TUnit.Engine.Tests/FSharp.cs +++ b/tests/TUnit.Engine.Tests/FSharp.cs @@ -2,6 +2,7 @@ using CliWrap.Buffered; using Shouldly; using TUnit.Engine.Tests.Enums; +using TUnit.Tests.Shared; namespace TUnit.Engine.Tests; @@ -15,13 +16,13 @@ public async Task Test() var testProject = Sourcy.DotNet.Projects.TUnit_TestProject_FSharp; var guid = Guid.NewGuid().ToString("N"); var trxFilename = guid + ".trx"; - var command = Cli.Wrap("dotnet") + var command = Cli.Wrap(DotNetCli.Path) .WithArguments( [ "run", "--no-build", "-f", "net10.0", - "--configuration", "Release", + "--configuration", EnvironmentVariables.BuildConfiguration, "--report-trx", "--report-trx-filename", trxFilename, "--diagnostic-verbosity", "Debug", "--diagnostic", "--diagnostic-file-prefix", $"log_{GetType().Name}_", diff --git a/tests/TUnit.Engine.Tests/HtmlReportCliTests.cs b/tests/TUnit.Engine.Tests/HtmlReportCliTests.cs index 4a1839a641e..cd25055a023 100644 --- a/tests/TUnit.Engine.Tests/HtmlReportCliTests.cs +++ b/tests/TUnit.Engine.Tests/HtmlReportCliTests.cs @@ -2,6 +2,7 @@ using CliWrap.Buffered; using Shouldly; using TUnit.Engine.Tests.Enums; +using TUnit.Tests.Shared; namespace TUnit.Engine.Tests; @@ -94,7 +95,7 @@ private static Task RunTUnitOnlyProject( "--no-build", "--project", testProject.FullName, "--framework", "net10.0", - "--configuration", "Release", + "--configuration", EnvironmentVariables.BuildConfiguration, "--", "--treenode-filter", "/*/*/DefaultHtmlReportTests/Pass", "--results-directory", resultsDirectory, @@ -106,7 +107,7 @@ private static Task RunTUnitOnlyProject( arguments.Add("--reflection"); } - return Cli.Wrap("dotnet") + return Cli.Wrap(DotNetCli.Path) .WithArguments(arguments) .WithWorkingDirectory(testProject.DirectoryName!) .WithEnvironmentVariables(new Dictionary diff --git a/tests/TUnit.Engine.Tests/InvokableTestBase.cs b/tests/TUnit.Engine.Tests/InvokableTestBase.cs index 47c4c3ad36e..2646ec041ea 100644 --- a/tests/TUnit.Engine.Tests/InvokableTestBase.cs +++ b/tests/TUnit.Engine.Tests/InvokableTestBase.cs @@ -57,7 +57,7 @@ private async Task RunWithoutAot(string filter, { var testProject = Sourcy.DotNet.Projects.TUnit_TestProject; var projectName = Path.GetFileNameWithoutExtension(testProject.Name); - var binDir = new DirectoryInfo(Path.Combine(testProject.DirectoryName!, "bin", "Release", GetEnvironmentVariable)); + var binDir = new DirectoryInfo(Path.Combine(testProject.DirectoryName!, "bin", EnvironmentVariables.BuildConfiguration, GetEnvironmentVariable)); var executable = binDir.EnumerateFiles(projectName).FirstOrDefault() ?? binDir.EnumerateFiles(projectName + ".exe").First(); diff --git a/tests/TUnit.Engine.Tests/ListTestsFilterTests.cs b/tests/TUnit.Engine.Tests/ListTestsFilterTests.cs index 241929889c0..184577ca8dc 100644 --- a/tests/TUnit.Engine.Tests/ListTestsFilterTests.cs +++ b/tests/TUnit.Engine.Tests/ListTestsFilterTests.cs @@ -52,7 +52,7 @@ private static async Task RunListTestsAsync(bool reflecti { var testProject = Sourcy.DotNet.Projects.TUnit_TestProject; var projectName = Path.GetFileNameWithoutExtension(testProject.Name); - var binDir = new DirectoryInfo(Path.Combine(testProject.DirectoryName!, "bin", "Release", NetVersion)); + var binDir = new DirectoryInfo(Path.Combine(testProject.DirectoryName!, "bin", EnvironmentVariables.BuildConfiguration, NetVersion)); var executable = binDir.EnumerateFiles(projectName).FirstOrDefault() ?? binDir.EnumerateFiles(projectName + ".exe").First(); diff --git a/tests/TUnit.Engine.Tests/SigtermTests.cs b/tests/TUnit.Engine.Tests/SigtermTests.cs index c447c78361a..871b54469b4 100644 --- a/tests/TUnit.Engine.Tests/SigtermTests.cs +++ b/tests/TUnit.Engine.Tests/SigtermTests.cs @@ -26,7 +26,7 @@ public async Task Sigterm_Cancels_Gracefully_And_Runs_After_Hooks(bool reflectio var afterMarker = Path.Combine(markerDirectory, "after.txt"); var testProject = Sourcy.DotNet.Projects.TUnit_TestProject; - var executable = Path.Combine(testProject.DirectoryName!, "bin", "Release", NetVersion, "TUnit.TestProject"); + var executable = Path.Combine(testProject.DirectoryName!, "bin", EnvironmentVariables.BuildConfiguration, NetVersion, "TUnit.TestProject"); var environmentVariables = EnvironmentVariables.DisableHtmlReporterForChildProcess(); environmentVariables["TUNIT_SIGTERM_MARKER_DIR"] = markerDirectory; diff --git a/tests/TUnit.Engine.Tests/TUnit.Engine.Tests.csproj b/tests/TUnit.Engine.Tests/TUnit.Engine.Tests.csproj index eae576b9440..10e8d4dbe11 100644 --- a/tests/TUnit.Engine.Tests/TUnit.Engine.Tests.csproj +++ b/tests/TUnit.Engine.Tests/TUnit.Engine.Tests.csproj @@ -8,6 +8,10 @@ ..\..\eng\strongname.snk + + + + @@ -29,6 +33,11 @@ + + + + diff --git a/tests/TUnit.Engine.Tests/VB.cs b/tests/TUnit.Engine.Tests/VB.cs index 936ec40e4ea..54cb789a57e 100644 --- a/tests/TUnit.Engine.Tests/VB.cs +++ b/tests/TUnit.Engine.Tests/VB.cs @@ -2,6 +2,7 @@ using CliWrap.Buffered; using Shouldly; using TUnit.Engine.Tests.Enums; +using TUnit.Tests.Shared; namespace TUnit.Engine.Tests; @@ -15,13 +16,13 @@ public async Task Test() var testProject = Sourcy.DotNet.Projects.TUnit_TestProject_VB_NET; var guid = Guid.NewGuid().ToString("N"); var trxFilename = guid + ".trx"; - var command = Cli.Wrap("dotnet") + var command = Cli.Wrap(DotNetCli.Path) .WithArguments( [ "run", "--no-build", "-f", "net10.0", - "--configuration", "Release", + "--configuration", EnvironmentVariables.BuildConfiguration, "--report-trx", "--report-trx-filename", trxFilename, "--diagnostic-verbosity", "Debug", "--diagnostic", "--diagnostic-file-prefix", $"log_{GetType().Name}_", diff --git a/tests/TUnit.IntegrationTests/CleanArchitectureTests.cs b/tests/TUnit.IntegrationTests/CleanArchitectureTests.cs deleted file mode 100644 index 1e02201da74..00000000000 --- a/tests/TUnit.IntegrationTests/CleanArchitectureTests.cs +++ /dev/null @@ -1,279 +0,0 @@ -using System; -using System.Linq; -using System.Threading.Tasks; -using TUnit.Assertions; -using TUnit.Core; - -namespace TUnit.IntegrationTests; - -/// -/// Integration tests to verify the clean architecture with TestMetadataGenerator and TestBuilder works correctly. -/// -public class CleanArchitectureTests -{ - [Test] - public async Task SimpleTest_ExecutesCorrectly() - { - // This test verifies that a simple test is discovered and executed - var executed = false; - SimpleTestMarker.WasExecuted = false; - - // The test should have been discovered by TestMetadataGenerator - // and executed by TestBuilder - await Task.Delay(100); // Give time for test execution - - await Assert.That(SimpleTestMarker.WasExecuted).IsTrue(); - } - - [Test] - [Arguments(1, 2, 3)] - [Arguments(4, 5, 6)] - public async Task ParameterizedTest_ReceivesCorrectArguments(int a, int b, int expected) - { - var sum = a + b; - await Assert.That(sum).IsEqualTo(expected); - } - - [Test] - [MethodDataSource(nameof(GetTestData))] - public async Task MethodDataSourceTest_ReceivesData(string input, int expected) - { - await Assert.That(input.Length).IsEqualTo(expected); - } - - public static IEnumerable<(string, int)> GetTestData() - { - yield return ("hello", 5); - yield return ("world", 5); - yield return ("test", 4); - } - - [Test] - [Repeat(3)] - public async Task RepeatedTest_ExecutesMultipleTimes() - { - RepeatTestCounter.Count++; - await Assert.That(RepeatTestCounter.Count).IsGreaterThanOrEqualTo(1); - } - - [Test] - [Skip("Testing skip functionality")] - public async Task SkippedTest_ShouldNotExecute() - { - SkipTestMarker.WasExecuted = true; - await Assert.That(false).IsTrue(); // Should never reach here - } - - [Test] - [Timeout(1000)] - public async Task TimeoutTest_HasCorrectTimeout() - { - // This test should complete within the timeout - await Task.Delay(100); - await Assert.That(true).IsTrue(); - } - - // Helper classes for test state - private static class SimpleTestMarker - { - public static bool WasExecuted { get; set; } - } - - private static class RepeatTestCounter - { - public static int Count { get; set; } - } - - private static class SkipTestMarker - { - public static bool WasExecuted { get; set; } - } -} - -public class SimpleTestClass -{ - [Test] - public void SimpleTest() - { - CleanArchitectureTests.SimpleTestMarker.WasExecuted = true; - } -} - -/// -/// Tests for class-level data sources and constructor injection. -/// -[ClassDataSource(typeof(ClassTestData))] -public class ClassDataSourceTests -{ - private readonly int _value; - - public ClassDataSourceTests(int value) - { - _value = value; - } - - [Test] - public async Task ClassConstructor_ReceivesData() - { - await Assert.That(_value).IsGreaterThan(0); - } - - public class ClassTestData : IEnumerable - { - public IEnumerator GetEnumerator() - { - yield return 1; - yield return 2; - yield return 3; - } - - System.Collections.IEnumerator System.Collections.IEnumerable.GetEnumerator() => GetEnumerator(); - } -} - -/// -/// Tests for property injection with data sources. -/// -public class PropertyInjectionTests -{ - [Arguments("injected")] - public string? TestProperty { get; set; } - - [Test] - public async Task PropertyInjection_Works() - { - await Assert.That(TestProperty).IsNotNull(); - await Assert.That(TestProperty).IsEqualTo("injected"); - } -} - -/// -/// Tests for async test methods. -/// -public class AsyncTests -{ - [Test] - public async Task AsyncTest_ExecutesCorrectly() - { - await Task.Delay(10); - await Assert.That(true).IsTrue(); - } - - [Test] - public async ValueTask ValueTaskTest_ExecutesCorrectly() - { - await Task.Delay(10); - await Assert.That(true).IsTrue(); - } -} - -/// -/// Tests for complex scenarios combining multiple features. -/// -public class ComplexScenarioTests -{ - [Test] - [Arguments(1, "one")] - [Arguments(2, "two")] - [Repeat(2)] - public async Task ComplexTest_WithMultipleFeatures(int number, string text) - { - await Assert.That(number).IsGreaterThan(0); - await Assert.That(text).IsNotNull(); - await Assert.That(text.Length).IsGreaterThan(0); - } - - [Test] - [MethodDataSource(nameof(GetComplexData))] - [Timeout(2000)] - public async Task ComplexDataDrivenTest(ComplexTestData data) - { - await Assert.That(data).IsNotNull(); - await Assert.That(data.Id).IsGreaterThan(0); - await Assert.That(data.Name).IsNotNull(); - await Task.Delay(100); // Simulate some work - } - - public static IEnumerable GetComplexData() - { - yield return new ComplexTestData { Id = 1, Name = "First" }; - yield return new ComplexTestData { Id = 2, Name = "Second" }; - } - - public class ComplexTestData - { - public int Id { get; set; } - public string Name { get; set; } = ""; - } -} - -/// -/// Tests to verify the source generator handles edge cases correctly. -/// -public class EdgeCaseTests -{ - [Test] - public void VoidReturnType_Works() - { - // Void return type should work - } - - [Test] - public Task TaskReturnType_Works() - { - // Task return type should work - return Task.CompletedTask; - } - - [Test] - public ValueTask ValueTaskReturnType_Works() - { - // ValueTask return type should work - return ValueTask.CompletedTask; - } - - [Test] - [Arguments(null, null)] - public async Task NullArguments_HandleCorrectly(string? arg1, object? arg2) - { - await Assert.That(arg1).IsNull(); - await Assert.That(arg2).IsNull(); - } - - [Test] - [Arguments(new[] { 1, 2, 3 })] - public async Task ArrayArguments_Work(int[] values) - { - await Assert.That(values).Count().IsEqualTo(3); - await Assert.That(values[0]).IsEqualTo(1); - } -} - -/// -/// Verification tests to ensure the clean architecture is working. -/// -public class ArchitectureVerificationTests -{ - [Test] - public async Task TestMetadataIsGenerated_NotComplexCode() - { - // This test verifies that TestMetadataGenerator is being used - // If complex code generation was happening, we'd see different behavior - - // The fact that all our tests work proves TestMetadata + TestBuilder is functioning - await Assert.That(true).IsTrue(); - } - - [Test] - public async Task TestBuilder_HandlesAllComplexLogic() - { - // TestBuilder should handle: - // - Data source enumeration - // - Tuple unwrapping - // - Property injection - // - Test instance creation - - // The fact that our data-driven tests work proves this - await Assert.That(true).IsTrue(); - } -} \ No newline at end of file diff --git a/tests/TUnit.Mocks.InternalsAccess.Tests/DesignTimeProjectReferenceTests.cs b/tests/TUnit.Mocks.InternalsAccess.Tests/DesignTimeProjectReferenceTests.cs index 66c0efbc43a..d02f0bb22c9 100644 --- a/tests/TUnit.Mocks.InternalsAccess.Tests/DesignTimeProjectReferenceTests.cs +++ b/tests/TUnit.Mocks.InternalsAccess.Tests/DesignTimeProjectReferenceTests.cs @@ -2,6 +2,7 @@ using System.Security; using System.Text; using System.Text.Json; +using TUnit.Tests.Shared; using Task = System.Threading.Tasks.Task; namespace TUnit.Mocks.InternalsAccess.Tests; @@ -230,7 +231,7 @@ private static List ArgumentsFor(bool designTimeBuild) private static async Task RunAsync(string verb, string project, params string[] arguments) { - var startInfo = new ProcessStartInfo("dotnet") + var startInfo = new ProcessStartInfo(DotNetCli.Path) { RedirectStandardOutput = true, RedirectStandardError = true, diff --git a/tests/TUnit.Mocks.InternalsAccess.Tests/TUnit.Mocks.InternalsAccess.Tests.csproj b/tests/TUnit.Mocks.InternalsAccess.Tests/TUnit.Mocks.InternalsAccess.Tests.csproj index c9a606d0eb6..907375df137 100644 --- a/tests/TUnit.Mocks.InternalsAccess.Tests/TUnit.Mocks.InternalsAccess.Tests.csproj +++ b/tests/TUnit.Mocks.InternalsAccess.Tests/TUnit.Mocks.InternalsAccess.Tests.csproj @@ -8,6 +8,10 @@ true + + + + @@ -29,6 +33,9 @@ + + diff --git a/tests/TUnit.Mocks.SourceGenerator.Tests/SnapshotTestBase.cs b/tests/TUnit.Mocks.SourceGenerator.Tests/SnapshotTestBase.cs index 99eb4a14c32..2261096039d 100644 --- a/tests/TUnit.Mocks.SourceGenerator.Tests/SnapshotTestBase.cs +++ b/tests/TUnit.Mocks.SourceGenerator.Tests/SnapshotTestBase.cs @@ -2,6 +2,7 @@ using System.Text; using Microsoft.CodeAnalysis; using Microsoft.CodeAnalysis.CSharp; +using TUnit.Tests.Shared; namespace TUnit.Mocks.SourceGenerator.Tests; @@ -16,7 +17,7 @@ public abstract class SnapshotTestBase /// /// Returns the shared, lazily-loaded set of metadata references used by the test compilations - /// (current AppDomain assemblies, with exactly one TUnit.Mocks reference). Derived test classes + /// (the test host's assemblies, with exactly one TUnit.Mocks reference). Derived test classes /// should reuse this instead of re-discovering references per test invocation. /// protected static IEnumerable GetCachedReferences() => _references.Value; @@ -38,15 +39,10 @@ private static List LoadReferences() "No TUnit.Mocks reference available to the test compilations — the generator would silently produce nothing."); } - var refs = AppDomain.CurrentDomain.GetAssemblies() - .Where(a => !a.IsDynamic && !string.IsNullOrWhiteSpace(a.Location)) - .Where(a => a != mocksAssembly) - .Select(a => MetadataReference.CreateFromFile(a.Location)) - .ToList(); - - refs.Add(MetadataReference.CreateFromFile(mocksAssembly.Location)); - - return refs; + var mocksFileName = Path.GetFileName(mocksAssembly.Location); + return TestHostReferences.CreateReferences( + path => !string.Equals(Path.GetFileName(path), mocksFileName, StringComparison.OrdinalIgnoreCase), + mocksAssembly); } /// diff --git a/tests/TUnit.Mocks.SourceGenerator.Tests/TUnit.Mocks.SourceGenerator.Tests.csproj b/tests/TUnit.Mocks.SourceGenerator.Tests/TUnit.Mocks.SourceGenerator.Tests.csproj index f495e7553e9..c2856892c32 100644 --- a/tests/TUnit.Mocks.SourceGenerator.Tests/TUnit.Mocks.SourceGenerator.Tests.csproj +++ b/tests/TUnit.Mocks.SourceGenerator.Tests/TUnit.Mocks.SourceGenerator.Tests.csproj @@ -2,6 +2,10 @@ + + + + diff --git a/tests/TUnit.Mocks.Tests/AsyncTests.cs b/tests/TUnit.Mocks.Tests/AsyncTests.cs index df46158d069..88a89d950c8 100644 --- a/tests/TUnit.Mocks.Tests/AsyncTests.cs +++ b/tests/TUnit.Mocks.Tests/AsyncTests.cs @@ -438,6 +438,7 @@ public async Task Typed_Throws_On_Async_ValueTask_Method() IAsyncService service = mock.Object; var ex = await Assert.ThrowsAsync(async () => await service.ComputeValueTaskAsync(-1)); - await Assert.That(ex.Message).Contains("Invalid input: -1"); + // Formatted the same way as the factory above, so it matches under any culture. + await Assert.That(ex.Message).Contains($"Invalid input: {-1}"); } } diff --git a/tests/TUnit.Mocks.Tests/WrapNoParameterlessCtorTests.cs b/tests/TUnit.Mocks.Tests/WrapNoParameterlessCtorTests.cs index 6f44a9bd990..cd2131a1fed 100644 --- a/tests/TUnit.Mocks.Tests/WrapNoParameterlessCtorTests.cs +++ b/tests/TUnit.Mocks.Tests/WrapNoParameterlessCtorTests.cs @@ -43,7 +43,7 @@ public WrapMultiParam(string label, int count, double factor) _count = count; _factor = factor; } - public virtual string Compute() => $"{_label}:{_count}:{_factor}"; + public virtual string Compute() => FormattableString.Invariant($"{_label}:{_count}:{_factor}"); } public class WrapParamsOnly diff --git a/tests/TUnit.OpenTelemetry.Tests/TUnit.OpenTelemetry.Tests.csproj b/tests/TUnit.OpenTelemetry.Tests/TUnit.OpenTelemetry.Tests.csproj index 6166f253494..ce0633489bd 100644 --- a/tests/TUnit.OpenTelemetry.Tests/TUnit.OpenTelemetry.Tests.csproj +++ b/tests/TUnit.OpenTelemetry.Tests/TUnit.OpenTelemetry.Tests.csproj @@ -1,6 +1,6 @@ - + net10.0 @@ -11,17 +11,14 @@ - - - - - + + diff --git a/tests/TUnit.PublicAPI/SourcePathScrubberTests.cs b/tests/TUnit.PublicAPI/SourcePathScrubberTests.cs new file mode 100644 index 00000000000..6077c58e3bf --- /dev/null +++ b/tests/TUnit.PublicAPI/SourcePathScrubberTests.cs @@ -0,0 +1,63 @@ +namespace TUnit.PublicAPI; + +public class SourcePathScrubberTests +{ + [Test] + [Arguments("[.Before(., \"/_/TUnit.OpenTelemetry/File.cs\", 39, Order=-2147482648)]")] + [Arguments("[.After(., \"/_/F.cs\", 7)]")] + [Arguments("[.Before(., \"C:\\\\a\\\\File.cs\", 39)]")] + [Arguments("[.Before(., \"C:/a/File.cs\", 39)]")] + public async Task Scrubs_Single_Line_Caller_File_Paths(string line) + { + var scrubbed = Tests.ScrubSourcePaths(line); + + await Assert.That(scrubbed).Contains("\"PATH_SCRUBBED\""); + await Assert.That(scrubbed).DoesNotContain("File.cs"); + } + + [Test] + public async Task Scrubs_Wrapped_Unix_Caller_File_Path() + { + var text = "[.Before(., \"/home/user/src/TUnit/TUnit.OpenTelemetry/AutoStart/\" +\n" + + " \"TUnitOpenTelemetryAutoStart.cs\", 39, Order=-2147482648)]"; + + var scrubbed = Tests.ScrubSourcePaths(text); + + await Assert.That(scrubbed).IsEqualTo("[.Before(., \"PATH_SCRUBBED\", 39, Order=-2147482648)]"); + } + + [Test] + public async Task Scrubs_Wrapped_Windows_Caller_File_Path() + { + var text = "[.After(., \"C:\\\\Users\\\\dev\\\\source\\\\repos\\\\TUnit\\\\TUnit.OpenTelemetry\\\\\" +\r\n" + + " \"AutoStart\\\\TUnitOpenTelemetryAutoStart.cs\", 61)]"; + + var scrubbed = Tests.ScrubSourcePaths(text); + + await Assert.That(scrubbed).IsEqualTo("[.After(., \"PATH_SCRUBBED\", 61)]"); + } + + [Test] + public async Task Scrubs_Wrapped_Windows_Caller_File_Path_With_Forward_Slashes() + { + var text = "[.After(., \"C:/Users/dev/source/repos/TUnit/TUnit.OpenTelemetry/\" +\r\n" + + " \"AutoStart/TUnitOpenTelemetryAutoStart.cs\", 61)]"; + + var scrubbed = Tests.ScrubSourcePaths(text); + + await Assert.That(scrubbed).IsEqualTo("[.After(., \"PATH_SCRUBBED\", 61)]"); + } + + [Test] + [Arguments("public const string Prefix = \"/v1\";")] + [Arguments("[Route(\"/v1\", 2)]")] + [Arguments("public const string Template = \"/api/File.cs\";")] + [Arguments("[Description(\"C:\\\\docs\\\\readme.md\")]")] + [Arguments("[Description(\"File.cs\", 39)]")] + [Arguments("[Route(\"/api/File.cs\", 2)]")] + [Arguments("[Route(\"C:/api/File.cs\", 2)]")] + public async Task Leaves_Unrelated_Strings_Alone(string line) + { + await Assert.That(Tests.ScrubSourcePaths(line)).IsEqualTo(line); + } +} diff --git a/tests/TUnit.PublicAPI/Tests.cs b/tests/TUnit.PublicAPI/Tests.cs index 4bef708f001..9e847eb10f1 100644 --- a/tests/TUnit.PublicAPI/Tests.cs +++ b/tests/TUnit.PublicAPI/Tests.cs @@ -42,12 +42,7 @@ private async Task VerifyPublicApi(Assembly assembly) await VerifyTUnit.Verify(publicApi) .AddScrubber(sb => { - // Scrub deterministic source paths (e.g. "/_/TUnit.OpenTelemetry/File.cs") - // before the URL regex mangles them into bare "/_/". - var replaced = System.Text.RegularExpressions.Regex.Replace( - sb.ToString(), - @"/_/[^""\s,)]*", - "PATH_SCRUBBED"); + var replaced = ScrubSourcePaths(sb.ToString()); sb.Clear(); sb.Append(replaced); return sb; @@ -73,6 +68,15 @@ await VerifyTUnit.Verify(publicApi) .UniqueForTargetFrameworkAndVersion(assembly); } + /// + /// Scrubs source path literals (hook attributes' [CallerFilePath] argument) before the URL regex mangles + /// them. CI builds embed deterministic "/_/..." paths; local builds embed the full checkout path, which the + /// generator wraps into "..." + "..." pieces once it exceeds 80 characters. Only a rooted ".cs" path passed to a + /// hook attribute and followed by the [CallerLineNumber] argument matches, so public string values such as + /// "/v1" and other attributes' arguments are left alone. + /// + internal static string ScrubSourcePaths(string text) => SourcePathRegex().Replace(text, @"""PATH_SCRUBBED"""); + private StringBuilder Scrub(StringBuilder text) { var newText = UrlRegex().Replace(text.ToString(), string.Empty) @@ -94,10 +98,22 @@ private string Scrub(string text) } + /// + /// The first string argument of a Before/After(Every) hook attribute that is a rooted ".cs" literal, possibly + /// wrapped into "..." + "..." pieces, followed by the caller line number argument. See . + /// + private const string SourcePathPattern = + @"(?<=\b(?:Before|After)(?:Every)?\([^""\r\n]*)""(?:/|[A-Za-z]:(?:\\\\|/))[^""\r\n]*(?:""[ \t]*\+[ \t]*\r?\n[ \t]*""[^""\r\n]*)*\.cs""(?=,[ \t]*\d+[,)])"; + #if NET + [GeneratedRegex(SourcePathPattern)] + private static partial Regex SourcePathRegex(); + [GeneratedRegex(@"((http|https):\/\/)?(www\.)?([a-zA-Z0-9-]+\.[a-zA-Z]{2,})(\/[a-zA-Z0-9-._~:\/?#[\]@!$&'()*+,;=]*)?")] public static partial Regex UrlRegex(); #else + private static Regex SourcePathRegex() => new(SourcePathPattern); + public static Regex UrlRegex() => new( @"((http|https):\/\/)?(www\.)?([a-zA-Z0-9-]+\.[a-zA-Z]{2,})(\/[a-zA-Z0-9-._~:\/?#[\]@!$&'()*+,;=]*)?"); diff --git a/tests/TUnit.RpcTests/TUnit.RpcTests.csproj b/tests/TUnit.RpcTests/TUnit.RpcTests.csproj index d15c5164119..4e7eb2aba50 100644 --- a/tests/TUnit.RpcTests/TUnit.RpcTests.csproj +++ b/tests/TUnit.RpcTests/TUnit.RpcTests.csproj @@ -10,6 +10,10 @@ false + + + + diff --git a/tests/TUnit.RpcTests/TestHostSession.cs b/tests/TUnit.RpcTests/TestHostSession.cs index 0ec670dae4e..d2fb1be505f 100644 --- a/tests/TUnit.RpcTests/TestHostSession.cs +++ b/tests/TUnit.RpcTests/TestHostSession.cs @@ -4,6 +4,7 @@ using StreamJsonRpc; using TUnit.RpcTests.Clients; using TUnit.RpcTests.Models; +using TUnit.Tests.Shared; namespace TUnit.RpcTests; @@ -46,7 +47,7 @@ public static async Task StartAsync(string framework, Cancellat listener.Start(); var port = ((IPEndPoint)listener.LocalEndpoint).Port; - var cliProcess = Cli.Wrap("dotnet") + var cliProcess = Cli.Wrap(DotNetCli.Path) .WithWorkingDirectory(TestProjectBuilds.WorkingDirectory) .WithArguments([ "run", diff --git a/tests/TUnit.RpcTests/TestProjectBuilds.cs b/tests/TUnit.RpcTests/TestProjectBuilds.cs index 06a78a15c27..71edfe1bbd9 100644 --- a/tests/TUnit.RpcTests/TestProjectBuilds.cs +++ b/tests/TUnit.RpcTests/TestProjectBuilds.cs @@ -1,5 +1,7 @@ using System.Collections.Concurrent; using CliWrap; +using CliWrap.Buffered; +using TUnit.Tests.Shared; namespace TUnit.RpcTests; @@ -29,15 +31,16 @@ public static Task EnsureBuiltAsync(string framework, CancellationToken cancella private static async Task BuildAsync(string framework, CancellationToken cancellationToken) { - var result = await Cli.Wrap("dotnet") + var result = await Cli.Wrap(DotNetCli.Path) .WithWorkingDirectory(WorkingDirectory) .WithArguments(["build", "-c", Configuration, "-f", framework, "--nologo", "-v", "quiet"]) .WithValidation(CommandResultValidation.None) - .ExecuteAsync(cancellationToken); + .ExecuteBufferedAsync(cancellationToken); if (result.ExitCode != 0) { - throw new InvalidOperationException($"Test host pre-build ({framework}) failed with exit code {result.ExitCode}"); + throw new InvalidOperationException( + $"Test host pre-build ({framework}) failed with exit code {result.ExitCode} using '{DotNetCli.Path}':{Environment.NewLine}{result.StandardOutput}{result.StandardError}"); } } } diff --git a/tests/TUnit.SourceGenerator.IncrementalTests/AotConverterGeneratorIncrementalTests.cs b/tests/TUnit.SourceGenerator.IncrementalTests/AotConverterGeneratorIncrementalTests.cs index c7bc6e687b4..4cc8d3fd24d 100644 --- a/tests/TUnit.SourceGenerator.IncrementalTests/AotConverterGeneratorIncrementalTests.cs +++ b/tests/TUnit.SourceGenerator.IncrementalTests/AotConverterGeneratorIncrementalTests.cs @@ -3,7 +3,7 @@ using TUnit.Core.SourceGenerator.Generators; using TUnit.Core.SourceGenerator.Models; -namespace TUnit.Assertions.SourceGenerator.IncrementalTests; +namespace TUnit.SourceGenerator.IncrementalTests; public class AotConverterGeneratorIncrementalTests { @@ -51,42 +51,42 @@ public void Test1(FooBar data) } """; - [Fact] - public void AddUnrelatedType_MethodShouldNotRegenerate() + [Test] + public async Task AddUnrelatedType_MethodShouldNotRegenerate() { var syntaxTree = CSharpSyntaxTree.ParseText(DefaultConverter, CSharpParseOptions.Default); var compilation1 = Fixture.CreateLibrary(syntaxTree); var driver1 = TestHelper.GenerateTracked(compilation1); - AssertRunReasons(driver1, IncrementalGeneratorRunReasons.New, 1); + await AssertRunReasons(driver1, IncrementalGeneratorRunReasons.New, 1); var compilation2 = compilation1.AddSyntaxTrees(CSharpSyntaxTree.ParseText("struct MyValue {}")); var driver2 = driver1.RunGenerators(compilation2); - AssertRunReasons(driver2, IncrementalGeneratorRunReasons.Cached, 1); + await AssertRunReasons(driver2, IncrementalGeneratorRunReasons.Cached, 1); } - [Fact] - public void AddNewConverterShouldRegenerate() + [Test] + public async Task AddNewConverterShouldRegenerate() { var syntaxTree = CSharpSyntaxTree.ParseText(DefaultConverter, CSharpParseOptions.Default); var compilation1 = Fixture.CreateLibrary(syntaxTree); var driver1 = TestHelper.GenerateTracked(compilation1); - AssertRunReasons(driver1, IncrementalGeneratorRunReasons.New, 1); + await AssertRunReasons(driver1, IncrementalGeneratorRunReasons.New, 1); var compilation2 = compilation1.AddSyntaxTrees(CSharpSyntaxTree.ParseText(SecondConverter)); var driver2 = driver1.RunGenerators(compilation2); - AssertRunReasons(driver2, IncrementalGeneratorRunReasons.Modified, 2); + await AssertRunReasons(driver2, IncrementalGeneratorRunReasons.Modified, 2); } - [Fact] - public void ModifyOperatorShouldRegenerate() + [Test] + public async Task ModifyOperatorShouldRegenerate() { var syntaxTree = CSharpSyntaxTree.ParseText(DefaultConverter, CSharpParseOptions.Default); var compilation1 = Fixture.CreateLibrary(syntaxTree); var driver1 = TestHelper.GenerateTracked(compilation1); - AssertRunReasons(driver1, IncrementalGeneratorRunReasons.New, 1); + await AssertRunReasons(driver1, IncrementalGeneratorRunReasons.New, 1); var compilation2 = TestHelper.ReplaceTypeDeclaration(compilation1, "Foo", """ @@ -98,32 +98,32 @@ public record Foo ); var driver2 = driver1.RunGenerators(compilation2); - AssertRunReasons(driver2, IncrementalGeneratorRunReasons.Modified, 1); + await AssertRunReasons(driver2, IncrementalGeneratorRunReasons.Modified, 1); } - [Fact] - public void EditNonTestMethodShouldNotRegenerate() + [Test] + public async Task EditNonTestMethodShouldNotRegenerate() { var syntaxTree = CSharpSyntaxTree.ParseText(DefaultConverter, CSharpParseOptions.Default); var compilation1 = Fixture.CreateLibrary(syntaxTree); var driver1 = TestHelper.GenerateTracked(compilation1); - AssertRunReasons(driver1, IncrementalGeneratorRunReasons.New, 1); + await AssertRunReasons(driver1, IncrementalGeneratorRunReasons.New, 1); var compilation2 = TestHelper.ReplaceMethodDeclaration(compilation1, "Data", "public static IEnumerable Data() => [new(), new()];"); var driver2 = driver1.RunGenerators(compilation2); - AssertRunReasons(driver2, IncrementalGeneratorRunReasons.Cached, 1); + await AssertRunReasons(driver2, IncrementalGeneratorRunReasons.Cached, 1); } - [Fact] - public void ChangeTestParameterShouldRegenerate() + [Test] + public async Task ChangeTestParameterShouldRegenerate() { var syntaxTree = CSharpSyntaxTree.ParseText(DefaultConverter, CSharpParseOptions.Default); var compilation1 = Fixture.CreateLibrary(syntaxTree); var driver1 = TestHelper.GenerateTracked(compilation1); - AssertRunReasons(driver1, IncrementalGeneratorRunReasons.New, 1); + await AssertRunReasons(driver1, IncrementalGeneratorRunReasons.New, 1); var compilation2 = TestHelper.ReplaceMethodDeclaration(compilation1, "Test1", """ @@ -133,10 +133,10 @@ public void Test1(int data) } """); var driver2 = driver1.RunGenerators(compilation2); - AssertRunReasons(driver2, IncrementalGeneratorRunReasons.Modified, 0); + await AssertRunReasons(driver2, IncrementalGeneratorRunReasons.Modified, 0); } - private static void AssertRunReasons( + private static async Task AssertRunReasons( GeneratorDriver driver, IncrementalGeneratorRunReasons reasons, int conversionMetadataLength, @@ -146,8 +146,8 @@ private static void AssertRunReasons( var runResult = driver.GetRunResult().Results[0]; var runValue = runResult.TrackedSteps[AotConverterGenerator.ParseAotConverter][0].Outputs[0].Value; var runState = (ValueTuple, bool>)runValue; - Xunit.Assert.Equal(conversionMetadataLength, runState.Item1.Length); + await Assert.That(runState.Item1.Length).IsEqualTo(conversionMetadataLength); - TestHelper.AssertRunReason(runResult, AotConverterGenerator.ParseAotConverter, reasons.BuildStep, outputIndex); + await TestHelper.AssertRunReason(runResult, AotConverterGenerator.ParseAotConverter, reasons.BuildStep, outputIndex); } -} +} \ No newline at end of file diff --git a/tests/TUnit.SourceGenerator.IncrementalTests/AssertionExtensionGeneratorIncrementalTests.cs b/tests/TUnit.SourceGenerator.IncrementalTests/AssertionExtensionGeneratorIncrementalTests.cs index 9327e55b8df..aa9b6595573 100644 --- a/tests/TUnit.SourceGenerator.IncrementalTests/AssertionExtensionGeneratorIncrementalTests.cs +++ b/tests/TUnit.SourceGenerator.IncrementalTests/AssertionExtensionGeneratorIncrementalTests.cs @@ -2,7 +2,7 @@ using Microsoft.CodeAnalysis.CSharp; using TUnit.Assertions.SourceGenerator.Generators; -namespace TUnit.Assertions.SourceGenerator.IncrementalTests; +namespace TUnit.SourceGenerator.IncrementalTests; public class AssertionExtensionGeneratorIncrementalTests { @@ -49,8 +49,8 @@ public void Method() { } } """; - [Fact] - public void AddUnrelatedTypeShouldNotRegenerate() + [Test] + public async Task AddUnrelatedTypeShouldNotRegenerate() { var compilation1 = Fixture.CreateLibrary(CSharpSyntaxTree.ParseText(DefaultSource)); var driver1 = TestHelper.GenerateTracked(compilation1); @@ -59,13 +59,13 @@ public void AddUnrelatedTypeShouldNotRegenerate() var driver2 = driver1.RunGenerators(compilation2); var runResult = driver2.GetRunResult().Results[0]; - TestHelper.AssertAllRunReasons(runResult, AssertionExtensionGenerator.AssertionExtensionStep, + await TestHelper.AssertAllRunReasons(runResult, AssertionExtensionGenerator.AssertionExtensionStep, IncrementalStepRunReason.Cached, IncrementalStepRunReason.Unchanged); - TestHelper.AssertSourceOutputsCached(runResult); + await TestHelper.AssertSourceOutputsCached(runResult); } - [Fact] - public void EditUnrelatedTypeShouldNotRegenerate() + [Test] + public async Task EditUnrelatedTypeShouldNotRegenerate() { var compilation1 = Fixture.CreateLibrary(CSharpSyntaxTree.ParseText(DefaultSource)); var driver1 = TestHelper.GenerateTracked(compilation1); @@ -74,13 +74,13 @@ public void EditUnrelatedTypeShouldNotRegenerate() var driver2 = driver1.RunGenerators(compilation2); var runResult = driver2.GetRunResult().Results[0]; - TestHelper.AssertAllRunReasons(runResult, AssertionExtensionGenerator.AssertionExtensionStep, + await TestHelper.AssertAllRunReasons(runResult, AssertionExtensionGenerator.AssertionExtensionStep, IncrementalStepRunReason.Cached, IncrementalStepRunReason.Unchanged); - TestHelper.AssertSourceOutputsCached(runResult); + await TestHelper.AssertSourceOutputsCached(runResult); } - [Fact] - public void ModifyAssertionClassShouldRegenerateOnlyThatClass() + [Test] + public async Task ModifyAssertionClassShouldRegenerateOnlyThatClass() { var compilation1 = Fixture.CreateLibrary(CSharpSyntaxTree.ParseText(DefaultSource)); var driver1 = TestHelper.GenerateTracked(compilation1); @@ -107,16 +107,16 @@ protected override Task CheckAsync(EvaluationMetadata m .SelectMany(x => x.Outputs) .Select(x => x.Reason) .ToArray(); - Xunit.Assert.Equal(2, reasons.Length); - Xunit.Assert.Contains(reasons[0], new[] { IncrementalStepRunReason.Cached, IncrementalStepRunReason.Unchanged }); - Xunit.Assert.Equal(IncrementalStepRunReason.Modified, reasons[1]); + await Assert.That(reasons.Length).IsEqualTo(2); + await Assert.That(new[] { IncrementalStepRunReason.Cached, IncrementalStepRunReason.Unchanged }).Contains(reasons[0]); + await Assert.That(reasons[1]).IsEqualTo(IncrementalStepRunReason.Modified); var sourceOutputReasons = runResult.TrackedOutputSteps .SelectMany(x => x.Value) .SelectMany(x => x.Outputs) .Select(x => x.Reason) .ToArray(); - Xunit.Assert.Single(sourceOutputReasons, IncrementalStepRunReason.Modified); - Xunit.Assert.Contains("IsBaz", runResult.GeneratedSources.Single(x => x.HintName == "BarAssertion.Extensions.g.cs").SourceText.ToString()); + await Assert.That(sourceOutputReasons).HasSingleItem(x => x == IncrementalStepRunReason.Modified); + await Assert.That(runResult.GeneratedSources.Single(x => x.HintName == "BarAssertion.Extensions.g.cs").SourceText.ToString()).Contains("IsBaz"); } -} +} \ No newline at end of file diff --git a/tests/TUnit.SourceGenerator.IncrementalTests/AssertionMethodGeneratorIncrementalTests.cs b/tests/TUnit.SourceGenerator.IncrementalTests/AssertionMethodGeneratorIncrementalTests.cs index d2a4a40e06a..ce6c29dd36b 100644 --- a/tests/TUnit.SourceGenerator.IncrementalTests/AssertionMethodGeneratorIncrementalTests.cs +++ b/tests/TUnit.SourceGenerator.IncrementalTests/AssertionMethodGeneratorIncrementalTests.cs @@ -2,7 +2,7 @@ using Microsoft.CodeAnalysis.CSharp; using TUnit.Assertions.SourceGenerator.Generators; -namespace TUnit.Assertions.SourceGenerator.IncrementalTests; +namespace TUnit.SourceGenerator.IncrementalTests; public class AssertionMethodGeneratorIncrementalTests { @@ -28,20 +28,20 @@ public void Method() { } } """; - [Fact] - public void GenericAndNonGenericAttributesAreDiscovered() + [Test] + public async Task GenericAndNonGenericAttributesAreDiscovered() { var compilation = Fixture.CreateLibrary(CSharpSyntaxTree.ParseText(DefaultSource)); var driver = TestHelper.GenerateTracked(compilation); var hintNames = driver.GetRunResult().Results[0].GeneratedSources.Select(x => x.HintName).ToArray(); - Xunit.Assert.Contains("MyCharAssertionExtensions.g.cs", hintNames); - Xunit.Assert.Contains("MyStringAssertionExtensions.g.cs", hintNames); + await Assert.That(hintNames).Contains("MyCharAssertionExtensions.g.cs"); + await Assert.That(hintNames).Contains("MyStringAssertionExtensions.g.cs"); } - [Fact] - public void AddUnrelatedTypeShouldNotRegenerate() + [Test] + public async Task AddUnrelatedTypeShouldNotRegenerate() { var compilation1 = Fixture.CreateLibrary(CSharpSyntaxTree.ParseText(DefaultSource)); var driver1 = TestHelper.GenerateTracked(compilation1); @@ -49,11 +49,11 @@ public void AddUnrelatedTypeShouldNotRegenerate() var compilation2 = compilation1.AddSyntaxTrees(CSharpSyntaxTree.ParseText("struct MyValue {}")); var driver2 = driver1.RunGenerators(compilation2); - AssertUnchanged(driver2.GetRunResult().Results[0]); + await AssertUnchanged(driver2.GetRunResult().Results[0]); } - [Fact] - public void EditUnrelatedTypeShouldNotRegenerate() + [Test] + public async Task EditUnrelatedTypeShouldNotRegenerate() { var compilation1 = Fixture.CreateLibrary(CSharpSyntaxTree.ParseText(DefaultSource)); var driver1 = TestHelper.GenerateTracked(compilation1); @@ -61,11 +61,11 @@ public void EditUnrelatedTypeShouldNotRegenerate() var compilation2 = TestHelper.ReplaceMethodDeclaration(compilation1, "Method", "public void Method() { var x = 1; }"); var driver2 = driver1.RunGenerators(compilation2); - AssertUnchanged(driver2.GetRunResult().Results[0]); + await AssertUnchanged(driver2.GetRunResult().Results[0]); } - [Fact] - public void ModifyGenericAttributeShouldRegenerate() + [Test] + public async Task ModifyGenericAttributeShouldRegenerate() { var compilation1 = Fixture.CreateLibrary(CSharpSyntaxTree.ParseText(DefaultSource)); var driver1 = TestHelper.GenerateTracked(compilation1); @@ -80,14 +80,14 @@ public static partial class MyCharAssertionExtensions var driver2 = driver1.RunGenerators(compilation2); var runResult = driver2.GetRunResult().Results[0]; - TestHelper.AssertAnyRunReason(runResult, AssertionMethodGenerator.GenericAssertionFromStep, IncrementalStepRunReason.Modified); - TestHelper.AssertAllRunReasons(runResult, AssertionMethodGenerator.NonGenericAssertionFromStep, + await TestHelper.AssertAnyRunReason(runResult, AssertionMethodGenerator.GenericAssertionFromStep, IncrementalStepRunReason.Modified); + await TestHelper.AssertAllRunReasons(runResult, AssertionMethodGenerator.NonGenericAssertionFromStep, IncrementalStepRunReason.Cached, IncrementalStepRunReason.Unchanged); - Xunit.Assert.Contains("be a letter!", runResult.GeneratedSources.Single(x => x.HintName == "MyCharAssertionExtensions.g.cs").SourceText.ToString()); + await Assert.That(runResult.GeneratedSources.Single(x => x.HintName == "MyCharAssertionExtensions.g.cs").SourceText.ToString()).Contains("be a letter!"); } - [Fact] - public void ModifyNonGenericAttributeShouldRegenerate() + [Test] + public async Task ModifyNonGenericAttributeShouldRegenerate() { var compilation1 = Fixture.CreateLibrary(CSharpSyntaxTree.ParseText(DefaultSource)); var driver1 = TestHelper.GenerateTracked(compilation1); @@ -102,18 +102,18 @@ public static partial class MyStringAssertionExtensions var driver2 = driver1.RunGenerators(compilation2); var runResult = driver2.GetRunResult().Results[0]; - TestHelper.AssertAnyRunReason(runResult, AssertionMethodGenerator.NonGenericAssertionFromStep, IncrementalStepRunReason.Modified); - TestHelper.AssertAllRunReasons(runResult, AssertionMethodGenerator.GenericAssertionFromStep, + await TestHelper.AssertAnyRunReason(runResult, AssertionMethodGenerator.NonGenericAssertionFromStep, IncrementalStepRunReason.Modified); + await TestHelper.AssertAllRunReasons(runResult, AssertionMethodGenerator.GenericAssertionFromStep, IncrementalStepRunReason.Cached, IncrementalStepRunReason.Unchanged); - Xunit.Assert.Contains("IsNullOrWhiteSpace", runResult.GeneratedSources.Single(x => x.HintName == "MyStringAssertionExtensions.g.cs").SourceText.ToString()); + await Assert.That(runResult.GeneratedSources.Single(x => x.HintName == "MyStringAssertionExtensions.g.cs").SourceText.ToString()).Contains("IsNullOrWhiteSpace"); } - private static void AssertUnchanged(GeneratorRunResult runResult) + private static async Task AssertUnchanged(GeneratorRunResult runResult) { - TestHelper.AssertAllRunReasons(runResult, AssertionMethodGenerator.GenericAssertionFromStep, + await TestHelper.AssertAllRunReasons(runResult, AssertionMethodGenerator.GenericAssertionFromStep, IncrementalStepRunReason.Cached, IncrementalStepRunReason.Unchanged); - TestHelper.AssertAllRunReasons(runResult, AssertionMethodGenerator.NonGenericAssertionFromStep, + await TestHelper.AssertAllRunReasons(runResult, AssertionMethodGenerator.NonGenericAssertionFromStep, IncrementalStepRunReason.Cached, IncrementalStepRunReason.Unchanged); - TestHelper.AssertSourceOutputsCached(runResult); + await TestHelper.AssertSourceOutputsCached(runResult); } -} +} \ No newline at end of file diff --git a/tests/TUnit.SourceGenerator.IncrementalTests/DynamicTestsGeneratorIncrementalTests.cs b/tests/TUnit.SourceGenerator.IncrementalTests/DynamicTestsGeneratorIncrementalTests.cs index dc27055539b..2db2bed8e48 100644 --- a/tests/TUnit.SourceGenerator.IncrementalTests/DynamicTestsGeneratorIncrementalTests.cs +++ b/tests/TUnit.SourceGenerator.IncrementalTests/DynamicTestsGeneratorIncrementalTests.cs @@ -2,7 +2,7 @@ using Microsoft.CodeAnalysis.CSharp; using TUnit.Core.SourceGenerator.CodeGenerators; -namespace TUnit.Assertions.SourceGenerator.IncrementalTests; +namespace TUnit.SourceGenerator.IncrementalTests; public class DynamicTestsGeneratorIncrementalTests { @@ -25,28 +25,28 @@ public void SecondBuildDynamicTests(DynamicTestBuilderContext context) } """; - [Fact] - public void AddUnrelatedType_MethodShouldNotRegenerate() + [Test] + public async Task AddUnrelatedType_MethodShouldNotRegenerate() { var syntaxTree = CSharpSyntaxTree.ParseText(DefaultConverter, CSharpParseOptions.Default); var compilation1 = Fixture.CreateLibrary(syntaxTree); var driver1 = TestHelper.GenerateTracked(compilation1); - AssertRunReasons(driver1, IncrementalGeneratorRunReasons.New); + await AssertRunReasons(driver1, IncrementalGeneratorRunReasons.New); var compilation2 = compilation1.AddSyntaxTrees(CSharpSyntaxTree.ParseText("struct MyValue {}")); var driver2 = driver1.RunGenerators(compilation2); - AssertRunReasons(driver2, IncrementalGeneratorRunReasons.Cached); + await AssertRunReasons(driver2, IncrementalGeneratorRunReasons.Cached); } - [Fact] - public void ModifyDynamicMethodShouldRegenerate() + [Test] + public async Task ModifyDynamicMethodShouldRegenerate() { var syntaxTree = CSharpSyntaxTree.ParseText(DefaultConverter, CSharpParseOptions.Default); var compilation1 = Fixture.CreateLibrary(syntaxTree); var driver1 = TestHelper.GenerateTracked(compilation1); - AssertRunReasons(driver1, IncrementalGeneratorRunReasons.New, 0); + await AssertRunReasons(driver1, IncrementalGeneratorRunReasons.New, 0); var compilation2 = TestHelper.ReplaceMethodDeclaration(compilation1, "BuildDynamicTests", """ @@ -58,17 +58,17 @@ public static void BuildDynamicTests(DynamicTestBuilderContext context) ); var driver2 = driver1.RunGenerators(compilation2); - AssertRunReasons(driver2, IncrementalGeneratorRunReasons.Modified); + await AssertRunReasons(driver2, IncrementalGeneratorRunReasons.Modified); } - [Fact] - public void AddDynamicMethodShouldRegenerate() + [Test] + public async Task AddDynamicMethodShouldRegenerate() { var syntaxTree = CSharpSyntaxTree.ParseText(DefaultConverter, CSharpParseOptions.Default); var compilation1 = Fixture.CreateLibrary(syntaxTree); var driver1 = TestHelper.GenerateTracked(compilation1); - AssertRunReasons(driver1, IncrementalGeneratorRunReasons.New); + await AssertRunReasons(driver1, IncrementalGeneratorRunReasons.New); var compilation2 = TestHelper.ReplaceMethodDeclaration(compilation1, "SecondBuildDynamicTests", """ @@ -80,18 +80,18 @@ public void SecondBuildDynamicTests(DynamicTestBuilderContext context) ); var driver2 = driver1.RunGenerators(compilation2); - AssertRunReasons(driver2, IncrementalGeneratorRunReasons.Cached, 0); - AssertRunReasons(driver2, IncrementalGeneratorRunReasons.New, 1); + await AssertRunReasons(driver2, IncrementalGeneratorRunReasons.Cached, 0); + await AssertRunReasons(driver2, IncrementalGeneratorRunReasons.New, 1); } - [Fact] - public void MoveDynamicMethodToDifferentLine_ShouldRegenerate() + [Test] + public async Task MoveDynamicMethodToDifferentLine_ShouldRegenerate() { var syntaxTree = CSharpSyntaxTree.ParseText(DefaultConverter, CSharpParseOptions.Default); var compilation1 = Fixture.CreateLibrary(syntaxTree); var driver1 = TestHelper.GenerateTracked(compilation1); - AssertRunReasons(driver1, IncrementalGeneratorRunReasons.New); + await AssertRunReasons(driver1, IncrementalGeneratorRunReasons.New); // The [CallerLineNumber] captured by DynamicTestBuilder feeds the hint name and the // generated DynamicTestBuilderContext, so shifting the method must regenerate. @@ -100,10 +100,10 @@ public void MoveDynamicMethodToDifferentLine_ShouldRegenerate() CSharpSyntaxTree.ParseText(DefaultConverter.Replace("public class DynamicTestArgumentsTests", "\n\npublic class DynamicTestArgumentsTests"), CSharpParseOptions.Default)); var driver2 = driver1.RunGenerators(compilation2); - AssertRunReasons(driver2, IncrementalGeneratorRunReasons.Modified); + await AssertRunReasons(driver2, IncrementalGeneratorRunReasons.Modified); } - private static void AssertRunReasons( + private static async Task AssertRunReasons( GeneratorDriver driver, IncrementalGeneratorRunReasons reasons, int outputIndex = 0 @@ -111,6 +111,6 @@ private static void AssertRunReasons( { var runResult = driver.GetRunResult().Results[0]; - TestHelper.AssertRunReason(runResult, DynamicTestsGenerator.ParseDynamicTests, reasons.BuildStep, outputIndex); + await TestHelper.AssertRunReason(runResult, DynamicTestsGenerator.ParseDynamicTests, reasons.BuildStep, outputIndex); } -} +} \ No newline at end of file diff --git a/tests/TUnit.SourceGenerator.IncrementalTests/Fixture.cs b/tests/TUnit.SourceGenerator.IncrementalTests/Fixture.cs index 563750461fd..9d5ddd8f594 100644 --- a/tests/TUnit.SourceGenerator.IncrementalTests/Fixture.cs +++ b/tests/TUnit.SourceGenerator.IncrementalTests/Fixture.cs @@ -4,8 +4,9 @@ using Microsoft.CodeAnalysis.CSharp; using TUnit.Assertions.Attributes; using TUnit.Core; +using TUnit.Tests.Shared; -namespace TUnit.Assertions.SourceGenerator.IncrementalTests; +namespace TUnit.SourceGenerator.IncrementalTests; public static class Fixture { @@ -19,13 +20,10 @@ public static class Fixture typeof(TestAttribute).Assembly, }; - public static Assembly[] AssemblyReferencesForCodegen => - AppDomain - .CurrentDomain.GetAssemblies() - .Concat(ImportantAssemblies) - .Distinct() - .Where(a => !a.IsDynamic) - .ToArray(); + private static readonly string[] AssemblyPathsForCodegen = TestHostReferences.AssemblyPaths + .Concat(ImportantAssemblies.Select(static assembly => assembly.Location)) + .Distinct() + .ToArray(); public static DirectoryInfo GetSolutionDirectoryInfo() { @@ -43,15 +41,9 @@ public static CSharpCompilation CreateLibrary(params string[] source) => public static CSharpCompilation CreateLibrary(params SyntaxTree[] source) { - var references = new List(); - var assemblies = AssemblyReferencesForCodegen; - foreach (Assembly assembly in assemblies) - { - if (!assembly.IsDynamic) - { - references.Add(MetadataReference.CreateFromFile(assembly.Location)); - } - } + var references = AssemblyPathsForCodegen + .Select(static path => (MetadataReference)MetadataReference.CreateFromFile(path)) + .ToList(); var compilation = CSharpCompilation.Create( "Library", @@ -62,13 +54,4 @@ public static CSharpCompilation CreateLibrary(params SyntaxTree[] source) return compilation; } - - public static async Task SourceFromResourceFile(string file) - { - var currentDir = Path.GetDirectoryName(Assembly.GetExecutingAssembly().Location); - Assert.NotNull(currentDir); - var resourcesDir = Path.Combine(currentDir, "resources"); - - return await File.ReadAllTextAsync(Path.Combine(resourcesDir, file)); - } } diff --git a/tests/TUnit.SourceGenerator.IncrementalTests/HookMetadataGeneratorIncrementalTests.cs b/tests/TUnit.SourceGenerator.IncrementalTests/HookMetadataGeneratorIncrementalTests.cs index 5d9249599ae..d486c871ad6 100644 --- a/tests/TUnit.SourceGenerator.IncrementalTests/HookMetadataGeneratorIncrementalTests.cs +++ b/tests/TUnit.SourceGenerator.IncrementalTests/HookMetadataGeneratorIncrementalTests.cs @@ -2,7 +2,7 @@ using Microsoft.CodeAnalysis.CSharp; using TUnit.Core.SourceGenerator.Generators; -namespace TUnit.Assertions.SourceGenerator.IncrementalTests; +namespace TUnit.SourceGenerator.IncrementalTests; public class HookMetadataGeneratorIncrementalTests { @@ -20,22 +20,22 @@ public void Setup() } """; - [Fact] - public void AddUnrelatedType_ShouldNotRegenerate() + [Test] + public async Task AddUnrelatedType_ShouldNotRegenerate() { var compilation1 = Fixture.CreateLibrary(CSharpSyntaxTree.ParseText(DefaultSource, CSharpParseOptions.Default)); var driver1 = TestHelper.GenerateTracked(compilation1); - AssertRunReason(driver1, IncrementalStepRunReason.New); + await AssertRunReason(driver1, IncrementalStepRunReason.New); var compilation2 = compilation1.AddSyntaxTrees(CSharpSyntaxTree.ParseText("struct MyValue {}")); var driver2 = driver1.RunGenerators(compilation2); - AssertRunReason(driver2, IncrementalStepRunReason.Cached); - TestHelper.AssertRunReason(driver2.GetRunResult().Results[0], HookMetadataGenerator.HookClassGroups, IncrementalStepRunReason.Cached, 0); + await AssertRunReason(driver2, IncrementalStepRunReason.Cached); + await TestHelper.AssertRunReason(driver2.GetRunResult().Results[0], HookMetadataGenerator.HookClassGroups, IncrementalStepRunReason.Cached, 0); } - [Fact] - public void TypesWithSameSanitizedName_ShouldGenerateDistinctFilesAndMembers() + [Test] + public async Task TypesWithSameSanitizedName_ShouldGenerateDistinctFilesAndMembers() { // A_B.C and A.B_C both sanitize to A_B_C. Hint names and the members emitted into the shared // TUnit_HookRegistration partial class must still be unique. @@ -71,18 +71,18 @@ public void Setup() var driver = TestHelper.GenerateTracked(compilation); var runResult = driver.GetRunResult(); - Xunit.Assert.Empty(runResult.Diagnostics); - var generatorResult = Xunit.Assert.Single(runResult.Results); - Xunit.Assert.Null(generatorResult.Exception); - Xunit.Assert.Equal(2, generatorResult.GeneratedSources.Length); - Xunit.Assert.Equal(2, generatorResult.GeneratedSources.Select(static s => s.HintName).Distinct().Count()); + await Assert.That(runResult.Diagnostics).IsEmpty(); + var generatorResult = await Assert.That(runResult.Results).HasSingleItem(); + await Assert.That(generatorResult.Exception).IsNull(); + await Assert.That(generatorResult.GeneratedSources.Length).IsEqualTo(2); + await Assert.That(generatorResult.GeneratedSources.Select(static s => s.HintName).Distinct().Count()).IsEqualTo(2); var outputCompilation = compilation.AddSyntaxTrees(generatorResult.GeneratedSources.Select(static s => s.SyntaxTree)); - Xunit.Assert.Empty(outputCompilation.GetDiagnostics().Where(static d => d.Severity == DiagnosticSeverity.Error)); + await Assert.That(outputCompilation.GetDiagnostics().Where(static d => d.Severity == DiagnosticSeverity.Error)).IsEmpty(); } - [Fact] - public void ChangeHookInOneClass_ShouldOnlyModifyThatClassGroup() + [Test] + public async Task ChangeHookInOneClass_ShouldOnlyModifyThatClassGroup() { const string source = """ @@ -122,17 +122,17 @@ public async Task OtherSetup() var driver2 = driver1.RunGenerators(compilation2); var runResult = driver2.GetRunResult().Results[0]; - TestHelper.AssertRunReason(runResult, HookMetadataGenerator.HookClassGroups, IncrementalStepRunReason.Unchanged, 0); - TestHelper.AssertRunReason(runResult, HookMetadataGenerator.HookClassGroups, IncrementalStepRunReason.Modified, 1); + await TestHelper.AssertRunReason(runResult, HookMetadataGenerator.HookClassGroups, IncrementalStepRunReason.Unchanged, 0); + await TestHelper.AssertRunReason(runResult, HookMetadataGenerator.HookClassGroups, IncrementalStepRunReason.Modified, 1); } - [Fact] - public void MoveHookToDifferentLine_ShouldRegenerate() + [Test] + public async Task MoveHookToDifferentLine_ShouldRegenerate() { var compilation1 = Fixture.CreateLibrary(CSharpSyntaxTree.ParseText(DefaultSource, CSharpParseOptions.Default)); var driver1 = TestHelper.GenerateTracked(compilation1); - AssertRunReason(driver1, IncrementalStepRunReason.New); + await AssertRunReason(driver1, IncrementalStepRunReason.New); // Same hook shifted down two lines: the emitted LineNumber must follow it. var compilation2 = compilation1.ReplaceSyntaxTree( @@ -140,16 +140,16 @@ public void MoveHookToDifferentLine_ShouldRegenerate() CSharpSyntaxTree.ParseText(DefaultSource.Replace("public class HookTests", "\n\npublic class HookTests"), CSharpParseOptions.Default)); var driver2 = driver1.RunGenerators(compilation2); - AssertRunReason(driver2, IncrementalStepRunReason.Modified); + await AssertRunReason(driver2, IncrementalStepRunReason.Modified); } - [Fact] - public void MakeHookAsync_ShouldRegenerate() + [Test] + public async Task MakeHookAsync_ShouldRegenerate() { var compilation1 = Fixture.CreateLibrary(CSharpSyntaxTree.ParseText(DefaultSource, CSharpParseOptions.Default)); var driver1 = TestHelper.GenerateTracked(compilation1); - AssertRunReason(driver1, IncrementalStepRunReason.New); + await AssertRunReason(driver1, IncrementalStepRunReason.New); var compilation2 = TestHelper.ReplaceMethodDeclaration(compilation1, "Setup", """ @@ -161,11 +161,11 @@ public async Task Setup() """); var driver2 = driver1.RunGenerators(compilation2); - AssertRunReason(driver2, IncrementalStepRunReason.Modified); + await AssertRunReason(driver2, IncrementalStepRunReason.Modified); } - [Fact] - public void ClassGroups_AcrossFilesWithDisjointHookKinds_AreEmittedInCompilationOrder() + [Test] + public async Task ClassGroups_AcrossFilesWithDisjointHookKinds_AreEmittedInCompilationOrder() { // The first file's class has only a Before hook besides the shared BeforeEvery hook, and the second // file's class has only an After hook. No single hook kind orders the two files except BeforeEvery, @@ -202,18 +202,18 @@ public static void BeforeEveryAssembly(AssemblyHookContext context) { } CSharpSyntaxTree.ParseText(first, CSharpParseOptions.Default, path: "First.cs"), CSharpSyntaxTree.ParseText(second, CSharpParseOptions.Default, path: "Second.cs")); - AssertGeneratedOrder(compilation, "FirstFileHooks", "SecondFileHooks"); + await AssertGeneratedOrder(compilation, "FirstFileHooks", "SecondFileHooks"); // Reversing the files in the compilation reverses the emitted order. var reversed = Fixture.CreateLibrary( CSharpSyntaxTree.ParseText(second, CSharpParseOptions.Default, path: "Second.cs"), CSharpSyntaxTree.ParseText(first, CSharpParseOptions.Default, path: "First.cs")); - AssertGeneratedOrder(reversed, "SecondFileHooks", "FirstFileHooks"); + await AssertGeneratedOrder(reversed, "SecondFileHooks", "FirstFileHooks"); } - [Fact] - public void ClassGroups_DeclaredOnOneLine_AreEmittedInDeclarationOrder() + [Test] + public async Task ClassGroups_DeclaredOnOneLine_AreEmittedInDeclarationOrder() { const string source = """ @@ -224,11 +224,11 @@ public class ZHooks { [Before(HookType.Test)] public void Setup() { } } public c var compilation = Fixture.CreateLibrary(CSharpSyntaxTree.ParseText(source, CSharpParseOptions.Default)); - AssertGeneratedOrder(compilation, "ZHooks", "AHooks"); + await AssertGeneratedOrder(compilation, "ZHooks", "AHooks"); } - [Fact] - public void AddUnrelatedFile_ShouldNotChangeHookFileOrder() + [Test] + public async Task AddUnrelatedFile_ShouldNotChangeHookFileOrder() { var compilation1 = Fixture.CreateLibrary(CSharpSyntaxTree.ParseText(DefaultSource, CSharpParseOptions.Default, path: "Hooks.cs")); @@ -238,29 +238,29 @@ public void AddUnrelatedFile_ShouldNotChangeHookFileOrder() var driver2 = driver1.RunGenerators(compilation2); var runResult = driver2.GetRunResult().Results[0]; - TestHelper.AssertRunReason(runResult, HookMetadataGenerator.HookFileOrder, IncrementalStepRunReason.Unchanged, 0); - TestHelper.AssertRunReason(runResult, HookMetadataGenerator.HookClassGroups, IncrementalStepRunReason.Cached, 0); + await TestHelper.AssertRunReason(runResult, HookMetadataGenerator.HookFileOrder, IncrementalStepRunReason.Unchanged, 0); + await TestHelper.AssertRunReason(runResult, HookMetadataGenerator.HookClassGroups, IncrementalStepRunReason.Cached, 0); } - private static void AssertGeneratedOrder(Compilation compilation, params string[] typeNames) + private static async Task AssertGeneratedOrder(Compilation compilation, params string[] typeNames) { var driver = TestHelper.GenerateTracked(compilation); - var generatorResult = Xunit.Assert.Single(driver.GetRunResult().Results); - Xunit.Assert.Null(generatorResult.Exception); + var generatorResult = await Assert.That(driver.GetRunResult().Results).HasSingleItem(); + await Assert.That(generatorResult.Exception).IsNull(); var hintNames = generatorResult.GeneratedSources.Select(static s => s.HintName).ToArray(); var indices = typeNames .Select(typeName => Array.FindIndex(hintNames, hintName => hintName.Contains(typeName))) .ToArray(); - Xunit.Assert.DoesNotContain(-1, indices); - Xunit.Assert.Equal(indices.OrderBy(static i => i), indices); + await Assert.That(indices).DoesNotContain(-1); + await Assert.That(indices).IsInOrder(); } - private static void AssertRunReason(GeneratorDriver driver, IncrementalStepRunReason reason) + private static async Task AssertRunReason(GeneratorDriver driver, IncrementalStepRunReason reason) { var runResult = driver.GetRunResult().Results[0]; - TestHelper.AssertRunReason(runResult, HookMetadataGenerator.ExtractBeforeHooks, reason, 0); + await TestHelper.AssertRunReason(runResult, HookMetadataGenerator.ExtractBeforeHooks, reason, 0); } -} +} \ No newline at end of file diff --git a/tests/TUnit.SourceGenerator.IncrementalTests/InfrastructureGeneratorIncrementalTests.cs b/tests/TUnit.SourceGenerator.IncrementalTests/InfrastructureGeneratorIncrementalTests.cs index cc67303266c..0b91f126794 100644 --- a/tests/TUnit.SourceGenerator.IncrementalTests/InfrastructureGeneratorIncrementalTests.cs +++ b/tests/TUnit.SourceGenerator.IncrementalTests/InfrastructureGeneratorIncrementalTests.cs @@ -3,7 +3,7 @@ using Microsoft.CodeAnalysis.CSharp; using TUnit.Core.SourceGenerator.CodeGenerators; -namespace TUnit.Assertions.SourceGenerator.IncrementalTests; +namespace TUnit.SourceGenerator.IncrementalTests; public class InfrastructureGeneratorIncrementalTests { @@ -20,20 +20,20 @@ public void Test1() } """; - [Fact] - public void EditSource_ShouldNotRegenerate() + [Test] + public async Task EditSource_ShouldNotRegenerate() { var compilation1 = Fixture.CreateLibrary(CSharpSyntaxTree.ParseText(DefaultSource, CSharpParseOptions.Default)); var driver1 = TestHelper.GenerateTracked(compilation1); - AssertRunReason(driver1, IncrementalStepRunReason.New); + await AssertRunReason(driver1, IncrementalStepRunReason.New); // Syntax-only edits rerun the cheap Select, whose model is unchanged, so the generated source // stays cached. Memo_SyntaxOnlyEdits_ReuseModel checks that the reference walk is skipped. var compilation2 = compilation1.AddSyntaxTrees(CSharpSyntaxTree.ParseText("struct MyValue {}")); var driver2 = driver1.RunGenerators(compilation2); - AssertRunReason(driver2, IncrementalStepRunReason.Unchanged); - TestHelper.AssertSourceOutputsCached(driver2.GetRunResult().Results[0]); + await AssertRunReason(driver2, IncrementalStepRunReason.Unchanged); + await TestHelper.AssertSourceOutputsCached(driver2.GetRunResult().Results[0]); var compilation3 = TestHelper.ReplaceMethodDeclaration(compilation1, "Test1", """ @@ -44,12 +44,12 @@ public void Test1() } """); var driver3 = driver2.RunGenerators(compilation3); - AssertRunReason(driver3, IncrementalStepRunReason.Unchanged); - TestHelper.AssertSourceOutputsCached(driver3.GetRunResult().Results[0]); + await AssertRunReason(driver3, IncrementalStepRunReason.Unchanged); + await TestHelper.AssertSourceOutputsCached(driver3.GetRunResult().Results[0]); } - [Fact] - public void EditSource_DoesNotRetainPreviousCompilation() + [Test] + public async Task EditSource_DoesNotRetainPreviousCompilation() { var (driver, firstCompilation, latestCompilation) = RunSourceEdits(10); @@ -61,7 +61,7 @@ public void EditSource_DoesNotRetainPreviousCompilation() // A comparer that reports the new compilation as equal makes the input node keep the old // one, pinning its syntax trees and bound state for as long as the driver lives. - Xunit.Assert.False(firstCompilation.IsAlive, "The generator driver kept the first compilation alive after syntax-only edits."); + await Assert.That(firstCompilation.IsAlive).IsFalse().Because("The generator driver kept the first compilation alive after syntax-only edits."); GC.KeepAlive(driver); GC.KeepAlive(latestCompilation); } @@ -90,13 +90,13 @@ private static (GeneratorDriver Driver, WeakReference FirstCompilation, Compilat private static object? GetExtractedModel(GeneratorDriver driver) => driver.GetRunResult().Results[0].TrackedSteps[InfrastructureGenerator.ExtractAssemblyInfoStep][0].Outputs[0].Value; - [Fact] - public void AddReference_ShouldRegenerate() + [Test] + public async Task AddReference_ShouldRegenerate() { var compilation1 = Fixture.CreateLibrary(CSharpSyntaxTree.ParseText(DefaultSource, CSharpParseOptions.Default)); var driver1 = TestHelper.GenerateTracked(compilation1); - AssertRunReason(driver1, IncrementalStepRunReason.New); + await AssertRunReason(driver1, IncrementalStepRunReason.New); // A library that references TUnit.Core must be pre-loaded by TUnitInfrastructure.g.cs. var library = CSharpCompilation.Create( @@ -107,14 +107,14 @@ public void AddReference_ShouldRegenerate() var compilation2 = compilation1.AddReferences(library.ToMetadataReference()); var driver2 = driver1.RunGenerators(compilation2); - AssertRunReason(driver2, IncrementalStepRunReason.Modified); + await AssertRunReason(driver2, IncrementalStepRunReason.Modified); var generated = driver2.GetRunResult().GeneratedTrees.Single(t => t.FilePath.EndsWith("TUnitInfrastructure.g.cs")); - Xunit.Assert.Contains("global::OtherTestLibrary.SharedHooks", generated.ToString()); + await Assert.That(generated.ToString()).Contains("global::OtherTestLibrary.SharedHooks"); } - [Fact] - public void EditProjectReference_ShouldRegenerate() + [Test] + public async Task EditProjectReference_ShouldRegenerate() { var compilation1 = Fixture.CreateLibrary(CSharpSyntaxTree.ParseText(DefaultSource, CSharpParseOptions.Default)); @@ -122,7 +122,7 @@ public void EditProjectReference_ShouldRegenerate() compilation1 = compilation1.AddReferences(library1.ToMetadataReference()); var driver1 = TestHelper.GenerateTracked(compilation1); - AssertRunReason(driver1, IncrementalStepRunReason.New); + await AssertRunReason(driver1, IncrementalStepRunReason.New); // In the IDE, editing a referenced project replaces its CompilationReference while the // assembly name stays the same. Renaming the only public type must reach the output, @@ -130,23 +130,23 @@ public void EditProjectReference_ShouldRegenerate() var library2 = CreateHookLibrary(compilation1, "RenamedHooks"); var compilation2 = compilation1.ReplaceReference(compilation1.References.Last(), library2.ToMetadataReference()); var driver2 = driver1.RunGenerators(compilation2); - AssertRunReason(driver2, IncrementalStepRunReason.Modified); + await AssertRunReason(driver2, IncrementalStepRunReason.Modified); var generated = driver2.GetRunResult().GeneratedTrees.Single(t => t.FilePath.EndsWith("TUnitInfrastructure.g.cs")).ToString(); - Xunit.Assert.Contains("global::OtherTestLibrary.RenamedHooks", generated); - Xunit.Assert.DoesNotContain("global::OtherTestLibrary.SharedHooks", generated); + await Assert.That(generated).Contains("global::OtherTestLibrary.RenamedHooks"); + await Assert.That(generated).DoesNotContain("global::OtherTestLibrary.SharedHooks"); // An edit that does not change the extracted model reruns extraction but keeps the output cached. var library3 = CreateHookLibrary(compilation1, "RenamedHooks"); var compilation3 = compilation2.ReplaceReference(compilation2.References.Last(), library3.ToMetadataReference()); var driver3 = driver2.RunGenerators(compilation3); - AssertRunReason(driver3, IncrementalStepRunReason.Unchanged); + await AssertRunReason(driver3, IncrementalStepRunReason.Unchanged); } private const string ShadowingSource = "namespace OtherTestLibrary { public class FirstHooks { } }"; - [Fact] - public void FreshDriver_SameReferences_DoesNotShareMemo() + [Test] + public async Task FreshDriver_SameReferences_DoesNotShareMemo() { var compilation = Fixture.CreateLibrary(CSharpSyntaxTree.ParseText(DefaultSource, CSharpParseOptions.Default)); @@ -154,55 +154,55 @@ public void FreshDriver_SameReferences_DoesNotShareMemo() // extracts fresh instead of reusing another driver's result. var first = GetExtractedModel(TestHelper.GenerateTracked(compilation)); var second = GetExtractedModel(TestHelper.GenerateTracked(compilation)); - Xunit.Assert.NotSame(first, second); - Xunit.Assert.Equal(first, second); + await Assert.That(second).IsNotSameReferenceAs(first); + await Assert.That(second).IsEqualTo(first); } - [Fact] - public void EditSource_SourceSensitiveSelectionIsNotReused() + [Test] + public async Task EditSource_SourceSensitiveSelectionIsNotReused() { var baseCompilation = CreateWithTwoTypeLibrary(); var shadowedCompilation = baseCompilation.AddSyntaxTrees(CSharpSyntaxTree.ParseText(ShadowingSource)); // The shadowed run must not memoize its (source-dependent) choice for later compilations. var driver1 = TestHelper.GenerateTracked(shadowedCompilation); - Xunit.Assert.Contains("typeof(global::OtherTestLibrary.SecondHooks)", GenerateInfrastructure(driver1)); + await Assert.That(GenerateInfrastructure(driver1)).Contains("typeof(global::OtherTestLibrary.SecondHooks)"); var driver2 = driver1.RunGenerators(baseCompilation); - AssertRunReason(driver2, IncrementalStepRunReason.Modified); - Xunit.Assert.Contains("typeof(global::OtherTestLibrary.FirstHooks)", GenerateInfrastructure(driver2)); + await AssertRunReason(driver2, IncrementalStepRunReason.Modified); + await Assert.That(GenerateInfrastructure(driver2)).Contains("typeof(global::OtherTestLibrary.FirstHooks)"); } - [Fact] - public void EditSource_ShadowingSelectedType_ShouldRegenerate() + [Test] + public async Task EditSource_ShadowingSelectedType_ShouldRegenerate() { var compilation1 = CreateWithTwoTypeLibrary(); var driver1 = TestHelper.GenerateTracked(compilation1); - Xunit.Assert.Contains("typeof(global::OtherTestLibrary.FirstHooks)", GenerateInfrastructure(driver1)); + await Assert.That(GenerateInfrastructure(driver1)).Contains("typeof(global::OtherTestLibrary.FirstHooks)"); var compilation2 = compilation1.AddSyntaxTrees(CSharpSyntaxTree.ParseText(ShadowingSource)); var driver2 = driver1.RunGenerators(compilation2); - AssertRunReason(driver2, IncrementalStepRunReason.Modified); - Xunit.Assert.Contains("typeof(global::OtherTestLibrary.SecondHooks)", GenerateInfrastructure(driver2)); + await AssertRunReason(driver2, IncrementalStepRunReason.Modified); + await Assert.That(GenerateInfrastructure(driver2)).Contains("typeof(global::OtherTestLibrary.SecondHooks)"); var driver3 = driver2.RunGenerators(compilation1); - AssertRunReason(driver3, IncrementalStepRunReason.Modified); - Xunit.Assert.Contains("typeof(global::OtherTestLibrary.FirstHooks)", GenerateInfrastructure(driver3)); + await AssertRunReason(driver3, IncrementalStepRunReason.Modified); + await Assert.That(GenerateInfrastructure(driver3)).Contains("typeof(global::OtherTestLibrary.FirstHooks)"); } // The driver keeps the previous output instance whenever a rerun produces an equal model, so // whether the walk was skipped is only observable on the memo itself: it returns the same // instance on a hit and a new one after re-extracting. - [Fact] - public void Memo_SyntaxOnlyEdits_ReuseModel() + [Test] + public async Task Memo_SyntaxOnlyEdits_ReuseModel() { var memo = new InfrastructureGenerator.AssemblyInfoMemo(); var compilation1 = Fixture.CreateLibrary(CSharpSyntaxTree.ParseText(DefaultSource, CSharpParseOptions.Default)); var model1 = memo.GetAssemblyInfo(compilation1); var compilation2 = compilation1.AddSyntaxTrees(CSharpSyntaxTree.ParseText("struct MyValue {}")); - Xunit.Assert.Same(model1, memo.GetAssemblyInfo(compilation2)); + await Assert.That(memo.GetAssemblyInfo(compilation2)).IsSameReferenceAs(model1); var compilation3 = TestHelper.ReplaceMethodDeclaration(compilation1, "Test1", """ @@ -212,11 +212,11 @@ public void Test1() var x = 1; } """); - Xunit.Assert.Same(model1, memo.GetAssemblyInfo(compilation3)); + await Assert.That(memo.GetAssemblyInfo(compilation3)).IsSameReferenceAs(model1); } - [Fact] - public void Memo_ReferenceChange_ReExtracts() + [Test] + public async Task Memo_ReferenceChange_ReExtracts() { var memo = new InfrastructureGenerator.AssemblyInfoMemo(); var compilation1 = Fixture.CreateLibrary(CSharpSyntaxTree.ParseText(DefaultSource, CSharpParseOptions.Default)); @@ -224,12 +224,12 @@ public void Memo_ReferenceChange_ReExtracts() var compilation2 = compilation1.AddReferences(CreateHookLibrary(compilation1, "SharedHooks").ToMetadataReference()); var model2 = memo.GetAssemblyInfo(compilation2); - Xunit.Assert.NotSame(model1, model2); - Xunit.Assert.NotEqual(model1, model2); + await Assert.That(model2).IsNotSameReferenceAs(model1); + await Assert.That(model2).IsNotEqualTo(model1); } - [Fact] - public void Memo_OptionsOrAssemblyNameChange_ReExtracts() + [Test] + public async Task Memo_OptionsOrAssemblyNameChange_ReExtracts() { var memo = new InfrastructureGenerator.AssemblyInfoMemo(); var baseCompilation = Fixture.CreateLibrary(CSharpSyntaxTree.ParseText(DefaultSource, CSharpParseOptions.Default)); @@ -239,29 +239,29 @@ public void Memo_OptionsOrAssemblyNameChange_ReExtracts() // so a new options instance must not reuse the model extracted under the old one. var withComparer = baseCompilation.WithOptions( baseCompilation.Options.WithAssemblyIdentityComparer(DesktopAssemblyIdentityComparer.Default)); - Xunit.Assert.True(baseCompilation.ExternalReferences == withComparer.ExternalReferences); + await Assert.That(baseCompilation.ExternalReferences == withComparer.ExternalReferences).IsTrue(); var comparerModel = memo.GetAssemblyInfo(withComparer); - Xunit.Assert.NotSame(baseModel, comparerModel); - Xunit.Assert.Equal(baseModel, comparerModel); + await Assert.That(comparerModel).IsNotSameReferenceAs(baseModel); + await Assert.That(comparerModel).IsEqualTo(baseModel); var withImportOptions = baseCompilation.WithOptions( baseCompilation.Options.WithMetadataImportOptions(MetadataImportOptions.All)); var importModel = memo.GetAssemblyInfo(withImportOptions); - Xunit.Assert.NotSame(comparerModel, importModel); + await Assert.That(importModel).IsNotSameReferenceAs(comparerModel); // Syntax-only edits under the new options reuse the memo again. - Xunit.Assert.Same(importModel, memo.GetAssemblyInfo( - withImportOptions.AddSyntaxTrees(CSharpSyntaxTree.ParseText("struct MyValue {}")))); + await Assert.That(memo.GetAssemblyInfo( + withImportOptions.AddSyntaxTrees(CSharpSyntaxTree.ParseText("struct MyValue {}")))).IsSameReferenceAs(importModel); var renamed = withImportOptions.WithAssemblyName("Renamed"); - Xunit.Assert.True(withImportOptions.ExternalReferences == renamed.ExternalReferences); + await Assert.That(withImportOptions.ExternalReferences == renamed.ExternalReferences).IsTrue(); var renamedModel = memo.GetAssemblyInfo(renamed); - Xunit.Assert.NotSame(importModel, renamedModel); - Xunit.Assert.Equal("Renamed", renamedModel.AssemblyName); + await Assert.That(renamedModel).IsNotSameReferenceAs(importModel); + await Assert.That(renamedModel.AssemblyName).IsEqualTo("Renamed"); } - [Fact] - public void Memo_ScriptCompilation_IsNeverMemoized() + [Test] + public async Task Memo_ScriptCompilation_IsNeverMemoized() { var memo = new InfrastructureGenerator.AssemblyInfoMemo(); var baseCompilation = Fixture.CreateLibrary(CSharpSyntaxTree.ParseText(DefaultSource, CSharpParseOptions.Default)); @@ -274,14 +274,14 @@ public void Memo_ScriptCompilation_IsNeverMemoized() baseCompilation.AssemblyName!, CSharpSyntaxTree.ParseText("var x = 1;", CSharpParseOptions.Default.WithKind(SourceCodeKind.Script)), baseCompilation.ExternalReferences); - Xunit.Assert.True(baseCompilation.ExternalReferences == script.ExternalReferences); + await Assert.That(baseCompilation.ExternalReferences == script.ExternalReferences).IsTrue(); var first = memo.GetAssemblyInfo(script); var second = memo.GetAssemblyInfo(script.ReplaceSyntaxTree( script.SyntaxTrees.Single(), CSharpSyntaxTree.ParseText("var y = 2;", CSharpParseOptions.Default.WithKind(SourceCodeKind.Script)))); - Xunit.Assert.NotSame(baseModel, first); - Xunit.Assert.NotSame(first, second); + await Assert.That(first).IsNotSameReferenceAs(baseModel); + await Assert.That(second).IsNotSameReferenceAs(first); } private static CSharpCompilation CreateWithTwoTypeLibrary() @@ -305,10 +305,10 @@ private static CSharpCompilation CreateHookLibrary(Compilation consumer, string consumer.References.Where(r => r is not CompilationReference), new CSharpCompilationOptions(OutputKind.DynamicallyLinkedLibrary)); - private static void AssertRunReason(GeneratorDriver driver, IncrementalStepRunReason reason) + private static async Task AssertRunReason(GeneratorDriver driver, IncrementalStepRunReason reason) { var runResult = driver.GetRunResult().Results[0]; - TestHelper.AssertRunReason(runResult, InfrastructureGenerator.ExtractAssemblyInfoStep, reason, 0); + await TestHelper.AssertRunReason(runResult, InfrastructureGenerator.ExtractAssemblyInfoStep, reason, 0); } -} +} \ No newline at end of file diff --git a/tests/TUnit.SourceGenerator.IncrementalTests/MethodAssertionGeneratorIncrementalTests.cs b/tests/TUnit.SourceGenerator.IncrementalTests/MethodAssertionGeneratorIncrementalTests.cs index 9ad9c1c10d6..18e290cde82 100644 --- a/tests/TUnit.SourceGenerator.IncrementalTests/MethodAssertionGeneratorIncrementalTests.cs +++ b/tests/TUnit.SourceGenerator.IncrementalTests/MethodAssertionGeneratorIncrementalTests.cs @@ -2,7 +2,7 @@ using Microsoft.CodeAnalysis.CSharp; using TUnit.Assertions.SourceGenerator.Generators; -namespace TUnit.Assertions.SourceGenerator.IncrementalTests; +namespace TUnit.SourceGenerator.IncrementalTests; public class MethodAssertionGeneratorIncrementalTests { @@ -27,28 +27,28 @@ public static bool IsNegative(this int value) } """; - [Fact] - public void AddUnrelatedMethodShouldNotRegenerate() + [Test] + public async Task AddUnrelatedMethodShouldNotRegenerate() { var syntaxTree = CSharpSyntaxTree.ParseText(DefaultAssertion, CSharpParseOptions.Default); var compilation1 = Fixture.CreateLibrary(syntaxTree); var driver1 = TestHelper.GenerateTracked(compilation1); - AssertRunReasons(driver1, IncrementalGeneratorRunReasons.New); + await AssertRunReasons(driver1, IncrementalGeneratorRunReasons.New); var compilation2 = compilation1.AddSyntaxTrees(CSharpSyntaxTree.ParseText("struct MyValue {}")); var driver2 = driver1.RunGenerators(compilation2); - AssertRunReasons(driver2, IncrementalGeneratorRunReasons.Cached); + await AssertRunReasons(driver2, IncrementalGeneratorRunReasons.Cached); } - [Fact] - public void AddNewTypeAssertionShouldRegenerate() + [Test] + public async Task AddNewTypeAssertionShouldRegenerate() { var syntaxTree = CSharpSyntaxTree.ParseText(DefaultAssertion, CSharpParseOptions.Default); var compilation1 = Fixture.CreateLibrary(syntaxTree); var driver1 = TestHelper.GenerateTracked(compilation1); - AssertRunReasons(driver1, IncrementalGeneratorRunReasons.New); + await AssertRunReasons(driver1, IncrementalGeneratorRunReasons.New); var compilation2 = compilation1.AddSyntaxTrees(CSharpSyntaxTree.ParseText( """ @@ -64,18 +64,18 @@ public static bool IsPositive(this long value) } """)); var driver2 = driver1.RunGenerators(compilation2); - AssertRunReasons(driver2, IncrementalGeneratorRunReasons.Cached, 0); - AssertRunReasons(driver2, IncrementalGeneratorRunReasons.New, 1); + await AssertRunReasons(driver2, IncrementalGeneratorRunReasons.Cached, 0); + await AssertRunReasons(driver2, IncrementalGeneratorRunReasons.New, 1); } - [Fact] - public void AddNewSameTypeAssertionShouldRegenerate() + [Test] + public async Task AddNewSameTypeAssertionShouldRegenerate() { var syntaxTree = CSharpSyntaxTree.ParseText(DefaultAssertion, CSharpParseOptions.Default); var compilation1 = Fixture.CreateLibrary(syntaxTree); var driver1 = TestHelper.GenerateTracked(compilation1); - AssertRunReasons(driver1, IncrementalGeneratorRunReasons.New); + await AssertRunReasons(driver1, IncrementalGeneratorRunReasons.New); var compilation2 = TestHelper.ReplaceMethodDeclaration(compilation1, "IsNegative", """ @@ -87,18 +87,18 @@ public static bool IsNegative(this int value) """ ); var driver2 = driver1.RunGenerators(compilation2); - AssertRunReasons(driver2, IncrementalGeneratorRunReasons.Cached, 0); - AssertRunReasons(driver2, IncrementalGeneratorRunReasons.New, 1); + await AssertRunReasons(driver2, IncrementalGeneratorRunReasons.Cached, 0); + await AssertRunReasons(driver2, IncrementalGeneratorRunReasons.New, 1); } - [Fact] - public void ModifyMessageShouldRegenerate() + [Test] + public async Task ModifyMessageShouldRegenerate() { var syntaxTree = CSharpSyntaxTree.ParseText(DefaultAssertion, CSharpParseOptions.Default); var compilation1 = Fixture.CreateLibrary(syntaxTree); var driver1 = TestHelper.GenerateTracked(compilation1); - AssertRunReasons(driver1, IncrementalGeneratorRunReasons.New); + await AssertRunReasons(driver1, IncrementalGeneratorRunReasons.New); var compilation2 = TestHelper.ReplaceMethodDeclaration(compilation1, "IsPositive", """ @@ -110,11 +110,11 @@ public static bool IsPositive(this int value) """ ); var driver2 = driver1.RunGenerators(compilation2); - AssertRunReasons(driver2, IncrementalGeneratorRunReasons.Modified); + await AssertRunReasons(driver2, IncrementalGeneratorRunReasons.Modified); } - [Fact] - public void ModifyOneContainingTypeShouldOnlyRegenerateThatType() + [Test] + public async Task ModifyOneContainingTypeShouldOnlyRegenerateThatType() { var compilation1 = Fixture.CreateLibrary( DefaultAssertion, @@ -150,19 +150,19 @@ public static bool IsPositive(this long value) var driver2 = driver1.RunGenerators(compilation2); var runResult = driver2.GetRunResult().Results[0]; - TestHelper.AssertRunReason(runResult, MethodAssertionGenerator.BuildAssertionGroup, IncrementalStepRunReason.Unchanged, 0); - TestHelper.AssertRunReason(runResult, MethodAssertionGenerator.BuildAssertionGroup, IncrementalStepRunReason.Modified, 1); + await TestHelper.AssertRunReason(runResult, MethodAssertionGenerator.BuildAssertionGroup, IncrementalStepRunReason.Unchanged, 0); + await TestHelper.AssertRunReason(runResult, MethodAssertionGenerator.BuildAssertionGroup, IncrementalStepRunReason.Modified, 1); var sourceOutputReasons = runResult.TrackedOutputSteps .SelectMany(x => x.Value) .SelectMany(x => x.Outputs) .Select(x => x.Reason) .ToArray(); - Xunit.Assert.Single(sourceOutputReasons, IncrementalStepRunReason.Modified); + await Assert.That(sourceOutputReasons).HasSingleItem(x => x == IncrementalStepRunReason.Modified); } - [Fact] - public void UnrelatedEditWithDiagnosticShouldNotRegenerate() + [Test] + public async Task UnrelatedEditWithDiagnosticShouldNotRegenerate() { var brokenTree = CSharpSyntaxTree.ParseText( """ @@ -180,13 +180,13 @@ public static partial class BrokenAssertionExtensions brokenTree); var driver1 = TestHelper.GenerateTracked(compilation1); - Xunit.Assert.Contains(driver1.GetRunResult().Diagnostics, d => d.Id == "TUNITGEN001"); + await Assert.That(driver1.GetRunResult().Diagnostics).Contains(d => d.Id == "TUNITGEN001"); var compilation2 = compilation1.AddSyntaxTrees(CSharpSyntaxTree.ParseText("struct MyValue {}")); var driver2 = driver1.RunGenerators(compilation2); var runResult = driver2.GetRunResult().Results[0]; - TestHelper.AssertAllRunReasons(runResult, MethodAssertionGenerator.BuildAssertionGroup, + await TestHelper.AssertAllRunReasons(runResult, MethodAssertionGenerator.BuildAssertionGroup, IncrementalStepRunReason.Cached, IncrementalStepRunReason.Unchanged); // Only the diagnostic reporter re-runs (it is paired with the compilation); the generated file stays cached. @@ -195,18 +195,18 @@ public static partial class BrokenAssertionExtensions .SelectMany(x => x.Outputs) .Select(x => x.Reason) .ToArray(); - Xunit.Assert.Single(sourceOutputReasons, reason => reason != IncrementalStepRunReason.Cached); + await Assert.That(sourceOutputReasons).HasSingleItem(reason => reason != IncrementalStepRunReason.Cached); - var diagnostic = Xunit.Assert.Single(runResult.Diagnostics, d => d.Id == "TUNITGEN001"); - Xunit.Assert.Equal(4, diagnostic.Location.GetLineSpan().StartLinePosition.Line); + var diagnostic = await Assert.That(runResult.Diagnostics).HasSingleItem(d => d.Id == "TUNITGEN001"); + await Assert.That(diagnostic.Location.GetLineSpan().StartLinePosition.Line).IsEqualTo(4); // The location must stay tied to the syntax tree so #pragma and per-file severities apply. - Xunit.Assert.True(diagnostic.Location.IsInSource); - Xunit.Assert.Same(brokenTree, diagnostic.Location.SourceTree); + await Assert.That(diagnostic.Location.IsInSource).IsTrue(); + await Assert.That(diagnostic.Location.SourceTree).IsSameReferenceAs(brokenTree); } - [Fact] - public void DiagnosticInPathlessTreeKeepsSourceTree() + [Test] + public async Task DiagnosticInPathlessTreeKeepsSourceTree() { // Trees parsed without a path all share the empty path, so the path alone cannot identify the tree. var brokenTree = CSharpSyntaxTree.ParseText( @@ -222,17 +222,18 @@ public static partial class BrokenAssertionExtensions var compilation1 = Fixture.CreateLibrary(CSharpSyntaxTree.ParseText(DefaultAssertion), brokenTree); var driver1 = TestHelper.GenerateTracked(compilation1); - Xunit.Assert.Same(brokenTree, Xunit.Assert.Single(driver1.GetRunResult().Diagnostics, d => d.Id == "TUNITGEN001").Location.SourceTree); + var firstDiagnostic = await Assert.That(driver1.GetRunResult().Diagnostics).HasSingleItem(d => d.Id == "TUNITGEN001"); + await Assert.That(firstDiagnostic.Location.SourceTree).IsSameReferenceAs(brokenTree); var compilation2 = compilation1.AddSyntaxTrees(CSharpSyntaxTree.ParseText("struct MyValue {}")); var driver2 = driver1.RunGenerators(compilation2); - var diagnostic = Xunit.Assert.Single(driver2.GetRunResult().Diagnostics, d => d.Id == "TUNITGEN001"); - Xunit.Assert.True(diagnostic.Location.IsInSource); - Xunit.Assert.Same(brokenTree, diagnostic.Location.SourceTree); + var diagnostic = await Assert.That(driver2.GetRunResult().Diagnostics).HasSingleItem(d => d.Id == "TUNITGEN001"); + await Assert.That(diagnostic.Location.IsInSource).IsTrue(); + await Assert.That(diagnostic.Location.SourceTree).IsSameReferenceAs(brokenTree); } - private static void AssertRunReasons( + private static async Task AssertRunReasons( GeneratorDriver driver, IncrementalGeneratorRunReasons reasons, int outputIndex = 0 @@ -240,6 +241,6 @@ private static void AssertRunReasons( { var runResult = driver.GetRunResult().Results[0]; - TestHelper.AssertRunReason(runResult, MethodAssertionGenerator.BuildAssertion, reasons.BuildStep, outputIndex); + await TestHelper.AssertRunReason(runResult, MethodAssertionGenerator.BuildAssertion, reasons.BuildStep, outputIndex); } -} +} \ No newline at end of file diff --git a/tests/TUnit.SourceGenerator.IncrementalTests/PropertyInjectionSourceGeneratorIncrementalTests.cs b/tests/TUnit.SourceGenerator.IncrementalTests/PropertyInjectionSourceGeneratorIncrementalTests.cs index c16757624e8..37c8c55f373 100644 --- a/tests/TUnit.SourceGenerator.IncrementalTests/PropertyInjectionSourceGeneratorIncrementalTests.cs +++ b/tests/TUnit.SourceGenerator.IncrementalTests/PropertyInjectionSourceGeneratorIncrementalTests.cs @@ -2,7 +2,7 @@ using Microsoft.CodeAnalysis.CSharp; using TUnit.Core.SourceGenerator.Generators; -namespace TUnit.Assertions.SourceGenerator.IncrementalTests; +namespace TUnit.SourceGenerator.IncrementalTests; public class PropertyInjectionSourceGeneratorIncrementalTests { @@ -52,13 +52,13 @@ public void Test1() PropertyInjectionSourceGenerator.ConcreteGenericTypesStep, ]; - [Fact] - public void AddUnrelatedTypeShouldNotRegenerate() + [Test] + public async Task AddUnrelatedTypeShouldNotRegenerate() { var compilation1 = Fixture.CreateLibrary(CSharpSyntaxTree.ParseText(DefaultSource, CSharpParseOptions.Default)); var driver1 = TestHelper.GenerateTracked(compilation1); - AssertAllOutputs(driver1, IncrementalStepRunReason.New); + await AssertAllOutputs(driver1, IncrementalStepRunReason.New); var compilation2 = compilation1.AddSyntaxTrees(CSharpSyntaxTree.ParseText( """ @@ -72,24 +72,24 @@ public class Unrelated } """)); var driver2 = driver1.RunGenerators(compilation2); - AssertAllOutputs(driver2, IncrementalStepRunReason.Cached, IncrementalStepRunReason.Unchanged); + await AssertAllOutputs(driver2, IncrementalStepRunReason.Cached, IncrementalStepRunReason.Unchanged); } - [Fact] - public void EditUnrelatedMemberShouldNotRegenerate() + [Test] + public async Task EditUnrelatedMemberShouldNotRegenerate() { var compilation1 = Fixture.CreateLibrary(CSharpSyntaxTree.ParseText(DefaultSource, CSharpParseOptions.Default)); var driver1 = TestHelper.GenerateTracked(compilation1); - AssertAllOutputs(driver1, IncrementalStepRunReason.New); + await AssertAllOutputs(driver1, IncrementalStepRunReason.New); var compilation2 = TestHelper.ReplacePropertyDeclaration(compilation1, "Plain", "public long Plain { get; set; }"); var driver2 = driver1.RunGenerators(compilation2); - AssertAllOutputs(driver2, IncrementalStepRunReason.Cached, IncrementalStepRunReason.Unchanged); + await AssertAllOutputs(driver2, IncrementalStepRunReason.Cached, IncrementalStepRunReason.Unchanged); } - [Fact] - public void EditUnrelatedMemberShouldNotRerunConcreteGenericTypes() + [Test] + public async Task EditUnrelatedMemberShouldNotRerunConcreteGenericTypes() { var compilation1 = Fixture.CreateLibrary(CSharpSyntaxTree.ParseText(DefaultSource, CSharpParseOptions.Default)); @@ -99,12 +99,12 @@ public void EditUnrelatedMemberShouldNotRerunConcreteGenericTypes() // flattened step from re-running rather than merely re-producing equal values. var compilation2 = TestHelper.ReplacePropertyDeclaration(compilation1, "Plain", "public long Plain { get; set; }"); var driver2 = driver1.RunGenerators(compilation2); - TestHelper.AssertAllRunReasons(driver2.GetRunResult().Results[0], + await TestHelper.AssertAllRunReasons(driver2.GetRunResult().Results[0], PropertyInjectionSourceGenerator.ConcreteGenericTypesStep, IncrementalStepRunReason.Cached); } - [Fact] - public void ModifyDataSourcePropertyShouldRegenerate() + [Test] + public async Task ModifyDataSourcePropertyShouldRegenerate() { var compilation1 = Fixture.CreateLibrary(CSharpSyntaxTree.ParseText(DefaultSource, CSharpParseOptions.Default)); @@ -116,11 +116,11 @@ public void ModifyDataSourcePropertyShouldRegenerate() public Fixture? Injected { get; set; } """); var driver2 = driver1.RunGenerators(compilation2); - AssertAnyOutput(driver2, PropertyInjectionSourceGenerator.PropertyDataSourcesStep, IncrementalStepRunReason.Modified); + await AssertAnyOutput(driver2, PropertyInjectionSourceGenerator.PropertyDataSourcesStep, IncrementalStepRunReason.Modified); } - [Fact] - public void AddInitializerPropertyShouldRegenerate() + [Test] + public async Task AddInitializerPropertyShouldRegenerate() { var compilation1 = Fixture.CreateLibrary(CSharpSyntaxTree.ParseText(DefaultSource, CSharpParseOptions.Default)); @@ -137,11 +137,11 @@ public class Fixture : IAsyncInitializer } """); var driver2 = driver1.RunGenerators(compilation2); - AssertAnyOutput(driver2, PropertyInjectionSourceGenerator.AsyncInitializersStep, IncrementalStepRunReason.Modified); + await AssertAnyOutput(driver2, PropertyInjectionSourceGenerator.AsyncInitializersStep, IncrementalStepRunReason.Modified); } - [Fact] - public void AddConcreteGenericInstantiationShouldRegenerate() + [Test] + public async Task AddConcreteGenericInstantiationShouldRegenerate() { var compilation1 = Fixture.CreateLibrary(CSharpSyntaxTree.ParseText(DefaultSource, CSharpParseOptions.Default)); @@ -163,37 +163,37 @@ public void Test1() } """)); var driver2 = driver1.RunGenerators(compilation2); - AssertAnyOutput(driver2, PropertyInjectionSourceGenerator.ConcreteGenericTypesStep, IncrementalStepRunReason.New); + await AssertAnyOutput(driver2, PropertyInjectionSourceGenerator.ConcreteGenericTypesStep, IncrementalStepRunReason.New); var concreteTypes2 = driver2.GetRunResult().Results[0].TrackedSteps[PropertyInjectionSourceGenerator.ConcreteGenericTypesStep] .SelectMany(x => x.Outputs) .Count(); - Xunit.Assert.Equal(concreteTypes1 + 1, concreteTypes2); + await Assert.That(concreteTypes2).IsEqualTo(concreteTypes1 + 1); } - private static void AssertAllOutputs(GeneratorDriver driver, params IncrementalStepRunReason[] allowedReasons) + private static async Task AssertAllOutputs(GeneratorDriver driver, params IncrementalStepRunReason[] allowedReasons) { var runResult = driver.GetRunResult().Results[0]; foreach (var step in Steps) { var outputs = runResult.TrackedSteps[step].SelectMany(x => x.Outputs).ToArray(); - Xunit.Assert.NotEmpty(outputs); + await Assert.That(outputs).IsNotEmpty(); foreach (var output in outputs) { - Xunit.Assert.True(allowedReasons.Contains(output.Reason), - $"Step {step} produced an output with reason {output.Reason}; expected one of {string.Join(", ", allowedReasons)}."); + await Assert.That(allowedReasons).Contains(output.Reason) + .Because($"step {step} produced an output with reason {output.Reason}"); } } } - private static void AssertAnyOutput(GeneratorDriver driver, string step, IncrementalStepRunReason expectedReason) + private static async Task AssertAnyOutput(GeneratorDriver driver, string step, IncrementalStepRunReason expectedReason) { var runResult = driver.GetRunResult().Results[0]; var reasons = runResult.TrackedSteps[step].SelectMany(x => x.Outputs).Select(x => x.Reason).ToArray(); - Xunit.Assert.True(reasons.Contains(expectedReason), - $"Step {step} had no output with reason {expectedReason}; actual reasons: {string.Join(", ", reasons)}."); + await Assert.That(reasons).Contains(expectedReason) + .Because($"step {step} should have an output with reason {expectedReason}"); } -} +} \ No newline at end of file diff --git a/tests/TUnit.SourceGenerator.IncrementalTests/ShouldExtensionGeneratorIncrementalTests.cs b/tests/TUnit.SourceGenerator.IncrementalTests/ShouldExtensionGeneratorIncrementalTests.cs index 07c99c61b78..369f0762bdb 100644 --- a/tests/TUnit.SourceGenerator.IncrementalTests/ShouldExtensionGeneratorIncrementalTests.cs +++ b/tests/TUnit.SourceGenerator.IncrementalTests/ShouldExtensionGeneratorIncrementalTests.cs @@ -4,7 +4,7 @@ using Microsoft.CodeAnalysis.CSharp; using ShouldGenerator::TUnit.Assertions.Should.SourceGenerator; -namespace TUnit.Assertions.SourceGenerator.IncrementalTests; +namespace TUnit.SourceGenerator.IncrementalTests; public class ShouldExtensionGeneratorIncrementalTests { @@ -57,20 +57,20 @@ public void Method() { } } """; - [Fact] - public void GeneratesFromLocalContainersAndWrappers() + [Test] + public async Task GeneratesFromLocalContainersAndWrappers() { var compilation = Fixture.CreateLibrary(CSharpSyntaxTree.ParseText(DefaultSource)); var driver = TestHelper.GenerateTracked(compilation); var sources = driver.GetRunResult().Results[0].GeneratedSources; - Xunit.Assert.Contains("BeFoo", sources.Single(x => x.HintName == "ShouldFooExtensions.g.cs").SourceText.ToString()); - Xunit.Assert.Contains("BeFooToo", sources.Single(x => x.HintName == "FooWrapper.Generated.g.cs").SourceText.ToString()); + await Assert.That(sources.Single(x => x.HintName == "ShouldFooExtensions.g.cs").SourceText.ToString()).Contains("BeFoo"); + await Assert.That(sources.Single(x => x.HintName == "FooWrapper.Generated.g.cs").SourceText.ToString()).Contains("BeFooToo"); } - [Fact] - public void AddUnrelatedTypeShouldNotRegenerate() + [Test] + public async Task AddUnrelatedTypeShouldNotRegenerate() { var compilation1 = Fixture.CreateLibrary(CSharpSyntaxTree.ParseText(DefaultSource)); var driver1 = TestHelper.GenerateTracked(compilation1); @@ -78,11 +78,11 @@ public void AddUnrelatedTypeShouldNotRegenerate() var compilation2 = compilation1.AddSyntaxTrees(CSharpSyntaxTree.ParseText("struct MyValue {}")); var driver2 = driver1.RunGenerators(compilation2); - AssertUnchanged(driver2.GetRunResult().Results[0]); + await AssertUnchanged(driver2.GetRunResult().Results[0]); } - [Fact] - public void EditUnrelatedTypeShouldNotRegenerate() + [Test] + public async Task EditUnrelatedTypeShouldNotRegenerate() { var compilation1 = Fixture.CreateLibrary(CSharpSyntaxTree.ParseText(DefaultSource)); var driver1 = TestHelper.GenerateTracked(compilation1); @@ -90,11 +90,11 @@ public void EditUnrelatedTypeShouldNotRegenerate() var compilation2 = TestHelper.ReplaceMethodDeclaration(compilation1, "Method", "public void Method() { var x = 1; }"); var driver2 = driver1.RunGenerators(compilation2); - AssertUnchanged(driver2.GetRunResult().Results[0]); + await AssertUnchanged(driver2.GetRunResult().Results[0]); } - [Fact] - public void ModifyExtensionMethodShouldRegenerate() + [Test] + public async Task ModifyExtensionMethodShouldRegenerate() { var compilation1 = Fixture.CreateLibrary(CSharpSyntaxTree.ParseText(DefaultSource)); var driver1 = TestHelper.GenerateTracked(compilation1); @@ -107,15 +107,15 @@ public static FooAssertion IsFooish(this IAssertionSource source, int expec var driver2 = driver1.RunGenerators(compilation2); var runResult = driver2.GetRunResult().Results[0]; - TestHelper.AssertAllRunReasons(runResult, ShouldExtensionGenerator.LocalWrappersStep, + await TestHelper.AssertAllRunReasons(runResult, ShouldExtensionGenerator.LocalWrappersStep, IncrementalStepRunReason.Cached, IncrementalStepRunReason.Unchanged); - TestHelper.AssertAllRunReasons(runResult, ShouldExtensionGenerator.LocalDeclarationsStep, IncrementalStepRunReason.Modified); - TestHelper.AssertAllRunReasons(runResult, ShouldExtensionGenerator.PayloadStep, IncrementalStepRunReason.Modified); - Xunit.Assert.Contains("BeFooish", runResult.GeneratedSources.Single(x => x.HintName == "ShouldFooExtensions.g.cs").SourceText.ToString()); + await TestHelper.AssertAllRunReasons(runResult, ShouldExtensionGenerator.LocalDeclarationsStep, IncrementalStepRunReason.Modified); + await TestHelper.AssertAllRunReasons(runResult, ShouldExtensionGenerator.PayloadStep, IncrementalStepRunReason.Modified); + await Assert.That(runResult.GeneratedSources.Single(x => x.HintName == "ShouldFooExtensions.g.cs").SourceText.ToString()).Contains("BeFooish"); } - [Fact] - public void ModifyWrapperShouldRegenerate() + [Test] + public async Task ModifyWrapperShouldRegenerate() { var compilation1 = Fixture.CreateLibrary(CSharpSyntaxTree.ParseText(DefaultSource)); var driver1 = TestHelper.GenerateTracked(compilation1); @@ -131,18 +131,18 @@ public void BeFooToo(int expected) { } var driver2 = driver1.RunGenerators(compilation2); var runResult = driver2.GetRunResult().Results[0]; - TestHelper.AssertAllRunReasons(runResult, ShouldExtensionGenerator.LocalContainersStep, + await TestHelper.AssertAllRunReasons(runResult, ShouldExtensionGenerator.LocalContainersStep, IncrementalStepRunReason.Cached, IncrementalStepRunReason.Unchanged); - TestHelper.AssertAllRunReasons(runResult, ShouldExtensionGenerator.PayloadStep, IncrementalStepRunReason.Modified); - Xunit.Assert.DoesNotContain(runResult.GeneratedSources, x => x.HintName == "FooWrapper.Generated.g.cs"); + await TestHelper.AssertAllRunReasons(runResult, ShouldExtensionGenerator.PayloadStep, IncrementalStepRunReason.Modified); + await Assert.That(runResult.GeneratedSources).DoesNotContain(x => x.HintName == "FooWrapper.Generated.g.cs"); } - [Fact] - public void ModifyWrappedAssertionInOtherFileShouldRegenerateWrapper() + [Test] + public async Task ModifyWrappedAssertionInOtherFileShouldRegenerateWrapper() { var compilation1 = Fixture.CreateLibrary(SplitAssertionTree(SplitAssertion), SplitDeclarationsTree()); var driver1 = TestHelper.GenerateTracked(compilation1); - Xunit.Assert.Contains("BeFooToo", GetSource(driver1, "FooWrapper.Generated.g.cs")); + await Assert.That(GetSource(driver1, "FooWrapper.Generated.g.cs")).Contains("BeFooToo"); var compilation2 = compilation1.ReplaceSyntaxTree( compilation1.SyntaxTrees.First(), @@ -150,20 +150,20 @@ public void ModifyWrappedAssertionInOtherFileShouldRegenerateWrapper() var driver2 = driver1.RunGenerators(compilation2); var runResult = driver2.GetRunResult().Results[0]; - TestHelper.AssertAllRunReasons(runResult, ShouldExtensionGenerator.LocalWrappersStep, + await TestHelper.AssertAllRunReasons(runResult, ShouldExtensionGenerator.LocalWrappersStep, IncrementalStepRunReason.Cached, IncrementalStepRunReason.Unchanged); - TestHelper.AssertAllRunReasons(runResult, ShouldExtensionGenerator.LocalDeclarationsStep, IncrementalStepRunReason.Modified); + await TestHelper.AssertAllRunReasons(runResult, ShouldExtensionGenerator.LocalDeclarationsStep, IncrementalStepRunReason.Modified); var wrapperSource = GetSource(driver2, "FooWrapper.Generated.g.cs"); - Xunit.Assert.Contains("BeFooThree", wrapperSource); - Xunit.Assert.DoesNotContain("BeFooToo", wrapperSource); + await Assert.That(wrapperSource).Contains("BeFooThree"); + await Assert.That(wrapperSource).DoesNotContain("BeFooToo"); } - [Fact] - public void ModifyReturnedAssertionInOtherFileShouldRegenerateContainer() + [Test] + public async Task ModifyReturnedAssertionInOtherFileShouldRegenerateContainer() { var compilation1 = Fixture.CreateLibrary(SplitAssertionTree(SplitAssertion), SplitDeclarationsTree()); var driver1 = TestHelper.GenerateTracked(compilation1); - Xunit.Assert.Contains("BeFoo", GetSource(driver1, "ShouldFooExtensions.g.cs")); + await Assert.That(GetSource(driver1, "ShouldFooExtensions.g.cs")).Contains("BeFoo"); // The extension no longer maps onto a constructor, so its Should counterpart must disappear. var compilation2 = compilation1.ReplaceSyntaxTree( @@ -174,14 +174,14 @@ public void ModifyReturnedAssertionInOtherFileShouldRegenerateContainer() var driver2 = driver1.RunGenerators(compilation2); var runResult = driver2.GetRunResult().Results[0]; - TestHelper.AssertAllRunReasons(runResult, ShouldExtensionGenerator.LocalContainersStep, + await TestHelper.AssertAllRunReasons(runResult, ShouldExtensionGenerator.LocalContainersStep, IncrementalStepRunReason.Cached, IncrementalStepRunReason.Unchanged); - TestHelper.AssertAllRunReasons(runResult, ShouldExtensionGenerator.LocalDeclarationsStep, IncrementalStepRunReason.Modified); - Xunit.Assert.DoesNotContain(runResult.GeneratedSources, x => x.HintName == "ShouldFooExtensions.g.cs"); + await TestHelper.AssertAllRunReasons(runResult, ShouldExtensionGenerator.LocalDeclarationsStep, IncrementalStepRunReason.Modified); + await Assert.That(runResult.GeneratedSources).DoesNotContain(x => x.HintName == "ShouldFooExtensions.g.cs"); } - [Fact] - public void PartialContainerSplitAcrossFilesGeneratesAllMethodsOnce() + [Test] + public async Task PartialContainerSplitAcrossFilesGeneratesAllMethodsOnce() { var compilation1 = Fixture.CreateLibrary( SplitAssertionTree(SplitAssertion), @@ -191,8 +191,8 @@ public void PartialContainerSplitAcrossFilesGeneratesAllMethodsOnce() var driver1 = TestHelper.GenerateTracked(compilation1); var source = GetSource(driver1, "ShouldFooExtensions.g.cs"); - Xunit.Assert.Single(System.Text.RegularExpressions.Regex.Matches(source, @"> BeFoo\(")); - Xunit.Assert.Single(System.Text.RegularExpressions.Regex.Matches(source, @"> BeBar\(")); + await Assert.That(System.Text.RegularExpressions.Regex.Matches(source, @"> BeFoo\(")).HasSingleItem(); + await Assert.That(System.Text.RegularExpressions.Regex.Matches(source, @"> BeBar\(")).HasSingleItem(); // Editing the part without extension methods changes nothing the generator reads. var compilation2 = compilation1.ReplaceSyntaxTree(compilation1.SyntaxTrees.Last(), HelperPartTree("2")); @@ -200,17 +200,17 @@ public void PartialContainerSplitAcrossFilesGeneratesAllMethodsOnce() // No [ShouldGeneratePartial] here, so the wrappers step never runs and is not asserted. var runResult = driver2.GetRunResult().Results[0]; - TestHelper.AssertAllRunReasons(runResult, ShouldExtensionGenerator.LocalContainersStep, + await TestHelper.AssertAllRunReasons(runResult, ShouldExtensionGenerator.LocalContainersStep, IncrementalStepRunReason.Cached, IncrementalStepRunReason.Unchanged); - TestHelper.AssertAllRunReasons(runResult, ShouldExtensionGenerator.LocalDeclarationsStep, + await TestHelper.AssertAllRunReasons(runResult, ShouldExtensionGenerator.LocalDeclarationsStep, IncrementalStepRunReason.Cached, IncrementalStepRunReason.Unchanged); - TestHelper.AssertAllRunReasons(runResult, ShouldExtensionGenerator.PayloadStep, + await TestHelper.AssertAllRunReasons(runResult, ShouldExtensionGenerator.PayloadStep, IncrementalStepRunReason.Cached, IncrementalStepRunReason.Unchanged); - TestHelper.AssertSourceOutputsCached(runResult); + await TestHelper.AssertSourceOutputsCached(runResult); } - [Fact] - public void GenericAndNestedWrappersResolveByMetadataName() + [Test] + public async Task GenericAndNestedWrappersResolveByMetadataName() { // The syntax step hands the resolver hand-built metadata names; a wrong name makes // GetTypeByMetadataName return null and the wrapper silently disappears. Cover a @@ -242,10 +242,10 @@ public partial class NestedWrapper var driver = TestHelper.GenerateTracked(compilation); - Xunit.Assert.Contains("BeFooToo", GetSource(driver, "GenericWrapper.Generated.g.cs")); + await Assert.That(GetSource(driver, "GenericWrapper.Generated.g.cs")).Contains("BeFooToo"); var nestedSource = GetSource(driver, "NestedWrapper.Generated.g.cs"); - Xunit.Assert.Contains("BeFooToo", nestedSource); - Xunit.Assert.Contains("partial class Outer", nestedSource); + await Assert.That(nestedSource).Contains("BeFooToo"); + await Assert.That(nestedSource).Contains("partial class Outer"); } private static SyntaxTree HelperPartTree(string value) => @@ -338,18 +338,18 @@ public partial class FooWrapper private static string GetSource(GeneratorDriver driver, string hintName) => driver.GetRunResult().Results[0].GeneratedSources.Single(x => x.HintName == hintName).SourceText.ToString(); - private static void AssertUnchanged(GeneratorRunResult runResult) + private static async Task AssertUnchanged(GeneratorRunResult runResult) { - TestHelper.AssertAllRunReasons(runResult, ShouldExtensionGenerator.LocalContainersStep, + await TestHelper.AssertAllRunReasons(runResult, ShouldExtensionGenerator.LocalContainersStep, IncrementalStepRunReason.Cached, IncrementalStepRunReason.Unchanged); - TestHelper.AssertAllRunReasons(runResult, ShouldExtensionGenerator.LocalWrappersStep, + await TestHelper.AssertAllRunReasons(runResult, ShouldExtensionGenerator.LocalWrappersStep, IncrementalStepRunReason.Cached, IncrementalStepRunReason.Unchanged); - TestHelper.AssertAllRunReasons(runResult, ShouldExtensionGenerator.LocalDeclarationsStep, + await TestHelper.AssertAllRunReasons(runResult, ShouldExtensionGenerator.LocalDeclarationsStep, IncrementalStepRunReason.Cached, IncrementalStepRunReason.Unchanged); - TestHelper.AssertAllRunReasons(runResult, ShouldExtensionGenerator.CompilationDataStep, + await TestHelper.AssertAllRunReasons(runResult, ShouldExtensionGenerator.CompilationDataStep, IncrementalStepRunReason.Cached, IncrementalStepRunReason.Unchanged); - TestHelper.AssertAllRunReasons(runResult, ShouldExtensionGenerator.PayloadStep, + await TestHelper.AssertAllRunReasons(runResult, ShouldExtensionGenerator.PayloadStep, IncrementalStepRunReason.Cached, IncrementalStepRunReason.Unchanged); - TestHelper.AssertSourceOutputsCached(runResult); + await TestHelper.AssertSourceOutputsCached(runResult); } -} +} \ No newline at end of file diff --git a/tests/TUnit.SourceGenerator.IncrementalTests/StaticPropertyInitializationGeneratorIncrementalTests.cs b/tests/TUnit.SourceGenerator.IncrementalTests/StaticPropertyInitializationGeneratorIncrementalTests.cs index b50c7b409c5..b327072d24f 100644 --- a/tests/TUnit.SourceGenerator.IncrementalTests/StaticPropertyInitializationGeneratorIncrementalTests.cs +++ b/tests/TUnit.SourceGenerator.IncrementalTests/StaticPropertyInitializationGeneratorIncrementalTests.cs @@ -3,7 +3,7 @@ using TUnit.Core.SourceGenerator.CodeGenerators; using TUnit.Core.SourceGenerator.Models; -namespace TUnit.Assertions.SourceGenerator.IncrementalTests; +namespace TUnit.SourceGenerator.IncrementalTests; public class StaticPropertyInitializationGeneratorIncrementalTests { @@ -28,29 +28,29 @@ public class StaticPropertyDataSourceTests } """; - [Fact] - public void AddUnrelatedMethodShouldNotRegenerate() + [Test] + public async Task AddUnrelatedMethodShouldNotRegenerate() { var syntaxTree = CSharpSyntaxTree.ParseText(DefaultProperties, CSharpParseOptions.Default); var compilation1 = Fixture.CreateLibrary(syntaxTree); var driver1 = TestHelper.GenerateTracked(compilation1); - AssertRunReasons(driver1, IncrementalGeneratorRunReasons.New); + await AssertRunReasons(driver1, IncrementalGeneratorRunReasons.New); var compilation2 = compilation1.AddSyntaxTrees(CSharpSyntaxTree.ParseText("struct MyValue {}")); var driver2 = driver1.RunGenerators(compilation2); - AssertRunParseLength(driver2,2); - AssertRunReasons(driver2, IncrementalGeneratorRunReasons.Cached); + await AssertRunParseLength(driver2,2); + await AssertRunReasons(driver2, IncrementalGeneratorRunReasons.Cached); } - [Fact] - public void AddUnrelatedClassWithBaseListShouldNotRerunParse() + [Test] + public async Task AddUnrelatedClassWithBaseListShouldNotRerunParse() { var syntaxTree = CSharpSyntaxTree.ParseText(DefaultProperties, CSharpParseOptions.Default); var compilation1 = Fixture.CreateLibrary(syntaxTree); var driver1 = TestHelper.GenerateTracked(compilation1); - AssertRunReasons(driver1, IncrementalGeneratorRunReasons.New); + await AssertRunReasons(driver1, IncrementalGeneratorRunReasons.New); // A class with a base list is a syntactic candidate, but its chain has no static // data-source property, so it must not reach the collected input of the parse step. @@ -62,18 +62,18 @@ public void Dispose() { } } """)); var driver2 = driver1.RunGenerators(compilation2); - AssertRunParseLength(driver2, 2); - AssertRunReasons(driver2, IncrementalGeneratorRunReasons.Cached); + await AssertRunParseLength(driver2, 2); + await AssertRunReasons(driver2, IncrementalGeneratorRunReasons.Cached); } - [Fact] - public void AddClassWithValidPropertyShouldRegenerate() + [Test] + public async Task AddClassWithValidPropertyShouldRegenerate() { var syntaxTree = CSharpSyntaxTree.ParseText(DefaultProperties, CSharpParseOptions.Default); var compilation1 = Fixture.CreateLibrary(syntaxTree); var driver1 = TestHelper.GenerateTracked(compilation1); - AssertRunReasons(driver1, IncrementalGeneratorRunReasons.New); + await AssertRunReasons(driver1, IncrementalGeneratorRunReasons.New); var compilation2 = compilation1.AddSyntaxTrees(CSharpSyntaxTree.ParseText( """ @@ -88,18 +88,18 @@ public class ExtraStaticProperty } """)); var driver2 = driver1.RunGenerators(compilation2); - AssertRunParseLength(driver2,3); - AssertRunReasons(driver2, IncrementalGeneratorRunReasons.ModifiedSource); + await AssertRunParseLength(driver2,3); + await AssertRunReasons(driver2, IncrementalGeneratorRunReasons.ModifiedSource); } - [Fact] - public void ModifyPropertyAttributeShouldRegenerate() + [Test] + public async Task ModifyPropertyAttributeShouldRegenerate() { var syntaxTree = CSharpSyntaxTree.ParseText(DefaultProperties, CSharpParseOptions.Default); var compilation1 = Fixture.CreateLibrary(syntaxTree); var driver1 = TestHelper.GenerateTracked(compilation1); - AssertRunReasons(driver1, IncrementalGeneratorRunReasons.New); + await AssertRunReasons(driver1, IncrementalGeneratorRunReasons.New); var compilation2 = compilation1.AddSyntaxTrees(CSharpSyntaxTree.ParseText( """ @@ -114,13 +114,13 @@ public class ExtraStaticProperty } """)); var driver2 = driver1.RunGenerators(compilation2); - AssertRunReasons(driver2, IncrementalGeneratorRunReasons.Modified); + await AssertRunReasons(driver2, IncrementalGeneratorRunReasons.Modified); } - [Theory] - [InlineData(true)] - [InlineData(false)] - public void HiddenBaseStaticPropertyIsInitializedRegardlessOfDeclarationOrder(bool derivedFirst) + [Test] + [Arguments(true)] + [Arguments(false)] + public async Task HiddenBaseStaticPropertyIsInitializedRegardlessOfDeclarationOrder(bool derivedFirst) { const string baseClass = """ @@ -153,20 +153,20 @@ public class HidingDerived : HidingBase var driver = TestHelper.GenerateTracked(compilation); // Both HidingDerived.Value and the hidden HidingBase.Value need initializing - AssertRunParseLength(driver, 2); + await AssertRunParseLength(driver, 2); } - private static void AssertRunReasons( + private static async Task AssertRunReasons( GeneratorDriver driver, IncrementalGeneratorRunReasons reasons, int outputIndex = 0 ) { var runResult = driver.GetRunResult().Results[0]; - TestHelper.AssertRunReason(runResult, StaticPropertyInitializationGenerator.ParseStaticProperties, reasons.BuildStep, outputIndex); + await TestHelper.AssertRunReason(runResult, StaticPropertyInitializationGenerator.ParseStaticProperties, reasons.BuildStep, outputIndex); } - private static void AssertRunParseLength( + private static async Task AssertRunParseLength( GeneratorDriver driver, int staticPropertyModelCount ) @@ -174,6 +174,6 @@ int staticPropertyModelCount var runResult = driver.GetRunResult().Results[0]; var runValue = runResult.TrackedSteps[StaticPropertyInitializationGenerator.ParseStaticProperties][0].Outputs[0].Value; var runState = (EquatableArray)runValue; - Xunit.Assert.Equal(staticPropertyModelCount, runState.Length); + await Assert.That(runState.Length).IsEqualTo(staticPropertyModelCount); } -} +} \ No newline at end of file diff --git a/tests/TUnit.SourceGenerator.IncrementalTests/TUnit.SourceGenerator.IncrementalTests.csproj b/tests/TUnit.SourceGenerator.IncrementalTests/TUnit.SourceGenerator.IncrementalTests.csproj index 063a016f6ce..0d82772e057 100644 --- a/tests/TUnit.SourceGenerator.IncrementalTests/TUnit.SourceGenerator.IncrementalTests.csproj +++ b/tests/TUnit.SourceGenerator.IncrementalTests/TUnit.SourceGenerator.IncrementalTests.csproj @@ -1,33 +1,33 @@  + + - net10.0 + net10.0 enable enable false $(NoWarn);MSB3277 - TUnit.Assertions.SourceGenerator.IncrementalTests - - + + + + - - - - - - + + + diff --git a/tests/TUnit.SourceGenerator.IncrementalTests/TestHelper.cs b/tests/TUnit.SourceGenerator.IncrementalTests/TestHelper.cs index d3b71da0310..8fcda9b567b 100644 --- a/tests/TUnit.SourceGenerator.IncrementalTests/TestHelper.cs +++ b/tests/TUnit.SourceGenerator.IncrementalTests/TestHelper.cs @@ -2,7 +2,7 @@ using Microsoft.CodeAnalysis.CSharp; using Microsoft.CodeAnalysis.CSharp.Syntax; -namespace TUnit.Assertions.SourceGenerator.IncrementalTests; +namespace TUnit.SourceGenerator.IncrementalTests; internal static class TestHelper { @@ -110,7 +110,7 @@ string newDeclaration /// Asserts every output of the tracked step has one of the /// , and that the step produced at least one output. /// - public static void AssertAllRunReasons( + public static async Task AssertAllRunReasons( GeneratorRunResult runResult, string stepName, params IncrementalStepRunReason[] allowedReasons @@ -120,17 +120,17 @@ params IncrementalStepRunReason[] allowedReasons .SelectMany(x => x.Outputs) .ToArray(); - Xunit.Assert.NotEmpty(outputs); + await Assert.That(outputs).IsNotEmpty(); foreach (var output in outputs) { - Xunit.Assert.Contains(output.Reason, allowedReasons); + await Assert.That(allowedReasons).Contains(output.Reason); } } /// /// Asserts at least one output of the tracked step has . /// - public static void AssertAnyRunReason( + public static async Task AssertAnyRunReason( GeneratorRunResult runResult, string stepName, IncrementalStepRunReason expectedReason @@ -141,27 +141,27 @@ IncrementalStepRunReason expectedReason .Select(x => x.Reason) .ToArray(); - Xunit.Assert.Contains(expectedReason, reasons); + await Assert.That(reasons).Contains(expectedReason); } /// /// Asserts no source output was re-run, i.e. nothing was regenerated. /// - public static void AssertSourceOutputsCached(GeneratorRunResult runResult) + public static async Task AssertSourceOutputsCached(GeneratorRunResult runResult) { var outputs = runResult.TrackedOutputSteps .SelectMany(x => x.Value) .SelectMany(x => x.Outputs) .ToArray(); - Xunit.Assert.NotEmpty(outputs); + await Assert.That(outputs).IsNotEmpty(); foreach (var output in outputs) { - Xunit.Assert.Equal(IncrementalStepRunReason.Cached, output.Reason); + await Assert.That(output.Reason).IsEqualTo(IncrementalStepRunReason.Cached); } } - public static void AssertRunReason( + public static async Task AssertRunReason( GeneratorRunResult runResult, string stepName, IncrementalStepRunReason expectedStepReason, diff --git a/tests/TUnit.TestProject/Bugs/2136/Tests.cs b/tests/TUnit.TestProject/Bugs/2136/Tests.cs index c57d2e6d19f..bbd68fc49b3 100644 --- a/tests/TUnit.TestProject/Bugs/2136/Tests.cs +++ b/tests/TUnit.TestProject/Bugs/2136/Tests.cs @@ -14,7 +14,8 @@ public class Tests public async Task GenericArgumentsTest(T value, string expected) { // Assert - await Assert.That(value?.ToString()).IsEqualTo(expected); + // Invariant: the expected strings use invariant formatting (e.g. "1.1"), whatever the machine culture. + await Assert.That(Convert.ToString(value, System.Globalization.CultureInfo.InvariantCulture)).IsEqualTo(expected); } } diff --git a/tests/TUnit.UnitTests/ArgumentFormatterTests.cs b/tests/TUnit.UnitTests/ArgumentFormatterTests.cs new file mode 100644 index 00000000000..f1059727e95 --- /dev/null +++ b/tests/TUnit.UnitTests/ArgumentFormatterTests.cs @@ -0,0 +1,97 @@ +using TUnit.Core.Helpers; + +namespace TUnit.UnitTests; + +public class ArgumentFormatterTests +{ + [Test] + public async Task FormatDefault_ValueTuple_FormatsCorrectly() + { + var tuple = (1, "test", true); + + var result = ArgumentFormatter.Format(tuple, []); + + await Assert.That(result).IsEqualTo("(1, test, True)"); + } + + [Test] + public async Task FormatDefault_NestedValueTuple_FormatsCorrectly() + { + var tuple = (1, (2, "inner"), true); + + var result = ArgumentFormatter.Format(tuple, []); + + await Assert.That(result).IsEqualTo("(1, (2, inner), True)"); + } + + [Test] + public async Task FormatDefault_SystemTuple_FormatsCorrectly() + { + var tuple = Tuple.Create(1, "test", false); + + var result = ArgumentFormatter.Format(tuple, []); + + await Assert.That(result).IsEqualTo("(1, test, False)"); + } + + [Test] + public async Task FormatArguments_WithTuples_FormatsCorrectly() + { + var args = new object?[] { (1, "a"), 42, (true, 3.14) }; + + var result = ArgumentFormatter.FormatArguments(args); + + // Primitives are formatted with ToString(), i.e. the current culture (3,14 under sv-SE). + await Assert.That(result).IsEqualTo($"(1, a), 42, (True, {3.14})"); + } + + [Test] + public async Task FormatDefault_LargeTuple_FormatsAllElements() + { + var tuple = (1, 2, 3, 4, 5, 6, 7, 8); + + var result = ArgumentFormatter.Format(tuple, []); + + await Assert.That(result).IsEqualTo("(1, 2, 3, 4, 5, 6, 7, 8)"); + } + + [Test] + public async Task FormatDefault_TupleWithNull_HandlesNullCorrectly() + { + (int, string?, string) tuple = (1, null, "test"); + + var result = ArgumentFormatter.Format(tuple, []); + + await Assert.That(result).IsEqualTo("(1, null, test)"); + } + + [Test] + public async Task FormatDefault_StringWithDots_EscapesDotsWithMiddleDot() + { + var stringWithDots = "1.2.3"; + + var result = ArgumentFormatter.Format(stringWithDots, []); + + await Assert.That(result).IsEqualTo("1·2·3"); + } + + [Test] + public async Task FormatDefault_StringWithoutDots_ReturnsUnchanged() + { + var stringWithoutDots = "hello world"; + + var result = ArgumentFormatter.Format(stringWithoutDots, []); + + await Assert.That(result).IsEqualTo("hello world"); + } + + [Test] + public async Task FormatArguments_WithStringsContainingDots_EscapesDots() + { + var args = new object?[] { "hello", "with.dot", "1.2.3" }; + + var result = ArgumentFormatter.FormatArguments(args); + + await Assert.That(result).IsEqualTo("hello, with·dot, 1·2·3"); + } +} \ No newline at end of file diff --git a/tools/TUnit.Pipeline/Modules/Abstract/TestBaseModule.cs b/tools/TUnit.Pipeline/Modules/Abstract/TestBaseModule.cs index f944a5144fc..95353b87e1c 100644 --- a/tools/TUnit.Pipeline/Modules/Abstract/TestBaseModule.cs +++ b/tools/TUnit.Pipeline/Modules/Abstract/TestBaseModule.cs @@ -11,10 +11,21 @@ namespace TUnit.Pipeline.Modules.Abstract; public abstract class TestBaseModule : Module> { - protected virtual IEnumerable TestableFrameworks - { - get { yield return "net10.0"; } - } + /// Every modern TFM the repo targets. + protected static IReadOnlyList ModernFrameworks { get; } = ["net10.0", "net9.0", "net8.0"]; + + /// + /// , plus net472 on Windows, the only OS that can run .NET Framework tests. + /// + protected static IReadOnlyList ModernAndNetFrameworks { get; } = + IsWindows ? [.. ModernFrameworks, "net472"] : ModernFrameworks; + + /// + /// Frameworks to run. Defaults to ; frameworks the project did not + /// build are skipped (see ), so net10.0-only projects run once. + /// Override with to add net472 on Windows, or to deliberately narrow the set. + /// + protected virtual IEnumerable TestableFrameworks => ModernFrameworks; /// True on Windows, where legacy .NET Framework TFMs (net4xx) can be tested. protected static bool IsWindows => RuntimeInformation.IsOSPlatform(OSPlatform.Windows); diff --git a/tools/TUnit.Pipeline/Modules/RunAnalyzersTestsModule.cs b/tools/TUnit.Pipeline/Modules/RunAnalyzersTestsModule.cs index d487d0e7db5..18a6275aa13 100644 --- a/tools/TUnit.Pipeline/Modules/RunAnalyzersTestsModule.cs +++ b/tools/TUnit.Pipeline/Modules/RunAnalyzersTestsModule.cs @@ -1,41 +1,34 @@ -using ModularPipelines.Attributes; -using ModularPipelines.Context; -using ModularPipelines.DotNet.Extensions; +using ModularPipelines.Context; using ModularPipelines.DotNet.Options; using ModularPipelines.Extensions; using ModularPipelines.Git.Extensions; -using ModularPipelines.Models; -using ModularPipelines.Modules; using ModularPipelines.Options; +using TUnit.Pipeline.Modules.Abstract; namespace TUnit.Pipeline.Modules; -public class RunAnalyzersTestsModule : Module +public class RunAnalyzersTestsModule : TestBaseModule { - protected override async Task ExecuteAsync(IModuleContext context, CancellationToken cancellationToken) + protected override Task<(DotNetRunOptions Options, CommandExecutionOptions? ExecutionOptions)> GetTestOptions(IModuleContext context, string framework, CancellationToken cancellationToken) { var project = context.Git().RootDirectory.FindFile(x => x.Name == "TUnit.Analyzers.Tests.csproj").AssertExists(); - return await context.DotNet().Test(new DotNetTestOptions - { - NoBuild = true, - Configuration = "Release", - Framework = "net8.0", - Arguments = ["--", "--hangdump", "--hangdump-filename", "hangdump.analyzers-tests.dmp", "--hangdump-timeout", "5m"], - }, new CommandExecutionOptions - { - WorkingDirectory = project.Folder!.Path, - EnvironmentVariables = new Dictionary + return Task.FromResult<(DotNetRunOptions, CommandExecutionOptions?)>(( + new DotNetRunOptions { - ["DISABLE_GITHUB_REPORTER"] = "true", + NoBuild = true, + Configuration = "Release", + Framework = framework, + Arguments = ["--hangdump", "--hangdump-filename", $"hangdump.analyzers-tests-{framework}.dmp", "--hangdump-timeout", "5m"], }, - LogSettings = new CommandLoggingOptions + new CommandExecutionOptions { - ShowCommandArguments = true, - ShowStandardError = true, - ShowExecutionTime = true, - ShowExitCode = true + WorkingDirectory = project.Folder!.Path, + EnvironmentVariables = new Dictionary + { + ["DISABLE_GITHUB_REPORTER"] = "true", + } } - }, cancellationToken); + )); } } diff --git a/tools/TUnit.Pipeline/Modules/RunAspNetCoreAnalyzersTestsModule.cs b/tools/TUnit.Pipeline/Modules/RunAspNetCoreAnalyzersTestsModule.cs index b1e399ab4d1..7589a8b9567 100644 --- a/tools/TUnit.Pipeline/Modules/RunAspNetCoreAnalyzersTestsModule.cs +++ b/tools/TUnit.Pipeline/Modules/RunAspNetCoreAnalyzersTestsModule.cs @@ -1,41 +1,34 @@ -using ModularPipelines.Attributes; using ModularPipelines.Context; -using ModularPipelines.DotNet.Extensions; using ModularPipelines.DotNet.Options; using ModularPipelines.Extensions; using ModularPipelines.Git.Extensions; -using ModularPipelines.Models; -using ModularPipelines.Modules; using ModularPipelines.Options; +using TUnit.Pipeline.Modules.Abstract; namespace TUnit.Pipeline.Modules; -public class RunAspNetCoreAnalyzersTestsModule : Module +public class RunAspNetCoreAnalyzersTestsModule : TestBaseModule { - protected override async Task ExecuteAsync(IModuleContext context, CancellationToken cancellationToken) + protected override Task<(DotNetRunOptions Options, CommandExecutionOptions? ExecutionOptions)> GetTestOptions(IModuleContext context, string framework, CancellationToken cancellationToken) { var project = context.Git().RootDirectory.FindFile(x => x.Name == "TUnit.AspNetCore.Analyzers.Tests.csproj").AssertExists(); - return await context.DotNet().Test(new DotNetTestOptions - { - NoBuild = true, - Configuration = "Release", - Framework = "net9.0", - Arguments = ["--", "--hangdump", "--hangdump-filename", "hangdump.aspnetcore-analyzers-tests.dmp", "--hangdump-timeout", "5m"], - }, new CommandExecutionOptions - { - WorkingDirectory = project.Folder!.Path, - EnvironmentVariables = new Dictionary + return Task.FromResult<(DotNetRunOptions, CommandExecutionOptions?)>(( + new DotNetRunOptions { - ["DISABLE_GITHUB_REPORTER"] = "true", + NoBuild = true, + Configuration = "Release", + Framework = framework, + Arguments = ["--hangdump", "--hangdump-filename", $"hangdump.aspnetcore-analyzers-tests-{framework}.dmp", "--hangdump-timeout", "5m"], }, - LogSettings = new CommandLoggingOptions + new CommandExecutionOptions { - ShowCommandArguments = true, - ShowStandardError = true, - ShowExecutionTime = true, - ShowExitCode = true + WorkingDirectory = project.Folder!.Path, + EnvironmentVariables = new Dictionary + { + ["DISABLE_GITHUB_REPORTER"] = "true", + } } - }, cancellationToken); + )); } } diff --git a/tools/TUnit.Pipeline/Modules/RunAspNetCoreTestsModule.cs b/tools/TUnit.Pipeline/Modules/RunAspNetCoreTestsModule.cs index f4c3187bcf5..8eba3e73b51 100644 --- a/tools/TUnit.Pipeline/Modules/RunAspNetCoreTestsModule.cs +++ b/tools/TUnit.Pipeline/Modules/RunAspNetCoreTestsModule.cs @@ -9,15 +9,6 @@ namespace TUnit.Pipeline.Modules; public class RunAspNetCoreTestsModule : TestBaseModule { - protected override IEnumerable TestableFrameworks - { - get - { - yield return "net10.0"; - yield return "net8.0"; - } - } - protected override Task<(DotNetRunOptions Options, CommandExecutionOptions? ExecutionOptions)> GetTestOptions(IModuleContext context, string framework, CancellationToken cancellationToken) { var project = context.Git().RootDirectory.FindFile(x => x.Name == "TUnit.AspNetCore.Tests.csproj").AssertExists(); diff --git a/tools/TUnit.Pipeline/Modules/RunAssertionsAnalyzersTestsModule.cs b/tools/TUnit.Pipeline/Modules/RunAssertionsAnalyzersTestsModule.cs index bd51ada274e..70b3565d8fd 100644 --- a/tools/TUnit.Pipeline/Modules/RunAssertionsAnalyzersTestsModule.cs +++ b/tools/TUnit.Pipeline/Modules/RunAssertionsAnalyzersTestsModule.cs @@ -1,41 +1,34 @@ -using ModularPipelines.Attributes; -using ModularPipelines.Context; -using ModularPipelines.DotNet.Extensions; +using ModularPipelines.Context; using ModularPipelines.DotNet.Options; using ModularPipelines.Extensions; using ModularPipelines.Git.Extensions; -using ModularPipelines.Models; -using ModularPipelines.Modules; using ModularPipelines.Options; +using TUnit.Pipeline.Modules.Abstract; namespace TUnit.Pipeline.Modules; -public class RunAssertionsAnalyzersTestsModule : Module +public class RunAssertionsAnalyzersTestsModule : TestBaseModule { - protected override async Task ExecuteAsync(IModuleContext context, CancellationToken cancellationToken) + protected override Task<(DotNetRunOptions Options, CommandExecutionOptions? ExecutionOptions)> GetTestOptions(IModuleContext context, string framework, CancellationToken cancellationToken) { var project = context.Git().RootDirectory.FindFile(x => x.Name == "TUnit.Assertions.Analyzers.Tests.csproj").AssertExists(); - return await context.DotNet().Test(new DotNetTestOptions - { - NoBuild = true, - Configuration = "Release", - Framework = "net8.0", - Arguments = ["--", "--hangdump", "--hangdump-filename", "hangdump.assertions-analyzers-tests.dmp", "--hangdump-timeout", "5m"], - }, new CommandExecutionOptions - { - WorkingDirectory = project.Folder!.Path, - EnvironmentVariables = new Dictionary + return Task.FromResult<(DotNetRunOptions, CommandExecutionOptions?)>(( + new DotNetRunOptions { - ["DISABLE_GITHUB_REPORTER"] = "true", + NoBuild = true, + Configuration = "Release", + Framework = framework, + Arguments = ["--hangdump", "--hangdump-filename", $"hangdump.assertions-analyzers-tests-{framework}.dmp", "--hangdump-timeout", "5m"], }, - LogSettings = new CommandLoggingOptions + new CommandExecutionOptions { - ShowCommandArguments = true, - ShowStandardError = true, - ShowExecutionTime = true, - ShowExitCode = true + WorkingDirectory = project.Folder!.Path, + EnvironmentVariables = new Dictionary + { + ["DISABLE_GITHUB_REPORTER"] = "true", + } } - }, cancellationToken); + )); } } diff --git a/tools/TUnit.Pipeline/Modules/RunAssertionsCodeFixersTestsModule.cs b/tools/TUnit.Pipeline/Modules/RunAssertionsCodeFixersTestsModule.cs index 55076284676..059d3b5ddc2 100644 --- a/tools/TUnit.Pipeline/Modules/RunAssertionsCodeFixersTestsModule.cs +++ b/tools/TUnit.Pipeline/Modules/RunAssertionsCodeFixersTestsModule.cs @@ -1,41 +1,34 @@ -using ModularPipelines.Attributes; -using ModularPipelines.Context; -using ModularPipelines.DotNet.Extensions; +using ModularPipelines.Context; using ModularPipelines.DotNet.Options; using ModularPipelines.Extensions; using ModularPipelines.Git.Extensions; -using ModularPipelines.Models; -using ModularPipelines.Modules; using ModularPipelines.Options; +using TUnit.Pipeline.Modules.Abstract; namespace TUnit.Pipeline.Modules; -public class RunAssertionsCodeFixersTestsModule : Module +public class RunAssertionsCodeFixersTestsModule : TestBaseModule { - protected override async Task ExecuteAsync(IModuleContext context, CancellationToken cancellationToken) + protected override Task<(DotNetRunOptions Options, CommandExecutionOptions? ExecutionOptions)> GetTestOptions(IModuleContext context, string framework, CancellationToken cancellationToken) { var project = context.Git().RootDirectory.FindFile(x => x.Name == "TUnit.Assertions.Analyzers.CodeFixers.Tests.csproj").AssertExists(); - return await context.DotNet().Test(new DotNetTestOptions - { - NoBuild = true, - Configuration = "Release", - Framework = "net8.0", - Arguments = ["--", "--hangdump", "--hangdump-filename", "hangdump.assertions-codefixers-tests.dmp", "--hangdump-timeout", "5m"], - }, new CommandExecutionOptions - { - WorkingDirectory = project.Folder!.Path, - EnvironmentVariables = new Dictionary + return Task.FromResult<(DotNetRunOptions, CommandExecutionOptions?)>(( + new DotNetRunOptions { - ["DISABLE_GITHUB_REPORTER"] = "true", + NoBuild = true, + Configuration = "Release", + Framework = framework, + Arguments = ["--hangdump", "--hangdump-filename", $"hangdump.assertions-codefixers-tests-{framework}.dmp", "--hangdump-timeout", "5m"], }, - LogSettings = new CommandLoggingOptions + new CommandExecutionOptions { - ShowCommandArguments = true, - ShowStandardError = true, - ShowExecutionTime = true, - ShowExitCode = true + WorkingDirectory = project.Folder!.Path, + EnvironmentVariables = new Dictionary + { + ["DISABLE_GITHUB_REPORTER"] = "true", + } } - }, cancellationToken); + )); } } diff --git a/tools/TUnit.Pipeline/Modules/RunAssertionsShouldSourceGeneratorTestsModule.cs b/tools/TUnit.Pipeline/Modules/RunAssertionsShouldSourceGeneratorTestsModule.cs index 4c9b785947f..1c133054a0c 100644 --- a/tools/TUnit.Pipeline/Modules/RunAssertionsShouldSourceGeneratorTestsModule.cs +++ b/tools/TUnit.Pipeline/Modules/RunAssertionsShouldSourceGeneratorTestsModule.cs @@ -15,15 +15,7 @@ public class RunAssertionsShouldSourceGeneratorTestsModule : TestBaseModule // in TUnit.Assertions.Should.SourceGenerator.Tests.csproj. net472 is // intentionally omitted there: the generator output is consumer-TFM-independent and the // .NET Framework BCL trips the in-memory compilation harness for user-declared generics. - protected override IEnumerable TestableFrameworks - { - get - { - yield return "net10.0"; - yield return "net9.0"; - yield return "net8.0"; - } - } + protected override IEnumerable TestableFrameworks => ModernFrameworks; protected override Task<(DotNetRunOptions Options, CommandExecutionOptions? ExecutionOptions)> GetTestOptions(IModuleContext context, string framework, CancellationToken cancellationToken) { diff --git a/tools/TUnit.Pipeline/Modules/RunAssertionsSourceGeneratorTestsModule.cs b/tools/TUnit.Pipeline/Modules/RunAssertionsSourceGeneratorTestsModule.cs new file mode 100644 index 00000000000..a32ce1a0c42 --- /dev/null +++ b/tools/TUnit.Pipeline/Modules/RunAssertionsSourceGeneratorTestsModule.cs @@ -0,0 +1,39 @@ +using ModularPipelines.Attributes; +using ModularPipelines.Context; +using ModularPipelines.DotNet.Options; +using ModularPipelines.Extensions; +using ModularPipelines.Git.Extensions; +using ModularPipelines.Options; +using TUnit.Pipeline.Modules.Abstract; + +namespace TUnit.Pipeline.Modules; + +[NotInParallel("SnapshotTests")] +public class RunAssertionsSourceGeneratorTestsModule : TestBaseModule +{ + // Generator output snapshots verify behaviour across consumer TFMs — keep aligned with + // in TUnit.Assertions.SourceGenerator.Tests.csproj. + protected override IEnumerable TestableFrameworks => ModernAndNetFrameworks; + + protected override Task<(DotNetRunOptions Options, CommandExecutionOptions? ExecutionOptions)> GetTestOptions(IModuleContext context, string framework, CancellationToken cancellationToken) + { + var project = context.Git().RootDirectory.FindFile(x => x.Name == "TUnit.Assertions.SourceGenerator.Tests.csproj").AssertExists(); + + return Task.FromResult<(DotNetRunOptions, CommandExecutionOptions?)>(( + new DotNetRunOptions + { + NoBuild = true, + Configuration = "Release", + Framework = framework, + }, + new CommandExecutionOptions + { + WorkingDirectory = project.Folder!.Path, + EnvironmentVariables = new Dictionary + { + ["DISABLE_GITHUB_REPORTER"] = "true", + } + } + )); + } +} diff --git a/tools/TUnit.Pipeline/Modules/RunInternalAnalyzersTestsModule.cs b/tools/TUnit.Pipeline/Modules/RunInternalAnalyzersTestsModule.cs index 5d9014a0944..8dc99b5f58b 100644 --- a/tools/TUnit.Pipeline/Modules/RunInternalAnalyzersTestsModule.cs +++ b/tools/TUnit.Pipeline/Modules/RunInternalAnalyzersTestsModule.cs @@ -1,41 +1,34 @@ -using ModularPipelines.Attributes; -using ModularPipelines.Context; -using ModularPipelines.DotNet.Extensions; +using ModularPipelines.Context; using ModularPipelines.DotNet.Options; using ModularPipelines.Extensions; using ModularPipelines.Git.Extensions; -using ModularPipelines.Models; -using ModularPipelines.Modules; using ModularPipelines.Options; +using TUnit.Pipeline.Modules.Abstract; namespace TUnit.Pipeline.Modules; -public class RunInternalAnalyzersTestsModule : Module +public class RunInternalAnalyzersTestsModule : TestBaseModule { - protected override async Task ExecuteAsync(IModuleContext context, CancellationToken cancellationToken) + protected override Task<(DotNetRunOptions Options, CommandExecutionOptions? ExecutionOptions)> GetTestOptions(IModuleContext context, string framework, CancellationToken cancellationToken) { var project = context.Git().RootDirectory.FindFile(x => x.Name == "TUnit.Analyzers.Internal.Tests.csproj").AssertExists(); - return await context.DotNet().Test(new DotNetTestOptions - { - NoBuild = true, - Configuration = "Release", - Framework = "net8.0", - Arguments = ["--", "--hangdump", "--hangdump-filename", "hangdump.internal-analyzers-tests.dmp", "--hangdump-timeout", "5m"], - }, new CommandExecutionOptions - { - WorkingDirectory = project.Folder!.Path, - EnvironmentVariables = new Dictionary + return Task.FromResult<(DotNetRunOptions, CommandExecutionOptions?)>(( + new DotNetRunOptions { - ["DISABLE_GITHUB_REPORTER"] = "true", + NoBuild = true, + Configuration = "Release", + Framework = framework, + Arguments = ["--hangdump", "--hangdump-filename", $"hangdump.internal-analyzers-tests-{framework}.dmp", "--hangdump-timeout", "5m"], }, - LogSettings = new CommandLoggingOptions + new CommandExecutionOptions { - ShowCommandArguments = true, - ShowStandardError = true, - ShowExecutionTime = true, - ShowExitCode = true + WorkingDirectory = project.Folder!.Path, + EnvironmentVariables = new Dictionary + { + ["DISABLE_GITHUB_REPORTER"] = "true", + } } - }, cancellationToken); + )); } } diff --git a/tools/TUnit.Pipeline/Modules/RunMockHttpTestsModule.cs b/tools/TUnit.Pipeline/Modules/RunMockHttpTestsModule.cs index d8798b6c173..ae0bd8f8792 100644 --- a/tools/TUnit.Pipeline/Modules/RunMockHttpTestsModule.cs +++ b/tools/TUnit.Pipeline/Modules/RunMockHttpTestsModule.cs @@ -9,15 +9,6 @@ namespace TUnit.Pipeline.Modules; public class RunMockHttpTestsModule : TestBaseModule { - protected override IEnumerable TestableFrameworks - { - get - { - yield return "net10.0"; - yield return "net8.0"; - } - } - protected override Task<(DotNetRunOptions Options, CommandExecutionOptions? ExecutionOptions)> GetTestOptions(IModuleContext context, string framework, CancellationToken cancellationToken) { var project = context.Git().RootDirectory.FindFile(x => x.Name == "TUnit.Mocks.Http.Tests.csproj").AssertExists(); diff --git a/tools/TUnit.Pipeline/Modules/RunMockLoggingTestsModule.cs b/tools/TUnit.Pipeline/Modules/RunMockLoggingTestsModule.cs index 022f9a5dad2..c7cd93cb544 100644 --- a/tools/TUnit.Pipeline/Modules/RunMockLoggingTestsModule.cs +++ b/tools/TUnit.Pipeline/Modules/RunMockLoggingTestsModule.cs @@ -9,15 +9,6 @@ namespace TUnit.Pipeline.Modules; public class RunMockLoggingTestsModule : TestBaseModule { - protected override IEnumerable TestableFrameworks - { - get - { - yield return "net10.0"; - yield return "net8.0"; - } - } - protected override Task<(DotNetRunOptions Options, CommandExecutionOptions? ExecutionOptions)> GetTestOptions(IModuleContext context, string framework, CancellationToken cancellationToken) { var project = context.Git().RootDirectory.FindFile(x => x.Name == "TUnit.Mocks.Logging.Tests.csproj").AssertExists(); diff --git a/tools/TUnit.Pipeline/Modules/RunPublicAPITestsModule.cs b/tools/TUnit.Pipeline/Modules/RunPublicAPITestsModule.cs index 6b33c7a6afd..be38fad3083 100644 --- a/tools/TUnit.Pipeline/Modules/RunPublicAPITestsModule.cs +++ b/tools/TUnit.Pipeline/Modules/RunPublicAPITestsModule.cs @@ -13,20 +13,7 @@ public class RunPublicAPITestsModule : TestBaseModule { // Public API snapshots cover every supported consumer TFM — keep aligned with // in TUnit.PublicAPI.csproj. - protected override IEnumerable TestableFrameworks - { - get - { - yield return "net10.0"; - yield return "net9.0"; - yield return "net8.0"; - - if (IsWindows) - { - yield return "net472"; - } - } - } + protected override IEnumerable TestableFrameworks => ModernAndNetFrameworks; protected override Task<(DotNetRunOptions Options, CommandExecutionOptions? ExecutionOptions)> GetTestOptions(IModuleContext context, string framework, CancellationToken cancellationToken) { diff --git a/tools/TUnit.Pipeline/Modules/RunSourceGeneratorIncrementalTestsModule.cs b/tools/TUnit.Pipeline/Modules/RunSourceGeneratorIncrementalTestsModule.cs new file mode 100644 index 00000000000..8be00ef76b1 --- /dev/null +++ b/tools/TUnit.Pipeline/Modules/RunSourceGeneratorIncrementalTestsModule.cs @@ -0,0 +1,33 @@ +using ModularPipelines.Context; +using ModularPipelines.DotNet.Options; +using ModularPipelines.Extensions; +using ModularPipelines.Git.Extensions; +using ModularPipelines.Options; +using TUnit.Pipeline.Modules.Abstract; + +namespace TUnit.Pipeline.Modules; + +public class RunSourceGeneratorIncrementalTestsModule : TestBaseModule +{ + protected override Task<(DotNetRunOptions Options, CommandExecutionOptions? ExecutionOptions)> GetTestOptions(IModuleContext context, string framework, CancellationToken cancellationToken) + { + var project = context.Git().RootDirectory.FindFile(x => x.Name == "TUnit.SourceGenerator.IncrementalTests.csproj").AssertExists(); + + return Task.FromResult<(DotNetRunOptions, CommandExecutionOptions?)>(( + new DotNetRunOptions + { + NoBuild = true, + Configuration = "Release", + Framework = framework, + }, + new CommandExecutionOptions + { + WorkingDirectory = project.Folder!.Path, + EnvironmentVariables = new Dictionary + { + ["DISABLE_GITHUB_REPORTER"] = "true", + } + } + )); + } +} diff --git a/tools/TUnit.Pipeline/Modules/RunSourceGeneratorTestsModule.cs b/tools/TUnit.Pipeline/Modules/RunSourceGeneratorTestsModule.cs index 33d670bacf0..365d2ac2171 100644 --- a/tools/TUnit.Pipeline/Modules/RunSourceGeneratorTestsModule.cs +++ b/tools/TUnit.Pipeline/Modules/RunSourceGeneratorTestsModule.cs @@ -13,19 +13,7 @@ public class RunSourceGeneratorTestsModule : TestBaseModule { // Generator output snapshots verify behaviour across consumer TFMs — keep aligned with // in TUnit.Core.SourceGenerator.Tests.csproj. - protected override IEnumerable TestableFrameworks - { - get - { - yield return "net10.0"; - yield return "net8.0"; - - if (IsWindows) - { - yield return "net472"; - } - } - } + protected override IEnumerable TestableFrameworks => ModernAndNetFrameworks; protected override Task<(DotNetRunOptions Options, CommandExecutionOptions? ExecutionOptions)> GetTestOptions(IModuleContext context, string framework, CancellationToken cancellationToken) {