Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
[
// <auto-generated/>
#pragma warning disable
#nullable enable

using System;
using System.Runtime.CompilerServices;
using TUnit.Assertions.Core;
using TUnit.Assertions.Enums;
using TUnit.Assertions.Tests.TestData;

namespace TUnit.Assertions.Extensions;

/// <summary>
/// Generated extension methods for StringRespectsTokenAssertion.
/// </summary>
public static partial class StringRespectsTokenAssertionExtensions
{

/// <summary>
/// Extension method for StringRespectsTokenAssertion.
/// </summary>
public static StringRespectsTokenAssertion RespectsToken(this IAssertionSource<string> source, System.Threading.CancellationToken token = default, [CallerArgumentExpression(nameof(token))] string? tokenExpression = null)
{
source.Context.ExpressionBuilder.Append(".RespectsToken(");
source.Context.ExpressionBuilder.Append(tokenExpression);
source.Context.ExpressionBuilder.Append(")");
return new StringRespectsTokenAssertion(source.Context, token);
}
}

]
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
[
// <auto-generated/>
#pragma warning disable
#nullable enable

using System;
using System.Runtime.CompilerServices;
using TUnit.Assertions.Core;
using TUnit.Assertions.Enums;
using TUnit.Assertions.Tests.TestData;

namespace TUnit.Assertions.Extensions;

/// <summary>
/// Generated extension methods for StringRespectsTokenAssertion.
/// </summary>
public static partial class StringRespectsTokenAssertionExtensions
{

/// <summary>
/// Extension method for StringRespectsTokenAssertion.
/// </summary>
public static StringRespectsTokenAssertion RespectsToken(this IAssertionSource<string> source, System.Threading.CancellationToken token = default, [CallerArgumentExpression(nameof(token))] string? tokenExpression = null)
{
source.Context.ExpressionBuilder.Append(".RespectsToken(");
source.Context.ExpressionBuilder.Append(tokenExpression);
source.Context.ExpressionBuilder.Append(")");
return new StringRespectsTokenAssertion(source.Context, token);
}
}

]
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
[
// <auto-generated/>
#pragma warning disable
#nullable enable

using System;
using System.Runtime.CompilerServices;
using TUnit.Assertions.Core;
using TUnit.Assertions.Enums;
using TUnit.Assertions.Tests.TestData;

namespace TUnit.Assertions.Extensions;

/// <summary>
/// Generated extension methods for StringRespectsTokenAssertion.
/// </summary>
public static partial class StringRespectsTokenAssertionExtensions
{

/// <summary>
/// Extension method for StringRespectsTokenAssertion.
/// </summary>
public static StringRespectsTokenAssertion RespectsToken(this IAssertionSource<string> source, System.Threading.CancellationToken token = default, [CallerArgumentExpression(nameof(token))] string? tokenExpression = null)
{
source.Context.ExpressionBuilder.Append(".RespectsToken(");
source.Context.ExpressionBuilder.Append(tokenExpression);
source.Context.ExpressionBuilder.Append(")");
return new StringRespectsTokenAssertion(source.Context, token);
}
}

]
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
[
// <auto-generated/>
#pragma warning disable
#nullable enable

using System;
using System.Runtime.CompilerServices;
using TUnit.Assertions.Core;
using TUnit.Assertions.Enums;
using TUnit.Assertions.Tests.TestData;

namespace TUnit.Assertions.Extensions;

/// <summary>
/// Generated extension methods for StringRespectsTokenAssertion.
/// </summary>
public static partial class StringRespectsTokenAssertionExtensions
{

/// <summary>
/// Extension method for StringRespectsTokenAssertion.
/// </summary>
public static StringRespectsTokenAssertion RespectsToken(this IAssertionSource<string> source, System.Threading.CancellationToken token = default, [CallerArgumentExpression(nameof(token))] string? tokenExpression = null)
{
source.Context.ExpressionBuilder.Append(".RespectsToken(");
source.Context.ExpressionBuilder.Append(tokenExpression);
source.Context.ExpressionBuilder.Append(")");
return new StringRespectsTokenAssertion(source.Context, token);
}
}

]
Original file line number Diff line number Diff line change
Expand Up @@ -210,4 +210,27 @@ public Task AssertionWithMultipleParameters() => RunTest(
var callerExprCount = System.Text.RegularExpressions.Regex.Matches(extensionFile!, "CallerArgumentExpression").Count;
await Assert.That(callerExprCount).IsGreaterThanOrEqualTo(2);
});

[Test]
public Task ValueTypeDefaultParameter() => RunTest(
Path.Combine(Sourcy.Git.RootDirectory.FullName,
"TUnit.Assertions.SourceGenerator.Tests",
"TestData",
"AssertionExtensionValueTypeDefaultParameterAssertion.cs"),
async generatedFiles =>
{
await Assert.That(generatedFiles).Count().IsEqualTo(1);

var extensionFile = generatedFiles.First();
await Assert.That(extensionFile).IsNotNull();

// A non-nullable value-type constructor parameter declared with `= default` must
// render as the bare `default` literal, not `= null`. The literal `null` is invalid
// for a non-nullable value type and produces CS1750. The trailing comma anchors the
// assertion to bare `default`, ruling out the longer `default(TypeName)` form.
await Assert.That(extensionFile).Contains("CancellationToken token = default,");
await Assert.That(extensionFile).DoesNotContain("CancellationToken token = null");

await CompileChecker.AssertNoErrors(generatedFiles);
});
}
43 changes: 43 additions & 0 deletions TUnit.Assertions.SourceGenerator.Tests/CompileChecker.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
using Microsoft.CodeAnalysis;
using Microsoft.CodeAnalysis.CSharp;

namespace TUnit.Assertions.SourceGenerator.Tests;

/// <summary>
/// Parses generator output as C# and asserts there are no error-severity diagnostics.
/// Pins the entire class of source-generator emit bugs (mis-paired brackets, wrong
/// default-value rendering, invalid generic parameter lists) regardless of the specific
/// diagnostic id. Use alongside content-shape assertions when the test wants both a
/// targeted regression check and a structural compile-clean gate.
/// </summary>
internal static class CompileChecker
{
public static async Task AssertNoErrors(IEnumerable<string> generatedFiles)
{
var trees = generatedFiles
.Select(source => CSharpSyntaxTree.ParseText(source))
.ToArray();

var compilation = CSharpCompilation.Create(
"CompileCheck",
trees,
ReferencesHelper.References,
new CSharpCompilationOptions(OutputKind.DynamicallyLinkedLibrary));

// On the net472 leg of CI, the Polyfill assembly's CallerArgumentExpressionAttribute
// is declared internal, which produces a CS0122 ('inaccessible due to its protection
// level') false positive when Roslyn compiles the generator's output through the test
// project's reference set. Filter CS0122 only on net472; the emit shape is still
// pinned by the `.Net4_7` snapshot files. On modern TFMs the BCL attribute is public,
// so CS0122 (if it ever appears) would be a genuine signal and is not filtered.
var errors = compilation.GetDiagnostics()
.Where(d => d.Severity == DiagnosticSeverity.Error)
#if NETFRAMEWORK
.Where(d => !string.Equals(d.Id, "CS0122", System.StringComparison.Ordinal))
#endif
.Select(d => $"{d.Id}: {d.GetMessage()}")
.ToArray();

await Assert.That(errors).IsEmpty();
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,64 @@
[
// <auto-generated/>
#pragma warning disable
#nullable enable

using System;
using System.Runtime.CompilerServices;
using System.Threading.Tasks;
using TUnit.Assertions.Core;
using TUnit.Assertions.Tests.TestData;

namespace TUnit.Assertions.Extensions;

/// <summary>
/// Generated assertion for RespectsToken
/// </summary>
public sealed class Int_RespectsToken_CancellationToken_Assertion : Assertion<int>
{
private static readonly Task<AssertionResult> _passedTask = Task.FromResult(AssertionResult.Passed);

private readonly System.Threading.CancellationToken _token;

public Int_RespectsToken_CancellationToken_Assertion(AssertionContext<int> context, System.Threading.CancellationToken token)
: base(context)
{
_token = token;
}

protected override Task<AssertionResult> CheckAsync(EvaluationMetadata<int> metadata)
{
var value = metadata.Value;
var exception = metadata.Exception;

if (exception != null)
{
return Task.FromResult(AssertionResult.Failed($"threw {exception.GetType().FullName}"));
}

var result = value!.RespectsToken(_token);
return result
? _passedTask
: Task.FromResult(AssertionResult.Failed($"found {value}"));
}

protected override string GetExpectation()
{
return $"to satisfy RespectsToken({_token})";
}
}

public static partial class ValueTypeDefaultParameterAssertionExtensions
{
/// <summary>
/// Generated extension method for RespectsToken
/// </summary>
public static Int_RespectsToken_CancellationToken_Assertion RespectsToken(this IAssertionSource<int> source, System.Threading.CancellationToken token = default, [CallerArgumentExpression(nameof(token))] string? tokenExpression = null)
{
source.Context.ExpressionBuilder.Append($".RespectsToken({tokenExpression})");
return new Int_RespectsToken_CancellationToken_Assertion(source.Context, token);
}

}

]
Original file line number Diff line number Diff line change
@@ -0,0 +1,64 @@
[
// <auto-generated/>
#pragma warning disable
#nullable enable

using System;
using System.Runtime.CompilerServices;
using System.Threading.Tasks;
using TUnit.Assertions.Core;
using TUnit.Assertions.Tests.TestData;

namespace TUnit.Assertions.Extensions;

/// <summary>
/// Generated assertion for RespectsToken
/// </summary>
public sealed class Int_RespectsToken_CancellationToken_Assertion : Assertion<int>
{
private static readonly Task<AssertionResult> _passedTask = Task.FromResult(AssertionResult.Passed);

private readonly System.Threading.CancellationToken _token;

public Int_RespectsToken_CancellationToken_Assertion(AssertionContext<int> context, System.Threading.CancellationToken token)
: base(context)
{
_token = token;
}

protected override Task<AssertionResult> CheckAsync(EvaluationMetadata<int> metadata)
{
var value = metadata.Value;
var exception = metadata.Exception;

if (exception != null)
{
return Task.FromResult(AssertionResult.Failed($"threw {exception.GetType().FullName}"));
}

var result = value!.RespectsToken(_token);
return result
? _passedTask
: Task.FromResult(AssertionResult.Failed($"found {value}"));
}

protected override string GetExpectation()
{
return $"to satisfy RespectsToken({_token})";
}
}

public static partial class ValueTypeDefaultParameterAssertionExtensions
{
/// <summary>
/// Generated extension method for RespectsToken
/// </summary>
public static Int_RespectsToken_CancellationToken_Assertion RespectsToken(this IAssertionSource<int> source, System.Threading.CancellationToken token = default, [CallerArgumentExpression(nameof(token))] string? tokenExpression = null)
{
source.Context.ExpressionBuilder.Append($".RespectsToken({tokenExpression})");
return new Int_RespectsToken_CancellationToken_Assertion(source.Context, token);
}

}

]
Loading
Loading