mirror of
https://github.com/coder/coder.git
synced 2026-10-16 14:48:56 +08:00
Stack context: second layer of the Go lint gate stack, built on the exclusion fix below. Why: adds commented-out code detection and a `log/slog` ban to the main config, plus a new-code-only pass requiring reasons on lint suppressions, flagging ignored errors (including `_, _ = w.Write(...)`), and banning `time.Sleep` in tests. Fixing the hits surfaced a real bug: GitLab warnings went to the wrong logger. The new-code pass resolves symlinked checkout paths so it does not silently report nothing. Validation: both configs report 0 issues; each seeded violation is caught; `make pre-commit` passed. > Xum acted for Mike to open this PR.
144 lines
3.4 KiB
Go
144 lines
3.4 KiB
Go
package testutil
|
|
|
|
import (
|
|
"reflect"
|
|
"time"
|
|
|
|
"golang.org/x/xerrors"
|
|
)
|
|
|
|
type Random struct {
|
|
String func() string
|
|
Bool func() bool
|
|
Int func() int64
|
|
Uint func() uint64
|
|
Float func() float64
|
|
Complex func() complex128
|
|
Time func() time.Time
|
|
}
|
|
|
|
func NewRandom() *Random {
|
|
// Guaranteed to be random...
|
|
return &Random{
|
|
String: func() string { return "foo" },
|
|
Bool: func() bool { return true },
|
|
Int: func() int64 { return 500 },
|
|
Uint: func() uint64 { return 126 },
|
|
Float: func() float64 { return 3.14 },
|
|
Complex: func() complex128 { return 6.24 },
|
|
Time: func() time.Time { return time.Date(2020, 5, 2, 5, 19, 21, 30, time.UTC) },
|
|
}
|
|
}
|
|
|
|
// PopulateStruct does a best effort to populate a struct with random values.
|
|
func PopulateStruct(s interface{}, r *Random) error {
|
|
if r == nil {
|
|
r = NewRandom()
|
|
}
|
|
|
|
v := reflect.ValueOf(s)
|
|
if v.Kind() != reflect.Ptr || v.IsNil() {
|
|
return xerrors.Errorf("s must be a non-nil pointer")
|
|
}
|
|
|
|
v = v.Elem()
|
|
if v.Kind() != reflect.Struct {
|
|
return xerrors.Errorf("s must be a pointer to a struct")
|
|
}
|
|
|
|
t := v.Type()
|
|
for i := 0; i < t.NumField(); i++ {
|
|
field := t.Field(i)
|
|
fieldName := field.Name
|
|
|
|
fieldValue := v.Field(i)
|
|
if !fieldValue.CanSet() {
|
|
continue // Skip if field is unexported
|
|
}
|
|
|
|
nv, err := populateValue(fieldValue, r)
|
|
if err != nil {
|
|
return xerrors.Errorf("%s : %w", fieldName, err)
|
|
}
|
|
v.Field(i).Set(nv)
|
|
}
|
|
|
|
return nil
|
|
}
|
|
|
|
func populateValue(v reflect.Value, r *Random) (reflect.Value, error) {
|
|
var err error
|
|
|
|
// Handle some special cases
|
|
switch v.Type() {
|
|
case reflect.TypeOf(time.Time{}):
|
|
v.Set(reflect.ValueOf(r.Time()))
|
|
return v, nil
|
|
default:
|
|
// Go to Kind instead
|
|
}
|
|
|
|
switch v.Kind() {
|
|
case reflect.Struct:
|
|
if err := PopulateStruct(v.Addr().Interface(), r); err != nil {
|
|
return v, err
|
|
}
|
|
case reflect.String:
|
|
v.SetString(r.String())
|
|
case reflect.Bool:
|
|
v.SetBool(true)
|
|
case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
|
|
v.SetInt(r.Int())
|
|
case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64:
|
|
v.SetUint(r.Uint())
|
|
case reflect.Float32, reflect.Float64:
|
|
v.SetFloat(r.Float())
|
|
case reflect.Complex64, reflect.Complex128:
|
|
v.SetComplex(r.Complex())
|
|
case reflect.Array:
|
|
for i := 0; i < v.Len(); i++ {
|
|
nv, err := populateValue(v.Index(i), r)
|
|
if err != nil {
|
|
return v, xerrors.Errorf("array index %d : %w", i, err)
|
|
}
|
|
v.Index(i).Set(nv)
|
|
}
|
|
case reflect.Map:
|
|
m := reflect.MakeMap(v.Type())
|
|
|
|
// Set a value in the map
|
|
k := reflect.New(v.Type().Key())
|
|
kv := reflect.New(v.Type().Elem())
|
|
k, err = populateValue(k, r)
|
|
if err != nil {
|
|
return v, xerrors.Errorf("map key : %w", err)
|
|
}
|
|
kv, err = populateValue(kv, r)
|
|
if err != nil {
|
|
return v, xerrors.Errorf("map value : %w", err)
|
|
}
|
|
|
|
m.SetMapIndex(k, kv)
|
|
return m, nil
|
|
case reflect.Pointer:
|
|
return populateValue(v.Elem(), r)
|
|
case reflect.Slice:
|
|
s := reflect.MakeSlice(v.Type(), 2, 2)
|
|
sv, err := populateValue(reflect.New(v.Type().Elem()), r)
|
|
if err != nil {
|
|
return v, xerrors.Errorf("slice value : %w", err)
|
|
}
|
|
|
|
s.Index(0).Set(sv)
|
|
s.Index(1).Set(sv)
|
|
|
|
return s, nil
|
|
case reflect.Uintptr, reflect.UnsafePointer, reflect.Chan, reflect.Func, reflect.Interface:
|
|
// Unsupported
|
|
return v, xerrors.Errorf("%s is not supported", v.Kind())
|
|
default:
|
|
return v, xerrors.Errorf("unsupported kind %s", v.Kind())
|
|
}
|
|
return v, nil
|
|
}
|