Files
coder/testutil/faker.go
Steven Masley ce935657f6 test: start migrating dbauthz tests to mocked db (#19257)
This PR adds a framework to move to a mocked db. And therefore massively speed up these tests.
2025-08-08 13:46:24 -05:00

68 lines
1.6 KiB
Go

package testutil
import (
"reflect"
"testing"
"github.com/brianvoe/gofakeit/v7"
"github.com/stretchr/testify/require"
)
// Fake will populate any zero fields in the provided struct with fake data.
// Non-zero fields will remain unchanged.
// Usage:
//
// key := Fake(t, faker, database.APIKey{
// TokenName: "keep-my-name",
// })
func Fake[T any](t *testing.T, faker *gofakeit.Faker, seed T) T {
t.Helper()
var tmp T
err := faker.Struct(&tmp)
require.NoError(t, err, "failed to generate fake data for type %T", tmp)
mergeZero(&seed, tmp)
return seed
}
// mergeZero merges the fields of src into dst, but only if the field in dst is
// currently the zero value.
// Make sure `dst` is a pointer to a struct, otherwise the fields are not assignable.
func mergeZero(dst any, src any) {
srcv := reflect.ValueOf(src)
if srcv.Kind() == reflect.Ptr {
srcv = srcv.Elem()
}
remain := [][2]reflect.Value{
{reflect.ValueOf(dst).Elem(), srcv},
}
// Traverse the struct fields and set them only if they are currently zero.
// This is a breadth-first traversal of the struct fields. Struct definitions
// Should not be that deep, so we should not hit any stack overflow issues.
for {
if len(remain) == 0 {
return
}
dv, sv := remain[0][0], remain[0][1]
remain = remain[1:] //
for i := 0; i < dv.NumField(); i++ {
df := dv.Field(i)
sf := sv.Field(i)
if !df.CanSet() {
continue
}
if df.IsZero() { // only write if currently zero
df.Set(sf)
continue
}
if dv.Field(i).Kind() == reflect.Struct {
// If the field is a struct, we need to traverse it as well.
remain = append(remain, [2]reflect.Value{df, sf})
}
}
}
}