github.com/zebozhuang/go@v0.0.0-20200207033046-f8a98f6f5c5d/src/database/sql/convert_test.go (about) 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. 4 5 package sql 6 7 import ( 8 "database/sql/driver" 9 "fmt" 10 "reflect" 11 "runtime" 12 "strings" 13 "sync" 14 "testing" 15 "time" 16 ) 17 18 var someTime = time.Unix(123, 0) 19 var answer int64 = 42 20 21 type ( 22 userDefined float64 23 userDefinedSlice []int 24 userDefinedString string 25 ) 26 27 type conversionTest struct { 28 s, d interface{} // source and destination 29 30 // following are used if they're non-zero 31 wantint int64 32 wantuint uint64 33 wantstr string 34 wantbytes []byte 35 wantraw RawBytes 36 wantf32 float32 37 wantf64 float64 38 wanttime time.Time 39 wantbool bool // used if d is of type *bool 40 wanterr string 41 wantiface interface{} 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 46 } 47 48 // Target variables for scanning into. 49 var ( 50 scanstr string 51 scanbytes []byte 52 scanraw RawBytes 53 scanint int 54 scanint8 int8 55 scanint16 int16 56 scanint32 int32 57 scanuint8 uint8 58 scanuint16 uint16 59 scanbool bool 60 scanf32 float32 61 scanf64 float64 62 scantime time.Time 63 scanptr *int64 64 scaniface interface{} 65 ) 66 67 var conversionTests = []conversionTest{ 68 // Exact conversions (destination pointer type matches source type) 69 {s: "foo", d: &scanstr, wantstr: "foo"}, 70 {s: 123, d: &scanint, wantint: 123}, 71 {s: someTime, d: &scantime, wanttime: someTime}, 72 73 // To strings 74 {s: "string", d: &scanstr, wantstr: "string"}, 75 {s: []byte("byteslice"), d: &scanstr, wantstr: "byteslice"}, 76 {s: 123, d: &scanstr, wantstr: "123"}, 77 {s: int8(123), d: &scanstr, wantstr: "123"}, 78 {s: int64(123), d: &scanstr, wantstr: "123"}, 79 {s: uint8(123), d: &scanstr, wantstr: "123"}, 80 {s: uint16(123), d: &scanstr, wantstr: "123"}, 81 {s: uint32(123), d: &scanstr, wantstr: "123"}, 82 {s: uint64(123), d: &scanstr, wantstr: "123"}, 83 {s: 1.5, d: &scanstr, wantstr: "1.5"}, 84 85 // From time.Time: 86 {s: time.Unix(1, 0).UTC(), d: &scanstr, wantstr: "1970-01-01T00:00:01Z"}, 87 {s: time.Unix(1453874597, 0).In(time.FixedZone("here", -3600*8)), d: &scanstr, wantstr: "2016-01-26T22:03:17-08:00"}, 88 {s: time.Unix(1, 2).UTC(), d: &scanstr, wantstr: "1970-01-01T00:00:01.000000002Z"}, 89 {s: time.Time{}, d: &scanstr, wantstr: "0001-01-01T00:00:00Z"}, 90 {s: time.Unix(1, 2).UTC(), d: &scanbytes, wantbytes: []byte("1970-01-01T00:00:01.000000002Z")}, 91 {s: time.Unix(1, 2).UTC(), d: &scaniface, wantiface: time.Unix(1, 2).UTC()}, 92 93 // To []byte 94 {s: nil, d: &scanbytes, wantbytes: nil}, 95 {s: "string", d: &scanbytes, wantbytes: []byte("string")}, 96 {s: []byte("byteslice"), d: &scanbytes, wantbytes: []byte("byteslice")}, 97 {s: 123, d: &scanbytes, wantbytes: []byte("123")}, 98 {s: int8(123), d: &scanbytes, wantbytes: []byte("123")}, 99 {s: int64(123), d: &scanbytes, wantbytes: []byte("123")}, 100 {s: uint8(123), d: &scanbytes, wantbytes: []byte("123")}, 101 {s: uint16(123), d: &scanbytes, wantbytes: []byte("123")}, 102 {s: uint32(123), d: &scanbytes, wantbytes: []byte("123")}, 103 {s: uint64(123), d: &scanbytes, wantbytes: []byte("123")}, 104 {s: 1.5, d: &scanbytes, wantbytes: []byte("1.5")}, 105 106 // To RawBytes 107 {s: nil, d: &scanraw, wantraw: nil}, 108 {s: []byte("byteslice"), d: &scanraw, wantraw: RawBytes("byteslice")}, 109 {s: 123, d: &scanraw, wantraw: RawBytes("123")}, 110 {s: int8(123), d: &scanraw, wantraw: RawBytes("123")}, 111 {s: int64(123), d: &scanraw, wantraw: RawBytes("123")}, 112 {s: uint8(123), d: &scanraw, wantraw: RawBytes("123")}, 113 {s: uint16(123), d: &scanraw, wantraw: RawBytes("123")}, 114 {s: uint32(123), d: &scanraw, wantraw: RawBytes("123")}, 115 {s: uint64(123), d: &scanraw, wantraw: RawBytes("123")}, 116 {s: 1.5, d: &scanraw, wantraw: RawBytes("1.5")}, 117 118 // Strings to integers 119 {s: "255", d: &scanuint8, wantuint: 255}, 120 {s: "256", d: &scanuint8, wanterr: "converting driver.Value type string (\"256\") to a uint8: value out of range"}, 121 {s: "256", d: &scanuint16, wantuint: 256}, 122 {s: "-1", d: &scanint, wantint: -1}, 123 {s: "foo", d: &scanint, wanterr: "converting driver.Value type string (\"foo\") to a int: invalid syntax"}, 124 125 // int64 to smaller integers 126 {s: int64(5), d: &scanuint8, wantuint: 5}, 127 {s: int64(256), d: &scanuint8, wanterr: "converting driver.Value type int64 (\"256\") to a uint8: value out of range"}, 128 {s: int64(256), d: &scanuint16, wantuint: 256}, 129 {s: int64(65536), d: &scanuint16, wanterr: "converting driver.Value type int64 (\"65536\") to a uint16: value out of range"}, 130 131 // True bools 132 {s: true, d: &scanbool, wantbool: true}, 133 {s: "True", d: &scanbool, wantbool: true}, 134 {s: "TRUE", d: &scanbool, wantbool: true}, 135 {s: "1", d: &scanbool, wantbool: true}, 136 {s: 1, d: &scanbool, wantbool: true}, 137 {s: int64(1), d: &scanbool, wantbool: true}, 138 {s: uint16(1), d: &scanbool, wantbool: true}, 139 140 // False bools 141 {s: false, d: &scanbool, wantbool: false}, 142 {s: "false", d: &scanbool, wantbool: false}, 143 {s: "FALSE", d: &scanbool, wantbool: false}, 144 {s: "0", d: &scanbool, wantbool: false}, 145 {s: 0, d: &scanbool, wantbool: false}, 146 {s: int64(0), d: &scanbool, wantbool: false}, 147 {s: uint16(0), d: &scanbool, wantbool: false}, 148 149 // Not bools 150 {s: "yup", d: &scanbool, wanterr: `sql/driver: couldn't convert "yup" into type bool`}, 151 {s: 2, d: &scanbool, wanterr: `sql/driver: couldn't convert 2 into type bool`}, 152 153 // Floats 154 {s: float64(1.5), d: &scanf64, wantf64: float64(1.5)}, 155 {s: int64(1), d: &scanf64, wantf64: float64(1)}, 156 {s: float64(1.5), d: &scanf32, wantf32: float32(1.5)}, 157 {s: "1.5", d: &scanf32, wantf32: float32(1.5)}, 158 {s: "1.5", d: &scanf64, wantf64: float64(1.5)}, 159 160 // Pointers 161 {s: interface{}(nil), d: &scanptr, wantnil: true}, 162 {s: int64(42), d: &scanptr, wantptr: &answer}, 163 164 // To interface{} 165 {s: float64(1.5), d: &scaniface, wantiface: float64(1.5)}, 166 {s: int64(1), d: &scaniface, wantiface: int64(1)}, 167 {s: "str", d: &scaniface, wantiface: "str"}, 168 {s: []byte("byteslice"), d: &scaniface, wantiface: []byte("byteslice")}, 169 {s: true, d: &scaniface, wantiface: true}, 170 {s: nil, d: &scaniface}, 171 {s: []byte(nil), d: &scaniface, wantiface: []byte(nil)}, 172 173 // To a user-defined type 174 {s: 1.5, d: new(userDefined), wantusrdef: 1.5}, 175 {s: int64(123), d: new(userDefined), wantusrdef: 123}, 176 {s: "1.5", d: new(userDefined), wantusrdef: 1.5}, 177 {s: []byte{1, 2, 3}, d: new(userDefinedSlice), wanterr: `unsupported Scan, storing driver.Value type []uint8 into type *sql.userDefinedSlice`}, 178 {s: "str", d: new(userDefinedString), wantusrstr: "str"}, 179 180 // Other errors 181 {s: complex(1, 2), d: &scanstr, wanterr: `unsupported Scan, storing driver.Value type complex128 into type *string`}, 182 } 183 184 func intPtrValue(intptr interface{}) interface{} { 185 return reflect.Indirect(reflect.Indirect(reflect.ValueOf(intptr))).Int() 186 } 187 188 func intValue(intptr interface{}) int64 { 189 return reflect.Indirect(reflect.ValueOf(intptr)).Int() 190 } 191 192 func uintValue(intptr interface{}) uint64 { 193 return reflect.Indirect(reflect.ValueOf(intptr)).Uint() 194 } 195 196 func float64Value(ptr interface{}) float64 { 197 return *(ptr.(*float64)) 198 } 199 200 func float32Value(ptr interface{}) float32 { 201 return *(ptr.(*float32)) 202 } 203 204 func timeValue(ptr interface{}) time.Time { 205 return *(ptr.(*time.Time)) 206 } 207 208 func TestConversions(t *testing.T) { 209 for n, ct := range conversionTests { 210 err := convertAssign(ct.d, ct.s) 211 errstr := "" 212 if err != nil { 213 errstr = err.Error() 214 } 215 errf := func(format string, args ...interface{}) { 216 base := fmt.Sprintf("convertAssign #%d: for %v (%T) -> %T, ", n, ct.s, ct.s, ct.d) 217 t.Errorf(base+format, args...) 218 } 219 if errstr != ct.wanterr { 220 errf("got error %q, want error %q", errstr, ct.wanterr) 221 } 222 if ct.wantstr != "" && ct.wantstr != scanstr { 223 errf("want string %q, got %q", ct.wantstr, scanstr) 224 } 225 if ct.wantint != 0 && ct.wantint != intValue(ct.d) { 226 errf("want int %d, got %d", ct.wantint, intValue(ct.d)) 227 } 228 if ct.wantuint != 0 && ct.wantuint != uintValue(ct.d) { 229 errf("want uint %d, got %d", ct.wantuint, uintValue(ct.d)) 230 } 231 if ct.wantf32 != 0 && ct.wantf32 != float32Value(ct.d) { 232 errf("want float32 %v, got %v", ct.wantf32, float32Value(ct.d)) 233 } 234 if ct.wantf64 != 0 && ct.wantf64 != float64Value(ct.d) { 235 errf("want float32 %v, got %v", ct.wantf64, float64Value(ct.d)) 236 } 237 if bp, boolTest := ct.d.(*bool); boolTest && *bp != ct.wantbool && ct.wanterr == "" { 238 errf("want bool %v, got %v", ct.wantbool, *bp) 239 } 240 if !ct.wanttime.IsZero() && !ct.wanttime.Equal(timeValue(ct.d)) { 241 errf("want time %v, got %v", ct.wanttime, timeValue(ct.d)) 242 } 243 if ct.wantnil && *ct.d.(**int64) != nil { 244 errf("want nil, got %v", intPtrValue(ct.d)) 245 } 246 if ct.wantptr != nil { 247 if *ct.d.(**int64) == nil { 248 errf("want pointer to %v, got nil", *ct.wantptr) 249 } else if *ct.wantptr != intPtrValue(ct.d) { 250 errf("want pointer to %v, got %v", *ct.wantptr, intPtrValue(ct.d)) 251 } 252 } 253 if ifptr, ok := ct.d.(*interface{}); ok { 254 if !reflect.DeepEqual(ct.wantiface, scaniface) { 255 errf("want interface %#v, got %#v", ct.wantiface, scaniface) 256 continue 257 } 258 if srcBytes, ok := ct.s.([]byte); ok { 259 dstBytes := (*ifptr).([]byte) 260 if len(srcBytes) > 0 && &dstBytes[0] == &srcBytes[0] { 261 errf("copy into interface{} didn't copy []byte data") 262 } 263 } 264 } 265 if ct.wantusrdef != 0 && ct.wantusrdef != *ct.d.(*userDefined) { 266 errf("want userDefined %f, got %f", ct.wantusrdef, *ct.d.(*userDefined)) 267 } 268 if len(ct.wantusrstr) != 0 && ct.wantusrstr != *ct.d.(*userDefinedString) { 269 errf("want userDefined %q, got %q", ct.wantusrstr, *ct.d.(*userDefinedString)) 270 } 271 } 272 } 273 274 func TestNullString(t *testing.T) { 275 var ns NullString 276 convertAssign(&ns, []byte("foo")) 277 if !ns.Valid { 278 t.Errorf("expecting not null") 279 } 280 if ns.String != "foo" { 281 t.Errorf("expecting foo; got %q", ns.String) 282 } 283 convertAssign(&ns, nil) 284 if ns.Valid { 285 t.Errorf("expecting null on nil") 286 } 287 if ns.String != "" { 288 t.Errorf("expecting blank on nil; got %q", ns.String) 289 } 290 } 291 292 type valueConverterTest struct { 293 c driver.ValueConverter 294 in, out interface{} 295 err string 296 } 297 298 var valueConverterTests = []valueConverterTest{ 299 {driver.DefaultParameterConverter, NullString{"hi", true}, "hi", ""}, 300 {driver.DefaultParameterConverter, NullString{"", false}, nil, ""}, 301 } 302 303 func TestValueConverters(t *testing.T) { 304 for i, tt := range valueConverterTests { 305 out, err := tt.c.ConvertValue(tt.in) 306 goterr := "" 307 if err != nil { 308 goterr = err.Error() 309 } 310 if goterr != tt.err { 311 t.Errorf("test %d: %T(%T(%v)) error = %q; want error = %q", 312 i, tt.c, tt.in, tt.in, goterr, tt.err) 313 } 314 if tt.err != "" { 315 continue 316 } 317 if !reflect.DeepEqual(out, tt.out) { 318 t.Errorf("test %d: %T(%T(%v)) = %v (%T); want %v (%T)", 319 i, tt.c, tt.in, tt.in, out, out, tt.out, tt.out) 320 } 321 } 322 } 323 324 // Tests that assigning to RawBytes doesn't allocate (and also works). 325 func TestRawBytesAllocs(t *testing.T) { 326 var tests = []struct { 327 name string 328 in interface{} 329 want string 330 }{ 331 {"uint64", uint64(12345678), "12345678"}, 332 {"uint32", uint32(1234), "1234"}, 333 {"uint16", uint16(12), "12"}, 334 {"uint8", uint8(1), "1"}, 335 {"uint", uint(123), "123"}, 336 {"int", int(123), "123"}, 337 {"int8", int8(1), "1"}, 338 {"int16", int16(12), "12"}, 339 {"int32", int32(1234), "1234"}, 340 {"int64", int64(12345678), "12345678"}, 341 {"float32", float32(1.5), "1.5"}, 342 {"float64", float64(64), "64"}, 343 {"bool", false, "false"}, 344 } 345 346 buf := make(RawBytes, 10) 347 test := func(name string, in interface{}, want string) { 348 if err := convertAssign(&buf, in); err != nil { 349 t.Fatalf("%s: convertAssign = %v", name, err) 350 } 351 match := len(buf) == len(want) 352 if match { 353 for i, b := range buf { 354 if want[i] != b { 355 match = false 356 break 357 } 358 } 359 } 360 if !match { 361 t.Fatalf("%s: got %q (len %d); want %q (len %d)", name, buf, len(buf), want, len(want)) 362 } 363 } 364 365 n := testing.AllocsPerRun(100, func() { 366 for _, tt := range tests { 367 test(tt.name, tt.in, tt.want) 368 } 369 }) 370 371 // The numbers below are only valid for 64-bit interface word sizes, 372 // and gc. With 32-bit words there are more convT2E allocs, and 373 // with gccgo, only pointers currently go in interface data. 374 // So only care on amd64 gc for now. 375 measureAllocs := runtime.GOARCH == "amd64" && runtime.Compiler == "gc" 376 377 if n > 0.5 && measureAllocs { 378 t.Fatalf("allocs = %v; want 0", n) 379 } 380 381 // This one involves a convT2E allocation, string -> interface{} 382 n = testing.AllocsPerRun(100, func() { 383 test("string", "foo", "foo") 384 }) 385 if n > 1.5 && measureAllocs { 386 t.Fatalf("allocs = %v; want max 1", n) 387 } 388 } 389 390 // https://github.com/golang/go/issues/13905 391 func TestUserDefinedBytes(t *testing.T) { 392 type userDefinedBytes []byte 393 var u userDefinedBytes 394 v := []byte("foo") 395 396 convertAssign(&u, v) 397 if &u[0] == &v[0] { 398 t.Fatal("userDefinedBytes got potentially dirty driver memory") 399 } 400 } 401 402 type Valuer_V string 403 404 func (v Valuer_V) Value() (driver.Value, error) { 405 return strings.ToUpper(string(v)), nil 406 } 407 408 type Valuer_P string 409 410 func (p *Valuer_P) Value() (driver.Value, error) { 411 if p == nil { 412 return "nil-to-str", nil 413 } 414 return strings.ToUpper(string(*p)), nil 415 } 416 417 func TestDriverArgs(t *testing.T) { 418 var nilValuerVPtr *Valuer_V 419 var nilValuerPPtr *Valuer_P 420 var nilStrPtr *string 421 tests := []struct { 422 args []interface{} 423 want []driver.NamedValue 424 }{ 425 0: { 426 args: []interface{}{Valuer_V("foo")}, 427 want: []driver.NamedValue{ 428 driver.NamedValue{ 429 Ordinal: 1, 430 Value: "FOO", 431 }, 432 }, 433 }, 434 1: { 435 args: []interface{}{nilValuerVPtr}, 436 want: []driver.NamedValue{ 437 driver.NamedValue{ 438 Ordinal: 1, 439 Value: nil, 440 }, 441 }, 442 }, 443 2: { 444 args: []interface{}{nilValuerPPtr}, 445 want: []driver.NamedValue{ 446 driver.NamedValue{ 447 Ordinal: 1, 448 Value: "nil-to-str", 449 }, 450 }, 451 }, 452 3: { 453 args: []interface{}{"plain-str"}, 454 want: []driver.NamedValue{ 455 driver.NamedValue{ 456 Ordinal: 1, 457 Value: "plain-str", 458 }, 459 }, 460 }, 461 4: { 462 args: []interface{}{nilStrPtr}, 463 want: []driver.NamedValue{ 464 driver.NamedValue{ 465 Ordinal: 1, 466 Value: nil, 467 }, 468 }, 469 }, 470 } 471 for i, tt := range tests { 472 ds := &driverStmt{Locker: &sync.Mutex{}, si: stubDriverStmt{nil}} 473 got, err := driverArgs(nil, ds, tt.args) 474 if err != nil { 475 t.Errorf("test[%d]: %v", i, err) 476 continue 477 } 478 if !reflect.DeepEqual(got, tt.want) { 479 t.Errorf("test[%d]: got %v, want %v", i, got, tt.want) 480 } 481 } 482 }