Skip to content

Commit d834474

Browse files
committed
test: added ai generated tests for pipe pkg
1 parent 3896ee6 commit d834474

1 file changed

Lines changed: 223 additions & 0 deletions

File tree

pipe/pipe_test.go

Lines changed: 223 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,223 @@
1+
package pipe_test
2+
3+
import (
4+
"bytes"
5+
"context"
6+
"errors"
7+
"io"
8+
"strings"
9+
"testing"
10+
11+
"github.com/bit8bytes/beago/pipe"
12+
)
13+
14+
// uppercase transforms input to uppercase as a simple deterministic handler.
15+
func uppercase() pipe.HandlerFunc {
16+
return func(ctx context.Context, r io.Reader, w io.Writer) error {
17+
data, err := io.ReadAll(r)
18+
if err != nil {
19+
return err
20+
}
21+
_, err = w.Write(bytes.ToUpper(data))
22+
return err
23+
}
24+
}
25+
26+
// append returns a handler that appends suffix to whatever it reads.
27+
func appendSuffix(suffix string) pipe.HandlerFunc {
28+
return func(ctx context.Context, r io.Reader, w io.Writer) error {
29+
data, err := io.ReadAll(r)
30+
if err != nil {
31+
return err
32+
}
33+
_, err = w.Write(append(data, []byte(suffix)...))
34+
return err
35+
}
36+
}
37+
38+
// counter counts how many times it was invoked.
39+
func counter(n *int) pipe.HandlerFunc {
40+
return func(ctx context.Context, r io.Reader, w io.Writer) error {
41+
*n++
42+
_, err := io.Copy(w, r)
43+
return err
44+
}
45+
}
46+
47+
func TestExecute_SingleHandler(t *testing.T) {
48+
var out bytes.Buffer
49+
err := pipe.Execute(context.Background(), strings.NewReader("hello"), &out, uppercase())
50+
if err != nil {
51+
t.Fatal(err)
52+
}
53+
if got := out.String(); got != "HELLO" {
54+
t.Errorf("got %q, want %q", got, "HELLO")
55+
}
56+
}
57+
58+
func TestExecute_ChainedHandlers(t *testing.T) {
59+
var out bytes.Buffer
60+
err := pipe.Execute(context.Background(), strings.NewReader("hi"),
61+
&out,
62+
uppercase(),
63+
appendSuffix("!"),
64+
)
65+
if err != nil {
66+
t.Fatal(err)
67+
}
68+
if got := out.String(); got != "HI!" {
69+
t.Errorf("got %q, want %q", got, "HI!")
70+
}
71+
}
72+
73+
func TestExecute_PropagatesHandlerError(t *testing.T) {
74+
boom := errors.New("boom")
75+
fail := pipe.HandlerFunc(func(ctx context.Context, r io.Reader, w io.Writer) error {
76+
return boom
77+
})
78+
79+
var out bytes.Buffer
80+
err := pipe.Execute(context.Background(), strings.NewReader("x"), &out, uppercase(), fail)
81+
if !errors.Is(err, boom) {
82+
t.Errorf("expected boom error, got %v", err)
83+
}
84+
}
85+
86+
func TestExecute_NoHandlers(t *testing.T) {
87+
// With no handlers Execute should return nil without writing anything.
88+
var out bytes.Buffer
89+
err := pipe.Execute(context.Background(), strings.NewReader("x"), &out)
90+
if err != nil {
91+
t.Fatal(err)
92+
}
93+
if out.Len() != 0 {
94+
t.Errorf("expected no output, got %q", out.String())
95+
}
96+
}
97+
98+
func TestLoop_RunsUpToMaxIter(t *testing.T) {
99+
n := 0
100+
h := pipe.Loop(3, counter(&n))
101+
102+
var out bytes.Buffer
103+
if err := h.Handle(context.Background(), strings.NewReader("x"), &out); err != nil {
104+
t.Fatal(err)
105+
}
106+
if n != 3 {
107+
t.Errorf("expected 3 iterations, got %d", n)
108+
}
109+
}
110+
111+
func TestLoop_StopsOnErrDone(t *testing.T) {
112+
n := 0
113+
stopAfter := 2
114+
115+
h := pipe.Loop(10, counter(&n), pipe.Exit(func(data []byte) bool {
116+
return n >= stopAfter
117+
}))
118+
119+
var out bytes.Buffer
120+
if err := h.Handle(context.Background(), strings.NewReader("x"), &out); err != nil {
121+
t.Fatal(err)
122+
}
123+
if n != stopAfter {
124+
t.Errorf("expected %d iterations, got %d", stopAfter, n)
125+
}
126+
}
127+
128+
func TestLoop_OutputIsLastIterationResult(t *testing.T) {
129+
n := 0
130+
h := pipe.Loop(3, appendSuffix("."), pipe.Exit(func(data []byte) bool {
131+
n++
132+
return n >= 3
133+
}))
134+
135+
var out bytes.Buffer
136+
if err := h.Handle(context.Background(), strings.NewReader("x"), &out); err != nil {
137+
t.Fatal(err)
138+
}
139+
// After 3 iterations of appending ".", output should be "x..."
140+
if got := out.String(); got != "x..." {
141+
t.Errorf("got %q, want %q", got, "x...")
142+
}
143+
}
144+
145+
func TestLoop_PropagatesHandlerError(t *testing.T) {
146+
boom := errors.New("boom")
147+
fail := pipe.HandlerFunc(func(ctx context.Context, r io.Reader, w io.Writer) error {
148+
return boom
149+
})
150+
151+
h := pipe.Loop(5, fail)
152+
var out bytes.Buffer
153+
err := h.Handle(context.Background(), strings.NewReader("x"), &out)
154+
if !errors.Is(err, boom) {
155+
t.Errorf("expected boom, got %v", err)
156+
}
157+
}
158+
159+
func TestTee_WritesToBothSinks(t *testing.T) {
160+
var primary, debug bytes.Buffer
161+
h := pipe.Tee(&debug)
162+
163+
err := h.Handle(context.Background(), strings.NewReader("hello"), &primary)
164+
if err != nil {
165+
t.Fatal(err)
166+
}
167+
if primary.String() != "hello" {
168+
t.Errorf("primary got %q, want %q", primary.String(), "hello")
169+
}
170+
if debug.String() != "hello" {
171+
t.Errorf("debug got %q, want %q", debug.String(), "hello")
172+
}
173+
}
174+
175+
func TestExit_ReturnsDoneWhenPredicateTrue(t *testing.T) {
176+
h := pipe.Exit(func(data []byte) bool { return true })
177+
178+
var out bytes.Buffer
179+
err := h.Handle(context.Background(), strings.NewReader("done"), &out)
180+
if !errors.Is(err, pipe.ErrDone) {
181+
t.Errorf("expected ErrDone, got %v", err)
182+
}
183+
// Content must still be passed through.
184+
if out.String() != "done" {
185+
t.Errorf("got %q, want %q", out.String(), "done")
186+
}
187+
}
188+
189+
func TestExit_ContinuesWhenPredicateFalse(t *testing.T) {
190+
h := pipe.Exit(func(data []byte) bool { return false })
191+
192+
var out bytes.Buffer
193+
err := h.Handle(context.Background(), strings.NewReader("keep going"), &out)
194+
if err != nil {
195+
t.Fatalf("expected nil, got %v", err)
196+
}
197+
}
198+
199+
func TestHandlerFunc_ImplementsHandler(t *testing.T) {
200+
// Compile-time check that HandlerFunc satisfies Handler.
201+
var _ pipe.Handler = pipe.HandlerFunc(nil)
202+
}
203+
204+
func TestExecute_ContextCancellation(t *testing.T) {
205+
ctx, cancel := context.WithCancel(context.Background())
206+
cancel()
207+
208+
slow := pipe.HandlerFunc(func(ctx context.Context, r io.Reader, w io.Writer) error {
209+
select {
210+
case <-ctx.Done():
211+
return ctx.Err()
212+
default:
213+
_, err := io.Copy(w, r)
214+
return err
215+
}
216+
})
217+
218+
var out bytes.Buffer
219+
err := pipe.Execute(ctx, strings.NewReader("x"), &out, slow)
220+
if err == nil {
221+
t.Error("expected an error due to cancelled context")
222+
}
223+
}

0 commit comments

Comments
 (0)