From c27b9c2daa364981e3c248b24128e4e595ce8889 Mon Sep 17 00:00:00 2001 From: Arpad Ryszka Date: Wed, 3 Sep 2025 23:52:33 +0200 Subject: [PATCH] testing --- field_test.go | 48 ++++++++++++++++++++++++++ lib.go | 1 + lib_test.go | 94 ++++++++++++++++++++++++++++++++++++++++++++++++++ scalar_test.go | 7 ++++ scan_test.go | 7 ++++ type_test.go | 66 +++++++++++++++++++++++++++++++++++ 6 files changed, 223 insertions(+) create mode 100644 lib_test.go diff --git a/field_test.go b/field_test.go index 1252b4d..5415f40 100644 --- a/field_test.go +++ b/field_test.go @@ -7,6 +7,8 @@ import ( "sort" "strings" "testing" + "time" + "fmt" ) func TestField(t *testing.T) { @@ -136,6 +138,41 @@ func TestField(t *testing.T) { 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("field values", func(t *testing.T) { @@ -868,6 +905,17 @@ func TestField(t *testing.T) { 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.BindFields(&v, bind.NamedValue("foo", &str)) + if len(u) != 0 || v.Foo != time.Second { + t.Fatal() + } + }) }) t.Run("bind fields create", func(t *testing.T) { diff --git a/lib.go b/lib.go index 9754e49..f31f730 100644 --- a/lib.go +++ b/lib.go @@ -21,6 +21,7 @@ const ( Uintptr FieldType = reflect.Uintptr Float32 FieldType = reflect.Float32 Float64 FieldType = reflect.Float64 + String FieldType = reflect.String Any FieldType = reflect.Interface Struct FieldType = reflect.Struct Duration FieldType = 0xfffe diff --git a/lib_test.go b/lib_test.go new file mode 100644 index 0000000..c03e232 --- /dev/null +++ b/lib_test.go @@ -0,0 +1,94 @@ +package bind_test + +import ( + "testing" + "code.squareroundforest.org/arpio/bind" +) + +func TestLib(t *testing.T) { + t.Run("field", func(t *testing.T) { + t.Run("type", func(t *testing.T) { + t.Run("not from input", func(t *testing.T) { + v := struct{Foo int}{42} + f := bind.FieldValues(v) + if len(f) != 1 || f[0].Type() != bind.Int { + t.Fatal() + } + }) + + t.Run("nil", func(t *testing.T) { + f := bind.NamedValue("foo", nil) + if f.Type() != bind.Any { + t.Fatal() + } + }) + + t.Run("circular type", func(t *testing.T) { + type p *p + var v p + v = &v + f := bind.NamedValue("foo", v) + if f.Type() != bind.Any { + t.Fatal() + } + }) + + t.Run("direct", func(t *testing.T) { + f := bind.NamedValue("foo", 42) + if f.Type() != bind.Int { + t.Fatal() + } + }) + + t.Run("unpacked", func(t *testing.T) { + var v int + f := bind.NamedValue("foo", &v) + if f.Type() != bind.Int { + t.Fatal() + } + }) + }) + + t.Run("name and path", func(t *testing.T) { + t.Run("returns path", func(t *testing.T) { + f := bind.ValueByPath([]string{"Foo", "Bar"}, 42) + p := f.Path() + if len(p) != 2 || p[0] != "Foo" || p[1] != "Bar" { + t.Fatal() + } + }) + + t.Run("cannot change path", func(t *testing.T) { + f := bind.ValueByPath([]string{"Foo", "Bar"}, 42) + p := f.Path() + p[1] = "Baz" + p = f.Path() + if p[1] != "Bar" { + t.Fatal() + } + }) + + t.Run("has name", func(t *testing.T) { + f := bind.NamedValue("foo-bar", 42) + if f.Name() != "foo-bar" { + t.Fatal() + } + }) + + t.Run("has path", func(t *testing.T) { + f := bind.ValueByPath([]string{"Foo", "Bar"}, 42) + if f.Name() != "foo-bar" { + t.Fatal() + } + }) + + t.Run("no name and no path", func(t *testing.T) { + f := bind.ValueByPath(nil, 42) + if f.Name() != "" { + t.Fatal() + } + }) + + }) + }) +} diff --git a/scalar_test.go b/scalar_test.go index 2a0c3b9..0f06e58 100644 --- a/scalar_test.go +++ b/scalar_test.go @@ -165,6 +165,13 @@ func TestScalar(t *testing.T) { } }) + t.Run("nil value and non-nillable receiver", func(t *testing.T) { + var v int + if bind.BindScalar(&v, nil) { + t.Fatal() + } + }) + t.Run("nil receiver", func(t *testing.T) { if bind.BindScalar(nil, 42) { t.Fatal() diff --git a/scan_test.go b/scan_test.go index 3b51e47..d52af5d 100644 --- a/scan_test.go +++ b/scan_test.go @@ -144,4 +144,11 @@ func TestScan(t *testing.T) { t.Fatal(tim) } }) + + t.Run("time invalid", func(t *testing.T) { + var tim time.Time + if bind.BindScalar(&tim, "foo") { + t.Fatal() + } + }) } diff --git a/type_test.go b/type_test.go index 8be1b63..f40c648 100644 --- a/type_test.go +++ b/type_test.go @@ -357,4 +357,70 @@ func TestTypeChecks(t *testing.T) { } }) }) + + t.Run("accept", func(t *testing.T) { + t.Run("scalar", func(t *testing.T) { + t.Run("yes", func(t *testing.T) { + if !bind.AcceptsScalar[int]() { + t.Fatal() + } + }) + + t.Run("no", func(t *testing.T) { + if bind.AcceptsScalar[chan int]() { + t.Fatal() + } + }) + + t.Run("circular", func(t *testing.T) { + type p *p + if bind.AcceptsScalar[p]() { + t.Fatal() + } + }) + }) + + t.Run("fields", func(t *testing.T) { + t.Run("yes", func(t *testing.T) { + type s struct{Foo int} + if !bind.AcceptsFields[s]() { + t.Fatal() + } + }) + + t.Run("no", func(t *testing.T) { + if bind.AcceptsFields[chan int]() { + t.Fatal() + } + }) + + t.Run("circular", func(t *testing.T) { + type p *p + if bind.AcceptsFields[p]() { + t.Fatal() + } + }) + }) + + t.Run("list", func(t *testing.T) { + t.Run("yes", func(t *testing.T) { + if !bind.AcceptsList[[]int]() { + t.Fatal() + } + }) + + t.Run("no", func(t *testing.T) { + if bind.AcceptsList[int]() { + t.Fatal() + } + }) + + t.Run("circular", func(t *testing.T) { + type p *p + if bind.AcceptsList[p]() { + t.Fatal() + } + }) + }) + }) }