diff --git a/README.md b/README.md
index f541c00..a6872c4 100644
--- a/README.md
+++ b/README.md
@@ -106,8 +106,8 @@ await Expect.That(request).HasHeader("Cache-Control").WithValue("max-age=0");
```text title="Failure message"
Expected that request
-has a `Cache-Control` header whose value is equal to "max-age=0",
-but the value was "no-cache", which differs at index 0:
+has a "Cache-Control" header whose value is equal to "max-age=0",
+but it had header value "no-cache", which differs at index 0:
↓ (actual)
"no-cache"
"max-age=0"
@@ -233,7 +233,7 @@ await Expect.That(response).HasContentType("text/plain");
```text title="Failure message"
Expected that response
has a `Content-Type` header equal to "text/plain",
-but it was "application/json", which differs at index 0:
+but it had content type "application/json", which differs at index 0:
↓ (actual)
"application/json"
"text/plain"
diff --git a/Source/aweXpect.Web/Helpers/ThrowHelper.cs b/Source/aweXpect.Web/Helpers/ThrowHelper.cs
index 9a669db..bbd0fe4 100644
--- a/Source/aweXpect.Web/Helpers/ThrowHelper.cs
+++ b/Source/aweXpect.Web/Helpers/ThrowHelper.cs
@@ -12,4 +12,17 @@ public static void ThrowIfNull(object? value, string paramName)
throw Tracing.WriteException(new ArgumentNullException(paramName, $"The '{paramName}' cannot be null."));
}
}
+
+ ///
+ /// Rejects the when it , because the later
+ /// value would silently replace the earlier one.
+ ///
+ public static void ThrowIfOptionIsAlreadySpecified(bool isAlreadySpecified, string option)
+ {
+ if (isAlreadySpecified)
+ {
+ throw Tracing.WriteException(new InvalidOperationException(
+ $"{option} cannot be specified more than once."));
+ }
+ }
}
diff --git a/Source/aweXpect.Web/ThatHttpRequestMessage.HasContent.cs b/Source/aweXpect.Web/ThatHttpRequestMessage.HasContent.cs
index 8d67fe0..bc01789 100644
--- a/Source/aweXpect.Web/ThatHttpRequestMessage.HasContent.cs
+++ b/Source/aweXpect.Web/ThatHttpRequestMessage.HasContent.cs
@@ -93,7 +93,7 @@ public async ValueTask IsMetBy(
}
protected override void AppendNormalExpectation(StringBuilder stringBuilder, string? indentation = null)
- => stringBuilder.Append("has a string content ")
+ => stringBuilder.Append(Grammars.Verb("has a string content ", "have a string content "))
.Append(options.GetExpectation(expected, ExpectationGrammars.None));
protected override void AppendNormalResult(StringBuilder stringBuilder, string? indentation = null)
@@ -104,12 +104,12 @@ protected override void AppendNormalResult(StringBuilder stringBuilder, string?
}
else
{
- stringBuilder.Append(options.GetExtendedFailure(It, Grammars, _message, expected));
+ stringBuilder.Append(options.GetExtendedMemberFailure(It, "string content", Grammars, _message, expected));
}
}
protected override void AppendNegatedExpectation(StringBuilder stringBuilder, string? indentation = null)
- => stringBuilder.Append("does not have a string content ")
+ => stringBuilder.Append(Grammars.Verb("does not have a string content ", "do not have a string content "))
.Append(options.GetExpectation(expected, ExpectationGrammars.None));
protected override void AppendNegatedResult(StringBuilder stringBuilder, string? indentation = null)
diff --git a/Source/aweXpect.Web/ThatHttpRequestMessage.HasHeader.cs b/Source/aweXpect.Web/ThatHttpRequestMessage.HasHeader.cs
index cd35a0a..4c7f4f9 100644
--- a/Source/aweXpect.Web/ThatHttpRequestMessage.HasHeader.cs
+++ b/Source/aweXpect.Web/ThatHttpRequestMessage.HasHeader.cs
@@ -76,19 +76,28 @@ public ConstraintResult IsMetBy(HttpRequestMessage? actual)
}
protected override void AppendNormalExpectation(StringBuilder stringBuilder, string? indentation = null)
- => stringBuilder.Append("has ").Append(expected.IndefiniteArticleForHeader()).Append(" `").Append(expected)
- .Append("` header");
+ {
+ stringBuilder.Append(Grammars.Verb("has ", "have ")).Append(expected.IndefiniteArticleForHeader()).Append(' ');
+ Formatter.Format(stringBuilder, expected);
+ stringBuilder.Append(" header");
+ }
protected override void AppendNormalResult(StringBuilder stringBuilder, string? indentation = null)
=> stringBuilder.Append(It).Append(" did not contain the expected header");
protected override void AppendNegatedExpectation(StringBuilder stringBuilder, string? indentation = null)
- => stringBuilder.Append("does not have ").Append(expected.IndefiniteArticleForHeader()).Append(" `")
- .Append(expected).Append("` header");
+ {
+ stringBuilder.Append(Grammars.Verb("does not have ", "do not have "))
+ .Append(expected.IndefiniteArticleForHeader()).Append(' ');
+ Formatter.Format(stringBuilder, expected);
+ stringBuilder.Append(" header");
+ }
protected override void AppendNegatedResult(StringBuilder stringBuilder, string? indentation = null)
{
- stringBuilder.Append(It).Append(" did contain the `").Append(expected).Append("` header: ");
+ stringBuilder.Append(It).Append(" did contain the ");
+ Formatter.Format(stringBuilder, expected);
+ stringBuilder.Append(" header: ");
Formatter.Format(stringBuilder, _foundHeader);
}
}
diff --git a/Source/aweXpect.Web/ThatHttpRequestMessage.HasMethod.cs b/Source/aweXpect.Web/ThatHttpRequestMessage.HasMethod.cs
index 28d6b34..b0cdb4e 100644
--- a/Source/aweXpect.Web/ThatHttpRequestMessage.HasMethod.cs
+++ b/Source/aweXpect.Web/ThatHttpRequestMessage.HasMethod.cs
@@ -57,7 +57,11 @@ public override string ToString()
=> $"has {Article} {expected} method";
protected override void AppendNormalExpectation(StringBuilder stringBuilder, string? indentation = null)
- => stringBuilder.Append("has ").Append(Article).Append(' ').Append(expected).Append(" method");
+ {
+ stringBuilder.Append(Grammars.Verb("has ", "have ")).Append(Article).Append(' ');
+ Formatter.Format(stringBuilder, expected);
+ stringBuilder.Append(" method");
+ }
protected override void AppendNormalResult(StringBuilder stringBuilder, string? indentation = null)
{
@@ -66,7 +70,11 @@ protected override void AppendNormalResult(StringBuilder stringBuilder, string?
}
protected override void AppendNegatedExpectation(StringBuilder stringBuilder, string? indentation = null)
- => stringBuilder.Append("does not have ").Append(Article).Append(' ').Append(expected).Append(" method");
+ {
+ stringBuilder.Append(Grammars.Verb("does not have ", "do not have ")).Append(Article).Append(' ');
+ Formatter.Format(stringBuilder, expected);
+ stringBuilder.Append(" method");
+ }
protected override void AppendNegatedResult(StringBuilder stringBuilder, string? indentation = null)
=> stringBuilder.Append(It).Append(" had");
diff --git a/Source/aweXpect.Web/ThatHttpRequestMessage.HasRequestUri.cs b/Source/aweXpect.Web/ThatHttpRequestMessage.HasRequestUri.cs
index 6e51d4b..636caf2 100644
--- a/Source/aweXpect.Web/ThatHttpRequestMessage.HasRequestUri.cs
+++ b/Source/aweXpect.Web/ThatHttpRequestMessage.HasRequestUri.cs
@@ -58,6 +58,7 @@ private sealed class HasRequestUriConstraint(
: ConstraintResult.WithNotNullValue(it, grammars),
IValueConstraint
{
+ private readonly StringEqualityOptions _options = new StringEqualityOptions(nameof(expected)).IgnoringCase();
private string? _requestUri;
public ConstraintResult IsMetBy(HttpRequestMessage? actual)
@@ -81,20 +82,15 @@ public ConstraintResult IsMetBy(HttpRequestMessage? actual)
}
protected override void AppendNormalExpectation(StringBuilder stringBuilder, string? indentation = null)
- {
- stringBuilder.Append("has a request URI equal to ");
- Formatter.Format(stringBuilder, expected);
- }
+ => stringBuilder.Append(Grammars.Verb("has a request URI ", "have a request URI "))
+ .Append(_options.GetExpectation(expected, ExpectationGrammars.None));
protected override void AppendNormalResult(StringBuilder stringBuilder, string? indentation = null)
- => stringBuilder.Append(new StringEqualityOptions(nameof(expected)).IgnoringCase()
- .GetExtendedFailure(It, Grammars, _requestUri, expected));
+ => stringBuilder.Append(_options.GetExtendedMemberFailure(It, "request URI", Grammars, _requestUri, expected));
protected override void AppendNegatedExpectation(StringBuilder stringBuilder, string? indentation = null)
- {
- stringBuilder.Append("does not have a request URI equal to ");
- Formatter.Format(stringBuilder, expected);
- }
+ => stringBuilder.Append(Grammars.Verb("does not have a request URI ", "do not have a request URI "))
+ .Append(_options.GetExpectation(expected, ExpectationGrammars.None));
protected override void AppendNegatedResult(StringBuilder stringBuilder, string? indentation = null)
=> stringBuilder.Append(It).Append(" had");
diff --git a/Source/aweXpect.Web/ThatHttpResponseMessage.HasContent.cs b/Source/aweXpect.Web/ThatHttpResponseMessage.HasContent.cs
index 5fc15a3..0962b77 100644
--- a/Source/aweXpect.Web/ThatHttpResponseMessage.HasContent.cs
+++ b/Source/aweXpect.Web/ThatHttpResponseMessage.HasContent.cs
@@ -87,7 +87,7 @@ public async ValueTask IsMetBy(
}
protected override void AppendNormalExpectation(StringBuilder stringBuilder, string? indentation = null)
- => stringBuilder.Append("has a string content ")
+ => stringBuilder.Append(Grammars.Verb("has a string content ", "have a string content "))
.Append(options.GetExpectation(expected, ExpectationGrammars.None));
protected override void AppendNormalResult(StringBuilder stringBuilder, string? indentation = null)
@@ -98,12 +98,12 @@ protected override void AppendNormalResult(StringBuilder stringBuilder, string?
}
else
{
- stringBuilder.Append(options.GetExtendedFailure(It, Grammars, _message, expected));
+ stringBuilder.Append(options.GetExtendedMemberFailure(It, "string content", Grammars, _message, expected));
}
}
protected override void AppendNegatedExpectation(StringBuilder stringBuilder, string? indentation = null)
- => stringBuilder.Append("does not have a string content ")
+ => stringBuilder.Append(Grammars.Verb("does not have a string content ", "do not have a string content "))
.Append(options.GetExpectation(expected, ExpectationGrammars.None));
protected override void AppendNegatedResult(StringBuilder stringBuilder, string? indentation = null)
diff --git a/Source/aweXpect.Web/ThatHttpResponseMessage.HasContentType.cs b/Source/aweXpect.Web/ThatHttpResponseMessage.HasContentType.cs
index e9b56b9..858f91e 100644
--- a/Source/aweXpect.Web/ThatHttpResponseMessage.HasContentType.cs
+++ b/Source/aweXpect.Web/ThatHttpResponseMessage.HasContentType.cs
@@ -72,7 +72,7 @@ public async ValueTask IsMetBy(HttpResponseMessage? actual, Ca
}
protected override void AppendNormalExpectation(StringBuilder stringBuilder, string? indentation = null)
- => stringBuilder.Append("has a `Content-Type` header ")
+ => stringBuilder.Append(Grammars.Verb("has a `Content-Type` header ", "have a `Content-Type` header "))
.Append(options.GetExpectation(expected, Grammars));
protected override void AppendNormalResult(StringBuilder stringBuilder, string? indentation = null)
@@ -83,12 +83,12 @@ protected override void AppendNormalResult(StringBuilder stringBuilder, string?
}
else
{
- stringBuilder.Append(options.GetExtendedFailure(It, Grammars, _contentType, expected));
+ stringBuilder.Append(options.GetExtendedMemberFailure(It, "content type", Grammars, _contentType, expected));
}
}
protected override void AppendNegatedExpectation(StringBuilder stringBuilder, string? indentation = null)
- => stringBuilder.Append("does not have a `Content-Type` header ")
+ => stringBuilder.Append(Grammars.Verb("does not have a `Content-Type` header ", "do not have a `Content-Type` header "))
.Append(options.GetExpectation(expected, Grammars.Negate()));
protected override void AppendNegatedResult(StringBuilder stringBuilder, string? indentation = null)
diff --git a/Source/aweXpect.Web/ThatHttpResponseMessage.HasHeader.cs b/Source/aweXpect.Web/ThatHttpResponseMessage.HasHeader.cs
index 847d517..2ae5b0f 100644
--- a/Source/aweXpect.Web/ThatHttpResponseMessage.HasHeader.cs
+++ b/Source/aweXpect.Web/ThatHttpResponseMessage.HasHeader.cs
@@ -76,19 +76,28 @@ public ConstraintResult IsMetBy(HttpResponseMessage? actual)
}
protected override void AppendNormalExpectation(StringBuilder stringBuilder, string? indentation = null)
- => stringBuilder.Append("has ").Append(expected.IndefiniteArticleForHeader()).Append(" `").Append(expected)
- .Append("` header");
+ {
+ stringBuilder.Append(Grammars.Verb("has ", "have ")).Append(expected.IndefiniteArticleForHeader()).Append(' ');
+ Formatter.Format(stringBuilder, expected);
+ stringBuilder.Append(" header");
+ }
protected override void AppendNormalResult(StringBuilder stringBuilder, string? indentation = null)
=> stringBuilder.Append(It).Append(" did not contain the expected header");
protected override void AppendNegatedExpectation(StringBuilder stringBuilder, string? indentation = null)
- => stringBuilder.Append("does not have ").Append(expected.IndefiniteArticleForHeader()).Append(" `")
- .Append(expected).Append("` header");
+ {
+ stringBuilder.Append(Grammars.Verb("does not have ", "do not have "))
+ .Append(expected.IndefiniteArticleForHeader()).Append(' ');
+ Formatter.Format(stringBuilder, expected);
+ stringBuilder.Append(" header");
+ }
protected override void AppendNegatedResult(StringBuilder stringBuilder, string? indentation = null)
{
- stringBuilder.Append(It).Append(" did contain the `").Append(expected).Append("` header: ");
+ stringBuilder.Append(It).Append(" did contain the ");
+ Formatter.Format(stringBuilder, expected);
+ stringBuilder.Append(" header: ");
Formatter.Format(stringBuilder, _foundHeader);
}
}
diff --git a/Source/aweXpect.Web/ThatHttpResponseMessage.HasProblemDetailsContent.cs b/Source/aweXpect.Web/ThatHttpResponseMessage.HasProblemDetailsContent.cs
index 4534d9b..98a823a 100644
--- a/Source/aweXpect.Web/ThatHttpResponseMessage.HasProblemDetailsContent.cs
+++ b/Source/aweXpect.Web/ThatHttpResponseMessage.HasProblemDetailsContent.cs
@@ -210,13 +210,14 @@ private static string DescribeKind(JsonValueKind kind)
protected override void AppendNormalExpectation(StringBuilder stringBuilder, string? indentation = null)
{
+ stringBuilder.Append(Grammars.Verb("has a ProblemDetails content with ", "have a ProblemDetails content with "));
if (expectedType is null)
{
- stringBuilder.Append("has a ProblemDetails content with any type");
+ stringBuilder.Append("any type");
}
else
{
- stringBuilder.Append("has a ProblemDetails content with type ");
+ stringBuilder.Append("type ");
Formatter.Format(stringBuilder, expectedType);
stringBuilder.Append(typeOptions);
}
@@ -240,13 +241,10 @@ private void AppendParseError(StringBuilder stringBuilder)
protected override void AppendNegatedExpectation(StringBuilder stringBuilder, string? indentation = null)
{
- if (expectedType is null)
- {
- stringBuilder.Append("does not have a ProblemDetails content");
- }
- else
+ stringBuilder.Append(Grammars.Verb("does not have a ProblemDetails content", "do not have a ProblemDetails content"));
+ if (expectedType is not null)
{
- stringBuilder.Append("does not have a ProblemDetails content with type ");
+ stringBuilder.Append(" with type ");
Formatter.Format(stringBuilder, expectedType);
stringBuilder.Append(typeOptions);
}
diff --git a/Source/aweXpect.Web/ThatHttpResponseMessage.HasStatusCode.cs b/Source/aweXpect.Web/ThatHttpResponseMessage.HasStatusCode.cs
index 6b75f57..9994cd8 100644
--- a/Source/aweXpect.Web/ThatHttpResponseMessage.HasStatusCode.cs
+++ b/Source/aweXpect.Web/ThatHttpResponseMessage.HasStatusCode.cs
@@ -31,6 +31,5 @@ public static StatusCodeResult HasStatusCode(this IThat so
expected,
m => m.StatusCode,
(a, e) => a.Equals(e),
- $"has status code {Formatter.Format(expected)}",
- $"does not have status code {Formatter.Format(expected)}")), source);
+ $"status code {Formatter.Format(expected)}")), source);
}
diff --git a/Source/aweXpect.Web/ThatUri.HasDefaultPort.cs b/Source/aweXpect.Web/ThatUri.HasDefaultPort.cs
index f281216..771e193 100644
--- a/Source/aweXpect.Web/ThatUri.HasDefaultPort.cs
+++ b/Source/aweXpect.Web/ThatUri.HasDefaultPort.cs
@@ -46,7 +46,7 @@ public ConstraintResult IsMetBy(Uri? actual)
}
protected override void AppendNormalExpectation(StringBuilder stringBuilder, string? indentation = null)
- => stringBuilder.Append("has the default port for the used scheme");
+ => stringBuilder.Append(Grammars.Verb("has ", "have ")).Append("the default port for the used scheme");
protected override void AppendNormalResult(StringBuilder stringBuilder, string? indentation = null)
{
@@ -55,7 +55,7 @@ protected override void AppendNormalResult(StringBuilder stringBuilder, string?
}
protected override void AppendNegatedExpectation(StringBuilder stringBuilder, string? indentation = null)
- => stringBuilder.Append("does not have the default port for the used scheme");
+ => stringBuilder.Append(Grammars.Verb("does not have ", "do not have ")).Append("the default port for the used scheme");
protected override void AppendNegatedResult(StringBuilder stringBuilder, string? indentation = null)
=> AppendNormalResult(stringBuilder, indentation);
diff --git a/Source/aweXpect.Web/ThatUri.IsAbsolute.cs b/Source/aweXpect.Web/ThatUri.IsAbsolute.cs
index 84cf284..0b96a16 100644
--- a/Source/aweXpect.Web/ThatUri.IsAbsolute.cs
+++ b/Source/aweXpect.Web/ThatUri.IsAbsolute.cs
@@ -46,7 +46,7 @@ public ConstraintResult IsMetBy(Uri? actual)
}
protected override void AppendNormalExpectation(StringBuilder stringBuilder, string? indentation = null)
- => stringBuilder.Append("is an absolute URI");
+ => stringBuilder.Append(Grammars.Verb("is an absolute URI", "are absolute URIs"));
protected override void AppendNormalResult(StringBuilder stringBuilder, string? indentation = null)
{
@@ -55,7 +55,7 @@ protected override void AppendNormalResult(StringBuilder stringBuilder, string?
}
protected override void AppendNegatedExpectation(StringBuilder stringBuilder, string? indentation = null)
- => stringBuilder.Append("is not an absolute URI");
+ => stringBuilder.Append(Grammars.Verb("is not an absolute URI", "are not absolute URIs"));
protected override void AppendNegatedResult(StringBuilder stringBuilder, string? indentation = null)
=> AppendNormalResult(stringBuilder, indentation);
diff --git a/Source/aweXpect.Web/ThatUri.IsFile.cs b/Source/aweXpect.Web/ThatUri.IsFile.cs
index ea249fc..b45a4ee 100644
--- a/Source/aweXpect.Web/ThatUri.IsFile.cs
+++ b/Source/aweXpect.Web/ThatUri.IsFile.cs
@@ -46,7 +46,7 @@ public ConstraintResult IsMetBy(Uri? actual)
}
protected override void AppendNormalExpectation(StringBuilder stringBuilder, string? indentation = null)
- => stringBuilder.Append("is a file URI");
+ => stringBuilder.Append(Grammars.Verb("is a file URI", "are file URIs"));
protected override void AppendNormalResult(StringBuilder stringBuilder, string? indentation = null)
{
@@ -55,7 +55,7 @@ protected override void AppendNormalResult(StringBuilder stringBuilder, string?
}
protected override void AppendNegatedExpectation(StringBuilder stringBuilder, string? indentation = null)
- => stringBuilder.Append("is not a file URI");
+ => stringBuilder.Append(Grammars.Verb("is not a file URI", "are not file URIs"));
protected override void AppendNegatedResult(StringBuilder stringBuilder, string? indentation = null)
=> AppendNormalResult(stringBuilder, indentation);
diff --git a/Source/aweXpect.Web/ThatUri.IsLoopback.cs b/Source/aweXpect.Web/ThatUri.IsLoopback.cs
index a8828fd..9052c74 100644
--- a/Source/aweXpect.Web/ThatUri.IsLoopback.cs
+++ b/Source/aweXpect.Web/ThatUri.IsLoopback.cs
@@ -46,7 +46,7 @@ public ConstraintResult IsMetBy(Uri? actual)
}
protected override void AppendNormalExpectation(StringBuilder stringBuilder, string? indentation = null)
- => stringBuilder.Append("references the local host");
+ => stringBuilder.Append(Grammars.Verb("references ", "reference ")).Append("the local host");
protected override void AppendNormalResult(StringBuilder stringBuilder, string? indentation = null)
{
@@ -55,7 +55,7 @@ protected override void AppendNormalResult(StringBuilder stringBuilder, string?
}
protected override void AppendNegatedExpectation(StringBuilder stringBuilder, string? indentation = null)
- => stringBuilder.Append("does not reference the local host");
+ => stringBuilder.Append(Grammars.Verb("does not ", "do not ")).Append("reference the local host");
protected override void AppendNegatedResult(StringBuilder stringBuilder, string? indentation = null)
=> AppendNormalResult(stringBuilder, indentation);
diff --git a/Source/aweXpect.Web/ThatUri.IsUnc.cs b/Source/aweXpect.Web/ThatUri.IsUnc.cs
index 389332c..241b7b3 100644
--- a/Source/aweXpect.Web/ThatUri.IsUnc.cs
+++ b/Source/aweXpect.Web/ThatUri.IsUnc.cs
@@ -46,7 +46,7 @@ public ConstraintResult IsMetBy(Uri? actual)
}
protected override void AppendNormalExpectation(StringBuilder stringBuilder, string? indentation = null)
- => stringBuilder.Append("is an UNC path");
+ => stringBuilder.Append(Grammars.Verb("is an UNC path", "are UNC paths"));
protected override void AppendNormalResult(StringBuilder stringBuilder, string? indentation = null)
{
@@ -55,7 +55,7 @@ protected override void AppendNormalResult(StringBuilder stringBuilder, string?
}
protected override void AppendNegatedExpectation(StringBuilder stringBuilder, string? indentation = null)
- => stringBuilder.Append("is not an UNC path");
+ => stringBuilder.Append(Grammars.Verb("is not an UNC path", "are not UNC paths"));
protected override void AppendNegatedResult(StringBuilder stringBuilder, string? indentation = null)
=> AppendNormalResult(stringBuilder, indentation);
diff --git a/Source/aweXpect.Web/Web/Results/HasHeaderValueResult.cs b/Source/aweXpect.Web/Web/Results/HasHeaderValueResult.cs
index 39f6e5d..ced2efa 100644
--- a/Source/aweXpect.Web/Web/Results/HasHeaderValueResult.cs
+++ b/Source/aweXpect.Web/Web/Results/HasHeaderValueResult.cs
@@ -41,8 +41,8 @@ internal HasHeaderValueResult(
public StringEqualityResult WithValue(string? expected)
{
StringEqualityOptions options = new(nameof(expected));
- _expectationBuilder.And("").AddConstraint((_, grammars) =>
- new WithHeaderValueConstraint("the value", grammars, expected, _headerValueAccessor, options));
+ _expectationBuilder.And("").AddConstraint((it, grammars) =>
+ new WithHeaderValueConstraint(it, grammars, expected, _headerValueAccessor, options));
return new StringEqualityResult(_expectationBuilder, _returnValue, options);
}
@@ -118,10 +118,14 @@ public async ValueTask IsMetBy(TType? actual, CancellationToke
return this;
}
+ ///
+ /// The text continues the one of the header, which carries the negation and the number of the subject, like
+ /// the member expectations of Whose do.
+ ///
protected override void AppendNormalExpectation(StringBuilder stringBuilder, string? indentation = null)
{
stringBuilder.Append(" whose value ");
- stringBuilder.Append(options.GetExpectation(expected, Grammars | ExpectationGrammars.Active));
+ stringBuilder.Append(options.GetExpectation(expected, ExpectationGrammars.Active));
}
protected override void AppendNormalResult(StringBuilder stringBuilder, string? indentation = null)
@@ -132,22 +136,23 @@ protected override void AppendNormalResult(StringBuilder stringBuilder, string?
}
else if (_headerValues.Length != 1)
{
- stringBuilder.Append("the header contained ").Append(_headerValues.Length).Append(" values ");
+ stringBuilder.Append(It).Append(" had ").Append(_headerValues.Length).Append(" header values ");
Formatter.Format(stringBuilder, _headerValues);
}
else
{
- stringBuilder.Append(options.GetExtendedFailure(It, Grammars, _headerValues[0], expected));
+ AppendValueFailure(stringBuilder);
}
}
protected override void AppendNegatedExpectation(StringBuilder stringBuilder, string? indentation = null)
- {
- stringBuilder.Append(" whose value ");
- stringBuilder.Append(options.GetExpectation(expected, Grammars | ExpectationGrammars.Active));
- }
+ => AppendNormalExpectation(stringBuilder, indentation);
protected override void AppendNegatedResult(StringBuilder stringBuilder, string? indentation = null)
- => stringBuilder.Append(It).Append(" was");
+ => AppendValueFailure(stringBuilder);
+
+ private void AppendValueFailure(StringBuilder stringBuilder)
+ => stringBuilder.Append(options.GetExtendedMemberFailure(It, "header value", Grammars, _headerValues?[0],
+ expected));
}
}
diff --git a/Source/aweXpect.Web/Web/Results/ProblemDetailsOptions.cs b/Source/aweXpect.Web/Web/Results/ProblemDetailsOptions.cs
index 6a7ed6f..1867284 100644
--- a/Source/aweXpect.Web/Web/Results/ProblemDetailsOptions.cs
+++ b/Source/aweXpect.Web/Web/Results/ProblemDetailsOptions.cs
@@ -64,6 +64,7 @@ public class ProblemDetailsOptions
public StringEqualityOptions WithTitle(string title)
{
ThrowHelper.ThrowIfNull(title, nameof(title));
+ ThrowHelper.ThrowIfOptionIsAlreadySpecified(Title is not null, nameof(WithTitle));
Title = title;
_parts.Add(() => $"title {Formatter.Format(title)}{_titleOptions}");
return _titleOptions;
@@ -74,6 +75,7 @@ public StringEqualityOptions WithTitle(string title)
///
public void WithStatus(int status)
{
+ ThrowHelper.ThrowIfOptionIsAlreadySpecified(Status is not null, nameof(WithStatus));
Status = status;
_parts.Add(() => $"status {Formatter.Format(status)}");
}
@@ -84,6 +86,7 @@ public void WithStatus(int status)
public StringEqualityOptions WithDetail(string detail)
{
ThrowHelper.ThrowIfNull(detail, nameof(detail));
+ ThrowHelper.ThrowIfOptionIsAlreadySpecified(Detail is not null, nameof(WithDetail));
Detail = detail;
_parts.Add(() => $"detail {Formatter.Format(detail)}{_detailOptions}");
return _detailOptions;
@@ -95,6 +98,7 @@ public StringEqualityOptions WithDetail(string detail)
public StringEqualityOptions WithInstance(string instance)
{
ThrowHelper.ThrowIfNull(instance, nameof(instance));
+ ThrowHelper.ThrowIfOptionIsAlreadySpecified(Instance is not null, nameof(WithInstance));
Instance = instance;
_parts.Add(() => $"instance {Formatter.Format(instance)}{_instanceOptions}");
return _instanceOptions;
diff --git a/Source/aweXpect.Web/Web/Results/StatusCodeResult.cs b/Source/aweXpect.Web/Web/Results/StatusCodeResult.cs
index 29dde22..a55467e 100644
--- a/Source/aweXpect.Web/Web/Results/StatusCodeResult.cs
+++ b/Source/aweXpect.Web/Web/Results/StatusCodeResult.cs
@@ -29,8 +29,7 @@ public class StatusCodeResult(
expected,
mapper,
(a, e) => a.Equals(e),
- $"has status code {Formatter.Format(expected)}",
- $"does not have status code {Formatter.Format(expected)}")),
+ $"status code {Formatter.Format(expected)}")),
source);
///
@@ -46,8 +45,8 @@ public class StatusCodeResult(
unexpected,
mapper,
(a, u) => !a.Equals(u),
- $"has status code different to {Formatter.Format(unexpected)}",
- $"has status code {Formatter.Format(unexpected)}")),
+ $"status code different to {Formatter.Format(unexpected)}",
+ $"status code {Formatter.Format(unexpected)}")),
source);
///
@@ -62,8 +61,7 @@ public class StatusCodeResult(
null,
mapper,
(a, _) => (int)a is >= 200 and < 300,
- "has a success status code (2xx)",
- "does not have a success status code (2xx)")),
+ "a success status code (2xx)")),
source);
///
@@ -78,8 +76,7 @@ public class StatusCodeResult(
null,
mapper,
(a, _) => (int)a is >= 300 and < 400,
- "has a redirection status code (3xx)",
- "does not have a redirection status code (3xx)")),
+ "a redirection status code (3xx)")),
source);
///
@@ -94,8 +91,7 @@ public class StatusCodeResult(
null,
mapper,
(a, _) => (int)a is >= 400 and < 500,
- "has a client error status code (4xx)",
- "does not have a client error status code (4xx)")),
+ "a client error status code (4xx)")),
source);
///
@@ -110,8 +106,7 @@ public class StatusCodeResult(
null,
mapper,
(a, _) => (int)a is >= 500 and < 600,
- "has a server error status code (5xx)",
- "does not have a server error status code (5xx)")),
+ "a server error status code (5xx)")),
source);
///
@@ -126,8 +121,7 @@ public class StatusCodeResult(
null,
mapper,
(a, _) => (int)a is >= 400 and < 600,
- "has an error status code (4xx or 5xx)",
- "does not have an error status code (4xx or 5xx)")),
+ "an error status code (4xx or 5xx)")),
source);
internal sealed class PropertyConstraint(
@@ -137,7 +131,7 @@ internal sealed class PropertyConstraint(
Func mapper,
Func condition,
string expectation,
- string negatedExpectation)
+ string? hasExpectationWhenNegated = null)
: ConstraintResult.WithNotNullValue(it, grammars),
IValueConstraint
{
@@ -164,7 +158,7 @@ public ConstraintResult IsMetBy(HttpResponseMessage? actual)
}
protected override void AppendNormalExpectation(StringBuilder stringBuilder, string? indentation = null)
- => stringBuilder.Append(expectation);
+ => stringBuilder.Append(Grammars.Verb("has ", "have ")).Append(expectation);
protected override void AppendNormalResult(StringBuilder stringBuilder, string? indentation = null)
{
@@ -173,7 +167,9 @@ protected override void AppendNormalResult(StringBuilder stringBuilder, string?
}
protected override void AppendNegatedExpectation(StringBuilder stringBuilder, string? indentation = null)
- => stringBuilder.Append(negatedExpectation);
+ => stringBuilder.Append(hasExpectationWhenNegated is null
+ ? Grammars.Verb("does not have ", "do not have ") + expectation
+ : Grammars.Verb("has ", "have ") + hasExpectationWhenNegated);
protected override void AppendNegatedResult(StringBuilder stringBuilder, string? indentation = null)
=> AppendNormalResult(stringBuilder, indentation);
diff --git a/Tests/Aot/aweXpect.Web.Aot/Checks.cs b/Tests/Aot/aweXpect.Web.Aot/Checks.cs
index bd59ce6..36b96d2 100644
--- a/Tests/Aot/aweXpect.Web.Aot/Checks.cs
+++ b/Tests/Aot/aweXpect.Web.Aot/Checks.cs
@@ -55,10 +55,10 @@ internal static class Checks
.HasHeader("x-track").WithValue("42"))),
new("a missing header fails and is named",
() => ShouldFail(async () => await That(Response(HttpStatusCode.OK)).HasHeader("x-track"),
- "has an `x-track` header")),
+ "has an \"x-track\" header")),
new("an unexpected header fails and is named",
() => ShouldFail(async () => await That(Response(HttpStatusCode.OK, header: "x-track")).DoesNotHaveHeader("x-track"),
- "does not have an `x-track` header","[\"42\"]")),
+ "does not have an \"x-track\" header","[\"42\"]")),
new("an equal content passes",
() => ShouldPass(async () => await That(Response(HttpStatusCode.OK, Json)).HasContent(Json))),
new("a differing content fails and shows both",
diff --git a/Tests/aweXpect.Web.Samples.Tests/CoverTests.cs b/Tests/aweXpect.Web.Samples.Tests/CoverTests.cs
index fef7ef1..2871abd 100644
--- a/Tests/aweXpect.Web.Samples.Tests/CoverTests.cs
+++ b/Tests/aweXpect.Web.Samples.Tests/CoverTests.cs
@@ -33,7 +33,7 @@ await Expect.That(Act).Throws()
.WithMessage("""
Expected that response
has a `Content-Type` header equal to "image/jpg",
- but it was "image/png", which differs at index 6:
+ but it had content type "image/png", which differs at index 6:
↓ (actual)
"image/png"
"image/jpg"
diff --git a/Tests/aweXpect.Web.Tests/ThatHttpRequestMessage.CombinedTests.cs b/Tests/aweXpect.Web.Tests/ThatHttpRequestMessage.CombinedTests.cs
index 3fc2df2..b69f747 100644
--- a/Tests/aweXpect.Web.Tests/ThatHttpRequestMessage.CombinedTests.cs
+++ b/Tests/aweXpect.Web.Tests/ThatHttpRequestMessage.CombinedTests.cs
@@ -19,13 +19,13 @@ async Task Act()
await That(Act).Throws()
.WithMessage("""
Expected that subject
- has a string content equal to "bar" and has a request URI equal to "https://example.com/",
- but it was "foo", which differs at index 0:
+ has a string content equal to "bar" and has a request URI equal to "https://example.com/" ignoring case,
+ but it had string content "foo", which differs at index 0:
↓ (actual)
"foo"
"bar"
↑ (expected)
- and it was "https://awexpect.com/", which differs at index 8:
+ and it had request URI "https://awexpect.com/", which differs at index 8:
↓ (actual)
"https://awexpect.com/"
"https://example.com/"
@@ -53,7 +53,7 @@ async Task Act()
await That(Act).Throws()
.WithMessage("""
Expected that subject
- has a POST method and has a `y` header,
+ has a POST method and has a "y" header,
but it was GET and did not contain the expected header
HTTP-Request:
diff --git a/Tests/aweXpect.Web.Tests/ThatHttpRequestMessage.DoesNotHaveHeader.Tests.cs b/Tests/aweXpect.Web.Tests/ThatHttpRequestMessage.DoesNotHaveHeader.Tests.cs
index af5e322..734dc9a 100644
--- a/Tests/aweXpect.Web.Tests/ThatHttpRequestMessage.DoesNotHaveHeader.Tests.cs
+++ b/Tests/aweXpect.Web.Tests/ThatHttpRequestMessage.DoesNotHaveHeader.Tests.cs
@@ -8,6 +8,21 @@ public sealed class DoesNotHaveHeader
{
public sealed class Tests
{
+ [Fact]
+ public async Task WhenMemberIsACollection_ShouldUsePluralVerb()
+ {
+ HttpRequestMessage[] subjects = [RequestBuilder.WithHeader("x-my-header", "foo"),];
+
+ async Task Act()
+ => await That(new { Requests = subjects, })
+ .Whose(x => x.Requests, items => items.All()
+ .ComplyWith(item => item.DoesNotHaveHeader("x-my-header")));
+
+ await That(Act).Throws()
+ .WithMessage("""*whose Requests do not have an "x-my-header" header for all items,*""").AsWildcard()
+ .Because("the verb agrees with the plural member");
+ }
+
[Fact]
public async Task WhenUnexpectedIsNull_ShouldThrowArgumentNullException()
{
@@ -37,7 +52,7 @@ async Task Act()
await That(Act).Throws()
.WithMessage($"""
Expected that subject
- does not have {article} `{name}` header,
+ does not have {article} "{name}" header,
but it was
""");
}
@@ -69,8 +84,8 @@ async Task Act()
await That(Act).Throws()
.WithMessage("""
Expected that subject
- does not have an `x-my-header` header,
- but it did contain the `x-my-header` header: ["some header"]
+ does not have an "x-my-header" header,
+ but it did contain the "x-my-header" header: ["some header"]
HTTP-Request:
HEAD https://awexpect.com/ HTTP/1.1
@@ -92,7 +107,7 @@ async Task Act()
await That(Act).Throws()
.WithMessage("""
Expected that subject
- does not have an `x-my-header` header,
+ does not have an "x-my-header" header,
but it was
""");
}
diff --git a/Tests/aweXpect.Web.Tests/ThatHttpRequestMessage.HasContent.Tests.cs b/Tests/aweXpect.Web.Tests/ThatHttpRequestMessage.HasContent.Tests.cs
index 128376d..6df9e3f 100644
--- a/Tests/aweXpect.Web.Tests/ThatHttpRequestMessage.HasContent.Tests.cs
+++ b/Tests/aweXpect.Web.Tests/ThatHttpRequestMessage.HasContent.Tests.cs
@@ -8,6 +8,21 @@ public sealed partial class HasContent
{
public sealed class Tests
{
+ [Fact]
+ public async Task WhenMemberIsACollection_ShouldUsePluralVerb()
+ {
+ HttpRequestMessage[] subjects = [RequestBuilder.WithContent("foo"),];
+
+ async Task Act()
+ => await That(new { Requests = subjects, })
+ .Whose(x => x.Requests, items => items.All()
+ .ComplyWith(item => item.HasContent("bar")));
+
+ await That(Act).Throws()
+ .WithMessage("""*whose Requests have a string content equal to "bar" for all items,*""").AsWildcard()
+ .Because("the verb agrees with the plural member");
+ }
+
[Fact]
public async Task WhenExpectedIsNull_ShouldThrowArgumentNullException()
{
@@ -37,7 +52,7 @@ await That(Act).Throws()
.WithMessage("""
Expected that subject
has a string content equal to "other content",
- but it was "some content", which differs at index 0:
+ but it had string content "some content", which differs at index 0:
↓ (actual)
"some content"
"other content"
@@ -66,7 +81,7 @@ await That(Act).Throws()
.WithMessage("""
Expected that subject
has a string content equal to "other content",
- but it was "some content", which differs at index 0:
+ but it had string content "some content", which differs at index 0:
↓ (actual)
"some content"
"other content"
diff --git a/Tests/aweXpect.Web.Tests/ThatHttpRequestMessage.HasHeader.Tests.cs b/Tests/aweXpect.Web.Tests/ThatHttpRequestMessage.HasHeader.Tests.cs
index c269052..d2e5695 100644
--- a/Tests/aweXpect.Web.Tests/ThatHttpRequestMessage.HasHeader.Tests.cs
+++ b/Tests/aweXpect.Web.Tests/ThatHttpRequestMessage.HasHeader.Tests.cs
@@ -8,6 +8,21 @@ public sealed partial class HasHeader
{
public sealed class Tests
{
+ [Fact]
+ public async Task WhenMemberIsACollection_ShouldUsePluralVerb()
+ {
+ HttpRequestMessage[] subjects = [RequestBuilder,];
+
+ async Task Act()
+ => await That(new { Requests = subjects, })
+ .Whose(x => x.Requests, items => items.All()
+ .ComplyWith(item => item.HasHeader("x-my-header")));
+
+ await That(Act).Throws()
+ .WithMessage("""*whose Requests have an "x-my-header" header for all items,*""").AsWildcard()
+ .Because("the verb agrees with the plural member");
+ }
+
[Fact]
public async Task WhenExpectedIsNull_ShouldThrowArgumentNullException()
{
@@ -37,7 +52,7 @@ async Task Act()
await That(Act).Throws()
.WithMessage($"""
Expected that subject
- has {article} `{name}` header,
+ has {article} "{name}" header,
but it was
""");
}
@@ -55,7 +70,7 @@ async Task Act()
await That(Act).Throws()
.WithMessage("""
Expected that subject
- has an `x-my-header` header,
+ has an "x-my-header" header,
but it did not contain the expected header
HTTP-Request:
@@ -90,7 +105,7 @@ async Task Act()
await That(Act).Throws()
.WithMessage("""
Expected that subject
- has an `x-my-header` header,
+ has an "x-my-header" header,
but it was
""");
}
diff --git a/Tests/aweXpect.Web.Tests/ThatHttpRequestMessage.HasHeader.WhoseValueTests.cs b/Tests/aweXpect.Web.Tests/ThatHttpRequestMessage.HasHeader.WhoseValueTests.cs
index 48fb1c1..5c4ae42 100644
--- a/Tests/aweXpect.Web.Tests/ThatHttpRequestMessage.HasHeader.WhoseValueTests.cs
+++ b/Tests/aweXpect.Web.Tests/ThatHttpRequestMessage.HasHeader.WhoseValueTests.cs
@@ -36,7 +36,7 @@ async Task Act()
await That(Act).Throws()
.WithMessage("""
Expected that subject
- has an `x-some-other-key` header whose value is equal to "some header",
+ has an "x-some-other-key" header whose value is equal to "some header",
but it did not contain the expected header
HTTP-Request:
@@ -60,7 +60,7 @@ async Task Act()
await That(Act).Throws()
.WithMessage("""
Expected that subject
- has an `x-my-header` header whose value is equal to "some other header",
+ has an "x-my-header" header whose value is equal to "some other header",
but the value was "some header", which differs at index 5:
↓ (actual)
"some header"
@@ -98,7 +98,7 @@ async Task Act()
await That(Act).Throws()
.WithMessage("""
Expected that subject
- has an `x-my-key` header whose value is empty,
+ has an "x-my-key" header whose value is empty,
but it was
""");
}
@@ -153,8 +153,8 @@ async Task Act()
await That(Act).Throws()
.WithMessage("""
Expected that subject
- does not have an `x-my-header` header whose value is equal to "some header",
- but it did contain the `x-my-header` header: ["some header"]
+ does not have an "x-my-header" header whose value is equal to "some header",
+ but it did contain the "x-my-header" header: ["some header"]
HTTP-Request:
HEAD https://awexpect.com/ HTTP/1.1
diff --git a/Tests/aweXpect.Web.Tests/ThatHttpRequestMessage.HasHeader.WhoseValuesTests.cs b/Tests/aweXpect.Web.Tests/ThatHttpRequestMessage.HasHeader.WhoseValuesTests.cs
index efa3f79..f93aebd 100644
--- a/Tests/aweXpect.Web.Tests/ThatHttpRequestMessage.HasHeader.WhoseValuesTests.cs
+++ b/Tests/aweXpect.Web.Tests/ThatHttpRequestMessage.HasHeader.WhoseValuesTests.cs
@@ -36,7 +36,7 @@ async Task Act()
await That(Act).Throws()
.WithMessage("""
Expected that subject
- has an `x-some-other-key` header whose values have exactly 3 items,
+ has an "x-some-other-key" header whose values have exactly 3 items,
but it did not contain the expected header
HTTP-Request:
@@ -62,7 +62,7 @@ async Task Act()
await That(Act).Throws()
.WithMessage("""
Expected that subject
- has an `x-my-header` header whose values contain "some other header" at least once,
+ has an "x-my-header" header whose values contain "some other header" at least once,
but the values did not contain it
HTTP-Request:
@@ -101,7 +101,7 @@ async Task Act()
await That(Act).Throws()
.WithMessage("""
Expected that subject
- has an `x-my-key` header whose values are empty,
+ has an "x-my-key" header whose values are empty,
but it was
""");
}
diff --git a/Tests/aweXpect.Web.Tests/ThatHttpRequestMessage.HasHeader.WithValueTests.cs b/Tests/aweXpect.Web.Tests/ThatHttpRequestMessage.HasHeader.WithValueTests.cs
index 76e2e45..74fe117 100644
--- a/Tests/aweXpect.Web.Tests/ThatHttpRequestMessage.HasHeader.WithValueTests.cs
+++ b/Tests/aweXpect.Web.Tests/ThatHttpRequestMessage.HasHeader.WithValueTests.cs
@@ -36,7 +36,7 @@ async Task Act()
await That(Act).Throws()
.WithMessage("""
Expected that subject
- has an `x-some-other-key` header whose value is equal to "some header",
+ has an "x-some-other-key" header whose value is equal to "some header",
but it did not contain the expected header
HTTP-Request:
@@ -60,8 +60,8 @@ async Task Act()
await That(Act).Throws()
.WithMessage("""
Expected that subject
- has an `x-my-header` header whose value is equal to "some other header",
- but the value was "some header", which differs at index 5:
+ has an "x-my-header" header whose value is equal to "some other header",
+ but it had header value "some header", which differs at index 5:
↓ (actual)
"some header"
"some other header"
@@ -101,7 +101,7 @@ async Task Act()
await That(Act).Throws()
.WithMessage("""
Expected that subject
- has an `x-some-other-key` header whose value is equal to "some header",
+ has an "x-some-other-key" header whose value is equal to "some header",
but it did not contain the expected header
HTTP-Request:
@@ -121,10 +121,48 @@ async Task Act()
await That(Act).Throws()
.WithMessage("""
Expected that subject
- has an `x-my-key` header whose value is equal to "foo",
+ has an "x-my-key" header whose value is equal to "foo",
but it was
""");
}
}
+
+ public sealed class NegatedWithValueTests
+ {
+ [Fact]
+ public async Task WhenHeaderExistsAndValueDiffers_ShouldSucceed()
+ {
+ HttpRequestMessage subject = RequestBuilder
+ .WithHeader("x-my-header", "some header");
+
+ async Task Act()
+ => await That(subject)
+ .DoesNotComplyWith(it => it.HasHeader("x-my-header").WithValue("some other header"));
+
+ await That(Act).DoesNotThrow();
+ }
+
+ [Fact]
+ public async Task WhenHeaderExistsAndValueIsEqual_ShouldFail()
+ {
+ HttpRequestMessage subject = RequestBuilder
+ .WithHeader("x-my-header", "some header");
+
+ async Task Act()
+ => await That(subject).DoesNotComplyWith(it => it.HasHeader("x-my-header").WithValue("some header"));
+
+ await That(Act).Throws()
+ .WithMessage("""
+ Expected that subject
+ does not have an "x-my-header" header whose value is equal to "some header",
+ but it did contain the "x-my-header" header: ["some header"] and had header value "some header"
+
+ HTTP-Request:
+ HEAD https://awexpect.com/ HTTP/1.1
+ x-my-header: some header
+ """)
+ .Because("the negation applies to the header as a whole, like the negated text of a `Whose`");
+ }
+ }
}
}
diff --git a/Tests/aweXpect.Web.Tests/ThatHttpRequestMessage.HasMethod.Tests.cs b/Tests/aweXpect.Web.Tests/ThatHttpRequestMessage.HasMethod.Tests.cs
index c69bcb5..9281a59 100644
--- a/Tests/aweXpect.Web.Tests/ThatHttpRequestMessage.HasMethod.Tests.cs
+++ b/Tests/aweXpect.Web.Tests/ThatHttpRequestMessage.HasMethod.Tests.cs
@@ -8,6 +8,36 @@ public sealed class HasMethod
{
public sealed class Tests
{
+ [Fact]
+ public async Task WhenMemberIsACollection_Negated_ShouldUsePluralVerb()
+ {
+ HttpRequestMessage[] subjects = [RequestBuilder,];
+
+ async Task Act()
+ => await That(new { Requests = subjects, })
+ .Whose(x => x.Requests, items => items.All()
+ .ComplyWith(item => item.DoesNotComplyWith(request => request.HasMethod(HttpMethod.Head))));
+
+ await That(Act).Throws()
+ .WithMessage("""*whose Requests do not have a HEAD method for all items,*""").AsWildcard()
+ .Because("the verb agrees with the plural member");
+ }
+
+ [Fact]
+ public async Task WhenMemberIsACollection_ShouldUsePluralVerb()
+ {
+ HttpRequestMessage[] subjects = [RequestBuilder,];
+
+ async Task Act()
+ => await That(new { Requests = subjects, })
+ .Whose(x => x.Requests, items => items.All()
+ .ComplyWith(item => item.HasMethod(HttpMethod.Get)));
+
+ await That(Act).Throws()
+ .WithMessage("""*whose Requests have a GET method for all items,*""").AsWildcard()
+ .Because("the verb agrees with the plural member");
+ }
+
[Fact]
public async Task WhenExpectedIsNull_ShouldThrowArgumentNullException()
{
diff --git a/Tests/aweXpect.Web.Tests/ThatHttpRequestMessage.HasRequestUri.Tests.cs b/Tests/aweXpect.Web.Tests/ThatHttpRequestMessage.HasRequestUri.Tests.cs
index 37ed09b..0df2009 100644
--- a/Tests/aweXpect.Web.Tests/ThatHttpRequestMessage.HasRequestUri.Tests.cs
+++ b/Tests/aweXpect.Web.Tests/ThatHttpRequestMessage.HasRequestUri.Tests.cs
@@ -8,6 +8,36 @@ public sealed class HasRequestUri
{
public sealed class Tests
{
+ [Fact]
+ public async Task WhenMemberIsACollection_Negated_ShouldUsePluralVerb()
+ {
+ HttpRequestMessage[] subjects = [RequestBuilder,];
+
+ async Task Act()
+ => await That(new { Requests = subjects, })
+ .Whose(x => x.Requests, items => items.All()
+ .ComplyWith(item => item.DoesNotComplyWith(request => request.HasRequestUri("https://awexpect.com/"))));
+
+ await That(Act).Throws()
+ .WithMessage("""*whose Requests do not have a request URI equal to "https://awexpect.com/" ignoring case for all items,*""").AsWildcard()
+ .Because("the verb agrees with the plural member");
+ }
+
+ [Fact]
+ public async Task WhenMemberIsACollection_ShouldUsePluralVerb()
+ {
+ HttpRequestMessage[] subjects = [RequestBuilder,];
+
+ async Task Act()
+ => await That(new { Requests = subjects, })
+ .Whose(x => x.Requests, items => items.All()
+ .ComplyWith(item => item.HasRequestUri("https://example.com/")));
+
+ await That(Act).Throws()
+ .WithMessage("""*whose Requests have a request URI equal to "https://example.com/" ignoring case for all items,*""").AsWildcard()
+ .Because("the verb agrees with the plural member");
+ }
+
[Fact]
public async Task WhenExpectedStringIsNull_ShouldThrowArgumentNullException()
{
@@ -61,7 +91,7 @@ async Task Act()
await That(Act).Throws()
.WithMessage("""
Expected that subject
- has a request URI equal to "https://awexpect.com/",
+ has a request URI equal to "https://awexpect.com/" ignoring case,
but it was
""");
}
@@ -79,8 +109,8 @@ async Task Act()
await That(Act).Throws()
.WithMessage("""
Expected that subject
- has a request URI equal to "https://awexpect.com/awexpect.Web",
- but it was "https://awexpect.com/" with a length of 21, which is shorter than the expected length of 33 and misses:
+ has a request URI equal to "https://awexpect.com/awexpect.…" ignoring case,
+ but it had request URI "https://awexpect.com/" with a length of 21, which is shorter than the expected length of 33 and misses:
"awexpect.Web"
HTTP-Request:
@@ -101,8 +131,8 @@ async Task Act()
await That(Act).Throws()
.WithMessage("""
Expected that subject
- has a request URI equal to "https://awexpect.com/abd",
- but it was "https://awexpect.com/ABC", which differs at index 23:
+ has a request URI equal to "https://awexpect.com/abd" ignoring case,
+ but it had request URI "https://awexpect.com/ABC", which differs at index 23:
↓ (actual)
"…ect.com/ABC"
"…ect.com/abd"
@@ -140,7 +170,7 @@ async Task Act()
await That(Act).Throws()
.WithMessage("""
Expected that subject
- does not have a request URI equal to "https://awexpect.com/",
+ does not have a request URI equal to "https://awexpect.com/" ignoring case,
but it was
""");
}
@@ -171,7 +201,7 @@ async Task Act()
await That(Act).Throws()
.WithMessage("""
Expected that subject
- does not have a request URI equal to "https://awexpect.com/",
+ does not have a request URI equal to "https://awexpect.com/" ignoring case,
but it had
HTTP-Request:
diff --git a/Tests/aweXpect.Web.Tests/ThatHttpResponseMessage.CombinedTests.cs b/Tests/aweXpect.Web.Tests/ThatHttpResponseMessage.CombinedTests.cs
index b400ff1..3a64325 100644
--- a/Tests/aweXpect.Web.Tests/ThatHttpResponseMessage.CombinedTests.cs
+++ b/Tests/aweXpect.Web.Tests/ThatHttpResponseMessage.CombinedTests.cs
@@ -23,7 +23,7 @@ async Task Act()
await That(Act).Throws()
.WithMessage("""
Expected that subject
- has an `x-b` header and has a success status code (2xx) for all items,
+ has an "x-b" header and has a success status code (2xx) for all items,
but none of 2 did
*
HTTP-Response (item [0]):
@@ -47,8 +47,8 @@ async Task Act()
await That(Act).Throws()
.WithMessage("""
Expected that subject
- does not have an `x-a` header and has a success status code (2xx),
- but it did contain the `x-a` header: ["1"] and had status code 404 NotFound
+ does not have an "x-a" header and has a success status code (2xx),
+ but it did contain the "x-a" header: ["1"] and had status code 404 NotFound
HTTP-Response:
404 NotFound HTTP/1.1
@@ -79,7 +79,7 @@ Expected that subject
"foo"
"bar"
↑ (expected)
- and it was "foo", which differs at index 0:
+ and it had string content "foo", which differs at index 0:
↓ (actual)
"foo"
"baz"
@@ -107,7 +107,7 @@ async Task Act()
await That(Act).Throws()
.WithMessage("""
Expected that subject
- has an `x-a` header whose value is equal to "2" and has status code 201 Created,
+ has an "x-a" header whose value is equal to "2" and has status code 201 Created,
but the value was "1", which differs at index 0:
↓ (actual)
"1"
@@ -137,7 +137,7 @@ async Task Act()
await That(Act).Throws()
.WithMessage("""
Expected that subject
- has a request message which has a `y` header and has an `x` header,
+ has a request message which has a "y" header and has an "x" header,
but it did not contain the expected header
HTTP-Request:
@@ -198,7 +198,7 @@ await That(Act).Throws()
.WithMessage("""
Expected that subject
has a success status code (2xx) and has a `Content-Type` header equal to "application/json",
- but it had status code 404 NotFound and was "text/plain", which differs at index 0:
+ but it had status code 404 NotFound and had content type "text/plain", which differs at index 0:
↓ (actual)
"text/plain"
"application/json"
@@ -225,7 +225,7 @@ async Task Act()
await That(Act).Throws()
.WithMessage("""
Expected that subject
- has a success status code (2xx) and has an `x-missing` header,
+ has a success status code (2xx) and has an "x-missing" header,
but it had status code 404 NotFound and did not contain the expected header
HTTP-Response:
@@ -249,7 +249,7 @@ async Task Act()
await That(Act).Throws()
.WithMessage("""
Expected that subject
- has a success status code (2xx) or has an `x-missing` header,
+ has a success status code (2xx) or has an "x-missing" header,
but it had status code 404 NotFound and did not contain the expected header
HTTP-Response:
diff --git a/Tests/aweXpect.Web.Tests/ThatHttpResponseMessage.DoesNotHaveHeader.Tests.cs b/Tests/aweXpect.Web.Tests/ThatHttpResponseMessage.DoesNotHaveHeader.Tests.cs
index bdb52c0..607df8c 100644
--- a/Tests/aweXpect.Web.Tests/ThatHttpResponseMessage.DoesNotHaveHeader.Tests.cs
+++ b/Tests/aweXpect.Web.Tests/ThatHttpResponseMessage.DoesNotHaveHeader.Tests.cs
@@ -8,6 +8,21 @@ public sealed class DoesNotHaveHeader
{
public sealed class Tests
{
+ [Fact]
+ public async Task WhenMemberIsACollection_ShouldUsePluralVerb()
+ {
+ HttpResponseMessage[] subjects = [ResponseBuilder.WithHeader("x-my-header", "foo"),];
+
+ async Task Act()
+ => await That(new { Responses = subjects, })
+ .Whose(x => x.Responses, items => items.All()
+ .ComplyWith(item => item.DoesNotHaveHeader("x-my-header")));
+
+ await That(Act).Throws()
+ .WithMessage("""*whose Responses do not have an "x-my-header" header for all items,*""").AsWildcard()
+ .Because("the verb agrees with the plural member");
+ }
+
[Fact]
public async Task WhenUnexpectedIsNull_ShouldThrowArgumentNullException()
{
@@ -37,7 +52,7 @@ async Task Act()
await That(Act).Throws()
.WithMessage($"""
Expected that subject
- does not have {article} `{name}` header,
+ does not have {article} "{name}" header,
but it was
""");
}
@@ -69,8 +84,8 @@ async Task Act()
await That(Act).Throws()
.WithMessage("""
Expected that subject
- does not have an `x-my-header` header,
- but it did contain the `x-my-header` header: ["some header"]
+ does not have an "x-my-header" header,
+ but it did contain the "x-my-header" header: ["some header"]
HTTP-Response:
200 OK HTTP/1.1
@@ -92,7 +107,7 @@ async Task Act()
await That(Act).Throws()
.WithMessage("""
Expected that subject
- does not have an `x-my-header` header,
+ does not have an "x-my-header" header,
but it was
""");
}
diff --git a/Tests/aweXpect.Web.Tests/ThatHttpResponseMessage.HasContent.Tests.cs b/Tests/aweXpect.Web.Tests/ThatHttpResponseMessage.HasContent.Tests.cs
index 7fdc063..a8e8bf6 100644
--- a/Tests/aweXpect.Web.Tests/ThatHttpResponseMessage.HasContent.Tests.cs
+++ b/Tests/aweXpect.Web.Tests/ThatHttpResponseMessage.HasContent.Tests.cs
@@ -8,6 +8,36 @@ public sealed partial class HasContent
{
public sealed class Tests
{
+ [Fact]
+ public async Task WhenMemberIsACollection_Negated_ShouldUsePluralVerb()
+ {
+ HttpResponseMessage[] subjects = [ResponseBuilder.WithContent("foo"),];
+
+ async Task Act()
+ => await That(new { Responses = subjects, })
+ .Whose(x => x.Responses, items => items.All()
+ .ComplyWith(item => item.DoesNotComplyWith(response => response.HasContent("foo"))));
+
+ await That(Act).Throws()
+ .WithMessage("""*whose Responses do not have a string content equal to "foo" for all items,*""").AsWildcard()
+ .Because("the verb agrees with the plural member");
+ }
+
+ [Fact]
+ public async Task WhenMemberIsACollection_ShouldUsePluralVerb()
+ {
+ HttpResponseMessage[] subjects = [ResponseBuilder.WithContent("foo"),];
+
+ async Task Act()
+ => await That(new { Responses = subjects, })
+ .Whose(x => x.Responses, items => items.All()
+ .ComplyWith(item => item.HasContent("bar")));
+
+ await That(Act).Throws()
+ .WithMessage("""*whose Responses have a string content equal to "bar" for all items,*""").AsWildcard()
+ .Because("the verb agrees with the plural member");
+ }
+
[Fact]
public async Task WhenExpectedIsNull_ShouldThrowArgumentNullException()
{
@@ -35,7 +65,7 @@ await That(Act).Throws()
.WithMessage("""
Expected that subject
has a string content equal to "other content",
- but it was "some content", which differs at index 0:
+ but it had string content "some content", which differs at index 0:
↓ (actual)
"some content"
"other content"
diff --git a/Tests/aweXpect.Web.Tests/ThatHttpResponseMessage.HasContentType.Tests.cs b/Tests/aweXpect.Web.Tests/ThatHttpResponseMessage.HasContentType.Tests.cs
index fcf4dda..65dba80 100644
--- a/Tests/aweXpect.Web.Tests/ThatHttpResponseMessage.HasContentType.Tests.cs
+++ b/Tests/aweXpect.Web.Tests/ThatHttpResponseMessage.HasContentType.Tests.cs
@@ -9,6 +9,21 @@ public sealed class HasContentType
{
public sealed class Tests
{
+ [Fact]
+ public async Task WhenMemberIsACollection_ShouldUsePluralVerb()
+ {
+ HttpResponseMessage[] subjects = [ResponseBuilder.WithContent("foo"),];
+
+ async Task Act()
+ => await That(new { Responses = subjects, })
+ .Whose(x => x.Responses, items => items.All()
+ .ComplyWith(item => item.HasContentType("application/json")));
+
+ await That(Act).Throws()
+ .WithMessage("""*whose Responses have a `Content-Type` header equal to "application/json" for all items,*""").AsWildcard()
+ .Because("the verb agrees with the plural member");
+ }
+
[Fact]
public async Task WhenExpectedIsNull_ShouldThrowArgumentNullException()
{
@@ -37,7 +52,7 @@ await That(Act).Throws()
.WithMessage("""
Expected that subject
has a `Content-Type` header equal to "text/content-type",
- but it was "text/other-content-type", which differs at index 5:
+ but it had content type "text/other-content-type", which differs at index 5:
↓ (actual)
"text/other-content-type"
"text/content-type"
diff --git a/Tests/aweXpect.Web.Tests/ThatHttpResponseMessage.HasHeader.Tests.cs b/Tests/aweXpect.Web.Tests/ThatHttpResponseMessage.HasHeader.Tests.cs
index 60e468f..993106d 100644
--- a/Tests/aweXpect.Web.Tests/ThatHttpResponseMessage.HasHeader.Tests.cs
+++ b/Tests/aweXpect.Web.Tests/ThatHttpResponseMessage.HasHeader.Tests.cs
@@ -8,6 +8,21 @@ public sealed partial class HasHeader
{
public sealed class Tests
{
+ [Fact]
+ public async Task WhenMemberIsACollection_ShouldUsePluralVerb()
+ {
+ HttpResponseMessage[] subjects = [ResponseBuilder,];
+
+ async Task Act()
+ => await That(new { Responses = subjects, })
+ .Whose(x => x.Responses, items => items.All()
+ .ComplyWith(item => item.HasHeader("x-my-header")));
+
+ await That(Act).Throws()
+ .WithMessage("""*whose Responses have an "x-my-header" header for all items,*""").AsWildcard()
+ .Because("the verb agrees with the plural member");
+ }
+
[Fact]
public async Task WhenExpectedIsNull_ShouldThrowArgumentNullException()
{
@@ -37,7 +52,7 @@ async Task Act()
await That(Act).Throws()
.WithMessage($"""
Expected that subject
- has {article} `{name}` header,
+ has {article} "{name}" header,
but it was
""");
}
@@ -55,7 +70,7 @@ async Task Act()
await That(Act).Throws()
.WithMessage("""
Expected that subject
- has an `x-my-header` header,
+ has an "x-my-header" header,
but it did not contain the expected header
HTTP-Response:
@@ -90,7 +105,7 @@ async Task Act()
await That(Act).Throws()
.WithMessage("""
Expected that subject
- has an `x-my-header` header,
+ has an "x-my-header" header,
but it was
""");
}
diff --git a/Tests/aweXpect.Web.Tests/ThatHttpResponseMessage.HasHeader.WhoseValueTests.cs b/Tests/aweXpect.Web.Tests/ThatHttpResponseMessage.HasHeader.WhoseValueTests.cs
index 90174c2..9cc856d 100644
--- a/Tests/aweXpect.Web.Tests/ThatHttpResponseMessage.HasHeader.WhoseValueTests.cs
+++ b/Tests/aweXpect.Web.Tests/ThatHttpResponseMessage.HasHeader.WhoseValueTests.cs
@@ -23,7 +23,7 @@ async Task Act()
await That(Act).Throws()
.WithMessage("""
Expected that subject
- has an `x-some-other-key` header whose value is equal to "some header",
+ has an "x-some-other-key" header whose value is equal to "some header",
but it did not contain the expected header
HTTP-Response:
@@ -49,7 +49,7 @@ async Task Act()
await That(Act).Throws()
.WithMessage("""
Expected that subject
- has an `x-my-header` header whose value is equal to "some other header",
+ has an "x-my-header" header whose value is equal to "some other header",
but the value was "some header", which differs at index 5:
↓ (actual)
"some header"
@@ -89,7 +89,7 @@ async Task Act()
await That(Act).Throws()
.WithMessage("""
Expected that subject
- has an `x-my-key` header whose value is empty,
+ has an "x-my-key" header whose value is empty,
but it was
""");
}
diff --git a/Tests/aweXpect.Web.Tests/ThatHttpResponseMessage.HasHeader.WhoseValuesTests.cs b/Tests/aweXpect.Web.Tests/ThatHttpResponseMessage.HasHeader.WhoseValuesTests.cs
index 4f341fc..a8596e5 100644
--- a/Tests/aweXpect.Web.Tests/ThatHttpResponseMessage.HasHeader.WhoseValuesTests.cs
+++ b/Tests/aweXpect.Web.Tests/ThatHttpResponseMessage.HasHeader.WhoseValuesTests.cs
@@ -23,7 +23,7 @@ async Task Act()
await That(Act).Throws()
.WithMessage("""
Expected that subject
- has an `x-some-other-key` header whose values have exactly 3 items,
+ has an "x-some-other-key" header whose values have exactly 3 items,
but it did not contain the expected header
HTTP-Response:
@@ -51,7 +51,7 @@ async Task Act()
await That(Act).Throws()
.WithMessage("""
Expected that subject
- has an `x-my-header` header whose values contain "some other header" at least once,
+ has an "x-my-header" header whose values contain "some other header" at least once,
but the values did not contain it
HTTP-Response:
@@ -92,7 +92,7 @@ async Task Act()
await That(Act).Throws()
.WithMessage("""
Expected that subject
- has an `x-my-key` header whose values are empty,
+ has an "x-my-key" header whose values are empty,
but it was
""");
}
diff --git a/Tests/aweXpect.Web.Tests/ThatHttpResponseMessage.HasHeader.WithValueTests.cs b/Tests/aweXpect.Web.Tests/ThatHttpResponseMessage.HasHeader.WithValueTests.cs
index f56757b..191d39a 100644
--- a/Tests/aweXpect.Web.Tests/ThatHttpResponseMessage.HasHeader.WithValueTests.cs
+++ b/Tests/aweXpect.Web.Tests/ThatHttpResponseMessage.HasHeader.WithValueTests.cs
@@ -23,7 +23,7 @@ async Task Act()
await That(Act).Throws()
.WithMessage("""
Expected that subject
- has an `x-some-other-key` header whose value is equal to "some header",
+ has an "x-some-other-key" header whose value is equal to "some header",
but it did not contain the expected header
HTTP-Response:
@@ -49,8 +49,8 @@ async Task Act()
await That(Act).Throws()
.WithMessage("""
Expected that subject
- has an `x-my-header` header whose value is equal to "some other header",
- but the value was "some header", which differs at index 5:
+ has an "x-my-header" header whose value is equal to "some other header",
+ but it had header value "some header", which differs at index 5:
↓ (actual)
"some header"
"some other header"
@@ -93,8 +93,8 @@ async Task Act()
await That(Act).Throws()
.WithMessage("""
Expected that subject
- has an `x-my-header` header whose value is equal to "some other header",
- but the header contained 2 values ["some header", "some other value"]
+ has an "x-my-header" header whose value is equal to "some other header",
+ but it had 2 header values ["some header", "some other value"]
HTTP-Response:
200 OK HTTP/1.1
@@ -116,10 +116,50 @@ async Task Act()
await That(Act).Throws()
.WithMessage("""
Expected that subject
- has an `x-my-key` header whose value is equal to "foo",
+ has an "x-my-key" header whose value is equal to "foo",
but it was
""");
}
}
+
+ public sealed class NegatedWithValueTests
+ {
+ [Fact]
+ public async Task WhenHeaderExistsAndValueDiffers_ShouldSucceed()
+ {
+ HttpResponseMessage subject = ResponseBuilder
+ .WithHeader("x-my-header", "some header");
+
+ async Task Act()
+ => await That(subject)
+ .DoesNotComplyWith(it => it.HasHeader("x-my-header").WithValue("some other header"));
+
+ await That(Act).DoesNotThrow();
+ }
+
+ [Fact]
+ public async Task WhenHeaderExistsAndValueIsEqual_ShouldFail()
+ {
+ HttpResponseMessage subject = ResponseBuilder
+ .WithHeader("x-my-header", "some header");
+
+ async Task Act()
+ => await That(subject).DoesNotComplyWith(it => it.HasHeader("x-my-header").WithValue("some header"));
+
+ await That(Act).Throws()
+ .WithMessage("""
+ Expected that subject
+ does not have an "x-my-header" header whose value is equal to "some header",
+ but it did contain the "x-my-header" header: ["some header"] and had header value "some header"
+
+ HTTP-Response:
+ 200 OK HTTP/1.1
+ x-my-header: some header
+ Content-Type: text/plain; charset=utf-8
+ Content-Length: 0
+ """)
+ .Because("the negation applies to the header as a whole, like the negated text of a `Whose`");
+ }
+ }
}
}
diff --git a/Tests/aweXpect.Web.Tests/ThatHttpResponseMessage.HasProblemDetails.Tests.cs b/Tests/aweXpect.Web.Tests/ThatHttpResponseMessage.HasProblemDetails.Tests.cs
index 1802d41..6b3bbf5 100644
--- a/Tests/aweXpect.Web.Tests/ThatHttpResponseMessage.HasProblemDetails.Tests.cs
+++ b/Tests/aweXpect.Web.Tests/ThatHttpResponseMessage.HasProblemDetails.Tests.cs
@@ -8,6 +8,36 @@ public sealed partial class HasProblemDetailsContent
{
public sealed class Tests
{
+ [Fact]
+ public async Task WhenMemberIsACollection_Negated_ShouldUsePluralVerb()
+ {
+ HttpResponseMessage[] subjects = [ResponseBuilder.WithContent("foo"),];
+
+ async Task Act()
+ => await That(new { Responses = subjects, })
+ .Whose(x => x.Responses, items => items.All()
+ .ComplyWith(item => item.DoesNotComplyWith(response => response.HasProblemDetailsContent())));
+
+ await That(Act).Throws()
+ .WithMessage("""*whose Responses do not have a ProblemDetails content for all items,*""").AsWildcard()
+ .Because("the verb agrees with the plural member");
+ }
+
+ [Fact]
+ public async Task WhenMemberIsACollection_ShouldUsePluralVerb()
+ {
+ HttpResponseMessage[] subjects = [ResponseBuilder.WithContent("foo"),];
+
+ async Task Act()
+ => await That(new { Responses = subjects, })
+ .Whose(x => x.Responses, items => items.All()
+ .ComplyWith(item => item.HasProblemDetailsContent()));
+
+ await That(Act).Throws()
+ .WithMessage("""*whose Responses have a ProblemDetails content with any type for all items,*""").AsWildcard()
+ .Because("the verb agrees with the plural member");
+ }
+
[Fact]
public async Task ShouldCombineMultipleChecks()
{
diff --git a/Tests/aweXpect.Web.Tests/ThatHttpResponseMessage.HasProblemDetails.WithDetailTests.cs b/Tests/aweXpect.Web.Tests/ThatHttpResponseMessage.HasProblemDetails.WithDetailTests.cs
index 786fae9..7ef2287 100644
--- a/Tests/aweXpect.Web.Tests/ThatHttpResponseMessage.HasProblemDetails.WithDetailTests.cs
+++ b/Tests/aweXpect.Web.Tests/ThatHttpResponseMessage.HasProblemDetails.WithDetailTests.cs
@@ -8,6 +8,32 @@ public sealed partial class HasProblemDetailsContent
{
public sealed class WithDetailTests
{
+ [Fact]
+ public async Task WhenDetailIsSpecifiedTwice_ShouldThrowInvalidOperationException()
+ {
+ HttpResponseMessage subject = ResponseBuilder.WithContent("{}");
+
+ async Task Act()
+ => await That(subject).HasProblemDetailsContent().WithDetail("foo").WithDetail("bar");
+
+ await That(Act).Throws()
+ .WithMessage("WithDetail cannot be specified more than once.")
+ .Because("the second detail would silently replace the first one");
+ }
+
+ [Fact]
+ public async Task WhenDetailIsSpecifiedTwiceAroundStatus_ShouldThrowInvalidOperationException()
+ {
+ HttpResponseMessage subject = ResponseBuilder.WithContent("{}");
+
+ async Task Act()
+ => await That(subject).HasProblemDetailsContent().WithDetail("foo").WithStatus(500).WithDetail("bar");
+
+ await That(Act).Throws()
+ .WithMessage("WithDetail cannot be specified more than once.")
+ .Because("the second detail would silently replace the first one");
+ }
+
[Fact]
public async Task WhenDetailIsNull_ShouldThrowArgumentNullException()
{
diff --git a/Tests/aweXpect.Web.Tests/ThatHttpResponseMessage.HasProblemDetails.WithInstanceTests.cs b/Tests/aweXpect.Web.Tests/ThatHttpResponseMessage.HasProblemDetails.WithInstanceTests.cs
index c879fb4..9df8c04 100644
--- a/Tests/aweXpect.Web.Tests/ThatHttpResponseMessage.HasProblemDetails.WithInstanceTests.cs
+++ b/Tests/aweXpect.Web.Tests/ThatHttpResponseMessage.HasProblemDetails.WithInstanceTests.cs
@@ -8,6 +8,32 @@ public sealed partial class HasProblemDetailsContent
{
public sealed class WithInstanceTests
{
+ [Fact]
+ public async Task WhenInstanceIsSpecifiedTwice_ShouldThrowInvalidOperationException()
+ {
+ HttpResponseMessage subject = ResponseBuilder.WithContent("{}");
+
+ async Task Act()
+ => await That(subject).HasProblemDetailsContent().WithInstance("foo").WithInstance("bar");
+
+ await That(Act).Throws()
+ .WithMessage("WithInstance cannot be specified more than once.")
+ .Because("the second instance would silently replace the first one");
+ }
+
+ [Fact]
+ public async Task WhenInstanceIsSpecifiedTwiceAroundStatus_ShouldThrowInvalidOperationException()
+ {
+ HttpResponseMessage subject = ResponseBuilder.WithContent("{}");
+
+ async Task Act()
+ => await That(subject).HasProblemDetailsContent().WithInstance("foo").WithStatus(500).WithInstance("bar");
+
+ await That(Act).Throws()
+ .WithMessage("WithInstance cannot be specified more than once.")
+ .Because("the second instance would silently replace the first one");
+ }
+
[Fact]
public async Task WhenInstanceIsNull_ShouldThrowArgumentNullException()
{
diff --git a/Tests/aweXpect.Web.Tests/ThatHttpResponseMessage.HasProblemDetails.WithStatusTests.cs b/Tests/aweXpect.Web.Tests/ThatHttpResponseMessage.HasProblemDetails.WithStatusTests.cs
index fa8a32b..3cb82c3 100644
--- a/Tests/aweXpect.Web.Tests/ThatHttpResponseMessage.HasProblemDetails.WithStatusTests.cs
+++ b/Tests/aweXpect.Web.Tests/ThatHttpResponseMessage.HasProblemDetails.WithStatusTests.cs
@@ -9,34 +9,29 @@ public sealed partial class HasProblemDetailsContent
public sealed class WithStatusTests
{
[Fact]
- public async Task WhenCheckingStatusDifferentlyTwice_ShouldFail()
+ public async Task WhenStatusIsSpecifiedTwice_ShouldThrowInvalidOperationException()
{
- HttpResponseMessage subject = ResponseBuilder
- .WithContent("""
- {
- "type": "my-type",
- "status": 500
- }
- """);
+ HttpResponseMessage subject = ResponseBuilder.WithContent("{}");
async Task Act()
=> await That(subject).HasProblemDetailsContent().WithStatus(500).WithStatus(501);
- await That(Act).Throws()
- .WithMessage("""
- Expected that subject
- has a ProblemDetails content with any type, status 500 and status 501,
- but it had status 500
+ await That(Act).Throws()
+ .WithMessage("WithStatus cannot be specified more than once.")
+ .Because("the second status would silently replace the first one");
+ }
- HTTP-Response:
- 200 OK HTTP/1.1
- Content-Type: text/plain; charset=utf-8
- Content-Length: *
- {
- "type": "my-type",
- "status": 500
- }
- """).AsWildcard();
+ [Fact]
+ public async Task WhenStatusIsSpecifiedTwiceAroundTitle_ShouldThrowInvalidOperationException()
+ {
+ HttpResponseMessage subject = ResponseBuilder.WithContent("{}");
+
+ async Task Act()
+ => await That(subject).HasProblemDetailsContent().WithStatus(500).WithTitle("foo").WithStatus(501);
+
+ await That(Act).Throws()
+ .WithMessage("WithStatus cannot be specified more than once.")
+ .Because("the second status would silently replace the first one");
}
[Theory]
@@ -84,7 +79,7 @@ public async Task WhenStatusMatches_ShouldSucceed()
""");
async Task Act()
- => await That(subject).HasProblemDetailsContent().WithStatus(500).WithStatus(500);
+ => await That(subject).HasProblemDetailsContent().WithStatus(500);
await That(Act).DoesNotThrow();
}
diff --git a/Tests/aweXpect.Web.Tests/ThatHttpResponseMessage.HasProblemDetails.WithTitleTests.cs b/Tests/aweXpect.Web.Tests/ThatHttpResponseMessage.HasProblemDetails.WithTitleTests.cs
index 52358db..2953adc 100644
--- a/Tests/aweXpect.Web.Tests/ThatHttpResponseMessage.HasProblemDetails.WithTitleTests.cs
+++ b/Tests/aweXpect.Web.Tests/ThatHttpResponseMessage.HasProblemDetails.WithTitleTests.cs
@@ -8,6 +8,32 @@ public sealed partial class HasProblemDetailsContent
{
public sealed class WithTitleTests
{
+ [Fact]
+ public async Task WhenTitleIsSpecifiedTwice_ShouldThrowInvalidOperationException()
+ {
+ HttpResponseMessage subject = ResponseBuilder.WithContent("{}");
+
+ async Task Act()
+ => await That(subject).HasProblemDetailsContent().WithTitle("foo").WithTitle("bar");
+
+ await That(Act).Throws()
+ .WithMessage("WithTitle cannot be specified more than once.")
+ .Because("the second title would silently replace the first one");
+ }
+
+ [Fact]
+ public async Task WhenTitleIsSpecifiedTwiceAroundStatus_ShouldThrowInvalidOperationException()
+ {
+ HttpResponseMessage subject = ResponseBuilder.WithContent("{}");
+
+ async Task Act()
+ => await That(subject).HasProblemDetailsContent().WithTitle("foo").WithStatus(500).WithTitle("bar");
+
+ await That(Act).Throws()
+ .WithMessage("WithTitle cannot be specified more than once.")
+ .Because("the second title would silently replace the first one");
+ }
+
[Fact]
public async Task WhenTitleIsNull_ShouldThrowArgumentNullException()
{
diff --git a/Tests/aweXpect.Web.Tests/ThatHttpResponseMessage.HasRequestMessage.Tests.cs b/Tests/aweXpect.Web.Tests/ThatHttpResponseMessage.HasRequestMessage.Tests.cs
index 50c0b8e..66d0b4b 100644
--- a/Tests/aweXpect.Web.Tests/ThatHttpResponseMessage.HasRequestMessage.Tests.cs
+++ b/Tests/aweXpect.Web.Tests/ThatHttpResponseMessage.HasRequestMessage.Tests.cs
@@ -36,7 +36,7 @@ await That(Act).Throws()
.WithMessage("""
Expected that subject
has a request message which has a string content equal to "bar",
- but it was "foo", which differs at index 0:
+ but it had string content "foo", which differs at index 0:
↓ (actual)
"foo"
"bar"
diff --git a/Tests/aweXpect.Web.Tests/ThatHttpResponseMessage.HasStatusCode.DifferentToTests.cs b/Tests/aweXpect.Web.Tests/ThatHttpResponseMessage.HasStatusCode.DifferentToTests.cs
index d511165..46c4cdf 100644
--- a/Tests/aweXpect.Web.Tests/ThatHttpResponseMessage.HasStatusCode.DifferentToTests.cs
+++ b/Tests/aweXpect.Web.Tests/ThatHttpResponseMessage.HasStatusCode.DifferentToTests.cs
@@ -9,6 +9,36 @@ public sealed partial class HasStatusCode
{
public sealed class DifferentToTests
{
+ [Fact]
+ public async Task WhenMemberIsACollection_Negated_ShouldUsePluralVerb()
+ {
+ HttpResponseMessage[] subjects = [ResponseBuilder,];
+
+ async Task Act()
+ => await That(new { Responses = subjects, })
+ .Whose(x => x.Responses, items => items.All()
+ .ComplyWith(item => item.DoesNotComplyWith(response => response.HasStatusCode().DifferentTo(HttpStatusCode.NotFound))));
+
+ await That(Act).Throws()
+ .WithMessage("""*whose Responses have status code 404 NotFound for all items,*""").AsWildcard()
+ .Because("the verb agrees with the plural member");
+ }
+
+ [Fact]
+ public async Task WhenMemberIsACollection_ShouldUsePluralVerb()
+ {
+ HttpResponseMessage[] subjects = [ResponseBuilder,];
+
+ async Task Act()
+ => await That(new { Responses = subjects, })
+ .Whose(x => x.Responses, items => items.All()
+ .ComplyWith(item => item.HasStatusCode().DifferentTo(HttpStatusCode.OK)));
+
+ await That(Act).Throws()
+ .WithMessage("""*whose Responses have status code different to 200 OK for all items,*""").AsWildcard()
+ .Because("the verb agrees with the plural member");
+ }
+
[Fact]
public async Task WhenStatusCodeDiffersFromExpected_ShouldSucceed()
{
diff --git a/Tests/aweXpect.Web.Tests/ThatHttpResponseMessage.HasStatusCode.EqualToTests.cs b/Tests/aweXpect.Web.Tests/ThatHttpResponseMessage.HasStatusCode.EqualToTests.cs
index 0a293f4..4744917 100644
--- a/Tests/aweXpect.Web.Tests/ThatHttpResponseMessage.HasStatusCode.EqualToTests.cs
+++ b/Tests/aweXpect.Web.Tests/ThatHttpResponseMessage.HasStatusCode.EqualToTests.cs
@@ -9,6 +9,36 @@ public sealed partial class HasStatusCode
{
public sealed class EqualToTests
{
+ [Fact]
+ public async Task WhenMemberIsACollection_Negated_ShouldUsePluralVerb()
+ {
+ HttpResponseMessage[] subjects = [ResponseBuilder,];
+
+ async Task Act()
+ => await That(new { Responses = subjects, })
+ .Whose(x => x.Responses, items => items.All()
+ .ComplyWith(item => item.DoesNotComplyWith(response => response.HasStatusCode().EqualTo(HttpStatusCode.OK))));
+
+ await That(Act).Throws()
+ .WithMessage("""*whose Responses do not have status code 200 OK for all items,*""").AsWildcard()
+ .Because("the verb agrees with the plural member");
+ }
+
+ [Fact]
+ public async Task WhenMemberIsACollection_ShouldUsePluralVerb()
+ {
+ HttpResponseMessage[] subjects = [ResponseBuilder,];
+
+ async Task Act()
+ => await That(new { Responses = subjects, })
+ .Whose(x => x.Responses, items => items.All()
+ .ComplyWith(item => item.HasStatusCode().EqualTo(HttpStatusCode.NotFound)));
+
+ await That(Act).Throws()
+ .WithMessage("""*whose Responses have status code 404 NotFound for all items,*""").AsWildcard()
+ .Because("the verb agrees with the plural member");
+ }
+
[Fact]
public async Task WhenFailing_ShouldIncludeRequestInMessage()
{
diff --git a/Tests/aweXpect.Web.Tests/ThatHttpResponseMessage.HasStatusCode.SuccessTests.cs b/Tests/aweXpect.Web.Tests/ThatHttpResponseMessage.HasStatusCode.SuccessTests.cs
index 0c5e042..a25375f 100644
--- a/Tests/aweXpect.Web.Tests/ThatHttpResponseMessage.HasStatusCode.SuccessTests.cs
+++ b/Tests/aweXpect.Web.Tests/ThatHttpResponseMessage.HasStatusCode.SuccessTests.cs
@@ -9,6 +9,20 @@ public sealed partial class HasStatusCode
{
public sealed class SuccessTests
{
+ [Fact]
+ public async Task WhenMemberIsACollection_ShouldUsePluralVerb()
+ {
+ HttpResponseMessage[] subjects = [ResponseBuilder.WithStatusCode(HttpStatusCode.NotFound),];
+
+ async Task Act()
+ => await That(new { Responses = subjects, })
+ .Whose(x => x.Responses, items => items.All()
+ .ComplyWith(item => item.HasStatusCode().Success()));
+
+ await That(Act).Throws()
+ .WithMessage("""*whose Responses have a success status code (2xx) for all items,*""").AsWildcard()
+ .Because("the verb agrees with the plural member");
+ }
[Theory]
[MemberData(nameof(SuccessStatusCodes), MemberType = typeof(ThatHttpResponseMessage))]
public async Task WhenStatusCodeIsExpected_ShouldSucceed(HttpStatusCode statusCode)
diff --git a/Tests/aweXpect.Web.Tests/ThatHttpResponseMessage.HasStatusCode.Tests.cs b/Tests/aweXpect.Web.Tests/ThatHttpResponseMessage.HasStatusCode.Tests.cs
index fafb429..cce3013 100644
--- a/Tests/aweXpect.Web.Tests/ThatHttpResponseMessage.HasStatusCode.Tests.cs
+++ b/Tests/aweXpect.Web.Tests/ThatHttpResponseMessage.HasStatusCode.Tests.cs
@@ -9,6 +9,21 @@ public sealed partial class HasStatusCode
{
public sealed class Tests
{
+ [Fact]
+ public async Task WhenMemberIsACollection_ShouldUsePluralVerb()
+ {
+ HttpResponseMessage[] subjects = [ResponseBuilder,];
+
+ async Task Act()
+ => await That(new { Responses = subjects, })
+ .Whose(x => x.Responses, items => items.All()
+ .ComplyWith(item => item.HasStatusCode(HttpStatusCode.NotFound)));
+
+ await That(Act).Throws()
+ .WithMessage("""*whose Responses have status code 404 NotFound for all items,*""").AsWildcard()
+ .Because("the verb agrees with the plural member");
+ }
+
[Fact]
public async Task WhenFailing_ShouldIncludeRequestInMessage()
{
diff --git a/Tests/aweXpect.Web.Tests/ThatUri.DoesNotHaveDefaultPort.Tests.cs b/Tests/aweXpect.Web.Tests/ThatUri.DoesNotHaveDefaultPort.Tests.cs
index 63b3162..6a730ab 100644
--- a/Tests/aweXpect.Web.Tests/ThatUri.DoesNotHaveDefaultPort.Tests.cs
+++ b/Tests/aweXpect.Web.Tests/ThatUri.DoesNotHaveDefaultPort.Tests.cs
@@ -6,6 +6,21 @@ public sealed class DoesNotHaveDefaultPort
{
public sealed class Tests
{
+ [Fact]
+ public async Task WhenMemberIsACollection_ShouldUsePluralVerb()
+ {
+ Uri[] subjects = [new Uri("https://awexpect.com/"),];
+
+ async Task Act()
+ => await That(new { Uris = subjects, })
+ .Whose(x => x.Uris, items => items.All()
+ .ComplyWith(item => item.DoesNotHaveDefaultPort()));
+
+ await That(Act).Throws()
+ .WithMessage("""*whose Uris do not have the default port for the used scheme for all items,*""").AsWildcard()
+ .Because("the verb agrees with the plural member");
+ }
+
[Fact]
public async Task WhenSubjectIsNull_ShouldFail()
{
diff --git a/Tests/aweXpect.Web.Tests/ThatUri.HasDefaultPort.Tests.cs b/Tests/aweXpect.Web.Tests/ThatUri.HasDefaultPort.Tests.cs
index fd2733d..62af8ff 100644
--- a/Tests/aweXpect.Web.Tests/ThatUri.HasDefaultPort.Tests.cs
+++ b/Tests/aweXpect.Web.Tests/ThatUri.HasDefaultPort.Tests.cs
@@ -6,6 +6,21 @@ public sealed class HasDefaultPort
{
public sealed class Tests
{
+ [Fact]
+ public async Task WhenMemberIsACollection_ShouldUsePluralVerb()
+ {
+ Uri[] subjects = [new Uri("https://awexpect.com:8080/"),];
+
+ async Task Act()
+ => await That(new { Uris = subjects, })
+ .Whose(x => x.Uris, items => items.All()
+ .ComplyWith(item => item.HasDefaultPort()));
+
+ await That(Act).Throws()
+ .WithMessage("""*whose Uris have the default port for the used scheme for all items,*""").AsWildcard()
+ .Because("the verb agrees with the plural member");
+ }
+
[Fact]
public async Task WhenSubjectIsNull_ShouldFail()
{
diff --git a/Tests/aweXpect.Web.Tests/ThatUri.IsAbsolute.Tests.cs b/Tests/aweXpect.Web.Tests/ThatUri.IsAbsolute.Tests.cs
index c23fcaa..3bd1cf3 100644
--- a/Tests/aweXpect.Web.Tests/ThatUri.IsAbsolute.Tests.cs
+++ b/Tests/aweXpect.Web.Tests/ThatUri.IsAbsolute.Tests.cs
@@ -6,6 +6,21 @@ public sealed class IsAbsolute
{
public sealed class Tests
{
+ [Fact]
+ public async Task WhenMemberIsACollection_ShouldUsePluralVerb()
+ {
+ Uri[] subjects = [new Uri("/foo", UriKind.Relative),];
+
+ async Task Act()
+ => await That(new { Uris = subjects, })
+ .Whose(x => x.Uris, items => items.All()
+ .ComplyWith(item => item.IsAbsolute()));
+
+ await That(Act).Throws()
+ .WithMessage("""*whose Uris are absolute URIs for all items,*""").AsWildcard()
+ .Because("the verb agrees with the plural member");
+ }
+
[Fact]
public async Task WhenSubjectIsNull_ShouldFail()
{
diff --git a/Tests/aweXpect.Web.Tests/ThatUri.IsFile.Tests.cs b/Tests/aweXpect.Web.Tests/ThatUri.IsFile.Tests.cs
index 23bd1a7..3f6a5b4 100644
--- a/Tests/aweXpect.Web.Tests/ThatUri.IsFile.Tests.cs
+++ b/Tests/aweXpect.Web.Tests/ThatUri.IsFile.Tests.cs
@@ -6,6 +6,21 @@ public sealed class IsFile
{
public sealed class Tests
{
+ [Fact]
+ public async Task WhenMemberIsACollection_ShouldUsePluralVerb()
+ {
+ Uri[] subjects = [new Uri("https://awexpect.com/"),];
+
+ async Task Act()
+ => await That(new { Uris = subjects, })
+ .Whose(x => x.Uris, items => items.All()
+ .ComplyWith(item => item.IsFile()));
+
+ await That(Act).Throws()
+ .WithMessage("""*whose Uris are file URIs for all items,*""").AsWildcard()
+ .Because("the verb agrees with the plural member");
+ }
+
[Fact]
public async Task WhenSubjectIsNull_ShouldFail()
{
diff --git a/Tests/aweXpect.Web.Tests/ThatUri.IsLoopback.Tests.cs b/Tests/aweXpect.Web.Tests/ThatUri.IsLoopback.Tests.cs
index 87c24e0..b95a810 100644
--- a/Tests/aweXpect.Web.Tests/ThatUri.IsLoopback.Tests.cs
+++ b/Tests/aweXpect.Web.Tests/ThatUri.IsLoopback.Tests.cs
@@ -6,6 +6,21 @@ public sealed class IsLoopback
{
public sealed class Tests
{
+ [Fact]
+ public async Task WhenMemberIsACollection_ShouldUsePluralVerb()
+ {
+ Uri[] subjects = [new Uri("https://awexpect.com/"),];
+
+ async Task Act()
+ => await That(new { Uris = subjects, })
+ .Whose(x => x.Uris, items => items.All()
+ .ComplyWith(item => item.IsLoopback()));
+
+ await That(Act).Throws()
+ .WithMessage("""*whose Uris reference the local host for all items,*""").AsWildcard()
+ .Because("the verb agrees with the plural member");
+ }
+
[Fact]
public async Task WhenSubjectIsNull_ShouldFail()
{
diff --git a/Tests/aweXpect.Web.Tests/ThatUri.IsNotAbsolute.Tests.cs b/Tests/aweXpect.Web.Tests/ThatUri.IsNotAbsolute.Tests.cs
index a43e5e1..04a925f 100644
--- a/Tests/aweXpect.Web.Tests/ThatUri.IsNotAbsolute.Tests.cs
+++ b/Tests/aweXpect.Web.Tests/ThatUri.IsNotAbsolute.Tests.cs
@@ -6,6 +6,21 @@ public sealed class IsNotAbsolute
{
public sealed class Tests
{
+ [Fact]
+ public async Task WhenMemberIsACollection_ShouldUsePluralVerb()
+ {
+ Uri[] subjects = [new Uri("https://awexpect.com/"),];
+
+ async Task Act()
+ => await That(new { Uris = subjects, })
+ .Whose(x => x.Uris, items => items.All()
+ .ComplyWith(item => item.IsNotAbsolute()));
+
+ await That(Act).Throws()
+ .WithMessage("""*whose Uris are not absolute URIs for all items,*""").AsWildcard()
+ .Because("the verb agrees with the plural member");
+ }
+
[Fact]
public async Task WhenSubjectIsNull_ShouldFail()
{
diff --git a/Tests/aweXpect.Web.Tests/ThatUri.IsNotFile.Tests.cs b/Tests/aweXpect.Web.Tests/ThatUri.IsNotFile.Tests.cs
index 3769369..d263f21 100644
--- a/Tests/aweXpect.Web.Tests/ThatUri.IsNotFile.Tests.cs
+++ b/Tests/aweXpect.Web.Tests/ThatUri.IsNotFile.Tests.cs
@@ -6,6 +6,21 @@ public sealed class IsNotFile
{
public sealed class Tests
{
+ [Fact]
+ public async Task WhenMemberIsACollection_ShouldUsePluralVerb()
+ {
+ Uri[] subjects = [new Uri("file:///C:/foo"),];
+
+ async Task Act()
+ => await That(new { Uris = subjects, })
+ .Whose(x => x.Uris, items => items.All()
+ .ComplyWith(item => item.IsNotFile()));
+
+ await That(Act).Throws()
+ .WithMessage("""*whose Uris are not file URIs for all items,*""").AsWildcard()
+ .Because("the verb agrees with the plural member");
+ }
+
[Fact]
public async Task WhenSubjectIsNull_ShouldFail()
{
diff --git a/Tests/aweXpect.Web.Tests/ThatUri.IsNotLoopback.Tests.cs b/Tests/aweXpect.Web.Tests/ThatUri.IsNotLoopback.Tests.cs
index 915445e..3e77c71 100644
--- a/Tests/aweXpect.Web.Tests/ThatUri.IsNotLoopback.Tests.cs
+++ b/Tests/aweXpect.Web.Tests/ThatUri.IsNotLoopback.Tests.cs
@@ -6,6 +6,21 @@ public sealed class IsNotLoopback
{
public sealed class Tests
{
+ [Fact]
+ public async Task WhenMemberIsACollection_ShouldUsePluralVerb()
+ {
+ Uri[] subjects = [new Uri("http://localhost/"),];
+
+ async Task Act()
+ => await That(new { Uris = subjects, })
+ .Whose(x => x.Uris, items => items.All()
+ .ComplyWith(item => item.IsNotLoopback()));
+
+ await That(Act).Throws()
+ .WithMessage("""*whose Uris do not reference the local host for all items,*""").AsWildcard()
+ .Because("the verb agrees with the plural member");
+ }
+
[Fact]
public async Task WhenSubjectIsNull_ShouldFail()
{
diff --git a/Tests/aweXpect.Web.Tests/ThatUri.IsNotUnc.Tests.cs b/Tests/aweXpect.Web.Tests/ThatUri.IsNotUnc.Tests.cs
index 16c9400..75fe9ae 100644
--- a/Tests/aweXpect.Web.Tests/ThatUri.IsNotUnc.Tests.cs
+++ b/Tests/aweXpect.Web.Tests/ThatUri.IsNotUnc.Tests.cs
@@ -6,6 +6,21 @@ public sealed class IsNotUnc
{
public sealed class Tests
{
+ [Fact]
+ public async Task WhenMemberIsACollection_ShouldUsePluralVerb()
+ {
+ Uri[] subjects = [new Uri(@"\\server\share"),];
+
+ async Task Act()
+ => await That(new { Uris = subjects, })
+ .Whose(x => x.Uris, items => items.All()
+ .ComplyWith(item => item.IsNotUnc()));
+
+ await That(Act).Throws()
+ .WithMessage("""*whose Uris are not UNC paths for all items,*""").AsWildcard()
+ .Because("the verb agrees with the plural member");
+ }
+
[Fact]
public async Task WhenSubjectIsNull_ShouldFail()
{
diff --git a/Tests/aweXpect.Web.Tests/ThatUri.IsUnc.Tests.cs b/Tests/aweXpect.Web.Tests/ThatUri.IsUnc.Tests.cs
index 3f9a24d..16c76f9 100644
--- a/Tests/aweXpect.Web.Tests/ThatUri.IsUnc.Tests.cs
+++ b/Tests/aweXpect.Web.Tests/ThatUri.IsUnc.Tests.cs
@@ -6,6 +6,21 @@ public sealed class IsUnc
{
public sealed class Tests
{
+ [Fact]
+ public async Task WhenMemberIsACollection_ShouldUsePluralVerb()
+ {
+ Uri[] subjects = [new Uri("https://awexpect.com/"),];
+
+ async Task Act()
+ => await That(new { Uris = subjects, })
+ .Whose(x => x.Uris, items => items.All()
+ .ComplyWith(item => item.IsUnc()));
+
+ await That(Act).Throws()
+ .WithMessage("""*whose Uris are UNC paths for all items,*""").AsWildcard()
+ .Because("the verb agrees with the plural member");
+ }
+
[Fact]
public async Task WhenSubjectIsNull_ShouldFail()
{