Skip to content

Commit 9bcd8b4

Browse files
authored
feat: include actual and expected context in string contains (#838)
This pull request enhances error messages in string containment assertions by adding detailed "Actual" and "Expected" context sections. The changes make test failure messages more informative by explicitly showing both the full string being tested and the substring being searched for, rather than using vague pronouns like "it". ### Key Changes: - Modified the `ContainsConstraint` class to accept an `ExpectationBuilder` parameter and add context information when assertions fail - Updated error messages to include the expected substring explicitly (e.g., "contained 'investigator' once" instead of "contained it once") - Added "Actual" and "Expected" sections to all string contains/does not contain assertion error messages - Updated all corresponding test expectations across multiple test files to match the new error message format
1 parent 6c57313 commit 9bcd8b4

12 files changed

Lines changed: 250 additions & 40 deletions

Source/aweXpect/That/Strings/ThatString.Contains.cs

Lines changed: 26 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -28,8 +28,8 @@ public static partial class ThatString
2828
Quantifier quantifier = new();
2929
StringEqualityOptions options = new();
3030
return new StringEqualityTypeCountResult<string?, IThat<string?>>(
31-
source.Get().ExpectationBuilder.AddConstraint((it, grammars) =>
32-
new ContainsConstraint(it, grammars, expected, quantifier, options)),
31+
source.Get().ExpectationBuilder.AddConstraint((expectationBuilder, it, grammars) =>
32+
new ContainsConstraint(expectationBuilder, it, grammars, expected, quantifier, options)),
3333
source,
3434
quantifier,
3535
options);
@@ -51,14 +51,15 @@ public static partial class ThatString
5151
Quantifier quantifier = new();
5252
StringEqualityOptions options = new();
5353
return new StringEqualityTypeCountResult<string?, IThat<string?>>(
54-
source.Get().ExpectationBuilder.AddConstraint((it, grammars) =>
55-
new ContainsConstraint(it, grammars, unexpected, quantifier, options).Invert()),
54+
source.Get().ExpectationBuilder.AddConstraint((expectationBuilder, it, grammars) =>
55+
new ContainsConstraint(expectationBuilder, it, grammars, unexpected, quantifier, options).Invert()),
5656
source,
5757
quantifier,
5858
options);
5959
}
6060

6161
private sealed class ContainsConstraint(
62+
ExpectationBuilder expectationBuilder,
6263
string it,
6364
ExpectationGrammars grammars,
6465
string? expected,
@@ -83,6 +84,15 @@ public async Task<ConstraintResult> IsMetBy(string? actual, CancellationToken ca
8384

8485
_actualCount = await CountOccurrences(actual, expected, options);
8586
Outcome = quantifier.Check(_actualCount, true) ?? _isNegated ? Outcome.Success : Outcome.Failure;
87+
if (Outcome != Outcome.Success && !string.IsNullOrEmpty(actual))
88+
{
89+
expectationBuilder.AddContext(new ResultContext.Fixed("Actual", actual));
90+
if (!string.IsNullOrEmpty(expected))
91+
{
92+
expectationBuilder.AddContext(new ResultContext.Fixed("Expected", expected));
93+
}
94+
}
95+
8696
return this;
8797
}
8898

@@ -165,19 +175,27 @@ public override void AppendResult(StringBuilder stringBuilder, string? indentati
165175
{
166176
if (_actualCount == 0)
167177
{
168-
stringBuilder.Append(it).Append(" did not contain it in ");
178+
stringBuilder.Append(it).Append(" did not contain ");
179+
Formatter.Format(stringBuilder, expected);
180+
stringBuilder.Append(" in ");
169181
}
170182
else if (_actualCount == 1)
171183
{
172-
stringBuilder.Append(it).Append(" contained it once in ");
184+
stringBuilder.Append(it).Append(" contained ");
185+
Formatter.Format(stringBuilder, expected);
186+
stringBuilder.Append(" once in ");
173187
}
174188
else if (_actualCount == 2)
175189
{
176-
stringBuilder.Append(it).Append(" contained it twice in ");
190+
stringBuilder.Append(it).Append(" contained ");
191+
Formatter.Format(stringBuilder, expected);
192+
stringBuilder.Append(" twice in ");
177193
}
178194
else
179195
{
180-
stringBuilder.Append(it).Append(" contained it ").Append(_actualCount).Append(" times in ");
196+
stringBuilder.Append(it).Append(" contained ");
197+
Formatter.Format(stringBuilder, expected);
198+
stringBuilder.Append(' ').Append(_actualCount).Append(" times in ");
181199
}
182200

183201
Formatter.Format(stringBuilder, _actual);

Tests/aweXpect.Tests/Strings/ThatString.Contains.AtLeastTests.cs

Lines changed: 14 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -33,7 +33,13 @@ await That(Act).Throws<XunitException>()
3333
.WithMessage("""
3434
Expected that subject
3535
contains "in" at least 5 times,
36-
but it contained it 3 times in "In this text in between the word an investigator should find the word 'IN' multiple times."
36+
but it contained "in" 3 times in "In this text in between the word an investigator should find the word 'IN' multiple times."
37+
38+
Actual:
39+
In this text in between the word an investigator should find the word 'IN' multiple times.
40+
41+
Expected:
42+
in
3743
""");
3844
}
3945

@@ -51,7 +57,13 @@ await That(Act).Throws<XunitException>()
5157
.WithMessage("""
5258
Expected that subject
5359
contains "text that does not occur" at least once,
54-
but it did not contain it in "In this text in between the word an investigator should find the word 'IN' multiple times."
60+
but it did not contain "text that does not occur" in "In this text in between the word an investigator should find the word 'IN' multiple times."
61+
62+
Actual:
63+
In this text in between the word an investigator should find the word 'IN' multiple times.
64+
65+
Expected:
66+
text that does not occur
5567
""");
5668
}
5769

Tests/aweXpect.Tests/Strings/ThatString.Contains.AtMostTests.cs

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,13 @@ await That(Act).Throws<XunitException>()
2020
.WithMessage("""
2121
Expected that subject
2222
contains "in" at most twice,
23-
but it contained it 3 times in "In this text in between the word an investigator should find the word 'IN' multiple times."
23+
but it contained "in" 3 times in "In this text in between the word an investigator should find the word 'IN' multiple times."
24+
25+
Actual:
26+
In this text in between the word an investigator should find the word 'IN' multiple times.
27+
28+
Expected:
29+
in
2430
""");
2531
}
2632

Tests/aweXpect.Tests/Strings/ThatString.Contains.BetweenTests.cs

Lines changed: 14 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,13 @@ await That(Act).Throws<XunitException>()
2020
.WithMessage("""
2121
Expected that subject
2222
contains "in" between 4 and 9 times,
23-
but it contained it 3 times in "In this text in between the word an investigator should find the word 'IN' multiple times."
23+
but it contained "in" 3 times in "In this text in between the word an investigator should find the word 'IN' multiple times."
24+
25+
Actual:
26+
In this text in between the word an investigator should find the word 'IN' multiple times.
27+
28+
Expected:
29+
in
2430
""");
2531
}
2632

@@ -38,7 +44,13 @@ await That(Act).Throws<XunitException>()
3844
.WithMessage("""
3945
Expected that subject
4046
contains "in" between 1 and 2 times,
41-
but it contained it 3 times in "In this text in between the word an investigator should find the word 'IN' multiple times."
47+
but it contained "in" 3 times in "In this text in between the word an investigator should find the word 'IN' multiple times."
48+
49+
Actual:
50+
In this text in between the word an investigator should find the word 'IN' multiple times.
51+
52+
Expected:
53+
in
4254
""");
4355
}
4456

Tests/aweXpect.Tests/Strings/ThatString.Contains.ExactlyTests.cs

Lines changed: 14 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -49,7 +49,13 @@ await That(Act).Throws<XunitException>()
4949
.WithMessage("""
5050
Expected that subject
5151
contains "in" exactly 4 times,
52-
but it contained it 3 times in "In this text in between the word an investigator should find the word 'IN' multiple times."
52+
but it contained "in" 3 times in "In this text in between the word an investigator should find the word 'IN' multiple times."
53+
54+
Actual:
55+
In this text in between the word an investigator should find the word 'IN' multiple times.
56+
57+
Expected:
58+
in
5359
""");
5460
}
5561

@@ -67,7 +73,13 @@ await That(Act).Throws<XunitException>()
6773
.WithMessage("""
6874
Expected that subject
6975
contains "in" exactly twice,
70-
but it contained it 3 times in "In this text in between the word an investigator should find the word 'IN' multiple times."
76+
but it contained "in" 3 times in "In this text in between the word an investigator should find the word 'IN' multiple times."
77+
78+
Actual:
79+
In this text in between the word an investigator should find the word 'IN' multiple times.
80+
81+
Expected:
82+
in
7183
""");
7284
}
7385
}

Tests/aweXpect.Tests/Strings/ThatString.Contains.LessThanTests.cs

Lines changed: 14 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -33,7 +33,13 @@ await That(Act).Throws<XunitException>()
3333
.WithMessage("""
3434
Expected that subject
3535
contains "in" less than 3 times,
36-
but it contained it 3 times in "In this text in between the word an investigator should find the word 'IN' multiple times."
36+
but it contained "in" 3 times in "In this text in between the word an investigator should find the word 'IN' multiple times."
37+
38+
Actual:
39+
In this text in between the word an investigator should find the word 'IN' multiple times.
40+
41+
Expected:
42+
in
3743
""");
3844
}
3945

@@ -51,7 +57,13 @@ await That(Act).Throws<XunitException>()
5157
.WithMessage("""
5258
Expected that subject
5359
contains "in" less than once,
54-
but it contained it 3 times in "In this text in between the word an investigator should find the word 'IN' multiple times."
60+
but it contained "in" 3 times in "In this text in between the word an investigator should find the word 'IN' multiple times."
61+
62+
Actual:
63+
In this text in between the word an investigator should find the word 'IN' multiple times.
64+
65+
Expected:
66+
in
5567
""");
5668
}
5769

Tests/aweXpect.Tests/Strings/ThatString.Contains.MoreThanTests.cs

Lines changed: 14 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,13 @@ await That(Act).Throws<XunitException>()
2020
.WithMessage("""
2121
Expected that subject
2222
contains "text that does not occur" more than once,
23-
but it did not contain it in "In this text in between the word an investigator should find the word 'IN' multiple times."
23+
but it did not contain "text that does not occur" in "In this text in between the word an investigator should find the word 'IN' multiple times."
24+
25+
Actual:
26+
In this text in between the word an investigator should find the word 'IN' multiple times.
27+
28+
Expected:
29+
text that does not occur
2430
""");
2531
}
2632

@@ -53,7 +59,13 @@ await That(Act).Throws<XunitException>()
5359
.WithMessage($"""
5460
Expected that subject
5561
contains "in" more than {minimum} times,
56-
but it contained it 3 times in "In this text in between the word an investigator should find the word 'IN' multiple times."
62+
but it contained "in" 3 times in "In this text in between the word an investigator should find the word 'IN' multiple times."
63+
64+
Actual:
65+
In this text in between the word an investigator should find the word 'IN' multiple times.
66+
67+
Expected:
68+
in
5769
""");
5870
}
5971

Tests/aweXpect.Tests/Strings/ThatString.Contains.NeverTests.cs

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -33,7 +33,13 @@ await That(Act).Throws<XunitException>()
3333
.WithMessage("""
3434
Expected that subject
3535
does not contain "investigator",
36-
but it contained it once in "In this text in between the word an investigator should find the word 'IN' multiple times."
36+
but it contained "investigator" once in "In this text in between the word an investigator should find the word 'IN' multiple times."
37+
38+
Actual:
39+
In this text in between the word an investigator should find the word 'IN' multiple times.
40+
41+
Expected:
42+
investigator
3743
""");
3844
}
3945
}

Tests/aweXpect.Tests/Strings/ThatString.Contains.OnceTests.cs

Lines changed: 14 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -33,7 +33,13 @@ await That(Act).Throws<XunitException>()
3333
.WithMessage("""
3434
Expected that subject
3535
contains "detective" exactly once,
36-
but it did not contain it in "In this text in between the word an investigator should find the word 'IN' multiple times."
36+
but it did not contain "detective" in "In this text in between the word an investigator should find the word 'IN' multiple times."
37+
38+
Actual:
39+
In this text in between the word an investigator should find the word 'IN' multiple times.
40+
41+
Expected:
42+
detective
3743
""");
3844
}
3945

@@ -51,7 +57,13 @@ await That(Act).Throws<XunitException>()
5157
.WithMessage("""
5258
Expected that subject
5359
contains "word" exactly once,
54-
but it contained it twice in "In this text in between the word an investigator should find the word 'IN' multiple times."
60+
but it contained "word" twice in "In this text in between the word an investigator should find the word 'IN' multiple times."
61+
62+
Actual:
63+
In this text in between the word an investigator should find the word 'IN' multiple times.
64+
65+
Expected:
66+
word
5567
""");
5668
}
5769
}

Tests/aweXpect.Tests/Strings/ThatString.Contains.Tests.cs

Lines changed: 21 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -78,7 +78,13 @@ await That(Act).Throws<XunitException>()
7878
.WithMessage("""
7979
Expected that subject
8080
contains "not" at least once,
81-
but it did not contain it in "some text"
81+
but it did not contain "not" in "some text"
82+
83+
Actual:
84+
some text
85+
86+
Expected:
87+
not
8288
""");
8389
}
8490
}
@@ -99,7 +105,13 @@ await That(Act).Throws<XunitException>()
99105
.WithMessage("""
100106
Expected that subject
101107
contains "in" at least 7 times ignoring case,
102-
but it contained it 5 times in "In this text in between the word an investigator should find the word 'IN' multiple times."
108+
but it contained "in" 5 times in "In this text in between the word an investigator should find the word 'IN' multiple times."
109+
110+
Actual:
111+
In this text in between the word an investigator should find the word 'IN' multiple times.
112+
113+
Expected:
114+
in
103115
""");
104116
}
105117

@@ -151,7 +163,13 @@ await That(Act).Throws<XunitException>()
151163
.WithMessage("""
152164
Expected that subject
153165
contains "in" exactly 5 times using IgnoreCaseForVocalsComparer,
154-
but it contained it 4 times in "In this text in between the word an investigator should find the word 'IN' multiple times."
166+
but it contained "in" 4 times in "In this text in between the word an investigator should find the word 'IN' multiple times."
167+
168+
Actual:
169+
In this text in between the word an investigator should find the word 'IN' multiple times.
170+
171+
Expected:
172+
in
155173
""");
156174
}
157175
}

0 commit comments

Comments
 (0)