diff --git a/TUnit.Assertions.Tests/SatisfiesTests.cs b/TUnit.Assertions.Tests/SatisfiesTests.cs index 07af2a659e..671c126638 100644 --- a/TUnit.Assertions.Tests/SatisfiesTests.cs +++ b/TUnit.Assertions.Tests/SatisfiesTests.cs @@ -49,7 +49,7 @@ public async Task Async_Satisfies_On_Direct_Property() }; await Assert.That(myModel) - .Satisfies(model => model.Value, assert => assert.IsEqualTo("Hello")!); + .SatisfiesAsync(async model => await model.Value!, assert => assert.IsEqualTo("Hello")!); } [Test] @@ -69,9 +69,9 @@ public async Task Async_Satisfies_On_Nested_Property() }; await Assert.That(myModel) - .Satisfies(model => model.Nested, assert => - assert.Satisfies(model => model?.Nested, innerAssert => - innerAssert.Satisfies(model => model?.Value, innerAssert2 => + .SatisfiesAsync(async model => await model.Nested!, assert => + assert.SatisfiesAsync(async model => await model?.Nested!, innerAssert => + innerAssert.SatisfiesAsync(async model => await model?.Value!, innerAssert2 => innerAssert2.IsEqualTo("Baz")! ) ) @@ -88,7 +88,7 @@ public async Task Satisfies_On_Direct_Property_Throws() await Assert.That(async () => await Assert.That(myModel) - .Satisfies(model => model.Value, assert => assert.IsEqualTo("Blah")!) + .Satisfies(model => model.Value!, assert => assert.IsEqualTo("Blah")!) ).Throws() .WithMessageMatching(""" *to satisfy* @@ -140,7 +140,7 @@ public async Task Async_Satisfies_On_Direct_Property_Throws() await Assert.That(async () => await Assert.That(myModel) - .Satisfies(model => model.Value, assert => assert.IsEqualTo("Blah")!) + .SatisfiesAsync(async model => await model.Value!, assert => assert.IsEqualTo("Blah")!) ).Throws() .WithMessageMatching(""" *to satisfy* @@ -166,9 +166,9 @@ public async Task Async_Satisfies_On_Nested_Property_Throws() await Assert.That(async () => await Assert.That(myModel) - .Satisfies(model => model.Nested, assert => - assert.Satisfies(model => model?.Nested, innerAssert => - innerAssert.Satisfies(model => model?.Value, innerAssert2 => + .SatisfiesAsync(async model => await model.Nested!, assert => + assert.SatisfiesAsync(async model => await model?.Nested!, innerAssert => + innerAssert.SatisfiesAsync(async model => await model?.Value!, innerAssert2 => innerAssert2.IsEqualTo("Baz")! ) ) diff --git a/TUnit.Assertions.Tests/TypeAssertionAmbiguityTests.cs b/TUnit.Assertions.Tests/TypeAssertionAmbiguityTests.cs new file mode 100644 index 0000000000..629695faea --- /dev/null +++ b/TUnit.Assertions.Tests/TypeAssertionAmbiguityTests.cs @@ -0,0 +1,464 @@ +namespace TUnit.Assertions.Tests; + +/// +/// Tests to ensure no ambiguous invocation errors for type assertion methods. +/// Regression tests for GitHub issue #3737. +/// +public class TypeAssertionAmbiguityTests +{ + // Test hierarchy for inheritance testing + private interface IElement { } + private class Element : IElement { } + private class DerivedElement : Element { } + + // ============ IsTypeOf TESTS ============ + + [Test] + public async Task IsTypeOf_SingleTypeParameter_NoAmbiguity() + { + object obj = "test"; + var result = await Assert.That(obj).IsTypeOf(); + await Assert.That(result).IsEqualTo("test"); + } + + [Test] + public async Task IsTypeOf_WithBaseType_NoAmbiguity() + { + IElement element = new Element(); + var result = await Assert.That(element).IsTypeOf(); + await Assert.That(result).IsNotNull(); + } + + [Test] + public async Task IsTypeOf_WithDerivedType_NoAmbiguity() + { + Element element = new DerivedElement(); + var result = await Assert.That(element).IsTypeOf(); + await Assert.That(result).IsNotNull(); + } + + // ============ IsNotTypeOf TESTS ============ + + [Test] + public async Task IsNotTypeOf_SingleTypeParameter_NoAmbiguity() + { + object obj = "test"; + await Assert.That(obj).IsNotTypeOf(); + } + + [Test] + public async Task IsNotTypeOf_WithBaseType_NoAmbiguity() + { + IElement element = new Element(); + await Assert.That(element).IsNotTypeOf(); + } + + [Test] + public async Task IsNotTypeOf_WithDerivedType_NoAmbiguity() + { + Element element = new Element(); + await Assert.That(element).IsNotTypeOf(); + } + + [Test] + public async Task IsNotTypeOf_Fails_WhenTypeMatches() + { + await Assert.That(async () => + { + object obj = "test"; + await Assert.That(obj).IsNotTypeOf(); + }).Throws(); + } + + // ============ IsAssignableTo TESTS ============ + + [Test] + public async Task IsAssignableTo_SingleTypeParameter_NoAmbiguity() + { + Element element = new Element(); + await Assert.That(element).IsAssignableTo(); + } + + [Test] + public async Task IsAssignableTo_DerivedToBase_NoAmbiguity() + { + DerivedElement derived = new DerivedElement(); + await Assert.That(derived).IsAssignableTo(); + } + + [Test] + public async Task IsAssignableTo_DerivedToInterface_NoAmbiguity() + { + DerivedElement derived = new DerivedElement(); + await Assert.That(derived).IsAssignableTo(); + } + + [Test] + public async Task IsAssignableTo_ObjectVariable_NoAmbiguity() + { + object obj = new Element(); + await Assert.That(obj).IsAssignableTo(); + } + + [Test] + public async Task IsAssignableTo_ExactType_NoAmbiguity() + { + Element element = new Element(); + await Assert.That(element).IsAssignableTo(); + } + + [Test] + public async Task IsAssignableTo_Fails_WhenNotAssignable() + { + await Assert.That(async () => + { + Element element = new Element(); + await Assert.That(element).IsAssignableTo(); + }).Throws(); + } + + // ============ IsNotAssignableTo TESTS ============ + + [Test] + public async Task IsNotAssignableTo_SingleTypeParameter_NoAmbiguity() + { + Element element = new Element(); + await Assert.That(element).IsNotAssignableTo(); + } + + [Test] + public async Task IsNotAssignableTo_UnrelatedTypes_NoAmbiguity() + { + Element element = new Element(); + await Assert.That(element).IsNotAssignableTo(); + } + + [Test] + public async Task IsNotAssignableTo_ObjectVariable_NoAmbiguity() + { + object obj = new Element(); + await Assert.That(obj).IsNotAssignableTo(); + } + + [Test] + public async Task IsNotAssignableTo_Fails_WhenAssignable() + { + await Assert.That(async () => + { + Element element = new Element(); + await Assert.That(element).IsNotAssignableTo(); + }).Throws(); + } + + // ============ ISSUE #3737 REGRESSION TESTS ============ + + [Test] + public async Task Issue3737_IsAssignableTo_WithInterface_NoAmbiguity() + { + Element element = new Element(); + await Assert.That(element).IsAssignableTo(); + } + + [Test] + public async Task Issue3737_IsAssignableTo_WithBaseClass_NoAmbiguity() + { + DerivedElement derived = new DerivedElement(); + await Assert.That(derived).IsAssignableTo(); + } + + [Test] + public async Task Issue3737_IsNotAssignableTo_WithUnrelatedType_NoAmbiguity() + { + Element element = new Element(); + await Assert.That(element).IsNotAssignableTo(); + } + + // ============ CHAINING TESTS ============ + + [Test] + public async Task IsTypeOf_Chained_NoAmbiguity() + { + object obj = "test"; + await Assert.That(obj) + .IsNotNull() + .And + .IsTypeOf() + .And + .HasLength(4); + } + + [Test] + public async Task IsNotTypeOf_Chained_NoAmbiguity() + { + object obj = "test"; + await Assert.That(obj) + .IsNotNull() + .And + .IsNotTypeOf() + .And + .IsTypeOf(); + } + + [Test] + public async Task IsAssignableTo_Chained_NoAmbiguity() + { + Element element = new Element(); + await Assert.That(element) + .IsNotNull() + .And + .IsAssignableTo() + .And + .IsAssignableTo(); + } + + [Test] + public async Task IsNotAssignableTo_Chained_NoAmbiguity() + { + Element element = new Element(); + await Assert.That(element) + .IsNotNull() + .And + .IsNotAssignableTo() + .And + .IsNotAssignableTo(); + } + + // ============ GENERIC TYPE TESTS ============ + + [Test] + public async Task IsTypeOf_GenericType_NoAmbiguity() + { + object obj = new List { "a", "b" }; + var result = await Assert.That(obj).IsTypeOf>(); + await Assert.That(result.Count).IsEqualTo(2); + } + + [Test] + public async Task IsNotTypeOf_GenericType_NoAmbiguity() + { + object obj = new List(); + await Assert.That(obj).IsNotTypeOf>(); + } + + [Test] + public async Task IsAssignableTo_GenericInterface_NoAmbiguity() + { + List list = new List(); + await Assert.That(list).IsAssignableTo>(); + } + + [Test] + public async Task IsNotAssignableTo_WrongGenericType_NoAmbiguity() + { + List list = new List(); + await Assert.That(list).IsNotAssignableTo>(); + } + + // ============ VALUE TYPE TESTS ============ + + [Test] + public async Task IsTypeOf_ValueType_NoAmbiguity() + { + object boxed = 42; + var result = await Assert.That(boxed).IsTypeOf(); + await Assert.That(result).IsEqualTo(42); + } + + [Test] + public async Task IsNotTypeOf_ValueType_NoAmbiguity() + { + object boxed = 42; + await Assert.That(boxed).IsNotTypeOf(); + } + + [Test] + public async Task IsAssignableTo_ValueType_NoAmbiguity() + { + object boxed = 42; + await Assert.That(boxed).IsAssignableTo(); + } + + [Test] + public async Task IsNotAssignableTo_ValueType_NoAmbiguity() + { + object boxed = 42; + await Assert.That(boxed).IsNotAssignableTo(); + } + + // ============ ALL FOUR METHODS TOGETHER ============ + + [Test] + public async Task AllFourMethods_Combined_NoAmbiguity() + { + object obj1 = new Element(); + await Assert.That(obj1).IsTypeOf(); + + object obj2 = "test"; + await Assert.That(obj2).IsNotTypeOf(); + + Element element = new Element(); + await Assert.That(element).IsAssignableTo(); + + Element element2 = new Element(); + await Assert.That(element2).IsNotAssignableTo(); + } + + [Test] + public async Task AllFourMethods_InSingleChain_NoAmbiguity() + { + object obj = new Element(); + + await Assert.That(obj) + .IsNotNull() + .And + .IsNotTypeOf() + .And + .IsTypeOf() + .And + .IsAssignableTo() + .And + .IsNotAssignableTo(); + } + + // ============ LAMBDA ASSERTION CONTEXTS (.Member) ============ + + private class Container + { + public object? Value { get; init; } + public IElement? ElementProperty { get; init; } + } + + [Test] + public async Task IsTypeOf_InMemberLambda_NoAmbiguity() + { + var container = new Container { Value = "test" }; + + await Assert.That(container) + .Member(c => c.Value, assert => assert.IsTypeOf()); + } + + [Test] + public async Task IsNotTypeOf_InMemberLambda_NoAmbiguity() + { + var container = new Container { Value = "test" }; + + await Assert.That(container) + .Member(c => c.Value, assert => assert.IsNotTypeOf()); + } + + [Test] + public async Task IsAssignableTo_InMemberLambda_NoAmbiguity() + { + var container = new Container { ElementProperty = new Element() }; + + await Assert.That(container) + .Member(c => c.ElementProperty, assert => assert.IsAssignableTo()); + } + + [Test] + public async Task IsNotAssignableTo_InMemberLambda_NoAmbiguity() + { + var container = new Container { ElementProperty = new Element() }; + + await Assert.That(container) + .Member(c => c.ElementProperty, assert => assert.IsNotAssignableTo()); + } + + [Test] + public async Task AllFourMethods_InMemberLambdas_NoAmbiguity() + { + var container = new Container { Value = new Element() }; + + await Assert.That(container) + .Member(c => c.Value, assert => assert.IsNotTypeOf()) + .And + .Member(c => c.Value, assert => assert.IsTypeOf()) + .And + .Member(c => c.Value, assert => assert.IsAssignableTo()) + .And + .Member(c => c.Value, assert => assert.IsNotAssignableTo()); + } + + [Test] + public async Task IsTypeOf_WithMemberChaining_NoAmbiguity() + { + var container = new Container { Value = "test" }; + + await Assert.That(container) + .Member(c => c.Value, assert => assert.IsNotNull()) + .And + .Member(c => c.Value, assert => assert.IsTypeOf()); + } + + [Test] + public async Task IsAssignableTo_WithMemberChaining_NoAmbiguity() + { + var container = new Container { ElementProperty = new Element() }; + + await Assert.That(container) + .Member(c => c.ElementProperty, assert => assert.IsNotNull()) + .And + .Member(c => c.ElementProperty, assert => assert.IsAssignableTo()) + .And + .Member(c => c.ElementProperty, assert => assert.IsNotAssignableTo()); + } + + // ============ COLLECTION ASSERTION CONTEXTS ============ + + [Test] + public async Task IsTypeOf_WithCollectionItems_NoAmbiguity() + { + List items = ["test", "hello", "world"]; + + foreach (var item in items) + { + await Assert.That(item).IsTypeOf(); + } + } + + [Test] + public async Task IsAssignableTo_WithCollectionItems_NoAmbiguity() + { + List items = [new Element(), new DerivedElement()]; + + foreach (var item in items) + { + await Assert.That(item).IsAssignableTo(); + } + } + + [Test] + public async Task IsTypeOf_WithFirstItem_NoAmbiguity() + { + List items = ["test", "hello"]; + + await Assert.That(items.First()).IsTypeOf(); + } + + [Test] + public async Task IsAssignableTo_WithSingleItem_NoAmbiguity() + { + List items = [new Element()]; + + await Assert.That(items.Single()).IsAssignableTo(); + } + + [Test] + public async Task IsTypeOf_WithCollectionChaining_NoAmbiguity() + { + List items = ["test", "hello"]; + + await Assert.That(items).HasCount(2); + await Assert.That(items.First()).IsTypeOf(); + } + + [Test] + public async Task IsAssignableTo_WithCollectionFiltering_NoAmbiguity() + { + List items = [new Element(), new DerivedElement()]; + var derived = items.OfType().ToList(); + + await Assert.That(derived).HasCount(1); + await Assert.That(derived.First()).IsAssignableTo(); + } +} diff --git a/TUnit.Assertions/Assertions/PropertyAssertion.cs b/TUnit.Assertions/Assertions/PropertyAssertion.cs index 8112b3db53..5b167cf11e 100644 --- a/TUnit.Assertions/Assertions/PropertyAssertion.cs +++ b/TUnit.Assertions/Assertions/PropertyAssertion.cs @@ -121,6 +121,28 @@ public TypeOfAssertion IsTypeOf() return new TypeOfAssertion(Context); } + public IsAssignableToAssertion IsAssignableTo() + { + Context.ExpressionBuilder.Append($".IsAssignableTo<{typeof(TTarget).Name}>()"); + return new IsAssignableToAssertion(Context); + } + + public IsNotAssignableToAssertion IsNotAssignableTo() + { + Context.ExpressionBuilder.Append($".IsNotAssignableTo<{typeof(TTarget).Name}>()"); + return new IsNotAssignableToAssertion(Context); + } + + /// + /// Asserts that the parent object is NOT of the specified type. + /// Example: await Assert.That(obj).HasProperty(x => x.Name).IsEqualTo("test").IsNotTypeOf(); + /// + public IsNotTypeOfAssertion IsNotTypeOf() + { + Context.ExpressionBuilder.Append($".IsNotTypeOf<{typeof(TExpected).Name}>()"); + return new IsNotTypeOfAssertion(Context); + } + /// /// Enables await syntax by executing the property assertion and returning the parent object. /// diff --git a/TUnit.Assertions/Assertions/Strings/ParseAssertions.cs b/TUnit.Assertions/Assertions/Strings/ParseAssertions.cs index 231f4091c9..944333a3f2 100644 --- a/TUnit.Assertions/Assertions/Strings/ParseAssertions.cs +++ b/TUnit.Assertions/Assertions/Strings/ParseAssertions.cs @@ -253,6 +253,28 @@ public TypeOfAssertion IsTypeOf() return new TypeOfAssertion(Context); } + public IsAssignableToAssertion IsAssignableTo() + { + Context.ExpressionBuilder.Append($".IsAssignableTo<{typeof(TTarget).Name}>()"); + return new IsAssignableToAssertion(Context); + } + + public IsNotAssignableToAssertion IsNotAssignableTo() + { + Context.ExpressionBuilder.Append($".IsNotAssignableTo<{typeof(TTarget).Name}>()"); + return new IsNotAssignableToAssertion(Context); + } + + /// + /// Asserts that the parsed value is NOT of the specified type. + /// Example: await Assert.That("123").WhenParsedInto().IsNotTypeOf(); + /// + public IsNotTypeOfAssertion IsNotTypeOf() + { + Context.ExpressionBuilder.Append($".IsNotTypeOf<{typeof(TExpected).Name}>()"); + return new IsNotTypeOfAssertion(Context); + } + /// /// Specifies the format provider to use when parsing. /// Returns a new assertion with the format provider set. diff --git a/TUnit.Assertions/Conditions/MappedSatisfiesAssertion.cs b/TUnit.Assertions/Conditions/MappedSatisfiesAssertion.cs index 518cb67ae6..fa8494c247 100644 --- a/TUnit.Assertions/Conditions/MappedSatisfiesAssertion.cs +++ b/TUnit.Assertions/Conditions/MappedSatisfiesAssertion.cs @@ -7,18 +7,20 @@ namespace TUnit.Assertions.Conditions; /// /// Asserts that a mapped value satisfies custom assertions. /// Maps the source value using a selector, then runs assertions on the mapped value. +/// This version supports both same-type and type-changing assertions (e.g., IsTypeOf). /// Example: await Assert.That(model).Satisfies(m => m.Name, assert => assert.IsEqualTo("John")); +/// Example: await Assert.That(model).Satisfies(m => m.Value, assert => assert.IsTypeOf()); /// public class MappedSatisfiesAssertion : Assertion { private readonly Func _selector; - private readonly Func, Assertion?> _assertions; + private readonly Func, IAssertion?> _assertions; private readonly string _selectorDescription; public MappedSatisfiesAssertion( AssertionContext context, Func selector, - Func, Assertion?> assertions, + Func, IAssertion?> assertions, string selectorDescription) : base(context) { @@ -73,19 +75,19 @@ protected override async Task CheckAsync(EvaluationMetadata /// Asserts that an async-mapped value satisfies custom assertions. /// Maps the source value using an async selector, then runs assertions on the mapped value. +/// This version supports both same-type and type-changing assertions (e.g., IsTypeOf). /// Example: await Assert.That(model).Satisfies(m => m.GetNameAsync(), assert => assert.IsEqualTo("John")); /// -public class AsyncMappedSatisfiesAssertion : Assertion - where TAssertion : Assertion +public class AsyncMappedSatisfiesAssertion : Assertion { private readonly Func> _selector; - private readonly Func, TAssertion> _assertions; + private readonly Func, IAssertion?> _assertions; private readonly string _selectorDescription; public AsyncMappedSatisfiesAssertion( AssertionContext context, Func> selector, - Func, TAssertion> assertions, + Func, IAssertion?> assertions, string selectorDescription) : base(context) { diff --git a/TUnit.Assertions/Conditions/MemberAssertion.cs b/TUnit.Assertions/Conditions/MemberAssertion.cs index 991c6147b5..a8315d6f09 100644 --- a/TUnit.Assertions/Conditions/MemberAssertion.cs +++ b/TUnit.Assertions/Conditions/MemberAssertion.cs @@ -7,8 +7,9 @@ namespace TUnit.Assertions.Conditions; /// /// Result of a member assertion that allows returning to the parent object context. /// Enables chaining multiple member assertions on the same parent object. +/// Implements IAssertion to allow use in Satisfies() lambdas that accept IAssertion. /// -public class MemberAssertionResult +public class MemberAssertionResult : IAssertion { private readonly AssertionContext _parentContext; private readonly Assertion _memberAssertion; @@ -19,6 +20,15 @@ internal MemberAssertionResult(AssertionContext parentContext, Assertio _memberAssertion = memberAssertion ?? throw new ArgumentNullException(nameof(memberAssertion)); } + /// + /// Implements IAssertion.AssertAsync to allow use in Satisfies() lambdas. + /// Executes the member assertion and returns a Task (not TObject). + /// + async Task IAssertion.AssertAsync() + { + await _memberAssertion.AssertAsync(); + } + /// /// Returns an And continuation that operates on the parent object's context, /// allowing chaining of multiple member assertions on the same parent object. @@ -146,6 +156,28 @@ public TypeOfAssertion IsTypeOf() Context.ExpressionBuilder.Append($".IsTypeOf<{typeof(TExpected).Name}>()"); return new TypeOfAssertion(Context); } + + public IsAssignableToAssertion IsAssignableTo() + { + Context.ExpressionBuilder.Append($".IsAssignableTo<{typeof(TTarget).Name}>()"); + return new IsAssignableToAssertion(Context); + } + + public IsNotAssignableToAssertion IsNotAssignableTo() + { + Context.ExpressionBuilder.Append($".IsNotAssignableTo<{typeof(TTarget).Name}>()"); + return new IsNotAssignableToAssertion(Context); + } + + /// + /// Asserts that the value is NOT of the specified type. + /// Example: await Assert.That(obj).Member(x => x.Property).Satisfies(val => val.IsNotTypeOf()); + /// + public IsNotTypeOfAssertion IsNotTypeOf() + { + Context.ExpressionBuilder.Append($".IsNotTypeOf<{typeof(TExpected).Name}>()"); + return new IsNotTypeOfAssertion(Context); + } } /// diff --git a/TUnit.Assertions/Conditions/TypeOfAssertion.cs b/TUnit.Assertions/Conditions/TypeOfAssertion.cs index 323c4dec05..4121c14e25 100644 --- a/TUnit.Assertions/Conditions/TypeOfAssertion.cs +++ b/TUnit.Assertions/Conditions/TypeOfAssertion.cs @@ -48,11 +48,52 @@ protected override Task CheckAsync(EvaluationMetadata meta protected override string GetExpectation() => $"to be of type {_expectedType.Name}"; } +/// +/// Asserts that a value is NOT exactly of the specified type. +/// +public class IsNotTypeOfAssertion : Assertion +{ + private readonly Type _expectedType; + + public IsNotTypeOfAssertion( + AssertionContext context) + : base(context) + { + _expectedType = typeof(TExpected); + } + + protected override Task CheckAsync(EvaluationMetadata metadata) + { + var value = metadata.Value; + var exception = metadata.Exception; + + if (exception != null) + { + return Task.FromResult(AssertionResult.Failed($"threw {exception.GetType().Name}")); + } + + if (value == null) + { + return Task.FromResult(AssertionResult.Failed("value was null")); + } + + var actualType = value.GetType(); + + if (actualType != _expectedType) + { + return Task.FromResult(AssertionResult.Passed); + } + + return Task.FromResult(AssertionResult.Failed($"type was {actualType.Name}")); + } + + protected override string GetExpectation() => $"to not be of type {_expectedType.Name}"; +} + /// /// Asserts that a value's type is assignable to a specific type (is the type or a subtype). /// Works with both direct value assertions and exception assertions (via .And after Throws). /// -[AssertionExtension("IsAssignableTo")] public class IsAssignableToAssertion : Assertion { private readonly Type _targetType; @@ -103,7 +144,6 @@ protected override Task CheckAsync(EvaluationMetadata m /// Asserts that a value's type is NOT assignable to a specific type. /// Works with both direct value assertions and exception assertions (via .And after Throws). /// -[AssertionExtension("IsNotAssignableTo")] public class IsNotAssignableToAssertion : Assertion { private readonly Type _targetType; diff --git a/TUnit.Assertions/Conditions/Wrappers/CountWrapper.cs b/TUnit.Assertions/Conditions/Wrappers/CountWrapper.cs index 34095447a1..f2b2ea3364 100644 --- a/TUnit.Assertions/Conditions/Wrappers/CountWrapper.cs +++ b/TUnit.Assertions/Conditions/Wrappers/CountWrapper.cs @@ -33,6 +33,36 @@ TypeOfAssertion IAssertionSource.IsTypeOf>().HasCount().EqualTo(5)"); } + /// + /// Not supported on CountWrapper - use IsAssignableTo on the assertion source before calling HasCount(). + /// + IsAssignableToAssertion IAssertionSource.IsAssignableTo() + { + throw new NotSupportedException( + "IsAssignableTo is not supported after HasCount(). " + + "Use: Assert.That(value).IsAssignableTo>().HasCount().EqualTo(5)"); + } + + /// + /// Not supported on CountWrapper - use IsNotAssignableTo on the assertion source before calling HasCount(). + /// + IsNotAssignableToAssertion IAssertionSource.IsNotAssignableTo() + { + throw new NotSupportedException( + "IsNotAssignableTo is not supported after HasCount(). " + + "Use: Assert.That(value).IsNotAssignableTo>().HasCount().EqualTo(5)"); + } + + /// + /// Not supported on CountWrapper - use IsNotTypeOf on the assertion source before calling HasCount(). + /// + IsNotTypeOfAssertion IAssertionSource.IsNotTypeOf() + { + throw new NotSupportedException( + "IsNotTypeOf is not supported after HasCount(). " + + "Use: Assert.That(value).IsNotTypeOf>().HasCount().EqualTo(5)"); + } + /// /// Asserts that the collection count is equal to the expected count. /// diff --git a/TUnit.Assertions/Conditions/Wrappers/LengthWrapper.cs b/TUnit.Assertions/Conditions/Wrappers/LengthWrapper.cs index ec81506cf2..c1d027bfcf 100644 --- a/TUnit.Assertions/Conditions/Wrappers/LengthWrapper.cs +++ b/TUnit.Assertions/Conditions/Wrappers/LengthWrapper.cs @@ -30,6 +30,36 @@ TypeOfAssertion IAssertionSource.IsTypeOf( "Use: Assert.That(value).IsTypeOf().HasLength().EqualTo(5)"); } + /// + /// Not supported on LengthWrapper - use IsAssignableTo on the assertion source before calling HasLength(). + /// + IsAssignableToAssertion IAssertionSource.IsAssignableTo() + { + throw new NotSupportedException( + "IsAssignableTo is not supported after HasLength(). " + + "Use: Assert.That(value).IsAssignableTo().HasLength().EqualTo(5)"); + } + + /// + /// Not supported on LengthWrapper - use IsNotAssignableTo on the assertion source before calling HasLength(). + /// + IsNotAssignableToAssertion IAssertionSource.IsNotAssignableTo() + { + throw new NotSupportedException( + "IsNotAssignableTo is not supported after HasLength(). " + + "Use: Assert.That(value).IsNotAssignableTo().HasLength().EqualTo(5)"); + } + + /// + /// Not supported on LengthWrapper - use IsNotTypeOf on the assertion source before calling HasLength(). + /// + IsNotTypeOfAssertion IAssertionSource.IsNotTypeOf() + { + throw new NotSupportedException( + "IsNotTypeOf is not supported after HasLength(). " + + "Use: Assert.That(value).IsNotTypeOf().HasLength().EqualTo(5)"); + } + /// /// Asserts that the string length is equal to the expected length. /// diff --git a/TUnit.Assertions/Core/Assertion.cs b/TUnit.Assertions/Core/Assertion.cs index a79e213396..cda35ff933 100644 --- a/TUnit.Assertions/Core/Assertion.cs +++ b/TUnit.Assertions/Core/Assertion.cs @@ -15,7 +15,7 @@ namespace TUnit.Assertions.Core; /// OrContinuation) implement IAssertionSource. This design prevents direct chaining of assertions /// without And/Or keywords and prevents awaiting bare sources without an assertion. /// The type of value being asserted -public abstract class Assertion +public abstract class Assertion : IAssertion { /// /// The assertion context shared by all assertions in this chain. @@ -242,4 +242,11 @@ protected internal void AppendExpression(string expression) Context.ExpressionBuilder.Append(expression); } } + + /// + /// Explicitly implements the non-generic method. + /// This allows any assertion to be executed via the interface + /// without losing the strongly-typed return value from the public method. + /// + Task IAssertion.AssertAsync() => AssertAsync(); } diff --git a/TUnit.Assertions/Core/IAssertion.cs b/TUnit.Assertions/Core/IAssertion.cs new file mode 100644 index 0000000000..64ad0b8283 --- /dev/null +++ b/TUnit.Assertions/Core/IAssertion.cs @@ -0,0 +1,16 @@ +namespace TUnit.Assertions.Core; + +/// +/// Defines a non-generic contract for all assertions, allowing them to be +/// executed without knowledge of their underlying generic type. This is crucial +/// for scenarios like `.Satisfies()` where type-changing assertions can occur. +/// +public interface IAssertion +{ + /// + /// Executes the assertion logic and throws an exception if it fails. + /// This is the type-erased version of . + /// + /// A that completes when the assertion is executed. + Task AssertAsync(); +} diff --git a/TUnit.Assertions/Core/IAssertionSource.cs b/TUnit.Assertions/Core/IAssertionSource.cs index 54f884f75f..92a34e915a 100644 --- a/TUnit.Assertions/Core/IAssertionSource.cs +++ b/TUnit.Assertions/Core/IAssertionSource.cs @@ -24,10 +24,22 @@ public interface IAssertionSource : IAssertionSource AssertionContext Context { get; } /// - /// Asserts that the value is of the specified type and returns an assertion on the casted value. - /// This allows chaining additional assertions on the typed value. - /// Only available at assertion source points (initial Assert.That, or after .And/.Or). - /// Example: await Assert.That(obj).IsTypeOf<string>().And.HasLength(5); + /// Asserts that the value is assignment-compatible with the specified type. /// TypeOfAssertion IsTypeOf(); + + /// + /// Asserts that the value is NOT exactly of the specified type. + /// + IsNotTypeOfAssertion IsNotTypeOf(); + + /// + /// Asserts that the value's type is assignable to the specified type. + /// + IsAssignableToAssertion IsAssignableTo(); + + /// + /// Asserts that the value's type is NOT assignable to the specified type. + /// + IsNotAssignableToAssertion IsNotAssignableTo(); } diff --git a/TUnit.Assertions/Extensions/AssertionExtensions.cs b/TUnit.Assertions/Extensions/AssertionExtensions.cs index 1261b6fa33..8287c6ebdd 100644 --- a/TUnit.Assertions/Extensions/AssertionExtensions.cs +++ b/TUnit.Assertions/Extensions/AssertionExtensions.cs @@ -740,17 +740,17 @@ public static NotStructuralEquivalencyAssertion IsNotEquivalentTo /// Asserts that a mapped Task value satisfies custom assertions on the unwrapped result. /// Maps the source value using a selector that returns a Task, then runs assertions on the awaited result. - /// Example: await Assert.That(model).Satisfies(m => m.AsyncValue, assert => assert.IsEqualTo("Hello")); + /// Supports both same-type and type-changing assertions. + /// Example: await Assert.That(model).SatisfiesAsync(m => m.AsyncValue, assert => assert.IsEqualTo("Hello")); /// - public static AsyncMappedSatisfiesAssertion Satisfies( + public static AsyncMappedSatisfiesAssertion SatisfiesAsync( this IAssertionSource source, Func> selector, - Func, TAssertion> assertions, + Func, IAssertion?> assertions, [CallerArgumentExpression(nameof(selector))] string? selectorExpression = null) - where TAssertion : Assertion { - source.Context.ExpressionBuilder.Append($".Satisfies({selectorExpression}, ...)"); - return new AsyncMappedSatisfiesAssertion( + source.Context.ExpressionBuilder.Append($".SatisfiesAsync({selectorExpression}, ...)"); + return new AsyncMappedSatisfiesAssertion( source.Context, selector!, assertions, @@ -760,12 +760,13 @@ public static AsyncMappedSatisfiesAssertion Satisfi /// /// Asserts that a mapped value satisfies custom assertions. /// Maps the source value using a selector, then runs assertions on the mapped value. + /// Supports both same-type and type-changing assertions. /// Example: await Assert.That(model).Satisfies(m => m.Name, assert => assert.IsEqualTo("John")); /// public static MappedSatisfiesAssertion Satisfies( this IAssertionSource source, Func selector, - Func, Assertion?> assertions, + Func, IAssertion?> assertions, [CallerArgumentExpression(nameof(selector))] string? selectorExpression = null) { source.Context.ExpressionBuilder.Append($".Satisfies({selectorExpression}, ...)"); @@ -1532,33 +1533,4 @@ public static Assertions.Enums.DoesNotHaveSameValueAsAssertion DoesNotHav return new Assertions.Enums.DoesNotHaveSameValueAsAssertion(source.Context, otherEnumValue); } - /// - /// Asserts that a value's type is assignable to a specific type (specialized for object). - /// - public static IsAssignableToAssertion IsAssignableTo( - this IAssertionSource source) - { - source.Context.ExpressionBuilder.Append($".IsAssignableTo<{typeof(TTarget).Name}>()"); - return new IsAssignableToAssertion(source.Context); - } - - /// - /// Asserts that a value's type is assignable to a specific type. - /// - public static IsAssignableToAssertion IsAssignableTo( - this IAssertionSource source) - { - source.Context.ExpressionBuilder.Append($".IsAssignableTo<{typeof(TTarget).Name}>()"); - return new IsAssignableToAssertion(source.Context); - } - - /// - /// Asserts that a value's type is NOT assignable to a specific type. - /// - public static IsNotAssignableToAssertion IsNotAssignableTo( - this IAssertionSource source) - { - source.Context.ExpressionBuilder.Append($".IsNotAssignableTo<{typeof(TTarget).Name}>()"); - return new IsNotAssignableToAssertion(source.Context); - } } diff --git a/TUnit.Assertions/Sources/AsyncDelegateAssertion.cs b/TUnit.Assertions/Sources/AsyncDelegateAssertion.cs index 17b03c5b48..0d2ea6c352 100644 --- a/TUnit.Assertions/Sources/AsyncDelegateAssertion.cs +++ b/TUnit.Assertions/Sources/AsyncDelegateAssertion.cs @@ -141,6 +141,58 @@ TypeOfAssertion IAssertionSource.IsTypeOf() return new TypeOfAssertion(TaskContext); } + public IsAssignableToAssertion IsAssignableTo() + { + Context.ExpressionBuilder.Append($".IsAssignableTo<{typeof(TTarget).Name}>()"); + return new IsAssignableToAssertion(Context); + } + + public IsNotAssignableToAssertion IsNotAssignableTo() + { + Context.ExpressionBuilder.Append($".IsNotAssignableTo<{typeof(TTarget).Name}>()"); + return new IsNotAssignableToAssertion(Context); + } + + /// + /// Explicit interface implementation for Task assignability checking. + /// Asserts that the task itself is assignable to the specified type. + /// + IsAssignableToAssertion IAssertionSource.IsAssignableTo() + { + TaskContext.ExpressionBuilder.Append($".IsAssignableTo<{typeof(TTarget).Name}>()"); + return new IsAssignableToAssertion(TaskContext); + } + + /// + /// Explicit interface implementation for Task assignability checking. + /// Asserts that the task itself is not assignable to the specified type. + /// + IsNotAssignableToAssertion IAssertionSource.IsNotAssignableTo() + { + TaskContext.ExpressionBuilder.Append($".IsNotAssignableTo<{typeof(TTarget).Name}>()"); + return new IsNotAssignableToAssertion(TaskContext); + } + + /// + /// Asserts that the value is NOT of the specified type. + /// Example: await Assert.That(async () => await SomeMethodAsync()).IsNotTypeOf(); + /// + public IsNotTypeOfAssertion IsNotTypeOf() + { + Context.ExpressionBuilder.Append($".IsNotTypeOf<{typeof(TExpected).Name}>()"); + return new IsNotTypeOfAssertion(Context); + } + + /// + /// Explicit interface implementation for Task type checking. + /// Asserts that the task itself is NOT of the specified type. + /// + IsNotTypeOfAssertion IAssertionSource.IsNotTypeOf() + { + TaskContext.ExpressionBuilder.Append($".IsNotTypeOf<{typeof(TExpected).Name}>()"); + return new IsNotTypeOfAssertion(TaskContext); + } + /// /// Asserts that the async delegate throws the specified exception type (or subclass). /// Instance method to avoid C# type inference issues with extension methods. diff --git a/TUnit.Assertions/Sources/AsyncFuncAssertion.cs b/TUnit.Assertions/Sources/AsyncFuncAssertion.cs index 45587fe631..0c4484b04f 100644 --- a/TUnit.Assertions/Sources/AsyncFuncAssertion.cs +++ b/TUnit.Assertions/Sources/AsyncFuncAssertion.cs @@ -43,6 +43,28 @@ public TypeOfAssertion IsTypeOf() return new TypeOfAssertion(Context); } + public IsAssignableToAssertion IsAssignableTo() + { + Context.ExpressionBuilder.Append($".IsAssignableTo<{typeof(TTarget).Name}>()"); + return new IsAssignableToAssertion(Context); + } + + public IsNotAssignableToAssertion IsNotAssignableTo() + { + Context.ExpressionBuilder.Append($".IsNotAssignableTo<{typeof(TTarget).Name}>()"); + return new IsNotAssignableToAssertion(Context); + } + + /// + /// Asserts that the async function result is NOT of the specified type. + /// Example: await Assert.That(async () => await GetValueAsync()).IsNotTypeOf(); + /// + public IsNotTypeOfAssertion IsNotTypeOf() + { + Context.ExpressionBuilder.Append($".IsNotTypeOf<{typeof(TExpected).Name}>()"); + return new IsNotTypeOfAssertion(Context); + } + /// /// Asserts that the async function throws the specified exception type (or subclass). /// Instance method to avoid C# type inference issues with extension methods. diff --git a/TUnit.Assertions/Sources/CollectionAssertionBase.cs b/TUnit.Assertions/Sources/CollectionAssertionBase.cs index 6677f8af26..233e954ca4 100644 --- a/TUnit.Assertions/Sources/CollectionAssertionBase.cs +++ b/TUnit.Assertions/Sources/CollectionAssertionBase.cs @@ -55,6 +55,29 @@ public TypeOfAssertion IsTypeOf() return new TypeOfAssertion(Context); } + public IsAssignableToAssertion IsAssignableTo() + { + Context.ExpressionBuilder.Append($".IsAssignableTo<{typeof(TTarget).Name}>()"); + return new IsAssignableToAssertion(Context); + } + + public IsNotAssignableToAssertion IsNotAssignableTo() + { + Context.ExpressionBuilder.Append($".IsNotAssignableTo<{typeof(TTarget).Name}>()"); + return new IsNotAssignableToAssertion(Context); + } + + /// + /// Asserts that the collection is NOT of the specified type. + /// This allows chaining additional assertions on the value. + /// Example: await Assert.That((IEnumerable)list).IsNotTypeOf>().And.HasCount(5); + /// + public IsNotTypeOfAssertion IsNotTypeOf() + { + Context.ExpressionBuilder.Append($".IsNotTypeOf<{typeof(TExpected).Name}>()"); + return new IsNotTypeOfAssertion(Context); + } + /// /// Asserts that the collection contains the expected item. /// This instance method enables calling Contains with proper type inference. diff --git a/TUnit.Assertions/Sources/DelegateAssertion.cs b/TUnit.Assertions/Sources/DelegateAssertion.cs index 24ca377acd..142aa6e0ee 100644 --- a/TUnit.Assertions/Sources/DelegateAssertion.cs +++ b/TUnit.Assertions/Sources/DelegateAssertion.cs @@ -46,6 +46,28 @@ public DelegateAssertion(Action action, string? expression) return new TypeOfAssertion(Context); } + public IsAssignableToAssertion IsAssignableTo() + { + Context.ExpressionBuilder.Append($".IsAssignableTo<{typeof(TTarget).Name}>()"); + return new IsAssignableToAssertion(Context); + } + + public IsNotAssignableToAssertion IsNotAssignableTo() + { + Context.ExpressionBuilder.Append($".IsNotAssignableTo<{typeof(TTarget).Name}>()"); + return new IsNotAssignableToAssertion(Context); + } + + /// + /// Asserts that the value is NOT of the specified type. + /// Example: await Assert.That(() => SomeMethod()).IsNotTypeOf(); + /// + public IsNotTypeOfAssertion IsNotTypeOf() + { + Context.ExpressionBuilder.Append($".IsNotTypeOf<{typeof(TExpected).Name}>()"); + return new IsNotTypeOfAssertion(Context); + } + /// /// Asserts that the delegate throws the specified exception type (or subclass). /// Instance method to avoid C# type inference issues with extension methods. diff --git a/TUnit.Assertions/Sources/FuncAssertion.cs b/TUnit.Assertions/Sources/FuncAssertion.cs index f1b09882cd..bcdf9a4450 100644 --- a/TUnit.Assertions/Sources/FuncAssertion.cs +++ b/TUnit.Assertions/Sources/FuncAssertion.cs @@ -43,6 +43,28 @@ public TypeOfAssertion IsTypeOf() return new TypeOfAssertion(Context); } + public IsAssignableToAssertion IsAssignableTo() + { + Context.ExpressionBuilder.Append($".IsAssignableTo<{typeof(TTarget).Name}>()"); + return new IsAssignableToAssertion(Context); + } + + public IsNotAssignableToAssertion IsNotAssignableTo() + { + Context.ExpressionBuilder.Append($".IsNotAssignableTo<{typeof(TTarget).Name}>()"); + return new IsNotAssignableToAssertion(Context); + } + + /// + /// Asserts that the value is NOT of the specified type. + /// Example: await Assert.That(() => GetValue()).IsNotTypeOf(); + /// + public IsNotTypeOfAssertion IsNotTypeOf() + { + Context.ExpressionBuilder.Append($".IsNotTypeOf<{typeof(TExpected).Name}>()"); + return new IsNotTypeOfAssertion(Context); + } + /// /// Asserts that the function throws the specified exception type (or subclass). /// Instance method to avoid C# type inference issues with extension methods. diff --git a/TUnit.Assertions/Sources/TaskAssertion.cs b/TUnit.Assertions/Sources/TaskAssertion.cs index c501194211..bfc7504263 100644 --- a/TUnit.Assertions/Sources/TaskAssertion.cs +++ b/TUnit.Assertions/Sources/TaskAssertion.cs @@ -73,6 +73,58 @@ public TypeOfAssertion IsTypeOf() return new TypeOfAssertion, TExpected>(TaskContext); } + public IsAssignableToAssertion IsAssignableTo() + { + Context.ExpressionBuilder.Append($".IsAssignableTo<{typeof(TTarget).Name}>()"); + return new IsAssignableToAssertion(Context); + } + + public IsNotAssignableToAssertion IsNotAssignableTo() + { + Context.ExpressionBuilder.Append($".IsNotAssignableTo<{typeof(TTarget).Name}>()"); + return new IsNotAssignableToAssertion(Context); + } + + /// + /// Explicit interface implementation for Task<TValue?> assignability checking. + /// Asserts that the task itself is assignable to the specified type. + /// + IsAssignableToAssertion> IAssertionSource>.IsAssignableTo() + { + TaskContext.ExpressionBuilder.Append($".IsAssignableTo<{typeof(TTarget).Name}>()"); + return new IsAssignableToAssertion>(TaskContext); + } + + /// + /// Explicit interface implementation for Task<TValue?> assignability checking. + /// Asserts that the task itself is not assignable to the specified type. + /// + IsNotAssignableToAssertion> IAssertionSource>.IsNotAssignableTo() + { + TaskContext.ExpressionBuilder.Append($".IsNotAssignableTo<{typeof(TTarget).Name}>()"); + return new IsNotAssignableToAssertion>(TaskContext); + } + + /// + /// Asserts that the task result is NOT of the specified type. + /// Example: await Assert.That(GetValueAsync()).IsNotTypeOf(); + /// + public IsNotTypeOfAssertion IsNotTypeOf() + { + Context.ExpressionBuilder.Append($".IsNotTypeOf<{typeof(TExpected).Name}>()"); + return new IsNotTypeOfAssertion(Context); + } + + /// + /// Explicit interface implementation for Task<TValue?> type checking. + /// Asserts that the task itself is NOT of the specified type. + /// + IsNotTypeOfAssertion, TExpected> IAssertionSource>.IsNotTypeOf() + { + TaskContext.ExpressionBuilder.Append($".IsNotTypeOf<{typeof(TExpected).Name}>()"); + return new IsNotTypeOfAssertion, TExpected>(TaskContext); + } + /// /// Asserts that the async function throws the specified exception type (or subclass). /// Instance method to avoid C# type inference issues with extension methods. diff --git a/TUnit.Assertions/Sources/ValueAssertion.cs b/TUnit.Assertions/Sources/ValueAssertion.cs index f11d4dd973..a17d8ed7e9 100644 --- a/TUnit.Assertions/Sources/ValueAssertion.cs +++ b/TUnit.Assertions/Sources/ValueAssertion.cs @@ -76,4 +76,15 @@ public IsNotAssignableToAssertion IsNotAssignableTo() Context.ExpressionBuilder.Append($".IsNotAssignableTo<{typeof(TTarget).Name}>()"); return new IsNotAssignableToAssertion(Context); } + + /// + /// Asserts that the value is NOT of the specified type. + /// This instance method allows single type parameter usage without needing to specify the source type. + /// Example: await Assert.That(myObject).IsNotTypeOf(); + /// + public IsNotTypeOfAssertion IsNotTypeOf() + { + Context.ExpressionBuilder.Append($".IsNotTypeOf<{typeof(TExpected).Name}>()"); + return new IsNotTypeOfAssertion(Context); + } } diff --git a/TUnit.PublicAPI/Tests.Assertions_Library_Has_No_API_Changes.DotNet10_0.verified.txt b/TUnit.PublicAPI/Tests.Assertions_Library_Has_No_API_Changes.DotNet10_0.verified.txt index f9b886b93f..35bcf00a2e 100644 --- a/TUnit.PublicAPI/Tests.Assertions_Library_Has_No_API_Changes.DotNet10_0.verified.txt +++ b/TUnit.PublicAPI/Tests.Assertions_Library_Has_No_API_Changes.DotNet10_0.verified.txt @@ -129,6 +129,9 @@ namespace .Assertions { public . Context { get; } public . GetAwaiter() { } + public . IsAssignableTo() { } + public . IsNotAssignableTo() { } + public . IsNotTypeOf() { } public . IsTypeOf() { } } public class PropertyAssertion @@ -198,6 +201,9 @@ namespace . public WhenParsedIntoAssertion(. stringContext, ? formatProvider = null) { } protected override .<.> CheckAsync(. metadata) { } protected override string GetExpectation() { } + public . IsAssignableTo() { } + public . IsNotAssignableTo() { } + public . IsNotTypeOf() { } public . IsTypeOf() { } public ..WhenParsedIntoAssertion WithFormatProvider( formatProvider) { } } @@ -271,12 +277,14 @@ namespace .Conditions { public AssertionSourceAdapter(. context) { } public . Context { get; } + public . IsAssignableTo() { } + public . IsNotAssignableTo() { } + public . IsNotTypeOf() { } public . IsTypeOf() { } } - public class AsyncMappedSatisfiesAssertion : . - where TAssertion : . + public class AsyncMappedSatisfiesAssertion : . { - public AsyncMappedSatisfiesAssertion(. context, > selector, <., TAssertion> assertions, string selectorDescription) { } + public AsyncMappedSatisfiesAssertion(. context, > selector, <., .?> assertions, string selectorDescription) { } protected override .<.> CheckAsync(. metadata) { } protected override string GetExpectation() { } } @@ -771,7 +779,6 @@ namespace .Conditions protected override string GetExpectation() { } public . Within(int tolerance) { } } - [.("IsAssignableTo")] public class IsAssignableToAssertion : . { public IsAssignableToAssertion(. context) { } @@ -823,7 +830,6 @@ namespace .Conditions protected override string GetExpectation() { } public . Using(. comparer) { } } - [.("IsNotAssignableTo")] public class IsNotAssignableToAssertion : . { public IsNotAssignableToAssertion(. context) { } @@ -854,6 +860,12 @@ namespace .Conditions protected override .<.> CheckAsync(. metadata) { } protected override string GetExpectation() { } } + public class IsNotTypeOfAssertion : . + { + public IsNotTypeOfAssertion(. context) { } + protected override .<.> CheckAsync(. metadata) { } + protected override string GetExpectation() { } + } public class IsTypeOfRuntimeAssertion : . { public IsTypeOfRuntimeAssertion(. context, expectedType) { } @@ -887,11 +899,11 @@ namespace .Conditions } public class MappedSatisfiesAssertion : . { - public MappedSatisfiesAssertion(. context, selector, <., .?> assertions, string selectorDescription) { } + public MappedSatisfiesAssertion(. context, selector, <., .?> assertions, string selectorDescription) { } protected override .<.> CheckAsync(. metadata) { } protected override string GetExpectation() { } } - public class MemberAssertionResult + public class MemberAssertionResult : . { public . And { get; } public . Or { get; } @@ -1389,7 +1401,7 @@ namespace .Core public static . FailIf(bool condition, string message) { } public static . Failed(string message) { } } - public abstract class Assertion + public abstract class Assertion : . { protected readonly . Context; protected Assertion(. context) { } @@ -1450,10 +1462,17 @@ namespace .Core public StartTime { get; } public TValue Value { get; } } + public interface IAssertion + { + . AssertAsync(); + } public interface IAssertionSource { } public interface IAssertionSource : . { . Context { get; } + . IsAssignableTo(); + . IsNotAssignableTo(); + . IsNotTypeOf(); . IsTypeOf(); } public interface IDelegateAssertionSource : ., . { } @@ -1582,8 +1601,6 @@ namespace .Extensions public static .<> IsAfterOrEqualTo(this .<> source, expected, [.("expected")] string? expression = null) { } public static .<> IsAfterOrEqualTo(this .<> source, expected, [.("expected")] string? expression = null) { } public static .<> IsAfterOrEqualTo(this .<> source, expected, [.("expected")] string? expression = null) { } - public static . IsAssignableTo(this . source) { } - public static . IsAssignableTo(this . source) { } public static .<> IsBefore(this .<> source, expected, [.("expected")] string? expression = null) { } public static .<> IsBefore(this .<> source, expected, [.("expected")] string? expression = null) { } public static .<> IsBefore(this .<> source, expected, [.("expected")] string? expression = null) { } @@ -1600,7 +1617,6 @@ namespace .Extensions where TValue : { } public static . IsNegative(this . source) where TValue : struct, { } - public static . IsNotAssignableTo(this . source) { } public static ..IsNotDefinedAssertion IsNotDefined(this . source) where TEnum : struct, { } [.("Uses reflection to compare members")] @@ -1641,9 +1657,8 @@ namespace .Extensions [.(3)] public static . Member(this . source, .<>> memberSelector, <.<., TKey, TValue>, .> assertions) { } public static . Satisfies(this . source, predicate, [.("predicate")] string? expression = null) { } - public static . Satisfies(this . source, selector, <., .?> assertions, [.("selector")] string? selectorExpression = null) { } - public static . Satisfies(this . source, > selector, <., TAssertion> assertions, [.("selector")] string? selectorExpression = null) - where TAssertion : . { } + public static . Satisfies(this . source, selector, <., .?> assertions, [.("selector")] string? selectorExpression = null) { } + public static . SatisfiesAsync(this . source, > selector, <., .?> assertions, [.("selector")] string? selectorExpression = null) { } public static . Throws(this . source) where TException : { } public static . Throws(this . source) @@ -3045,10 +3060,6 @@ namespace .Extensions protected override .<.> CheckAsync(. metadata) { } protected override string GetExpectation() { } } - public static class IsAssignableToAssertionExtensions - { - public static . IsAssignableTo(this . source) { } - } public static class IsDefaultAssertionExtensions { public static . IsDefault(this . source) @@ -3079,10 +3090,6 @@ namespace .Extensions public static . IsEquivalentTo(this . source, . expected, . comparer, . ordering = 0, [.("expected")] string? expectedExpression = null, [.("comparer")] string? comparerExpression = null, [.("ordering")] string? orderingExpression = null) where TCollection : . { } } - public static class IsNotAssignableToAssertionExtensions - { - public static . IsNotAssignableTo(this . source) { } - } public static class IsNotDefaultAssertionExtensions { public static . IsNotDefault(this . source) @@ -4294,14 +4301,17 @@ namespace .Sources { public AsyncDelegateAssertion(<.> action, string? expression) { } public . Context { get; } + public . IsAssignableTo() { } public .<.> IsCanceled() { } public .<.> IsCompleted() { } public .<.> IsCompletedSuccessfully() { } public .<.> IsFaulted() { } + public . IsNotAssignableTo() { } public .<.> IsNotCanceled() { } public .<.> IsNotCompleted() { } public .<.> IsNotCompletedSuccessfully() { } public .<.> IsNotFaulted() { } + public . IsNotTypeOf() { } public . IsTypeOf() { } public . Throws( exceptionType) { } public . Throws() @@ -4315,6 +4325,9 @@ namespace .Sources { public AsyncFuncAssertion(<.> func, string? expression) { } public . Context { get; } + public . IsAssignableTo() { } + public . IsNotAssignableTo() { } + public . IsNotTypeOf() { } public . IsTypeOf() { } public . Throws() where TException : { } @@ -4342,10 +4355,13 @@ namespace .Sources public . HasCount(int expectedCount, [.("expectedCount")] string? expression = null) { } public . HasDistinctItems() { } public . HasSingleItem() { } + public . IsAssignableTo() { } public . IsEmpty() { } public . IsInDescendingOrder() { } public . IsInOrder() { } + public . IsNotAssignableTo() { } public . IsNotEmpty() { } + public . IsNotTypeOf() { } public . IsOrderedBy( keySelector, [.("keySelector")] string? expression = null) { } public . IsOrderedBy( keySelector, .? comparer, [.("keySelector")] string? selectorExpression = null, [.("comparer")] string? comparerExpression = null) { } public . IsOrderedByDescending( keySelector, [.("keySelector")] string? expression = null) { } @@ -4360,6 +4376,9 @@ namespace .Sources { public DelegateAssertion( action, string? expression) { } public . Context { get; } + public . IsAssignableTo() { } + public . IsNotAssignableTo() { } + public . IsNotTypeOf() { } public . IsTypeOf() { } public . Throws() where TException : { } @@ -4385,6 +4404,9 @@ namespace .Sources { public FuncAssertion( func, string? expression) { } public . Context { get; } + public . IsAssignableTo() { } + public . IsNotAssignableTo() { } + public . IsNotTypeOf() { } public . IsTypeOf() { } public . Throws() where TException : { } @@ -4395,14 +4417,17 @@ namespace .Sources { public TaskAssertion(. task, string? expression) { } public . Context { get; } + public . IsAssignableTo() { } public .<.> IsCanceled() { } public .<.> IsCompleted() { } public .<.> IsCompletedSuccessfully() { } public .<.> IsFaulted() { } + public . IsNotAssignableTo() { } public .<.> IsNotCanceled() { } public .<.> IsNotCompleted() { } public .<.> IsNotCompletedSuccessfully() { } public .<.> IsNotFaulted() { } + public . IsNotTypeOf() { } public . IsTypeOf() { } public . Throws() where TException : { } @@ -4416,6 +4441,7 @@ namespace .Sources public . Context { get; } public . IsAssignableTo() { } public . IsNotAssignableTo() { } + public . IsNotTypeOf() { } public . IsTypeOf() { } } } \ No newline at end of file diff --git a/TUnit.PublicAPI/Tests.Assertions_Library_Has_No_API_Changes.DotNet8_0.verified.txt b/TUnit.PublicAPI/Tests.Assertions_Library_Has_No_API_Changes.DotNet8_0.verified.txt index d865b2f284..060668995b 100644 --- a/TUnit.PublicAPI/Tests.Assertions_Library_Has_No_API_Changes.DotNet8_0.verified.txt +++ b/TUnit.PublicAPI/Tests.Assertions_Library_Has_No_API_Changes.DotNet8_0.verified.txt @@ -126,6 +126,9 @@ namespace .Assertions { public . Context { get; } public . GetAwaiter() { } + public . IsAssignableTo() { } + public . IsNotAssignableTo() { } + public . IsNotTypeOf() { } public . IsTypeOf() { } } public class PropertyAssertion @@ -195,6 +198,9 @@ namespace . public WhenParsedIntoAssertion(. stringContext, ? formatProvider = null) { } protected override .<.> CheckAsync(. metadata) { } protected override string GetExpectation() { } + public . IsAssignableTo() { } + public . IsNotAssignableTo() { } + public . IsNotTypeOf() { } public . IsTypeOf() { } public ..WhenParsedIntoAssertion WithFormatProvider( formatProvider) { } } @@ -268,12 +274,14 @@ namespace .Conditions { public AssertionSourceAdapter(. context) { } public . Context { get; } + public . IsAssignableTo() { } + public . IsNotAssignableTo() { } + public . IsNotTypeOf() { } public . IsTypeOf() { } } - public class AsyncMappedSatisfiesAssertion : . - where TAssertion : . + public class AsyncMappedSatisfiesAssertion : . { - public AsyncMappedSatisfiesAssertion(. context, > selector, <., TAssertion> assertions, string selectorDescription) { } + public AsyncMappedSatisfiesAssertion(. context, > selector, <., .?> assertions, string selectorDescription) { } protected override .<.> CheckAsync(. metadata) { } protected override string GetExpectation() { } } @@ -768,7 +776,6 @@ namespace .Conditions protected override string GetExpectation() { } public . Within(int tolerance) { } } - [.("IsAssignableTo")] public class IsAssignableToAssertion : . { public IsAssignableToAssertion(. context) { } @@ -820,7 +827,6 @@ namespace .Conditions protected override string GetExpectation() { } public . Using(. comparer) { } } - [.("IsNotAssignableTo")] public class IsNotAssignableToAssertion : . { public IsNotAssignableToAssertion(. context) { } @@ -851,6 +857,12 @@ namespace .Conditions protected override .<.> CheckAsync(. metadata) { } protected override string GetExpectation() { } } + public class IsNotTypeOfAssertion : . + { + public IsNotTypeOfAssertion(. context) { } + protected override .<.> CheckAsync(. metadata) { } + protected override string GetExpectation() { } + } public class IsTypeOfRuntimeAssertion : . { public IsTypeOfRuntimeAssertion(. context, expectedType) { } @@ -884,11 +896,11 @@ namespace .Conditions } public class MappedSatisfiesAssertion : . { - public MappedSatisfiesAssertion(. context, selector, <., .?> assertions, string selectorDescription) { } + public MappedSatisfiesAssertion(. context, selector, <., .?> assertions, string selectorDescription) { } protected override .<.> CheckAsync(. metadata) { } protected override string GetExpectation() { } } - public class MemberAssertionResult + public class MemberAssertionResult : . { public . And { get; } public . Or { get; } @@ -1386,7 +1398,7 @@ namespace .Core public static . FailIf(bool condition, string message) { } public static . Failed(string message) { } } - public abstract class Assertion + public abstract class Assertion : . { protected readonly . Context; protected Assertion(. context) { } @@ -1447,10 +1459,17 @@ namespace .Core public StartTime { get; } public TValue Value { get; } } + public interface IAssertion + { + . AssertAsync(); + } public interface IAssertionSource { } public interface IAssertionSource : . { . Context { get; } + . IsAssignableTo(); + . IsNotAssignableTo(); + . IsNotTypeOf(); . IsTypeOf(); } public interface IDelegateAssertionSource : ., . { } @@ -1579,8 +1598,6 @@ namespace .Extensions public static .<> IsAfterOrEqualTo(this .<> source, expected, [.("expected")] string? expression = null) { } public static .<> IsAfterOrEqualTo(this .<> source, expected, [.("expected")] string? expression = null) { } public static .<> IsAfterOrEqualTo(this .<> source, expected, [.("expected")] string? expression = null) { } - public static . IsAssignableTo(this . source) { } - public static . IsAssignableTo(this . source) { } public static .<> IsBefore(this .<> source, expected, [.("expected")] string? expression = null) { } public static .<> IsBefore(this .<> source, expected, [.("expected")] string? expression = null) { } public static .<> IsBefore(this .<> source, expected, [.("expected")] string? expression = null) { } @@ -1597,7 +1614,6 @@ namespace .Extensions where TValue : { } public static . IsNegative(this . source) where TValue : struct, { } - public static . IsNotAssignableTo(this . source) { } public static ..IsNotDefinedAssertion IsNotDefined(this . source) where TEnum : struct, { } [.("Uses reflection to compare members")] @@ -1631,9 +1647,8 @@ namespace .Extensions public static . Member(this . source, .<> memberSelector, <., .> assertions) { } public static . Member(this . source, .<>> memberSelector, <.<., TKey, TValue>, .> assertions) { } public static . Satisfies(this . source, predicate, [.("predicate")] string? expression = null) { } - public static . Satisfies(this . source, selector, <., .?> assertions, [.("selector")] string? selectorExpression = null) { } - public static . Satisfies(this . source, > selector, <., TAssertion> assertions, [.("selector")] string? selectorExpression = null) - where TAssertion : . { } + public static . Satisfies(this . source, selector, <., .?> assertions, [.("selector")] string? selectorExpression = null) { } + public static . SatisfiesAsync(this . source, > selector, <., .?> assertions, [.("selector")] string? selectorExpression = null) { } public static . Throws(this . source) where TException : { } public static . Throws(this . source) @@ -3028,10 +3043,6 @@ namespace .Extensions protected override .<.> CheckAsync(. metadata) { } protected override string GetExpectation() { } } - public static class IsAssignableToAssertionExtensions - { - public static . IsAssignableTo(this . source) { } - } public static class IsDefaultAssertionExtensions { public static . IsDefault(this . source) @@ -3062,10 +3073,6 @@ namespace .Extensions public static . IsEquivalentTo(this . source, . expected, . comparer, . ordering = 0, [.("expected")] string? expectedExpression = null, [.("comparer")] string? comparerExpression = null, [.("ordering")] string? orderingExpression = null) where TCollection : . { } } - public static class IsNotAssignableToAssertionExtensions - { - public static . IsNotAssignableTo(this . source) { } - } public static class IsNotDefaultAssertionExtensions { public static . IsNotDefault(this . source) @@ -4274,14 +4281,17 @@ namespace .Sources { public AsyncDelegateAssertion(<.> action, string? expression) { } public . Context { get; } + public . IsAssignableTo() { } public .<.> IsCanceled() { } public .<.> IsCompleted() { } public .<.> IsCompletedSuccessfully() { } public .<.> IsFaulted() { } + public . IsNotAssignableTo() { } public .<.> IsNotCanceled() { } public .<.> IsNotCompleted() { } public .<.> IsNotCompletedSuccessfully() { } public .<.> IsNotFaulted() { } + public . IsNotTypeOf() { } public . IsTypeOf() { } public . Throws( exceptionType) { } public . Throws() @@ -4295,6 +4305,9 @@ namespace .Sources { public AsyncFuncAssertion(<.> func, string? expression) { } public . Context { get; } + public . IsAssignableTo() { } + public . IsNotAssignableTo() { } + public . IsNotTypeOf() { } public . IsTypeOf() { } public . Throws() where TException : { } @@ -4322,10 +4335,13 @@ namespace .Sources public . HasCount(int expectedCount, [.("expectedCount")] string? expression = null) { } public . HasDistinctItems() { } public . HasSingleItem() { } + public . IsAssignableTo() { } public . IsEmpty() { } public . IsInDescendingOrder() { } public . IsInOrder() { } + public . IsNotAssignableTo() { } public . IsNotEmpty() { } + public . IsNotTypeOf() { } public . IsOrderedBy( keySelector, [.("keySelector")] string? expression = null) { } public . IsOrderedBy( keySelector, .? comparer, [.("keySelector")] string? selectorExpression = null, [.("comparer")] string? comparerExpression = null) { } public . IsOrderedByDescending( keySelector, [.("keySelector")] string? expression = null) { } @@ -4340,6 +4356,9 @@ namespace .Sources { public DelegateAssertion( action, string? expression) { } public . Context { get; } + public . IsAssignableTo() { } + public . IsNotAssignableTo() { } + public . IsNotTypeOf() { } public . IsTypeOf() { } public . Throws() where TException : { } @@ -4365,6 +4384,9 @@ namespace .Sources { public FuncAssertion( func, string? expression) { } public . Context { get; } + public . IsAssignableTo() { } + public . IsNotAssignableTo() { } + public . IsNotTypeOf() { } public . IsTypeOf() { } public . Throws() where TException : { } @@ -4375,14 +4397,17 @@ namespace .Sources { public TaskAssertion(. task, string? expression) { } public . Context { get; } + public . IsAssignableTo() { } public .<.> IsCanceled() { } public .<.> IsCompleted() { } public .<.> IsCompletedSuccessfully() { } public .<.> IsFaulted() { } + public . IsNotAssignableTo() { } public .<.> IsNotCanceled() { } public .<.> IsNotCompleted() { } public .<.> IsNotCompletedSuccessfully() { } public .<.> IsNotFaulted() { } + public . IsNotTypeOf() { } public . IsTypeOf() { } public . Throws() where TException : { } @@ -4396,6 +4421,7 @@ namespace .Sources public . Context { get; } public . IsAssignableTo() { } public . IsNotAssignableTo() { } + public . IsNotTypeOf() { } public . IsTypeOf() { } } } \ No newline at end of file diff --git a/TUnit.PublicAPI/Tests.Assertions_Library_Has_No_API_Changes.DotNet9_0.verified.txt b/TUnit.PublicAPI/Tests.Assertions_Library_Has_No_API_Changes.DotNet9_0.verified.txt index ff28d27625..634cbf0e26 100644 --- a/TUnit.PublicAPI/Tests.Assertions_Library_Has_No_API_Changes.DotNet9_0.verified.txt +++ b/TUnit.PublicAPI/Tests.Assertions_Library_Has_No_API_Changes.DotNet9_0.verified.txt @@ -129,6 +129,9 @@ namespace .Assertions { public . Context { get; } public . GetAwaiter() { } + public . IsAssignableTo() { } + public . IsNotAssignableTo() { } + public . IsNotTypeOf() { } public . IsTypeOf() { } } public class PropertyAssertion @@ -198,6 +201,9 @@ namespace . public WhenParsedIntoAssertion(. stringContext, ? formatProvider = null) { } protected override .<.> CheckAsync(. metadata) { } protected override string GetExpectation() { } + public . IsAssignableTo() { } + public . IsNotAssignableTo() { } + public . IsNotTypeOf() { } public . IsTypeOf() { } public ..WhenParsedIntoAssertion WithFormatProvider( formatProvider) { } } @@ -271,12 +277,14 @@ namespace .Conditions { public AssertionSourceAdapter(. context) { } public . Context { get; } + public . IsAssignableTo() { } + public . IsNotAssignableTo() { } + public . IsNotTypeOf() { } public . IsTypeOf() { } } - public class AsyncMappedSatisfiesAssertion : . - where TAssertion : . + public class AsyncMappedSatisfiesAssertion : . { - public AsyncMappedSatisfiesAssertion(. context, > selector, <., TAssertion> assertions, string selectorDescription) { } + public AsyncMappedSatisfiesAssertion(. context, > selector, <., .?> assertions, string selectorDescription) { } protected override .<.> CheckAsync(. metadata) { } protected override string GetExpectation() { } } @@ -771,7 +779,6 @@ namespace .Conditions protected override string GetExpectation() { } public . Within(int tolerance) { } } - [.("IsAssignableTo")] public class IsAssignableToAssertion : . { public IsAssignableToAssertion(. context) { } @@ -823,7 +830,6 @@ namespace .Conditions protected override string GetExpectation() { } public . Using(. comparer) { } } - [.("IsNotAssignableTo")] public class IsNotAssignableToAssertion : . { public IsNotAssignableToAssertion(. context) { } @@ -854,6 +860,12 @@ namespace .Conditions protected override .<.> CheckAsync(. metadata) { } protected override string GetExpectation() { } } + public class IsNotTypeOfAssertion : . + { + public IsNotTypeOfAssertion(. context) { } + protected override .<.> CheckAsync(. metadata) { } + protected override string GetExpectation() { } + } public class IsTypeOfRuntimeAssertion : . { public IsTypeOfRuntimeAssertion(. context, expectedType) { } @@ -887,11 +899,11 @@ namespace .Conditions } public class MappedSatisfiesAssertion : . { - public MappedSatisfiesAssertion(. context, selector, <., .?> assertions, string selectorDescription) { } + public MappedSatisfiesAssertion(. context, selector, <., .?> assertions, string selectorDescription) { } protected override .<.> CheckAsync(. metadata) { } protected override string GetExpectation() { } } - public class MemberAssertionResult + public class MemberAssertionResult : . { public . And { get; } public . Or { get; } @@ -1389,7 +1401,7 @@ namespace .Core public static . FailIf(bool condition, string message) { } public static . Failed(string message) { } } - public abstract class Assertion + public abstract class Assertion : . { protected readonly . Context; protected Assertion(. context) { } @@ -1450,10 +1462,17 @@ namespace .Core public StartTime { get; } public TValue Value { get; } } + public interface IAssertion + { + . AssertAsync(); + } public interface IAssertionSource { } public interface IAssertionSource : . { . Context { get; } + . IsAssignableTo(); + . IsNotAssignableTo(); + . IsNotTypeOf(); . IsTypeOf(); } public interface IDelegateAssertionSource : ., . { } @@ -1582,8 +1601,6 @@ namespace .Extensions public static .<> IsAfterOrEqualTo(this .<> source, expected, [.("expected")] string? expression = null) { } public static .<> IsAfterOrEqualTo(this .<> source, expected, [.("expected")] string? expression = null) { } public static .<> IsAfterOrEqualTo(this .<> source, expected, [.("expected")] string? expression = null) { } - public static . IsAssignableTo(this . source) { } - public static . IsAssignableTo(this . source) { } public static .<> IsBefore(this .<> source, expected, [.("expected")] string? expression = null) { } public static .<> IsBefore(this .<> source, expected, [.("expected")] string? expression = null) { } public static .<> IsBefore(this .<> source, expected, [.("expected")] string? expression = null) { } @@ -1600,7 +1617,6 @@ namespace .Extensions where TValue : { } public static . IsNegative(this . source) where TValue : struct, { } - public static . IsNotAssignableTo(this . source) { } public static ..IsNotDefinedAssertion IsNotDefined(this . source) where TEnum : struct, { } [.("Uses reflection to compare members")] @@ -1641,9 +1657,8 @@ namespace .Extensions [.(3)] public static . Member(this . source, .<>> memberSelector, <.<., TKey, TValue>, .> assertions) { } public static . Satisfies(this . source, predicate, [.("predicate")] string? expression = null) { } - public static . Satisfies(this . source, selector, <., .?> assertions, [.("selector")] string? selectorExpression = null) { } - public static . Satisfies(this . source, > selector, <., TAssertion> assertions, [.("selector")] string? selectorExpression = null) - where TAssertion : . { } + public static . Satisfies(this . source, selector, <., .?> assertions, [.("selector")] string? selectorExpression = null) { } + public static . SatisfiesAsync(this . source, > selector, <., .?> assertions, [.("selector")] string? selectorExpression = null) { } public static . Throws(this . source) where TException : { } public static . Throws(this . source) @@ -3045,10 +3060,6 @@ namespace .Extensions protected override .<.> CheckAsync(. metadata) { } protected override string GetExpectation() { } } - public static class IsAssignableToAssertionExtensions - { - public static . IsAssignableTo(this . source) { } - } public static class IsDefaultAssertionExtensions { public static . IsDefault(this . source) @@ -3079,10 +3090,6 @@ namespace .Extensions public static . IsEquivalentTo(this . source, . expected, . comparer, . ordering = 0, [.("expected")] string? expectedExpression = null, [.("comparer")] string? comparerExpression = null, [.("ordering")] string? orderingExpression = null) where TCollection : . { } } - public static class IsNotAssignableToAssertionExtensions - { - public static . IsNotAssignableTo(this . source) { } - } public static class IsNotDefaultAssertionExtensions { public static . IsNotDefault(this . source) @@ -4294,14 +4301,17 @@ namespace .Sources { public AsyncDelegateAssertion(<.> action, string? expression) { } public . Context { get; } + public . IsAssignableTo() { } public .<.> IsCanceled() { } public .<.> IsCompleted() { } public .<.> IsCompletedSuccessfully() { } public .<.> IsFaulted() { } + public . IsNotAssignableTo() { } public .<.> IsNotCanceled() { } public .<.> IsNotCompleted() { } public .<.> IsNotCompletedSuccessfully() { } public .<.> IsNotFaulted() { } + public . IsNotTypeOf() { } public . IsTypeOf() { } public . Throws( exceptionType) { } public . Throws() @@ -4315,6 +4325,9 @@ namespace .Sources { public AsyncFuncAssertion(<.> func, string? expression) { } public . Context { get; } + public . IsAssignableTo() { } + public . IsNotAssignableTo() { } + public . IsNotTypeOf() { } public . IsTypeOf() { } public . Throws() where TException : { } @@ -4342,10 +4355,13 @@ namespace .Sources public . HasCount(int expectedCount, [.("expectedCount")] string? expression = null) { } public . HasDistinctItems() { } public . HasSingleItem() { } + public . IsAssignableTo() { } public . IsEmpty() { } public . IsInDescendingOrder() { } public . IsInOrder() { } + public . IsNotAssignableTo() { } public . IsNotEmpty() { } + public . IsNotTypeOf() { } public . IsOrderedBy( keySelector, [.("keySelector")] string? expression = null) { } public . IsOrderedBy( keySelector, .? comparer, [.("keySelector")] string? selectorExpression = null, [.("comparer")] string? comparerExpression = null) { } public . IsOrderedByDescending( keySelector, [.("keySelector")] string? expression = null) { } @@ -4360,6 +4376,9 @@ namespace .Sources { public DelegateAssertion( action, string? expression) { } public . Context { get; } + public . IsAssignableTo() { } + public . IsNotAssignableTo() { } + public . IsNotTypeOf() { } public . IsTypeOf() { } public . Throws() where TException : { } @@ -4385,6 +4404,9 @@ namespace .Sources { public FuncAssertion( func, string? expression) { } public . Context { get; } + public . IsAssignableTo() { } + public . IsNotAssignableTo() { } + public . IsNotTypeOf() { } public . IsTypeOf() { } public . Throws() where TException : { } @@ -4395,14 +4417,17 @@ namespace .Sources { public TaskAssertion(. task, string? expression) { } public . Context { get; } + public . IsAssignableTo() { } public .<.> IsCanceled() { } public .<.> IsCompleted() { } public .<.> IsCompletedSuccessfully() { } public .<.> IsFaulted() { } + public . IsNotAssignableTo() { } public .<.> IsNotCanceled() { } public .<.> IsNotCompleted() { } public .<.> IsNotCompletedSuccessfully() { } public .<.> IsNotFaulted() { } + public . IsNotTypeOf() { } public . IsTypeOf() { } public . Throws() where TException : { } @@ -4416,6 +4441,7 @@ namespace .Sources public . Context { get; } public . IsAssignableTo() { } public . IsNotAssignableTo() { } + public . IsNotTypeOf() { } public . IsTypeOf() { } } } \ No newline at end of file diff --git a/TUnit.PublicAPI/Tests.Assertions_Library_Has_No_API_Changes.Net4_7.verified.txt b/TUnit.PublicAPI/Tests.Assertions_Library_Has_No_API_Changes.Net4_7.verified.txt index e1aa8c8580..03c58549c0 100644 --- a/TUnit.PublicAPI/Tests.Assertions_Library_Has_No_API_Changes.Net4_7.verified.txt +++ b/TUnit.PublicAPI/Tests.Assertions_Library_Has_No_API_Changes.Net4_7.verified.txt @@ -126,6 +126,9 @@ namespace .Assertions { public . Context { get; } public . GetAwaiter() { } + public . IsAssignableTo() { } + public . IsNotAssignableTo() { } + public . IsNotTypeOf() { } public . IsTypeOf() { } } public class PropertyAssertion @@ -195,6 +198,9 @@ namespace . public WhenParsedIntoAssertion(. stringContext, ? formatProvider = null) { } protected override .<.> CheckAsync(. metadata) { } protected override string GetExpectation() { } + public . IsAssignableTo() { } + public . IsNotAssignableTo() { } + public . IsNotTypeOf() { } public . IsTypeOf() { } public ..WhenParsedIntoAssertion WithFormatProvider( formatProvider) { } } @@ -268,12 +274,14 @@ namespace .Conditions { public AssertionSourceAdapter(. context) { } public . Context { get; } + public . IsAssignableTo() { } + public . IsNotAssignableTo() { } + public . IsNotTypeOf() { } public . IsTypeOf() { } } - public class AsyncMappedSatisfiesAssertion : . - where TAssertion : . + public class AsyncMappedSatisfiesAssertion : . { - public AsyncMappedSatisfiesAssertion(. context, > selector, <., TAssertion> assertions, string selectorDescription) { } + public AsyncMappedSatisfiesAssertion(. context, > selector, <., .?> assertions, string selectorDescription) { } protected override .<.> CheckAsync(. metadata) { } protected override string GetExpectation() { } } @@ -743,7 +751,6 @@ namespace .Conditions protected override string GetExpectation() { } public . Within(int tolerance) { } } - [.("IsAssignableTo")] public class IsAssignableToAssertion : . { public IsAssignableToAssertion(. context) { } @@ -792,7 +799,6 @@ namespace .Conditions protected override string GetExpectation() { } public . Using(. comparer) { } } - [.("IsNotAssignableTo")] public class IsNotAssignableToAssertion : . { public IsNotAssignableToAssertion(. context) { } @@ -823,6 +829,12 @@ namespace .Conditions protected override .<.> CheckAsync(. metadata) { } protected override string GetExpectation() { } } + public class IsNotTypeOfAssertion : . + { + public IsNotTypeOfAssertion(. context) { } + protected override .<.> CheckAsync(. metadata) { } + protected override string GetExpectation() { } + } public class IsTypeOfRuntimeAssertion : . { public IsTypeOfRuntimeAssertion(. context, expectedType) { } @@ -856,11 +868,11 @@ namespace .Conditions } public class MappedSatisfiesAssertion : . { - public MappedSatisfiesAssertion(. context, selector, <., .?> assertions, string selectorDescription) { } + public MappedSatisfiesAssertion(. context, selector, <., .?> assertions, string selectorDescription) { } protected override .<.> CheckAsync(. metadata) { } protected override string GetExpectation() { } } - public class MemberAssertionResult + public class MemberAssertionResult : . { public . And { get; } public . Or { get; } @@ -1299,7 +1311,7 @@ namespace .Core public static . FailIf(bool condition, string message) { } public static . Failed(string message) { } } - public abstract class Assertion + public abstract class Assertion : . { protected readonly . Context; protected Assertion(. context) { } @@ -1360,10 +1372,17 @@ namespace .Core public StartTime { get; } public TValue Value { get; } } + public interface IAssertion + { + . AssertAsync(); + } public interface IAssertionSource { } public interface IAssertionSource : . { . Context { get; } + . IsAssignableTo(); + . IsNotAssignableTo(); + . IsNotTypeOf(); . IsTypeOf(); } public interface IDelegateAssertionSource : ., . { } @@ -1474,8 +1493,6 @@ namespace .Extensions public static .<> IsAfter(this .<> source, expected, [.("expected")] string? expression = null) { } public static .<> IsAfterOrEqualTo(this .<> source, expected, [.("expected")] string? expression = null) { } public static .<> IsAfterOrEqualTo(this .<> source, expected, [.("expected")] string? expression = null) { } - public static . IsAssignableTo(this . source) { } - public static . IsAssignableTo(this . source) { } public static .<> IsBefore(this .<> source, expected, [.("expected")] string? expression = null) { } public static .<> IsBefore(this .<> source, expected, [.("expected")] string? expression = null) { } public static .<> IsBeforeOrEqualTo(this .<> source, expected, [.("expected")] string? expression = null) { } @@ -1487,7 +1504,6 @@ namespace .Extensions where TValue : { } public static . IsNegative(this . source) where TValue : struct, { } - public static . IsNotAssignableTo(this . source) { } public static ..IsNotDefinedAssertion IsNotDefined(this . source) where TEnum : struct, { } public static . IsNotEquivalentTo(this . source, object? expected, [.("expected")] string? expression = null) { } @@ -1514,9 +1530,8 @@ namespace .Extensions public static . Member(this . source, .<> memberSelector, <., .> assertions) { } public static . Member(this . source, .<>> memberSelector, <.<., TKey, TValue>, .> assertions) { } public static . Satisfies(this . source, predicate, [.("predicate")] string? expression = null) { } - public static . Satisfies(this . source, selector, <., .?> assertions, [.("selector")] string? selectorExpression = null) { } - public static . Satisfies(this . source, > selector, <., TAssertion> assertions, [.("selector")] string? selectorExpression = null) - where TAssertion : . { } + public static . Satisfies(this . source, selector, <., .?> assertions, [.("selector")] string? selectorExpression = null) { } + public static . SatisfiesAsync(this . source, > selector, <., .?> assertions, [.("selector")] string? selectorExpression = null) { } public static . Throws(this . source) where TException : { } public static . Throws(this . source) @@ -2755,10 +2770,6 @@ namespace .Extensions protected override .<.> CheckAsync(. metadata) { } protected override string GetExpectation() { } } - public static class IsAssignableToAssertionExtensions - { - public static . IsAssignableTo(this . source) { } - } public static class IsDefaultAssertionExtensions { public static . IsDefault(this . source) @@ -2785,10 +2796,6 @@ namespace .Extensions public static . IsEquivalentTo(this . source, . expected, . comparer, . ordering = 0, [.("expected")] string? expectedExpression = null, [.("comparer")] string? comparerExpression = null, [.("ordering")] string? orderingExpression = null) where TCollection : . { } } - public static class IsNotAssignableToAssertionExtensions - { - public static . IsNotAssignableTo(this . source) { } - } public static class IsNotDefaultAssertionExtensions { public static . IsNotDefault(this . source) @@ -3761,12 +3768,15 @@ namespace .Sources { public AsyncDelegateAssertion(<.> action, string? expression) { } public . Context { get; } + public . IsAssignableTo() { } public .<.> IsCanceled() { } public .<.> IsCompleted() { } public .<.> IsFaulted() { } + public . IsNotAssignableTo() { } public .<.> IsNotCanceled() { } public .<.> IsNotCompleted() { } public .<.> IsNotFaulted() { } + public . IsNotTypeOf() { } public . IsTypeOf() { } public . Throws( exceptionType) { } public . Throws() @@ -3780,6 +3790,9 @@ namespace .Sources { public AsyncFuncAssertion(<.> func, string? expression) { } public . Context { get; } + public . IsAssignableTo() { } + public . IsNotAssignableTo() { } + public . IsNotTypeOf() { } public . IsTypeOf() { } public . Throws() where TException : { } @@ -3807,10 +3820,13 @@ namespace .Sources public . HasCount(int expectedCount, [.("expectedCount")] string? expression = null) { } public . HasDistinctItems() { } public . HasSingleItem() { } + public . IsAssignableTo() { } public . IsEmpty() { } public . IsInDescendingOrder() { } public . IsInOrder() { } + public . IsNotAssignableTo() { } public . IsNotEmpty() { } + public . IsNotTypeOf() { } public . IsOrderedBy( keySelector, [.("keySelector")] string? expression = null) { } public . IsOrderedBy( keySelector, .? comparer, [.("keySelector")] string? selectorExpression = null, [.("comparer")] string? comparerExpression = null) { } public . IsOrderedByDescending( keySelector, [.("keySelector")] string? expression = null) { } @@ -3825,6 +3841,9 @@ namespace .Sources { public DelegateAssertion( action, string? expression) { } public . Context { get; } + public . IsAssignableTo() { } + public . IsNotAssignableTo() { } + public . IsNotTypeOf() { } public . IsTypeOf() { } public . Throws() where TException : { } @@ -3850,6 +3869,9 @@ namespace .Sources { public FuncAssertion( func, string? expression) { } public . Context { get; } + public . IsAssignableTo() { } + public . IsNotAssignableTo() { } + public . IsNotTypeOf() { } public . IsTypeOf() { } public . Throws() where TException : { } @@ -3860,12 +3882,15 @@ namespace .Sources { public TaskAssertion(. task, string? expression) { } public . Context { get; } + public . IsAssignableTo() { } public .<.> IsCanceled() { } public .<.> IsCompleted() { } public .<.> IsFaulted() { } + public . IsNotAssignableTo() { } public .<.> IsNotCanceled() { } public .<.> IsNotCompleted() { } public .<.> IsNotFaulted() { } + public . IsNotTypeOf() { } public . IsTypeOf() { } public . Throws() where TException : { } @@ -3879,6 +3904,7 @@ namespace .Sources public . Context { get; } public . IsAssignableTo() { } public . IsNotAssignableTo() { } + public . IsNotTypeOf() { } public . IsTypeOf() { } } } \ No newline at end of file