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