Skip to content

Commit 86c4adc

Browse files
committed
Extend SideEffect tests
1 parent 6ddf16e commit 86c4adc

File tree

2 files changed

+85
-1
lines changed

2 files changed

+85
-1
lines changed

src/FSharp.Control.TaskSeq.Test/TaskSeq.TakeWhile.Tests.fs

Lines changed: 84 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -133,3 +133,87 @@ module SideEffects =
133133
|> TaskSeq.map ((+) '@')
134134
|> TaskSeq.toArrayAsync
135135
|> Task.map (String >> should equal "ABCDE")
136+
137+
[<Theory; InlineData(false, false); InlineData(true, false); InlineData(false, true); InlineData(true, true)>]
138+
let ``TaskSeq-takeWhile(Inclusive)?(Async)? __special-case__ prove it does not read beyond the failing yield`` (inclusive, async) = task {
139+
let mutable x = 42 // for this test, the potential mutation should not actually occur
140+
141+
let items = taskSeq {
142+
yield x // Always passes the test; always returned
143+
yield x * 2 // the failing item (which will also be yielded in the result when using *Inclusive)
144+
x <- x + 1 // we are proving we never get here
145+
}
146+
147+
let f =
148+
match inclusive, async with
149+
| false, false -> TaskSeq.takeWhile (fun x -> x = 42)
150+
| true, false -> TaskSeq.takeWhileInclusive (fun x -> x = 42)
151+
| false, true -> TaskSeq.takeWhileAsync (fun x -> task { return x = 42 })
152+
| true, true -> TaskSeq.takeWhileInclusiveAsync (fun x -> task { return x = 42 })
153+
154+
let expected = if inclusive then [| 42; 84 |] else [| 42 |]
155+
156+
let! first = items |> f |> TaskSeq.toArrayAsync
157+
let! repeat = items |> f |> TaskSeq.toArrayAsync
158+
159+
first |> should equal expected
160+
repeat |> should equal expected
161+
x |> should equal 42
162+
}
163+
164+
[<Theory; InlineData(false, false); InlineData(true, false); InlineData(false, true); InlineData(true, true)>]
165+
let ``TaskSeq-takeWhile(Inclusive)?(Async)? __special-case__ prove side effects are executed`` (inclusive, async) = task {
166+
let mutable x = 41
167+
168+
let items = taskSeq {
169+
x <- x + 1
170+
yield x
171+
x <- x + 2
172+
yield x * 2
173+
x <- x + 200 // as previously proven, we should not trigger this
174+
}
175+
176+
let f =
177+
match inclusive, async with
178+
| false, false -> TaskSeq.takeWhile (fun x -> x < 50)
179+
| true, false -> TaskSeq.takeWhileInclusive (fun x -> x < 50)
180+
| false, true -> TaskSeq.takeWhileAsync (fun x -> task { return x < 50 })
181+
| true, true -> TaskSeq.takeWhileInclusiveAsync (fun x -> task { return x < 50 })
182+
183+
let expectedFirst = if inclusive then [| 42; 44*2 |] else [| 42 |]
184+
let expectedRepeat = if inclusive then [| 45; 47*2 |] else [| 45 |]
185+
186+
let! first = items |> f |> TaskSeq.toArrayAsync
187+
x |> should equal 44
188+
let! repeat = items |> f |> TaskSeq.toArrayAsync
189+
x |> should equal 47
190+
191+
first |> should equal expectedFirst
192+
repeat |> should equal expectedRepeat
193+
}
194+
195+
[<Theory; ClassData(typeof<TestSideEffectTaskSeq>)>]
196+
let ``TaskSeq-takeWhile consumes the prefix of a longer sequence, with mutation`` variant = task {
197+
let ts = Gen.getSeqWithSideEffect variant
198+
199+
let! first = TaskSeq.takeWhile (fun x -> x < 5) ts |> TaskSeq.toArrayAsync
200+
let expected = [| 1..4 |]
201+
first |> should equal expected
202+
203+
// side effect, reiterating causes it to resume from where we left it (minus the failing item)
204+
let! repeat = TaskSeq.takeWhile (fun x -> x < 5) ts |> TaskSeq.toArrayAsync
205+
repeat |> should not' (equal expected)
206+
}
207+
208+
[<Theory; ClassData(typeof<TestSideEffectTaskSeq>)>]
209+
let ``TaskSeq-takeWhileInclusiveAsync consumes the prefix for a longer sequence, with mutation`` variant = task {
210+
let ts = Gen.getSeqWithSideEffect variant
211+
212+
let! first = TaskSeq.takeWhileInclusiveAsync (fun x -> task { return x < 5 }) ts |> TaskSeq.toArrayAsync
213+
let expected = [| 1..5 |]
214+
first |> should equal expected
215+
216+
// side effect, reiterating causes it to resume from where we left it (minus the failing item)
217+
let! repeat = TaskSeq.takeWhileInclusiveAsync (fun x -> task { return x < 5 }) ts |> TaskSeq.toArrayAsync
218+
repeat |> should not' (equal expected)
219+
}

src/FSharp.Control.TaskSeq/TaskSeq.fs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -253,7 +253,7 @@ module TaskSeq =
253253
let chooseAsync chooser source = Internal.choose (TryPickAsync chooser) source
254254
let filter predicate source = Internal.filter (Predicate predicate) source
255255
let filterAsync predicate source = Internal.filter (PredicateAsync predicate) source
256-
let takeWhile predicate source = Internal.takeWhile false (Predicate predicate) source
256+
let takeWhile predicate source = Internal.takeWhile (*inclusive:*)false (Predicate predicate) source
257257
let takeWhileAsync predicate source = Internal.takeWhile false (PredicateAsync predicate) source
258258
let takeWhileInclusive predicate source = Internal.takeWhile true (Predicate predicate) source
259259
let takeWhileInclusiveAsync predicate source = Internal.takeWhile true (PredicateAsync predicate) source

0 commit comments

Comments
 (0)