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