Skip to content

Commit c5b24ec

Browse files
committed
Add tests to ensure DisposeAsync is called in task-for and async-for
1 parent 1bd4e71 commit c5b24ec

File tree

3 files changed

+92
-0
lines changed

3 files changed

+92
-0
lines changed

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

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -115,3 +115,30 @@ module SideEffects =
115115

116116
sum |> should equal 465 // eq to: List.sum [1..30]
117117
}
118+
119+
module Other =
120+
[<Fact>]
121+
let ``Async-for CE must call dispose in empty taskSeq`` () = async {
122+
let disposed = ref 0
123+
let values = Gen.getEmptyDisposableTaskSeq disposed
124+
125+
for x in values do
126+
()
127+
128+
// the DisposeAsync should be called by now
129+
disposed.Value |> should equal 1
130+
}
131+
132+
[<Fact>]
133+
let ``Async-for CE must call dispose on singleton`` () = async {
134+
let disposed = ref 0
135+
let mutable sum = 0
136+
let values = Gen.getSingletonDisposableTaskSeq disposed
137+
138+
for x in values do
139+
sum <- x
140+
141+
// the DisposeAsync should be called by now
142+
disposed.Value |> should equal 1
143+
sum |> should equal 42
144+
}

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

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -114,3 +114,30 @@ module SideEffects =
114114

115115
sum |> should equal 465 // eq to: List.sum [1..30]
116116
}
117+
118+
module Other =
119+
[<Fact>]
120+
let ``Task-for CE must call dispose in empty taskSeq`` () = async {
121+
let disposed = ref 0
122+
let values = Gen.getEmptyDisposableTaskSeq disposed
123+
124+
for x in values do
125+
()
126+
127+
// the DisposeAsync should be called by now
128+
disposed.Value |> should equal 1
129+
}
130+
131+
[<Fact>]
132+
let ``Task-for CE must call dispose on singleton`` () = async {
133+
let disposed = ref 0
134+
let mutable sum = 0
135+
let values = Gen.getSingletonDisposableTaskSeq disposed
136+
137+
for x in values do
138+
sum <- x
139+
140+
// the DisposeAsync should be called by now
141+
disposed.Value |> should equal 1
142+
sum |> should equal 42
143+
}

src/FSharp.Control.TaskSeq.Test/TestUtils.fs

Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -521,6 +521,44 @@ module TestUtils =
521521
}
522522
| x -> failwithf "Invalid test variant: %A" x
523523

524+
/// An empty taskSeq that can be used with tests for checking if the dispose method gets called.
525+
/// Will add 1 to the passed integer upon disposing.
526+
let getEmptyDisposableTaskSeq (disposed: int ref) =
527+
{ new IAsyncEnumerable<'T> with
528+
member _.GetAsyncEnumerator(_) =
529+
{ new IAsyncEnumerator<'T> with
530+
member _.MoveNextAsync() = ValueTask.False
531+
member _.Current = Unchecked.defaultof<'T>
532+
member _.DisposeAsync() = ValueTask(task { do disposed.Value <- disposed.Value + 1 })
533+
}
534+
}
535+
536+
/// A singleton taskSeq that can be used with tests for checking if the dispose method gets called
537+
/// The singleton value is '42'. Will add 1 to the passed integer upon disposing.
538+
let getSingletonDisposableTaskSeq (disposed: int ref) =
539+
{ new IAsyncEnumerable<int> with
540+
member _.GetAsyncEnumerator(_) =
541+
let mutable status = BeforeAll
542+
543+
{ new IAsyncEnumerator<int> with
544+
member _.MoveNextAsync() =
545+
match status with
546+
| BeforeAll ->
547+
status <- WithCurrent
548+
ValueTask.True
549+
| WithCurrent ->
550+
status <- AfterAll
551+
ValueTask.False
552+
| AfterAll -> ValueTask.False
553+
554+
member _.Current: int =
555+
match status with
556+
| WithCurrent -> 42
557+
| _ -> Unchecked.defaultof<int>
558+
559+
member _.DisposeAsync() = ValueTask(task { do disposed.Value <- disposed.Value + 1 })
560+
}
561+
}
524562
//
525563
// following types can be used with Theory & TestData
526564
//

0 commit comments

Comments
 (0)