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