diff --git a/Pipeline/Build.cs b/Pipeline/Build.cs
index a07a0cc08..25356ef59 100644
--- a/Pipeline/Build.cs
+++ b/Pipeline/Build.cs
@@ -19,7 +19,7 @@ partial class Build : NukeBuild
///
/// Afterward, you can update the package reference in `Directory.Packages.props` and reset this flag.
///
- readonly BuildScope BuildScope = BuildScope.Default;
+ readonly BuildScope BuildScope = BuildScope.CoreOnly;
[Parameter("Github Token")] readonly string GithubToken;
diff --git a/Source/aweXpect.Core/Core/ExpectationBuilder.cs b/Source/aweXpect.Core/Core/ExpectationBuilder.cs
index c5eb9bce8..f889cabea 100644
--- a/Source/aweXpect.Core/Core/ExpectationBuilder.cs
+++ b/Source/aweXpect.Core/Core/ExpectationBuilder.cs
@@ -44,7 +44,7 @@ public abstract class ExpectationBuilder
protected ExpectationBuilder(string subjectExpression, ExpectationGrammars grammars = ExpectationGrammars.None)
{
AweXpectInitialization.EnsureInitialized();
- Subject = subjectExpression;
+ Subject = subjectExpression.TrimCommonWhiteSpace();
ExpectationGrammars = grammars;
}
diff --git a/Source/aweXpect.Core/Core/Helpers/StringExtensions.cs b/Source/aweXpect.Core/Core/Helpers/StringExtensions.cs
index ec90a0a94..ff111981e 100644
--- a/Source/aweXpect.Core/Core/Helpers/StringExtensions.cs
+++ b/Source/aweXpect.Core/Core/Helpers/StringExtensions.cs
@@ -1,6 +1,7 @@
using System;
using System.Diagnostics.CodeAnalysis;
using System.Linq;
+using System.Text;
namespace aweXpect.Core.Helpers;
@@ -90,4 +91,54 @@ public static string SubstringUntilFirst(this string name, char c)
const char ellipsis = '\u2026';
return $"{value.Substring(0, indexOfWordBoundary)}{ellipsis}";
}
+
+ public static string TrimCommonWhiteSpace(this string value)
+ {
+ string[] lines = value.Split('\n');
+ if (lines.Length <= 1)
+ {
+ return value;
+ }
+
+ StringBuilder sb = new();
+ foreach (char c in lines[1])
+ {
+ if (char.IsWhiteSpace(c))
+ {
+ sb.Append(c);
+ }
+ else
+ {
+ break;
+ }
+ }
+
+ string commonWhiteSpace = sb.ToString();
+
+ for (int l = 2; l < lines.Length; l++)
+ {
+ if (lines[l].StartsWith(commonWhiteSpace))
+ {
+ continue;
+ }
+
+ for (int i = 0; i < Math.Min(lines[l].Length, commonWhiteSpace.Length); i++)
+ {
+ if (lines[l][i] != commonWhiteSpace[i])
+ {
+ commonWhiteSpace = commonWhiteSpace[..i];
+ break;
+ }
+ }
+ }
+
+ sb.Clear();
+ sb.Append(lines[0]);
+ foreach (string? line in lines.Skip(1))
+ {
+ sb.Append('\n').Append(line[commonWhiteSpace.Length..]);
+ }
+
+ return sb.ToString();
+ }
}
diff --git a/Tests/aweXpect.Core.Tests/Core/ExpectationBuilderTests.cs b/Tests/aweXpect.Core.Tests/Core/ExpectationBuilderTests.cs
index 596339837..60891ac66 100644
--- a/Tests/aweXpect.Core.Tests/Core/ExpectationBuilderTests.cs
+++ b/Tests/aweXpect.Core.Tests/Core/ExpectationBuilderTests.cs
@@ -66,6 +66,29 @@ public async Task ForMember_WithSucceedingExpectation_ShouldReturnSuccessConstra
await That(constraintResult.GetExpectationText()).IsEqualTo("length equal to 3");
}
+ [Fact]
+ public async Task WhenSubjectHasMultipleLines_ShouldTrimCommonWhiteSpace()
+ {
+ async Task Act() => await That(new[]
+ {
+ 1, 2, 3,
+ }).IsEmpty();
+
+ await That(Act).Throws()
+ .WithMessage("""
+ Expected that new[]
+ {
+ 1, 2, 3,
+ }
+ is empty,
+ but it was [
+ 1,
+ 2,
+ 3
+ ]
+ """);
+ }
+
[Fact]
public async Task WhenTypeImplementsIDescribableSubject_ShouldUseToStringFromIt()
{
diff --git a/Tests/aweXpect.Core.Tests/Core/Helpers/StringExtensionsTests.cs b/Tests/aweXpect.Core.Tests/Core/Helpers/StringExtensionsTests.cs
index 8129d08a1..7089c9cc3 100644
--- a/Tests/aweXpect.Core.Tests/Core/Helpers/StringExtensionsTests.cs
+++ b/Tests/aweXpect.Core.Tests/Core/Helpers/StringExtensionsTests.cs
@@ -4,239 +4,353 @@ namespace aweXpect.Core.Tests.Core.Helpers;
public class StringExtensionsTests
{
- [Fact]
- public async Task DisplayWhitespace_ShouldEscapeNewlines()
+ public sealed class DisplayWhitespace
{
- string input = "\r,\n;\t ";
- string expected = @"\r,\n;\t ";
+ [Fact]
+ public async Task ShouldEscapeNewlines()
+ {
+ string input = "\r,\n;\t ";
+ string expected = @"\r,\n;\t ";
- string result = input.DisplayWhitespace();
+ string result = input.DisplayWhitespace();
- await That(result).IsEqualTo(expected);
- }
+ await That(result).IsEqualTo(expected);
+ }
- [Fact]
- public async Task DisplayWhitespace_WhenNull_ShouldReturnNull()
- {
- string? input = null;
+ [Fact]
+ public async Task WhenNull_ShouldReturnNull()
+ {
+ string? input = null;
- string? result = input.DisplayWhitespace();
+ string? result = input.DisplayWhitespace();
- await That(result).IsNull();
+ await That(result).IsNull();
+ }
}
-
- [Fact]
- public async Task Indent_WhenIndentationIsEmpty_ShouldReturnInput()
+ public sealed class Indent
{
- string input = "foo\nbar";
+ [Fact]
+ public async Task WhenIndentationIsEmpty_ShouldReturnInput()
+ {
+ string input = "foo\nbar";
- string result = input.Indent("");
+ string result = input.Indent("");
- await That(result).IsEqualTo(input);
- }
+ await That(result).IsEqualTo(input);
+ }
- [Fact]
- public async Task Indent_WhenIndentationIsNotEmpty_ShouldReturnIndentedInput()
- {
- string input = "foo\nbar";
- string expected = " foo\n bar";
+ [Fact]
+ public async Task WhenIndentationIsNotEmpty_ShouldReturnIndentedInput()
+ {
+ string input = "foo\nbar";
+ string expected = " foo\n bar";
- string result = input.Indent(" ");
+ string result = input.Indent(" ");
- await That(result).IsEqualTo(expected);
- }
+ await That(result).IsEqualTo(expected);
+ }
- [Fact]
- public async Task Indent_WhenIndentFirstLineIsFalse_ShouldOnlyIndentSubsequentLines()
- {
- string input = "foo\nbar";
- string expected = "foo\n bar";
+ [Fact]
+ public async Task WhenIndentFirstLineIsFalse_ShouldOnlyIndentSubsequentLines()
+ {
+ string input = "foo\nbar";
+ string expected = "foo\n bar";
- string result = input.Indent(" ", false);
+ string result = input.Indent(" ", false);
- await That(result).IsEqualTo(expected);
- }
+ await That(result).IsEqualTo(expected);
+ }
- [Fact]
- public async Task Indent_WhenNull_ShouldReturnNull()
- {
- string? input = null;
+ [Fact]
+ public async Task WhenNull_ShouldReturnNull()
+ {
+ string? input = null;
- string? result = input.Indent();
+ string? result = input.Indent();
- await That(result).IsNull();
+ await That(result).IsNull();
+ }
}
- [Theory]
- [InlineData("", "a ")]
- [InlineData("apple", "an apple")]
- [InlineData("bee", "a bee")]
- [InlineData("Exception", "an Exception")]
- [InlineData("NotSupportedException", "a NotSupportedException")]
- public async Task PrependAOrAn(string input, string expected)
+ public sealed class PrependAOrAn
{
- string result = input.PrependAOrAn();
-
- await That(result).IsEqualTo(expected);
+ [Theory]
+ [InlineData("", "a ")]
+ [InlineData("apple", "an apple")]
+ [InlineData("bee", "a bee")]
+ [InlineData("Exception", "an Exception")]
+ [InlineData("NotSupportedException", "a NotSupportedException")]
+ public async Task ShouldReturnExpectedResult(string input, string expected)
+ {
+ string result = input.PrependAOrAn();
+
+ await That(result).IsEqualTo(expected);
+ }
}
- [Fact]
- public async Task RemoveNewlineStyle_ShouldReplaceNewlinesWithSlashN()
+ public sealed class RemoveNewlineStyle
{
- string input = "\ra\r\nb\nc";
- string expected = "\na\nb\nc";
+ [Fact]
+ public async Task ShouldReplaceNewlinesWithSlashN()
+ {
+ string input = "\ra\r\nb\nc";
+ string expected = "\na\nb\nc";
- string result = input.RemoveNewlineStyle();
+ string result = input.RemoveNewlineStyle();
- await That(result).IsEqualTo(expected);
- }
+ await That(result).IsEqualTo(expected);
+ }
- [Fact]
- public async Task RemoveNewlineStyle_WhenNull_ShouldReturnNull()
- {
- string? input = null;
+ [Fact]
+ public async Task WhenNull_ShouldReturnNull()
+ {
+ string? input = null;
- string? result = input.RemoveNewlineStyle();
+ string? result = input.RemoveNewlineStyle();
- await That(result).IsNull();
+ await That(result).IsNull();
+ }
}
- [Fact]
- public async Task SubstringUntilFirst_WhenFirstCharacter_ShouldReturnEmptyString()
+ public sealed class SubstringUntilFirst
{
- string input = "a,b,c";
+ [Fact]
+ public async Task WhenFirstCharacter_ShouldReturnEmptyString()
+ {
+ string input = "a,b,c";
- string result = input.SubstringUntilFirst('a');
+ string result = input.SubstringUntilFirst('a');
- await That(result).IsEqualTo("");
- }
+ await That(result).IsEqualTo("");
+ }
- [Fact]
- public async Task SubstringUntilFirst_WhenNotPresent_ShouldReturnString()
- {
- string input = "foo";
+ [Fact]
+ public async Task WhenNotPresent_ShouldReturnString()
+ {
+ string input = "foo";
- string result = input.SubstringUntilFirst('X');
+ string result = input.SubstringUntilFirst('X');
- await That(result).IsEqualTo(input);
- }
+ await That(result).IsEqualTo(input);
+ }
- [Fact]
- public async Task SubstringUntilFirst_WhenPresent_ShouldReturnSubstringUntilFirstOccurrence()
- {
- string input = "a,b,c";
+ [Fact]
+ public async Task WhenPresent_ShouldReturnSubstringUntilFirstOccurrence()
+ {
+ string input = "a,b,c";
- string result = input.SubstringUntilFirst(',');
+ string result = input.SubstringUntilFirst(',');
- await That(result).IsEqualTo("a");
+ await That(result).IsEqualTo("a");
+ }
}
-
- [Fact]
- public async Task ToSingleLine_ShouldEscapeNewlines()
+ public sealed class ToSingleLine
{
- string input = "\r,\n;\t ";
- string expected = "\\r,\\n;\t ";
+ [Fact]
+ public async Task ShouldEscapeNewlines()
+ {
+ string input = "\r,\n;\t ";
+ string expected = "\\r,\\n;\t ";
- string result = input.ToSingleLine();
+ string result = input.ToSingleLine();
- await That(result).IsEqualTo(expected);
- }
+ await That(result).IsEqualTo(expected);
+ }
- [Fact]
- public async Task ToSingleLine_WhenNull_ShouldReturnNull()
- {
- string? input = null;
+ [Fact]
+ public async Task WhenNull_ShouldReturnNull()
+ {
+ string? input = null;
- string? result = input.ToSingleLine();
+ string? result = input.ToSingleLine();
- await That(result).IsNull();
+ await That(result).IsNull();
+ }
}
- [Fact]
- public async Task TruncateWithEllipsis_WhenLonger_ShouldTruncateWithEllipsis()
+ public sealed class TruncateWithEllipsis
{
- string input = "12345678910";
- string expected = "1234567891…";
+ [Fact]
+ public async Task WhenLonger_ShouldTruncateWithEllipsis()
+ {
+ string input = "12345678910";
+ string expected = "1234567891…";
- string result = input.TruncateWithEllipsis(10);
+ string result = input.TruncateWithEllipsis(10);
- await That(result).IsEqualTo(expected);
- }
+ await That(result).IsEqualTo(expected);
+ }
- [Fact]
- public async Task TruncateWithEllipsis_WhenNull_ShouldReturnNull()
- {
- string? input = null;
+ [Fact]
+ public async Task WhenNull_ShouldReturnNull()
+ {
+ string? input = null;
- string? result = input.TruncateWithEllipsis(10);
+ string? result = input.TruncateWithEllipsis(10);
- await That(result).IsNull();
- }
+ await That(result).IsNull();
+ }
- [Fact]
- public async Task TruncateWithEllipsis_WhenShorter_ShouldReturnInput()
- {
- string input = "1234567890";
+ [Fact]
+ public async Task WhenShorter_ShouldReturnInput()
+ {
+ string input = "1234567890";
- string result = input.TruncateWithEllipsis(10);
+ string result = input.TruncateWithEllipsis(10);
- await That(result).IsEqualTo(input);
+ await That(result).IsEqualTo(input);
+ }
}
- [Fact]
- public async Task TruncateWithEllipsisOnWord_WhenLongerWithoutWordBoundary_ShouldTruncateOnWordWithEllipsis()
+ public sealed class TruncateWithEllipsisOnWord
{
- string input = "some word boundary";
- string expected = "some word…";
+ [Fact]
+ public async Task WhenLongerWithoutWordBoundary_ShouldTruncateOnWordWithEllipsis()
+ {
+ string input = "some word boundary";
+ string expected = "some word…";
- string result = input.TruncateWithEllipsisOnWord(11);
+ string result = input.TruncateWithEllipsisOnWord(11);
- await That(result).IsEqualTo(expected);
- }
+ await That(result).IsEqualTo(expected);
+ }
- [Fact]
- public async Task TruncateWithEllipsisOnWord_WhenLongerWithoutWordBoundary_ShouldTruncateWithEllipsis()
- {
- string input = "12345678910";
- string expected = "1234567891…";
+ [Fact]
+ public async Task WhenLongerWithoutWordBoundary_ShouldTruncateWithEllipsis()
+ {
+ string input = "12345678910";
+ string expected = "1234567891…";
- string result = input.TruncateWithEllipsisOnWord(10);
+ string result = input.TruncateWithEllipsisOnWord(10);
- await That(result).IsEqualTo(expected);
- }
+ await That(result).IsEqualTo(expected);
+ }
- [Fact]
- public async Task TruncateWithEllipsisOnWord_WhenNull_ShouldReturnNull()
- {
- string? input = null;
+ [Fact]
+ public async Task WhenNull_ShouldReturnNull()
+ {
+ string? input = null;
- string? result = input.TruncateWithEllipsisOnWord(10);
+ string? result = input.TruncateWithEllipsisOnWord(10);
- await That(result).IsNull();
- }
+ await That(result).IsNull();
+ }
- [Fact]
- public async Task TruncateWithEllipsisOnWord_WhenShorter_ShouldReturnInput()
- {
- string input = "1234567890";
+ [Fact]
+ public async Task WhenShorter_ShouldReturnInput()
+ {
+ string input = "1234567890";
+
+ string result = input.TruncateWithEllipsisOnWord(10);
- string result = input.TruncateWithEllipsisOnWord(10);
+ await That(result).IsEqualTo(input);
+ }
- await That(result).IsEqualTo(input);
+ [Theory]
+ [InlineData("another word-boundary", "another wo…")]
+ [InlineData("_another word-boundary", "_another…")]
+ public async Task WhenWordBoundaryIsBelow80Percent_ShouldTruncateWithEllipsis(
+ string input, string expected)
+ {
+ string result = input.TruncateWithEllipsisOnWord(10);
+
+ await That(result).IsEqualTo(expected);
+ }
}
- [Theory]
- [InlineData("another word-boundary", "another wo…")]
- [InlineData("_another word-boundary", "_another…")]
- public async Task TruncateWithEllipsisOnWord_WhenWordBoundaryIsBelow80Percent_ShouldTruncateWithEllipsis(
- string input, string expected)
+ public sealed class TrimCommonWhiteSpace
{
- string result = input.TruncateWithEllipsisOnWord(10);
-
- await That(result).IsEqualTo(expected);
+ [Fact]
+ public async Task WhenAnyLaterLineHasNoWhiteSpace_ShouldReturnUnchangedInput()
+ {
+ string input = """
+ foo
+ bar
+ baz
+ bay
+ """;
+
+ string result = input.TrimCommonWhiteSpace();
+
+ await That(result).IsEqualTo(input);
+ }
+
+ [Fact]
+ public async Task WhenEmpty_ShouldReturnEmptyString()
+ {
+ string input = string.Empty;
+
+ string result = input.TrimCommonWhiteSpace();
+
+ await That(result).IsEmpty();
+ }
+
+ [Fact]
+ public async Task WhenLinesHaveDifferentWhiteSpace_ShouldKeepAllWhiteSpace()
+ {
+ string input = """
+ foo
+ bar
+ baz
+ """;
+
+ string result = input.TrimCommonWhiteSpace();
+
+ await That(result).IsEqualTo("""
+ foo
+ bar
+ baz
+ """);
+ }
+
+ [Fact]
+ public async Task WhenLinesHaveSomeCommonWhiteSpace_ShouldTrim()
+ {
+ string input = """
+ foo
+ bar
+ baz
+ bay
+ """;
+
+ string result = input.TrimCommonWhiteSpace();
+
+ await That(result).IsEqualTo("""
+ foo
+ bar
+ baz
+ bay
+ """);
+ }
+
+ [Fact]
+ public async Task WhenOnlyHasOneLine_ShouldReturnLine()
+ {
+ string input = "foo";
+
+ string result = input.TrimCommonWhiteSpace();
+
+ await That(result).IsEqualTo(input);
+ }
+
+ [Fact]
+ public async Task WhenTwoLines_ShouldTrimSecondLine()
+ {
+ string input = """
+ foo
+ bar
+ """;
+
+ string result = input.TrimCommonWhiteSpace();
+
+ await That(result).IsEqualTo("""
+ foo
+ bar
+ """);
+ }
}
}