github.com/hasnat/dolt/go@v0.0.0-20210628190320-9eb5d843fbb7/libraries/doltcore/sqle/expreval/literal_helpers_test.go (about)

     1  // Copyright 2019-2020 Dolthub, Inc.
     2  //
     3  // Licensed under the Apache License, Version 2.0 (the "License");
     4  // you may not use this file except in compliance with the License.
     5  // You may obtain a copy of the License at
     6  //
     7  //     http://www.apache.org/licenses/LICENSE-2.0
     8  //
     9  // Unless required by applicable law or agreed to in writing, software
    10  // distributed under the License is distributed on an "AS IS" BASIS,
    11  // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
    12  // See the License for the specific language governing permissions and
    13  // limitations under the License.
    14  
    15  package expreval
    16  
    17  import (
    18  	"testing"
    19  	"time"
    20  
    21  	"github.com/dolthub/go-mysql-server/sql"
    22  	"github.com/dolthub/go-mysql-server/sql/expression"
    23  	"github.com/stretchr/testify/assert"
    24  
    25  	"github.com/dolthub/dolt/go/store/types"
    26  )
    27  
    28  func TestLiteralAsInt64(t *testing.T) {
    29  	tests := []struct {
    30  		name      string
    31  		l         *expression.Literal
    32  		expected  int64
    33  		expectErr bool
    34  	}{
    35  		{
    36  			"int8 literal",
    37  			expression.NewLiteral(int8(5), sql.Int8),
    38  			5,
    39  			false,
    40  		},
    41  		{
    42  			"int16 literal",
    43  			expression.NewLiteral(int16(5), sql.Int16),
    44  			5,
    45  			false,
    46  		},
    47  		{
    48  			"int32 literal",
    49  			expression.NewLiteral(int32(5), sql.Int32),
    50  			5,
    51  			false,
    52  		},
    53  		{
    54  			"int literal",
    55  			expression.NewLiteral(int(5), sql.Int32),
    56  			5,
    57  			false,
    58  		},
    59  		{
    60  			"int64 literal",
    61  			expression.NewLiteral(int64(5), sql.Int64),
    62  			5,
    63  			false,
    64  		},
    65  
    66  		{
    67  			"uint8 literal",
    68  			expression.NewLiteral(uint8(5), sql.Uint8),
    69  			5,
    70  			false,
    71  		},
    72  		{
    73  			"uint16 literal",
    74  			expression.NewLiteral(uint16(5), sql.Uint16),
    75  			5,
    76  			false,
    77  		},
    78  		{
    79  			"uint32 literal",
    80  			expression.NewLiteral(uint32(5), sql.Uint32),
    81  			5,
    82  			false,
    83  		},
    84  		{
    85  			"uint literal",
    86  			expression.NewLiteral(uint(5), sql.Uint32),
    87  			5,
    88  			false,
    89  		},
    90  		{
    91  			"uint64 literal",
    92  			expression.NewLiteral(uint64(5), sql.Uint64),
    93  			5,
    94  			false,
    95  		},
    96  		{
    97  			"true literal",
    98  			expression.NewLiteral(true, sql.Boolean),
    99  			1,
   100  			false,
   101  		},
   102  		{
   103  			"false literal",
   104  			expression.NewLiteral(false, sql.Boolean),
   105  			0,
   106  			false,
   107  		},
   108  		{
   109  			"float32 literal",
   110  			expression.NewLiteral(float32(32.0), sql.Float32),
   111  			32,
   112  			false,
   113  		},
   114  		{
   115  			"float64 literal",
   116  			expression.NewLiteral(float64(32.0), sql.Float64),
   117  			32,
   118  			false,
   119  		},
   120  		{
   121  			"string literal",
   122  			expression.NewLiteral("54321", sql.Text),
   123  			54321,
   124  			false,
   125  		},
   126  		{
   127  			"uint literal too big",
   128  			expression.NewLiteral(uint64(0xFFFFFFFFFFFFFFFF), sql.Uint32),
   129  			0,
   130  			true,
   131  		},
   132  		{
   133  			"float64 with fractional portion",
   134  			expression.NewLiteral(float64(5.0005), sql.Float64),
   135  			0,
   136  			true,
   137  		},
   138  		{
   139  			"float32 with fractional portion",
   140  			expression.NewLiteral(float32(5.0005), sql.Float32),
   141  			0,
   142  			true,
   143  		},
   144  		{
   145  			"string not a number",
   146  			expression.NewLiteral("not a number", sql.Text),
   147  			0,
   148  			true,
   149  		},
   150  	}
   151  
   152  	for _, test := range tests {
   153  		t.Run(test.name, func(t *testing.T) {
   154  			res, err := literalAsInt64(test.l)
   155  			assertOnUnexpectedErr(t, test.expectErr, err)
   156  
   157  			if err == nil {
   158  				assert.Equal(t, test.expected, res)
   159  			}
   160  		})
   161  	}
   162  }
   163  
   164  func TestLiteralAsUint64(t *testing.T) {
   165  	tests := []struct {
   166  		name      string
   167  		l         *expression.Literal
   168  		expected  uint64
   169  		expectErr bool
   170  	}{
   171  		{
   172  			"int8 literal",
   173  			expression.NewLiteral(int8(5), sql.Int8),
   174  			5,
   175  			false,
   176  		},
   177  		{
   178  			"int16 literal",
   179  			expression.NewLiteral(int16(5), sql.Int16),
   180  			5,
   181  			false,
   182  		},
   183  		{
   184  			"int32 literal",
   185  			expression.NewLiteral(int32(5), sql.Int32),
   186  			5,
   187  			false,
   188  		},
   189  		{
   190  			"int literal",
   191  			expression.NewLiteral(int(5), sql.Int32),
   192  			5,
   193  			false,
   194  		},
   195  		{
   196  			"int64 literal",
   197  			expression.NewLiteral(int64(5), sql.Int64),
   198  			5,
   199  			false,
   200  		},
   201  		{
   202  			"uint8 literal",
   203  			expression.NewLiteral(uint8(5), sql.Uint8),
   204  			5,
   205  			false,
   206  		},
   207  		{
   208  			"uint16 literal",
   209  			expression.NewLiteral(uint16(5), sql.Uint16),
   210  			5,
   211  			false,
   212  		},
   213  		{
   214  			"uint32 literal",
   215  			expression.NewLiteral(uint32(5), sql.Uint32),
   216  			5,
   217  			false,
   218  		},
   219  		{
   220  			"uint literal",
   221  			expression.NewLiteral(uint(5), sql.Uint32),
   222  			5,
   223  			false,
   224  		},
   225  		{
   226  			"uint64 literal",
   227  			expression.NewLiteral(uint64(5), sql.Uint64),
   228  			5,
   229  			false,
   230  		},
   231  		{
   232  			"true literal",
   233  			expression.NewLiteral(true, sql.Boolean),
   234  			1,
   235  			false,
   236  		},
   237  		{
   238  			"false literal",
   239  			expression.NewLiteral(false, sql.Boolean),
   240  			0,
   241  			false,
   242  		},
   243  		{
   244  			"float32 literal",
   245  			expression.NewLiteral(float32(32.0), sql.Float32),
   246  			32,
   247  			false,
   248  		},
   249  		{
   250  			"float64 literal",
   251  			expression.NewLiteral(float64(32.0), sql.Float64),
   252  			32,
   253  			false,
   254  		},
   255  		{
   256  			"string literal",
   257  			expression.NewLiteral("54321", sql.Text),
   258  			54321,
   259  			false,
   260  		},
   261  		{
   262  			"negative int8 literal",
   263  			expression.NewLiteral(int8(-1), sql.Int8),
   264  			0,
   265  			true,
   266  		},
   267  		{
   268  			"negative int16 literal",
   269  			expression.NewLiteral(int16(-1), sql.Int16),
   270  			0,
   271  			true,
   272  		},
   273  		{
   274  			"negative int32 literal",
   275  			expression.NewLiteral(int32(-1), sql.Int32),
   276  			0,
   277  			true,
   278  		},
   279  		{
   280  			"negative int literal",
   281  			expression.NewLiteral(int(-1), sql.Int32),
   282  			0,
   283  			true,
   284  		},
   285  		{
   286  			"negative int64 literal",
   287  			expression.NewLiteral(int64(-1), sql.Int64),
   288  			0,
   289  			true,
   290  		},
   291  		{
   292  			"float32 with fractional portion",
   293  			expression.NewLiteral(float32(5.0005), sql.Float32),
   294  			0,
   295  			true,
   296  		},
   297  		{
   298  			"float64 with fractional portion",
   299  			expression.NewLiteral(float64(5.0005), sql.Float64),
   300  			0,
   301  			true,
   302  		},
   303  		{
   304  			"string not a number",
   305  			expression.NewLiteral("not a number", sql.Text),
   306  			0,
   307  			true,
   308  		},
   309  	}
   310  
   311  	for _, test := range tests {
   312  		t.Run(test.name, func(t *testing.T) {
   313  			res, err := literalAsUint64(test.l)
   314  			assertOnUnexpectedErr(t, test.expectErr, err)
   315  
   316  			if err == nil {
   317  				assert.Equal(t, test.expected, res)
   318  			}
   319  		})
   320  	}
   321  }
   322  
   323  func TestLiteralAsFloat64(t *testing.T) {
   324  	tests := []struct {
   325  		name      string
   326  		l         *expression.Literal
   327  		expected  float64
   328  		expectErr bool
   329  	}{
   330  		{
   331  			"int8 literal",
   332  			expression.NewLiteral(int8(-5), sql.Int8),
   333  			-5.0,
   334  			false,
   335  		},
   336  		{
   337  			"int16 literal",
   338  			expression.NewLiteral(int16(-5), sql.Int16),
   339  			-5.0,
   340  			false,
   341  		},
   342  		{
   343  			"int32 literal",
   344  			expression.NewLiteral(int32(-5), sql.Int32),
   345  			-5.0,
   346  			false,
   347  		},
   348  		{
   349  			"int literal",
   350  			expression.NewLiteral(int(-5), sql.Int32),
   351  			-5.0,
   352  			false,
   353  		},
   354  		{
   355  			"int64 literal",
   356  			expression.NewLiteral(int64(-5), sql.Int64),
   357  			-5.0,
   358  			false,
   359  		},
   360  		{
   361  			"uint8 literal",
   362  			expression.NewLiteral(uint8(5), sql.Uint8),
   363  			5.0,
   364  			false,
   365  		},
   366  		{
   367  			"uint16 literal",
   368  			expression.NewLiteral(uint16(5), sql.Uint16),
   369  			5.0,
   370  			false,
   371  		},
   372  		{
   373  			"uint32 literal",
   374  			expression.NewLiteral(uint32(5), sql.Uint32),
   375  			5.0,
   376  			false,
   377  		},
   378  		{
   379  			"uint literal",
   380  			expression.NewLiteral(uint(5), sql.Uint32),
   381  			5.0,
   382  			false,
   383  		},
   384  		{
   385  			"uint64 literal",
   386  			expression.NewLiteral(uint64(5), sql.Uint64),
   387  			5.0,
   388  			false,
   389  		},
   390  		{
   391  			"bool literal",
   392  			expression.NewLiteral(true, sql.Boolean),
   393  			0.0,
   394  			true,
   395  		},
   396  		{
   397  			"float32 literal",
   398  			expression.NewLiteral(float32(32.0), sql.Float32),
   399  			32.0,
   400  			false,
   401  		},
   402  		{
   403  			"float64 literal",
   404  			expression.NewLiteral(float64(32.0), sql.Float64),
   405  			32.0,
   406  			false,
   407  		},
   408  		{
   409  			"string literal",
   410  			expression.NewLiteral("-54.321", sql.Text),
   411  			-54.321,
   412  			false,
   413  		},
   414  		{
   415  			"non numeric string",
   416  			expression.NewLiteral("test", sql.Text),
   417  			0,
   418  			true,
   419  		},
   420  	}
   421  
   422  	for _, test := range tests {
   423  		t.Run(test.name, func(t *testing.T) {
   424  			res, err := literalAsFloat64(test.l)
   425  			assertOnUnexpectedErr(t, test.expectErr, err)
   426  
   427  			if err == nil {
   428  				assert.Equal(t, test.expected, res)
   429  			}
   430  		})
   431  	}
   432  }
   433  
   434  func TestLiteralAsBool(t *testing.T) {
   435  	tests := []struct {
   436  		name      string
   437  		l         *expression.Literal
   438  		expected  bool
   439  		expectErr bool
   440  	}{
   441  		{
   442  			"int8 literal",
   443  			expression.NewLiteral(int8(0), sql.Int8),
   444  			false,
   445  			false,
   446  		},
   447  		{
   448  			"int16 literal",
   449  			expression.NewLiteral(int16(1), sql.Int16),
   450  			true,
   451  			false,
   452  		},
   453  		{
   454  			"int32 literal",
   455  			expression.NewLiteral(int32(0), sql.Int32),
   456  			false,
   457  			false,
   458  		},
   459  		{
   460  			"int literal",
   461  			expression.NewLiteral(int(1), sql.Int32),
   462  			true,
   463  			false,
   464  		},
   465  		{
   466  			"int64 literal",
   467  			expression.NewLiteral(int64(0), sql.Int64),
   468  			false,
   469  			false,
   470  		},
   471  
   472  		{
   473  			"uint8 literal",
   474  			expression.NewLiteral(uint8(1), sql.Uint8),
   475  			true,
   476  			false,
   477  		},
   478  		{
   479  			"uint16 literal",
   480  			expression.NewLiteral(uint16(0), sql.Uint16),
   481  			false,
   482  			false,
   483  		},
   484  		{
   485  			"uint32 literal",
   486  			expression.NewLiteral(uint32(1), sql.Uint32),
   487  			true,
   488  			false,
   489  		},
   490  		{
   491  			"uint literal",
   492  			expression.NewLiteral(uint(0), sql.Uint32),
   493  			false,
   494  			false,
   495  		},
   496  		{
   497  			"uint64 literal",
   498  			expression.NewLiteral(uint64(1), sql.Uint64),
   499  			true,
   500  			false,
   501  		},
   502  		{
   503  			"bool literal",
   504  			expression.NewLiteral(true, sql.Boolean),
   505  			true,
   506  			false,
   507  		},
   508  		{
   509  			"float literal not supported",
   510  			expression.NewLiteral(float32(32.0), sql.Float32),
   511  			false,
   512  			true,
   513  		},
   514  		{
   515  			"string literal false",
   516  			expression.NewLiteral("false", sql.Text),
   517  			false,
   518  			false,
   519  		},
   520  		{
   521  			"string literal 1",
   522  			expression.NewLiteral("1", sql.Text),
   523  			true,
   524  			false,
   525  		},
   526  		{
   527  			"non numeric non bool string",
   528  			expression.NewLiteral("test", sql.Text),
   529  			false,
   530  			true,
   531  		},
   532  	}
   533  
   534  	for _, test := range tests {
   535  		t.Run(test.name, func(t *testing.T) {
   536  			res, err := literalAsBool(test.l)
   537  			assertOnUnexpectedErr(t, test.expectErr, err)
   538  
   539  			if err == nil {
   540  				assert.Equal(t, test.expected, res)
   541  			}
   542  		})
   543  	}
   544  }
   545  
   546  func TestLiteralAsString(t *testing.T) {
   547  	tests := []struct {
   548  		name      string
   549  		l         *expression.Literal
   550  		expected  string
   551  		expectErr bool
   552  	}{
   553  		{
   554  			"int literal",
   555  			expression.NewLiteral(5, sql.Int16),
   556  			"5",
   557  			false,
   558  		},
   559  		{
   560  			"uint literal",
   561  			expression.NewLiteral(uint32(5), sql.Uint32),
   562  			"5",
   563  			false,
   564  		},
   565  		{
   566  			"bool literal",
   567  			expression.NewLiteral(true, sql.Boolean),
   568  			"true",
   569  			false,
   570  		},
   571  		{
   572  			"float literal",
   573  			expression.NewLiteral(float32(-2.5), sql.Float32),
   574  			"-2.5",
   575  			false,
   576  		},
   577  		{
   578  			"string literal",
   579  			expression.NewLiteral("test", sql.Text),
   580  			"test",
   581  			false,
   582  		},
   583  	}
   584  
   585  	for _, test := range tests {
   586  		t.Run(test.name, func(t *testing.T) {
   587  			res, err := literalAsString(test.l)
   588  			assertOnUnexpectedErr(t, test.expectErr, err)
   589  
   590  			if err == nil {
   591  				assert.Equal(t, test.expected, res)
   592  			}
   593  		})
   594  	}
   595  }
   596  
   597  func TestParseDate(t *testing.T) {
   598  	tests := []struct {
   599  		name      string
   600  		str       string
   601  		expected  time.Time
   602  		expectErr bool
   603  	}{
   604  		{
   605  			"YYYY-MM-DD",
   606  			"2006-01-02",
   607  			time.Date(2006, 1, 2, 0, 0, 0, 0, time.UTC),
   608  			false,
   609  		},
   610  		{
   611  			"YYYY-MM-DD HH:MM:SS",
   612  			"2006-01-02 15:04:05",
   613  			time.Date(2006, 1, 2, 15, 4, 5, 0, time.UTC),
   614  			false,
   615  		},
   616  		{
   617  			"Invalid format",
   618  			"not a date",
   619  			time.Time{},
   620  			true,
   621  		},
   622  	}
   623  
   624  	for _, test := range tests {
   625  		t.Run(test.name, func(t *testing.T) {
   626  			res, err := parseDate(test.str)
   627  			assertOnUnexpectedErr(t, test.expectErr, err)
   628  
   629  			if err == nil {
   630  				assert.Equal(t, test.expected, res)
   631  			}
   632  		})
   633  	}
   634  }
   635  
   636  func TestLiteralAsTimestamp(t *testing.T) {
   637  	tests := []struct {
   638  		name      string
   639  		l         *expression.Literal
   640  		expected  time.Time
   641  		expectErr bool
   642  	}{
   643  		{
   644  			"YYYY-MM-DD",
   645  			expression.NewLiteral("2006-01-02", sql.Text),
   646  			time.Date(2006, 1, 2, 0, 0, 0, 0, time.UTC),
   647  			false,
   648  		},
   649  		{
   650  			"YYYY-MM-DD HH:MM:SS",
   651  			expression.NewLiteral("2006-01-02 15:04:05", sql.Text),
   652  			time.Date(2006, 1, 2, 15, 4, 5, 0, time.UTC),
   653  			false,
   654  		},
   655  		{
   656  			"Invalid format",
   657  			expression.NewLiteral("not a date", sql.Text),
   658  			time.Time{},
   659  			true,
   660  		},
   661  		{
   662  			"int literal",
   663  			expression.NewLiteral(5, sql.Int8),
   664  			time.Time{},
   665  			true,
   666  		},
   667  	}
   668  
   669  	for _, test := range tests {
   670  		t.Run(test.name, func(t *testing.T) {
   671  			res, err := literalAsTimestamp(test.l)
   672  			assertOnUnexpectedErr(t, test.expectErr, err)
   673  
   674  			if err == nil {
   675  				assert.Equal(t, test.expected, res)
   676  			}
   677  		})
   678  	}
   679  }
   680  
   681  func TestLiteralToNomsValue(t *testing.T) {
   682  	tests := []struct {
   683  		name      string
   684  		l         *expression.Literal
   685  		expected  types.Value
   686  		expectErr bool
   687  	}{
   688  		{"int", expression.NewLiteral(-1, sql.Int32), types.Int(-1), false},
   689  		{"int err", expression.NewLiteral(uint64(0xFFFFFFFFFFFFFFFF), sql.Uint64), types.Int(0), true},
   690  		{"uint", expression.NewLiteral(1, sql.Uint32), types.Uint(1), false},
   691  		{"uint err", expression.NewLiteral(-1, sql.Int16), types.Uint(1), true},
   692  		{"float", expression.NewLiteral(1.5, sql.Float32), types.Float(1.5), false},
   693  		{"float err", expression.NewLiteral("not a valid float", sql.Text), types.Float(1.5), true},
   694  		{"bool", expression.NewLiteral(true, sql.Boolean), types.Bool(true), false},
   695  		{"bool err", expression.NewLiteral("not a valid bool", sql.Text), types.Bool(true), true},
   696  		{"string", expression.NewLiteral("this is a test", sql.Text), types.String("this is a test"), false},
   697  		{
   698  			"date",
   699  			expression.NewLiteral("1900-01-01", sql.Text),
   700  			types.Timestamp(time.Date(1900, 1, 1, 0, 0, 0, 0, time.UTC)),
   701  			false,
   702  		},
   703  		{
   704  			"date err",
   705  			expression.NewLiteral("not a valid date", sql.Text),
   706  			types.Timestamp(time.Date(1900, 1, 1, 0, 0, 0, 0, time.UTC)),
   707  			true,
   708  		},
   709  	}
   710  
   711  	for _, test := range tests {
   712  		t.Run(test.name, func(t *testing.T) {
   713  			res, err := LiteralToNomsValue(test.expected.Kind(), test.l)
   714  			assertOnUnexpectedErr(t, test.expectErr, err)
   715  
   716  			if err == nil {
   717  				assert.Equal(t, test.expected, res)
   718  			}
   719  		})
   720  	}
   721  }