aboutsummaryrefslogtreecommitdiff
path: root/pipeline/stage_test.go
diff options
context:
space:
mode:
authorsangtran <tranquangsang12.7@gmail.com>2026-09-03 23:10:33 +0700
committersangtran <tranquangsang12.7@gmail.com>2026-09-03 23:10:33 +0700
commit02123df8cc15896f97c1580e49d8e2a991e37ddd (patch)
treed0c00bc3f65e5f5493a9dff8034c80640cb12960 /pipeline/stage_test.go
signatureVerified sangtran <tranquangsang12.7@gmail.com> Key: 8DD79823D235E1BB ultimate trust
downloadquacker-main.tar.gz
quacker-main.zip
Verified Moving all legacy quacker source code from github to cgitHEADmain
Diffstat (limited to 'pipeline/stage_test.go')
-rw-r--r--pipeline/stage_test.go308
1 files changed, 308 insertions, 0 deletions
diff --git a/pipeline/stage_test.go b/pipeline/stage_test.go
new file mode 100644
index 0000000..4579158
--- /dev/null
+++ b/pipeline/stage_test.go
@@ -0,0 +1,308 @@
1package pipeline
2
3import (
4 "context"
5 "sort"
6 "sync"
7 "sync/atomic"
8 "testing"
9)
10
11func TestMap_Basic(t *testing.T) {
12 t.Parallel()
13
14 input := make(chan int, 3)
15 input <- 1
16 input <- 2
17 input <- 3
18 close(input)
19
20 out := Map(1, func(_ context.Context, v int) (int, bool) {
21 return v * 10, true
22 })(t.Context(), input)
23
24 var got []int
25 for v := range out {
26 got = append(got, v)
27 }
28
29 sort.Ints(got)
30 if len(got) != 3 || got[0] != 10 || got[1] != 20 || got[2] != 30 {
31 t.Fatalf("expected [10 20 30], got %v", got)
32 }
33}
34
35func TestMap_Concurrent(t *testing.T) {
36 t.Parallel()
37
38 input := make(chan int, 100)
39 for i := range 100 {
40 input <- i
41 }
42 close(input)
43
44 out := Map(5, func(_ context.Context, v int) (int, bool) {
45 return v, true
46 })(t.Context(), input)
47
48 var got []int
49 for v := range out {
50 got = append(got, v)
51 }
52
53 if len(got) != 100 {
54 t.Fatalf("expected 100 items, got %d", len(got))
55 }
56
57 sort.Ints(got)
58 for i, v := range got {
59 if v != i {
60 t.Fatalf("missing item %d, got %v at position %d", i, v, i)
61 }
62 }
63}
64
65func TestMap_Drop(t *testing.T) {
66 t.Parallel()
67
68 input := make(chan int, 5)
69 for i := 1; i <= 5; i++ {
70 input <- i
71 }
72 close(input)
73
74 out := Map(1, func(_ context.Context, v int) (int, bool) {
75 return v, v > 3
76 })(t.Context(), input)
77
78 var got []int
79 for v := range out {
80 got = append(got, v)
81 }
82
83 if len(got) != 2 {
84 t.Fatalf("expected 2 items, got %d: %v", len(got), got)
85 }
86}
87
88func TestMap_PanicOnZeroConcurrency(t *testing.T) {
89 t.Parallel()
90
91 defer func() {
92 if r := recover(); r == nil {
93 t.Error("expected panic for concurrency < 1")
94 }
95 }()
96
97 Map(0, func(_ context.Context, v int) (int, bool) { return v, true })
98}
99
100func TestFilter(t *testing.T) {
101 t.Parallel()
102
103 input := make(chan int, 10)
104 for i := 1; i <= 10; i++ {
105 input <- i
106 }
107 close(input)
108
109 out := Filter(func(v int) bool { return v%3 == 0 })(t.Context(), input)
110
111 var got []int
112 for v := range out {
113 got = append(got, v)
114 }
115
116 if len(got) != 3 {
117 t.Fatalf("expected [3 6 9], got %v", got)
118 }
119}
120
121func TestForEach(t *testing.T) {
122 t.Parallel()
123
124 input := make(chan int, 3)
125 input <- 1
126 input <- 2
127 input <- 3
128 close(input)
129
130 var sum atomic.Int32
131 out := ForEach(func(v int) {
132 sum.Add(int32(v))
133 })(t.Context(), input)
134
135 var got []int
136 for v := range out {
137 got = append(got, v)
138 }
139
140 if sum.Load() != 6 {
141 t.Fatalf("expected side effect sum 6, got %d", sum.Load())
142 }
143 if len(got) != 3 {
144 t.Fatalf("expected 3 forwarded items, got %d", len(got))
145 }
146}
147
148func TestBuffer(t *testing.T) {
149 t.Parallel()
150
151 input := make(chan int, 5)
152 for i := 1; i <= 5; i++ {
153 input <- i
154 }
155 close(input)
156
157 out := Buffer[int](10)(t.Context(), input)
158
159 var got []int
160 for v := range out {
161 got = append(got, v)
162 }
163
164 if len(got) != 5 {
165 t.Fatalf("expected 5 items, got %d", len(got))
166 }
167}
168
169func TestBuffer_PanicOnZero(t *testing.T) {
170 t.Parallel()
171
172 defer func() {
173 if r := recover(); r == nil {
174 t.Error("expected panic for buffer size < 1")
175 }
176 }()
177
178 Buffer[int](0)
179}
180
181func TestTee(t *testing.T) {
182 t.Parallel()
183
184 input := make(chan int, 3)
185 input <- 1
186 input <- 2
187 input <- 3
188 close(input)
189
190 side := make(chan int, 10)
191 out := Tee(side)(t.Context(), input)
192
193 var got []int
194 for v := range out {
195 got = append(got, v)
196 }
197 close(side)
198
199 var sideGot []int
200 for v := range side {
201 sideGot = append(sideGot, v)
202 }
203
204 if len(got) != 3 {
205 t.Fatalf("expected 3 forwarded items, got %d", len(got))
206 }
207 if len(sideGot) != 3 {
208 t.Fatalf("expected 3 side items, got %d", len(sideGot))
209 }
210}
211
212func TestTee_NilSide(t *testing.T) {
213 t.Parallel()
214
215 defer func() {
216 if r := recover(); r == nil {
217 t.Error("expected panic for nil side channel")
218 }
219 }()
220
221 Tee[int](nil)
222}
223
224func TestTake(t *testing.T) {
225 t.Parallel()
226 ctx, cancel := context.WithCancel(t.Context())
227 defer cancel()
228
229 input := make(chan int, 10)
230 for i := 1; i <= 10; i++ {
231 input <- i
232 }
233 close(input)
234
235 out := Take[int](3)(ctx, input)
236
237 var got []int
238 for v := range out {
239 got = append(got, v)
240 }
241
242 if len(got) != 3 {
243 t.Fatalf("expected 3 items, got %d: %v", len(got), got)
244 }
245}
246
247func TestTake_Zero(t *testing.T) {
248 t.Parallel()
249
250 input := make(chan int, 5)
251 for i := 1; i <= 5; i++ {
252 input <- i
253 }
254 close(input)
255
256 out := Take[int](0)(t.Context(), input)
257
258 count := 0
259 for range out {
260 count++
261 }
262
263 if count != 0 {
264 t.Fatalf("expected 0 items from Take(0), got %d", count)
265 }
266}
267
268func TestSink(t *testing.T) {
269 t.Parallel()
270
271 input := make(chan int, 5)
272 for i := 1; i <= 5; i++ {
273 input <- i
274 }
275 close(input)
276
277 var mu sync.Mutex
278 var collected []int
279
280 out := Sink(2, func(_ context.Context, v int) {
281 mu.Lock()
282 collected = append(collected, v)
283 mu.Unlock()
284 })(t.Context(), input)
285
286 for range out {
287 t.Fatal("Sink should not forward items")
288 }
289
290 mu.Lock()
291 defer mu.Unlock()
292
293 if len(collected) != 5 {
294 t.Fatalf("expected 5 items consumed, got %d", len(collected))
295 }
296}
297
298func TestSink_PanicOnZeroConcurrency(t *testing.T) {
299 t.Parallel()
300
301 defer func() {
302 if r := recover(); r == nil {
303 t.Error("expected panic for concurrency < 1")
304 }
305 }()
306
307 Sink(0, func(_ context.Context, v int) {})
308}