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