11module TaskSeq.Tests.Concat
22
3+ open System
34open System.Collections .Generic
45
56open Xunit
@@ -8,7 +9,11 @@ open FsUnit.Xunit
89open FSharp.Control
910
1011//
11- // TaskSeq.concat
12+ // TaskSeq.concat - of task seqs
13+ // TaskSeq.concat - of seqs
14+ // TaskSeq.concat - of lists
15+ // TaskSeq.concat - of arrays
16+ // TaskSeq.concat - of resizable arrays
1217//
1318
1419let validateSequence ts =
@@ -20,31 +25,126 @@ let validateSequence ts =
2025
2126module EmptySeq =
2227 [<Fact>]
23- let ``Null source is invalid`` () = assertNullArg <| fun () -> TaskSeq.concat null
28+ let ``Null source is invalid ( taskseq ) `` () =
29+ assertNullArg
30+ <| fun () -> TaskSeq.concat ( null : TaskSeq< TaskSeq<_>>)
31+
32+ [<Fact>]
33+ let ``Null source is invalid ( seq ) `` () =
34+ assertNullArg
35+ <| fun () -> TaskSeq.concat ( null : TaskSeq< seq<_>>)
36+
37+ [<Fact>]
38+ let ``Null source is invalid ( array ) `` () =
39+ assertNullArg
40+ <| fun () -> TaskSeq.concat ( null : TaskSeq< array<_>>)
41+
42+ [<Fact>]
43+ let ``Null source is invalid ( list ) `` () =
44+ assertNullArg
45+ <| fun () -> TaskSeq.concat ( null : TaskSeq< list<_>>)
46+
47+ [<Fact>]
48+ let ``Null source is invalid ( resizarray ) `` () =
49+ assertNullArg
50+ <| fun () -> TaskSeq.concat ( null : TaskSeq< ResizeArray<_>>)
2451
2552 [<Theory; ClassData( typeof< TestEmptyVariants>) >]
26- let ``TaskSeq - concat with empty sequences`` variant =
53+ let ``TaskSeq - concat with nested empty task sequences`` variant =
2754 taskSeq {
28- yield Gen.getEmptyVariant variant // not yield-bang!
2955 yield Gen.getEmptyVariant variant
3056 yield Gen.getEmptyVariant variant
57+ yield Gen.getEmptyVariant variant
58+ }
59+ |> TaskSeq.concat
60+ |> verifyEmpty
61+
62+ [<Fact>]
63+ let ``TaskSeq - concat with nested empty sequences`` () =
64+ taskSeq {
65+ yield Seq.empty< string>
66+ yield Seq.empty< string>
67+ yield Seq.empty< string>
68+ }
69+ |> TaskSeq.concat
70+ |> verifyEmpty
71+
72+ [<Fact>]
73+ let ``TaskSeq - concat with nested empty arrays`` () =
74+ taskSeq {
75+ yield Array.empty< int>
76+ yield Array.empty< int>
77+ yield Array.empty< int>
78+ }
79+ |> TaskSeq.concat
80+ |> verifyEmpty
81+
82+ [<Fact>]
83+ let ``TaskSeq - concat with nested empty lists`` () =
84+ taskSeq {
85+ yield List.empty< Guid>
86+ yield List.empty< Guid>
87+ yield List.empty< Guid>
3188 }
3289 |> TaskSeq.concat
3390 |> verifyEmpty
3491
92+ [<Fact>]
93+ let ``TaskSeq - concat with multiple nested empty resizable arrays`` () =
94+ taskSeq {
95+ yield ResizeArray( List.empty< byte>)
96+ yield ResizeArray( List.empty< byte>)
97+ yield ResizeArray( List.empty< byte>)
98+ }
99+ |> TaskSeq.concat
100+ |> verifyEmpty
101+
102+ [<Theory; ClassData( typeof< TestEmptyVariants>) >]
103+ let ``TaskSeq - concat with empty source ( taskseq ) `` variant =
104+ Gen.getEmptyVariant variant
105+ |> TaskSeq.box
106+ |> TaskSeq.cast< IAsyncEnumerable< int>> // task seq is empty so this should not raise
107+ |> TaskSeq.concat
108+ |> verifyEmpty
109+
110+ [<Theory; ClassData( typeof< TestEmptyVariants>) >]
111+ let ``TaskSeq - concat with empty source ( seq ) `` variant =
112+ Gen.getEmptyVariant variant
113+ |> TaskSeq.box
114+ |> TaskSeq.cast< int seq> // task seq is empty so this should not raise
115+ |> TaskSeq.concat
116+ |> verifyEmpty
117+
35118 [<Theory; ClassData( typeof< TestEmptyVariants>) >]
36- let ``TaskSeq - concat with top sequence empty `` variant =
119+ let ``TaskSeq - concat with empty source ( list ) `` variant =
37120 Gen.getEmptyVariant variant
38121 |> TaskSeq.box
39- |> TaskSeq.cast< IAsyncEnumerable < int>> // casting an int to an enumerable, LOL!
122+ |> TaskSeq.cast< int list > // task seq is empty so this should not raise
40123 |> TaskSeq.concat
41124 |> verifyEmpty
42125
126+ [<Theory; ClassData( typeof< TestEmptyVariants>) >]
127+ let ``TaskSeq - concat with empty source ( array ) `` variant =
128+ Gen.getEmptyVariant variant
129+ |> TaskSeq.box
130+ |> TaskSeq.cast< int[]> // task seq is empty so this should not raise
131+ |> TaskSeq.concat
132+ |> verifyEmpty
133+
134+ [<Theory; ClassData( typeof< TestEmptyVariants>) >]
135+ let ``TaskSeq - concat with empty source ( resizearray ) `` variant =
136+ Gen.getEmptyVariant variant
137+ |> TaskSeq.box
138+ |> TaskSeq.cast< ResizeArray< int>> // task seq is empty so this should not raise
139+ |> TaskSeq.concat
140+ |> verifyEmpty
141+
142+
43143module Immutable =
44144 [<Theory; ClassData( typeof< TestImmTaskSeq>) >]
45145 let ``TaskSeq - concat with three sequences of sequences`` variant =
46146 taskSeq {
47- yield Gen.getSeqImmutable variant // not yield-bang!
147+ yield Gen.getSeqImmutable variant
48148 yield Gen.getSeqImmutable variant
49149 yield Gen.getSeqImmutable variant
50150 }
@@ -55,7 +155,7 @@ module Immutable =
55155 let ``TaskSeq - concat with three sequences of sequences and few empties`` variant =
56156 taskSeq {
57157 yield TaskSeq.empty
58- yield Gen.getSeqImmutable variant // not yield-bang!
158+ yield Gen.getSeqImmutable variant
59159 yield TaskSeq.empty
60160 yield TaskSeq.empty
61161 yield Gen.getSeqImmutable variant
@@ -69,23 +169,100 @@ module Immutable =
69169 |> TaskSeq.concat
70170 |> validateSequence
71171
72- module SideEffect =
73172 [<Theory; ClassData( typeof< TestImmTaskSeq>) >]
74- let ``TaskSeq - concat consumes until the end , including side - effects`` variant =
173+ let ``TaskSeq - concat throws when one of inner task sequence is null`` variant =
174+ fun () ->
175+ taskSeq {
176+ yield Gen.getSeqImmutable variant
177+ yield TaskSeq.empty
178+ yield null
179+ }
180+ |> TaskSeq.concat
181+ |> consumeTaskSeq
182+ |> should throwAsyncExact typeof< NullReferenceException>
183+
184+ module SideEffect =
185+ [<Fact>]
186+ let ``TaskSeq - concat executes side effects of nested ( taskseq ) `` () =
75187 let mutable i = 0
76188
77189 taskSeq {
78- yield Gen.getSeqImmutable variant // not yield-bang!
79- yield Gen.getSeqImmutable variant
190+ yield Gen.getSeqImmutable SeqImmutable.ThreadSpinWait
191+ yield Gen.getSeqImmutable SeqImmutable.ThreadSpinWait
80192
81193 yield taskSeq {
82194 yield ! [ 1 .. 10 ]
83195 i <- i + 1
84196 }
85197 }
86198 |> TaskSeq.concat
87- |> validateSequence
88- |> Task.map ( fun () -> i |> should equal 1 )
199+ |> TaskSeq.last // consume
200+ |> Task.map ( fun _ -> i |> should equal 1 )
201+
202+ [<Fact>]
203+ let ``TaskSeq - concat executes side effects of nested ( seq ) `` () =
204+ let mutable i = 0
205+
206+ taskSeq {
207+ yield seq { 1 .. 10 }
208+ yield seq { 1 .. 10 }
209+
210+ yield seq {
211+ yield ! [ 1 .. 10 ]
212+ i <- i + 1
213+ }
214+ }
215+ |> TaskSeq.concat
216+ |> TaskSeq.last // consume
217+ |> Task.map ( fun _ -> i |> should equal 1 )
218+
219+ [<Fact>]
220+ let ``TaskSeq - concat executes side effects of nested ( array ) `` () =
221+ let mutable i = 0
222+
223+ taskSeq {
224+ yield [| 1 .. 10 |]
225+ yield [| 1 .. 10 |]
226+
227+ yield [| yield ! [ 1 .. 10 ]; i <- i + 1 |]
228+ }
229+ |> TaskSeq.concat
230+ |> TaskSeq.last // consume
231+ |> Task.map ( fun _ -> i |> should equal 1 )
232+
233+ [<Fact>]
234+ let ``TaskSeq - concat executes side effects of nested ( list ) `` () =
235+ let mutable i = 0
236+
237+ taskSeq {
238+ yield [ 1 .. 10 ]
239+ yield [ 1 .. 10 ]
240+
241+ yield [ yield ! [ 1 .. 10 ]; i <- i + 1 ]
242+ }
243+ |> TaskSeq.concat
244+ |> TaskSeq.last // consume
245+ |> Task.map ( fun _ -> i |> should equal 1 )
246+
247+ [<Fact>]
248+ let ``TaskSeq - concat executes side effects of nested ( resizearray ) `` () =
249+ let mutable i = 0
250+
251+ taskSeq {
252+ yield ResizeArray { 1 .. 10 }
253+ yield ResizeArray { 1 .. 10 }
254+
255+ yield
256+ ResizeArray(
257+ seq {
258+ yield ! [ 1 .. 10 ]
259+ i <- i + 1
260+ }
261+ )
262+ }
263+ |> TaskSeq.concat
264+ |> TaskSeq.last // consume
265+ |> Task.map ( fun _ -> i |> should equal 1 )
89266
90267 [<Theory; ClassData( typeof< TestImmTaskSeq>) >]
91268 let ``TaskSeq - concat consumes side effects in empty sequences`` variant =
0 commit comments