Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
48 commits
Select commit Hold shift + click to select a range
5f0ea92
Vibe-coding Match / Async tests - #53
bfren Feb 18, 2026
a9444df
Vibe-coding MatchIf / Async tests - #53
bfren Feb 18, 2026
ef7b36a
Vibe-coding Filter / Async tests - #53
bfren Feb 18, 2026
ca5af94
Vibe-coding Dictionary tests - #53
bfren Feb 18, 2026
1642edc
Adding WrapId test - #53
bfren Feb 18, 2026
452f936
Vibe-coding Monad extensions test - #53
bfren Feb 18, 2026
7dac03f
Vibe-coding AddWrapConverters tests - #53
bfren Feb 18, 2026
8f69770
Vibe-coding Filter / Async tests - #53
bfren Feb 18, 2026
cd9bc14
Vibe-coding IfOk / IfFailed + Async tests - #53
bfren Feb 18, 2026
0e9e375
Vibe-coding IsFalse / IsTrue + Async tests - #53
bfren Feb 18, 2026
44e2e3b
Return test false message rather than exception object - #53
bfren Feb 18, 2026
d2187e2
Using Assert.Collection and standard value variable names - #53
bfren Feb 18, 2026
9b69fda
Vibe-coding Audit / Async tests - #53
bfren Feb 18, 2026
8e2af78
Vibe-coding Bind / Async tests - #53
bfren Feb 18, 2026
23214d7
Vibe-coding Co0ntinueIf / Async tests - #53
bfren Feb 18, 2026
ec6b80b
Vibe-coding GetSingle / Async tests - #53
bfren Feb 18, 2026
9c31b14
Vibe-coding If/ Async tests - #53
bfren Feb 18, 2026
e41bef5
Vibe-coding Map / Async tests - #53
bfren Feb 18, 2026
e898ecf
Vibe-coding Match / Async tests - #53
bfren Feb 18, 2026
1ce270b
Vibe-coding ToMaybe / Async tests - #53
bfren Feb 18, 2026
acff85c
Vibe-coding Unsafe / Async tests - #53
bfren Feb 18, 2026
75e5de3
Vibe-coding UnwrapAsync tests - #53
bfren Feb 18, 2026
1b78490
Removing unnecessary usings - #53
bfren Feb 19, 2026
82f3845
Vibe-coding Filter / Async tests - #53
bfren Feb 20, 2026
bbc11ad
Vibe-coding IterateAsync tests - #53
bfren Feb 20, 2026
d1e27d2
Vibe-coding Discard / Async tests - #53
bfren Feb 20, 2026
1a81300
Vibe-coding Unwrap / Async tests - #53
bfren Feb 20, 2026
0ac2fee
Fixing Claude's incorrect use of AsTask() method - #53
bfren Feb 20, 2026
d8f3158
Vibe-coding Wrap tests - #53
bfren Feb 20, 2026
bdef5b2
Removing unnecessary Act comments - #53
bfren Feb 20, 2026
9875807
Removing unnecessary using and moving to correct location - #53
bfren Feb 20, 2026
0b2d155
Vibe-coding remaining MatchIfAsync tests - #53
bfren Feb 20, 2026
f25a61b
Adding missing overload tests - #53
bfren Feb 20, 2026
f85559d
Using async instead of Task.FromResult - #53
bfren Feb 20, 2026
3ed265c
Using async instead of Task.CompletedTask - #53
bfren Feb 20, 2026
1840bca
Splitting Wrap / Async tests and adding missing cases - #53
bfren Feb 20, 2026
0fa755f
Moving Unsafe call to arrange - #53
bfren Feb 20, 2026
0375ef0
Adding additional options for UnwrapAsync plus tests - #53
bfren Feb 20, 2026
025c79c
Fixing ToMaybe / Async tests - #53
bfren Feb 20, 2026
d21a935
Fixing Audit / Async tests - #53
bfren Feb 20, 2026
2300113
Fixing Unsafe tests - #53
bfren Feb 20, 2026
225277a
Merge branch 'main' into 53-improve-test-coverage
bfren Feb 20, 2026
6ecbb84
Using constants for GetSingle error messages - #53
bfren Feb 20, 2026
e60ab9f
Renaming variables for consistency - #53
bfren Feb 20, 2026
a69d413
Use random string for Exception messages - #53
bfren Feb 20, 2026
cb71e8b
Don't use Setup for single variable - #53
bfren Feb 20, 2026
4ebdd73
Bumping version to 1.2.1
bfren Feb 20, 2026
62125d7
Updating local package validation baseline to 1.2.1 - #53
bfren Feb 20, 2026
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 Version
Original file line number Diff line number Diff line change
@@ -1 +1 @@
1.2.1-beta.1
1.2.1
15 changes: 15 additions & 0 deletions src/All/Constants.cs
Original file line number Diff line number Diff line change
Expand Up @@ -10,4 +10,19 @@ internal static class C
internal const string NullValueFailureMessage = "Null value of type '{Type}'.";

internal const string TestFalseMessage = "Test returned false.";

internal static class GetSingle
{
internal const string EmptyList =
"Cannot get single value from an empty list.";

internal const string MultipleValues =
"Cannot get single value from a list with multiple values.";

internal const string IncorrectType =
"Cannot get single value of type '{ValueType}' from a list type '{ListType}'.";

internal const string NotAList =
"Result value type is not a list.";
}
}
13 changes: 0 additions & 13 deletions src/All/Exceptions/TestFalseException.cs

This file was deleted.

9 changes: 4 additions & 5 deletions src/All/Extensions/Result/ResultExtensions.Filter.cs
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,6 @@

using System;
using System.Threading.Tasks;
using Wrap.Exceptions;

namespace Wrap.Extensions;

Expand All @@ -21,7 +20,7 @@ public static Result<T> Filter<T>(this Result<T> @this, Func<T, bool> fTest) =>
@this.Bind(x => fTest(x) switch
{
false =>
R.Fail<TestFalseException>(),
R.Fail(C.TestFalseMessage).Ctx(nameof(ResultExtensions), nameof(Filter)),

true =>
R.Wrap(x)
Expand All @@ -32,7 +31,7 @@ public static Task<Result<T>> FilterAsync<T>(this Result<T> @this, Func<T, Task<
@this.BindAsync(async x => await fTest(x) switch
{
false =>
R.Fail<TestFalseException>(),
R.Fail(C.TestFalseMessage).Ctx(nameof(ResultExtensions), nameof(FilterAsync)),

true =>
R.Wrap(x)
Expand All @@ -43,7 +42,7 @@ public static Task<Result<T>> FilterAsync<T>(this Task<Result<T>> @this, Func<T,
@this.BindAsync(x => fTest(x) switch
{
false =>
R.Fail<TestFalseException>(),
R.Fail(C.TestFalseMessage).Ctx(nameof(ResultExtensions), nameof(FilterAsync)),

true =>
R.Wrap(x)
Expand All @@ -54,7 +53,7 @@ public static Task<Result<T>> FilterAsync<T>(this Task<Result<T>> @this, Func<T,
@this.BindAsync(async x => await fTest(x) switch
{
false =>
R.Fail<TestFalseException>(),
R.Fail(C.TestFalseMessage).Ctx(nameof(ResultExtensions), nameof(FilterAsync)),

true =>
R.Wrap(x)
Expand Down
20 changes: 4 additions & 16 deletions src/All/Extensions/Result/ResultExtensions.GetSingle.cs
Original file line number Diff line number Diff line change
Expand Up @@ -11,18 +11,6 @@ namespace Wrap.Extensions;

public static partial class ResultExtensions
{
private const string EmptyList =
"Cannot get single value from an empty list.";

private const string MultipleValues =
"Cannot get single value from a list with multiple values.";

private const string IncorrectType =
"Cannot get single value of type '{ValueType}' from a list type '{ListType}'.";

private const string NotAList =
"Result value type is not a list.";

/// <inheritdoc cref="GetSingle{T, TSingle}(Result{T}, R.ErrorHandler?)"/>
public static Result<TSingle> GetSingle<T, TSingle>(this Result<T> @this)
where T : IEnumerable =>
Expand Down Expand Up @@ -51,19 +39,19 @@ IEnumerable<TSingle> list when list.Count() == 1 =>
R.Wrap(list.Single()),

IEnumerable<TSingle> list when !list.Any() =>
onError?.Invoke(EmptyList) ?? R.Fail(EmptyList)
onError?.Invoke(C.GetSingle.EmptyList) ?? R.Fail(C.GetSingle.EmptyList)
.Ctx(nameof(ResultExtensions), nameof(GetSingle)),

IEnumerable<TSingle> =>
onError?.Invoke(MultipleValues) ?? R.Fail(MultipleValues)
onError?.Invoke(C.GetSingle.MultipleValues) ?? R.Fail(C.GetSingle.MultipleValues)
.Ctx(nameof(ResultExtensions), nameof(GetSingle)),

IEnumerable =>
onError?.Invoke(IncorrectType, typeof(TSingle).Name, typeof(T).Name) ?? R.Fail(IncorrectType, typeof(TSingle).Name, typeof(T).Name)
onError?.Invoke(C.GetSingle.IncorrectType, typeof(TSingle).Name, typeof(T).Name) ?? R.Fail(C.GetSingle.IncorrectType, typeof(TSingle).Name, typeof(T).Name)
.Ctx(nameof(ResultExtensions), nameof(GetSingle)),

_ =>
onError?.Invoke(NotAList) ?? R.Fail(NotAList)
onError?.Invoke(C.GetSingle.NotAList) ?? R.Fail(C.GetSingle.NotAList)
.Ctx(nameof(ResultExtensions), nameof(GetSingle))
});

Expand Down
39 changes: 37 additions & 2 deletions src/All/Extensions/Result/ResultExtensions.Unwrap.cs
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@ public static Task<T> UnwrapAsync<T>(this Task<Result<T>> @this)
{
// use local functions to avoid function signature ambiguity
static Task<T> fail(FailureValue f) => R.ThrowFailure<Task<T>>(f);
static Task<T> ok(T x) => Task.FromResult(x);
static async Task<T> ok(T x) => x;
return R.MatchAsync(@this, fail, ok);
}

Expand Down Expand Up @@ -87,14 +87,49 @@ public static Task<T> UnwrapAsync<T>(this Task<Result<T>> @this, Func<FailureVal
/// <param name="ifFailed">Function to handle a FailureValue.</param>
/// <param name="returnThis">Function to return a value on a Failure.</param>
/// <returns>The value of <paramref name="this"/> or generated by <paramref name="returnThis"/>.</returns>
public static Task<T> UnwrapAsync<T>(this Result<T> @this, Func<FailureValue, Task> ifFailed, Func<Task<T>> returnThis) =>
R.MatchAsync(@this,
fFail: async f => { await ifFailed(f); return await returnThis(); },
fOk: x => x
);

/// <inheritdoc cref="UnwrapAsync{T}(Result{T}, Func{FailureValue, Task}, Func{Task{T}})"/>
public static Task<T> UnwrapAsync<T>(this Result<T> @this, Func<FailureValue, Task> ifFailed, Func<T> returnThis) =>
R.MatchAsync(@this,
fFail: async f => { await ifFailed(f); return returnThis(); },
fOk: x => x
);

/// <inheritdoc cref="UnwrapAsync{T}(Result{T}, Func{FailureValue, Task}, Func{Task{T}})"/>
public static Task<T> UnwrapAsync<T>(this Result<T> @this, Action<FailureValue> ifFailed, Func<Task<T>> returnThis) =>
R.MatchAsync(@this,
fFail: async f => { ifFailed(f); return await returnThis(); },
fOk: x => x
);

/// <inheritdoc cref="UnwrapAsync{T}(Result{T}, Func{FailureValue, Task}, Func{T})"/>
public static Task<T> UnwrapAsync<T>(this Result<T> @this, Func<FailureValue, Task> ifFailed, Func<Task<T>> returnThis) =>
public static Task<T> UnwrapAsync<T>(this Task<Result<T>> @this, Action<FailureValue> ifFailed, Func<T> returnThis) =>
R.MatchAsync(@this,
fFail: async f => { ifFailed(f); return returnThis(); },
fOk: x => x
);

/// <inheritdoc cref="UnwrapAsync{T}(Result{T}, Func{FailureValue, Task}, Func{T})"/>
public static Task<T> UnwrapAsync<T>(this Task<Result<T>> @this, Func<FailureValue, Task> ifFailed, Func<T> returnThis) =>
R.MatchAsync(@this,
fFail: async f => { await ifFailed(f); return returnThis(); },
fOk: x => x
);

/// <inheritdoc cref="UnwrapAsync{T}(Result{T}, Func{FailureValue, Task}, Func{T})"/>
public static Task<T> UnwrapAsync<T>(this Task<Result<T>> @this, Action<FailureValue> ifFailed, Func<Task<T>> returnThis) =>
R.MatchAsync(@this,
fFail: async f => { ifFailed(f); return await returnThis(); },
fOk: x => x
);

/// <inheritdoc cref="UnwrapAsync{T}(Result{T}, Func{FailureValue, Task}, Func{T})"/>
public static Task<T> UnwrapAsync<T>(this Task<Result<T>> @this, Func<FailureValue, Task> ifFailed, Func<Task<T>> returnThis) =>
R.MatchAsync(@this,
fFail: async f => { await ifFailed(f); return await returnThis(); },
fOk: x => x
Expand Down
2 changes: 1 addition & 1 deletion src/Directory.Build.props
Original file line number Diff line number Diff line change
Expand Up @@ -86,7 +86,7 @@
<Import Project="$(LocalPackPath)" Condition="Exists('$(LocalPackPath)') and '$(Configuration)'=='Release'"/>
<PropertyGroup Label="Local Package Validation" Condition="Exists('$(LocalPackPath)') and '$(Configuration)'=='Release'">
<EnablePackageValidation>true</EnablePackageValidation>
<PackageValidationBaselineVersion>1.2.0</PackageValidationBaselineVersion>
<PackageValidationBaselineVersion>1.2.1</PackageValidationBaselineVersion>
</PropertyGroup>
<Target Name="PackAndPushToLocalNuget" AfterTargets="DispatchToInnerBuilds" Condition="Exists('$(LocalPackPath)') and '$(Configuration)'=='Release'">
<Exec Command="dotnet pack &quot;$(ProjectFileName)&quot; -p:PackageVersion=$(WrapVersion) --no-build --configuration Release"/>
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
// Wrap: Unit Tests.
// Copyright (c) bfren - licensed under https://mit.bfren.dev/2019

namespace Wrap.Extensions.DictionaryExtensions_Tests;

public class GetValueOrNone_Tests
{
public class With_Key_Not_Found
{
[Fact]
public void Returns_None()
{
// Arrange
var dict = new Dictionary<string, int> { [Rnd.Str] = Rnd.Int };
var key = Rnd.Str;

// Act
var result = dict.GetValueOrNone(key);

// Assert
result.AssertNone();
}
}

public class With_Key_Found
{
[Fact]
public void Returns_Some_With_Value()
{
// Arrange
var key = Rnd.Str;
var value = Rnd.Int;
var dict = new Dictionary<string, int> { [key] = value };

// Act
var result = dict.GetValueOrNone(key);

// Assert
result.AssertSome(value);
}
}
}
Loading
Loading