1
- module TaskSeq.Tests.Exists
1
+ module TaskSeq.Tests.Forall
2
2
3
3
open Xunit
4
4
open FsUnit.Xunit
5
5
6
6
open FSharp.Control
7
7
8
8
//
9
- // TaskSeq.exists
10
- // TaskSeq.existsAsyncc
9
+ // TaskSeq.forall
10
+ // TaskSeq.forallAsyncc
11
11
//
12
12
13
13
module EmptySeq =
14
14
[<Fact>]
15
15
let ``Null source is invalid`` () =
16
16
assertNullArg
17
- <| fun () -> TaskSeq.exists ( fun _ -> false ) null
17
+ <| fun () -> TaskSeq.forall ( fun _ -> false ) null
18
18
19
19
assertNullArg
20
- <| fun () -> TaskSeq.existsAsync ( fun _ -> Task.fromResult false ) null
20
+ <| fun () -> TaskSeq.forallAsync ( fun _ -> Task.fromResult false ) null
21
21
22
22
[<Theory; ClassData( typeof< TestEmptyVariants>) >]
23
- let ``TaskSeq - exists returns false `` variant =
23
+ let ``TaskSeq - forall always returns true `` variant =
24
24
Gen.getEmptyVariant variant
25
- |> TaskSeq.exists ((=) 12 )
26
- |> Task.map ( should be False )
25
+ |> TaskSeq.forall ((=) 12 )
26
+ |> Task.map ( should be True )
27
27
28
28
[<Theory; ClassData( typeof< TestEmptyVariants>) >]
29
- let ``TaskSeq - existsAsync returns false `` variant =
29
+ let ``TaskSeq - forallAsync always returns true `` variant =
30
30
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 })
57
32
|> Task.map ( should be True)
58
33
34
+ module Immutable =
59
35
[<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
+ }
64
47
65
48
[<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
+ }
70
60
71
61
[<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 =
73
63
Gen.getSeqImmutable variant
74
- |> TaskSeq.exists ((=) 10 )
64
+ |> TaskSeq.forall ( fun x -> x < 6 || x > 5 )
75
65
|> Task.map ( should be True)
76
66
77
67
[<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 =
79
69
Gen.getSeqImmutable variant
80
- |> TaskSeq.existsAsync ( fun x -> task { return x = 10 })
70
+ |> TaskSeq.forallAsync ( fun x -> task { return x < = 10 && x >= 0 })
81
71
|> Task.map ( should be True)
82
72
83
73
module SideEffects =
84
74
[<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 {
86
76
let ts = Gen.getSeqWithSideEffect variant
87
- let finder = (=) 11
77
+ let predicate x = x > 10
88
78
89
79
// 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
92
85
93
86
// find again: found now, because of side effects
94
- let! found = TaskSeq.exists finder ts
87
+ let! found = TaskSeq.forall predicate ts
95
88
found |> should be True
96
89
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
100
94
}
101
95
102
96
[<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 {
104
98
let ts = Gen.getSeqWithSideEffect variant
105
- let finder x = task { return x = 11 }
99
+ let predicate x = Task.fromResult ( x > 10 )
106
100
107
101
// 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
110
107
111
108
// find again: found now, because of side effects
112
- let! found = TaskSeq.existsAsync finder ts
109
+ let! found = TaskSeq.forallAsync predicate ts
113
110
found |> should be True
114
111
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
118
116
}
119
117
120
118
[<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 {
122
120
let mutable i = 0
123
121
124
122
let ts = taskSeq {
@@ -127,18 +125,18 @@ module SideEffects =
127
125
yield i
128
126
}
129
127
130
- let! found = ts |> TaskSeq.exists ((= ) 3 )
131
- found |> should be True
128
+ let! found = ts |> TaskSeq.forall ((> ) 3 )
129
+ found |> should be False
132
130
i |> should equal 3 // only partial evaluation!
133
131
134
132
// 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 )
136
134
found |> should be True
137
- i |> should equal 4 // only partial evaluation!
135
+ i |> should equal 13 // we evaluated to the end
138
136
}
139
137
140
138
[<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 {
142
140
let mutable i = 0
143
141
144
142
let ts = taskSeq {
@@ -147,48 +145,22 @@ module SideEffects =
147
145
yield i
148
146
}
149
147
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
152
150
i |> should equal 3 // only partial evaluation!
153
151
154
152
// 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 ))
159
156
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 )
171
157
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
173
159
}
174
160
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
- }
189
161
190
162
[<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 {
192
164
let mutable i = 0
193
165
194
166
let ts = taskSeq {
@@ -197,18 +169,18 @@ module SideEffects =
197
169
i <- i + 1
198
170
}
199
171
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
203
175
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
207
179
i |> should equal 4 // only partial evaluation!
208
180
}
209
181
210
182
[<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 {
212
184
let mutable i = 0
213
185
214
186
let ts = taskSeq {
@@ -217,12 +189,12 @@ module SideEffects =
217
189
i <- i + 1
218
190
}
219
191
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
223
195
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
227
199
i |> should equal 4 // only partial evaluation!
228
200
}
0 commit comments