Skip to content

Commit ceb9009

Browse files
1eyewonderTheAngryByrd
authored andcommitted
Updated AsyncValidation due to discovery in CancellableTaskValidation tests
1 parent fd823eb commit ceb9009

File tree

4 files changed

+110
-11
lines changed

4 files changed

+110
-11
lines changed

src/FsToolkit.ErrorHandling.IcedTasks/CancellableTaskValidationCE.fs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -812,7 +812,7 @@ module CancellableTaskValidationCE =
812812
this.ReturnFrom(Async.AwaitCancellableTaskValidation t)
813813

814814

815-
type FsToolkit.ErrorHandling.AsyncResultCE.AsyncResultBuilder with
815+
type FsToolkit.ErrorHandling.AsyncValidationCE.AsyncValidationBuilder with
816816

817817
member inline this.Source
818818
([<InlineIfLambda>] t: CancellableTaskValidation<'T, 'Error>)

src/FsToolkit.ErrorHandling/AsyncValidationCE.fs

Lines changed: 31 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -139,26 +139,54 @@ module AsyncValidationCE =
139139
let asyncValidation = AsyncValidationBuilder()
140140

141141
[<AutoOpen>]
142-
module AsyncValidationCEExtensions =
142+
module HighPriority =
143143

144144
// Having members as extensions gives them lower priority in
145145
// overload resolution and allows skipping more type annotations.
146146
type AsyncValidationBuilder with
147147

148148
/// <summary>
149-
/// Needed to allow `for..in` and `for..do` functionality
149+
/// Method lets us transform data types into our internal representation.
150150
/// </summary>
151-
member inline _.Source(s: #seq<_>) : #seq<_> = s
151+
member inline _.Source(s: Async<Result<'ok, 'error>>) : AsyncValidation<_, 'error> =
152+
s
153+
|> AsyncResult.mapError (fun e -> [ e ])
152154

153155
/// <summary>
154156
/// Method lets us transform data types into our internal representation.
155157
/// </summary>
156158
member inline _.Source(s: Result<'ok, 'error>) : AsyncValidation<'ok, 'error> =
157159
AsyncValidation.ofResult s
158160

161+
/// <summary>
162+
/// Method lets us transform data types into our internal representation.
163+
/// </summary>
164+
/// <returns></returns>
165+
member inline _.Source(a: Async<'ok>) : AsyncValidation<'ok, 'error> =
166+
async {
167+
let! result = a
168+
return! AsyncValidation.ok result
169+
}
170+
159171
/// <summary>
160172
/// Method lets us transform data types into our internal representation.
161173
/// </summary>
162174
/// <returns></returns>
163175
member inline _.Source(choice: Choice<'ok, 'error>) : AsyncValidation<'ok, 'error> =
164176
AsyncValidation.ofChoice choice
177+
178+
/// <summary>
179+
/// Needed to allow `for..in` and `for..do` functionality
180+
/// </summary>
181+
member inline _.Source(s: #seq<_>) : #seq<_> = s
182+
183+
[<AutoOpen>]
184+
module LowPriority =
185+
186+
type AsyncValidationBuilder with
187+
188+
/// <summary>
189+
/// Method lets us transform data types into our internal representation.
190+
/// </summary>
191+
member inline _.Source(s: Validation<'ok, 'error>) : AsyncValidation<'ok, 'error> =
192+
Async.retn s

tests/FsToolkit.ErrorHandling.IcedTasks.Tests/CancellableTaskValidationCE.fs

Lines changed: 62 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1088,7 +1088,39 @@ module CancellableTaskValidationCE =
10881088
Expect.equal actual expected "Should be Error"
10891089
}
10901090

1091-
testCaseTask "Fail Path Validation"
1091+
testCaseTask "Fail Path Error Validation"
1092+
<| fun () ->
1093+
task {
1094+
let expected =
1095+
Error [
1096+
"Error 1"
1097+
"Error 2"
1098+
"Error 3"
1099+
]
1100+
1101+
let actual =
1102+
cancellableTaskValidation {
1103+
let! a = Ok 3
1104+
and! b = Ok 2
1105+
and! c = Error "Error 1"
1106+
1107+
and! d =
1108+
Error [
1109+
"Error 2"
1110+
"Error 3"
1111+
]
1112+
1113+
return
1114+
a + b
1115+
- c
1116+
- d
1117+
}
1118+
1119+
let! actual = actual CancellationToken.None
1120+
Expect.equal actual expected "Should be Error"
1121+
}
1122+
1123+
testCaseTask "Fail Path Ok Validation"
10921124
<| fun () ->
10931125
task {
10941126
let expected = CancellableTaskValidation.error "TryParse failure"
@@ -1186,6 +1218,22 @@ module CancellableTaskValidationCE =
11861218

11871219
Expect.equal actual (Ok cts.Token) ""
11881220

1221+
testCase
1222+
"CancellationToken flows from AsyncValidation<T> to CancellableTaskValidation<T>"
1223+
<| fun () ->
1224+
let innerTask =
1225+
cancellableTaskValidation {
1226+
return! CancellableTaskValidation.getCancellationToken ()
1227+
}
1228+
1229+
let outerAsync = asyncValidation { return! innerTask }
1230+
1231+
use cts = new CancellationTokenSource()
1232+
1233+
let actual = Async.RunSynchronously(outerAsync, cancellationToken = cts.Token)
1234+
1235+
Expect.equal actual (Ok cts.Token) ""
1236+
11891237
testCase "CancellationToken flows from CancellableTaskValidation<T> to Async<unit>"
11901238
<| fun () ->
11911239
let innerAsync = async { return! Async.CancellationToken }
@@ -1211,6 +1259,19 @@ module CancellableTaskValidationCE =
12111259

12121260
Expect.equal actual (Ok cts.Token) ""
12131261

1262+
testCase
1263+
"CancellationToken flows from CancellableTaskValidation<T> to AsyncValidation<unit>"
1264+
<| fun () ->
1265+
let innerAsync = asyncValidation { return! Async.CancellationToken }
1266+
1267+
let outerTask = cancellableTaskValidation { return! innerAsync }
1268+
1269+
use cts = new CancellationTokenSource()
1270+
1271+
let actual = (outerTask cts.Token).GetAwaiter().GetResult()
1272+
1273+
Expect.equal actual (Ok cts.Token) ""
1274+
12141275
testCase
12151276
"CancellationToken flows from CancellableTaskValidation<T> to CancellableTask<T>"
12161277
<| fun () ->

tests/FsToolkit.ErrorHandling.Tests/AsyncValidationCE.fs

Lines changed: 16 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -57,14 +57,14 @@ let ``AsyncValidationCE return! Tests`` =
5757
testCaseAsync "Return Ok Validation"
5858
<| async {
5959
let innerData = "Foo"
60-
let! data = AsyncValidation.ok innerData
60+
let data = Validation.ok innerData
6161
let! actual = asyncValidation { return! data }
6262
Expect.equal actual (Result.Ok innerData) "Should be ok"
6363
}
6464
testCaseAsync "Return Error Validation"
6565
<| async {
6666
let innerData = "Foo"
67-
let! expected = AsyncValidation.error innerData
67+
let expected = Validation.error innerData
6868
let data = AsyncValidation.error innerData
6969
let! actual = asyncValidation { return! data }
7070
Expect.equal actual expected "Should be ok"
@@ -74,6 +74,18 @@ let ``AsyncValidationCE return! Tests`` =
7474

7575
let ``AsyncValidationCE bind Tests`` =
7676
testList "AsyncValidationCE bind Tests" [
77+
testCaseAsync "let! Async"
78+
<| async {
79+
let data = "Foo"
80+
81+
let! actual =
82+
asyncValidation {
83+
let! f = async { return data }
84+
return f
85+
}
86+
87+
Expect.equal actual (Ok data) "Should be ok"
88+
}
7789
testCaseAsync "let! Ok result"
7890
<| async {
7991
let data = Result.Ok "Foo"
@@ -130,11 +142,10 @@ let ``AsyncValidationCE bind Tests`` =
130142
testCaseAsync "let! Ok Validation"
131143
<| async {
132144
let innerData = "Foo"
133-
let! data = AsyncValidation.ok innerData
134145

135146
let! actual =
136147
asyncValidation {
137-
let! f = data
148+
let! f = validation { return innerData }
138149
return f
139150
}
140151

@@ -143,12 +154,11 @@ let ``AsyncValidationCE bind Tests`` =
143154
testCaseAsync "let! Error Validation"
144155
<| async {
145156
let innerData = "Foo"
146-
let data = AsyncValidation.error innerData
147157
let! expected = AsyncValidation.error innerData
148158

149159
let! actual =
150160
asyncValidation {
151-
let! f = data
161+
let! f = validation { return Error innerData }
152162
return f
153163
}
154164

0 commit comments

Comments
 (0)