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 Directory.Packages.props
Original file line number Diff line number Diff line change
Expand Up @@ -7,8 +7,8 @@
<PackageVersion Include="Microsoft.Bcl.HashCode" Version="1.1.1" />
<PackageVersion Include="System.Collections.Immutable" Version="1.7.1" />
<PackageVersion Include="System.Text.Json" Version="5.0.0" />
<PackageVersion Include="xunit.assert" Version="[2.4.0, 2.5)" />
<PackageVersion Include="xunit.extensibility.core" Version="[2.4.0, 2.5)" />
<PackageVersion Include="xunit.assert" Version="[2.9.3, 2.10)" />
<PackageVersion Include="xunit.extensibility.core" Version="[2.9.3, 2.10)" />
<PackageVersion Include="System.Linq.Async" Version="[5.0.0, 7)" />
</ItemGroup>
<ItemGroup Label="Build Dependencies">
Expand All @@ -18,8 +18,8 @@
</ItemGroup>
<ItemGroup Label="Test Dependencies">
<PackageVersion Include="Microsoft.NET.Test.Sdk" Version="17.2.0" />
<PackageVersion Include="xunit" Version="2.4.2" />
<PackageVersion Include="xunit.runner.visualstudio" Version="2.4.5" />
<PackageVersion Include="xunit" Version="2.9.3" />
<PackageVersion Include="xunit.runner.visualstudio" Version="3.0.1" />
<PackageVersion Include="FsCheck.Xunit" Version="2.16.4" />
<PackageVersion Include="coverlet.collector" Version="3.1.2" />
<PackageVersion Include="Verify.XUnit" Version="16.8.1" />
Expand Down
4 changes: 2 additions & 2 deletions Funcky.Async.Test/AsyncSequence/CycleRangeTest.cs
Original file line number Diff line number Diff line change
Expand Up @@ -16,8 +16,8 @@ public async Task CycleRangeIsEnumeratedLazilyAsync()
}

[Fact]
public void CyclingAnEmptySetThrowsAnArgumentException()
=> Assert.ThrowsAsync<InvalidOperationException>(CycleEmptySequenceAsync);
public async Task CyclingAnEmptySetThrowsAnArgumentException()
=> await Assert.ThrowsAsync<InvalidOperationException>(CycleEmptySequenceAsync);

[Property]
public Property CycleRangeCanProduceArbitraryManyItemsAsync(NonEmptySet<int> sequence, PositiveInt arbitraryElements)
Expand Down
2 changes: 1 addition & 1 deletion Funcky.Async.Test/AsyncSequence/RepeatRangeTest.cs
Original file line number Diff line number Diff line change
Expand Up @@ -41,7 +41,7 @@ public async Task RepeatRangeThrowsWhenAlreadyDisposedEvenIfYouDisposeBetweenMov
var repeatRange = AsyncSequence.RepeatRange(list, repeats);
await using var enumerator = repeatRange.GetAsyncEnumerator();

Assert.True(await AsyncEnumerable.Range(0, i).AllAwaitAsync(async _ => await enumerator.MoveNextAsync()).ConfigureAwait(false));
Assert.True(await AsyncEnumerable.Range(0, i).AllAwaitAsync(async _ => await enumerator.MoveNextAsync()));

#pragma warning disable IDISP016 // we test behaviour after Dispose
#pragma warning disable IDISP017 // we test behaviour after Dispose
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,13 +8,13 @@ namespace Funcky.Async.Test.Extensions.AsyncEnumerableExtensions;
public sealed class ShuffleTest
{
[Fact]
public void AShuffleIsEnumeratedLazilyAsync()
public async Task AShuffleIsEnumeratedLazilyAsync()
{
var doNotEnumerate = new FailOnEnumerateAsyncSequence<object>();

var shuffled = doNotEnumerate.ShuffleAsync();

Assert.ThrowsAsync<XunitException>(async () => await shuffled);
await Assert.ThrowsAsync<XunitException>(async () => await shuffled);
}

[Fact]
Expand Down
45 changes: 22 additions & 23 deletions Funcky.Async.Test/TestUtilities/AsyncAssert.cs
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ public static async Task Empty<TElement>(IAsyncEnumerable<TElement> asyncSequenc
{
if (await asyncEnumerator.MoveNextAsync())
{
throw new EmptyException(await asyncSequence.ToListAsync());
throw EmptyException.ForNonEmptyCollection(collection: await FormatCollectionStart(asyncSequence));
}
}
finally
Expand All @@ -27,7 +27,7 @@ public static async Task NotEmpty<TElement>(IAsyncEnumerable<TElement> asyncSequ
{
if (!await asyncEnumerator.MoveNextAsync())
{
throw new NotEmptyException();
throw NotEmptyException.ForNonEmptyCollection();
}
}
finally
Expand All @@ -39,25 +39,7 @@ public static async Task NotEmpty<TElement>(IAsyncEnumerable<TElement> asyncSequ
public static async Task Collection<TElement>(IAsyncEnumerable<TElement> asyncSequence, params Action<TElement>[] elementInspectors)
{
var elements = await asyncSequence.ToListAsync();
var elementInspectorsLength = elementInspectors.Length;
var elementsLength = elements.Count;

if (elementInspectorsLength != elementsLength)
{
throw new CollectionException(asyncSequence.ToListAsync(), elementInspectorsLength, elementsLength);
}

foreach (var ((elementInspector, element), indexFailurePoint) in elementInspectors.Zip(elements).WithIndex())
{
try
{
elementInspector(element);
}
catch (Exception ex)
{
throw new CollectionException(asyncSequence.ToListAsync(), elementInspectorsLength, elementsLength, indexFailurePoint, ex);
}
}
Assert.Collection(elements, elementInspectors);
}

public static async Task<T> Single<T>(IAsyncEnumerable<T> asyncSequence)
Expand All @@ -66,19 +48,36 @@ public static async Task<T> Single<T>(IAsyncEnumerable<T> asyncSequence)

if (await asyncEnumerator.MoveNextAsync() is false)
{
SingleException.Empty(null);
throw SingleException.Empty(expected: null, collection: string.Empty);
}

var result = asyncEnumerator.Current;

if (await asyncEnumerator.MoveNextAsync())
{
SingleException.MoreThanOne(await asyncSequence.CountAsync(), null);
var actual = await MaterializeCollectionStart(asyncSequence);
throw SingleException.MoreThanOne(expected: null, collection: FormatCollectionStart(actual), count: actual.Count, matchIndices: Array.Empty<int>());
}

return result;
}

public static async Task Equal<TElement>(IAsyncEnumerable<TElement> expectedResult, IAsyncEnumerable<TElement> actual)
=> Assert.Equal(await expectedResult.ToListAsync(), await actual.ToListAsync());

private static async Task<IReadOnlyCollection<TElement>> MaterializeCollectionStart<TElement>(IAsyncEnumerable<TElement> asyncSequence)
{
// This should *ideally* be kept in sync with XUnit's `ArgumentFormatter.MAX_ENUMERABLE_LENGTH + 1` (which is private).
const int maxEnumerableLength = 6;
return await asyncSequence.Take(maxEnumerableLength).ToListAsync();
}

private static async Task<string> FormatCollectionStart<TElement>(IAsyncEnumerable<TElement> asyncSequence)
=> FormatCollectionStart(await MaterializeCollectionStart(asyncSequence));

private static string FormatCollectionStart<TElement>(IEnumerable<TElement> sequence)
{
using var tracker = sequence.AsTracker();
return tracker.FormatStart();
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -45,7 +45,7 @@ public void MaterializeWithMaterializationReturnsCorrectCollectionWhenEnumerate(
public void MaterializeDoesNotEnumerableEnumerableReturnedByRepeat()
{
var sequence = Enumerable.Repeat("Hello world!", 3);
var materialized = sequence.Materialize<string, IReadOnlyCollection<string>>(_ => throw new FailException("Materialization should never be called"));
var materialized = sequence.Materialize<string, IReadOnlyCollection<string>>(_ => throw FailException.ForFailure("Materialization should never be called"));
Assert.Same(sequence, materialized);
}
#endif
Expand Down
25 changes: 25 additions & 0 deletions Funcky.Xunit.Test/FunctionalAssertClass/ErrorTest.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
using Xunit.Sdk;

namespace Funcky.Xunit.Test.FunctionalAssertClass;

public sealed class ErrorTest
{
[Fact]
public void DoesNotThrowForError()
{
FunctionalAssert.Error(Result<int>.Error(new ArgumentException("foo")));
}

[Fact]
public void ThrowsForOk()
{
const string expectedMessage =
"""
FunctionalAssert.Error() Failure: Values differ
Expected: Error(...)
Actual: Ok(42)
""";
var exception = Assert.ThrowsAny<XunitException>(() => FunctionalAssert.Error(Result.Ok(42)));
Assert.Equal(expectedMessage.ReplaceLineEndings(Environment.NewLine), exception.Message);
}
}
57 changes: 57 additions & 0 deletions Funcky.Xunit.Test/FunctionalAssertClass/LeftTest.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,57 @@
using Xunit.Sdk;

namespace Funcky.Xunit.Test.FunctionalAssertClass;

public sealed class LeftTest
{
[Fact]
public void DoesNotThrowForMatchingLeft()
{
FunctionalAssert.Left(10, Either<int, string>.Left(10));
}

[Fact]
public void DoesNotThrowForLeft()
{
FunctionalAssert.Left(Either<int, string>.Left(10));
}

[Fact]
public void ThrowsForMismatchingLeft()
{
const string expectedMessage =
"""
FunctionalAssert.Left() Failure: Values differ
Expected: Left(10)
Actual: Left(11)
""";
var exception = Assert.ThrowsAny<XunitException>(() => FunctionalAssert.Left(10, Either<int, string>.Left(11)));
Assert.Equal(expectedMessage.ReplaceLineEndings(Environment.NewLine), exception.Message);
}

[Fact]
public void ThrowsForRightWithExpectedValue()
{
const string expectedMessage =
"""
FunctionalAssert.Left() Failure: Values differ
Expected: Left(10)
Actual: Right("right")
""";
var exception = Assert.ThrowsAny<XunitException>(() => FunctionalAssert.Left(10, Either<int, string>.Right("right")));
Assert.Equal(expectedMessage.ReplaceLineEndings(Environment.NewLine), exception.Message);
}

[Fact]
public void ThrowsForRight()
{
const string expectedMessage =
"""
FunctionalAssert.Left() Failure: Values differ
Expected: Left(...)
Actual: Right("right")
""";
var exception = Assert.ThrowsAny<XunitException>(() => FunctionalAssert.Left(Either<int, string>.Right("right")));
Assert.Equal(expectedMessage.ReplaceLineEndings(Environment.NewLine), exception.Message);
}
}
25 changes: 25 additions & 0 deletions Funcky.Xunit.Test/FunctionalAssertClass/NoneTest.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
using Xunit.Sdk;

namespace Funcky.Xunit.Test.FunctionalAssertClass;

public sealed class NoneTest
{
[Fact]
public void DoesNotThrowForNone()
{
FunctionalAssert.None(Option<string>.None);
}

[Fact]
public void ThrowsForSome()
{
const string expectedMessage =
"""
FunctionalAssert.None() Failure: Values differ
Expected: None
Actual: Some("something")
""";
var exception = Assert.ThrowsAny<XunitException>(() => FunctionalAssert.None(Option.Some("something")));
Assert.Equal(expectedMessage.ReplaceLineEndings(Environment.NewLine), exception.Message);
}
}
57 changes: 57 additions & 0 deletions Funcky.Xunit.Test/FunctionalAssertClass/OkTest.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,57 @@
using Xunit.Sdk;

namespace Funcky.Xunit.Test.FunctionalAssertClass;

public sealed class OkTest
{
[Fact]
public void DoesNotThrowForMatchingOk()
{
FunctionalAssert.Ok(10, Result.Ok(10));
}

[Fact]
public void DoesNotThrowForOk()
{
FunctionalAssert.Ok(Result.Ok(10));
}

[Fact]
public void ThrowsForMismatchingOk()
{
const string expectedMessage =
"""
FunctionalAssert.Ok() Failure: Values differ
Expected: Ok(10)
Actual: Ok(11)
""";
var exception = Assert.ThrowsAny<XunitException>(() => FunctionalAssert.Ok(10, Result.Ok(11)));
Assert.Equal(expectedMessage.ReplaceLineEndings(Environment.NewLine), exception.Message);
}

[Fact]
public void ThrowsForErrorWithExpectedValue()
{
const string expectedMessage =
"""
FunctionalAssert.Ok() Failure: Values differ
Expected: Ok(10)
Actual: Error(System.ArgumentException: "message")
""";
var exception = Assert.ThrowsAny<XunitException>(() => FunctionalAssert.Ok(10, Result<int>.Error(new ArgumentException("message"))));
Assert.Equal(expectedMessage.ReplaceLineEndings(Environment.NewLine), exception.Message);
}

[Fact]
public void ThrowsForError()
{
const string expectedMessage =
"""
FunctionalAssert.Ok() Failure: Values differ
Expected: Ok(...)
Actual: Error(System.ArgumentException: "message")
""";
var exception = Assert.ThrowsAny<XunitException>(() => FunctionalAssert.Ok(Result<int>.Error(new ArgumentException("message"))));
Assert.Equal(expectedMessage.ReplaceLineEndings(Environment.NewLine), exception.Message);
}
}
57 changes: 57 additions & 0 deletions Funcky.Xunit.Test/FunctionalAssertClass/RightTest.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,57 @@
using Xunit.Sdk;

namespace Funcky.Xunit.Test.FunctionalAssertClass;

public sealed class RightTest
{
[Fact]
public void DoesNotThrowForMatchingRight()
{
FunctionalAssert.Right(10, Either<string, int>.Right(10));
}

[Fact]
public void DoesNotThrowForRight()
{
FunctionalAssert.Right(Either<string, int>.Right(10));
}

[Fact]
public void ThrowsForMismatchingRight()
{
const string expectedMessage =
"""
FunctionalAssert.Right() Failure: Values differ
Expected: Right(10)
Actual: Right(11)
""";
var exception = Assert.ThrowsAny<XunitException>(() => FunctionalAssert.Right(10, Either<string, int>.Right(11)));
Assert.Equal(expectedMessage.ReplaceLineEndings(Environment.NewLine), exception.Message);
}

[Fact]
public void ThrowsForLeftWithExpectedValue()
{
const string expectedMessage =
"""
FunctionalAssert.Right() Failure: Values differ
Expected: Right(10)
Actual: Left("left")
""";
var exception = Assert.ThrowsAny<XunitException>(() => FunctionalAssert.Right(10, Either<string, int>.Left("left")));
Assert.Equal(expectedMessage.ReplaceLineEndings(Environment.NewLine), exception.Message);
}

[Fact]
public void ThrowsForLeft()
{
const string expectedMessage =
"""
FunctionalAssert.Right() Failure: Values differ
Expected: Right(...)
Actual: Left("left")
""";
var exception = Assert.ThrowsAny<XunitException>(() => FunctionalAssert.Right(Either<string, int>.Left("left")));
Assert.Equal(expectedMessage.ReplaceLineEndings(Environment.NewLine), exception.Message);
}
}
Loading
Loading