Skip to content

Commit 4ec0d5c

Browse files
test(utilities): add tests for previously-uncovered helpers
internal/utilities/strings.go, context.go, and io.go held small pure-ish helpers but had no test coverage. Add focused unit tests so behaviour changes get caught: round-trip tests for StringValue and StringPtr; a context-key formatting check plus set/read/replace/derive cases for WithRequestID and GetRequestID; cancellation and completion cases for WaitForCleanup; and behaviour assertions for SafeClose covering the happy path, the error path, and io.NopCloser. Coverage for the package goes from 50.8% to 62.4% with no behaviour changes. Signed-off-by: Manas Srivastava <mastermanas805@gmail.com>
1 parent 7f88985 commit 4ec0d5c

3 files changed

Lines changed: 234 additions & 0 deletions

File tree

internal/utilities/context_test.go

Lines changed: 84 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,84 @@
1+
package utilities
2+
3+
import (
4+
"context"
5+
"sync"
6+
"testing"
7+
"time"
8+
9+
"github.com/stretchr/testify/require"
10+
)
11+
12+
func TestContextKeyString(t *testing.T) {
13+
require.Equal(t, "gotrue api context key request_id", contextKey("request_id").String())
14+
require.Equal(t, "gotrue api context key ", contextKey("").String())
15+
}
16+
17+
func TestRequestIDRoundtrip(t *testing.T) {
18+
t.Run("set then read", func(t *testing.T) {
19+
ctx := WithRequestID(context.Background(), "abc-123")
20+
require.Equal(t, "abc-123", GetRequestID(ctx))
21+
})
22+
23+
t.Run("missing key returns empty string", func(t *testing.T) {
24+
require.Equal(t, "", GetRequestID(context.Background()))
25+
})
26+
27+
t.Run("set replaces previous value", func(t *testing.T) {
28+
ctx := WithRequestID(context.Background(), "first")
29+
ctx = WithRequestID(ctx, "second")
30+
require.Equal(t, "second", GetRequestID(ctx))
31+
})
32+
33+
t.Run("derived context inherits value", func(t *testing.T) {
34+
ctx := WithRequestID(context.Background(), "parent-id")
35+
child, cancel := context.WithCancel(ctx)
36+
defer cancel()
37+
require.Equal(t, "parent-id", GetRequestID(child))
38+
})
39+
}
40+
41+
func TestWaitForCleanup(t *testing.T) {
42+
t.Run("returns when wait group is done", func(t *testing.T) {
43+
var wg sync.WaitGroup
44+
wg.Add(1)
45+
go func() {
46+
time.Sleep(10 * time.Millisecond)
47+
wg.Done()
48+
}()
49+
50+
done := make(chan struct{})
51+
go func() {
52+
defer close(done)
53+
WaitForCleanup(context.Background(), &wg)
54+
}()
55+
56+
select {
57+
case <-done:
58+
case <-time.After(time.Second):
59+
t.Fatal("WaitForCleanup did not return after wg.Done()")
60+
}
61+
})
62+
63+
t.Run("returns when context is cancelled before wait group is done", func(t *testing.T) {
64+
var wg sync.WaitGroup
65+
wg.Add(1)
66+
67+
ctx, cancel := context.WithCancel(context.Background())
68+
done := make(chan struct{})
69+
go func() {
70+
defer close(done)
71+
WaitForCleanup(ctx, &wg)
72+
}()
73+
74+
cancel()
75+
76+
select {
77+
case <-done:
78+
case <-time.After(time.Second):
79+
t.Fatal("WaitForCleanup did not return after context cancellation")
80+
}
81+
82+
wg.Done()
83+
})
84+
}

internal/utilities/io_test.go

Lines changed: 50 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,50 @@
1+
package utilities
2+
3+
import (
4+
"errors"
5+
"io"
6+
"testing"
7+
8+
"github.com/stretchr/testify/require"
9+
)
10+
11+
type closerFunc func() error
12+
13+
func (f closerFunc) Close() error { return f() }
14+
15+
func TestSafeClose(t *testing.T) {
16+
tests := []struct {
17+
name string
18+
closer io.Closer
19+
closerErr error
20+
}{
21+
{
22+
name: "happy path: Close returns nil",
23+
closerErr: nil,
24+
},
25+
{
26+
name: "Close returns error: SafeClose must not panic",
27+
closerErr: errors.New("close failed"),
28+
},
29+
{
30+
name: "io.NopCloser: SafeClose must not panic",
31+
closer: io.NopCloser(nil),
32+
},
33+
}
34+
for _, tt := range tests {
35+
t.Run(tt.name, func(t *testing.T) {
36+
closer := tt.closer
37+
if closer == nil {
38+
called := false
39+
closer = closerFunc(func() error {
40+
called = true
41+
return tt.closerErr
42+
})
43+
require.NotPanics(t, func() { SafeClose(closer) })
44+
require.True(t, called, "Close should have been invoked")
45+
return
46+
}
47+
require.NotPanics(t, func() { SafeClose(closer) })
48+
})
49+
}
50+
}

internal/utilities/strings_test.go

Lines changed: 100 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,100 @@
1+
package utilities
2+
3+
import (
4+
"testing"
5+
6+
"github.com/stretchr/testify/require"
7+
)
8+
9+
func TestStringValue(t *testing.T) {
10+
empty := ""
11+
hello := "hello"
12+
tests := []struct {
13+
name string
14+
in *string
15+
want string
16+
}{
17+
{
18+
name: "nil pointer returns empty string",
19+
in: nil,
20+
want: "",
21+
},
22+
{
23+
name: "pointer to empty string returns empty string",
24+
in: &empty,
25+
want: "",
26+
},
27+
{
28+
name: "pointer to non-empty string returns the value",
29+
in: &hello,
30+
want: "hello",
31+
},
32+
}
33+
for _, tt := range tests {
34+
t.Run(tt.name, func(t *testing.T) {
35+
require.Equal(t, tt.want, StringValue(tt.in))
36+
})
37+
}
38+
}
39+
40+
func TestStringPtr(t *testing.T) {
41+
tests := []struct {
42+
name string
43+
in string
44+
expectNil bool
45+
wantPointee string
46+
}{
47+
{
48+
name: "empty string returns nil",
49+
in: "",
50+
expectNil: true,
51+
},
52+
{
53+
name: "non-empty string returns pointer to that value",
54+
in: "hello",
55+
wantPointee: "hello",
56+
},
57+
{
58+
name: "string with whitespace and newline preserved",
59+
in: " hi\nthere ",
60+
wantPointee: " hi\nthere ",
61+
},
62+
}
63+
for _, tt := range tests {
64+
t.Run(tt.name, func(t *testing.T) {
65+
got := StringPtr(tt.in)
66+
if tt.expectNil {
67+
require.Nil(t, got)
68+
return
69+
}
70+
require.NotNil(t, got)
71+
require.Equal(t, tt.wantPointee, *got)
72+
})
73+
}
74+
75+
t.Run("returned pointer is independent of the input variable", func(t *testing.T) {
76+
s := "original"
77+
p := StringPtr(s)
78+
require.Equal(t, "original", *p)
79+
s = "mutated"
80+
require.Equal(t, "original", *p)
81+
})
82+
}
83+
84+
func TestStringValueAndStringPtrRoundtrip(t *testing.T) {
85+
tests := []struct {
86+
name string
87+
in string
88+
}{
89+
{name: "empty", in: ""},
90+
{name: "ascii", in: "hello"},
91+
{name: "with spaces", in: "with spaces"},
92+
{name: "with newline", in: "with\nnewline"},
93+
{name: "multibyte rune", in: "🦄"},
94+
}
95+
for _, tt := range tests {
96+
t.Run(tt.name, func(t *testing.T) {
97+
require.Equal(t, tt.in, StringValue(StringPtr(tt.in)))
98+
})
99+
}
100+
}

0 commit comments

Comments
 (0)