Skip to content

Commit cc1a858

Browse files
authored
Merge pull request #286 from fsprojects/repo-assist/test-missing-coverage-2026-03-21-8caa3b63f77bef88
[Repo Assist] Tests: add coverage for indexed, iteriAsync, tryLast, replicateUntilNoneAsync, reduceAsync
2 parents 7319e42 + dac50aa commit cc1a858

File tree

2 files changed

+143
-0
lines changed

2 files changed

+143
-0
lines changed

RELEASE_NOTES.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@
1212
* Added `AsyncSeq.delay` — defers sequence creation to enumeration time by calling a factory function each time `GetAsyncEnumerator` is called. Mirrors `TaskSeq.delay`.
1313
* Added `AsyncSeq.collectAsync` — like `collect` but the mapping function is asynchronous (`'T -> Async<AsyncSeq<'U>>`). Mirrors `TaskSeq.collectAsync`.
1414
* Added `AsyncSeq.partition` / `AsyncSeq.partitionAsync` — splits a sequence into two arrays using a (optionally async) predicate; the first array contains matching elements, the second non-matching. Mirrors `TaskSeq.partition` / `TaskSeq.partitionAsync`.
15+
* Tests: added 14 new unit tests covering previously untested functions — `AsyncSeq.indexed`, `AsyncSeq.iteriAsync`, `AsyncSeq.tryLast`, `AsyncSeq.replicateUntilNoneAsync`, and `AsyncSeq.reduceAsync` (empty-sequence edge case).
1516

1617
### 4.10.0
1718

tests/FSharp.Control.AsyncSeq.Tests/AsyncSeqTests.fs

Lines changed: 142 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3720,6 +3720,148 @@ let ``AsyncSeq.withCancellation with cancelled token raises OperationCanceledExc
37203720
|> ignore)
37213721
|> ignore
37223722

3723+
// ===== indexed =====
3724+
3725+
[<Test>]
3726+
let ``AsyncSeq.indexed pairs elements with int64 indices`` () =
3727+
let result =
3728+
AsyncSeq.ofSeq [ "a"; "b"; "c" ]
3729+
|> AsyncSeq.indexed
3730+
|> AsyncSeq.toArrayAsync
3731+
|> Async.RunSynchronously
3732+
Assert.AreEqual([| (0L, "a"); (1L, "b"); (2L, "c") |], result)
3733+
3734+
[<Test>]
3735+
let ``AsyncSeq.indexed on empty sequence returns empty`` () =
3736+
let result =
3737+
AsyncSeq.empty<int>
3738+
|> AsyncSeq.indexed
3739+
|> AsyncSeq.toArrayAsync
3740+
|> Async.RunSynchronously
3741+
Assert.AreEqual([||], result)
3742+
3743+
[<Test>]
3744+
let ``AsyncSeq.indexed index starts at zero for singleton`` () =
3745+
let result =
3746+
AsyncSeq.singleton 42
3747+
|> AsyncSeq.indexed
3748+
|> AsyncSeq.toArrayAsync
3749+
|> Async.RunSynchronously
3750+
Assert.AreEqual([| (0L, 42) |], result)
3751+
3752+
[<Test>]
3753+
let ``AsyncSeq.indexed produces consecutive int64 indices`` () =
3754+
let n = 100
3755+
let result =
3756+
AsyncSeq.init (int64 n) id
3757+
|> AsyncSeq.indexed
3758+
|> AsyncSeq.toArrayAsync
3759+
|> Async.RunSynchronously
3760+
let indices = result |> Array.map fst
3761+
Assert.AreEqual(Array.init n int64, indices)
3762+
3763+
// ===== iteriAsync =====
3764+
3765+
[<Test>]
3766+
let ``AsyncSeq.iteriAsync calls action with correct indices and values`` () =
3767+
let log = ResizeArray<int * int>()
3768+
AsyncSeq.ofSeq [ 10; 20; 30 ]
3769+
|> AsyncSeq.iteriAsync (fun i v -> async { log.Add(i, v) })
3770+
|> Async.RunSynchronously
3771+
Assert.AreEqual([ (0, 10); (1, 20); (2, 30) ], log |> Seq.toList)
3772+
3773+
[<Test>]
3774+
let ``AsyncSeq.iteriAsync on empty sequence does not call action`` () =
3775+
let mutable callCount = 0
3776+
AsyncSeq.empty<int>
3777+
|> AsyncSeq.iteriAsync (fun _ _ -> async { callCount <- callCount + 1 })
3778+
|> Async.RunSynchronously
3779+
Assert.AreEqual(0, callCount)
3780+
3781+
[<Test>]
3782+
let ``AsyncSeq.iteriAsync index is zero-based`` () =
3783+
let indices = ResizeArray<int>()
3784+
AsyncSeq.ofSeq [ "x"; "y"; "z" ]
3785+
|> AsyncSeq.iteriAsync (fun i _ -> async { indices.Add(i) })
3786+
|> Async.RunSynchronously
3787+
Assert.AreEqual([ 0; 1; 2 ], indices |> Seq.toList)
3788+
3789+
// ===== tryLast =====
3790+
3791+
[<Test>]
3792+
let ``AsyncSeq.tryLast returns Some last element for non-empty sequence`` () =
3793+
let result =
3794+
AsyncSeq.ofSeq [ 1; 2; 3 ]
3795+
|> AsyncSeq.tryLast
3796+
|> Async.RunSynchronously
3797+
Assert.AreEqual(Some 3, result)
3798+
3799+
[<Test>]
3800+
let ``AsyncSeq.tryLast returns None for empty sequence`` () =
3801+
let result =
3802+
AsyncSeq.empty<int>
3803+
|> AsyncSeq.tryLast
3804+
|> Async.RunSynchronously
3805+
Assert.AreEqual(None, result)
3806+
3807+
[<Test>]
3808+
let ``AsyncSeq.tryLast returns Some for singleton sequence`` () =
3809+
let result =
3810+
AsyncSeq.singleton 99
3811+
|> AsyncSeq.tryLast
3812+
|> Async.RunSynchronously
3813+
Assert.AreEqual(Some 99, result)
3814+
3815+
// ===== replicateUntilNoneAsync =====
3816+
3817+
[<Test>]
3818+
let ``AsyncSeq.replicateUntilNoneAsync generates elements until None`` () =
3819+
let mutable counter = 0
3820+
let gen = async {
3821+
counter <- counter + 1
3822+
if counter <= 3 then return Some counter
3823+
else return None
3824+
}
3825+
let result =
3826+
AsyncSeq.replicateUntilNoneAsync gen
3827+
|> AsyncSeq.toArrayAsync
3828+
|> Async.RunSynchronously
3829+
Assert.AreEqual([| 1; 2; 3 |], result)
3830+
3831+
[<Test>]
3832+
let ``AsyncSeq.replicateUntilNoneAsync returns empty for immediate None`` () =
3833+
let result =
3834+
AsyncSeq.replicateUntilNoneAsync (async { return None })
3835+
|> AsyncSeq.toArrayAsync
3836+
|> Async.RunSynchronously
3837+
Assert.AreEqual([||], result)
3838+
3839+
[<Test>]
3840+
let ``AsyncSeq.replicateUntilNoneAsync returns single element then stops`` () =
3841+
let mutable called = false
3842+
let gen = async {
3843+
if not called then
3844+
called <- true
3845+
return Some 42
3846+
else
3847+
return None
3848+
}
3849+
let result =
3850+
AsyncSeq.replicateUntilNoneAsync gen
3851+
|> AsyncSeq.toArrayAsync
3852+
|> Async.RunSynchronously
3853+
Assert.AreEqual([| 42 |], result)
3854+
3855+
// ===== reduceAsync edge case =====
3856+
3857+
[<Test>]
3858+
let ``AsyncSeq.reduceAsync raises InvalidOperationException on empty sequence`` () =
3859+
Assert.Throws<System.InvalidOperationException>(fun () ->
3860+
AsyncSeq.empty<int>
3861+
|> AsyncSeq.reduceAsync (fun a b -> async { return a + b })
3862+
|> Async.RunSynchronously
3863+
|> ignore)
3864+
|> ignore
37233865
// ── Design parity with FSharp.Control.TaskSeq (issue #277, batch 2) ─────────
37243866

37253867
[<Test>]

0 commit comments

Comments
 (0)