1- module TaskSeq.Tests.Exists
1+ module TaskSeq.Tests.Forall
22
33open Xunit
44open FsUnit.Xunit
55
66open FSharp.Control
77
88//
9- // TaskSeq.exists
10- // TaskSeq.existsAsyncc
9+ // TaskSeq.forall
10+ // TaskSeq.forallAsyncc
1111//
1212
1313module EmptySeq =
1414 [<Fact>]
1515 let ``Null source is invalid`` () =
1616 assertNullArg
17- <| fun () -> TaskSeq.exists ( fun _ -> false ) null
17+ <| fun () -> TaskSeq.forall ( fun _ -> false ) null
1818
1919 assertNullArg
20- <| fun () -> TaskSeq.existsAsync ( fun _ -> Task.fromResult false ) null
20+ <| fun () -> TaskSeq.forallAsync ( fun _ -> Task.fromResult false ) null
2121
2222 [<Theory; ClassData( typeof< TestEmptyVariants>) >]
23- let ``TaskSeq - exists returns false `` variant =
23+ let ``TaskSeq - forall always returns true `` variant =
2424 Gen.getEmptyVariant variant
25- |> TaskSeq.exists ((=) 12 )
26- |> Task.map ( should be False )
25+ |> TaskSeq.forall ((=) 12 )
26+ |> Task.map ( should be True )
2727
2828 [<Theory; ClassData( typeof< TestEmptyVariants>) >]
29- let ``TaskSeq - existsAsync returns false `` variant =
29+ let ``TaskSeq - forallAsync always returns true `` variant =
3030 Gen.getEmptyVariant variant
31- |> TaskSeq.existsAsync ( fun x -> task { return x = 12 })
32- |> Task.map ( should be False)
33-
34- module Immutable =
35- [<Theory; ClassData( typeof< TestImmTaskSeq>) >]
36- let ``TaskSeq - exists sad path returns false`` variant =
37- Gen.getSeqImmutable variant
38- |> TaskSeq.exists ((=) 0 )
39- |> Task.map ( should be False)
40-
41- [<Theory; ClassData( typeof< TestImmTaskSeq>) >]
42- let ``TaskSeq - existsAsync sad path return false`` variant =
43- Gen.getSeqImmutable variant
44- |> TaskSeq.existsAsync ( fun x -> task { return x = 0 })
45- |> Task.map ( should be False)
46-
47- [<Theory; ClassData( typeof< TestImmTaskSeq>) >]
48- let ``TaskSeq - exists happy path middle of seq`` variant =
49- Gen.getSeqImmutable variant
50- |> TaskSeq.exists ( fun x -> x < 6 && x > 4 )
51- |> Task.map ( should be True)
52-
53- [<Theory; ClassData( typeof< TestImmTaskSeq>) >]
54- let ``TaskSeq - existsAsync happy path middle of seq`` variant =
55- Gen.getSeqImmutable variant
56- |> TaskSeq.existsAsync ( fun x -> task { return x < 6 && x > 4 })
31+ |> TaskSeq.forallAsync ( fun x -> task { return x = 12 })
5732 |> Task.map ( should be True)
5833
34+ module Immutable =
5935 [<Theory; ClassData( typeof< TestImmTaskSeq>) >]
60- let ``TaskSeq - exists happy path first item of seq`` variant =
61- Gen.getSeqImmutable variant
62- |> TaskSeq.exists ((=) 1 )
63- |> Task.map ( should be True)
36+ let ``TaskSeq - forall sad path returns false`` variant = task {
37+ do !
38+ Gen.getSeqImmutable variant
39+ |> TaskSeq.forall ((=) 0 )
40+ |> Task.map ( should be False)
41+
42+ do !
43+ Gen.getSeqImmutable variant
44+ |> TaskSeq.forall ((>) 9 ) // lt
45+ |> Task.map ( should be False)
46+ }
6447
6548 [<Theory; ClassData( typeof< TestImmTaskSeq>) >]
66- let ``TaskSeq - existsAsync happy path first item of seq`` variant =
67- Gen.getSeqImmutable variant
68- |> TaskSeq.existsAsync ( fun x -> task { return x = 1 })
69- |> Task.map ( should be True)
49+ let ``TaskSeq - forallAsync sad path returns false`` variant = task {
50+ do !
51+ Gen.getSeqImmutable variant
52+ |> TaskSeq.forallAsync ( fun x -> task { return x = 0 })
53+ |> Task.map ( should be False)
54+
55+ do !
56+ Gen.getSeqImmutable variant
57+ |> TaskSeq.forallAsync ( fun x -> task { return x < 9 })
58+ |> Task.map ( should be False)
59+ }
7060
7161 [<Theory; ClassData( typeof< TestImmTaskSeq>) >]
72- let ``TaskSeq - exists happy path last item of seq`` variant =
62+ let ``TaskSeq - forall happy path whole seq true `` variant =
7363 Gen.getSeqImmutable variant
74- |> TaskSeq.exists ((=) 10 )
64+ |> TaskSeq.forall ( fun x -> x < 6 || x > 5 )
7565 |> Task.map ( should be True)
7666
7767 [<Theory; ClassData( typeof< TestImmTaskSeq>) >]
78- let ``TaskSeq - existsAsync happy path last item of seq`` variant =
68+ let ``TaskSeq - forallAsync happy path whole seq true `` variant =
7969 Gen.getSeqImmutable variant
80- |> TaskSeq.existsAsync ( fun x -> task { return x = 10 })
70+ |> TaskSeq.forallAsync ( fun x -> task { return x < = 10 && x >= 0 })
8171 |> Task.map ( should be True)
8272
8373module SideEffects =
8474 [<Theory; ClassData( typeof< TestSideEffectTaskSeq>) >]
85- let ``TaskSeq - exists KeyNotFoundException only sometimes for mutated state `` variant = task {
75+ let ``TaskSeq - forall mutated state can change result `` variant = task {
8676 let ts = Gen.getSeqWithSideEffect variant
87- let finder = (=) 11
77+ let predicate x = x > 10
8878
8979 // first: false
90- let! found = TaskSeq.exists finder ts
91- found |> should be False
80+ let! found = TaskSeq.forall predicate ts
81+ found |> should be False // fails on first item, not many side effects yet
82+
83+ // ensure side effects executes
84+ do ! consumeTaskSeq ts
9285
9386 // find again: found now, because of side effects
94- let! found = TaskSeq.exists finder ts
87+ let! found = TaskSeq.forall predicate ts
9588 found |> should be True
9689
97- // find once more: false
98- let! found = TaskSeq.exists finder ts
99- found |> should be False
90+ // find once more, still true, as numbers increase
91+ do ! consumeTaskSeq ts // ensure side effects executes
92+ let! found = TaskSeq.forall predicate ts
93+ found |> should be True
10094 }
10195
10296 [<Theory; ClassData( typeof< TestSideEffectTaskSeq>) >]
103- let ``TaskSeq - existsAsync KeyNotFoundException only sometimes for mutated state `` variant = task {
97+ let ``TaskSeq - forallAsync mutated state can change result `` variant = task {
10498 let ts = Gen.getSeqWithSideEffect variant
105- let finder x = task { return x = 11 }
99+ let predicate x = Task.fromResult ( x > 10 )
106100
107101 // first: false
108- let! found = TaskSeq.existsAsync finder ts
109- found |> should be False
102+ let! found = TaskSeq.forallAsync predicate ts
103+ found |> should be False // fails on first item, not many side effects yet
104+
105+ // ensure side effects executes
106+ do ! consumeTaskSeq ts
110107
111108 // find again: found now, because of side effects
112- let! found = TaskSeq.existsAsync finder ts
109+ let! found = TaskSeq.forallAsync predicate ts
113110 found |> should be True
114111
115- // find once more: false
116- let! found = TaskSeq.existsAsync finder ts
117- found |> should be False
112+ // find once more, still true, as numbers increase
113+ do ! consumeTaskSeq ts // ensure side effects executes
114+ let! found = TaskSeq.forallAsync predicate ts
115+ found |> should be True
118116 }
119117
120118 [<Fact>]
121- let ``TaskSeq - exists _specialcase_ prove we don't read past the found item`` () = task {
119+ let ``TaskSeq - forall _specialcase_ prove we don't read past the first failing item`` () = task {
122120 let mutable i = 0
123121
124122 let ts = taskSeq {
@@ -127,18 +125,18 @@ module SideEffects =
127125 yield i
128126 }
129127
130- let! found = ts |> TaskSeq.exists ((= ) 3 )
131- found |> should be True
128+ let! found = ts |> TaskSeq.forall ((> ) 3 )
129+ found |> should be False
132130 i |> should equal 3 // only partial evaluation!
133131
134132 // find next item. We do get a new iterator, but mutable state is now starting at '3', so first item now returned is '4'.
135- let! found = ts |> TaskSeq.exists ((=) 4 )
133+ let! found = ts |> TaskSeq.forall ((< =) 4 )
136134 found |> should be True
137- i |> should equal 4 // only partial evaluation!
135+ i |> should equal 13 // we evaluated to the end
138136 }
139137
140138 [<Fact>]
141- let ``TaskSeq - existsAsync _specialcase_ prove we don't read past the found item`` () = task {
139+ let ``TaskSeq - forallAsync _specialcase_ prove we don't read past the first failing item`` () = task {
142140 let mutable i = 0
143141
144142 let ts = taskSeq {
@@ -147,48 +145,22 @@ module SideEffects =
147145 yield i
148146 }
149147
150- let! found = ts |> TaskSeq.existsAsync ( fun x -> task { return x = 3 } )
151- found |> should be True
148+ let! found = ts |> TaskSeq.forallAsync ( fun x -> Task.fromResult ( x < 3 ) )
149+ found |> should be False
152150 i |> should equal 3 // only partial evaluation!
153151
154152 // find next item. We do get a new iterator, but mutable state is now starting at '3', so first item now returned is '4'.
155- let! found = ts |> TaskSeq.existsAsync ( fun x -> task { return x = 4 })
156- found |> should be True
157- i |> should equal 4
158- }
153+ let! found =
154+ ts
155+ |> TaskSeq.forallAsync ( fun x -> Task.fromResult ( x >= 4 ))
159156
160- [<Fact>]
161- let ``TaskSeq - exists _specialcase_ prove we don't read past the found item v2`` () = task {
162- let mutable i = 0
163-
164- let ts = taskSeq {
165- yield 42
166- i <- i + 1
167- i <- i + 1
168- }
169-
170- let! found = ts |> TaskSeq.exists ((=) 42 )
171157 found |> should be True
172- i |> should equal 0 // because no MoveNext after found item, the last statements are not executed
158+ i |> should equal 13 // we evaluated to the end
173159 }
174160
175- [<Fact>]
176- let ``TaskSeq - existsAsync _specialcase_ prove we don't read past the found item v2`` () = task {
177- let mutable i = 0
178-
179- let ts = taskSeq {
180- yield 42
181- i <- i + 1
182- i <- i + 1
183- }
184-
185- let! found = ts |> TaskSeq.existsAsync ( fun x -> task { return x = 42 })
186- found |> should be True
187- i |> should equal 0 // because no MoveNext after found item, the last statements are not executed
188- }
189161
190162 [<Fact>]
191- let ``TaskSeq - exists _specialcase_ prove statement after yield is not evaluated`` () = task {
163+ let ``TaskSeq - forall _specialcase_ prove statement after first false result is not evaluated`` () = task {
192164 let mutable i = 0
193165
194166 let ts = taskSeq {
@@ -197,18 +169,18 @@ module SideEffects =
197169 i <- i + 1
198170 }
199171
200- let! found = ts |> TaskSeq.exists ((= ) 0 )
201- found |> should be True
202- i |> should equal 0 // notice that it should be one higher if the statement after 'yield' is evaluated
172+ let! found = ts |> TaskSeq.forall ((> ) 0 )
173+ found |> should be False
174+ i |> should equal 0 // notice that it should be one higher if the statement after 'yield' was evaluated
203175
204- // find some next item. We do get a new iterator, but mutable state is now starting at '1 '
205- let! found = ts |> TaskSeq.exists ((= ) 4 )
206- found |> should be True
176+ // find some next item. We do get a new iterator, but mutable state is still starting at '0 '
177+ let! found = ts |> TaskSeq.forall ((> ) 4 )
178+ found |> should be False
207179 i |> should equal 4 // only partial evaluation!
208180 }
209181
210182 [<Fact>]
211- let ``TaskSeq - existsAsync _specialcase_ prove statement after yield is not evaluated`` () = task {
183+ let ``TaskSeq - forallAsync _specialcase_ prove statement after first false result is not evaluated`` () = task {
212184 let mutable i = 0
213185
214186 let ts = taskSeq {
@@ -217,12 +189,12 @@ module SideEffects =
217189 i <- i + 1
218190 }
219191
220- let! found = ts |> TaskSeq.existsAsync ( fun x -> task { return x = 0 } )
221- found |> should be True
222- i |> should equal 0 // notice that it should be one higher if the statement after 'yield' is evaluated
192+ let! found = ts |> TaskSeq.forallAsync ( fun x -> Task.fromResult ( x < 0 ) )
193+ found |> should be False
194+ i |> should equal 0 // notice that it should be one higher if the statement after 'yield' was evaluated
223195
224- // find some next item. We do get a new iterator, but mutable state is now starting at '1 '
225- let! found = ts |> TaskSeq.existsAsync ( fun x -> task { return x = 4 } )
226- found |> should be True
196+ // find some next item. We do get a new iterator, but mutable state is still starting at '0 '
197+ let! found = ts |> TaskSeq.forallAsync ( fun x -> Task.fromResult ( x < 4 ) )
198+ found |> should be False
227199 i |> should equal 4 // only partial evaluation!
228200 }
0 commit comments