Skip to content

Commit 3cfecd3

Browse files
committed
Add/fix more tests, all tests are good now, some failing due to reading too far
1 parent 033731d commit 3cfecd3

File tree

1 file changed

+124
-48
lines changed

1 file changed

+124
-48
lines changed

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

Lines changed: 124 additions & 48 deletions
Original file line numberDiff line numberDiff line change
@@ -16,28 +16,14 @@ open FSharp.Control
1616

1717
[<AutoOpen>]
1818
module With =
19-
/// The only real difference in semantics between the base and the *Inclusive variant lies in whether the final item is returned.
20-
/// NOTE the semantics are very clear on only propagating a single failing item in the inclusive case.
19+
/// The only real difference in semantics between the base and the *Inclusive variant lies in whether the final item is skipped.
2120
let getFunction inclusive isAsync =
2221
match inclusive, isAsync with
2322
| false, false -> TaskSeq.skipWhile
2423
| false, true -> fun pred -> TaskSeq.skipWhileAsync (pred >> Task.fromResult)
2524
| true, false -> TaskSeq.skipWhileInclusive
2625
| true, true -> fun pred -> TaskSeq.skipWhileInclusiveAsync (pred >> Task.fromResult)
2726

28-
/// This is the base condition as one would expect in actual code
29-
let inline cond x = x <> 6
30-
31-
/// For each of the tests below, we add a guard that will trigger if the predicate is passed items known to be beyond the
32-
/// first failing item in the known sequence (which is 1..10)
33-
let inline condWithGuard x =
34-
let res = cond x
35-
36-
if x > 6 then
37-
failwith "Test sequence should not be enumerated beyond the first item failing the predicate"
38-
39-
res
40-
4127
module EmptySeq =
4228

4329
// TaskSeq-skipWhile+A stands for:
@@ -76,6 +62,12 @@ module Immutable =
7662

7763
[<Theory; ClassData(typeof<TestImmTaskSeq>)>]
7864
let ``TaskSeq-skipWhile+A filters correctly`` variant = task {
65+
// truth table for f(x) = x < 5
66+
// 1 2 3 4 5 6 7 8 9 10
67+
// T T T T F F F F F F (stops at first F)
68+
// x x x x _ _ _ _ _ _ (skips exclusive)
69+
// A B C D E F G H I J
70+
7971
do!
8072
Gen.getSeqImmutable variant
8173
|> TaskSeq.skipWhile ((>) 5) // skip while less than 5
@@ -102,15 +94,21 @@ module Immutable =
10294

10395
[<Theory; ClassData(typeof<TestImmTaskSeq>)>]
10496
let ``TaskSeq-skipWhileInclusive+A filters correctly`` variant = task {
97+
// truth table for f(x) = x < 5
98+
// 1 2 3 4 5 6 7 8 9 10
99+
// T T T T F F F F F F (stops at first F)
100+
// x x x x x _ _ _ _ _ (skips inclusively)
101+
// A B C D E F G H I J
102+
105103
do!
106104
Gen.getSeqImmutable variant
107105
|> TaskSeq.skipWhileInclusive ((>) 5)
108-
|> verifyDigitsAsString "GHIJ" // last 4
106+
|> verifyDigitsAsString "FGHIJ" // last 4
109107

110108
do!
111109
Gen.getSeqImmutable variant
112110
|> TaskSeq.skipWhileInclusiveAsync (fun x -> task { return x < 5 })
113-
|> verifyDigitsAsString "GHIJ"
111+
|> verifyDigitsAsString "FGHIJ"
114112
}
115113

116114

@@ -142,16 +140,42 @@ module Immutable =
142140

143141
module SideEffects =
144142
[<Theory; ClassData(typeof<TestSideEffectTaskSeq>)>]
145-
let ``TaskSeq-skipWhile filters correctly`` variant =
146-
Gen.getSeqWithSideEffect variant
147-
|> TaskSeq.skipWhile condWithGuard
148-
|> verifyDigitsAsString "ABCDE"
143+
let ``TaskSeq-skipWhile+A filters correctly`` variant = task {
144+
// truth table for f(x) = x < 6
145+
// 1 2 3 4 5 6 7 8 9 10
146+
// T T T T T F F F F F (stops at first F)
147+
// x x x x x _ _ _ _ _ (skips exclusively)
148+
// A B C D E F G H I J
149+
150+
do!
151+
Gen.getSeqWithSideEffect variant
152+
|> TaskSeq.skipWhile ((>) 6)
153+
|> verifyDigitsAsString "FGHIJ"
154+
155+
do!
156+
Gen.getSeqWithSideEffect variant
157+
|> TaskSeq.skipWhileAsync (fun x -> task { return x < 6 })
158+
|> verifyDigitsAsString "FGHIJ"
159+
}
149160

150161
[<Theory; ClassData(typeof<TestSideEffectTaskSeq>)>]
151-
let ``TaskSeq-skipWhileAsync filters correctly`` variant =
152-
Gen.getSeqWithSideEffect variant
153-
|> TaskSeq.skipWhileAsync (fun x -> task { return condWithGuard x })
154-
|> verifyDigitsAsString "ABCDE"
162+
let ``TaskSeq-skipWhileInclusive+A filters correctly`` variant = task {
163+
// truth table for f(x) = x < 6
164+
// 1 2 3 4 5 6 7 8 9 10
165+
// T T T T T F F F F F (stops at first F)
166+
// x x x x x x _ _ _ _ (skips inclusively)
167+
// A B C D E F G H I J
168+
169+
do!
170+
Gen.getSeqWithSideEffect variant
171+
|> TaskSeq.skipWhileInclusive ((>) 6)
172+
|> verifyDigitsAsString "GHIJ"
173+
174+
do!
175+
Gen.getSeqWithSideEffect variant
176+
|> TaskSeq.skipWhileInclusiveAsync (fun x -> task { return x < 6 })
177+
|> verifyDigitsAsString "GHIJ"
178+
}
155179

156180
[<Theory>]
157181
[<InlineData(false, false)>]
@@ -163,19 +187,23 @@ module SideEffects =
163187
let functionToTest = getFunction inclusive isAsync ((=) 42)
164188

165189
let items = taskSeq {
166-
yield x // Always passes the test; always returned
167-
yield x * 2 // the failing item (which will also be yielded in the result when using *Inclusive)
190+
yield x // Always passes the test; always skipped
191+
yield x * 2 // Fails the test, skipped depending on "inclusive"
168192
x <- x + 1 // we are proving we never get here
169193
}
170194

171-
let expected = if inclusive then [| 42; 84 |] else [| 42 |]
195+
// we skip one more if "inclusive"
196+
let expected = if inclusive then [||] else [| 84 |]
172197

198+
x |> should equal 42
173199
let! first = items |> functionToTest |> TaskSeq.toArrayAsync
200+
x |> should equal 42
174201
let! repeat = items |> functionToTest |> TaskSeq.toArrayAsync
202+
x |> should equal 42
175203

176204
first |> should equal expected
177205
repeat |> should equal expected
178-
x |> should equal 42
206+
x |> should equal 42 // if the var changed, we got too far
179207
}
180208

181209
[<Theory>]
@@ -195,9 +223,10 @@ module SideEffects =
195223
x <- x + 200 // as previously proven, we should not trigger this
196224
}
197225

198-
let expectedFirst = if inclusive then [| 42; 44 * 2 |] else [| 42 |]
199-
let expectedRepeat = if inclusive then [| 45; 47 * 2 |] else [| 45 |]
226+
let expectedFirst = if inclusive then [||] else [| 44 * 2 |]
227+
let expectedRepeat = if inclusive then [||] else [| 47 * 2 |]
200228

229+
x |> should equal 41
201230
let! first = items |> functionToTest |> TaskSeq.toArrayAsync
202231
x |> should equal 44
203232
let! repeat = items |> functionToTest |> TaskSeq.toArrayAsync
@@ -215,10 +244,11 @@ module SideEffects =
215244
TaskSeq.skipWhile (fun x -> x < 5) ts
216245
|> TaskSeq.toArrayAsync
217246

218-
let expected = [| 1..4 |]
247+
let expected = [| 5..10 |]
219248
first |> should equal expected
220249

221250
// side effect, reiterating causes it to resume from where we left it (minus the failing item)
251+
// which means the original sequence has now changed due to the side effect
222252
let! repeat =
223253
TaskSeq.skipWhile (fun x -> x < 5) ts
224254
|> TaskSeq.toArrayAsync
@@ -234,10 +264,11 @@ module SideEffects =
234264
TaskSeq.skipWhileInclusiveAsync (fun x -> task { return x < 5 }) ts
235265
|> TaskSeq.toArrayAsync
236266

237-
let expected = [| 1..5 |]
267+
let expected = [| 6..10 |]
238268
first |> should equal expected
239269

240270
// side effect, reiterating causes it to resume from where we left it (minus the failing item)
271+
// which means the original sequence has now changed due to the side effect
241272
let! repeat =
242273
TaskSeq.skipWhileInclusiveAsync (fun x -> task { return x < 5 }) ts
243274
|> TaskSeq.toArrayAsync
@@ -251,26 +282,71 @@ module Other =
251282
[<InlineData(false, true)>]
252283
[<InlineData(true, false)>]
253284
[<InlineData(true, true)>]
254-
let ``TaskSeq-skipWhileXXX exclude all items after predicate fails`` (inclusive, isAsync) =
255-
let functionToTest = With.getFunction inclusive isAsync
285+
let ``TaskSeq-skipWhileXXX should include all items after predicate fails`` (inclusive, isAsync) = task {
286+
do!
287+
[ 1; 2; 2; 3; 3; 2; 1 ]
288+
|> TaskSeq.ofSeq
289+
|> TaskSeq.skipWhile (fun x -> x <= 2)
290+
|> verifyDigitsAsString "CCBA"
291+
292+
do!
293+
[ 1; 2; 2; 3; 3; 2; 1 ]
294+
|> TaskSeq.ofSeq
295+
|> TaskSeq.skipWhileInclusive (fun x -> x <= 2)
296+
|> verifyDigitsAsString "CBA"
297+
298+
do!
299+
[ 1; 2; 2; 3; 3; 2; 1 ]
300+
|> TaskSeq.ofSeq
301+
|> TaskSeq.skipWhileAsync (fun x -> Task.fromResult (x <= 2))
302+
|> verifyDigitsAsString "CCBA"
256303

257-
[ 1; 2; 2; 3; 3; 2; 1 ]
258-
|> TaskSeq.ofSeq
259-
|> functionToTest (fun x -> x <= 2)
260-
|> verifyDigitsAsString (if inclusive then "ABBC" else "ABB")
304+
do!
305+
[ 1; 2; 2; 3; 3; 2; 1 ]
306+
|> TaskSeq.ofSeq
307+
|> TaskSeq.skipWhileInclusiveAsync (fun x -> Task.fromResult (x <= 2))
308+
|> verifyDigitsAsString "CBA"
309+
}
261310

262311
[<Theory>]
263312
[<InlineData(false, false)>]
264313
[<InlineData(false, true)>]
265314
[<InlineData(true, false)>]
266315
[<InlineData(true, true)>]
267-
let ``TaskSeq-skipWhileXXX stops consuming after predicate fails`` (inclusive, isAsync) =
268-
let functionToTest = With.getFunction inclusive isAsync
316+
let ``TaskSeq-skipWhileXXX stops consuming after predicate fails`` (inclusive, isAsync) = task {
317+
do!
318+
seq {
319+
yield! [ 1; 2; 2; 3; 3 ]
320+
yield failwith "Too far"
321+
}
322+
|> TaskSeq.ofSeq
323+
|> TaskSeq.skipWhile (fun x -> x <= 2)
324+
|> verifyDigitsAsString "CC"
269325

270-
seq {
271-
yield! [ 1; 2; 2; 3; 3 ]
272-
yield failwith "Too far"
273-
}
274-
|> TaskSeq.ofSeq
275-
|> functionToTest (fun x -> x <= 2)
276-
|> verifyDigitsAsString (if inclusive then "ABBC" else "ABB")
326+
do!
327+
seq {
328+
yield! [ 1; 2; 2; 3; 3 ]
329+
yield failwith "Too far"
330+
}
331+
|> TaskSeq.ofSeq
332+
|> TaskSeq.skipWhileInclusive (fun x -> x <= 2)
333+
|> verifyDigitsAsString "C"
334+
335+
do!
336+
seq {
337+
yield! [ 1; 2; 2; 3; 3 ]
338+
yield failwith "Too far"
339+
}
340+
|> TaskSeq.ofSeq
341+
|> TaskSeq.skipWhileAsync (fun x -> Task.fromResult (x <= 2))
342+
|> verifyDigitsAsString "CC"
343+
344+
do!
345+
seq {
346+
yield! [ 1; 2; 2; 3; 3 ]
347+
yield failwith "Too far"
348+
}
349+
|> TaskSeq.ofSeq
350+
|> TaskSeq.skipWhileInclusiveAsync (fun x -> Task.fromResult (x <= 2))
351+
|> verifyDigitsAsString "C"
352+
}

0 commit comments

Comments
 (0)