vitess.io/vitess@v0.16.2/go/sqltypes/value_test.go (about)

     1  /*
     2  Copyright 2019 The Vitess Authors.
     3  
     4  Licensed under the Apache License, Version 2.0 (the "License");
     5  you may not use this file except in compliance with the License.
     6  You may obtain a copy of the License at
     7  
     8      http://www.apache.org/licenses/LICENSE-2.0
     9  
    10  Unless required by applicable law or agreed to in writing, software
    11  distributed under the License is distributed on an "AS IS" BASIS,
    12  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
    13  See the License for the specific language governing permissions and
    14  limitations under the License.
    15  */
    16  
    17  package sqltypes
    18  
    19  import (
    20  	"bytes"
    21  	"reflect"
    22  	"strings"
    23  	"testing"
    24  
    25  	"github.com/stretchr/testify/assert"
    26  
    27  	"github.com/stretchr/testify/require"
    28  
    29  	querypb "vitess.io/vitess/go/vt/proto/query"
    30  )
    31  
    32  const (
    33  	InvalidNeg = "-9223372036854775809"
    34  	MinNeg     = "-9223372036854775808"
    35  	MinPos     = "18446744073709551615"
    36  	InvalidPos = "18446744073709551616"
    37  )
    38  
    39  func TestNewValue(t *testing.T) {
    40  	testcases := []struct {
    41  		inType querypb.Type
    42  		inVal  string
    43  		outVal Value
    44  		outErr string
    45  	}{{
    46  		inType: Null,
    47  		inVal:  "",
    48  		outVal: NULL,
    49  	}, {
    50  		inType: Int8,
    51  		inVal:  "1",
    52  		outVal: TestValue(Int8, "1"),
    53  	}, {
    54  		inType: Int16,
    55  		inVal:  "1",
    56  		outVal: TestValue(Int16, "1"),
    57  	}, {
    58  		inType: Int24,
    59  		inVal:  "1",
    60  		outVal: TestValue(Int24, "1"),
    61  	}, {
    62  		inType: Int32,
    63  		inVal:  "1",
    64  		outVal: TestValue(Int32, "1"),
    65  	}, {
    66  		inType: Int64,
    67  		inVal:  "1",
    68  		outVal: TestValue(Int64, "1"),
    69  	}, {
    70  		inType: Uint8,
    71  		inVal:  "1",
    72  		outVal: TestValue(Uint8, "1"),
    73  	}, {
    74  		inType: Uint16,
    75  		inVal:  "1",
    76  		outVal: TestValue(Uint16, "1"),
    77  	}, {
    78  		inType: Uint24,
    79  		inVal:  "1",
    80  		outVal: TestValue(Uint24, "1"),
    81  	}, {
    82  		inType: Uint32,
    83  		inVal:  "1",
    84  		outVal: TestValue(Uint32, "1"),
    85  	}, {
    86  		inType: Uint64,
    87  		inVal:  "1",
    88  		outVal: TestValue(Uint64, "1"),
    89  	}, {
    90  		inType: Uint64,
    91  		inVal:  "01",
    92  		outVal: TestValue(Uint64, "01"),
    93  	}, {
    94  		inType: Int64,
    95  		inVal:  "01",
    96  		outVal: TestValue(Int64, "01"),
    97  	}, {
    98  		inType: Float32,
    99  		inVal:  "1.00",
   100  		outVal: TestValue(Float32, "1.00"),
   101  	}, {
   102  		inType: Float64,
   103  		inVal:  "1.00",
   104  		outVal: TestValue(Float64, "1.00"),
   105  	}, {
   106  		inType: Decimal,
   107  		inVal:  "1.00",
   108  		outVal: TestValue(Decimal, "1.00"),
   109  	}, {
   110  		inType: Timestamp,
   111  		inVal:  "2012-02-24 23:19:43",
   112  		outVal: TestValue(Timestamp, "2012-02-24 23:19:43"),
   113  	}, {
   114  		inType: Date,
   115  		inVal:  "2012-02-24",
   116  		outVal: TestValue(Date, "2012-02-24"),
   117  	}, {
   118  		inType: Time,
   119  		inVal:  "23:19:43",
   120  		outVal: TestValue(Time, "23:19:43"),
   121  	}, {
   122  		inType: Datetime,
   123  		inVal:  "2012-02-24 23:19:43",
   124  		outVal: TestValue(Datetime, "2012-02-24 23:19:43"),
   125  	}, {
   126  		inType: Year,
   127  		inVal:  "1",
   128  		outVal: TestValue(Year, "1"),
   129  	}, {
   130  		inType: Text,
   131  		inVal:  "a",
   132  		outVal: TestValue(Text, "a"),
   133  	}, {
   134  		inType: Blob,
   135  		inVal:  "a",
   136  		outVal: TestValue(Blob, "a"),
   137  	}, {
   138  		inType: VarChar,
   139  		inVal:  "a",
   140  		outVal: TestValue(VarChar, "a"),
   141  	}, {
   142  		inType: Binary,
   143  		inVal:  "a",
   144  		outVal: TestValue(Binary, "a"),
   145  	}, {
   146  		inType: Char,
   147  		inVal:  "a",
   148  		outVal: TestValue(Char, "a"),
   149  	}, {
   150  		inType: Bit,
   151  		inVal:  "1",
   152  		outVal: TestValue(Bit, "1"),
   153  	}, {
   154  		inType: Enum,
   155  		inVal:  "a",
   156  		outVal: TestValue(Enum, "a"),
   157  	}, {
   158  		inType: Set,
   159  		inVal:  "a",
   160  		outVal: TestValue(Set, "a"),
   161  	}, {
   162  		inType: VarBinary,
   163  		inVal:  "a",
   164  		outVal: TestValue(VarBinary, "a"),
   165  	}, {
   166  		inType: Int64,
   167  		inVal:  InvalidNeg,
   168  		outErr: "out of range",
   169  	}, {
   170  		inType: Int64,
   171  		inVal:  InvalidPos,
   172  		outErr: "out of range",
   173  	}, {
   174  		inType: Uint64,
   175  		inVal:  "-1",
   176  		outErr: "invalid syntax",
   177  	}, {
   178  		inType: Uint64,
   179  		inVal:  InvalidPos,
   180  		outErr: "out of range",
   181  	}, {
   182  		inType: Float64,
   183  		inVal:  "a",
   184  		outErr: "invalid syntax",
   185  	}, {
   186  		inType: Expression,
   187  		inVal:  "a",
   188  		outErr: "invalid type specified for MakeValue: EXPRESSION",
   189  	}}
   190  	for _, tcase := range testcases {
   191  		v, err := NewValue(tcase.inType, []byte(tcase.inVal))
   192  		if tcase.outErr != "" {
   193  			if err == nil || !strings.Contains(err.Error(), tcase.outErr) {
   194  				t.Errorf("ValueFromBytes(%v, %v) error: %v, must contain %v", tcase.inType, tcase.inVal, err, tcase.outErr)
   195  			}
   196  			continue
   197  		}
   198  		if err != nil {
   199  			t.Errorf("ValueFromBytes(%v, %v) error: %v", tcase.inType, tcase.inVal, err)
   200  			continue
   201  		}
   202  		if !reflect.DeepEqual(v, tcase.outVal) {
   203  			t.Errorf("ValueFromBytes(%v, %v) = %v, want %v", tcase.inType, tcase.inVal, v, tcase.outVal)
   204  		}
   205  	}
   206  }
   207  
   208  // TestNew tests 'New' functions that are not tested
   209  // through other code paths.
   210  func TestNew(t *testing.T) {
   211  	got := NewInt32(1)
   212  	want := MakeTrusted(Int32, []byte("1"))
   213  	if !reflect.DeepEqual(got, want) {
   214  		t.Errorf("NewInt32(aa): %v, want %v", got, want)
   215  	}
   216  
   217  	got = NewVarBinary("aa")
   218  	want = MakeTrusted(VarBinary, []byte("aa"))
   219  	if !reflect.DeepEqual(got, want) {
   220  		t.Errorf("NewVarBinary(aa): %v, want %v", got, want)
   221  	}
   222  }
   223  
   224  func TestMakeTrusted(t *testing.T) {
   225  	v := MakeTrusted(Null, []byte("abcd"))
   226  	if !reflect.DeepEqual(v, NULL) {
   227  		t.Errorf("MakeTrusted(Null...) = %v, want null", v)
   228  	}
   229  	v = MakeTrusted(Int64, []byte("1"))
   230  	want := TestValue(Int64, "1")
   231  	if !reflect.DeepEqual(v, want) {
   232  		t.Errorf("MakeTrusted(Int64, \"1\") = %v, want %v", v, want)
   233  	}
   234  }
   235  
   236  func TestIntegralValue(t *testing.T) {
   237  	testcases := []struct {
   238  		in     string
   239  		outVal Value
   240  		outErr string
   241  	}{{
   242  		in:     MinNeg,
   243  		outVal: TestValue(Int64, MinNeg),
   244  	}, {
   245  		in:     "1",
   246  		outVal: TestValue(Int64, "1"),
   247  	}, {
   248  		in:     MinPos,
   249  		outVal: TestValue(Uint64, MinPos),
   250  	}, {
   251  		in:     InvalidPos,
   252  		outErr: "out of range",
   253  	}}
   254  	for _, tcase := range testcases {
   255  		v, err := NewIntegral(tcase.in)
   256  		if tcase.outErr != "" {
   257  			if err == nil || !strings.Contains(err.Error(), tcase.outErr) {
   258  				t.Errorf("BuildIntegral(%v) error: %v, must contain %v", tcase.in, err, tcase.outErr)
   259  			}
   260  			continue
   261  		}
   262  		if err != nil {
   263  			t.Errorf("BuildIntegral(%v) error: %v", tcase.in, err)
   264  			continue
   265  		}
   266  		if !reflect.DeepEqual(v, tcase.outVal) {
   267  			t.Errorf("BuildIntegral(%v) = %v, want %v", tcase.in, v, tcase.outVal)
   268  		}
   269  	}
   270  }
   271  
   272  func TestInterfaceValue(t *testing.T) {
   273  	testcases := []struct {
   274  		in  any
   275  		out Value
   276  	}{{
   277  		in:  nil,
   278  		out: NULL,
   279  	}, {
   280  		in:  []byte("a"),
   281  		out: TestValue(VarBinary, "a"),
   282  	}, {
   283  		in:  int64(1),
   284  		out: TestValue(Int64, "1"),
   285  	}, {
   286  		in:  uint64(1),
   287  		out: TestValue(Uint64, "1"),
   288  	}, {
   289  		in:  float64(1.2),
   290  		out: TestValue(Float64, "1.2"),
   291  	}, {
   292  		in:  "a",
   293  		out: TestValue(VarChar, "a"),
   294  	}}
   295  	for _, tcase := range testcases {
   296  		v, err := InterfaceToValue(tcase.in)
   297  		if err != nil {
   298  			t.Errorf("BuildValue(%#v) error: %v", tcase.in, err)
   299  			continue
   300  		}
   301  		if !reflect.DeepEqual(v, tcase.out) {
   302  			t.Errorf("BuildValue(%#v) = %v, want %v", tcase.in, v, tcase.out)
   303  		}
   304  	}
   305  
   306  	_, err := InterfaceToValue(make(chan bool))
   307  	want := "unexpected"
   308  	if err == nil || !strings.Contains(err.Error(), want) {
   309  		t.Errorf("BuildValue(chan): %v, want %v", err, want)
   310  	}
   311  }
   312  
   313  func TestAccessors(t *testing.T) {
   314  	v := TestValue(Int64, "1")
   315  	if v.Type() != Int64 {
   316  		t.Errorf("v.Type=%v, want Int64", v.Type())
   317  	}
   318  	if !bytes.Equal(v.Raw(), []byte("1")) {
   319  		t.Errorf("v.Raw=%s, want 1", v.Raw())
   320  	}
   321  	if v.Len() != 1 {
   322  		t.Errorf("v.Len=%d, want 1", v.Len())
   323  	}
   324  	if v.ToString() != "1" {
   325  		t.Errorf("v.String=%s, want 1", v.ToString())
   326  	}
   327  	if v.IsNull() {
   328  		t.Error("v.IsNull: true, want false")
   329  	}
   330  	if !v.IsIntegral() {
   331  		t.Error("v.IsIntegral: false, want true")
   332  	}
   333  	if !v.IsSigned() {
   334  		t.Error("v.IsSigned: false, want true")
   335  	}
   336  	if v.IsUnsigned() {
   337  		t.Error("v.IsUnsigned: true, want false")
   338  	}
   339  	if v.IsFloat() {
   340  		t.Error("v.IsFloat: true, want false")
   341  	}
   342  	if v.IsQuoted() {
   343  		t.Error("v.IsQuoted: true, want false")
   344  	}
   345  	if v.IsText() {
   346  		t.Error("v.IsText: true, want false")
   347  	}
   348  	if v.IsBinary() {
   349  		t.Error("v.IsBinary: true, want false")
   350  	}
   351  	{
   352  		i, err := v.ToInt64()
   353  		if err != nil {
   354  			t.Errorf("v.ToInt64: got error: %+v, want no error", err)
   355  		}
   356  		if i != 1 {
   357  			t.Errorf("v.ToInt64=%+v, want 1", i)
   358  		}
   359  	}
   360  	{
   361  		i, err := v.ToUint64()
   362  		if err != nil {
   363  			t.Errorf("v.ToUint64: got error: %+v, want no error", err)
   364  		}
   365  		if i != 1 {
   366  			t.Errorf("v.ToUint64=%+v, want 1", i)
   367  		}
   368  	}
   369  	{
   370  		b, err := v.ToBool()
   371  		if err != nil {
   372  			t.Errorf("v.ToBool: got error: %+v, want no error", err)
   373  		}
   374  		if !b {
   375  			t.Errorf("v.ToBool=%+v, want true", b)
   376  		}
   377  	}
   378  }
   379  
   380  func TestAccessorsNegative(t *testing.T) {
   381  	v := TestValue(Int64, "-1")
   382  	if v.ToString() != "-1" {
   383  		t.Errorf("v.String=%s, want -1", v.ToString())
   384  	}
   385  	if v.IsNull() {
   386  		t.Error("v.IsNull: true, want false")
   387  	}
   388  	if !v.IsIntegral() {
   389  		t.Error("v.IsIntegral: false, want true")
   390  	}
   391  	{
   392  		i, err := v.ToInt64()
   393  		if err != nil {
   394  			t.Errorf("v.ToInt64: got error: %+v, want no error", err)
   395  		}
   396  		if i != -1 {
   397  			t.Errorf("v.ToInt64=%+v, want -1", i)
   398  		}
   399  	}
   400  	{
   401  		if _, err := v.ToUint64(); err == nil {
   402  			t.Error("v.ToUint64: got no error, want error")
   403  		}
   404  	}
   405  	{
   406  		if _, err := v.ToBool(); err == nil {
   407  			t.Error("v.ToUint64: got no error, want error")
   408  		}
   409  	}
   410  }
   411  
   412  func TestToBytesAndString(t *testing.T) {
   413  	for _, v := range []Value{
   414  		NULL,
   415  		TestValue(Int64, "1"),
   416  		TestValue(Int64, "12"),
   417  	} {
   418  		vBytes, err := v.ToBytes()
   419  		require.NoError(t, err)
   420  		if b := vBytes; !bytes.Equal(b, v.Raw()) {
   421  			t.Errorf("%v.ToBytes: %s, want %s", v, b, v.Raw())
   422  		}
   423  		if s := v.ToString(); s != string(v.Raw()) {
   424  			t.Errorf("%v.ToString: %s, want %s", v, s, v.Raw())
   425  		}
   426  	}
   427  
   428  	tv := TestValue(Expression, "aa")
   429  	tvBytes, err := tv.ToBytes()
   430  	require.EqualError(t, err, "expression cannot be converted to bytes")
   431  	if b := tvBytes; b != nil {
   432  		t.Errorf("%v.ToBytes: %s, want nil", tv, b)
   433  	}
   434  	if s := tv.ToString(); s != "" {
   435  		t.Errorf("%v.ToString: %s, want \"\"", tv, s)
   436  	}
   437  }
   438  
   439  func TestEncode(t *testing.T) {
   440  	testcases := []struct {
   441  		in       Value
   442  		outSQL   string
   443  		outASCII string
   444  	}{{
   445  		in:       NULL,
   446  		outSQL:   "null",
   447  		outASCII: "null",
   448  	}, {
   449  		in:       TestValue(Int64, "1"),
   450  		outSQL:   "1",
   451  		outASCII: "1",
   452  	}, {
   453  		in:       TestValue(VarChar, "foo"),
   454  		outSQL:   "'foo'",
   455  		outASCII: "'Zm9v'",
   456  	}, {
   457  		in:       TestValue(VarChar, "\x00'\"\b\n\r\t\x1A\\"),
   458  		outSQL:   "'\\0\\'\\\"\\b\\n\\r\\t\\Z\\\\'",
   459  		outASCII: "'ACciCAoNCRpc'",
   460  	}, {
   461  		in:       TestValue(Bit, "a"),
   462  		outSQL:   "b'01100001'",
   463  		outASCII: "'YQ=='",
   464  	}}
   465  	for _, tcase := range testcases {
   466  		buf := &bytes.Buffer{}
   467  		tcase.in.EncodeSQL(buf)
   468  		if tcase.outSQL != buf.String() {
   469  			t.Errorf("%v.EncodeSQL = %q, want %q", tcase.in, buf.String(), tcase.outSQL)
   470  		}
   471  		buf = &bytes.Buffer{}
   472  		tcase.in.EncodeASCII(buf)
   473  		if tcase.outASCII != buf.String() {
   474  			t.Errorf("%v.EncodeASCII = %q, want %q", tcase.in, buf.String(), tcase.outASCII)
   475  		}
   476  	}
   477  }
   478  
   479  // TestEncodeMap ensures DontEscape is not escaped
   480  func TestEncodeMap(t *testing.T) {
   481  	if SQLEncodeMap[DontEscape] != DontEscape {
   482  		t.Errorf("SQLEncodeMap[DontEscape] = %v, want %v", SQLEncodeMap[DontEscape], DontEscape)
   483  	}
   484  	if SQLDecodeMap[DontEscape] != DontEscape {
   485  		t.Errorf("SQLDecodeMap[DontEscape] = %v, want %v", SQLEncodeMap[DontEscape], DontEscape)
   486  	}
   487  }
   488  
   489  func TestHexAndBitToBytes(t *testing.T) {
   490  	tcases := []struct {
   491  		in  Value
   492  		out []byte
   493  	}{{
   494  		in:  MakeTrusted(HexNum, []byte("0x1234")),
   495  		out: []byte{0x12, 0x34},
   496  	}, {
   497  		in:  MakeTrusted(HexVal, []byte("X'1234'")),
   498  		out: []byte{0x12, 0x34},
   499  	}, {
   500  		in:  MakeTrusted(BitNum, []byte("0b1001000110100")),
   501  		out: []byte{0x12, 0x34},
   502  	}, {
   503  		in:  MakeTrusted(BitNum, []byte("0b11101010100101010010101010101010101010101000100100100100100101001101010101010101000001")),
   504  		out: []byte{0x3a, 0xa5, 0x4a, 0xaa, 0xaa, 0xa2, 0x49, 0x25, 0x35, 0x55, 0x41},
   505  	}}
   506  
   507  	for _, tcase := range tcases {
   508  		t.Run(tcase.in.String(), func(t *testing.T) {
   509  			out, err := tcase.in.ToBytes()
   510  			require.NoError(t, err)
   511  			assert.Equal(t, tcase.out, out)
   512  		})
   513  	}
   514  }