Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
84 changes: 84 additions & 0 deletions internal/utilities/context_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,84 @@
package utilities

import (
"context"
"sync"
"testing"
"time"

"github.com/stretchr/testify/require"
)

func TestContextKeyString(t *testing.T) {
require.Equal(t, "gotrue api context key request_id", contextKey("request_id").String())
require.Equal(t, "gotrue api context key ", contextKey("").String())
}

func TestRequestIDRoundtrip(t *testing.T) {
t.Run("set then read", func(t *testing.T) {
ctx := WithRequestID(context.Background(), "abc-123")
require.Equal(t, "abc-123", GetRequestID(ctx))
})

t.Run("missing key returns empty string", func(t *testing.T) {
require.Equal(t, "", GetRequestID(context.Background()))
})

t.Run("set replaces previous value", func(t *testing.T) {
ctx := WithRequestID(context.Background(), "first")
ctx = WithRequestID(ctx, "second")
require.Equal(t, "second", GetRequestID(ctx))
})

t.Run("derived context inherits value", func(t *testing.T) {
ctx := WithRequestID(context.Background(), "parent-id")
child, cancel := context.WithCancel(ctx)
defer cancel()
require.Equal(t, "parent-id", GetRequestID(child))
})
}

func TestWaitForCleanup(t *testing.T) {
t.Run("returns when wait group is done", func(t *testing.T) {
var wg sync.WaitGroup
wg.Add(1)
go func() {
time.Sleep(10 * time.Millisecond)
wg.Done()
}()

done := make(chan struct{})
go func() {
defer close(done)
WaitForCleanup(context.Background(), &wg)
}()

select {
case <-done:
case <-time.After(time.Second):
t.Fatal("WaitForCleanup did not return after wg.Done()")
}
})

t.Run("returns when context is cancelled before wait group is done", func(t *testing.T) {
var wg sync.WaitGroup
wg.Add(1)

ctx, cancel := context.WithCancel(context.Background())
done := make(chan struct{})
go func() {
defer close(done)
WaitForCleanup(ctx, &wg)
}()

cancel()

select {
case <-done:
case <-time.After(time.Second):
t.Fatal("WaitForCleanup did not return after context cancellation")
}

wg.Done()
})
}
50 changes: 50 additions & 0 deletions internal/utilities/io_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
package utilities

import (
"errors"
"io"
"testing"

"github.com/stretchr/testify/require"
)

type closerFunc func() error

func (f closerFunc) Close() error { return f() }

func TestSafeClose(t *testing.T) {
tests := []struct {
name string
closer io.Closer
closerErr error
}{
{
name: "happy path: Close returns nil",
closerErr: nil,
},
{
name: "Close returns error: SafeClose must not panic",
closerErr: errors.New("close failed"),
},
{
name: "io.NopCloser: SafeClose must not panic",
closer: io.NopCloser(nil),
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
closer := tt.closer
if closer == nil {
called := false
closer = closerFunc(func() error {
called = true
return tt.closerErr
})
require.NotPanics(t, func() { SafeClose(closer) })
require.True(t, called, "Close should have been invoked")
return
}
require.NotPanics(t, func() { SafeClose(closer) })
})
}
}
100 changes: 100 additions & 0 deletions internal/utilities/strings_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,100 @@
package utilities

import (
"testing"

"github.com/stretchr/testify/require"
)

func TestStringValue(t *testing.T) {
empty := ""
hello := "hello"
tests := []struct {
name string
in *string
want string
}{
{
name: "nil pointer returns empty string",
in: nil,
want: "",
},
{
name: "pointer to empty string returns empty string",
in: &empty,
want: "",
},
{
name: "pointer to non-empty string returns the value",
in: &hello,
want: "hello",
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
require.Equal(t, tt.want, StringValue(tt.in))
})
}
}

func TestStringPtr(t *testing.T) {
tests := []struct {
name string
in string
expectNil bool
wantPointee string
}{
{
name: "empty string returns nil",
in: "",
expectNil: true,
},
{
name: "non-empty string returns pointer to that value",
in: "hello",
wantPointee: "hello",
},
{
name: "string with whitespace and newline preserved",
in: " hi\nthere ",
wantPointee: " hi\nthere ",
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
got := StringPtr(tt.in)
if tt.expectNil {
require.Nil(t, got)
return
}
require.NotNil(t, got)
require.Equal(t, tt.wantPointee, *got)
})
}

t.Run("returned pointer is independent of the input variable", func(t *testing.T) {
s := "original"
p := StringPtr(s)
require.Equal(t, "original", *p)
s = "mutated"
require.Equal(t, "original", *p)
})
}

func TestStringValueAndStringPtrRoundtrip(t *testing.T) {
tests := []struct {
name string
in string
}{
{name: "empty", in: ""},
{name: "ascii", in: "hello"},
{name: "with spaces", in: "with spaces"},
{name: "with newline", in: "with\nnewline"},
{name: "multibyte rune", in: "🦄"},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
require.Equal(t, tt.in, StringValue(StringPtr(tt.in)))
})
}
}