github.com/gocuntian/go@v0.0.0-20160610041250-fee02d270bf8/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  }