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
8 changes: 4 additions & 4 deletions Benchmarks/aweXpect.Benchmarks/HappyCaseBenchmarks.String.cs
Original file line number Diff line number Diff line change
Expand Up @@ -10,17 +10,17 @@ namespace aweXpect.Benchmarks;
public partial class HappyCaseBenchmarks
{
private readonly string _stringExpectation = "foo";
private readonly string _stringSubject = "foo";
private readonly string _stringSubject = "FOO";

[Benchmark]
public async Task<string?> String_aweXpect()
=> await Expect.That(_stringSubject).IsEqualTo(_stringExpectation);
=> await Expect.That(_stringSubject).IsEqualTo(_stringExpectation).IgnoringCase();

[Benchmark]
public AndConstraint<StringAssertions> String_FluentAssertions()
=> _stringSubject.Should().Be(_stringExpectation);
=> _stringSubject.Should().BeEquivalentTo(_stringExpectation, o => o.IgnoringCase());

[Benchmark]
public async Task<string?> String_TUnit()
=> await Assert.That(_stringSubject).IsEqualTo(_stringExpectation);
=> await Assert.That(_stringSubject).IsEqualTo(_stringExpectation).IgnoringCase();
}
2 changes: 1 addition & 1 deletion Pipeline/Build.cs
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@ partial class Build : NukeBuild
/// <para />
/// Afterward, you can update the package reference in `Directory.Packages.props` and reset this flag.
/// </summary>
readonly BuildScope BuildScope = BuildScope.Default;
readonly BuildScope BuildScope = BuildScope.CoreOnly;
Comment thread
vbreuss marked this conversation as resolved.

[Parameter("Github Token")] readonly string GithubToken;
[GitRepository] readonly GitRepository Repository;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,7 @@ public FromException(
_inner = inner;
_exception = exception;
FurtherProcessingStrategy = inner.FurtherProcessingStrategy;
expectationBuilder.UpdateContexts(c => c.Add(new ResultContext("Exception", exception.ToString())));
expectationBuilder.AddContext(new ResultContext.Fixed("Exception", exception.ToString()));
}

public override Outcome Outcome
Expand Down
10 changes: 10 additions & 0 deletions Source/aweXpect.Core/Core/ExpectationBuilder.cs
Original file line number Diff line number Diff line change
Expand Up @@ -378,6 +378,16 @@ public virtual ExpectationBuilder UpdateContexts(Action<ResultContexts> callback
return this;
}

/// <summary>
/// Adds the <paramref name="resultContext"/> to the context that is included in the failure message.
/// </summary>
public virtual ExpectationBuilder AddContext(ResultContext resultContext)
{
_contexts ??= new ResultContexts();
_contexts.Add(resultContext);
return this;
}

/// <summary>
/// Gets the list of <see cref="ResultContext" />.
/// </summary>
Expand Down
5 changes: 3 additions & 2 deletions Source/aweXpect.Core/Core/IStringMatchType.cs
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
using System.Collections.Generic;
using System;
using System.Collections.Generic;
using System.Threading.Tasks;

namespace aweXpect.Core;
Expand All @@ -19,7 +20,7 @@ public interface IStringMatchType
#endif
AreConsideredEqual(string? actual, string? expected,
bool ignoreCase,
IEqualityComparer<string> comparer);
IEqualityComparer<string>? comparer);
Comment thread
vbreuss marked this conversation as resolved.
Comment thread
vbreuss marked this conversation as resolved.

/// <summary>
/// Get the expectations text.
Expand Down
8 changes: 8 additions & 0 deletions Source/aweXpect.Core/Core/ManualExpectationBuilder.cs
Original file line number Diff line number Diff line change
Expand Up @@ -83,6 +83,14 @@ public override ExpectationBuilder UpdateContexts(Action<ResultContexts> callbac
return this;
}

/// <inheritdoc cref="ExpectationBuilder.AddContext(ResultContext)" />
public override ExpectationBuilder AddContext(ResultContext resultContext)
{
inner?.AddContext(resultContext);
base.AddContext(resultContext);
return this;
}

/// <inheritdoc cref="object.ToString()" />
public override string ToString()
{
Expand Down
4 changes: 2 additions & 2 deletions Source/aweXpect.Core/Core/Polyfills/StringExtensions.cs
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@ internal static bool Contains(
this string @this,
char value,
StringComparison comparisonType)
=> @this.Contains(value);
=> @this.IndexOf(value, comparisonType) >= 0;
Comment thread
vbreuss marked this conversation as resolved.

/// <summary>
/// Returns a value indicating whether a specified character occurs within this string, using the specified comparison
Expand All @@ -37,7 +37,7 @@ internal static bool Contains(
this string @this,
string value,
StringComparison comparisonType)
=> @this.Contains(value);
=> @this.IndexOf(value, comparisonType) >= 0;

/// <summary>
/// Determines whether the end of this string instance matches the specified character.
Expand Down
94 changes: 60 additions & 34 deletions Source/aweXpect.Core/Core/ResultContext.cs
Original file line number Diff line number Diff line change
Expand Up @@ -7,42 +7,17 @@ namespace aweXpect.Core;
/// <summary>
/// A result context that is appended to a result error.
/// </summary>
public class ResultContext
public abstract class ResultContext
{
private readonly Func<CancellationToken, Task<string?>>? _contentFunc;

private readonly string? _fixedContent;

/// <summary>
/// A result context that is appended to a result error.
/// </summary>
/// <remarks>The optional <paramref name="priority" /> determines the displayed order (higher values are displayed first).</remarks>
public ResultContext(string title, string? content, int priority = 0)
{
Title = title;
_fixedContent = content;
Priority = priority;
}

/// <summary>
/// A result context that is appended to a result error.
/// </summary>
/// <remarks>The optional <paramref name="priority" /> determines the displayed order (higher values are displayed first).</remarks>
public ResultContext(string title, Func<CancellationToken, Task<string?>> asyncContent, int priority = 0)
{
Title = title;
_contentFunc = asyncContent;
Priority = priority;
}
internal ResultContext? _next;

/// <summary>
/// A result context that is appended to a result error.
/// </summary>
/// <remarks>The optional <paramref name="priority" /> determines the displayed order (higher values are displayed first).</remarks>
public ResultContext(string title, Func<string?> syncContent, int priority = 0)
protected ResultContext(string title, int priority = 0)
{
Title = title;
_contentFunc = _ => Task.FromResult(syncContent());
Priority = priority;
}

Expand All @@ -60,18 +35,69 @@ public ResultContext(string title, Func<string?> syncContent, int priority = 0)
/// <summary>
/// The content of the context.
/// </summary>
public async Task<string?> GetContent(CancellationToken cancellationToken = default)
public abstract Task<string?> GetContent(CancellationToken cancellationToken = default);

/// <summary>
/// A <see cref="ResultContext" /> from a fixed <see langword="string" /> content.
/// </summary>
public class Fixed : ResultContext
{
if (_fixedContent is not null)
private readonly string? _content;

/// <summary>
/// A <see cref="ResultContext" /> from a fixed <see langword="string" /> <paramref name="content" />.
/// </summary>
/// <remarks>The optional <paramref name="priority" /> determines the displayed order (higher values are displayed first).</remarks>
public Fixed(string title, string? content, int priority = 0) : base(title, priority)
{
return _fixedContent;
_content = content;
}

if (_contentFunc is not null)
/// <inheritdoc cref="ResultContext.GetContent(CancellationToken)" />
public override Task<string?> GetContent(CancellationToken cancellationToken = default)
=> Task.FromResult(_content);
}

/// <summary>
/// A <see cref="ResultContext" /> from an async callback.
/// </summary>
public class AsyncCallback : ResultContext
{
private readonly Func<CancellationToken, Task<string?>> _callback;

/// <summary>
/// A <see cref="ResultContext" /> from an async <paramref name="callback" />.
/// </summary>
/// <remarks>The optional <paramref name="priority" /> determines the displayed order (higher values are displayed first).</remarks>
public AsyncCallback(string title, Func<CancellationToken, Task<string?>> callback, int priority = 0) : base(
title, priority)
{
_callback = callback;
}

/// <inheritdoc cref="ResultContext.GetContent(CancellationToken)" />
public override Task<string?> GetContent(CancellationToken cancellationToken = default)
=> _callback(cancellationToken);
}

/// <summary>
/// A <see cref="ResultContext" /> from a sync callback.
/// </summary>
public class SyncCallback : ResultContext
{
private readonly Func<string?> _callback;

/// <summary>
/// A <see cref="ResultContext" /> from a sync <paramref name="callback" />.
/// </summary>
/// <remarks>The optional <paramref name="priority" /> determines the displayed order (higher values are displayed first).</remarks>
public SyncCallback(string title, Func<string?> callback, int priority = 0) : base(title, priority)
{
return await _contentFunc(cancellationToken);
_callback = callback;
}

return null;
/// <inheritdoc cref="ResultContext.GetContent(CancellationToken)" />
public override Task<string?> GetContent(CancellationToken cancellationToken = default)
=> Task.FromResult(_callback());
}
}
56 changes: 43 additions & 13 deletions Source/aweXpect.Core/Core/ResultContexts.cs
Original file line number Diff line number Diff line change
Expand Up @@ -9,11 +9,19 @@ namespace aweXpect.Core;
/// </summary>
public class ResultContexts : IEnumerable<ResultContext>
{
private readonly List<ResultContext> _results = new();
private ResultContext? _first;
private bool _isOpen = true;

/// <inheritdoc cref="IEnumerable{ResultContext}.GetEnumerator()" />
public IEnumerator<ResultContext> GetEnumerator() => _results.GetEnumerator();
public IEnumerator<ResultContext> GetEnumerator()
{
ResultContext? current = _first;
while (current != null)
{
yield return current;
current = current._next;
}
}

/// <inheritdoc cref="IEnumerable.GetEnumerator()" />
IEnumerator IEnumerable.GetEnumerator() => GetEnumerator();
Expand Down Expand Up @@ -43,7 +51,15 @@ public ResultContexts Add(ResultContext context)
{
if (_isOpen)
{
_results.Add(context);
if (_first is null)
{
_first = context;
}
else
{
context._next = _first._next;
_first._next = context;
}
}

return this;
Expand All @@ -56,7 +72,7 @@ public ResultContexts Clear()
{
if (_isOpen)
{
_results.Clear();
_first = null;
}

return this;
Expand All @@ -66,14 +82,7 @@ public ResultContexts Clear()
/// Removes all contexts with the given <paramref name="title" />.
/// </summary>
public ResultContexts Remove(string title, StringComparison stringComparison = StringComparison.OrdinalIgnoreCase)
{
if (_isOpen)
{
_results.RemoveAll(x => x.Title.Equals(title, stringComparison));
}

return this;
}
=> Remove(c => string.Equals(c.Title, title, stringComparison));

/// <summary>
/// Removes all contexts that match the <paramref name="predicate" />.
Expand All @@ -82,7 +91,28 @@ public ResultContexts Remove(Predicate<ResultContext> predicate)
{
if (_isOpen)
{
_results.RemoveAll(predicate);
ResultContext? previous = null;
ResultContext? current = _first;
while (current != null)
{
if (predicate(current))
{
if (previous == null)
{
_first = current._next;
}
else
{
previous._next = current._next;
}
}
else
{
previous = current;
}

current = current._next;
}
}

return this;
Expand Down
3 changes: 3 additions & 0 deletions Source/aweXpect.Core/Core/ThatBool.cs
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,9 @@ private sealed class WithDefaultExpectationBuilderProxy(ExpectationBuilder inner
public override ExpectationBuilder UpdateContexts(Action<ResultContexts> callback)
=> inner.UpdateContexts(callback);

public override ExpectationBuilder AddContext(ResultContext resultContext)
=> inner.AddContext(resultContext);

internal override Task<ConstraintResult> IsMet(Node rootNode, EvaluationContext.EvaluationContext context,
ITimeSystem timeSystem, TimeSpan? timeout,
CancellationToken cancellationToken)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -134,4 +134,7 @@ internal override Task<ConstraintResult> IsMet(Node rootNode,

/// <inheritdoc cref="ExpectationBuilder.UpdateContexts(Action{ResultContexts})" />
public override ExpectationBuilder UpdateContexts(Action<ResultContexts> callback) => this;

/// <inheritdoc cref="ExpectationBuilder.AddContext(ResultContext)" />
public override ExpectationBuilder AddContext(ResultContext resultContext) => this;
}
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
using System.Collections.Generic;
using System;
using System.Collections.Generic;
using System.Threading.Tasks;
using aweXpect.Core;
using aweXpect.Core.Helpers;
Expand Down Expand Up @@ -70,7 +71,7 @@ public ValueTask<bool>
public Task<bool>
#endif
AreConsideredEqual(string? actual, string? expected, bool ignoreCase,
IEqualityComparer<string> comparer)
IEqualityComparer<string>? comparer)
{
if (actual is null && expected is null)
{
Expand All @@ -90,10 +91,19 @@ public Task<bool>
#endif
}

if (comparer is not null)
{
#if NET8_0_OR_GREATER
return ValueTask.FromResult(Contains(actual, expected, comparer));
#else
return Task.FromResult(Contains(actual, expected, comparer));
#endif
}

#if NET8_0_OR_GREATER
return ValueTask.FromResult(Contains(actual, expected, comparer));
return ValueTask.FromResult(actual.Contains(expected, ignoreCase ? StringComparison.OrdinalIgnoreCase : StringComparison.Ordinal));
#else
return Task.FromResult(Contains(actual, expected, comparer));
return Task.FromResult(actual.Contains(expected, ignoreCase ? StringComparison.OrdinalIgnoreCase : StringComparison.Ordinal));
#endif
}

Expand Down
Loading
Loading