Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ public static partial class ThatStringShould
public static AndOrResult<string?, IThat<string?>> BeEmpty(
this IThat<string?> source)
=> new(source.ExpectationBuilder
.AddConstraint(new GenericConstraint(
.AddConstraint(new GenericConstraint<string>(
"",
_ => "be empty",
(a, _) => a == "",
Expand All @@ -27,7 +27,7 @@ public static partial class ThatStringShould
public static AndOrResult<string, IThat<string?>> NotBeEmpty(
this IThat<string?> source)
=> new(source.ExpectationBuilder
.AddConstraint(new GenericConstraint(
.AddConstraint(new GenericConstraint<string>(
"",
_ => "not be empty",
(a, _) => a != "",
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ public static partial class ThatStringShould
public static AndOrResult<string?, IThat<string?>> BeLowerCased(
this IThat<string?> source)
=> new(source.ExpectationBuilder
.AddConstraint(new GenericConstraint(
.AddConstraint(new GenericConstraint<string>(
"",
_ => "be lower-cased",
(a, _) => a != null && a == a.ToLowerInvariant(),
Expand All @@ -29,7 +29,7 @@ public static partial class ThatStringShould
public static AndOrResult<string, IThat<string?>> NotBeLowerCased(
this IThat<string?> source)
=> new(source.ExpectationBuilder
.AddConstraint(new GenericConstraint(
.AddConstraint(new GenericConstraint<string>(
"",
_ => "not be lower-cased",
(a, _) => a == null || a != a.ToLowerInvariant(),
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ public static partial class ThatStringShould
public static AndOrResult<string?, IThat<string?>> BeNull(
this IThat<string?> source)
=> new(source.ExpectationBuilder
.AddConstraint(new GenericConstraint(
.AddConstraint(new GenericConstraint<string>(
"",
_ => "be null",
(a, _) => a is null,
Expand All @@ -25,7 +25,7 @@ public static partial class ThatStringShould
public static AndOrResult<string, IThat<string?>> NotBeNull(
this IThat<string?> source)
=> new(source.ExpectationBuilder
.AddConstraint(new GenericConstraint(
.AddConstraint(new GenericConstraint<string>(
"",
_ => "not be null",
(a, _) => a is not null,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ public static partial class ThatStringShould
public static AndOrResult<string?, IThat<string?>> BeNullOrEmpty(
this IThat<string?> source)
=> new(source.ExpectationBuilder
.AddConstraint(new GenericConstraint(
.AddConstraint(new GenericConstraint<string>(
"",
_ => "be null or empty",
(a, _) => string.IsNullOrEmpty(a),
Expand All @@ -27,7 +27,7 @@ public static partial class ThatStringShould
public static AndOrResult<string, IThat<string?>> NotBeNullOrEmpty(
this IThat<string?> source)
=> new(source.ExpectationBuilder
.AddConstraint(new GenericConstraint(
.AddConstraint(new GenericConstraint<string>(
"",
_ => "not be null or empty",
(a, _) => !string.IsNullOrEmpty(a),
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ public static partial class ThatStringShould
public static AndOrResult<string?, IThat<string?>> BeNullOrWhiteSpace(
this IThat<string?> source)
=> new(source.ExpectationBuilder
.AddConstraint(new GenericConstraint(
.AddConstraint(new GenericConstraint<string>(
"",
_ => "be null or white-space",
(a, _) => string.IsNullOrWhiteSpace(a),
Expand All @@ -27,7 +27,7 @@ public static partial class ThatStringShould
public static AndOrResult<string, IThat<string?>> NotBeNullOrWhiteSpace(
this IThat<string?> source)
=> new(source.ExpectationBuilder
.AddConstraint(new GenericConstraint(
.AddConstraint(new GenericConstraint<string>(
"",
_ => "not be null or white-space",
(a, _) => !string.IsNullOrWhiteSpace(a),
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ public static partial class ThatStringShould
public static AndOrResult<string?, IThat<string?>> BeUpperCased(
this IThat<string?> source)
=> new(source.ExpectationBuilder
.AddConstraint(new GenericConstraint(
.AddConstraint(new GenericConstraint<string>(
"",
_ => "be upper-cased",
(a, _) => a != null && a == a.ToUpperInvariant(),
Expand All @@ -28,7 +28,7 @@ public static partial class ThatStringShould
public static AndOrResult<string, IThat<string?>> NotBeUpperCased(
this IThat<string?> source)
=> new(source.ExpectationBuilder
.AddConstraint(new GenericConstraint(
.AddConstraint(new GenericConstraint<string>(
"",
_ => "not be upper-cased",
(a, _) => a == null || a != a.ToUpperInvariant(),
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,56 @@
using System;
using Testably.Expectations.Core;
using Testably.Expectations.Core.Helpers;
using Testably.Expectations.Formatting;
using Testably.Expectations.Results;

namespace Testably.Expectations;

public static partial class ThatStringShould
{
/// <summary>
/// Verifies that the subject has the <paramref name="expected" /> length.
/// </summary>
public static AndOrResult<string?, IThat<string?>> HaveLength(
this IThat<string?> source,
int expected)
{
if (expected < 0)
{
throw new ArgumentOutOfRangeException(nameof(expected), expected,
"The expected length must be greater than or equal to zero.");
}

return new AndOrResult<string?, IThat<string?>>(source.ExpectationBuilder
.AddConstraint(new GenericConstraint<int>(
expected,
e => $"have length {e}",
(a, e) => a?.Length == e,
(a, _) => a == null
? "found <null>"
: $"it did have a length of {a.Length}:{Environment.NewLine}{Formatter.Format(a).Indent()}")),
source);
}

/// <summary>
/// Verifies that the subject does not have the <paramref name="unexpected" /> length.
/// </summary>
public static AndOrResult<string, IThat<string?>> NotHaveLength(
this IThat<string?> source,
int unexpected)
{
if (unexpected < 0)
{
throw new ArgumentOutOfRangeException(nameof(unexpected), unexpected,
"The unexpected length must be greater than or equal to zero.");
}

return new AndOrResult<string, IThat<string?>>(source.ExpectationBuilder
.AddConstraint(new GenericConstraint<int>(
unexpected,
e => $"not have length {e}",
(a, e) => a?.Length != e,
(a, _) => $"it did:{Environment.NewLine}{Formatter.Format(a).Indent()}")),
source);
}
}
10 changes: 5 additions & 5 deletions Source/Testably.Expectations/That/Strings/ThatStringShould.cs
Original file line number Diff line number Diff line change
Expand Up @@ -15,11 +15,11 @@ public static partial class ThatStringShould
public static IThat<string?> Should(this IExpectSubject<string?> subject)
=> subject.Should(_ => { });

private readonly struct GenericConstraint(
string? expected,
Func<string?, string> expectation,
Func<string?, string?, bool> condition,
Func<string?, string?, string> failureMessageFactory) : IValueConstraint<string?>
private readonly struct GenericConstraint<T>(
T expected,
Func<T, string> expectation,
Func<string?, T, bool> condition,
Func<string?, T, string> failureMessageFactory) : IValueConstraint<string?>
{
public ConstraintResult IsMetBy(string? actual)
{
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -694,6 +694,7 @@ namespace Testably.Expectations
public static Testably.Expectations.Results.AndOrResult<string?, Testably.Expectations.Core.IThat<string?>> BeUpperCased(this Testably.Expectations.Core.IThat<string?> source) { }
public static Testably.Expectations.Results.StringCountResult<string?, Testably.Expectations.Core.IThat<string?>> Contain(this Testably.Expectations.Core.IThat<string?> source, string expected) { }
public static Testably.Expectations.Results.StringEqualityResult<string?, Testably.Expectations.Core.IThat<string?>> EndWith(this Testably.Expectations.Core.IThat<string?> source, string expected) { }
public static Testably.Expectations.Results.AndOrResult<string?, Testably.Expectations.Core.IThat<string?>> HaveLength(this Testably.Expectations.Core.IThat<string?> source, int expected) { }
public static Testably.Expectations.Results.AndOrResult<string, Testably.Expectations.Core.IThat<string?>> NotBeEmpty(this Testably.Expectations.Core.IThat<string?> source) { }
public static Testably.Expectations.Results.AndOrResult<string, Testably.Expectations.Core.IThat<string?>> NotBeLowerCased(this Testably.Expectations.Core.IThat<string?> source) { }
public static Testably.Expectations.Results.AndOrResult<string, Testably.Expectations.Core.IThat<string?>> NotBeNull(this Testably.Expectations.Core.IThat<string?> source) { }
Expand All @@ -702,6 +703,7 @@ namespace Testably.Expectations
public static Testably.Expectations.Results.AndOrResult<string, Testably.Expectations.Core.IThat<string?>> NotBeUpperCased(this Testably.Expectations.Core.IThat<string?> source) { }
public static Testably.Expectations.Results.StringEqualityResult<string?, Testably.Expectations.Core.IThat<string?>> NotContain(this Testably.Expectations.Core.IThat<string?> source, string unexpected) { }
public static Testably.Expectations.Results.StringEqualityResult<string?, Testably.Expectations.Core.IThat<string?>> NotEndWith(this Testably.Expectations.Core.IThat<string?> source, string unexpected) { }
public static Testably.Expectations.Results.AndOrResult<string, Testably.Expectations.Core.IThat<string?>> NotHaveLength(this Testably.Expectations.Core.IThat<string?> source, int unexpected) { }
public static Testably.Expectations.Results.StringEqualityResult<string?, Testably.Expectations.Core.IThat<string?>> NotStartWith(this Testably.Expectations.Core.IThat<string?> source, string unexpected) { }
public static Testably.Expectations.Core.IThat<string?> Should(this Testably.Expectations.Core.IExpectSubject<string?> subject) { }
public static Testably.Expectations.Results.StringEqualityResult<string?, Testably.Expectations.Core.IThat<string?>> StartWith(this Testably.Expectations.Core.IThat<string?> source, string expected) { }
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -694,6 +694,7 @@ namespace Testably.Expectations
public static Testably.Expectations.Results.AndOrResult<string?, Testably.Expectations.Core.IThat<string?>> BeUpperCased(this Testably.Expectations.Core.IThat<string?> source) { }
public static Testably.Expectations.Results.StringCountResult<string?, Testably.Expectations.Core.IThat<string?>> Contain(this Testably.Expectations.Core.IThat<string?> source, string expected) { }
public static Testably.Expectations.Results.StringEqualityResult<string?, Testably.Expectations.Core.IThat<string?>> EndWith(this Testably.Expectations.Core.IThat<string?> source, string expected) { }
public static Testably.Expectations.Results.AndOrResult<string?, Testably.Expectations.Core.IThat<string?>> HaveLength(this Testably.Expectations.Core.IThat<string?> source, int expected) { }
public static Testably.Expectations.Results.AndOrResult<string, Testably.Expectations.Core.IThat<string?>> NotBeEmpty(this Testably.Expectations.Core.IThat<string?> source) { }
public static Testably.Expectations.Results.AndOrResult<string, Testably.Expectations.Core.IThat<string?>> NotBeLowerCased(this Testably.Expectations.Core.IThat<string?> source) { }
public static Testably.Expectations.Results.AndOrResult<string, Testably.Expectations.Core.IThat<string?>> NotBeNull(this Testably.Expectations.Core.IThat<string?> source) { }
Expand All @@ -702,6 +703,7 @@ namespace Testably.Expectations
public static Testably.Expectations.Results.AndOrResult<string, Testably.Expectations.Core.IThat<string?>> NotBeUpperCased(this Testably.Expectations.Core.IThat<string?> source) { }
public static Testably.Expectations.Results.StringEqualityResult<string?, Testably.Expectations.Core.IThat<string?>> NotContain(this Testably.Expectations.Core.IThat<string?> source, string unexpected) { }
public static Testably.Expectations.Results.StringEqualityResult<string?, Testably.Expectations.Core.IThat<string?>> NotEndWith(this Testably.Expectations.Core.IThat<string?> source, string unexpected) { }
public static Testably.Expectations.Results.AndOrResult<string, Testably.Expectations.Core.IThat<string?>> NotHaveLength(this Testably.Expectations.Core.IThat<string?> source, int unexpected) { }
public static Testably.Expectations.Results.StringEqualityResult<string?, Testably.Expectations.Core.IThat<string?>> NotStartWith(this Testably.Expectations.Core.IThat<string?> source, string unexpected) { }
public static Testably.Expectations.Core.IThat<string?> Should(this Testably.Expectations.Core.IExpectSubject<string?> subject) { }
public static Testably.Expectations.Results.StringEqualityResult<string?, Testably.Expectations.Core.IThat<string?>> StartWith(this Testably.Expectations.Core.IThat<string?> source, string expected) { }
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -639,6 +639,7 @@ namespace Testably.Expectations
public static Testably.Expectations.Results.AndOrResult<string?, Testably.Expectations.Core.IThat<string?>> BeUpperCased(this Testably.Expectations.Core.IThat<string?> source) { }
public static Testably.Expectations.Results.StringCountResult<string?, Testably.Expectations.Core.IThat<string?>> Contain(this Testably.Expectations.Core.IThat<string?> source, string expected) { }
public static Testably.Expectations.Results.StringEqualityResult<string?, Testably.Expectations.Core.IThat<string?>> EndWith(this Testably.Expectations.Core.IThat<string?> source, string expected) { }
public static Testably.Expectations.Results.AndOrResult<string?, Testably.Expectations.Core.IThat<string?>> HaveLength(this Testably.Expectations.Core.IThat<string?> source, int expected) { }
public static Testably.Expectations.Results.AndOrResult<string, Testably.Expectations.Core.IThat<string?>> NotBeEmpty(this Testably.Expectations.Core.IThat<string?> source) { }
public static Testably.Expectations.Results.AndOrResult<string, Testably.Expectations.Core.IThat<string?>> NotBeLowerCased(this Testably.Expectations.Core.IThat<string?> source) { }
public static Testably.Expectations.Results.AndOrResult<string, Testably.Expectations.Core.IThat<string?>> NotBeNull(this Testably.Expectations.Core.IThat<string?> source) { }
Expand All @@ -647,6 +648,7 @@ namespace Testably.Expectations
public static Testably.Expectations.Results.AndOrResult<string, Testably.Expectations.Core.IThat<string?>> NotBeUpperCased(this Testably.Expectations.Core.IThat<string?> source) { }
public static Testably.Expectations.Results.StringEqualityResult<string?, Testably.Expectations.Core.IThat<string?>> NotContain(this Testably.Expectations.Core.IThat<string?> source, string unexpected) { }
public static Testably.Expectations.Results.StringEqualityResult<string?, Testably.Expectations.Core.IThat<string?>> NotEndWith(this Testably.Expectations.Core.IThat<string?> source, string unexpected) { }
public static Testably.Expectations.Results.AndOrResult<string, Testably.Expectations.Core.IThat<string?>> NotHaveLength(this Testably.Expectations.Core.IThat<string?> source, int unexpected) { }
public static Testably.Expectations.Results.StringEqualityResult<string?, Testably.Expectations.Core.IThat<string?>> NotStartWith(this Testably.Expectations.Core.IThat<string?> source, string unexpected) { }
public static Testably.Expectations.Core.IThat<string?> Should(this Testably.Expectations.Core.IExpectSubject<string?> subject) { }
public static Testably.Expectations.Results.StringEqualityResult<string?, Testably.Expectations.Core.IThat<string?>> StartWith(this Testably.Expectations.Core.IThat<string?> source, string expected) { }
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,127 @@
using Testably.Expectations.Formatting;

namespace Testably.Expectations.Tests.ThatTests.Strings;

public sealed partial class StringShould
{
public class HaveLengthTests
{
[Fact]
public async Task WhenActualIsNull_ShouldFail()
{
string? subject = null;

async Task Act()
=> await That(subject).Should().HaveLength(0);

await That(Act).Should().Throw<XunitException>()
.WithMessage("""
Expected subject to
have length 0,
but found <null>.
""");
}

[Fact]
public async Task WhenExpectedLengthIsNegative_ShouldThrowArgumentOutOfRangeException()
{
string subject = "";

async Task Act()
=> await That(subject).Should().HaveLength(-1);

await That(Act).Should().Throw<ArgumentOutOfRangeException>()
.WithParamName("expected").And
.WithMessage("*The expected length must be greater than or equal to zero*")
.AsWildcard();
}

[Theory]
[InlineData("", 1)]
[InlineData("abc", 4)]
[InlineData(" a b c ", 6)]
public async Task WhenLengthDiffers_ShouldFail(string subject, int length)
{
async Task Act()
=> await That(subject).Should().HaveLength(length);

await That(Act).Should().Throw<XunitException>()
.WithMessage($"""
Expected subject to
have length {length},
but it did have a length of {subject.Length}:
{Formatter.Format(subject)}.
""");
}

[Theory]
[InlineData("", 0)]
[InlineData("abc", 3)]
[InlineData(" a b c ", 7)]
public async Task WhenLengthMatches_ShouldSucceed(string subject, int length)
{
async Task Act()
=> await That(subject).Should().HaveLength(length);

await That(Act).Should().NotThrow();
}
}

public sealed class NotHaveLengthTests
{
[Fact]
public async Task WhenActualIsNull_ShouldSucceed()
{
string? subject = null;

async Task Act()
=> await That(subject).Should().NotHaveLength(0);

await That(Act).Should().NotThrow();
}

[Theory]
[InlineData("", 1)]
[InlineData("abc", 4)]
[InlineData(" a b c ", 6)]
public async Task WhenLengthDiffers_ShouldSucceed(string subject, int length)
{
async Task Act()
=> await That(subject).Should().NotHaveLength(length);

await That(Act).Should().NotThrow();
}

[Theory]
[InlineData("", 0)]
[InlineData("abc", 3)]
[InlineData(" a b c ", 7)]
public async Task WhenLengthMatches_ShouldFail(string subject, int length)
{
async Task Act()
=> await That(subject).Should().NotHaveLength(length);

await That(Act).Should().Throw<XunitException>()
.WithMessage($"""
Expected subject to
not have length {length},
but it did:
{Formatter.Format(subject)}.
""");
}

[Fact]
public async Task WhenUnexpectedLengthIsNegative_ShouldThrowArgumentOutOfRangeException()
{
string subject = "";

async Task Act()
=> await That(subject).Should().NotHaveLength(-1);

await That(Act).Should().Throw<ArgumentOutOfRangeException>()
.WithParamName("unexpected").And
.WithMessage("*The unexpected length must be greater than or equal to zero*")
.AsWildcard();
}
}
}
Loading