@@ -14,6 +14,8 @@ open FSharp.Control
1414// TaskSeq.skipWhileInclusiveAsync
1515//
1616
17+ exception SideEffectPastEnd of string
18+
1719[<AutoOpen>]
1820module With =
1921 /// The only real difference in semantics between the base and the *Inclusive variant lies in whether the final item is skipped.
@@ -182,36 +184,34 @@ module SideEffects =
182184 [<InlineData( false , true ) >]
183185 [<InlineData( true , false ) >]
184186 [<InlineData( true , true ) >]
185- let ``TaskSeq - skipWhileXXX prove it does not read beyond the failing yield `` ( inclusive , isAsync ) = task {
187+ let ``TaskSeq - skipWhileXXX prove it reads the entire input stream `` ( inclusive , isAsync ) = task {
186188 let mutable x = 42 // for this test, the potential mutation should not actually occur
187189 let functionToTest = getFunction inclusive isAsync ((=) 42 )
188190
189191 let items = taskSeq {
190192 yield x // Always passes the test; always skipped
191193 yield x * 2 // Fails the test, skipped depending on "inclusive"
192- x <- x + 1 // we are proving we never get here
194+ x <- x + 1 // we are proving we ALWAYS get here
193195 }
194196
195- // we skip one more if "inclusive"
196- let expected = if inclusive then [||] else [| 84 |]
197-
198197 x |> should equal 42
199198 let! first = items |> functionToTest |> TaskSeq.toArrayAsync
200- x |> should equal 42
199+ x |> should equal 43
200+ first |> should equal ( if inclusive then [||] else [| 84 |])
201+
201202 let! repeat = items |> functionToTest |> TaskSeq.toArrayAsync
202- x |> should equal 42
203+ x |> should equal 44
203204
204- first |> should equal expected
205- repeat |> should equal expected
206- x |> should equal 42 // if the var changed, we got too far
205+ repeat
206+ |> should equal ( if inclusive then [| 86 |] else [| 43 ; 86 |])
207207 }
208208
209209 [<Theory>]
210210 [<InlineData( false , false ) >]
211211 [<InlineData( false , true ) >]
212212 [<InlineData( true , false ) >]
213213 [<InlineData( true , true ) >]
214- let ``TaskSeq - skipWhileXXX prove side effects are executed`` ( inclusive , isAsync ) = task {
214+ let ``TaskSeq - skipWhileXXX prove side effects are properly executed`` ( inclusive , isAsync ) = task {
215215 let mutable x = 41
216216 let functionToTest = getFunction inclusive isAsync ((>) 50 )
217217
@@ -220,17 +220,18 @@ module SideEffects =
220220 yield x
221221 x <- x + 2
222222 yield x * 2
223- x <- x + 200 // as previously proven, we should not trigger this
223+ x <- x + 200 // as previously proven, we should ALWAYS trigger this
224224 }
225225
226- let expectedFirst = if inclusive then [||] else [| 44 * 2 |]
227- let expectedRepeat = if inclusive then [||] else [| 47 * 2 |]
226+ let expectedFirst = if inclusive then [||] else [| 88 |]
227+ let expectedRepeat = if inclusive then [| 494 |] else [| 245 ; 494 |]
228228
229229 x |> should equal 41
230230 let! first = items |> functionToTest |> TaskSeq.toArrayAsync
231- x |> should equal 44
231+ x |> should equal 244
232+
232233 let! repeat = items |> functionToTest |> TaskSeq.toArrayAsync
233- x |> should equal 47
234+ x |> should equal 447
234235
235236 first |> should equal expectedFirst
236237 repeat |> should equal expectedRepeat
@@ -313,40 +314,19 @@ module Other =
313314 [<InlineData( false , true ) >]
314315 [<InlineData( true , false ) >]
315316 [<InlineData( true , true ) >]
316- let ``TaskSeq - skipWhileXXX stops consuming after predicate fails`` ( inclusive , isAsync ) = task {
317- do !
318- seq {
319- yield ! [ 1 ; 2 ; 2 ; 3 ; 3 ]
320- yield failwith " Too far"
321- }
322- |> TaskSeq.ofSeq
323- |> TaskSeq.skipWhile ( fun x -> x <= 2 )
324- |> verifyDigitsAsString " CC"
325-
326- do !
327- seq {
328- yield ! [ 1 ; 2 ; 2 ; 3 ; 3 ]
329- yield failwith " Too far"
330- }
331- |> TaskSeq.ofSeq
332- |> TaskSeq.skipWhileInclusive ( fun x -> x <= 2 )
333- |> verifyDigitsAsString " C"
334-
335- do !
336- seq {
337- yield ! [ 1 ; 2 ; 2 ; 3 ; 3 ]
338- yield failwith " Too far"
339- }
340- |> TaskSeq.ofSeq
341- |> TaskSeq.skipWhileAsync ( fun x -> Task.fromResult ( x <= 2 ))
342- |> verifyDigitsAsString " CC"
343-
344- do !
345- seq {
346- yield ! [ 1 ; 2 ; 2 ; 3 ; 3 ]
347- yield failwith " Too far"
348- }
349- |> TaskSeq.ofSeq
350- |> TaskSeq.skipWhileInclusiveAsync ( fun x -> Task.fromResult ( x <= 2 ))
351- |> verifyDigitsAsString " C"
352- }
317+ let ``TaskSeq - skipWhileXXX stops consuming after predicate fails`` ( inclusive , isAsync ) =
318+ let testSkipper skipper =
319+ fun () ->
320+ seq {
321+ yield ! [ 1 ; 2 ; 2 ; 3 ; 3 ]
322+ yield SideEffectPastEnd " Too far" |> raise
323+ }
324+ |> TaskSeq.ofSeq
325+ |> skipper
326+ |> consumeTaskSeq
327+ |> should throwAsyncExact typeof< SideEffectPastEnd>
328+
329+ do testSkipper ( TaskSeq.skipWhile ( fun x -> x <= 2 ))
330+ do testSkipper ( TaskSeq.skipWhileInclusive ( fun x -> x <= 2 ))
331+ do testSkipper ( TaskSeq.skipWhileAsync ( fun x -> Task.fromResult ( x <= 2 )))
332+ do testSkipper ( TaskSeq.skipWhileInclusiveAsync ( fun x -> Task.fromResult ( x <= 2 )))
0 commit comments