2025-08-27 21:03:25 +02:00
|
|
|
package bind_test
|
|
|
|
|
|
|
|
|
|
import (
|
|
|
|
|
"code.squareroundforest.org/arpio/bind"
|
|
|
|
|
"slices"
|
|
|
|
|
"testing"
|
|
|
|
|
)
|
|
|
|
|
|
|
|
|
|
type valuer interface {
|
|
|
|
|
value() int
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
type counter interface {
|
|
|
|
|
count() int
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
type countedSlice []int
|
|
|
|
|
|
|
|
|
|
type valueInt int
|
|
|
|
|
|
|
|
|
|
func (s countedSlice) count() int {
|
|
|
|
|
return len(s)
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
func (i *valueInt) value() int {
|
|
|
|
|
return int(*i)
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
func TestScalar(t *testing.T) {
|
|
|
|
|
t.Run("bind scalar", func(t *testing.T) {
|
|
|
|
|
t.Run("no value", func(t *testing.T) {
|
|
|
|
|
var i int
|
|
|
|
|
if bind.BindScalar(&i) {
|
|
|
|
|
t.Fatal()
|
|
|
|
|
}
|
|
|
|
|
})
|
|
|
|
|
|
|
|
|
|
t.Run("not scalar", func(t *testing.T) {
|
|
|
|
|
var s struct{ Foo int }
|
|
|
|
|
if bind.BindScalar(&s, "42") {
|
|
|
|
|
t.Fatal()
|
|
|
|
|
}
|
|
|
|
|
})
|
|
|
|
|
|
|
|
|
|
t.Run("cannot scan", func(t *testing.T) {
|
|
|
|
|
var i int
|
|
|
|
|
if bind.BindScalar(i, "foo") {
|
|
|
|
|
t.Fatal()
|
|
|
|
|
}
|
|
|
|
|
})
|
|
|
|
|
|
|
|
|
|
t.Run("receiver cannot be set", func(t *testing.T) {
|
|
|
|
|
var i int
|
|
|
|
|
if bind.BindScalar(i, "42") {
|
|
|
|
|
t.Fatal()
|
|
|
|
|
}
|
|
|
|
|
})
|
|
|
|
|
|
|
|
|
|
t.Run("one value set", func(t *testing.T) {
|
|
|
|
|
var i int
|
|
|
|
|
if !bind.BindScalar(&i, "42") || i != 42 {
|
|
|
|
|
t.Fatal(i)
|
|
|
|
|
}
|
|
|
|
|
})
|
|
|
|
|
|
|
|
|
|
t.Run("multiple values, not slice", func(t *testing.T) {
|
|
|
|
|
var i int
|
|
|
|
|
if bind.BindScalar(&i, "21", "42", "84") {
|
|
|
|
|
t.Fatal()
|
|
|
|
|
}
|
|
|
|
|
})
|
|
|
|
|
|
|
|
|
|
t.Run("multiple values, small slice", func(t *testing.T) {
|
|
|
|
|
s := make([]int, 2)
|
|
|
|
|
if bind.BindScalar(&s, "21", "42", "84") {
|
|
|
|
|
t.Fatal()
|
|
|
|
|
}
|
|
|
|
|
})
|
|
|
|
|
|
|
|
|
|
t.Run("multiple values set", func(t *testing.T) {
|
|
|
|
|
s := make([]int, 3)
|
|
|
|
|
if !bind.BindScalar(&s, "21", "42", "84") || !slices.Equal(s, []int{21, 42, 84}) {
|
|
|
|
|
t.Fatal()
|
|
|
|
|
}
|
|
|
|
|
})
|
|
|
|
|
|
|
|
|
|
t.Run("multiple values set, larger slice", func(t *testing.T) {
|
|
|
|
|
s := make([]int, 4)
|
|
|
|
|
if !bind.BindScalar(&s, "21", "42", "84") || !slices.Equal(s, []int{21, 42, 84, 0}) {
|
|
|
|
|
t.Fatal()
|
|
|
|
|
}
|
|
|
|
|
})
|
|
|
|
|
|
|
|
|
|
t.Run("multiple values, cannot scan", func(t *testing.T) {
|
|
|
|
|
s := make([]int, 3)
|
|
|
|
|
if bind.BindScalar(&s, "21", "42", "foo") {
|
|
|
|
|
t.Fatal()
|
|
|
|
|
}
|
|
|
|
|
})
|
|
|
|
|
|
|
|
|
|
t.Run("set item of a slice", func(t *testing.T) {
|
|
|
|
|
s := []int{21, 42, 84}
|
|
|
|
|
if !bind.BindScalar(&s, "27") || !slices.Equal(s, []int{27, 42, 84}) {
|
|
|
|
|
t.Fatal(s)
|
|
|
|
|
}
|
|
|
|
|
})
|
|
|
|
|
|
|
|
|
|
t.Run("interface receiver", func(t *testing.T) {
|
|
|
|
|
var i any
|
|
|
|
|
if !bind.BindScalar(&i, 42) || i != 42 {
|
|
|
|
|
t.Fatal(i)
|
|
|
|
|
}
|
|
|
|
|
})
|
|
|
|
|
|
|
|
|
|
t.Run("interface receiver has value", func(t *testing.T) {
|
|
|
|
|
var (
|
|
|
|
|
i int
|
|
|
|
|
iface any
|
|
|
|
|
)
|
|
|
|
|
|
|
|
|
|
i = 21
|
|
|
|
|
iface = &i
|
|
|
|
|
if ok := bind.BindScalar(&iface, "42"); !ok || iface != "42" || i != 21 {
|
|
|
|
|
t.Fatal(ok, iface)
|
|
|
|
|
}
|
|
|
|
|
})
|
|
|
|
|
|
|
|
|
|
t.Run("wrapped with non-empty interface", func(t *testing.T) {
|
|
|
|
|
// this could work in theory, but fails on checking the type of the receiver
|
|
|
|
|
// we leave the test undefiend, and checking only for no panic
|
|
|
|
|
var iface valuer
|
|
|
|
|
i := valueInt(21)
|
|
|
|
|
p := &i
|
|
|
|
|
iface = p
|
|
|
|
|
ok := bind.BindScalar(&iface, "42")
|
|
|
|
|
if ok != (i == 42) {
|
|
|
|
|
t.Fatal()
|
|
|
|
|
}
|
|
|
|
|
})
|
|
|
|
|
|
|
|
|
|
t.Run("slice wrapped by empty interface", func(t *testing.T) {
|
|
|
|
|
var iface any
|
|
|
|
|
s := make([]int, 3)
|
|
|
|
|
iface = s
|
|
|
|
|
if ok := bind.BindScalar(&iface, "21", "42", "84"); !ok || !slices.Equal(s, []int{21, 42, 84}) {
|
|
|
|
|
t.Fatal()
|
|
|
|
|
}
|
|
|
|
|
})
|
2025-08-28 05:04:06 +02:00
|
|
|
|
|
|
|
|
t.Run("value has circular reference", func(t *testing.T) {
|
|
|
|
|
var r any
|
|
|
|
|
var v any
|
|
|
|
|
p := &v
|
|
|
|
|
*p = p
|
|
|
|
|
if bind.BindScalar(&r, p) {
|
|
|
|
|
t.Fatal()
|
|
|
|
|
}
|
|
|
|
|
})
|
2025-08-27 21:03:25 +02:00
|
|
|
})
|
|
|
|
|
|
|
|
|
|
t.Run("bind scalar with create", func(t *testing.T) {
|
|
|
|
|
t.Run("no value", func(t *testing.T) {
|
|
|
|
|
if _, ok := bind.BindScalarCreate[int](); ok {
|
|
|
|
|
t.Fatal()
|
|
|
|
|
}
|
|
|
|
|
})
|
|
|
|
|
|
|
|
|
|
t.Run("does not accept scalar", func(t *testing.T) {
|
2025-08-28 05:04:06 +02:00
|
|
|
if _, ok := bind.BindScalarCreate[struct{ Foo int }]("42"); ok {
|
2025-08-27 21:03:25 +02:00
|
|
|
t.Fatal()
|
|
|
|
|
}
|
|
|
|
|
})
|
|
|
|
|
|
|
|
|
|
t.Run("empty interface", func(t *testing.T) {
|
|
|
|
|
if v, ok := bind.BindScalarCreate[any]("42"); !ok || v != "42" {
|
|
|
|
|
t.Fatal()
|
|
|
|
|
}
|
|
|
|
|
})
|
|
|
|
|
|
|
|
|
|
t.Run("scalar", func(t *testing.T) {
|
|
|
|
|
if v, ok := bind.BindScalarCreate[int]("42"); !ok || v != 42 {
|
|
|
|
|
t.Fatal()
|
|
|
|
|
}
|
|
|
|
|
})
|
|
|
|
|
|
|
|
|
|
t.Run("slice", func(t *testing.T) {
|
|
|
|
|
if v, ok := bind.BindScalarCreate[[]int]("21", "42", "84"); !ok || !slices.Equal(v, []int{21, 42, 84}) {
|
|
|
|
|
t.Fatal()
|
|
|
|
|
}
|
|
|
|
|
})
|
|
|
|
|
|
|
|
|
|
t.Run("slice with non-scalar type", func(t *testing.T) {
|
|
|
|
|
if _, ok := bind.BindScalarCreate[[]func(int)]("21", "42", "84"); ok {
|
|
|
|
|
t.Fatal()
|
|
|
|
|
}
|
|
|
|
|
})
|
|
|
|
|
|
|
|
|
|
t.Run("pointer to non-scalar", func(t *testing.T) {
|
|
|
|
|
if _, ok := bind.BindScalarCreate[*func()]("42"); ok {
|
|
|
|
|
t.Fatal()
|
|
|
|
|
}
|
|
|
|
|
})
|
|
|
|
|
|
|
|
|
|
t.Run("pointer", func(t *testing.T) {
|
|
|
|
|
if v, ok := bind.BindScalarCreate[*int]("42"); !ok || *v != 42 {
|
|
|
|
|
t.Fatal()
|
|
|
|
|
}
|
|
|
|
|
})
|
|
|
|
|
|
|
|
|
|
t.Run("unscannable", func(t *testing.T) {
|
|
|
|
|
if _, ok := bind.BindScalarCreate[int]("foo"); ok {
|
|
|
|
|
t.Fatal()
|
|
|
|
|
}
|
|
|
|
|
})
|
2025-08-28 05:04:06 +02:00
|
|
|
|
|
|
|
|
t.Run("receiver has circular type", func(t *testing.T) {
|
|
|
|
|
type s []s
|
|
|
|
|
if _, ok := bind.BindScalarCreate[s]("foo"); ok {
|
|
|
|
|
t.Fatal()
|
|
|
|
|
}
|
|
|
|
|
})
|
2025-08-31 01:23:21 +02:00
|
|
|
|
2025-08-28 05:04:06 +02:00
|
|
|
t.Run("value has circular reference", func(t *testing.T) {
|
|
|
|
|
var v any
|
|
|
|
|
p := &v
|
|
|
|
|
*p = p
|
|
|
|
|
if _, ok := bind.BindScalarCreate[any](p); ok {
|
|
|
|
|
t.Fatal()
|
|
|
|
|
}
|
|
|
|
|
})
|
2025-08-27 21:03:25 +02:00
|
|
|
})
|
|
|
|
|
}
|