Skip to content

Commit 676bcef

Browse files
authored
Merge pull request #410 from fsprojects/repo-assist/test-withcancellation-sideeffects-20260426-0dfeab7a31817c9a
[Repo Assist] test: add SideEffects module to TaskSeq.WithCancellation.Tests.fs
2 parents 6f1eae7 + e7f04da commit 676bcef

2 files changed

Lines changed: 55 additions & 0 deletions

File tree

release-notes.txt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@ Unreleased
55
- feat: add `TaskSeq.toChannelAsync` and `TaskSeq.ofChannel` for bidirectional `System.Threading.Channels` integration, closing #415
66
- eng: update PackageValidationBaselineVersion from 0.4.0 to 1.1.1 to enforce binary compatibility checks against the current stable release
77
- test: add SideEffects module and ImmTaskSeq variant tests to TaskSeq.ChunkBy.Tests.fs, improving coverage for chunkBy and chunkByAsync
8+
- test: add SideEffects module to TaskSeq.WithCancellation.Tests.fs, verifying re-iteration semantics are preserved when wrapping with a CancellationToken
89
- fixes: `Async.bind` signature corrected from `(Async<'T> -> Async<'U>)` to `('T -> Async<'U>)` to match standard monadic bind semantics (same as `Task.bind`); the previous signature made the function effectively equivalent to direct application
910
- refactor: simplify splitAt 'rest' taskSeq to use while!, removing redundant go2 mutable and manual MoveNextAsync pre-advance
1011

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

Lines changed: 54 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -170,3 +170,57 @@ module ``Sequence contents`` =
170170

171171
collected |> Seq.toArray |> should equal [| 1..5 |]
172172
}
173+
174+
module SideEffects =
175+
176+
[<Theory; ClassData(typeof<TestSideEffectTaskSeq>)>]
177+
let ``TaskSeq-withCancellation applied multiple times`` variant = task {
178+
let ts = Gen.getSeqWithSideEffect variant
179+
let wrapped = TaskSeq.withCancellation CancellationToken.None ts
180+
181+
let! first = wrapped |> TaskSeq.toArrayAsync
182+
let! second = wrapped |> TaskSeq.toArrayAsync
183+
let! third = wrapped |> TaskSeq.toArrayAsync
184+
185+
first |> should equal [| 1..10 |]
186+
second |> should equal [| 11..20 |]
187+
third |> should equal [| 21..30 |]
188+
}
189+
190+
[<Theory; ClassData(typeof<TestSideEffectTaskSeq>)>]
191+
let ``TaskSeq-withCancellation with active CancellationToken applied multiple times`` variant = task {
192+
use cts = new CancellationTokenSource()
193+
let ts = Gen.getSeqWithSideEffect variant
194+
let wrapped = TaskSeq.withCancellation cts.Token ts
195+
196+
let! first = wrapped |> TaskSeq.toArrayAsync
197+
let! second = wrapped |> TaskSeq.toArrayAsync
198+
199+
first |> should equal [| 1..10 |]
200+
second |> should equal [| 11..20 |]
201+
}
202+
203+
[<Fact>]
204+
let ``TaskSeq-withCancellation evaluates each source element exactly once per iteration`` () = task {
205+
let mutable count = 0
206+
207+
let ts = taskSeq {
208+
for i in 1..5 do
209+
count <- count + 1
210+
yield i
211+
}
212+
213+
let! _ =
214+
ts
215+
|> TaskSeq.withCancellation CancellationToken.None
216+
|> TaskSeq.toArrayAsync
217+
218+
count |> should equal 5
219+
220+
let! _ =
221+
ts
222+
|> TaskSeq.withCancellation CancellationToken.None
223+
|> TaskSeq.toArrayAsync
224+
225+
count |> should equal 10
226+
}

0 commit comments

Comments
 (0)