-
Notifications
You must be signed in to change notification settings - Fork 11
Expand file tree
/
Copy pathTaskSeq.DistinctUntilChanged.Tests.fs
More file actions
134 lines (107 loc) · 4.01 KB
/
TaskSeq.DistinctUntilChanged.Tests.fs
File metadata and controls
134 lines (107 loc) · 4.01 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
module TaskSeq.Tests.DistinctUntilChanged
open Xunit
open FsUnit.Xunit
open FSharp.Control
//
// TaskSeq.distinctUntilChanged
//
module EmptySeq =
[<Fact>]
let ``TaskSeq-distinctUntilChanged with null source raises`` () = assertNullArg <| fun () -> TaskSeq.distinctUntilChanged null
[<Theory; ClassData(typeof<TestEmptyVariants>)>]
let ``TaskSeq-distinctUntilChanged has no effect`` variant = task {
do!
Gen.getEmptyVariant variant
|> TaskSeq.distinctUntilChanged
|> TaskSeq.toListAsync
|> Task.map (List.isEmpty >> should be True)
}
module Functionality =
[<Fact>]
let ``TaskSeq-distinctUntilChanged should return no consecutive duplicates`` () = task {
let ts =
[ 'A'; 'A'; 'B'; 'Z'; 'C'; 'C'; 'Z'; 'C'; 'D'; 'D'; 'D'; 'Z' ]
|> TaskSeq.ofList
let! xs = ts |> TaskSeq.distinctUntilChanged |> TaskSeq.toListAsync
xs
|> List.map string
|> String.concat ""
|> should equal "ABZCZCDZ"
}
[<Fact>]
let ``TaskSeq-distinctUntilChanged with single element returns singleton`` () = task {
let! xs =
taskSeq { yield 42 }
|> TaskSeq.distinctUntilChanged
|> TaskSeq.toListAsync
xs |> should equal [ 42 ]
}
[<Fact>]
let ``TaskSeq-distinctUntilChanged with all identical elements returns one element`` () = task {
let! xs =
taskSeq { yield! [ 7; 7; 7; 7; 7 ] }
|> TaskSeq.distinctUntilChanged
|> TaskSeq.toListAsync
xs |> should equal [ 7 ]
}
[<Fact>]
let ``TaskSeq-distinctUntilChanged with all distinct elements returns all`` () = task {
let! xs =
taskSeq { yield! [ 1; 2; 3; 4; 5 ] }
|> TaskSeq.distinctUntilChanged
|> TaskSeq.toListAsync
xs |> should equal [ 1; 2; 3; 4; 5 ]
}
[<Fact>]
let ``TaskSeq-distinctUntilChanged with alternating pairs`` () = task {
// [A;A;B;B;A;A] -> [A;B;A]
let! xs =
taskSeq { yield! [ 'A'; 'A'; 'B'; 'B'; 'A'; 'A' ] }
|> TaskSeq.distinctUntilChanged
|> TaskSeq.toListAsync
xs |> should equal [ 'A'; 'B'; 'A' ]
}
[<Theory; ClassData(typeof<TestImmTaskSeq>)>]
let ``TaskSeq-distinctUntilChanged on immutable all-unique seq preserves all elements`` variant = task {
// getSeqImmutable yields 1..10, all unique, so all are returned
let! xs =
Gen.getSeqImmutable variant
|> TaskSeq.distinctUntilChanged
|> TaskSeq.toListAsync
xs |> should equal [ 1..10 ]
}
module SideEffects =
[<Fact>]
let ``TaskSeq-distinctUntilChanged consumes every element exactly once`` () = task {
let mutable count = 0
let ts = taskSeq {
for i in 1..6 do
count <- count + 1
yield i % 3 // yields 1,2,0,1,2,0 — no consecutive duplicates
}
let! xs = ts |> TaskSeq.distinctUntilChanged |> TaskSeq.toListAsync
count |> should equal 6
xs |> should equal [ 1; 2; 0; 1; 2; 0 ]
}
[<Fact>]
let ``TaskSeq-distinctUntilChanged skips duplicates without extra evaluation`` () = task {
let mutable count = 0
let ts = taskSeq {
for i in [ 1; 1; 2; 2; 3 ] do
count <- count + 1
yield i
}
let! xs = ts |> TaskSeq.distinctUntilChanged |> TaskSeq.toListAsync
// All 5 source elements must still be consumed
count |> should equal 5
xs |> should equal [ 1; 2; 3 ]
}
[<Theory; ClassData(typeof<TestSideEffectTaskSeq>)>]
let ``TaskSeq-distinctUntilChanged on side-effect seq preserves all unique elements`` variant = task {
// getSeqWithSideEffect yields 1..10 (all unique on first iteration)
let! xs =
Gen.getSeqWithSideEffect variant
|> TaskSeq.distinctUntilChanged
|> TaskSeq.toListAsync
xs |> should equal [ 1..10 ]
}