diff --git a/.editorconfig b/.editorconfig
index f4874fecc7..0ea4ede3a9 100644
--- a/.editorconfig
+++ b/.editorconfig
@@ -199,6 +199,11 @@ dotnet_diagnostic.SA1116.severity = none
dotnet_diagnostic.SA1117.severity = none
# SA1200: Using directive should appear within a namespace declaration
dotnet_diagnostic.SA1200.severity = none
+
+# Purpose: Use string. Empty for empty strings
+# Reason: There's no performance difference. See https://medium.com/@dk.kravtsov/string-empty-vs-in-c-70c64971161f
+dotnet_diagnostic.SA1122.severity = none
+
# SA1124: Do not use regions
dotnet_diagnostic.SA1124.severity = none
# SA1201: A property should not follow a method
diff --git a/Build/Build.cs b/Build/Build.cs
index 1859443ae5..a3f1c2695b 100644
--- a/Build/Build.cs
+++ b/Build/Build.cs
@@ -1,10 +1,6 @@
using System;
-using System.Collections.Generic;
using System.Linq;
-using System.Net.Http;
-using System.Runtime.InteropServices;
using LibGit2Sharp;
-using Microsoft.Build.Tasks;
using Nuke.Common;
using Nuke.Common.CI.GitHubActions;
using Nuke.Common.Execution;
diff --git a/Build/_build.csproj b/Build/_build.csproj
index 43668e90a3..5d31f778d9 100644
--- a/Build/_build.csproj
+++ b/Build/_build.csproj
@@ -7,6 +7,7 @@
..\
..\
8.1.0
+ 1
OS_WINDOWS
diff --git a/FluentAssertions.sln b/FluentAssertions.sln
index 2e6167875b..43bf07b29f 100644
--- a/FluentAssertions.sln
+++ b/FluentAssertions.sln
@@ -7,7 +7,6 @@ Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Solution Items", "Solution
.editorconfig = .editorconfig
Tests\Default.testsettings = Tests\Default.testsettings
Directory.Build.props = Directory.Build.props
- Src\JetBrainsAnnotations.cs = Src\JetBrainsAnnotations.cs
nuget.config = nuget.config
README.md = README.md
docs\_pages\releases.md = docs\_pages\releases.md
diff --git a/FluentAssertions.sln.DotSettings b/FluentAssertions.sln.DotSettings
index e58cf3d554..785299fbe3 100644
--- a/FluentAssertions.sln.DotSettings
+++ b/FluentAssertions.sln.DotSettings
@@ -1,4 +1,4 @@
-
+
True
True
False
@@ -143,7 +143,7 @@
<Policy Inspect="True" Prefix="" Suffix="" Style="aaBb" />
<Policy Inspect="True" Prefix="" Suffix="" Style="AaBb" />
<Policy Inspect="True" Prefix="" Suffix="" Style="AaBb" />
-
+
OUTLINE
SOLUTION_FOLDER
True
@@ -161,17 +161,17 @@
4
False
True
- True
- 1
- True
- 0
+ False
+
+ False
+
aaa
Arrange-Act-Assert
[Fact]
public void $END$()
{
// Arrange
-
+
// Act
diff --git a/Src/FluentAssertions/AndWhichConstraint.cs b/Src/FluentAssertions/AndWhichConstraint.cs
index a30126ba2f..b15aaaf5c8 100644
--- a/Src/FluentAssertions/AndWhichConstraint.cs
+++ b/Src/FluentAssertions/AndWhichConstraint.cs
@@ -2,45 +2,84 @@
using System.Collections.Generic;
using System.Linq;
using FluentAssertions.Common;
+using FluentAssertions.Execution;
using FluentAssertions.Formatting;
namespace FluentAssertions;
///
-/// Constraint which can be returned from an assertion which matches a condition and which will allow
-/// further matches to be performed on the matched condition as well as the parent constraint.
+/// Provides a property that can be used in chained assertions where the prior assertions returns a
+/// single object that the assertion continues on.
///
-/// The type of the original constraint that was matched
-/// The type of the matched object which the parent constraint matched
-public class AndWhichConstraint : AndConstraint
+public class AndWhichConstraint : AndConstraint
{
- private readonly Lazy matchedConstraint;
+ private readonly AssertionChain assertionChain;
+ private readonly string pathPostfix;
+ private readonly Lazy getSubject;
- public AndWhichConstraint(TParentConstraint parentConstraint, TMatchedElement matchedConstraint)
- : base(parentConstraint)
+ ///
+ /// Creates an object that allows continuing an assertion executed through and
+ /// which resulted in a single .
+ ///
+ public AndWhichConstraint(TParent parent, TSubject subject)
+ : base(parent)
+ {
+ getSubject = new Lazy(() => subject);
+ }
+
+ ///
+ /// Creates an object that allows continuing an assertion executed through and
+ /// which resulted in a single on an existing , but where
+ /// the previous caller identifier is post-fixed with .
+ ///
+ public AndWhichConstraint(TParent parent, TSubject subject, AssertionChain assertionChain, string pathPostfix = "")
+ : base(parent)
{
- this.matchedConstraint =
- new Lazy(() => matchedConstraint);
+ getSubject = new Lazy(() => subject);
+
+ this.assertionChain = assertionChain;
+ this.pathPostfix = pathPostfix;
}
- public AndWhichConstraint(TParentConstraint parentConstraint, IEnumerable matchedConstraint)
- : base(parentConstraint)
+ ///
+ /// Creates an object that allows continuing an assertion executed through and
+ /// which resulted in a potential collection of objects through .
+ ///
+ ///
+ /// If contains more than one object, a clear exception is thrown.
+ ///
+ public AndWhichConstraint(TParent parent, IEnumerable subjects)
+ : base(parent)
{
- this.matchedConstraint =
- new Lazy(
- () => SingleOrDefault(matchedConstraint));
+ getSubject = new Lazy(() => SingleOrDefault(subjects));
}
- private static TMatchedElement SingleOrDefault(
- IEnumerable matchedConstraint)
+ ///
+ /// Creates an object that allows continuing an assertion executed through and
+ /// which resulted in a potential collection of objects through on an
+ /// existing , but where
+ /// the previous caller identifier is post-fixed with .
+ ///
+ ///
+ /// If contains more than one object, a clear exception is thrown.
+ ///
+ public AndWhichConstraint(TParent parent, IEnumerable subjects, AssertionChain assertionChain, string pathPostfix)
+ : base(parent)
{
- TMatchedElement[] matchedElements = matchedConstraint.ToArray();
+ getSubject = new Lazy(() => SingleOrDefault(subjects));
+
+ this.assertionChain = assertionChain;
+ this.pathPostfix = pathPostfix;
+ }
+
+ private static TSubject SingleOrDefault(IEnumerable subjects)
+ {
+ TSubject[] matchedElements = subjects.ToArray();
if (matchedElements.Length > 1)
{
string foundObjects = string.Join(Environment.NewLine,
- matchedElements.Select(
- ele => "\t" + Formatter.ToString(ele)));
+ matchedElements.Select(ele => "\t" + Formatter.ToString(ele)));
string message = "More than one object found. FluentAssertions cannot determine which object is meant."
+ $" Found objects:{Environment.NewLine}{foundObjects}";
@@ -54,13 +93,24 @@ private static TMatchedElement SingleOrDefault(
///
/// Returns the single result of a prior assertion that is used to select a nested or collection item.
///
- public TMatchedElement Which => matchedConstraint.Value;
+ ///
+ /// Just a convenience property that returns the same value as .
+ ///
+ public TSubject Subject => Which;
///
/// Returns the single result of a prior assertion that is used to select a nested or collection item.
///
- ///
- /// Just a convenience property that returns the same value as .
- ///
- public TMatchedElement Subject => Which;
+ public TSubject Which
+ {
+ get
+ {
+ if (pathPostfix is not null and not "")
+ {
+ assertionChain.WithCallerPostfix(pathPostfix).ReuseOnce();
+ }
+
+ return getSubject.Value;
+ }
+ }
}
diff --git a/Src/FluentAssertions/AssertionExtensions.cs b/Src/FluentAssertions/AssertionExtensions.cs
index 0c69d58c41..47630b6d65 100644
--- a/Src/FluentAssertions/AssertionExtensions.cs
+++ b/Src/FluentAssertions/AssertionExtensions.cs
@@ -11,6 +11,7 @@
using System.Xml.Linq;
using FluentAssertions.Collections;
using FluentAssertions.Common;
+using FluentAssertions.Execution;
using FluentAssertions.Numeric;
using FluentAssertions.Primitives;
using FluentAssertions.Specialized;
@@ -149,7 +150,6 @@ public static ExecutionTime ExecutionTime(this Action action, StartTimer createT
///
/// Provides methods for asserting the execution time of an async action.
///
- /// An async action to measure the execution time of.
///
/// Returns an object for asserting that the execution time matches certain conditions.
///
@@ -167,7 +167,7 @@ public static ExecutionTime ExecutionTime(this Func action)
[Pure]
public static ExecutionTimeAssertions Should(this ExecutionTime executionTime)
{
- return new ExecutionTimeAssertions(executionTime);
+ return new ExecutionTimeAssertions(executionTime, AssertionChain.GetOrCreate());
}
///
@@ -177,7 +177,7 @@ public static ExecutionTimeAssertions Should(this ExecutionTime executionTime)
[Pure]
public static AssemblyAssertions Should([NotNull] this Assembly assembly)
{
- return new AssemblyAssertions(assembly);
+ return new AssemblyAssertions(assembly, AssertionChain.GetOrCreate());
}
///
@@ -187,7 +187,7 @@ public static AssemblyAssertions Should([NotNull] this Assembly assembly)
[Pure]
public static XDocumentAssertions Should([NotNull] this XDocument actualValue)
{
- return new XDocumentAssertions(actualValue);
+ return new XDocumentAssertions(actualValue, AssertionChain.GetOrCreate());
}
///
@@ -197,7 +197,7 @@ public static XDocumentAssertions Should([NotNull] this XDocument actualValue)
[Pure]
public static XElementAssertions Should([NotNull] this XElement actualValue)
{
- return new XElementAssertions(actualValue);
+ return new XElementAssertions(actualValue, AssertionChain.GetOrCreate());
}
///
@@ -207,7 +207,7 @@ public static XElementAssertions Should([NotNull] this XElement actualValue)
[Pure]
public static XAttributeAssertions Should([NotNull] this XAttribute actualValue)
{
- return new XAttributeAssertions(actualValue);
+ return new XAttributeAssertions(actualValue, AssertionChain.GetOrCreate());
}
///
@@ -217,9 +217,11 @@ public static XAttributeAssertions Should([NotNull] this XAttribute actualValue)
[Pure]
public static StreamAssertions Should([NotNull] this Stream actualValue)
{
- return new StreamAssertions(actualValue);
+ return new StreamAssertions(actualValue, AssertionChain.GetOrCreate());
}
+#if NET6_0_OR_GREATER || NETSTANDARD2_1
+
///
/// Returns an object that can be used to assert the
/// current .
@@ -227,9 +229,11 @@ public static StreamAssertions Should([NotNull] this Stream actualValue)
[Pure]
public static BufferedStreamAssertions Should([NotNull] this BufferedStream actualValue)
{
- return new BufferedStreamAssertions(actualValue);
+ return new BufferedStreamAssertions(actualValue, AssertionChain.GetOrCreate());
}
+#endif
+
///
/// Forces enumerating a collection. Should be used to assert that a method that uses the
/// keyword throws a particular exception.
@@ -284,7 +288,7 @@ private static void ForceEnumeration(T subject, Func enumerab
[Pure]
public static ObjectAssertions Should([NotNull] this object actualValue)
{
- return new ObjectAssertions(actualValue);
+ return new ObjectAssertions(actualValue, AssertionChain.GetOrCreate());
}
///
@@ -294,7 +298,7 @@ public static ObjectAssertions Should([NotNull] this object actualValue)
[Pure]
public static BooleanAssertions Should(this bool actualValue)
{
- return new BooleanAssertions(actualValue);
+ return new BooleanAssertions(actualValue, AssertionChain.GetOrCreate());
}
///
@@ -304,7 +308,7 @@ public static BooleanAssertions Should(this bool actualValue)
[Pure]
public static NullableBooleanAssertions Should(this bool? actualValue)
{
- return new NullableBooleanAssertions(actualValue);
+ return new NullableBooleanAssertions(actualValue, AssertionChain.GetOrCreate());
}
///
@@ -314,7 +318,7 @@ public static NullableBooleanAssertions Should(this bool? actualValue)
[Pure]
public static HttpResponseMessageAssertions Should([NotNull] this HttpResponseMessage actualValue)
{
- return new HttpResponseMessageAssertions(actualValue);
+ return new HttpResponseMessageAssertions(actualValue, AssertionChain.GetOrCreate());
}
///
@@ -324,7 +328,7 @@ public static HttpResponseMessageAssertions Should([NotNull] this HttpResponseMe
[Pure]
public static GuidAssertions Should(this Guid actualValue)
{
- return new GuidAssertions(actualValue);
+ return new GuidAssertions(actualValue, AssertionChain.GetOrCreate());
}
///
@@ -334,7 +338,7 @@ public static GuidAssertions Should(this Guid actualValue)
[Pure]
public static NullableGuidAssertions Should(this Guid? actualValue)
{
- return new NullableGuidAssertions(actualValue);
+ return new NullableGuidAssertions(actualValue, AssertionChain.GetOrCreate());
}
///
@@ -344,7 +348,7 @@ public static NullableGuidAssertions Should(this Guid? actualValue)
[Pure]
public static GenericCollectionAssertions Should([NotNull] this IEnumerable actualValue)
{
- return new GenericCollectionAssertions(actualValue);
+ return new GenericCollectionAssertions(actualValue, AssertionChain.GetOrCreate());
}
///
@@ -354,7 +358,7 @@ public static GenericCollectionAssertions Should([NotNull] this IEnumerabl
[Pure]
public static StringCollectionAssertions Should([NotNull] this IEnumerable @this)
{
- return new StringCollectionAssertions(@this);
+ return new StringCollectionAssertions(@this, AssertionChain.GetOrCreate());
}
///
@@ -365,7 +369,7 @@ public static StringCollectionAssertions Should([NotNull] this IEnumerable, TKey, TValue> Should(
[NotNull] this IDictionary actualValue)
{
- return new GenericDictionaryAssertions, TKey, TValue>(actualValue);
+ return new GenericDictionaryAssertions, TKey, TValue>(actualValue, AssertionChain.GetOrCreate());
}
///
@@ -376,7 +380,8 @@ public static GenericDictionaryAssertions, TKey, TValu
public static GenericDictionaryAssertions>, TKey, TValue> Should(
[NotNull] this IEnumerable> actualValue)
{
- return new GenericDictionaryAssertions>, TKey, TValue>(actualValue);
+ return new GenericDictionaryAssertions>, TKey, TValue>(actualValue,
+ AssertionChain.GetOrCreate());
}
///
@@ -388,7 +393,7 @@ public static GenericDictionaryAssertions Should>
{
- return new GenericDictionaryAssertions(actualValue);
+ return new GenericDictionaryAssertions(actualValue, AssertionChain.GetOrCreate());
}
///
@@ -398,7 +403,7 @@ public static GenericDictionaryAssertions Should
@@ -408,7 +413,7 @@ public static DateTimeAssertions Should(this DateTime actualValue)
[Pure]
public static DateTimeOffsetAssertions Should(this DateTimeOffset actualValue)
{
- return new DateTimeOffsetAssertions(actualValue);
+ return new DateTimeOffsetAssertions(actualValue, AssertionChain.GetOrCreate());
}
///
@@ -418,7 +423,7 @@ public static DateTimeOffsetAssertions Should(this DateTimeOffset actualValue)
[Pure]
public static NullableDateTimeAssertions Should(this DateTime? actualValue)
{
- return new NullableDateTimeAssertions(actualValue);
+ return new NullableDateTimeAssertions(actualValue, AssertionChain.GetOrCreate());
}
///
@@ -428,7 +433,7 @@ public static NullableDateTimeAssertions Should(this DateTime? actualValue)
[Pure]
public static NullableDateTimeOffsetAssertions Should(this DateTimeOffset? actualValue)
{
- return new NullableDateTimeOffsetAssertions(actualValue);
+ return new NullableDateTimeOffsetAssertions(actualValue, AssertionChain.GetOrCreate());
}
#if NET6_0_OR_GREATER
@@ -439,7 +444,7 @@ public static NullableDateTimeOffsetAssertions Should(this DateTimeOffset? actua
[Pure]
public static DateOnlyAssertions Should(this DateOnly actualValue)
{
- return new DateOnlyAssertions(actualValue);
+ return new DateOnlyAssertions(actualValue, AssertionChain.GetOrCreate());
}
///
@@ -449,7 +454,7 @@ public static DateOnlyAssertions Should(this DateOnly actualValue)
[Pure]
public static NullableDateOnlyAssertions Should(this DateOnly? actualValue)
{
- return new NullableDateOnlyAssertions(actualValue);
+ return new NullableDateOnlyAssertions(actualValue, AssertionChain.GetOrCreate());
}
///
@@ -459,7 +464,7 @@ public static NullableDateOnlyAssertions Should(this DateOnly? actualValue)
[Pure]
public static TimeOnlyAssertions Should(this TimeOnly actualValue)
{
- return new TimeOnlyAssertions(actualValue);
+ return new TimeOnlyAssertions(actualValue, AssertionChain.GetOrCreate());
}
///
@@ -469,7 +474,7 @@ public static TimeOnlyAssertions Should(this TimeOnly actualValue)
[Pure]
public static NullableTimeOnlyAssertions Should(this TimeOnly? actualValue)
{
- return new NullableTimeOnlyAssertions(actualValue);
+ return new NullableTimeOnlyAssertions(actualValue, AssertionChain.GetOrCreate());
}
#endif
@@ -481,7 +486,7 @@ public static NullableTimeOnlyAssertions Should(this TimeOnly? actualValue)
[Pure]
public static ComparableTypeAssertions Should([NotNull] this IComparable comparableValue)
{
- return new ComparableTypeAssertions(comparableValue);
+ return new ComparableTypeAssertions(comparableValue, AssertionChain.GetOrCreate());
}
///
@@ -491,7 +496,7 @@ public static ComparableTypeAssertions Should([NotNull] this IComparable Should(this int actualValue)
{
- return new Int32Assertions(actualValue);
+ return new Int32Assertions(actualValue, AssertionChain.GetOrCreate());
}
///
@@ -501,7 +506,7 @@ public static NumericAssertions Should(this int actualValue)
[Pure]
public static NullableNumericAssertions Should(this int? actualValue)
{
- return new NullableInt32Assertions(actualValue);
+ return new NullableInt32Assertions(actualValue, AssertionChain.GetOrCreate());
}
///
@@ -511,7 +516,7 @@ public static NullableNumericAssertions Should(this int? actualValue)
[Pure]
public static NumericAssertions Should(this uint actualValue)
{
- return new UInt32Assertions(actualValue);
+ return new UInt32Assertions(actualValue, AssertionChain.GetOrCreate());
}
///
@@ -521,7 +526,7 @@ public static NumericAssertions Should(this uint actualValue)
[Pure]
public static NullableNumericAssertions Should(this uint? actualValue)
{
- return new NullableUInt32Assertions(actualValue);
+ return new NullableUInt32Assertions(actualValue, AssertionChain.GetOrCreate());
}
///
@@ -531,7 +536,7 @@ public static NullableNumericAssertions Should(this uint? actualValue)
[Pure]
public static NumericAssertions Should(this decimal actualValue)
{
- return new DecimalAssertions(actualValue);
+ return new DecimalAssertions(actualValue, AssertionChain.GetOrCreate());
}
///
@@ -541,7 +546,7 @@ public static NumericAssertions Should(this decimal actualValue)
[Pure]
public static NullableNumericAssertions Should(this decimal? actualValue)
{
- return new NullableDecimalAssertions(actualValue);
+ return new NullableDecimalAssertions(actualValue, AssertionChain.GetOrCreate());
}
///
@@ -551,7 +556,7 @@ public static NullableNumericAssertions Should(this decimal? actualValu
[Pure]
public static NumericAssertions Should(this byte actualValue)
{
- return new ByteAssertions(actualValue);
+ return new ByteAssertions(actualValue, AssertionChain.GetOrCreate());
}
///
@@ -561,7 +566,7 @@ public static NumericAssertions Should(this byte actualValue)
[Pure]
public static NullableNumericAssertions Should(this byte? actualValue)
{
- return new NullableByteAssertions(actualValue);
+ return new NullableByteAssertions(actualValue, AssertionChain.GetOrCreate());
}
///
@@ -571,7 +576,7 @@ public static NullableNumericAssertions Should(this byte? actualValue)
[Pure]
public static NumericAssertions Should(this sbyte actualValue)
{
- return new SByteAssertions(actualValue);
+ return new SByteAssertions(actualValue, AssertionChain.GetOrCreate());
}
///
@@ -581,7 +586,7 @@ public static NumericAssertions Should(this sbyte actualValue)
[Pure]
public static NullableNumericAssertions Should(this sbyte? actualValue)
{
- return new NullableSByteAssertions(actualValue);
+ return new NullableSByteAssertions(actualValue, AssertionChain.GetOrCreate());
}
///
@@ -591,7 +596,7 @@ public static NullableNumericAssertions Should(this sbyte? actualValue)
[Pure]
public static NumericAssertions Should(this short actualValue)
{
- return new Int16Assertions(actualValue);
+ return new Int16Assertions(actualValue, AssertionChain.GetOrCreate());
}
///
@@ -601,7 +606,7 @@ public static NumericAssertions Should(this short actualValue)
[Pure]
public static NullableNumericAssertions Should(this short? actualValue)
{
- return new NullableInt16Assertions(actualValue);
+ return new NullableInt16Assertions(actualValue, AssertionChain.GetOrCreate());
}
///
@@ -611,7 +616,7 @@ public static NullableNumericAssertions Should(this short? actualValue)
[Pure]
public static NumericAssertions Should(this ushort actualValue)
{
- return new UInt16Assertions(actualValue);
+ return new UInt16Assertions(actualValue, AssertionChain.GetOrCreate());
}
///
@@ -621,7 +626,7 @@ public static NumericAssertions Should(this ushort actualValue)
[Pure]
public static NullableNumericAssertions Should(this ushort? actualValue)
{
- return new NullableUInt16Assertions(actualValue);
+ return new NullableUInt16Assertions(actualValue, AssertionChain.GetOrCreate());
}
///
@@ -631,7 +636,7 @@ public static NullableNumericAssertions Should(this ushort? actualValue)
[Pure]
public static NumericAssertions Should(this long actualValue)
{
- return new Int64Assertions(actualValue);
+ return new Int64Assertions(actualValue, AssertionChain.GetOrCreate());
}
///
@@ -641,7 +646,7 @@ public static NumericAssertions Should(this long actualValue)
[Pure]
public static NullableNumericAssertions Should(this long? actualValue)
{
- return new NullableInt64Assertions(actualValue);
+ return new NullableInt64Assertions(actualValue, AssertionChain.GetOrCreate());
}
///
@@ -651,7 +656,7 @@ public static NullableNumericAssertions Should(this long? actualValue)
[Pure]
public static NumericAssertions Should(this ulong actualValue)
{
- return new UInt64Assertions(actualValue);
+ return new UInt64Assertions(actualValue, AssertionChain.GetOrCreate());
}
///
@@ -661,7 +666,7 @@ public static NumericAssertions Should(this ulong actualValue)
[Pure]
public static NullableNumericAssertions Should(this ulong? actualValue)
{
- return new NullableUInt64Assertions(actualValue);
+ return new NullableUInt64Assertions(actualValue, AssertionChain.GetOrCreate());
}
///
@@ -671,7 +676,7 @@ public static NullableNumericAssertions Should(this ulong? actualValue)
[Pure]
public static NumericAssertions Should(this float actualValue)
{
- return new SingleAssertions(actualValue);
+ return new SingleAssertions(actualValue, AssertionChain.GetOrCreate());
}
///
@@ -681,7 +686,7 @@ public static NumericAssertions Should(this float actualValue)
[Pure]
public static NullableNumericAssertions Should(this float? actualValue)
{
- return new NullableSingleAssertions(actualValue);
+ return new NullableSingleAssertions(actualValue, AssertionChain.GetOrCreate());
}
///
@@ -691,7 +696,7 @@ public static NullableNumericAssertions Should(this float? actualValue)
[Pure]
public static NumericAssertions Should(this double actualValue)
{
- return new DoubleAssertions(actualValue);
+ return new DoubleAssertions(actualValue, AssertionChain.GetOrCreate());
}
///
@@ -701,7 +706,7 @@ public static NumericAssertions Should(this double actualValue)
[Pure]
public static NullableNumericAssertions Should(this double? actualValue)
{
- return new NullableDoubleAssertions(actualValue);
+ return new NullableDoubleAssertions(actualValue, AssertionChain.GetOrCreate());
}
///
@@ -711,7 +716,7 @@ public static NullableNumericAssertions Should(this double? actualValue)
[Pure]
public static StringAssertions Should([NotNull] this string actualValue)
{
- return new StringAssertions(actualValue);
+ return new StringAssertions(actualValue, AssertionChain.GetOrCreate());
}
///
@@ -721,7 +726,7 @@ public static StringAssertions Should([NotNull] this string actualValue)
[Pure]
public static SimpleTimeSpanAssertions Should(this TimeSpan actualValue)
{
- return new SimpleTimeSpanAssertions(actualValue);
+ return new SimpleTimeSpanAssertions(actualValue, AssertionChain.GetOrCreate());
}
///
@@ -731,7 +736,7 @@ public static SimpleTimeSpanAssertions Should(this TimeSpan actualValue)
[Pure]
public static NullableSimpleTimeSpanAssertions Should(this TimeSpan? actualValue)
{
- return new NullableSimpleTimeSpanAssertions(actualValue);
+ return new NullableSimpleTimeSpanAssertions(actualValue, AssertionChain.GetOrCreate());
}
///
@@ -741,7 +746,7 @@ public static NullableSimpleTimeSpanAssertions Should(this TimeSpan? actualValue
[Pure]
public static TypeAssertions Should([NotNull] this Type subject)
{
- return new TypeAssertions(subject);
+ return new TypeAssertions(subject, AssertionChain.GetOrCreate());
}
///
@@ -754,7 +759,7 @@ public static TypeSelectorAssertions Should(this TypeSelector typeSelector)
{
Guard.ThrowIfArgumentIsNull(typeSelector);
- return new TypeSelectorAssertions(typeSelector.ToArray());
+ return new TypeSelectorAssertions(AssertionChain.GetOrCreate(), typeSelector.ToArray());
}
///
@@ -765,7 +770,7 @@ public static TypeSelectorAssertions Should(this TypeSelector typeSelector)
[Pure]
public static ConstructorInfoAssertions Should([NotNull] this ConstructorInfo constructorInfo)
{
- return new ConstructorInfoAssertions(constructorInfo);
+ return new ConstructorInfoAssertions(constructorInfo, AssertionChain.GetOrCreate());
}
///
@@ -775,7 +780,7 @@ public static ConstructorInfoAssertions Should([NotNull] this ConstructorInfo co
[Pure]
public static MethodInfoAssertions Should([NotNull] this MethodInfo methodInfo)
{
- return new MethodInfoAssertions(methodInfo);
+ return new MethodInfoAssertions(methodInfo, AssertionChain.GetOrCreate());
}
///
@@ -789,7 +794,7 @@ public static MethodInfoSelectorAssertions Should(this MethodInfoSelector method
{
Guard.ThrowIfArgumentIsNull(methodSelector);
- return new MethodInfoSelectorAssertions(methodSelector.ToArray());
+ return new MethodInfoSelectorAssertions(AssertionChain.GetOrCreate(), methodSelector.ToArray());
}
///
@@ -800,7 +805,7 @@ public static MethodInfoSelectorAssertions Should(this MethodInfoSelector method
[Pure]
public static PropertyInfoAssertions Should([NotNull] this PropertyInfo propertyInfo)
{
- return new PropertyInfoAssertions(propertyInfo);
+ return new PropertyInfoAssertions(propertyInfo, AssertionChain.GetOrCreate());
}
///
@@ -814,7 +819,7 @@ public static PropertyInfoSelectorAssertions Should(this PropertyInfoSelector pr
{
Guard.ThrowIfArgumentIsNull(propertyInfoSelector);
- return new PropertyInfoSelectorAssertions(propertyInfoSelector.ToArray());
+ return new PropertyInfoSelectorAssertions(AssertionChain.GetOrCreate(), propertyInfoSelector.ToArray());
}
///
@@ -824,7 +829,7 @@ public static PropertyInfoSelectorAssertions Should(this PropertyInfoSelector pr
[Pure]
public static ActionAssertions Should([NotNull] this Action action)
{
- return new ActionAssertions(action, Extractor);
+ return new ActionAssertions(action, Extractor, AssertionChain.GetOrCreate());
}
///
@@ -834,7 +839,7 @@ public static ActionAssertions Should([NotNull] this Action action)
[Pure]
public static NonGenericAsyncFunctionAssertions Should([NotNull] this Func action)
{
- return new NonGenericAsyncFunctionAssertions(action, Extractor);
+ return new NonGenericAsyncFunctionAssertions(action, Extractor, AssertionChain.GetOrCreate());
}
///
@@ -844,7 +849,7 @@ public static NonGenericAsyncFunctionAssertions Should([NotNull] this Func
[Pure]
public static GenericAsyncFunctionAssertions Should([NotNull] this Func> action)
{
- return new GenericAsyncFunctionAssertions(action, Extractor);
+ return new GenericAsyncFunctionAssertions(action, Extractor, AssertionChain.GetOrCreate());
}
///
@@ -854,7 +859,7 @@ public static GenericAsyncFunctionAssertions Should([NotNull] this Func Should([NotNull] this Func func)
{
- return new FunctionAssertions(func, Extractor);
+ return new FunctionAssertions(func, Extractor, AssertionChain.GetOrCreate());
}
///
@@ -864,7 +869,7 @@ public static FunctionAssertions Should([NotNull] this Func func)
[Pure]
public static TaskCompletionSourceAssertions Should(this TaskCompletionSource tcs)
{
- return new TaskCompletionSourceAssertions(tcs);
+ return new TaskCompletionSourceAssertions(tcs, AssertionChain.GetOrCreate());
}
#if !NETSTANDARD2_0
@@ -906,7 +911,7 @@ public static IMonitor Monitor(this T eventSource, Action : GenericCollectionAssertions, T, GenericCollectionAssertions>
{
- public GenericCollectionAssertions(IEnumerable actualValue)
- : base(actualValue)
+ public GenericCollectionAssertions(IEnumerable actualValue, AssertionChain assertionChain)
+ : base(actualValue, assertionChain)
{
}
}
@@ -28,22 +28,26 @@ public class GenericCollectionAssertions
: GenericCollectionAssertions>
where TCollection : IEnumerable
{
- public GenericCollectionAssertions(TCollection actualValue)
- : base(actualValue)
+ public GenericCollectionAssertions(TCollection actualValue, AssertionChain assertionChain)
+ : base(actualValue, assertionChain)
{
}
}
#pragma warning disable CS0659, S1206 // Ignore not overriding Object.GetHashCode()
#pragma warning disable CA1065 // Ignore throwing NotSupportedException from Equals
+
[DebuggerNonUserCode]
public class GenericCollectionAssertions : ReferenceTypeAssertions
where TCollection : IEnumerable
where TAssertions : GenericCollectionAssertions
{
- public GenericCollectionAssertions(TCollection actualValue)
- : base(actualValue)
+ private readonly AssertionChain assertionChain;
+
+ public GenericCollectionAssertions(TCollection actualValue, AssertionChain assertionChain)
+ : base(actualValue, assertionChain)
{
+ this.assertionChain = assertionChain;
}
///
@@ -63,9 +67,10 @@ public GenericCollectionAssertions(TCollection actualValue)
/// Zero or more objects to format using the placeholders in .
///
public AndWhichConstraint> AllBeAssignableTo(
- [StringSyntax("CompositeFormat")] string because = "", params object[] becauseArgs)
+ [StringSyntax("CompositeFormat")] string because = "",
+ params object[] becauseArgs)
{
- bool success = Execute.Assertion
+ assertionChain
.BecauseOf(because, becauseArgs)
.ForCondition(Subject is not null)
.FailWith("Expected type to be {0}{reason}, but found {context:the collection} is .",
@@ -73,18 +78,16 @@ public AndWhichConstraint> AllBeAssignabl
IEnumerable matches = [];
- if (success)
+ if (assertionChain.Succeeded)
{
- Execute.Assertion
+ assertionChain
.BecauseOf(because, becauseArgs)
- .WithExpectation("Expected type to be {0}{reason}, ", typeof(TExpectation).FullName)
- .ForCondition(Subject!.All(x => x is not null))
- .FailWith("but found a null element.")
- .Then
- .ForCondition(Subject.All(x => typeof(TExpectation).IsAssignableFrom(GetType(x))))
- .FailWith("but found {0}.", () => $"[{string.Join(", ", Subject.Select(x => GetType(x).FullName))}]")
- .Then
- .ClearExpectation();
+ .WithExpectation("Expected type to be {0}{reason}, ", typeof(TExpectation).FullName, chain => chain
+ .ForCondition(Subject!.All(x => x is not null))
+ .FailWith("but found a null element.")
+ .Then
+ .ForCondition(Subject.All(x => typeof(TExpectation).IsAssignableFrom(GetType(x))))
+ .FailWith("but found {0}.", () => $"[{string.Join(", ", Subject.Select(x => GetType(x).FullName))}]"));
matches = Subject.OfType();
}
@@ -109,20 +112,18 @@ public AndConstraint AllBeAssignableTo(Type expectedType,
{
Guard.ThrowIfArgumentIsNull(expectedType);
- Execute.Assertion
+ assertionChain
.BecauseOf(because, becauseArgs)
- .WithExpectation("Expected type to be {0}{reason}, ", expectedType.FullName)
- .Given(() => Subject)
- .ForCondition(subject => subject is not null)
- .FailWith("but found {context:collection} is .")
- .Then
- .ForCondition(subject => subject.All(x => x is not null))
- .FailWith("but found a null element.")
- .Then
- .ForCondition(subject => subject.All(x => expectedType.IsAssignableFrom(GetType(x))))
- .FailWith("but found {0}.", subject => $"[{string.Join(", ", subject.Select(x => GetType(x).FullName))}]")
- .Then
- .ClearExpectation();
+ .WithExpectation("Expected type to be {0}{reason}, ", expectedType.FullName, chain => chain
+ .Given(() => Subject)
+ .ForCondition(subject => subject is not null)
+ .FailWith("but found {context:collection} is .")
+ .Then
+ .ForCondition(subject => subject.All(x => x is not null))
+ .FailWith("but found a null element.")
+ .Then
+ .ForCondition(subject => subject.All(x => expectedType.IsAssignableFrom(GetType(x))))
+ .FailWith("but found {0}.", subject => $"[{string.Join(", ", subject.Select(x => GetType(x).FullName))}]"));
return new AndConstraint((TAssertions)this);
}
@@ -180,7 +181,8 @@ public AndConstraint AllBeEquivalentTo(TExpectation e
/// is .
public AndConstraint AllBeEquivalentTo(TExpectation expectation,
Func, EquivalencyOptions> config,
- [StringSyntax("CompositeFormat")] string because = "", params object[] becauseArgs)
+ [StringSyntax("CompositeFormat")] string because = "",
+ params object[] becauseArgs)
{
Guard.ThrowIfArgumentIsNull(config);
@@ -210,9 +212,10 @@ public AndConstraint AllBeEquivalentTo(TExpectation e
/// Zero or more objects to format using the placeholders in .
///
public AndWhichConstraint> AllBeOfType(
- [StringSyntax("CompositeFormat")] string because = "", params object[] becauseArgs)
+ [StringSyntax("CompositeFormat")] string because = "",
+ params object[] becauseArgs)
{
- bool success = Execute.Assertion
+ assertionChain
.BecauseOf(because, becauseArgs)
.ForCondition(Subject is not null)
.FailWith("Expected type to be {0}{reason}, but found {context:collection} is .",
@@ -220,18 +223,16 @@ public AndWhichConstraint> AllBeOfType matches = [];
- if (success)
+ if (assertionChain.Succeeded)
{
- Execute.Assertion
+ assertionChain
.BecauseOf(because, becauseArgs)
- .WithExpectation("Expected type to be {0}{reason}, ", typeof(TExpectation).FullName)
- .ForCondition(Subject!.All(x => x is not null))
- .FailWith("but found a null element.")
- .Then
- .ForCondition(Subject.All(x => typeof(TExpectation) == GetType(x)))
- .FailWith("but found {0}.", () => $"[{string.Join(", ", Subject.Select(x => GetType(x).FullName))}]")
- .Then
- .ClearExpectation();
+ .WithExpectation("Expected type to be {0}{reason}, ", typeof(TExpectation).FullName, chain => chain
+ .ForCondition(Subject!.All(x => x is not null))
+ .FailWith("but found a null element.")
+ .Then
+ .ForCondition(Subject.All(x => typeof(TExpectation) == GetType(x)))
+ .FailWith("but found {0}.", () => $"[{string.Join(", ", Subject.Select(x => GetType(x).FullName))}]"));
matches = Subject.OfType();
}
@@ -251,25 +252,23 @@ public AndWhichConstraint> AllBeOfType.
///
/// is .
- public AndConstraint AllBeOfType(Type expectedType,
- [StringSyntax("CompositeFormat")] string because = "", params object[] becauseArgs)
+ public AndConstraint AllBeOfType(Type expectedType, [StringSyntax("CompositeFormat")] string because = "",
+ params object[] becauseArgs)
{
Guard.ThrowIfArgumentIsNull(expectedType);
- Execute.Assertion
+ assertionChain
.BecauseOf(because, becauseArgs)
- .WithExpectation("Expected type to be {0}{reason}, ", expectedType.FullName)
- .Given(() => Subject)
- .ForCondition(subject => subject is not null)
- .FailWith("but found {context:collection} is .")
- .Then
- .ForCondition(subject => subject.All(x => x is not null))
- .FailWith("but found a null element.")
- .Then
- .ForCondition(subject => subject.All(x => expectedType == GetType(x)))
- .FailWith("but found {0}.", subject => $"[{string.Join(", ", subject.Select(x => GetType(x).FullName))}]")
- .Then
- .ClearExpectation();
+ .WithExpectation("Expected type to be {0}{reason}, ", expectedType.FullName, chain => chain
+ .Given(() => Subject)
+ .ForCondition(subject => subject is not null)
+ .FailWith("but found {context:collection} is .")
+ .Then
+ .ForCondition(subject => subject.All(x => x is not null))
+ .FailWith("but found a null element.")
+ .Then
+ .ForCondition(subject => subject.All(x => expectedType == GetType(x)))
+ .FailWith("but found {0}.", subject => $"[{string.Join(", ", subject.Select(x => GetType(x).FullName))}]"));
return new AndConstraint((TAssertions)this);
}
@@ -287,17 +286,16 @@ public AndConstraint AllBeOfType(Type expectedType,
public AndConstraint BeEmpty([StringSyntax("CompositeFormat")] string because = "", params object[] becauseArgs)
{
var singleItemArray = Subject?.Take(1).ToArray();
- Execute.Assertion
+
+ assertionChain
.BecauseOf(because, becauseArgs)
- .WithExpectation("Expected {context:collection} to be empty{reason}, ")
- .Given(() => singleItemArray)
- .ForCondition(subject => subject is not null)
- .FailWith("but found .")
- .Then
- .ForCondition(subject => subject.Length == 0)
- .FailWith("but found at least one item {0}.", singleItemArray)
- .Then
- .ClearExpectation();
+ .WithExpectation("Expected {context:collection} to be empty{reason}, ", chain => chain
+ .Given(() => singleItemArray)
+ .ForCondition(subject => subject is not null)
+ .FailWith("but found .")
+ .Then
+ .ForCondition(subject => subject.Length == 0)
+ .FailWith("but found at least one item {0}.", singleItemArray));
return new AndConstraint((TAssertions)this);
}
@@ -355,7 +353,8 @@ public AndConstraint BeEquivalentTo(IEnumerable is .
public AndConstraint BeEquivalentTo(IEnumerable expectation,
Func, EquivalencyOptions> config,
- [StringSyntax("CompositeFormat")] string because = "", params object[] becauseArgs)
+ [StringSyntax("CompositeFormat")] string because = "",
+ params object[] becauseArgs)
{
Guard.ThrowIfArgumentIsNull(config);
@@ -363,7 +362,8 @@ public AndConstraint BeEquivalentTo(IEnumerable()).AsCollection();
var context =
- new EquivalencyValidationContext(Node.From>(() => AssertionScope.Current.CallerIdentity),
+ new EquivalencyValidationContext(
+ Node.From>(() => CallerIdentifier.DetermineCallerIdentity()),
options)
{
Reason = new Reason(because, becauseArgs),
@@ -425,8 +425,7 @@ public AndConstraint> BeInAscendingOrder
/// is .
public AndConstraint> BeInAscendingOrder(
- IComparer comparer,
- [StringSyntax("CompositeFormat")] string because = "", params object[] becauseArgs)
+ IComparer comparer, [StringSyntax("CompositeFormat")] string because = "", params object[] becauseArgs)
{
Guard.ThrowIfArgumentIsNull(comparer, nameof(comparer),
"Cannot assert collection ordering without specifying a comparer.");
@@ -457,7 +456,8 @@ public AndConstraint> BeInAscendingOrder(
/// is .
public AndConstraint> BeInAscendingOrder(
Expression> propertyExpression, IComparer