github.com/hongwozai/go-src-1.4.3@v0.0.0-20191127132709-dc3fce3dbccb/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 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  }