package bind_test import ( "code.squareroundforest.org/arpio/bind" "code.squareroundforest.org/arpio/notation" "fmt" "reflect" "slices" "sort" "strings" "testing" "time" ) func TestField(t *testing.T) { sortFields := func(f []bind.Field, p ...func(int, int) bool) { sort.Slice(f, func(i, j int) bool { pi, pj := strings.Join(f[i].Path(), ":"), strings.Join(f[j].Path(), ":") if pi < pj { return true } if f[i].Name() < f[j].Name() { return true } for _, pi := range p { if pi(i, j) { return true } } return false }) } t.Run("fields", func(t *testing.T) { type s0 struct { FieldOne int } type s1 struct { Foo int } type s2 struct { s0 foo int FooBar int Baz s1 Qux *s1 Chan chan int Que bool Hola []int } t.Run("mixed", func(t *testing.T) { f := bind.Fields[s2]() if len(f) != 6 { t.Fatal(notation.Sprintwt(f)) } m := make(map[string]bind.Field) for _, fi := range f { m[fi.Name()] = fi } fieldOne := m["field-one"] if !slices.Equal(fieldOne.Path(), []string{"FieldOne"}) { t.Fatal(fieldOne.Name()) } fooBar := m["foo-bar"] if !slices.Equal(fooBar.Path(), []string{"FooBar"}) { t.Fatal(fooBar.Name()) } bazFoo := m["baz-foo"] if !slices.Equal(bazFoo.Path(), []string{"Baz", "Foo"}) { t.Fatal(bazFoo.Name()) } quxFoo := m["qux-foo"] if !slices.Equal(quxFoo.Path(), []string{"Qux", "Foo"}) { t.Fatal(quxFoo.Name()) } que := m["que"] if !slices.Equal(que.Path(), []string{"Que"}) || que.Type() != bind.Bool { t.Fatal(que.Name()) } hola := m["hola"] if !slices.Equal(hola.Path(), []string{"Hola"}) || !hola.List() { t.Fatal(hola.Name()) } }) t.Run("cannot have fields", func(t *testing.T) { type i []int f := bind.Fields[i]() if len(f) != 0 { t.Fatal() } }) t.Run("has circular type", func(t *testing.T) { type s struct{ Foo *s } if len(bind.Fields[s]()) != 0 { t.Fatal() } }) t.Run("list", func(t *testing.T) { type s struct{ Foo int } f := bind.Fields[[]s]() if len(f) != 1 || f[0].List() { t.Fatal() } }) t.Run("anonymous fields", func(t *testing.T) { type s0 struct{ Foo int } type s1 struct { s0 Bar int } f := bind.Fields[s1]() if len(f) != 2 || f[0].Name() != "foo" || f[1].Name() != "bar" { t.Fatal(notation.Sprint(f)) } }) t.Run("list of struct", func(t *testing.T) { type s struct{ Foo []struct{ Bar int } } f := bind.Fields[s]() if len(f) != 1 || f[0].Name() != "foo-bar" || !f[0].List() { t.Fatal() } }) t.Run("field types", func(t *testing.T) { type s struct { B bool I int U uint F float64 S string D time.Duration T time.Time A any } f := bind.Fields[s]() if len(f) != 8 { t.Fatal(notation.Sprint(f)) } check := map[string]bind.FieldType{ "b": bind.Bool, "i": bind.Int, "u": bind.Uint, "f": bind.Float64, "s": bind.String, "d": bind.Duration, "t": bind.Time, "a": bind.Any, } for _, fi := range f { if fi.Type() != check[fi.Name()] { t.Fatal() } } }) t.Run("fields from reflection type", func(t *testing.T) { t.Run("ok", func(t *testing.T) { type s struct{ Foo int } f := bind.FieldsOf(reflect.TypeFor[s]()) if len(f) != 1 || f[0].Name() != "foo" { t.Fatal() } }) t.Run("nil type", func(t *testing.T) { f := bind.FieldsOf(nil) if len(f) != 0 { t.Fatal() } }) t.Run("circular type", func(t *testing.T) { type p *p f := bind.FieldsOf(reflect.TypeFor[p]()) if len(f) != 0 { t.Fatal() } }) }) }) t.Run("field values", func(t *testing.T) { t.Run("has circular reference", func(t *testing.T) { type s struct{ Foo any } var v s v.Foo = &v f := bind.FieldValues(v) if len(f) != 0 { t.Fatal(notation.Sprint(f)) } }) t.Run("slice", func(t *testing.T) { type s struct{ Foo int } f := bind.FieldValues([]s{{21}, {42}}) if len(f) != 2 || f[0].Value() != 21 || f[1].Value() != 42 { t.Fatal() } }) t.Run("scalar map", func(t *testing.T) { f := bind.FieldValues(map[string]int{"foo": 21, "bar": 42}) sortFields(f) if len(f) != 2 || f[0].Name() != "bar" || f[0].Value() != 42 || !f[0].Free() || f[1].Name() != "foo" || f[1].Value() != 21 || !f[1].Free() { t.Fatal(notation.Sprint(f)) } }) t.Run("scalar map with list values", func(t *testing.T) { f := bind.FieldValues(map[string][]int{"foo": []int{21, 36}, "bar": []int{42, 72}}) sortFields(f) if len(f) != 4 || f[0].Name() != "bar" || f[0].Value() != 42 || !f[0].Free() || f[1].Name() != "bar" || f[1].Value() != 72 || !f[1].Free() || f[2].Name() != "foo" || f[2].Value() != 21 || !f[2].Free() || f[3].Name() != "foo" || f[3].Value() != 36 || !f[3].Free() { t.Fatal(notation.Sprint(f)) } }) t.Run("not a struct", func(t *testing.T) { v := []int{21, 42, 84} f := bind.FieldValues(v) if len(f) != 0 { t.Fatal() } }) t.Run("not exported field", func(t *testing.T) { type s struct { Foo int bar string } v := s{Foo: 42, bar: "baz"} f := bind.FieldValues(v) if len(f) != 1 || f[0].Name() != "foo" { t.Fatal(notation.Sprint(f)) } }) t.Run("scalar fields", func(t *testing.T) { type s struct { Foo int Bar bool } v := s{Foo: 42, Bar: true} f := bind.FieldValues(v) if len(f) != 2 || f[0].Name() != "foo" || !slices.Equal(f[0].Path(), []string{"Foo"}) || f[0].Value() != 42 || f[0].Type() == bind.Bool || f[1].Name() != "bar" || !slices.Equal(f[1].Path(), []string{"Bar"}) || f[1].Value() != true || f[1.].Type() != bind.Bool { t.Fatal() } }) t.Run("list field", func(t *testing.T) { type s struct{ Foo []int } v := s{Foo: []int{21, 42, 84}} f := bind.FieldValues(v) if len(f) != 3 || f[0].Name() != "foo" || f[0].Value() != 21 || f[1].Name() != "foo" || f[1].Value() != 42 || f[2].Name() != "foo" || f[2].Value() != 84 { t.Fatal(notation.Sprintwt(f)) } }) t.Run("list of lists", func(t *testing.T) { type s struct{ Foo [][]int } v := s{Foo: [][]int{{21}, {42}}} f := bind.FieldValues(v) if len(f) != 2 || f[0].Name() != "foo" || f[0].Value() != 21 || f[1].Name() != "foo" || f[1].Value() != 42 { t.Fatal() } }) t.Run("list of scalar maps", func(t *testing.T) { type s struct{ Foo any } v := s{Foo: []any{map[string]int{"foo": 42}}} f := bind.FieldValues(v) if len(f) != 1 || f[0].Name() != "foo" || f[0].Value() != nil { t.Fatal(notation.Sprintwt(f)) } }) t.Run("list of structs", func(t *testing.T) { type s struct{ Foo any } v := s{Foo: []any{s{Foo: 21}, s{Foo: 42}}} f := bind.FieldValues(v) if len(f) != 1 || f[0].Name() != "foo" || f[0].Value() != nil { t.Fatal() } }) t.Run("scalar map field", func(t *testing.T) { type s struct{ Foo map[string]int } v := s{Foo: map[string]int{"foo": 42}} f := bind.FieldValues(v) if len(f) != 1 || f[0].Name() != "foo-foo" || f[0].Value() != 42 { t.Fatal() } }) t.Run("anonymous field", func(t *testing.T) { type s0 struct{ Foo int } type s1 struct { s0 Bar int } var v s1 v.Foo = 21 v.Bar = 42 f := bind.FieldValues(v) if len(f) != 2 || f[0].Name() != "foo" || f[0].Value() != 21 || f[1].Name() != "bar" || f[1].Value() != 42 { t.Fatal(notation.Sprint(f)) } }) t.Run("child struct", func(t *testing.T) { type S0 struct{ Foo int } type s1 struct { S0 S0 Bar int } var v s1 v.S0.Foo = 21 v.Bar = 42 f := bind.FieldValues(v) if len(f) != 2 || f[0].Name() != "s-0-foo" || f[0].Value() != 21 || f[1].Name() != "bar" || f[1].Value() != 42 { t.Fatal(notation.Sprintwt(f)) } }) t.Run("any type field nil", func(t *testing.T) { type s struct{ Foo any } var v s f := bind.FieldValues(v) if len(f) != 1 || f[0].Name() != "foo" || f[0].Type() != bind.Any { t.Fatal() } }) t.Run("any type field not nil", func(t *testing.T) { type s struct{ Foo any } v := s{42} f := bind.FieldValues(v) if len(f) != 1 || f[0].Name() != "foo" || f[0].Type() != bind.Any || f[0].Value() != 42 { t.Fatal(notation.Sprintt(v)) } }) t.Run("slice field empty", func(t *testing.T) { type s struct{ Foo []int } var v s f := bind.FieldValues(v) if len(f) != 1 || f[0].Name() != "foo" || !f[0].List() || f[0].Type() != bind.Int || f[0].Value() != nil { t.Fatal(notation.Sprint(f)) } }) t.Run("slice field not empty", func(t *testing.T) { type s struct{ Foo []int } v := s{[]int{21, 42, 84}} f := bind.FieldValues(v) if len(f) != 3 || f[0].Name() != "foo" || !f[0].List() || f[0].Type() != bind.Int || f[0].Value() != 21 || f[1].Name() != "foo" || !f[1].List() || f[1].Type() != bind.Int || f[1].Value() != 42 || f[2].Name() != "foo" || !f[2].List() || f[2].Type() != bind.Int || f[2].Value() != 84 { t.Fatal() } }) t.Run("slice field with any type empty", func(t *testing.T) { type s struct{ Foo []any } var v s f := bind.FieldValues(v) if len(f) != 1 || f[0].Name() != "foo" || !f[0].List() || f[0].Type() != bind.Any || f[0].Value() != nil { t.Fatal() } }) t.Run("slice field with any type not empty", func(t *testing.T) { type s struct{ Foo []any } v := s{[]any{21, 42, 84}} f := bind.FieldValues(v) if len(f) != 3 || f[0].Name() != "foo" || !f[0].List() || f[0].Type() != bind.Any || f[0].Value() != 21 || f[1].Name() != "foo" || !f[1].List() || f[1].Type() != bind.Any || f[1].Value() != 42 || f[2].Name() != "foo" || !f[2].List() || f[2].Type() != bind.Any || f[2].Value() != 84 { t.Fatal(notation.Sprintw(f)) } }) t.Run("struct in its own field via interface", func(t *testing.T) { var s struct{ F any } s.F = s f := bind.FieldValues(s) if len(f) != 1 || f[0].Name() != "f" || f[0].Value() != nil { t.Fatal(notation.Sprint(f)) } }) t.Run("list of struct", func(t *testing.T) { type s struct{ Foo []struct{ Bar int } } var v s f := bind.FieldValues(v) if len(f) != 1 || f[0].Name() != "foo-bar" || !f[0].List() { t.Fatal(notation.Sprint(f)) } }) t.Run("nil", func(t *testing.T) { f := bind.FieldValues(nil) if len(f) != 0 { t.Fatal() } }) }) t.Run("bind fields", func(t *testing.T) { t.Run("no circular receiver", func(t *testing.T) { type s struct { Foo *s Bar int } var v s if len(bind.Bind(&v, bind.NamedValue("bar", 42))) != 1 { t.Fatal() } }) t.Run("no circular valeu", func(t *testing.T) { type s struct{ Foo int } type p *p var v p if len(bind.Bind(&v, bind.NamedValue("foo", 42))) != 1 { t.Fatal() } }) t.Run("set by name", func(t *testing.T) { type s struct{ FooBar int } var v s u := bind.Bind(&v, bind.NamedValue("foo-bar", 42)) if len(u) != 0 || v.FooBar != 42 { t.Fatal(notation.Sprint(u), notation.Sprint(v)) } }) t.Run("set by path", func(t *testing.T) { type s struct{ FooBar int } var v s u := bind.Bind(&v, bind.ValueByPath([]string{"FooBar"}, 42)) if len(u) != 0 || v.FooBar != 42 { t.Fatal(notation.Sprint(u), notation.Sprint(v)) } }) t.Run("fail to bind", func(t *testing.T) { type s struct { Foo int Bar int } var v s u := bind.Bind( &v, bind.NamedValue("foo", 21), bind.NamedValue("baz", 42), ) if len(u) != 1 || u[0].Name() != "baz" { t.Fatal() } }) t.Run("bind list", func(t *testing.T) { type s struct{ Foo []int } var v s u := bind.Bind( &v, bind.NamedValue("foo", 21), bind.NamedValue("foo", 42), bind.NamedValue("foo", 84), ) if len(u) != 0 || v.Foo[0] != 21 || v.Foo[1] != 42 || v.Foo[2] != 84 { t.Fatal(notation.Sprint(u), notation.Sprint(v)) } }) t.Run("bind list of structs", func(t *testing.T) { type s struct{ Foo []struct{ Bar int } } var v s u := bind.Bind( &v, bind.NamedValue("foo-bar", 21), bind.NamedValue("foo-bar", 42), bind.NamedValue("foo-bar", 84), ) if len(u) != 0 || len(v.Foo) != 3 || v.Foo[0].Bar != 21 || v.Foo[1].Bar != 42 || v.Foo[2].Bar != 84 { t.Fatal() } }) t.Run("bind list in list", func(t *testing.T) { type s struct{ Foo []struct{ Bar []int } } var v s u := bind.Bind( &v, bind.NamedValue("foo-bar", 21), bind.NamedValue("foo-bar", 42), bind.NamedValue("foo-bar", 84), ) if len(u) != 0 || len(v.Foo) != 3 || len(v.Foo[0].Bar) != 1 || v.Foo[0].Bar[0] != 21 || len(v.Foo[1].Bar) != 1 || v.Foo[1].Bar[0] != 42 || len(v.Foo[2].Bar) != 1 || v.Foo[2].Bar[0] != 84 { t.Fatal(notation.Sprintw(v)) } }) t.Run("list receiver", func(t *testing.T) { var l []struct{ Foo int } u := bind.Bind( &l, bind.NamedValue("foo", 21), bind.NamedValue("foo", 42), bind.NamedValue("foo", 84), ) if len(u) != 0 || len(l) != 3 || l[0].Foo != 21 || l[1].Foo != 42 || l[2].Foo != 84 { t.Fatal() } }) t.Run("list short and cannot be set", func(t *testing.T) { type ( s0 struct{ Bar int } s1 struct{ Foo []s0 } ) v := s1{[]s0{{1}, {2}}} u := bind.Bind( v, bind.NamedValue("foo-bar", 21), bind.NamedValue("foo-bar", 42), bind.NamedValue("foo-bar", 84), ) if len(u) != 3 || len(v.Foo) != 2 || v.Foo[0].Bar != 1 || v.Foo[1].Bar != 2 { t.Fatal(notation.Sprint(u), notation.Sprint(v)) } }) t.Run("list short and gets reset", func(t *testing.T) { type ( s0 struct{ Bar int } s1 struct{ Foo []s0 } ) v := s1{[]s0{{1}, {2}}} u := bind.Bind( &v, bind.NamedValue("foo-bar", 21), bind.NamedValue("foo-bar", 42), bind.NamedValue("foo-bar", 84), ) if len(u) != 0 || len(v.Foo) != 3 || v.Foo[0].Bar != 21 || v.Foo[1].Bar != 42 || v.Foo[2].Bar != 84 { t.Fatal(notation.Sprint(u), notation.Sprint(v)) } }) t.Run("list has invalid type", func(t *testing.T) { type ( s0 struct{ Bar chan int } s1 struct{ Foo []s0 } ) v := s1{[]s0{{nil}, {nil}}} u := bind.Bind( &v, bind.NamedValue("foo-bar", 21), bind.NamedValue("foo-bar", 42), bind.NamedValue("foo-bar", 84), ) if len(u) != 3 { t.Fatal(notation.Sprint(u), notation.Sprint(v)) } }) t.Run("bind scalar map", func(t *testing.T) { m := make(map[string]int) u := bind.Bind(m, bind.NamedValue("foo-bar", 21), bind.NamedValue("baz-qux", 42)) if len(u) != 0 || len(m) != 2 || m["foo-bar"] != 21 || m["baz-qux"] != 42 { t.Fatal() } }) t.Run("scalar map key conversion", func(t *testing.T) { type key string m := make(map[key]int) u := bind.Bind(m, bind.NamedValue("foo", 42)) if len(u) != 0 || len(m) != 1 || m["foo"] != 42 { t.Fatal() } }) t.Run("scalar map pointer key", func(t *testing.T) { m := make(map[*string]int) u := bind.Bind(m, bind.NamedValue("foo", 42)) if len(u) != 0 || len(m) != 1 { t.Fatal() } for key, value := range m { if *key != "foo" || value != 42 { t.Fatal() } } }) t.Run("scalar map list value", func(t *testing.T) { m := make(map[string][]int) u := bind.Bind(m, bind.NamedValue("foo", 21), bind.NamedValue("foo", 42), bind.NamedValue("foo", 84)) if len(u) != 0 || len(m) != 1 || !slices.Equal(m["foo"], []int{21, 42, 84}) { t.Fatal(notation.Sprint(u), notation.Sprint(m)) } }) t.Run("scalar map pointer value", func(t *testing.T) { m := make(map[string]*int) u := bind.Bind(m, bind.NamedValue("foo", 42)) if len(u) != 0 || len(m) != 1 { t.Fatal() } for key, value := range m { if key != "foo" || *value != 42 { t.Fatal() } } }) t.Run("scalar map list pointer value", func(t *testing.T) { m := make(map[string]*[]int) u := bind.Bind(m, bind.NamedValue("foo", 21), bind.NamedValue("foo", 42), bind.NamedValue("foo", 84)) if len(u) != 0 || len(m) != 1 || !slices.Equal(*m["foo"], []int{21, 42, 84}) { t.Fatal() } }) t.Run("allocate scalar map", func(t *testing.T) { type s struct{ Foo map[string]int } var v s u := bind.Bind(&v, bind.NamedValue("foo-bar", 42)) if len(u) != 0 || len(v.Foo) != 1 || v.Foo["bar"] != 42 { t.Fatal() } }) t.Run("scalar map addressing via path", func(t *testing.T) { type s struct{ Foo map[string]int } var v s u := bind.Bind(&v, bind.ValueByPath([]string{"Foo", "Bar"}, 42)) if len(u) != 0 || len(v.Foo) != 1 || v.Foo["Bar"] != 42 { t.Fatal() } }) t.Run("scalar map and too long field path", func(t *testing.T) { m := make(map[string]int) u := bind.Bind(m, bind.ValueByPath([]string{"foo", "bar"}, 42)) if len(u) != 1 { t.Fatal() } }) t.Run("scalar map cannot be set", func(t *testing.T) { type s struct{ Foo map[string]int } var v s u := bind.Bind(v, bind.NamedValue("foo-bar", 42)) if len(u) != 1 { t.Fatal() } }) t.Run("scalar map with wrong value type", func(t *testing.T) { m := make(map[string]int) u := bind.Bind(m, bind.NamedValue("foo", "bar")) if len(u) != 1 { t.Fatal() } }) t.Run("struct fields", func(t *testing.T) { type s struct { Foo int Bar struct{ Baz string } } var v s u := bind.Bind( &v, bind.NamedValue("foo", 42), bind.NamedValue("bar-baz", "qux"), ) if len(u) != 0 || v.Foo != 42 || v.Bar.Baz != "qux" { t.Fatal() } }) t.Run("non-existing field", func(t *testing.T) { type s struct { Foo int Bar struct{ Baz string } } var v s u := bind.Bind( &v, bind.NamedValue("foo", 42), bind.NamedValue("bar-qux", "qux"), ) if len(u) != 1 || u[0].Name() != "bar-qux" || v.Foo != 42 || v.Bar.Baz != "" { t.Fatal() } }) t.Run("too many fields", func(t *testing.T) { type s struct { Foo int Bar struct{ Baz string } } var v s u := bind.Bind( &v, bind.NamedValue("foo", 42), bind.NamedValue("bar-baz", "qux"), bind.NamedValue("bar-baz", "quux"), ) if len(u) != 2 || u[0].Name() != "bar-baz" || u[1].Name() != "bar-baz" || v.Foo != 42 { t.Fatal() } }) t.Run("pointer fields", func(t *testing.T) { type s struct { Foo *int Bar *struct{ Baz *string } Qux *[]struct{ Quux string } } var v s u := bind.Bind( &v, bind.NamedValue("foo", 42), bind.NamedValue("bar-baz", "qux"), bind.NamedValue("qux-quux", "corge"), ) if len(u) != 0 || *v.Foo != 42 || *v.Bar.Baz != "qux" || len(*v.Qux) != 1 || (*v.Qux)[0].Quux != "corge" { t.Fatal() } }) t.Run("pointer field with invalid value", func(t *testing.T) { type s struct{ Foo *struct{ Bar int } } var v s u := bind.Bind( &v, bind.NamedValue("foo-bar", "baz"), ) if len(u) != 1 { t.Fatal() } }) t.Run("unsupported pointer fields", func(t *testing.T) { type s struct { Foo *int Bar *chan int } var v s u := bind.Bind( &v, bind.NamedValue("foo", 42), bind.NamedValue("bar", "qux"), bind.NamedValue("bar-baz", "corge"), ) sortFields(u) if len(u) != 2 || u[0].Name() != "bar" || u[1].Name() != "bar-baz" || *v.Foo != 42 { t.Fatal(notation.Sprint(u), notation.Sprint(v)) } }) t.Run("struct fields by path", func(t *testing.T) { type s struct { Foo int Bar struct{ Baz string } } var v s u := bind.Bind( &v, bind.ValueByPath([]string{"Foo"}, 42), bind.ValueByPath([]string{"Bar", "Baz"}, "qux"), ) if len(u) != 0 || v.Foo != 42 || v.Bar.Baz != "qux" { t.Fatal() } }) t.Run("cannot set field", func(t *testing.T) { type s struct{ Foo int } var v s u := bind.Bind(v, bind.NamedValue("foo", 42)) if len(u) != 1 { t.Fatal() } }) t.Run("struct with anonymous field", func(t *testing.T) { type ( s0 struct{ Foo int } s1 struct{ s0 } ) var v s1 u := bind.Bind(&v, bind.NamedValue("foo", 42)) if len(u) != 0 || v.Foo != 42 { t.Fatal() } }) t.Run("receiver cannot be set", func(t *testing.T) { type s struct{ Foo *struct{ Bar int } } var v s u := bind.Bind(v, bind.NamedValue("foo-bar", 42)) if len(u) != 1 { t.Fatal() } }) t.Run("receiver not supported", func(t *testing.T) { v := make(chan int) u := bind.Bind(&v, bind.NamedValue("foo-bar", 42)) if len(u) != 1 { t.Fatal() } }) t.Run("empty receiver", func(t *testing.T) { var v any u := bind.Bind(&v, bind.NamedValue("foo", 42)) if len(u) != 1 { t.Fatal() } }) t.Run("nil value", func(t *testing.T) { type s struct{ Foo any } v := s{42} u := bind.Bind(&v, bind.NamedValue("foo", nil)) if len(u) != 0 || v.Foo != nil { t.Fatal() } }) t.Run("nil receiver", func(t *testing.T) { u := bind.Bind(nil, bind.NamedValue("foo", nil)) if len(u) != 1 { t.Fatal() } }) t.Run("ambigously named fields", func(t *testing.T) { type s struct { FooBar int Foo struct{ Bar int } } var v s u := bind.Bind(&v, bind.NamedValue("foo-bar", 42)) if len(u) != 0 || v.FooBar != 42 || v.Foo.Bar != 42 { t.Fatal(notation.Sprint(u), notation.Sprint(v)) } }) t.Run("scalar map with invalid field type", func(t *testing.T) { v := make(map[string]int) u := bind.Bind(v, bind.NamedValue("foo", "bar")) if len(u) != 1 { t.Fatal() } }) t.Run("unpack interfaces", func(t *testing.T) { type s struct{ Foo time.Duration } var v s var str fmt.Stringer str = time.Second u := bind.Bind(&v, bind.NamedValue("foo", &str)) if len(u) != 0 || v.Foo != time.Second { t.Fatal() } }) }) t.Run("bind fields create", func(t *testing.T) { t.Run("circular type", func(t *testing.T) { type s struct { Foo int Bar *s } _, u := bind.CreateAndBind[s](bind.NamedValue("foo", 42)) if len(u) != 1 { t.Fatal() } }) t.Run("type does not accept fields", func(t *testing.T) { _, u := bind.CreateAndBind[[]int](bind.NamedValue("foo", 42)) if len(u) != 1 { t.Fatal() } }) t.Run("zero value when no fields were bound", func(t *testing.T) { type s struct{ Foo int } v, u := bind.CreateAndBind[*s](bind.NamedValue("bar", 42)) if len(u) != 1 || v != nil { t.Fatal() } }) t.Run("create receiver", func(t *testing.T) { type s struct{ Foo int } v, u := bind.CreateAndBind[*s](bind.NamedValue("foo", 42)) if len(u) != 0 || v == nil || v.Foo != 42 { t.Fatal() } }) t.Run("any type", func(t *testing.T) { _, u := bind.CreateAndBind[any](bind.NamedValue("foo", 42)) if len(u) != 1 { t.Fatal() } }) }) t.Run("bind fields create with reflection type", func(t *testing.T) { type s struct{ Foo int } typ := reflect.TypeFor[s]() v, u := bind.CreateAndBindFor(typ, bind.NamedValue("foo", 42)) if len(u) != 0 || v.Interface().(s).Foo != 42 { t.Fatal() } }) }