1 // Copyright 2011 The Go Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style
3 // license that can be found in the LICENSE file.
18 var someTime
= time
.Unix(123, 0)
23 userDefinedSlice
[]int
24 userDefinedString
string
27 type conversionTest
struct {
28 s
, d
interface{} // source and destination
30 // following are used if they're non-zero
39 wantbool
bool // used if d is of type *bool
42 wantptr
*int64 // if non-nil, *d's pointed value must be equal to *wantptr
43 wantnil
bool // if true, *d must be *int64(nil)
44 wantusrdef userDefined
45 wantusrstr userDefinedString
48 // Target variables for scanning into.
67 func conversionTests() []conversionTest
{
68 // Return a fresh instance to test so "go test -count 2" works correctly.
69 return []conversionTest
{
70 // Exact conversions (destination pointer type matches source type)
71 {s
: "foo", d
: &scanstr
, wantstr
: "foo"},
72 {s
: 123, d
: &scanint
, wantint
: 123},
73 {s
: someTime
, d
: &scantime
, wanttime
: someTime
},
76 {s
: "string", d
: &scanstr
, wantstr
: "string"},
77 {s
: []byte("byteslice"), d
: &scanstr
, wantstr
: "byteslice"},
78 {s
: 123, d
: &scanstr
, wantstr
: "123"},
79 {s
: int8(123), d
: &scanstr
, wantstr
: "123"},
80 {s
: int64(123), d
: &scanstr
, wantstr
: "123"},
81 {s
: uint8(123), d
: &scanstr
, wantstr
: "123"},
82 {s
: uint16(123), d
: &scanstr
, wantstr
: "123"},
83 {s
: uint32(123), d
: &scanstr
, wantstr
: "123"},
84 {s
: uint64(123), d
: &scanstr
, wantstr
: "123"},
85 {s
: 1.5, d
: &scanstr
, wantstr
: "1.5"},
88 {s
: time
.Unix(1, 0).UTC(), d
: &scanstr
, wantstr
: "1970-01-01T00:00:01Z"},
89 {s
: time
.Unix(1453874597, 0).In(time
.FixedZone("here", -3600*8)), d
: &scanstr
, wantstr
: "2016-01-26T22:03:17-08:00"},
90 {s
: time
.Unix(1, 2).UTC(), d
: &scanstr
, wantstr
: "1970-01-01T00:00:01.000000002Z"},
91 {s
: time
.Time
{}, d
: &scanstr
, wantstr
: "0001-01-01T00:00:00Z"},
92 {s
: time
.Unix(1, 2).UTC(), d
: &scanbytes
, wantbytes
: []byte("1970-01-01T00:00:01.000000002Z")},
93 {s
: time
.Unix(1, 2).UTC(), d
: &scaniface
, wantiface
: time
.Unix(1, 2).UTC()},
96 {s
: nil, d
: &scanbytes
, wantbytes
: nil},
97 {s
: "string", d
: &scanbytes
, wantbytes
: []byte("string")},
98 {s
: []byte("byteslice"), d
: &scanbytes
, wantbytes
: []byte("byteslice")},
99 {s
: 123, d
: &scanbytes
, wantbytes
: []byte("123")},
100 {s
: int8(123), d
: &scanbytes
, wantbytes
: []byte("123")},
101 {s
: int64(123), d
: &scanbytes
, wantbytes
: []byte("123")},
102 {s
: uint8(123), d
: &scanbytes
, wantbytes
: []byte("123")},
103 {s
: uint16(123), d
: &scanbytes
, wantbytes
: []byte("123")},
104 {s
: uint32(123), d
: &scanbytes
, wantbytes
: []byte("123")},
105 {s
: uint64(123), d
: &scanbytes
, wantbytes
: []byte("123")},
106 {s
: 1.5, d
: &scanbytes
, wantbytes
: []byte("1.5")},
109 {s
: nil, d
: &scanraw
, wantraw
: nil},
110 {s
: []byte("byteslice"), d
: &scanraw
, wantraw
: RawBytes("byteslice")},
111 {s
: "string", d
: &scanraw
, wantraw
: RawBytes("string")},
112 {s
: 123, d
: &scanraw
, wantraw
: RawBytes("123")},
113 {s
: int8(123), d
: &scanraw
, wantraw
: RawBytes("123")},
114 {s
: int64(123), d
: &scanraw
, wantraw
: RawBytes("123")},
115 {s
: uint8(123), d
: &scanraw
, wantraw
: RawBytes("123")},
116 {s
: uint16(123), d
: &scanraw
, wantraw
: RawBytes("123")},
117 {s
: uint32(123), d
: &scanraw
, wantraw
: RawBytes("123")},
118 {s
: uint64(123), d
: &scanraw
, wantraw
: RawBytes("123")},
119 {s
: 1.5, d
: &scanraw
, wantraw
: RawBytes("1.5")},
120 // time.Time has been placed here to check that the RawBytes slice gets
121 // correctly reset when calling time.Time.AppendFormat.
122 {s
: time
.Unix(2, 5).UTC(), d
: &scanraw
, wantraw
: RawBytes("1970-01-01T00:00:02.000000005Z")},
124 // Strings to integers
125 {s
: "255", d
: &scanuint8
, wantuint
: 255},
126 {s
: "256", d
: &scanuint8
, wanterr
: "converting driver.Value type string (\"256\") to a uint8: value out of range"},
127 {s
: "256", d
: &scanuint16
, wantuint
: 256},
128 {s
: "-1", d
: &scanint
, wantint
: -1},
129 {s
: "foo", d
: &scanint
, wanterr
: "converting driver.Value type string (\"foo\") to a int: invalid syntax"},
131 // int64 to smaller integers
132 {s
: int64(5), d
: &scanuint8
, wantuint
: 5},
133 {s
: int64(256), d
: &scanuint8
, wanterr
: "converting driver.Value type int64 (\"256\") to a uint8: value out of range"},
134 {s
: int64(256), d
: &scanuint16
, wantuint
: 256},
135 {s
: int64(65536), d
: &scanuint16
, wanterr
: "converting driver.Value type int64 (\"65536\") to a uint16: value out of range"},
138 {s
: true, d
: &scanbool
, wantbool
: true},
139 {s
: "True", d
: &scanbool
, wantbool
: true},
140 {s
: "TRUE", d
: &scanbool
, wantbool
: true},
141 {s
: "1", d
: &scanbool
, wantbool
: true},
142 {s
: 1, d
: &scanbool
, wantbool
: true},
143 {s
: int64(1), d
: &scanbool
, wantbool
: true},
144 {s
: uint16(1), d
: &scanbool
, wantbool
: true},
147 {s
: false, d
: &scanbool
, wantbool
: false},
148 {s
: "false", d
: &scanbool
, wantbool
: false},
149 {s
: "FALSE", d
: &scanbool
, wantbool
: false},
150 {s
: "0", d
: &scanbool
, wantbool
: false},
151 {s
: 0, d
: &scanbool
, wantbool
: false},
152 {s
: int64(0), d
: &scanbool
, wantbool
: false},
153 {s
: uint16(0), d
: &scanbool
, wantbool
: false},
156 {s
: "yup", d
: &scanbool
, wanterr
: `sql/driver: couldn't convert "yup" into type bool`},
157 {s
: 2, d
: &scanbool
, wanterr
: `sql/driver: couldn't convert 2 into type bool`},
160 {s
: float64(1.5), d
: &scanf64
, wantf64
: float64(1.5)},
161 {s
: int64(1), d
: &scanf64
, wantf64
: float64(1)},
162 {s
: float64(1.5), d
: &scanf32
, wantf32
: float32(1.5)},
163 {s
: "1.5", d
: &scanf32
, wantf32
: float32(1.5)},
164 {s
: "1.5", d
: &scanf64
, wantf64
: float64(1.5)},
167 {s
: interface{}(nil), d
: &scanptr
, wantnil
: true},
168 {s
: int64(42), d
: &scanptr
, wantptr
: &answer
},
171 {s
: float64(1.5), d
: &scaniface
, wantiface
: float64(1.5)},
172 {s
: int64(1), d
: &scaniface
, wantiface
: int64(1)},
173 {s
: "str", d
: &scaniface
, wantiface
: "str"},
174 {s
: []byte("byteslice"), d
: &scaniface
, wantiface
: []byte("byteslice")},
175 {s
: true, d
: &scaniface
, wantiface
: true},
176 {s
: nil, d
: &scaniface
},
177 {s
: []byte(nil), d
: &scaniface
, wantiface
: []byte(nil)},
179 // To a user-defined type
180 {s
: 1.5, d
: new(userDefined
), wantusrdef
: 1.5},
181 {s
: int64(123), d
: new(userDefined
), wantusrdef
: 123},
182 {s
: "1.5", d
: new(userDefined
), wantusrdef
: 1.5},
183 {s
: []byte{1, 2, 3}, d
: new(userDefinedSlice
), wanterr
: `unsupported Scan, storing driver.Value type []uint8 into type *sql.userDefinedSlice`},
184 {s
: "str", d
: new(userDefinedString
), wantusrstr
: "str"},
187 {s
: complex(1, 2), d
: &scanstr
, wanterr
: `unsupported Scan, storing driver.Value type complex128 into type *string`},
191 func intPtrValue(intptr
interface{}) interface{} {
192 return reflect
.Indirect(reflect
.Indirect(reflect
.ValueOf(intptr
))).Int()
195 func intValue(intptr
interface{}) int64 {
196 return reflect
.Indirect(reflect
.ValueOf(intptr
)).Int()
199 func uintValue(intptr
interface{}) uint64 {
200 return reflect
.Indirect(reflect
.ValueOf(intptr
)).Uint()
203 func float64Value(ptr
interface{}) float64 {
204 return *(ptr
.(*float64))
207 func float32Value(ptr
interface{}) float32 {
208 return *(ptr
.(*float32))
211 func timeValue(ptr
interface{}) time
.Time
{
212 return *(ptr
.(*time
.Time
))
215 func TestConversions(t
*testing
.T
) {
216 for n
, ct
:= range conversionTests() {
217 err
:= convertAssign(ct
.d
, ct
.s
)
222 errf
:= func(format
string, args
...interface{}) {
223 base
:= fmt
.Sprintf("convertAssign #%d: for %v (%T) -> %T, ", n
, ct
.s
, ct
.s
, ct
.d
)
224 t
.Errorf(base
+format
, args
...)
226 if errstr
!= ct
.wanterr
{
227 errf("got error %q, want error %q", errstr
, ct
.wanterr
)
229 if ct
.wantstr
!= "" && ct
.wantstr
!= scanstr
{
230 errf("want string %q, got %q", ct
.wantstr
, scanstr
)
232 if ct
.wantbytes
!= nil && string(ct
.wantbytes
) != string(scanbytes
) {
233 errf("want byte %q, got %q", ct
.wantbytes
, scanbytes
)
235 if ct
.wantraw
!= nil && string(ct
.wantraw
) != string(scanraw
) {
236 errf("want RawBytes %q, got %q", ct
.wantraw
, scanraw
)
238 if ct
.wantint
!= 0 && ct
.wantint
!= intValue(ct
.d
) {
239 errf("want int %d, got %d", ct
.wantint
, intValue(ct
.d
))
241 if ct
.wantuint
!= 0 && ct
.wantuint
!= uintValue(ct
.d
) {
242 errf("want uint %d, got %d", ct
.wantuint
, uintValue(ct
.d
))
244 if ct
.wantf32
!= 0 && ct
.wantf32
!= float32Value(ct
.d
) {
245 errf("want float32 %v, got %v", ct
.wantf32
, float32Value(ct
.d
))
247 if ct
.wantf64
!= 0 && ct
.wantf64
!= float64Value(ct
.d
) {
248 errf("want float32 %v, got %v", ct
.wantf64
, float64Value(ct
.d
))
250 if bp
, boolTest
:= ct
.d
.(*bool); boolTest
&& *bp
!= ct
.wantbool
&& ct
.wanterr
== "" {
251 errf("want bool %v, got %v", ct
.wantbool
, *bp
)
253 if !ct
.wanttime
.IsZero() && !ct
.wanttime
.Equal(timeValue(ct
.d
)) {
254 errf("want time %v, got %v", ct
.wanttime
, timeValue(ct
.d
))
256 if ct
.wantnil
&& *ct
.d
.(**int64) != nil {
257 errf("want nil, got %v", intPtrValue(ct
.d
))
259 if ct
.wantptr
!= nil {
260 if *ct
.d
.(**int64) == nil {
261 errf("want pointer to %v, got nil", *ct
.wantptr
)
262 } else if *ct
.wantptr
!= intPtrValue(ct
.d
) {
263 errf("want pointer to %v, got %v", *ct
.wantptr
, intPtrValue(ct
.d
))
266 if ifptr
, ok
:= ct
.d
.(*interface{}); ok
{
267 if !reflect
.DeepEqual(ct
.wantiface
, scaniface
) {
268 errf("want interface %#v, got %#v", ct
.wantiface
, scaniface
)
271 if srcBytes
, ok
:= ct
.s
.([]byte); ok
{
272 dstBytes
:= (*ifptr
).([]byte)
273 if len(srcBytes
) > 0 && &dstBytes
[0] == &srcBytes
[0] {
274 errf("copy into interface{} didn't copy []byte data")
278 if ct
.wantusrdef
!= 0 && ct
.wantusrdef
!= *ct
.d
.(*userDefined
) {
279 errf("want userDefined %f, got %f", ct
.wantusrdef
, *ct
.d
.(*userDefined
))
281 if len(ct
.wantusrstr
) != 0 && ct
.wantusrstr
!= *ct
.d
.(*userDefinedString
) {
282 errf("want userDefined %q, got %q", ct
.wantusrstr
, *ct
.d
.(*userDefinedString
))
287 func TestNullString(t
*testing
.T
) {
289 convertAssign(&ns
, []byte("foo"))
291 t
.Errorf("expecting not null")
293 if ns
.String
!= "foo" {
294 t
.Errorf("expecting foo; got %q", ns
.String
)
296 convertAssign(&ns
, nil)
298 t
.Errorf("expecting null on nil")
301 t
.Errorf("expecting blank on nil; got %q", ns
.String
)
305 type valueConverterTest
struct {
306 c driver
.ValueConverter
311 var valueConverterTests
= []valueConverterTest
{
312 {driver
.DefaultParameterConverter
, NullString
{"hi", true}, "hi", ""},
313 {driver
.DefaultParameterConverter
, NullString
{"", false}, nil, ""},
316 func TestValueConverters(t
*testing
.T
) {
317 for i
, tt
:= range valueConverterTests
{
318 out
, err
:= tt
.c
.ConvertValue(tt
.in
)
323 if goterr
!= tt
.err
{
324 t
.Errorf("test %d: %T(%T(%v)) error = %q; want error = %q",
325 i
, tt
.c
, tt
.in
, tt
.in
, goterr
, tt
.err
)
330 if !reflect
.DeepEqual(out
, tt
.out
) {
331 t
.Errorf("test %d: %T(%T(%v)) = %v (%T); want %v (%T)",
332 i
, tt
.c
, tt
.in
, tt
.in
, out
, out
, tt
.out
, tt
.out
)
337 // Tests that assigning to RawBytes doesn't allocate (and also works).
338 func TestRawBytesAllocs(t
*testing
.T
) {
339 var tests
= []struct {
344 {"uint64", uint64(12345678), "12345678"},
345 {"uint32", uint32(1234), "1234"},
346 {"uint16", uint16(12), "12"},
347 {"uint8", uint8(1), "1"},
348 {"uint", uint(123), "123"},
349 {"int", int(123), "123"},
350 {"int8", int8(1), "1"},
351 {"int16", int16(12), "12"},
352 {"int32", int32(1234), "1234"},
353 {"int64", int64(12345678), "12345678"},
354 {"float32", float32(1.5), "1.5"},
355 {"float64", float64(64), "64"},
356 {"bool", false, "false"},
357 {"time", time
.Unix(2, 5).UTC(), "1970-01-01T00:00:02.000000005Z"},
360 buf
:= make(RawBytes
, 10)
361 test
:= func(name
string, in
interface{}, want
string) {
362 if err
:= convertAssign(&buf
, in
); err
!= nil {
363 t
.Fatalf("%s: convertAssign = %v", name
, err
)
365 match
:= len(buf
) == len(want
)
367 for i
, b
:= range buf
{
375 t
.Fatalf("%s: got %q (len %d); want %q (len %d)", name
, buf
, len(buf
), want
, len(want
))
379 n
:= testing
.AllocsPerRun(100, func() {
380 for _
, tt
:= range tests
{
381 test(tt
.name
, tt
.in
, tt
.want
)
385 // The numbers below are only valid for 64-bit interface word sizes,
386 // and gc. With 32-bit words there are more convT2E allocs, and
387 // with gccgo, only pointers currently go in interface data.
388 // So only care on amd64 gc for now.
389 measureAllocs
:= runtime
.GOARCH
== "amd64" && runtime
.Compiler
== "gc"
391 if n
> 0.5 && measureAllocs
{
392 t
.Fatalf("allocs = %v; want 0", n
)
395 // This one involves a convT2E allocation, string -> interface{}
396 n
= testing
.AllocsPerRun(100, func() {
397 test("string", "foo", "foo")
399 if n
> 1.5 && measureAllocs
{
400 t
.Fatalf("allocs = %v; want max 1", n
)
404 // https://golang.org/issues/13905
405 func TestUserDefinedBytes(t
*testing
.T
) {
406 type userDefinedBytes
[]byte
407 var u userDefinedBytes
412 t
.Fatal("userDefinedBytes got potentially dirty driver memory")
418 func (v Valuer_V
) Value() (driver
.Value
, error
) {
419 return strings
.ToUpper(string(v
)), nil
424 func (p
*Valuer_P
) Value() (driver
.Value
, error
) {
426 return "nil-to-str", nil
428 return strings
.ToUpper(string(*p
)), nil
431 func TestDriverArgs(t
*testing
.T
) {
432 var nilValuerVPtr
*Valuer_V
433 var nilValuerPPtr
*Valuer_P
434 var nilStrPtr
*string
437 want
[]driver
.NamedValue
440 args
: []interface{}{Valuer_V("foo")},
441 want
: []driver
.NamedValue
{
449 args
: []interface{}{nilValuerVPtr
},
450 want
: []driver
.NamedValue
{
458 args
: []interface{}{nilValuerPPtr
},
459 want
: []driver
.NamedValue
{
467 args
: []interface{}{"plain-str"},
468 want
: []driver
.NamedValue
{
476 args
: []interface{}{nilStrPtr
},
477 want
: []driver
.NamedValue
{
485 for i
, tt
:= range tests
{
486 ds
:= &driverStmt
{Locker
: &sync
.Mutex
{}, si
: stubDriverStmt
{nil}}
487 got
, err
:= driverArgsConnLocked(nil, ds
, tt
.args
)
489 t
.Errorf("test[%d]: %v", i
, err
)
492 if !reflect
.DeepEqual(got
, tt
.want
) {
493 t
.Errorf("test[%d]: got %v, want %v", i
, got
, tt
.want
)