Skip to content

Commit 54b8258

Browse files
authored
Merge pull request #303 from fsprojects/repo-assist/test-async-variants-2026-04-05-3fe06108f7260367
[Repo Assist] Add tests for mapiAsync, tryPickAsync, pickAsync, groupByAsync
2 parents 44f0d67 + 3e8aa05 commit 54b8258

File tree

2 files changed

+137
-0
lines changed

2 files changed

+137
-0
lines changed

RELEASE_NOTES.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
### 4.12.0
22

3+
* Tests: Added tests for `mapiAsync`, `tryPickAsync`, `pickAsync`, and `groupByAsync` — these four async functions previously had no test coverage.
34
* Added `AsyncSeq.tryFindBack` — returns the last element for which the predicate returns true, or `None` if no match. Mirrors `Array.tryFindBack` / `List.tryFindBack`.
45
* Added `AsyncSeq.tryFindBackAsync` — async-predicate variant of `tryFindBack`.
56
* Added `AsyncSeq.findBack` — returns the last element for which the predicate returns true; raises `KeyNotFoundException` if no match. Mirrors `Array.findBack` / `List.findBack`.

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

Lines changed: 136 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4300,3 +4300,139 @@ let ``AsyncSeq.partitionAsync splits by async predicate`` () =
43004300
|> Async.RunSynchronously
43014301
Assert.AreEqual([|2;4;6|], trues)
43024302
Assert.AreEqual([|1;3;5|], falses)
4303+
4304+
// ===== mapiAsync =====
4305+
4306+
[<Test>]
4307+
let ``AsyncSeq.mapiAsync maps elements with their int64 index`` () =
4308+
let result =
4309+
AsyncSeq.ofSeq ["a"; "b"; "c"]
4310+
|> AsyncSeq.mapiAsync (fun i x -> async { return sprintf "%d:%s" i x })
4311+
|> AsyncSeq.toArrayAsync
4312+
|> Async.RunSynchronously
4313+
Assert.AreEqual([| "0:a"; "1:b"; "2:c" |], result)
4314+
4315+
[<Test>]
4316+
let ``AsyncSeq.mapiAsync on empty sequence returns empty`` () =
4317+
let result =
4318+
AsyncSeq.empty<string>
4319+
|> AsyncSeq.mapiAsync (fun i x -> async { return sprintf "%d:%s" i x })
4320+
|> AsyncSeq.toArrayAsync
4321+
|> Async.RunSynchronously
4322+
Assert.AreEqual([||], result)
4323+
4324+
[<Test>]
4325+
let ``AsyncSeq.mapiAsync index is int64 and starts at zero`` () =
4326+
let indices = ResizeArray<int64>()
4327+
AsyncSeq.ofSeq [10; 20; 30]
4328+
|> AsyncSeq.mapiAsync (fun i x -> async { indices.Add(i); return x })
4329+
|> AsyncSeq.toArrayAsync
4330+
|> Async.RunSynchronously
4331+
|> ignore
4332+
Assert.AreEqual([| 0L; 1L; 2L |], indices.ToArray())
4333+
4334+
[<Test>]
4335+
let ``AsyncSeq.mapiAsync matches mapi for pure function`` () =
4336+
for n in 0..20 do
4337+
let ls = List.init n (fun x -> x + 1)
4338+
let expected = ls |> List.mapi (fun i x -> i * x) |> List.toArray
4339+
let actual =
4340+
AsyncSeq.ofSeq ls
4341+
|> AsyncSeq.mapiAsync (fun i x -> async { return int i * x })
4342+
|> AsyncSeq.toArrayAsync
4343+
|> Async.RunSynchronously
4344+
Assert.AreEqual(expected, actual)
4345+
4346+
// ===== tryPickAsync / pickAsync =====
4347+
4348+
[<Test>]
4349+
let ``AsyncSeq.tryPickAsync returns Some for first matching element`` () =
4350+
let result =
4351+
AsyncSeq.ofSeq [1; 2; 3; 4; 5]
4352+
|> AsyncSeq.tryPickAsync (fun x -> async { return if x > 3 then Some (x * 10) else None })
4353+
|> Async.RunSynchronously
4354+
Assert.AreEqual(Some 40, result)
4355+
4356+
[<Test>]
4357+
let ``AsyncSeq.tryPickAsync returns None when no element matches`` () =
4358+
let result =
4359+
AsyncSeq.ofSeq [1; 2; 3]
4360+
|> AsyncSeq.tryPickAsync (fun x -> async { return if x > 99 then Some x else None })
4361+
|> Async.RunSynchronously
4362+
Assert.AreEqual(None, result)
4363+
4364+
[<Test>]
4365+
let ``AsyncSeq.tryPickAsync returns None for empty sequence`` () =
4366+
let result =
4367+
AsyncSeq.empty<int>
4368+
|> AsyncSeq.tryPickAsync (fun x -> async { return Some x })
4369+
|> Async.RunSynchronously
4370+
Assert.AreEqual(None, result)
4371+
4372+
[<Test>]
4373+
let ``AsyncSeq.tryPickAsync returns first match not last`` () =
4374+
let result =
4375+
AsyncSeq.ofSeq [10; 20; 30]
4376+
|> AsyncSeq.tryPickAsync (fun x -> async { return if x % 10 = 0 then Some x else None })
4377+
|> Async.RunSynchronously
4378+
Assert.AreEqual(Some 10, result)
4379+
4380+
[<Test>]
4381+
let ``AsyncSeq.pickAsync returns value for first matching element`` () =
4382+
let result =
4383+
AsyncSeq.ofSeq [1; 2; 3; 4; 5]
4384+
|> AsyncSeq.pickAsync (fun x -> async { return if x = 3 then Some "three" else None })
4385+
|> Async.RunSynchronously
4386+
Assert.AreEqual("three", result)
4387+
4388+
[<Test>]
4389+
let ``AsyncSeq.pickAsync raises KeyNotFoundException when no match`` () =
4390+
Assert.Throws<System.Collections.Generic.KeyNotFoundException>(fun () ->
4391+
AsyncSeq.ofSeq [1; 2; 3]
4392+
|> AsyncSeq.pickAsync (fun x -> async { return if x > 99 then Some x else None })
4393+
|> Async.RunSynchronously
4394+
|> ignore) |> ignore
4395+
4396+
[<Test>]
4397+
let ``AsyncSeq.pickAsync raises KeyNotFoundException for empty sequence`` () =
4398+
Assert.Throws<System.Collections.Generic.KeyNotFoundException>(fun () ->
4399+
AsyncSeq.empty<int>
4400+
|> AsyncSeq.pickAsync (fun x -> async { return Some x })
4401+
|> Async.RunSynchronously
4402+
|> ignore) |> ignore
4403+
4404+
// ===== groupByAsync =====
4405+
4406+
[<Test>]
4407+
let ``AsyncSeq.groupByAsync groups elements by async projection`` () =
4408+
let result =
4409+
AsyncSeq.ofSeq [1..6]
4410+
|> AsyncSeq.groupByAsync (fun x -> async { return x % 2 })
4411+
|> AsyncSeq.mapAsyncParallel (fun (key, grp) -> async {
4412+
let! items = AsyncSeq.toArrayAsync grp
4413+
return key, Array.sort items })
4414+
|> AsyncSeq.toArrayAsync
4415+
|> Async.RunSynchronously
4416+
|> Array.sortBy fst
4417+
Assert.AreEqual([| (0, [|2;4;6|]); (1, [|1;3;5|]) |], result)
4418+
4419+
[<Test>]
4420+
let ``AsyncSeq.groupByAsync on empty sequence returns empty`` () =
4421+
let result =
4422+
AsyncSeq.empty<int>
4423+
|> AsyncSeq.groupByAsync (fun x -> async { return x % 2 })
4424+
|> AsyncSeq.toArrayAsync
4425+
|> Async.RunSynchronously
4426+
Assert.AreEqual([||], result)
4427+
4428+
[<Test>]
4429+
let ``AsyncSeq.groupByAsync with all-same key produces single group`` () =
4430+
let result =
4431+
AsyncSeq.ofSeq [1; 2; 3]
4432+
|> AsyncSeq.groupByAsync (fun _ -> async { return "same" })
4433+
|> AsyncSeq.mapAsyncParallel (fun (key, grp) -> async {
4434+
let! items = AsyncSeq.toArrayAsync grp
4435+
return key, Array.sort items })
4436+
|> AsyncSeq.toArrayAsync
4437+
|> Async.RunSynchronously
4438+
Assert.AreEqual([| ("same", [|1;2;3|]) |], result)

0 commit comments

Comments
 (0)