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,47 @@
// <auto-generated />
#pragma warning disable
#nullable enable

using System;
using System.Runtime.CompilerServices;
using TUnit.Assertions.Core;
using TUnit.Assertions.Should.Core;

namespace TUnit.Assertions.Should.Extensions;

public static partial class ShouldExceptionExtensions
{

public static global::TUnit.Assertions.Should.Core.ShouldAssertion<TException> WithMessage<TException>(this global::TUnit.Assertions.Should.Core.IShouldSource<TException> source, string expectedMessage, [global::System.Runtime.CompilerServices.CallerArgumentExpression("expectedMessage")] string? expression = null)
where TException : System.Exception
{
var innerContext = source.Context;
innerContext.ExpressionBuilder.Append(".WithMessage(");
innerContext.ExpressionBuilder.Append(expression);
innerContext.ExpressionBuilder.Append(")");
var inner = new global::MyNamespace.ExceptionMessageEqualsAssertion<TException>(innerContext, expectedMessage);
var __tunit_should_because = source.ConsumeBecauseMessage();
if (__tunit_should_because is not null)
{
inner.Because(__tunit_should_because);
}
return new global::TUnit.Assertions.Should.Core.ShouldAssertion<TException>(innerContext, inner);
}

public static global::TUnit.Assertions.Should.Core.ShouldAssertion<TException> WithMessage<TException>(this global::TUnit.Assertions.Should.Core.IShouldSource<TException> source, string expectedMessage, System.StringComparison comparison, [global::System.Runtime.CompilerServices.CallerArgumentExpression("expectedMessage")] string? expression = null)
where TException : System.Exception
{
var innerContext = source.Context;
innerContext.ExpressionBuilder.Append(".WithMessage(");
innerContext.ExpressionBuilder.Append(expression);
innerContext.ExpressionBuilder.Append(")");
var inner = new global::MyNamespace.ExceptionMessageEqualsAssertion<TException>(innerContext, expectedMessage, comparison);
var __tunit_should_because = source.ConsumeBecauseMessage();
if (__tunit_should_because is not null)
{
inner.Because(__tunit_should_because);
}
return new global::TUnit.Assertions.Should.Core.ShouldAssertion<TException>(innerContext, inner);
}
}

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

using System;
using System.Runtime.CompilerServices;
using TUnit.Assertions.Core;
using TUnit.Assertions.Should.Core;

namespace TUnit.Assertions.Should.Extensions;

public static partial class ShouldExceptionExtensions
{

public static global::TUnit.Assertions.Should.Core.ShouldAssertion<TException> WithMessage<TException>(this global::TUnit.Assertions.Should.Core.IShouldSource<TException> source, string expectedMessage, [global::System.Runtime.CompilerServices.CallerArgumentExpression("expectedMessage")] string? expression = null)
where TException : System.Exception
{
var innerContext = source.Context;
innerContext.ExpressionBuilder.Append(".WithMessage(");
innerContext.ExpressionBuilder.Append(expression);
innerContext.ExpressionBuilder.Append(")");
var inner = new global::MyNamespace.ExceptionMessageEqualsAssertion<TException>(innerContext, expectedMessage);
var __tunit_should_because = source.ConsumeBecauseMessage();
if (__tunit_should_because is not null)
{
inner.Because(__tunit_should_because);
}
return new global::TUnit.Assertions.Should.Core.ShouldAssertion<TException>(innerContext, inner);
}

public static global::TUnit.Assertions.Should.Core.ShouldAssertion<TException> WithMessage<TException>(this global::TUnit.Assertions.Should.Core.IShouldSource<TException> source, string expectedMessage, System.StringComparison comparison, [global::System.Runtime.CompilerServices.CallerArgumentExpression("expectedMessage")] string? expression = null)
where TException : System.Exception
{
var innerContext = source.Context;
innerContext.ExpressionBuilder.Append(".WithMessage(");
innerContext.ExpressionBuilder.Append(expression);
innerContext.ExpressionBuilder.Append(")");
var inner = new global::MyNamespace.ExceptionMessageEqualsAssertion<TException>(innerContext, expectedMessage, comparison);
var __tunit_should_because = source.ConsumeBecauseMessage();
if (__tunit_should_because is not null)
{
inner.Because(__tunit_should_because);
}
return new global::TUnit.Assertions.Should.Core.ShouldAssertion<TException>(innerContext, inner);
}
}

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

using System;
using System.Runtime.CompilerServices;
using TUnit.Assertions.Core;
using TUnit.Assertions.Should.Core;

namespace TUnit.Assertions.Should.Extensions;

public static partial class ShouldExceptionExtensions
{

public static global::TUnit.Assertions.Should.Core.ShouldAssertion<TException> WithMessage<TException>(this global::TUnit.Assertions.Should.Core.IShouldSource<TException> source, string expectedMessage, [global::System.Runtime.CompilerServices.CallerArgumentExpression("expectedMessage")] string? expression = null)
where TException : System.Exception
{
var innerContext = source.Context;
innerContext.ExpressionBuilder.Append(".WithMessage(");
innerContext.ExpressionBuilder.Append(expression);
innerContext.ExpressionBuilder.Append(")");
var inner = new global::MyNamespace.ExceptionMessageEqualsAssertion<TException>(innerContext, expectedMessage);
var __tunit_should_because = source.ConsumeBecauseMessage();
if (__tunit_should_because is not null)
{
inner.Because(__tunit_should_because);
}
return new global::TUnit.Assertions.Should.Core.ShouldAssertion<TException>(innerContext, inner);
}

public static global::TUnit.Assertions.Should.Core.ShouldAssertion<TException> WithMessage<TException>(this global::TUnit.Assertions.Should.Core.IShouldSource<TException> source, string expectedMessage, System.StringComparison comparison, [global::System.Runtime.CompilerServices.CallerArgumentExpression("expectedMessage")] string? expression = null)
where TException : System.Exception
{
var innerContext = source.Context;
innerContext.ExpressionBuilder.Append(".WithMessage(");
innerContext.ExpressionBuilder.Append(expression);
innerContext.ExpressionBuilder.Append(")");
var inner = new global::MyNamespace.ExceptionMessageEqualsAssertion<TException>(innerContext, expectedMessage, comparison);
var __tunit_should_because = source.ConsumeBecauseMessage();
if (__tunit_should_because is not null)
{
inner.Because(__tunit_should_because);
}
return new global::TUnit.Assertions.Should.Core.ShouldAssertion<TException>(innerContext, inner);
}
}

Original file line number Diff line number Diff line change
Expand Up @@ -84,6 +84,53 @@ public static MyEqualsAssertion<TValue> IsEqualTo<TValue>(
await Assert.That(output).Contains("TValue expected");
}

[Test]
public async Task Overload_with_trailing_optional_constructor_parameter_is_emitted()
{
var output = await RunGenerator("""
using System;
using System.Runtime.CompilerServices;
using TUnit.Assertions.Core;

namespace MyNamespace;

public class ExceptionMessageEqualsAssertion<TException> : Assertion<TException>
where TException : Exception
{
public ExceptionMessageEqualsAssertion(
AssertionContext<TException> context,
string expectedMessage,
StringComparison comparison = StringComparison.Ordinal)
: base(context) { }
protected override Task<AssertionResult> CheckAsync(EvaluationMetadata<TException> metadata)
=> Task.FromResult(AssertionResult.Passed);
protected override string GetExpectation() => "to have message";
}

public static class ExceptionExtensions
{
public static ExceptionMessageEqualsAssertion<TException> WithMessage<TException>(
this IAssertionSource<TException> source,
string expectedMessage,
[CallerArgumentExpression(nameof(expectedMessage))] string? expression = null)
where TException : Exception
=> new(source.Context, expectedMessage);

public static ExceptionMessageEqualsAssertion<TException> WithMessage<TException>(
this IAssertionSource<TException> source,
string expectedMessage,
StringComparison comparison,
[CallerArgumentExpression(nameof(expectedMessage))] string? expression = null)
where TException : Exception
=> new(source.Context, expectedMessage, comparison);
}
""");

await Assert.That(output).Contains("WithMessage<TException>(this global::TUnit.Assertions.Should.Core.IShouldSource<TException> source, string expectedMessage, [global::System.Runtime.CompilerServices.CallerArgumentExpression(\"expectedMessage\")] string? expression = null)");
await Assert.That(output).Contains("WithMessage<TException>(this global::TUnit.Assertions.Should.Core.IShouldSource<TException> source, string expectedMessage, System.StringComparison comparison, [global::System.Runtime.CompilerServices.CallerArgumentExpression(\"expectedMessage\")] string? expression = null)");
await Assert.That(output).Contains("new global::MyNamespace.ExceptionMessageEqualsAssertion<TException>(innerContext, expectedMessage)");
}

[Test]
public async Task ShouldNameAttribute_overrides_conjugation()
{
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -830,11 +830,12 @@ private static bool HasMatchingConstructor(
INamedTypeSymbol assertionContextSymbol,
List<IParameterSymbol> ctorCandidates)
{
var minimumParameterCount = ctorCandidates.Count + 1;
foreach (var ctor in returnType.Constructors)
{
if (ctor.DeclaredAccessibility != Accessibility.Public
|| ctor.IsStatic
|| ctor.Parameters.Length != ctorCandidates.Count + 1)
|| ctor.Parameters.Length < minimumParameterCount)
{
continue;
}
Expand All @@ -857,11 +858,29 @@ private static bool HasMatchingConstructor(
break;
}
}

// Source overloads may intentionally omit simple constructor defaults, such as
// StringComparison or comparer parameters. Do not infer hidden boolean/string state:
// generated negation and expression parameters require body knowledge to forward.
for (var i = minimumParameterCount; allMatch && i < ctor.Parameters.Length; i++)
{
if (!CanOmitConstructorParameter(ctor.Parameters[i]))
{
allMatch = false;
}
}
if (allMatch) return true;
}
return false;
}

private static bool CanOmitConstructorParameter(IParameterSymbol parameter)
{
return parameter.HasExplicitDefaultValue
&& parameter.Type.SpecialType != SpecialType.System_Boolean
&& parameter.Type.SpecialType != SpecialType.System_String;
}

private static string? TryGetShouldNameOverride(INamedTypeSymbol returnType, INamedTypeSymbol? shouldNameAttr)
{
if (shouldNameAttr is null) return null;
Expand Down
9 changes: 9 additions & 0 deletions TUnit.Assertions.Should.Tests/DelegateTests.cs
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,15 @@ public async Task FuncTask_Throw()
await act.Should().Throw<InvalidOperationException>();
}

[Test]
public async Task Throw_WithMessage_without_StringComparison()
{
Action act = () => throw new InvalidOperationException("data is empty.");
await act.Should()
.Throw<InvalidOperationException>()
.WithMessage("data is empty.");
}

[Test]
public async Task FuncTaskT_NotThrow_returns_value()
{
Expand Down
Loading
Loading