package bind_test import ( "code.squareroundforest.org/arpio/bind" "testing" ) func TestTypeChecks(t *testing.T) { t.Run("accepts scalar", func(t *testing.T) { t.Run("bool", func(t *testing.T) { if !bind.AcceptsScalar[bool]() { t.Fatal() } }) t.Run("int", func(t *testing.T) { if !bind.AcceptsScalar[int]() { t.Fatal() } }) t.Run("uint", func(t *testing.T) { if !bind.AcceptsScalar[uint]() { t.Fatal() } }) t.Run("float", func(t *testing.T) { if !bind.AcceptsScalar[int]() { t.Fatal() } }) t.Run("string", func(t *testing.T) { if !bind.AcceptsScalar[bool]() { t.Fatal() } }) t.Run("any", func(t *testing.T) { if !bind.AcceptsScalar[any]() { t.Fatal() } }) t.Run("pointer", func(t *testing.T) { type p *int if !bind.AcceptsScalar[p]() { t.Fatal() } }) t.Run("slice", func(t *testing.T) { type s []int if !bind.AcceptsScalar[s]() { t.Fatal() } }) t.Run("pointer and slice combined", func(t *testing.T) { type c *[]*[]int if !bind.AcceptsScalar[c]() { t.Fatal() } }) t.Run("struct", func(t *testing.T) { type s struct{ Foo int } if bind.AcceptsScalar[s]() { t.Fatal() } }) t.Run("map", func(t *testing.T) { if bind.AcceptsScalar[map[string]int]() { t.Fatal() } }) t.Run("interface with methods", func(t *testing.T) { type i interface{ Foo(int) } if bind.AcceptsScalar[i]() { t.Fatal() } }) t.Run("func", func(t *testing.T) { if bind.AcceptsScalar[func(int)]() { t.Fatal() } }) t.Run("chan", func(t *testing.T) { if bind.AcceptsScalar[chan int]() { t.Fatal() } }) }) t.Run("accepts fields", func(t *testing.T) { t.Run("struct", func(t *testing.T) { type s struct{ Foo int } if !bind.AcceptsFields[s]() { t.Fatal() } }) t.Run("map", func(t *testing.T) { if !bind.AcceptsFields[map[string]int]() { t.Fatal() } }) t.Run("map with interface fields", func(t *testing.T) { if !bind.AcceptsFields[map[string]any]() { t.Fatal() } }) t.Run("map with list fields", func(t *testing.T) { if !bind.AcceptsFields[map[string][]int]() { t.Fatal() } }) t.Run("pointer", func(t *testing.T) { type p *struct{ Foo int } if !bind.AcceptsFields[p]() { t.Fatal() } }) t.Run("slice", func(t *testing.T) { type s []struct{ Foo int } if !bind.AcceptsFields[s]() { t.Fatal() } }) t.Run("pointer and slice combined", func(t *testing.T) { type c *[]*[]struct{ Foo int } if !bind.AcceptsFields[c]() { t.Fatal() } }) t.Run("wrong map key", func(t *testing.T) { if bind.AcceptsFields[map[int]int]() { t.Fatal() } }) t.Run("wrong map value", func(t *testing.T) { if bind.AcceptsFields[map[string]struct{ Foo int }]() { t.Fatal() } }) t.Run("scalar", func(t *testing.T) { if bind.AcceptsFields[int]() { t.Fatal() } }) t.Run("interface", func(t *testing.T) { type i interface{ Foo(int) } if bind.AcceptsFields[i]() { t.Fatal() } }) t.Run("any type", func(t *testing.T) { if bind.AcceptsFields[any]() { t.Fatal() } }) t.Run("func", func(t *testing.T) { if bind.AcceptsFields[func(int)]() { t.Fatal() } }) t.Run("chan", func(t *testing.T) { if bind.AcceptsFields[chan int]() { t.Fatal() } }) }) t.Run("accepts list", func(t *testing.T) { t.Run("scalars", func(t *testing.T) { if !bind.AcceptsList[[]int]() { t.Fatal() } }) t.Run("structs", func(t *testing.T) { if !bind.AcceptsList[[]struct{ Foo int }]() { t.Fatal() } }) t.Run("maps", func(t *testing.T) { if !bind.AcceptsList[[]map[string]int]() { t.Fatal() } }) t.Run("pointer to list", func(t *testing.T) { if !bind.AcceptsList[*[]int]() { t.Fatal() } }) t.Run("scalar", func(t *testing.T) { if bind.AcceptsList[int]() { t.Fatal() } }) t.Run("struct", func(t *testing.T) { if bind.AcceptsList[struct{ Foo int }]() { t.Fatal() } }) t.Run("map", func(t *testing.T) { if bind.AcceptsList[map[string]int]() { t.Fatal() } }) t.Run("map", func(t *testing.T) { if bind.AcceptsList[map[string]int]() { t.Fatal() } }) t.Run("struct pointer", func(t *testing.T) { if bind.AcceptsList[*struct{ Foo int }]() { t.Fatal() } }) t.Run("wrong elem type", func(t *testing.T) { if bind.AcceptsList[map[string]struct{ Foo int }]() { t.Fatal() } }) }) t.Run("bindable", func(t *testing.T) { t.Run("scalar", func(t *testing.T) { if !bind.Bindable[int]() { t.Fatal() } }) t.Run("struct", func(t *testing.T) { if !bind.Bindable[struct{ Foo int }]() { t.Fatal() } }) t.Run("func", func(t *testing.T) { if bind.Bindable[func()]() { t.Fatal() } }) t.Run("chan", func(t *testing.T) { if bind.Bindable[chan int]() { t.Fatal() } }) }) t.Run("circular type", func(t *testing.T) { t.Run("via pointer", func(t *testing.T) { type p *p if bind.Bindable[p]() { t.Fatal() } }) t.Run("via slice", func(t *testing.T) { type s []s if bind.Bindable[s]() { t.Fatal() } }) t.Run("pointer via struct field", func(t *testing.T) { type s struct{ f *s } if bind.Bindable[s]() { t.Fatal() } }) t.Run("slice via struct field", func(t *testing.T) { type s struct{ f []s } if bind.Bindable[s]() { t.Fatal() } }) }) t.Run("circular reference", func(t *testing.T) { t.Run("via pointer", func(t *testing.T) { p := new(any) *p = p if bind.BindScalar(p, "42") { t.Fatal() } }) t.Run("via slice", func(t *testing.T) { s := make([]any, 1) s[0] = s if bind.BindScalar(s, "42") { t.Fatal() } }) t.Run("via interface and pointer", func(t *testing.T) { var v any v = &v if bind.BindScalar(v, "42") { t.Fatal() } }) t.Run("via struct field and pointer", func(t *testing.T) { type s struct{ F *s } var v s v.F = &v if len(bind.FieldValues(v)) > 0 { t.Fatal() } }) t.Run("via struct field and slice", func(t *testing.T) { type s struct{ F []s } var v s v.F = []s{v} if len(bind.FieldValues(v)) > 0 { t.Fatal() } }) t.Run("value with circular type", func(t *testing.T) { type p *p var v p if len(bind.FieldValues(v)) > 0 { t.Fatal() } }) }) }