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  }