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
4 changes: 2 additions & 2 deletions Source/aweXpect.Core/Core/ExpectationBuilder.cs
Original file line number Diff line number Diff line change
Expand Up @@ -203,7 +203,7 @@ public MemberExpectationBuilder<TSource, TTarget> ForMember<TSource, TTarget>(
}

Node root = _node;
_node = _node.AddMapping(memberAccessor, expectationTextGenerator) ?? _node;
_node = _node.AddMapping(memberAccessor, expectationTextGenerator);
if (replaceIt)
{
_it = memberAccessor.ToString().Trim();
Expand Down Expand Up @@ -247,7 +247,7 @@ public MemberExpectationBuilder<TSource, TTarget> ForAsyncMember<TSource, TTarge
}

Node root = _node;
_node = _node.AddAsyncMapping(memberAccessor, expectationTextGenerator) ?? _node;
_node = _node.AddAsyncMapping(memberAccessor, expectationTextGenerator);
if (replaceIt)
{
_it = memberAccessor.ToString().Trim();
Expand Down
3 changes: 2 additions & 1 deletion Source/aweXpect.Core/Core/ManualExpectationBuilder.cs
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,8 @@ namespace aweXpect.Core;
public class ManualExpectationBuilder<TValue>(
ExpectationBuilder? inner,
ExpectationGrammars grammars = ExpectationGrammars.None)
: ExpectationBuilder("", grammars), IEqualityComparer<ManualExpectationBuilder<TValue>>
: ExpectationBuilder("", grammars),
IEqualityComparer<ManualExpectationBuilder<TValue>>
{
/// <inheritdoc cref="IEqualityComparer{T}.Equals(T, T)" />
public bool Equals(ManualExpectationBuilder<TValue>? x, ManualExpectationBuilder<TValue>? y)
Expand Down
3 changes: 1 addition & 2 deletions Source/aweXpect.Core/Core/MemberAccessor.cs
Original file line number Diff line number Diff line change
Expand Up @@ -67,8 +67,7 @@ public static MemberAccessor<TSource, TTarget> FromFuncAsMemberAccessor(
public override bool Equals(object? obj) => obj is MemberAccessor<TSource, TTarget> other && Equals(other);

private bool Equals(MemberAccessor<TSource, TTarget> other)
=> ToString().Equals(other.ToString()) &&
_accessor.ToString()?.Equals(other._accessor.ToString()) == true;
=> ToString().Equals(other.ToString());

/// <inheritdoc cref="object.GetHashCode()" />
public override int GetHashCode() => ToString().GetHashCode();
Expand Down
4 changes: 2 additions & 2 deletions Source/aweXpect.Core/Core/Nodes/AndNode.cs
Original file line number Diff line number Diff line change
Expand Up @@ -29,14 +29,14 @@ public override void AddConstraint(IConstraint constraint)
=> Current.AddConstraint(constraint);

/// <inheritdoc />
public override Node? AddMapping<TValue, TTarget>(MemberAccessor<TValue, TTarget> memberAccessor,
public override Node AddMapping<TValue, TTarget>(MemberAccessor<TValue, TTarget> memberAccessor,
Action<MemberAccessor, StringBuilder>? expectationTextGenerator = null)
where TValue : default
where TTarget : default
=> Current.AddMapping(memberAccessor, expectationTextGenerator);

/// <inheritdoc />
public override Node? AddAsyncMapping<TValue, TTarget>(
public override Node AddAsyncMapping<TValue, TTarget>(
MemberAccessor<TValue, Task<TTarget>> memberAccessor,
Action<MemberAccessor, StringBuilder>? expectationTextGenerator = null)
where TValue : default
Expand Down
4 changes: 2 additions & 2 deletions Source/aweXpect.Core/Core/Nodes/ExpectationNode.cs
Original file line number Diff line number Diff line change
Expand Up @@ -37,7 +37,7 @@ public override void AddConstraint(IConstraint constraint)
}

/// <inheritdoc />
public override Node? AddMapping<TValue, TTarget>(MemberAccessor<TValue, TTarget> memberAccessor,
public override Node AddMapping<TValue, TTarget>(MemberAccessor<TValue, TTarget> memberAccessor,
Action<MemberAccessor, StringBuilder>? expectationTextGenerator = null)
where TValue : default
where TTarget : default
Expand All @@ -50,7 +50,7 @@ public override void AddConstraint(IConstraint constraint)
}

/// <inheritdoc />
public override Node? AddAsyncMapping<TValue, TTarget>(
public override Node AddAsyncMapping<TValue, TTarget>(
MemberAccessor<TValue, Task<TTarget>> memberAccessor,
Action<MemberAccessor, StringBuilder>? expectationTextGenerator = null)
where TValue : default
Expand Down
4 changes: 2 additions & 2 deletions Source/aweXpect.Core/Core/Nodes/Node.cs
Original file line number Diff line number Diff line change
Expand Up @@ -20,14 +20,14 @@ internal abstract class Node
/// Add a mapping constraint which maps the value according to the <paramref name="memberAccessor" /> to a member
/// and applies this value to the inner expectations.
/// </summary>
public abstract Node? AddMapping<TValue, TTarget>(MemberAccessor<TValue, TTarget> memberAccessor,
public abstract Node AddMapping<TValue, TTarget>(MemberAccessor<TValue, TTarget> memberAccessor,
Action<MemberAccessor, StringBuilder>? expectationTextGenerator = null);

/// <summary>
/// Add a mapping constraint which maps the value according to the <paramref name="memberAccessor" /> asynchronously
/// to a member and applies this value to the inner expectations.
/// </summary>
public abstract Node? AddAsyncMapping<TValue, TTarget>(
public abstract Node AddAsyncMapping<TValue, TTarget>(
MemberAccessor<TValue, Task<TTarget>> memberAccessor,
Action<MemberAccessor, StringBuilder>? expectationTextGenerator = null);

Expand Down
4 changes: 2 additions & 2 deletions Source/aweXpect.Core/Core/Nodes/OrNode.cs
Original file line number Diff line number Diff line change
Expand Up @@ -29,14 +29,14 @@ public override void AddConstraint(IConstraint constraint)
=> Current.AddConstraint(constraint);

/// <inheritdoc />
public override Node? AddMapping<TValue, TTarget>(MemberAccessor<TValue, TTarget> memberAccessor,
public override Node AddMapping<TValue, TTarget>(MemberAccessor<TValue, TTarget> memberAccessor,
Action<MemberAccessor, StringBuilder>? expectationTextGenerator = null)
where TValue : default
where TTarget : default
=> Current.AddMapping(memberAccessor, expectationTextGenerator);

/// <inheritdoc />
public override Node? AddAsyncMapping<TValue, TTarget>(
public override Node AddAsyncMapping<TValue, TTarget>(
MemberAccessor<TValue, Task<TTarget>> memberAccessor,
Action<MemberAccessor, StringBuilder>? expectationTextGenerator = null)
where TValue : default
Expand Down
8 changes: 4 additions & 4 deletions Source/aweXpect.Core/Core/Nodes/WhichNode.cs
Original file line number Diff line number Diff line change
Expand Up @@ -43,19 +43,19 @@ public override void AddConstraint(IConstraint constraint)
=> _inner?.AddConstraint(constraint);

/// <inheritdoc />
public override Node? AddMapping<TValue, TTarget>(MemberAccessor<TValue, TTarget> memberAccessor,
public override Node AddMapping<TValue, TTarget>(MemberAccessor<TValue, TTarget> memberAccessor,
Action<MemberAccessor, StringBuilder>? expectationTextGenerator = null)
where TValue : default
where TTarget : default
=> _inner?.AddMapping(memberAccessor, expectationTextGenerator);
=> _inner?.AddMapping(memberAccessor, expectationTextGenerator) ?? this;

/// <inheritdoc />
public override Node? AddAsyncMapping<TValue, TTarget>(
public override Node AddAsyncMapping<TValue, TTarget>(
MemberAccessor<TValue, Task<TTarget>> memberAccessor,
Action<MemberAccessor, StringBuilder>? expectationTextGenerator = null)
where TValue : default
where TTarget : default
=> _inner?.AddAsyncMapping(memberAccessor, expectationTextGenerator);
=> _inner?.AddAsyncMapping(memberAccessor, expectationTextGenerator) ?? this;

/// <inheritdoc />
public override void AddNode(Node node, string? separator = null)
Expand Down
72 changes: 72 additions & 0 deletions Tests/aweXpect.Core.Tests/Core/ExpectationBuilderTests.cs
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,26 @@ namespace aweXpect.Core.Tests.Core;

public class ExpectationBuilderTests
{
[Fact]
public async Task ForAsyncMember_ShouldUseAndResetExpectationGrammars()
{
ManualExpectationBuilder<string> sut = new(null);
ExpectationGrammars usedExpectationGrammars = ExpectationGrammars.None;

sut.ForAsyncMember(MemberAccessor<string, Task<int>>.FromFunc(x => Task.FromResult(x.Length), "length "))
.AddExpectations(expectationBuilder => expectationBuilder.AddConstraint((_, g)
=>
{
usedExpectationGrammars = g;
return new DummyConstraint<int>(v => v == 2, "equal to 2");
}), _ => ExpectationGrammars.Nested);

await sut.IsMetBy("bar", null!, CancellationToken.None);

await That(usedExpectationGrammars).IsEqualTo(ExpectationGrammars.Nested);
await That(sut.ExpectationGrammars).IsEqualTo(ExpectationGrammars.None);
}

[Fact]
public async Task ForAsyncMember_WithFailingExpectation_ShouldReturnFailureConstraintResult()
{
Expand Down Expand Up @@ -36,6 +56,42 @@ public async Task ForAsyncMember_WithSucceedingExpectation_ShouldReturnSuccessCo
await That(constraintResult.GetExpectationText()).IsEqualTo("length equal to 3");
}

[Fact]
public async Task ForAsyncMember_WithValidation_ShouldIncludeValidation()
{
ManualExpectationBuilder<string> sut = new(null);

sut.ForAsyncMember(MemberAccessor<string, Task<int>>.FromFunc(x => Task.FromResult(x.Length), "length "))
.Validate((_, _) => new DummyConstraint<string>(_ => false, "validated and "))
.AddExpectations(expectationBuilder => expectationBuilder.AddConstraint((_, _)
=> new DummyConstraint<int>(v => v == 3, "equal to 3")));

ConstraintResult constraintResult = await sut.IsMetBy("bar", null!, CancellationToken.None);

await That(constraintResult.Outcome).IsEqualTo(Outcome.Failure);
await That(constraintResult.GetExpectationText()).IsEqualTo("validated and length equal to 3");
}

[Fact]
public async Task ForMember_ShouldUseAndResetExpectationGrammars()
{
ManualExpectationBuilder<string> sut = new(null);
ExpectationGrammars usedExpectationGrammars = ExpectationGrammars.None;

sut.ForMember(MemberAccessor<string, int>.FromFunc(x => x.Length, "length "))
.AddExpectations(expectationBuilder => expectationBuilder.AddConstraint((_, g)
=>
{
usedExpectationGrammars = g;
return new DummyConstraint<int>(v => v == 2, "equal to 2");
}), _ => ExpectationGrammars.Nested);

await sut.IsMetBy("bar", null!, CancellationToken.None);

await That(usedExpectationGrammars).IsEqualTo(ExpectationGrammars.Nested);
await That(sut.ExpectationGrammars).IsEqualTo(ExpectationGrammars.None);
}

[Fact]
public async Task ForMember_WithFailingExpectation_ShouldReturnFailureConstraintResult()
{
Expand Down Expand Up @@ -66,6 +122,22 @@ public async Task ForMember_WithSucceedingExpectation_ShouldReturnSuccessConstra
await That(constraintResult.GetExpectationText()).IsEqualTo("length equal to 3");
}

[Fact]
public async Task ForMember_WithValidation_ShouldIncludeValidation()
{
ManualExpectationBuilder<string> sut = new(null);

sut.ForMember(MemberAccessor<string, int>.FromFunc(x => x.Length, "length "))
.Validate((_, _) => new DummyConstraint<string>(_ => false, "validated and "))
.AddExpectations(expectationBuilder => expectationBuilder.AddConstraint((_, _)
=> new DummyConstraint<int>(v => v == 3, "equal to 3")));

ConstraintResult constraintResult = await sut.IsMetBy("bar", null!, CancellationToken.None);

await That(constraintResult.Outcome).IsEqualTo(Outcome.Failure);
await That(constraintResult.GetExpectationText()).IsEqualTo("validated and length equal to 3");
}

[Fact]
public async Task WhenSubjectHasMultipleLines_ShouldTrimCommonWhiteSpace()
{
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,55 @@
namespace aweXpect.Core.Tests.Core;

public sealed class ExpectationGrammarsExtensionsTests
{
[Theory]
[InlineData(ExpectationGrammars.None, false)]
[InlineData(ExpectationGrammars.Negated, true)]
[InlineData(ExpectationGrammars.Plural | ExpectationGrammars.Negated, true)]
[InlineData(ExpectationGrammars.Nested | ExpectationGrammars.Plural, false)]
[InlineData(ExpectationGrammars.Nested | ExpectationGrammars.Plural | ExpectationGrammars.Negated, true)]
public async Task IsNegated_ShouldReturnExpectedValue(ExpectationGrammars input, bool expected)
{
bool result = input.IsNegated();

await That(result).IsEqualTo(expected);
}

[Theory]
[InlineData(ExpectationGrammars.None, false)]
[InlineData(ExpectationGrammars.Nested, true)]
[InlineData(ExpectationGrammars.Plural | ExpectationGrammars.Nested, true)]
[InlineData(ExpectationGrammars.Negated | ExpectationGrammars.Plural, false)]
[InlineData(ExpectationGrammars.Nested | ExpectationGrammars.Plural | ExpectationGrammars.Negated, true)]
public async Task IsNested_ShouldReturnExpectedValue(ExpectationGrammars input, bool expected)
{
bool result = input.IsNested();

await That(result).IsEqualTo(expected);
}

[Theory]
[InlineData(ExpectationGrammars.None, false)]
[InlineData(ExpectationGrammars.Plural, true)]
[InlineData(ExpectationGrammars.Plural | ExpectationGrammars.Nested, true)]
[InlineData(ExpectationGrammars.Negated | ExpectationGrammars.Nested, false)]
[InlineData(ExpectationGrammars.Nested | ExpectationGrammars.Plural | ExpectationGrammars.Negated, true)]
public async Task IsPlural_ShouldReturnExpectedValue(ExpectationGrammars input, bool expected)
{
bool result = input.IsPlural();

await That(result).IsEqualTo(expected);
}

[Theory]
[InlineData(ExpectationGrammars.None, ExpectationGrammars.Negated)]
[InlineData(ExpectationGrammars.Plural, ExpectationGrammars.Plural | ExpectationGrammars.Negated)]
[InlineData(ExpectationGrammars.Nested | ExpectationGrammars.Plural,
ExpectationGrammars.Nested | ExpectationGrammars.Plural | ExpectationGrammars.Negated)]
public async Task Negate_ShouldAddNegated(ExpectationGrammars input, ExpectationGrammars expected)
{
ExpectationGrammars result = input.Negate();

await That(result).IsEqualTo(expected);
}
}
22 changes: 22 additions & 0 deletions Tests/aweXpect.Core.Tests/Core/ManualExpectationBuilderTests.cs
Original file line number Diff line number Diff line change
Expand Up @@ -113,6 +113,28 @@ public async Task Equals_WithSelf_ShouldBeTrue()
await That(result).IsTrue();
}

[Fact]
public async Task GetHashCode_DifferentConstraint_ShouldNotBeEqual()
{
ManualExpectationBuilder<int> sut1 = new(null);
sut1.AddConstraint((_, _, _) => new DummyConstraint("foo"));
ManualExpectationBuilder<int> sut2 = new(null);
sut2.ForWhich<int, int>(x => x)
.AddConstraint((_, _, _) => new DummyConstraint("foo"));

await That(sut1.GetHashCode()).IsNotEqualTo(sut2.GetHashCode());
}

[Fact]
public async Task GetHashCode_SameConstraint_ShouldBeEqual()
{
ManualExpectationBuilder<int> sut1 = new(null);
sut1.AddConstraint((_, _, _) => new DummyConstraint("foo"));
ManualExpectationBuilder<int> sut2 = new(null);
sut2.AddConstraint((_, _, _) => new DummyConstraint("foo"));

await That(sut1.GetHashCode()).IsEqualTo(sut2.GetHashCode());
}

[Fact]
public async Task IsMet_ShouldThrowNotSupportedException()
Expand Down
62 changes: 62 additions & 0 deletions Tests/aweXpect.Core.Tests/Core/MemberAccessorTests.cs
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,50 @@

public sealed class MemberAccessorTests
{
[Theory]
[InlineData(".Length ", true)]
[InlineData(".SomethingElse ", false)]
public async Task Equals_ShouldCompareStringRepresentation(string otherStringRepresentation, bool expectedResult)
{
MemberAccessor<string, int> sut = MemberAccessor<string, int>.FromExpression(x => x.Length);
MemberAccessor<string, int> other =
MemberAccessor<string, int>.FromFunc(x => x.Length, otherStringRepresentation);

bool result = sut.Equals(other);

await That(result).IsEqualTo(expectedResult);
}

[Fact]
public async Task Equals_ToNull_ShouldBeFalse()
{
MemberAccessor<string, int> sut = MemberAccessor<string, int>.FromExpression(x => x.Length);

bool result = sut.Equals(null);

await That(result).IsFalse();
}

[Fact]
public async Task Equals_ToOtherObject_ShouldBeFalse()
{
MemberAccessor<string, int> sut = MemberAccessor<string, int>.FromExpression(x => x.Length);
object other = MemberAccessor<string, string>.FromExpression(x => x);

bool result = sut.Equals(other);

await That(result).IsFalse();
}

[Fact]
public async Task FromExpression_ShouldCompileExpression()
{
MemberAccessor<string, int> subject = MemberAccessor<string, int>
.FromExpression(x => x.Length);

await That(subject.AccessMember("foo")).IsEqualTo(3);
}

[Fact]
public async Task FromExpression_ShouldGetMemberPath()
{
Expand Down Expand Up @@ -36,4 +80,22 @@ public async Task FromFuncAsMemberAccessor_ShouldTryToExtractMemberAccessor(stri

await That(subject.ToString()).IsEqualTo(expected);
}

[Fact]
public async Task GetHashCode_DifferentConstraint_ShouldNotBeEqual()
{
MemberAccessor<string, int> sut1 = MemberAccessor<string, int>.FromFunc(x => x.Length, "foo");
MemberAccessor<string, int> sut2 = MemberAccessor<string, int>.FromFunc(x => x.Length, "bar");

await That(sut1.GetHashCode()).IsNotEqualTo(sut2.GetHashCode());
}

[Fact]
public async Task GetHashCode_SameConstraint_ShouldBeEqual()
{
MemberAccessor<string, int> sut1 = MemberAccessor<string, int>.FromFunc(x => x.Length, "foo");
MemberAccessor<string, int> sut2 = MemberAccessor<string, int>.FromFunc(x => x.Length, "foo");

await That(sut1.GetHashCode()).IsEqualTo(sut2.GetHashCode());
}
}
Loading