@@ -39,6 +39,181 @@ module EmptySeq =
3939 alphabet |> should equal '_'
4040 }
4141
42+ [<Theory; ClassData( typeof< TestEmptyVariants>) >]
43+ let ``TaskSeq - fold does not call folder function when empty`` variant = task {
44+ let mutable called = false
45+
46+ let! _ =
47+ Gen.getEmptyVariant variant
48+ |> TaskSeq.fold
49+ ( fun state _ ->
50+ called <- true
51+ state)
52+ 0
53+
54+ called |> should be False
55+ }
56+
57+ [<Theory; ClassData( typeof< TestEmptyVariants>) >]
58+ let ``TaskSeq - foldAsync does not call folder function when empty`` variant = task {
59+ let mutable called = false
60+
61+ let! _ =
62+ Gen.getEmptyVariant variant
63+ |> TaskSeq.foldAsync
64+ ( fun state _ -> task {
65+ called <- true
66+ return state
67+ })
68+ 0
69+
70+ called |> should be False
71+ }
72+
73+ module Functionality =
74+ [<Fact>]
75+ let ``TaskSeq - fold calls folder exactly N times for N elements`` () = task {
76+ let mutable callCount = 0
77+
78+ let! _ =
79+ TaskSeq.ofList [ 1 ; 2 ; 3 ; 4 ; 5 ]
80+ |> TaskSeq.fold
81+ ( fun acc item ->
82+ callCount <- callCount + 1
83+ acc + item)
84+ 0
85+
86+ callCount |> should equal 5
87+ }
88+
89+ [<Fact>]
90+ let ``TaskSeq - foldAsync calls folder exactly N times for N elements`` () = task {
91+ let mutable callCount = 0
92+
93+ let! _ =
94+ TaskSeq.ofList [ 1 ; 2 ; 3 ; 4 ; 5 ]
95+ |> TaskSeq.foldAsync
96+ ( fun acc item -> task {
97+ callCount <- callCount + 1
98+ return acc + item
99+ })
100+ 0
101+
102+ callCount |> should equal 5
103+ }
104+
105+ [<Fact>]
106+ let ``TaskSeq - fold over singleton calls folder once`` () = task {
107+ let mutable callCount = 0
108+
109+ let! result =
110+ TaskSeq.singleton 42
111+ |> TaskSeq.fold
112+ ( fun acc item ->
113+ callCount <- callCount + 1
114+ acc + item)
115+ 0
116+
117+ result |> should equal 42
118+ callCount |> should equal 1
119+ }
120+
121+ [<Fact>]
122+ let ``TaskSeq - fold over two elements calls folder twice`` () = task {
123+ let mutable callCount = 0
124+
125+ let! result =
126+ taskSeq {
127+ yield 10
128+ yield 20
129+ }
130+ |> TaskSeq.fold
131+ ( fun acc item ->
132+ callCount <- callCount + 1
133+ acc + item)
134+ 0
135+
136+ result |> should equal 30
137+ callCount |> should equal 2
138+ }
139+
140+ [<Fact>]
141+ let ``TaskSeq - fold is left - associative : applies folder left - to - right`` () = task {
142+ // For non-commutative ops like string concat, order matters.
143+ // fold f s [a;b;c] = f (f (f s a) b) c
144+ let! result =
145+ TaskSeq.ofList [ " b" ; " c" ; " d" ]
146+ |> TaskSeq.fold ( fun acc item -> acc + item) " a"
147+
148+ result |> should equal " abcd"
149+ }
150+
151+ [<Fact>]
152+ let ``TaskSeq - foldAsync is left - associative : applies folder left - to - right`` () = task {
153+ let! result =
154+ TaskSeq.ofList [ " b" ; " c" ; " d" ]
155+ |> TaskSeq.foldAsync ( fun acc item -> task { return acc + item }) " a"
156+
157+ result |> should equal " abcd"
158+ }
159+
160+ [<Fact>]
161+ let ``TaskSeq - fold with null initial state works for reference types`` () = task {
162+ let! result =
163+ TaskSeq.ofList [ " hello" ; " " ; " world" ]
164+ |> TaskSeq.fold
165+ ( fun acc item ->
166+ match acc with
167+ | null -> item
168+ | _ -> acc + item)
169+ null
170+
171+ result |> should equal " hello world"
172+ }
173+
174+ [<Fact>]
175+ let ``TaskSeq - foldAsync and fold return the same result for pure functions`` () = task {
176+ let input = [ 1 .. 10 ]
177+
178+ let! syncResult =
179+ TaskSeq.ofList input
180+ |> TaskSeq.fold ( fun acc item -> acc + item) 0
181+
182+ let! asyncResult =
183+ TaskSeq.ofList input
184+ |> TaskSeq.foldAsync ( fun acc item -> task { return acc + item }) 0
185+
186+ syncResult |> should equal asyncResult
187+ }
188+
189+ [<Fact>]
190+ let ``TaskSeq - fold accumulates a list in correct order`` () = task {
191+ let! result =
192+ TaskSeq.ofList [ 1 ; 2 ; 3 ; 4 ; 5 ]
193+ |> TaskSeq.fold ( fun acc item -> acc @ [ item ]) []
194+
195+ result |> should equal [ 1 ; 2 ; 3 ; 4 ; 5 ]
196+ }
197+
198+ [<Theory; ClassData( typeof< TestImmTaskSeq>) >]
199+ let ``TaskSeq - fold sum over immutable variants`` variant = task {
200+ // items are 1..10; sum = 55
201+ let! result =
202+ Gen.getSeqImmutable variant
203+ |> TaskSeq.fold ( fun acc item -> acc + item) 0
204+
205+ result |> should equal 55
206+ }
207+
208+ [<Theory; ClassData( typeof< TestImmTaskSeq>) >]
209+ let ``TaskSeq - foldAsync sum over immutable variants`` variant = task {
210+ let! result =
211+ Gen.getSeqImmutable variant
212+ |> TaskSeq.foldAsync ( fun acc item -> task { return acc + item }) 0
213+
214+ result |> should equal 55
215+ }
216+
42217module Immutable =
43218 [<Theory; ClassData( typeof< TestImmTaskSeq>) >]
44219 let ``TaskSeq - fold folds with every item`` variant = task {
0 commit comments