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
2 changes: 1 addition & 1 deletion Pipeline/Build.cs
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,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;

[Parameter("Github Token")] readonly string GithubToken;

Expand Down
6 changes: 6 additions & 0 deletions Source/aweXpect.Core/Core/Helpers/ExceptionHelpers.cs
Original file line number Diff line number Diff line change
Expand Up @@ -11,4 +11,10 @@ public static TException LogTrace<TException>(this TException exception)
Customize.aweXpect.TraceWriter.Value?.WriteException(exception);
return exception;
}
public static bool IsDefault<T>(this T value) where T : struct
{
bool isDefault = value.Equals(default(T));

return isDefault;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -57,7 +57,7 @@ public bool VerifyComplete(string it, IOptionsEquality<T2> options, int maximumN

if (!_equivalenceRelations.HasFlag(EquivalenceRelations.IsContainedIn))
{
errors.AddRange(MissingItemsError(_totalExpectedCount, _missingItems, _equivalenceRelations));
errors.AddRange(MissingItemsError(_totalExpectedCount, _missingItems, _equivalenceRelations, false));
}
else if (_equivalenceRelations.HasFlag(EquivalenceRelations.IsContainedInProperly) && !_missingItems.Any())
{
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -64,7 +64,7 @@ public bool VerifyComplete(string it, IOptionsEquality<T2> options, int maximumN

if (!_equivalenceRelations.HasFlag(EquivalenceRelations.IsContainedIn))
{
errors.AddRange(MissingItemsError(_totalExpectedCount, _missingItems, _equivalenceRelations));
errors.AddRange(MissingItemsError(_totalExpectedCount, _missingItems, _equivalenceRelations, true));
}
else if (_equivalenceRelations.HasFlag(EquivalenceRelations.IsContainedInProperly) && !_missingItems.Any())
{
Expand Down
Original file line number Diff line number Diff line change
@@ -1,7 +1,9 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text.RegularExpressions;
using aweXpect.Core;
using aweXpect.Core.Helpers;

namespace aweXpect.Options;

Expand All @@ -14,18 +16,22 @@ private sealed class SameOrderCollectionMatcher<T, T2> : ICollectionMatcher<T, T
private readonly EquivalenceRelations _equivalenceRelations;
private readonly T[] _expectedItems;
private readonly List<T> _foundItems = new();
private readonly bool _ignoreInterspersedItems;
private readonly Dictionary<int, (T Item, T Expected)> _incorrectItems = new();
private readonly List<T> _matchingItems = new();
private readonly List<T> _missingItems = new();
private readonly int _totalExpectedItems;
private int _expectationIndex = -1;
private int _index;
private int _matchIndex;
private int _maxMatchIndex;

public SameOrderCollectionMatcher(EquivalenceRelations equivalenceRelation,
IEnumerable<T> expected)
IEnumerable<T> expected,
bool ignoreInterspersedItems)
{
_equivalenceRelations = equivalenceRelation;
_ignoreInterspersedItems = ignoreInterspersedItems;
_expectedItems = expected.ToArray();
_totalExpectedItems = _expectedItems.Length;
}
Expand All @@ -43,6 +49,10 @@ public bool Verify(string it, T value, IOptionsEquality<T2> options, int maximum
{
VerifyTheCurrentValueIsEqualToTheExpectedValue(value);
}
else if (_ignoreInterspersedItems)
{
_additionalItems.Add(_index, value);
}
else
{
VerifyTheCurrentValueIsDifferentFromTheExpectedValue(value, options);
Expand All @@ -56,14 +66,21 @@ public bool Verify(string it, T value, IOptionsEquality<T2> options, int maximum
#pragma warning disable S3776 // https://rules.sonarsource.com/csharp/RSPEC-3776
public bool VerifyComplete(string it, IOptionsEquality<T2> options, int maximumNumber, out string? error)
{
int consideredExpectedItems = Math.Max(_expectationIndex - 1, _matchIndex);
int consideredExpectedItems = Math.Max(_expectationIndex - 1, _maxMatchIndex);
if (_expectedItems.Length > consideredExpectedItems)
{
for (int i = consideredExpectedItems; i < _expectedItems.Length; i++)
{
T item = _expectedItems[i];
if (_additionalItems.All(x => !options.AreConsideredEqual(x.Value, item)) &&
_incorrectItems.All(x => !options.AreConsideredEqual(x.Value.Item, item)))
KeyValuePair<int, T> additionalItem = _additionalItems
.FirstOrDefault(a => options.AreConsideredEqual(a.Value, item));
if (!additionalItem.IsDefault())
{
_additionalItems.Remove(additionalItem.Key);
_missingItems.Add(additionalItem.Value);
}
else if (_additionalItems.All(x => !options.AreConsideredEqual(x.Value, item)) &&
_incorrectItems.All(x => !options.AreConsideredEqual(x.Value.Item, item)))
{
_missingItems.Add(item);
}
Expand Down Expand Up @@ -96,7 +113,7 @@ public bool VerifyComplete(string it, IOptionsEquality<T2> options, int maximumN

if (!_equivalenceRelations.HasFlag(EquivalenceRelations.IsContainedIn))
{
errors.AddRange(MissingItemsError(_totalExpectedItems, _missingItems, _equivalenceRelations));
errors.AddRange(MissingItemsError(_totalExpectedItems, _missingItems, _equivalenceRelations, false));
}
else if (_equivalenceRelations.HasFlag(EquivalenceRelations.IsContainedInProperly) && !_missingItems.Any())
{
Expand Down Expand Up @@ -136,6 +153,7 @@ private void VerifyTheCurrentValueIsDifferentFromTheExpectedValue(T value, IOpti

_matchingItems.Clear();
_matchIndex++;
_maxMatchIndex = Math.Max(_matchIndex, _maxMatchIndex);
_expectationIndex = 0;
_matchingItems.Add(value);
}
Expand Down Expand Up @@ -186,6 +204,7 @@ private bool SearchForMatchInFoundItems(T value, IOptionsEquality<T2> options)
private void VerifyTheCurrentValueIsEqualToTheExpectedValue(T value)
{
_matchIndex++;
_maxMatchIndex = Math.Max(_matchIndex, _maxMatchIndex);
_expectationIndex++;
_matchingItems.Add(value);
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@
using System.Collections.Generic;
using System.Linq;
using aweXpect.Core;
using aweXpect.Core.Helpers;

namespace aweXpect.Options;

Expand All @@ -12,6 +13,7 @@ private sealed class SameOrderIgnoreDuplicatesCollectionMatcher<T, T2> : ICollec
{
private readonly Dictionary<int, T> _additionalItems = new();
private readonly EquivalenceRelations _equivalenceRelations;
private readonly bool _ignoreInterspersedItems;
private readonly T[] _expectedDistinctItems;
private readonly List<T> _foundItems = new();
private readonly Dictionary<int, (T Item, T Expected)> _incorrectItems = new();
Expand All @@ -22,11 +24,14 @@ private sealed class SameOrderIgnoreDuplicatesCollectionMatcher<T, T2> : ICollec
private int _expectationIndex = -1;
private int _index;
private int _matchIndex;
private int _maxMatchIndex;

public SameOrderIgnoreDuplicatesCollectionMatcher(EquivalenceRelations equivalenceRelation,
IEnumerable<T> expected)
IEnumerable<T> expected,
bool ignoreInterspersedItems)
{
_equivalenceRelations = equivalenceRelation;
_ignoreInterspersedItems = ignoreInterspersedItems;
_expectedDistinctItems = expected.Distinct().ToArray();
_totalExpectedItems = _expectedDistinctItems.Length;
}
Expand All @@ -53,6 +58,15 @@ public bool Verify(string it, T value, IOptionsEquality<T2> options, int maximum
{
VerifyTheCurrentValueIsEqualToTheExpectedValue(value, options);
}
else if (_ignoreInterspersedItems)
{
if (!_uniqueItems.Add(value))
{
return false;
}

_additionalItems.Add(_index, value);
}
else
{
if (!_uniqueItems.Add(value))
Comment thread
vbreuss marked this conversation as resolved.
Expand All @@ -73,13 +87,21 @@ public bool VerifyComplete(string it, IOptionsEquality<T2> options, int maximumN
{
int maximumNumberOfCollectionItems =
maximumNumber;
foreach (T item in _expectedDistinctItems.Skip(Math.Max(_expectationIndex - 1, _matchIndex)))
foreach (T item in _expectedDistinctItems.Skip(Math.Max(_expectationIndex - 1, _maxMatchIndex)))
{
KeyValuePair<int, T> additionalItem = _additionalItems
.FirstOrDefault(a => options.AreConsideredEqual(a.Value, item));
if (!additionalItem.IsDefault())
{
_additionalItems.Remove(additionalItem.Key);
_missingItems.Add(additionalItem.Value);
}

if (!_uniqueItems.Add(item))
{
continue;
}

if (_additionalItems.All(x => !options.AreConsideredEqual(x.Value, item)) &&
_incorrectItems.All(x => !options.AreConsideredEqual(x.Value.Item, item)))
{
Expand Down Expand Up @@ -116,7 +138,7 @@ public bool VerifyComplete(string it, IOptionsEquality<T2> options, int maximumN

if (!_equivalenceRelations.HasFlag(EquivalenceRelations.IsContainedIn))
{
errors.AddRange(MissingItemsError(_totalExpectedItems, _missingItems, _equivalenceRelations));
errors.AddRange(MissingItemsError(_totalExpectedItems, _missingItems, _equivalenceRelations, true));
}
else if (_equivalenceRelations.HasFlag(EquivalenceRelations.IsContainedInProperly) && !_missingItems.Any())
{
Expand Down Expand Up @@ -169,6 +191,7 @@ private void VerifyTheCurrentValueIsDifferentFromTheExpectedValue(T value, IOpti

_matchingItems.Clear();
_matchIndex++;
_maxMatchIndex = Math.Max(_matchIndex, _maxMatchIndex);
_expectationIndex = 0;
_matchingItems.Add(value);
}
Expand All @@ -185,6 +208,7 @@ private void VerifyTheCurrentValueIsDifferentFromTheExpectedValue(T value, IOpti
private void VerifyTheCurrentValueIsEqualToTheExpectedValue(T value, IOptionsEquality<T2> options)
{
_matchIndex++;
_maxMatchIndex = Math.Max(_matchIndex, _maxMatchIndex);
_expectationIndex++;
_matchingItems.Add(value);
_uniqueItems.Add(value);
Expand Down
46 changes: 36 additions & 10 deletions Source/aweXpect.Core/Options/CollectionMatchOptions.cs
Original file line number Diff line number Diff line change
Expand Up @@ -50,6 +50,7 @@ public enum EquivalenceRelations

private EquivalenceRelations _equivalenceRelations = equivalenceRelations;
private bool _ignoringDuplicates;
private bool _ignoringInterspersedItems;
private bool _inAnyOrder;

/// <summary>
Expand All @@ -68,6 +69,11 @@ public void SetEquivalenceRelation(EquivalenceRelations equivalenceRelation)
/// </summary>
public void IgnoringDuplicates() => _ignoringDuplicates = true;

/// <summary>
/// Ignores interspersed items in the actual collection.
/// </summary>
public void IgnoringInterspersedItems() => _ignoringInterspersedItems = true;

/// <summary>
/// Get the collection matcher for the <paramref name="expected" /> enumerable.
/// </summary>
Expand All @@ -77,23 +83,33 @@ public ICollectionMatcher<T, T2> GetCollectionMatcher<T, T2>(IEnumerable<T> expe
{
(true, true) => new AnyOrderIgnoreDuplicatesCollectionMatcher<T, T2>(_equivalenceRelations, expected),
(true, false) => new AnyOrderCollectionMatcher<T, T2>(_equivalenceRelations, expected),
(false, true) => new SameOrderIgnoreDuplicatesCollectionMatcher<T, T2>(_equivalenceRelations, expected),
(false, false) => new SameOrderCollectionMatcher<T, T2>(_equivalenceRelations, expected),
(false, true) => new SameOrderIgnoreDuplicatesCollectionMatcher<T, T2>(_equivalenceRelations, expected,
_ignoringInterspersedItems),
(false, false) => new SameOrderCollectionMatcher<T, T2>(_equivalenceRelations, expected,
_ignoringInterspersedItems),
};

/// <summary>
/// Specifies the expectation for the <paramref name="expectedExpression" /> using the provided <paramref name="grammars"/>.
/// Specifies the expectation for the <paramref name="expectedExpression" /> using the provided
/// <paramref name="grammars" />.
/// </summary>
public string GetExpectation(string expectedExpression, ExpectationGrammars grammars)
=> (_inAnyOrder, _ignoringDuplicates) switch
=> (_inAnyOrder, _ignoringDuplicates, _ignoringInterspersedItems) switch
{
(true, true) => ToString(_equivalenceRelations, expectedExpression, grammars) + " in any order ignoring duplicates",
(true, false) => ToString(_equivalenceRelations, expectedExpression, grammars) + " in any order",
(false, true) => ToString(_equivalenceRelations, expectedExpression, grammars) + " in order ignoring duplicates",
(false, false) => ToString(_equivalenceRelations, expectedExpression, grammars) + " in order",
(true, true, _) => ToString(_equivalenceRelations, expectedExpression, grammars) +
" in any order ignoring duplicates",
(true, false, _) => ToString(_equivalenceRelations, expectedExpression, grammars) + " in any order",
(false, true, false) => ToString(_equivalenceRelations, expectedExpression, grammars) +
" in order ignoring duplicates",
(false, false, false) => ToString(_equivalenceRelations, expectedExpression, grammars) + " in order",
(false, true, true) => ToString(_equivalenceRelations, expectedExpression, grammars) +
" in order ignoring duplicates and interspersed items",
(false, false, true) => ToString(_equivalenceRelations, expectedExpression, grammars) +
" in order ignoring interspersed items",
};

private static string ToString(EquivalenceRelations equivalenceRelation, string expectedExpression, ExpectationGrammars grammars)
private static string ToString(EquivalenceRelations equivalenceRelation, string expectedExpression,
ExpectationGrammars grammars)
=> (equivalenceRelation, grammars.IsNegated()) switch
{
(EquivalenceRelations.Contains, false)
Expand Down Expand Up @@ -166,9 +182,19 @@ private static IEnumerable<string> IncorrectItemsError<T>(Dictionary<int, (T Ite
}

private static IEnumerable<string> MissingItemsError<T>(int total, List<T> missingItems,
EquivalenceRelations equivalenceRelation)
EquivalenceRelations equivalenceRelation, bool ignoringDuplicates)
{
bool hasMissingItems = missingItems.Any();
if (total == missingItems.Count)
{
yield return ignoringDuplicates switch
{
Comment thread
vbreuss marked this conversation as resolved.
true => $"lacked all {total} unique expected items",
false => $"lacked all {total} expected items",
};
yield break;
}

if (hasMissingItems && !equivalenceRelation.HasFlag(EquivalenceRelations.IsContainedIn))
{
if (missingItems.Count == 1)
Expand Down
12 changes: 12 additions & 0 deletions Source/aweXpect/Results/ObjectCollectionMatchResult.cs
Original file line number Diff line number Diff line change
Expand Up @@ -52,4 +52,16 @@ public TSelf IgnoringDuplicates()
collectionMatchOptions.IgnoringDuplicates();
return (TSelf)this;
}

/// <summary>
/// Ignores interspersed items in the actual collection.
/// </summary>
/// <remarks>
/// This option has no effect when <see cref="InAnyOrder()" /> is used.
/// </remarks>
public TSelf IgnoringInterspersedItems()
{
collectionMatchOptions.IgnoringInterspersedItems();
return (TSelf)this;
}
}
12 changes: 12 additions & 0 deletions Source/aweXpect/Results/StringCollectionMatchResult.cs
Original file line number Diff line number Diff line change
Expand Up @@ -52,4 +52,16 @@ public TSelf IgnoringDuplicates()
collectionMatchOptions.IgnoringDuplicates();
return (TSelf)this;
}

/// <summary>
/// Ignores interspersed items in the actual collection.
/// </summary>
/// <remarks>
/// This option has no effect when <see cref="InAnyOrder()" /> is used.
/// </remarks>
public TSelf IgnoringInterspersedItems()
{
collectionMatchOptions.IgnoringInterspersedItems();
return (TSelf)this;
}
}
2 changes: 2 additions & 0 deletions Tests/aweXpect.Api.Tests/Expected/aweXpect_net8.0.txt
Original file line number Diff line number Diff line change
Expand Up @@ -1246,6 +1246,7 @@ namespace aweXpect.Results
{
public ObjectCollectionMatchResult(aweXpect.Core.ExpectationBuilder expectationBuilder, TThat returnValue, aweXpect.Options.ObjectEqualityOptions<TElement> options, aweXpect.Options.CollectionMatchOptions collectionMatchOptions) { }
public TSelf IgnoringDuplicates() { }
public TSelf IgnoringInterspersedItems() { }
public TSelf InAnyOrder() { }
}
public class ObjectCollectionMatchWithToleranceResult<TType, TThat, TElement, TTolerance> : aweXpect.Results.ObjectCollectionMatchResult<TType, TThat, TElement>
Expand Down Expand Up @@ -1328,6 +1329,7 @@ namespace aweXpect.Results
{
public StringCollectionMatchResult(aweXpect.Core.ExpectationBuilder expectationBuilder, TThat returnValue, aweXpect.Options.StringEqualityOptions options, aweXpect.Options.CollectionMatchOptions collectionMatchOptions) { }
public TSelf IgnoringDuplicates() { }
public TSelf IgnoringInterspersedItems() { }
public TSelf InAnyOrder() { }
}
}
2 changes: 2 additions & 0 deletions Tests/aweXpect.Api.Tests/Expected/aweXpect_netstandard2.0.txt
Original file line number Diff line number Diff line change
Expand Up @@ -1229,6 +1229,7 @@ namespace aweXpect.Results
{
public ObjectCollectionMatchResult(aweXpect.Core.ExpectationBuilder expectationBuilder, TThat returnValue, aweXpect.Options.ObjectEqualityOptions<TElement> options, aweXpect.Options.CollectionMatchOptions collectionMatchOptions) { }
public TSelf IgnoringDuplicates() { }
public TSelf IgnoringInterspersedItems() { }
public TSelf InAnyOrder() { }
}
public class ObjectCollectionMatchWithToleranceResult<TType, TThat, TElement, TTolerance> : aweXpect.Results.ObjectCollectionMatchResult<TType, TThat, TElement>
Expand Down Expand Up @@ -1311,6 +1312,7 @@ namespace aweXpect.Results
{
public StringCollectionMatchResult(aweXpect.Core.ExpectationBuilder expectationBuilder, TThat returnValue, aweXpect.Options.StringEqualityOptions options, aweXpect.Options.CollectionMatchOptions collectionMatchOptions) { }
public TSelf IgnoringDuplicates() { }
public TSelf IgnoringInterspersedItems() { }
public TSelf InAnyOrder() { }
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -747,6 +747,7 @@ namespace aweXpect.Options
where T : T2 { }
public string GetExpectation(string expectedExpression, aweXpect.Core.ExpectationGrammars grammars) { }
public void IgnoringDuplicates() { }
public void IgnoringInterspersedItems() { }
public void InAnyOrder() { }
public void SetEquivalenceRelation(aweXpect.Options.CollectionMatchOptions.EquivalenceRelations equivalenceRelation) { }
[System.Flags]
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -730,6 +730,7 @@ namespace aweXpect.Options
where T : T2 { }
public string GetExpectation(string expectedExpression, aweXpect.Core.ExpectationGrammars grammars) { }
public void IgnoringDuplicates() { }
public void IgnoringInterspersedItems() { }
public void InAnyOrder() { }
public void SetEquivalenceRelation(aweXpect.Options.CollectionMatchOptions.EquivalenceRelations equivalenceRelation) { }
[System.Flags]
Expand Down
Loading
Loading