github.com/dolthub/dolt/go@v0.40.5-0.20240520175717-68db7794bea6/store/val/codec_test.go (about)

     1  // Copyright 2021 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 val
    16  
    17  import (
    18  	"math"
    19  	"testing"
    20  	"time"
    21  
    22  	"github.com/shopspring/decimal"
    23  
    24  	"github.com/stretchr/testify/assert"
    25  )
    26  
    27  func TestCompare(t *testing.T) {
    28  	tests := []struct {
    29  		typ  Type
    30  		l, r []byte
    31  		cmp  int
    32  	}{
    33  		// int
    34  		{
    35  			typ: Type{Enc: Int64Enc},
    36  			l:   encInt(0), r: encInt(0),
    37  			cmp: 0,
    38  		},
    39  		{
    40  			typ: Type{Enc: Int64Enc},
    41  			l:   encInt(-1), r: encInt(0),
    42  			cmp: -1,
    43  		},
    44  		{
    45  			typ: Type{Enc: Int64Enc},
    46  			l:   encInt(1), r: encInt(0),
    47  			cmp: 1,
    48  		},
    49  		// uint
    50  		{
    51  			typ: Type{Enc: Uint64Enc},
    52  			l:   encUint(0), r: encUint(0),
    53  			cmp: 0,
    54  		},
    55  		{
    56  			typ: Type{Enc: Uint64Enc},
    57  			l:   encUint(0), r: encUint(1),
    58  			cmp: -1,
    59  		},
    60  		{
    61  			typ: Type{Enc: Uint64Enc},
    62  			l:   encUint(1), r: encUint(0),
    63  			cmp: 1,
    64  		},
    65  		// float
    66  		{
    67  			typ: Type{Enc: Float64Enc},
    68  			l:   encFloat(0), r: encFloat(0),
    69  			cmp: 0,
    70  		},
    71  		{
    72  			typ: Type{Enc: Float64Enc},
    73  			l:   encFloat(-1), r: encFloat(0),
    74  			cmp: -1,
    75  		},
    76  		{
    77  			typ: Type{Enc: Float64Enc},
    78  			l:   encFloat(1), r: encFloat(0),
    79  			cmp: 1,
    80  		},
    81  		// bit
    82  		{
    83  			typ: Type{Enc: Bit64Enc},
    84  			l:   encBit(0), r: encBit(0),
    85  			cmp: 0,
    86  		},
    87  		{
    88  			typ: Type{Enc: Bit64Enc},
    89  			l:   encBit(0), r: encBit(1),
    90  			cmp: -1,
    91  		},
    92  		{
    93  			typ: Type{Enc: Bit64Enc},
    94  			l:   encBit(1), r: encBit(0),
    95  			cmp: 1,
    96  		},
    97  		// decimal
    98  		{
    99  			typ: Type{Enc: DecimalEnc},
   100  			l:   encDecimal(decimalFromString("-3.7e0")), r: encDecimal(decimalFromString("-3.7e0")),
   101  			cmp: 0,
   102  		},
   103  		{
   104  			typ: Type{Enc: DecimalEnc},
   105  			l:   encDecimal(decimalFromString("5.5729136e3")), r: encDecimal(decimalFromString("2634193746329327479.32030573792e-19")),
   106  			cmp: 1,
   107  		},
   108  		{
   109  			typ: Type{Enc: DecimalEnc},
   110  			l:   encDecimal(decimalFromString("2634193746329327479.32030573792e-19")), r: encDecimal(decimalFromString("5.5729136e3")),
   111  			cmp: -1,
   112  		},
   113  		// year
   114  		{
   115  			typ: Type{Enc: YearEnc},
   116  			l:   encYear(2022), r: encYear(2022),
   117  			cmp: 0,
   118  		},
   119  		{
   120  			typ: Type{Enc: YearEnc},
   121  			l:   encYear(2022), r: encYear(1999),
   122  			cmp: 1,
   123  		},
   124  		{
   125  			typ: Type{Enc: YearEnc},
   126  			l:   encYear(2000), r: encYear(2022),
   127  			cmp: -1,
   128  		},
   129  		// date
   130  		{
   131  			typ: Type{Enc: DateEnc},
   132  			l:   encDate(2022, 05, 24), r: encDate(2022, 05, 24),
   133  			cmp: 0,
   134  		},
   135  		{
   136  			typ: Type{Enc: DateEnc},
   137  			l:   encDate(2022, 12, 24), r: encDate(2022, 05, 24),
   138  			cmp: 1,
   139  		},
   140  		{
   141  			typ: Type{Enc: DateEnc},
   142  			l:   encDate(1999, 04, 24), r: encDate(2022, 05, 24),
   143  			cmp: -1,
   144  		},
   145  		// time
   146  		{
   147  			typ: Type{Enc: TimeEnc},
   148  			l:   encTime(978220860), r: encTime(978220860),
   149  			cmp: 0,
   150  		},
   151  		{
   152  			typ: Type{Enc: TimeEnc},
   153  			l:   encTime(599529660), r: encTime(-11644473600),
   154  			cmp: 1,
   155  		},
   156  		{
   157  			typ: Type{Enc: TimeEnc},
   158  			l:   encTime(-11644473600), r: encTime(599529660),
   159  			cmp: -1,
   160  		},
   161  		// datetime
   162  		{
   163  			typ: Type{Enc: DatetimeEnc},
   164  			l:   encDatetime(time.Date(1999, 11, 01, 01, 01, 01, 00, time.UTC)),
   165  			r:   encDatetime(time.Date(1999, 11, 01, 01, 01, 01, 00, time.UTC)),
   166  			cmp: 0,
   167  		},
   168  		{
   169  			typ: Type{Enc: DatetimeEnc},
   170  			l:   encDatetime(time.Date(2000, 11, 01, 01, 01, 01, 00, time.UTC)),
   171  			r:   encDatetime(time.Date(1999, 11, 01, 01, 01, 01, 00, time.UTC)),
   172  			cmp: 1,
   173  		},
   174  		{
   175  			typ: Type{Enc: DatetimeEnc},
   176  			l:   encDatetime(time.Date(1999, 11, 01, 01, 01, 01, 00, time.UTC)),
   177  			r:   encDatetime(time.Date(2000, 11, 01, 01, 01, 01, 00, time.UTC)),
   178  			cmp: -1,
   179  		},
   180  		// enum
   181  		{
   182  			typ: Type{Enc: EnumEnc},
   183  			l:   encEnum(0), r: encEnum(0),
   184  			cmp: 0,
   185  		},
   186  		{
   187  			typ: Type{Enc: EnumEnc},
   188  			l:   encEnum(0), r: encEnum(1),
   189  			cmp: -1,
   190  		},
   191  		{
   192  			typ: Type{Enc: EnumEnc},
   193  			l:   encEnum(1), r: encEnum(0),
   194  			cmp: 1,
   195  		},
   196  		// set
   197  		{
   198  			typ: Type{Enc: SetEnc},
   199  			l:   encSet(0), r: encSet(0),
   200  			cmp: 0,
   201  		},
   202  		{
   203  			typ: Type{Enc: SetEnc},
   204  			l:   encSet(0), r: encSet(1),
   205  			cmp: -1,
   206  		},
   207  		{
   208  			typ: Type{Enc: SetEnc},
   209  			l:   encSet(1), r: encSet(0),
   210  			cmp: 1,
   211  		},
   212  		// string
   213  		{
   214  			typ: Type{Enc: StringEnc},
   215  			l:   encStr(""), r: encStr(""),
   216  			cmp: 0,
   217  		},
   218  		{
   219  			typ: Type{Enc: StringEnc},
   220  			l:   encStr(""), r: encStr("a"),
   221  			cmp: -1,
   222  		},
   223  		{
   224  			typ: Type{Enc: StringEnc},
   225  			l:   encStr("a"), r: encStr(""),
   226  			cmp: 1,
   227  		},
   228  		{
   229  			typ: Type{Enc: StringEnc},
   230  			l:   encStr("a"), r: encStr("a"),
   231  			cmp: 0,
   232  		},
   233  		{
   234  			typ: Type{Enc: StringEnc},
   235  			l:   encStr("a"), r: encStr("b"),
   236  			cmp: -1,
   237  		},
   238  		{
   239  			typ: Type{Enc: StringEnc},
   240  			l:   encStr("b"), r: encStr("a"),
   241  			cmp: 1,
   242  		},
   243  		// z-address
   244  		{
   245  			typ: Type{Enc: StringEnc},
   246  			l:   encCell(Cell{}),
   247  			r:   encCell(Cell{}),
   248  			cmp: 0,
   249  		},
   250  	}
   251  
   252  	for _, test := range tests {
   253  		act := compare(test.typ, test.l, test.r)
   254  		assert.Equal(t, test.cmp, act, "expected %s %s %s ",
   255  			TupleDesc{}.formatValue(test.typ.Enc, 0, test.l),
   256  			fmtComparator(test.cmp),
   257  			TupleDesc{}.formatValue(test.typ.Enc, 0, test.r))
   258  	}
   259  }
   260  
   261  func fmtComparator(c int) string {
   262  	if c == 0 {
   263  		return "="
   264  	} else if c < 0 {
   265  		return "<"
   266  	} else {
   267  		return ">"
   268  	}
   269  }
   270  
   271  func encInt(i int64) []byte {
   272  	buf := make([]byte, uint64Size)
   273  	writeInt64(buf, i)
   274  	return buf
   275  }
   276  
   277  func encUint(u uint64) []byte {
   278  	buf := make([]byte, int64Size)
   279  	writeUint64(buf, u)
   280  	return buf
   281  }
   282  
   283  func encFloat(f float64) []byte {
   284  	buf := make([]byte, float64Size)
   285  	writeFloat64(buf, f)
   286  	return buf
   287  }
   288  
   289  func encBit(u uint64) []byte {
   290  	buf := make([]byte, bit64Size)
   291  	writeBit64(buf, u)
   292  	return buf
   293  }
   294  
   295  func encDecimal(d decimal.Decimal) []byte {
   296  	buf := make([]byte, sizeOfDecimal(d))
   297  	writeDecimal(buf, d)
   298  	return buf
   299  }
   300  
   301  func encStr(s string) []byte {
   302  	buf := make([]byte, len(s)+1)
   303  	writeString(buf, s)
   304  	return buf
   305  }
   306  
   307  func encCell(c Cell) []byte {
   308  	buf := make([]byte, cellSize)
   309  	writeCell(buf, c)
   310  	return buf
   311  }
   312  
   313  func encYear(y int16) []byte {
   314  	buf := make([]byte, yearSize)
   315  	writeYear(buf, y)
   316  	return buf
   317  }
   318  
   319  func encDate(y, m, d int) []byte {
   320  	date := time.Date(y, time.Month(m), d, 0, 0, 0, 0, time.UTC)
   321  	buf := make([]byte, dateSize)
   322  	writeDate(buf, date)
   323  	return buf
   324  }
   325  
   326  func encTime(t int64) []byte {
   327  	buf := make([]byte, timeSize)
   328  	writeTime(buf, t)
   329  	return buf
   330  }
   331  
   332  func encDatetime(dt time.Time) []byte {
   333  	buf := make([]byte, datetimeSize)
   334  	writeDatetime(buf, dt)
   335  	return buf
   336  }
   337  
   338  func encEnum(u uint16) []byte {
   339  	buf := make([]byte, enumSize)
   340  	writeEnum(buf, u)
   341  	return buf
   342  }
   343  
   344  func encSet(u uint64) []byte {
   345  	buf := make([]byte, setSize)
   346  	writeSet(buf, u)
   347  	return buf
   348  }
   349  
   350  func TestCodecRoundTrip(t *testing.T) {
   351  	t.Run("round trip bool", func(t *testing.T) {
   352  		roundTripBools(t)
   353  	})
   354  	t.Run("round trip ints", func(t *testing.T) {
   355  		roundTripInts(t)
   356  	})
   357  	t.Run("round trip uints", func(t *testing.T) {
   358  		roundTripUints(t)
   359  	})
   360  	t.Run("round trip floats", func(t *testing.T) {
   361  		roundTripFloats(t)
   362  	})
   363  	t.Run("round trip years", func(t *testing.T) {
   364  		roundTripYears(t)
   365  	})
   366  	t.Run("round trip dates", func(t *testing.T) {
   367  		roundTripDates(t)
   368  	})
   369  	t.Run("round trip times", func(t *testing.T) {
   370  		roundTripTimes(t)
   371  	})
   372  	t.Run("round trip datetimes", func(t *testing.T) {
   373  		roundTripDatetimes(t)
   374  	})
   375  	t.Run("round trip decimal", func(t *testing.T) {
   376  		roundTripDecimal(t)
   377  	})
   378  }
   379  
   380  func roundTripBools(t *testing.T) {
   381  	buf := make([]byte, 1)
   382  	integers := []bool{true, false}
   383  	for _, exp := range integers {
   384  		writeBool(buf, exp)
   385  		assert.Equal(t, exp, readBool(buf))
   386  		zero(buf)
   387  	}
   388  }
   389  
   390  func roundTripInts(t *testing.T) {
   391  	buf := make([]byte, int8Size)
   392  	integers := []int64{-1, 0, -1, math.MaxInt8, math.MinInt8}
   393  	for _, value := range integers {
   394  		exp := int8(value)
   395  		writeInt8(buf, exp)
   396  		assert.Equal(t, exp, readInt8(buf))
   397  		zero(buf)
   398  	}
   399  
   400  	buf = make([]byte, int16Size)
   401  	integers = append(integers, math.MaxInt16, math.MaxInt16)
   402  	for _, value := range integers {
   403  		exp := int16(value)
   404  		writeInt16(buf, exp)
   405  		assert.Equal(t, exp, readInt16(buf))
   406  		zero(buf)
   407  	}
   408  
   409  	buf = make([]byte, int32Size)
   410  	integers = append(integers, math.MaxInt32, math.MaxInt32)
   411  	for _, value := range integers {
   412  		exp := int32(value)
   413  		writeInt32(buf, exp)
   414  		assert.Equal(t, exp, readInt32(buf))
   415  		zero(buf)
   416  	}
   417  
   418  	buf = make([]byte, int64Size)
   419  	integers = append(integers, math.MaxInt64, math.MaxInt64)
   420  	for _, value := range integers {
   421  		exp := int64(value)
   422  		writeInt64(buf, exp)
   423  		assert.Equal(t, exp, readInt64(buf))
   424  		zero(buf)
   425  	}
   426  }
   427  
   428  func roundTripUints(t *testing.T) {
   429  	buf := make([]byte, uint8Size)
   430  	uintegers := []uint64{0, 1, math.MaxUint8}
   431  	for _, value := range uintegers {
   432  		exp := uint8(value)
   433  		writeUint8(buf, exp)
   434  		assert.Equal(t, exp, readUint8(buf))
   435  		zero(buf)
   436  	}
   437  
   438  	buf = make([]byte, uint16Size)
   439  	uintegers = append(uintegers, math.MaxUint16)
   440  	for _, value := range uintegers {
   441  		exp := uint16(value)
   442  		WriteUint16(buf, exp)
   443  		assert.Equal(t, exp, ReadUint16(buf))
   444  		zero(buf)
   445  	}
   446  
   447  	buf = make([]byte, enumSize)
   448  	for _, value := range uintegers {
   449  		exp := uint16(value)
   450  		writeEnum(buf, exp)
   451  		assert.Equal(t, exp, readEnum(buf))
   452  		zero(buf)
   453  	}
   454  
   455  	buf = make([]byte, uint32Size)
   456  	uintegers = append(uintegers, math.MaxUint32)
   457  	for _, value := range uintegers {
   458  		exp := uint32(value)
   459  		writeUint32(buf, exp)
   460  		assert.Equal(t, exp, readUint32(buf))
   461  		zero(buf)
   462  	}
   463  
   464  	buf = make([]byte, uint64Size)
   465  	uintegers = append(uintegers, math.MaxUint64)
   466  	for _, value := range uintegers {
   467  		exp := uint64(value)
   468  		writeUint64(buf, exp)
   469  		assert.Equal(t, exp, readUint64(buf))
   470  		zero(buf)
   471  	}
   472  
   473  	buf = make([]byte, bit64Size)
   474  	for _, value := range uintegers {
   475  		exp := uint64(value)
   476  		writeBit64(buf, exp)
   477  		assert.Equal(t, exp, readBit64(buf))
   478  		zero(buf)
   479  	}
   480  
   481  	buf = make([]byte, setSize)
   482  	for _, value := range uintegers {
   483  		exp := uint64(value)
   484  		writeSet(buf, exp)
   485  		assert.Equal(t, exp, readSet(buf))
   486  		zero(buf)
   487  	}
   488  }
   489  
   490  func roundTripFloats(t *testing.T) {
   491  	buf := make([]byte, float32Size)
   492  	floats := []float64{-1, 0, 1, math.MaxFloat32, math.SmallestNonzeroFloat32}
   493  	for _, value := range floats {
   494  		exp := float32(value)
   495  		writeFloat32(buf, exp)
   496  		assert.Equal(t, exp, readFloat32(buf))
   497  		zero(buf)
   498  	}
   499  
   500  	buf = make([]byte, float64Size)
   501  	floats = append(floats, math.MaxFloat64, math.SmallestNonzeroFloat64)
   502  	for _, value := range floats {
   503  		exp := float64(value)
   504  		writeFloat64(buf, exp)
   505  		assert.Equal(t, exp, readFloat64(buf))
   506  		zero(buf)
   507  	}
   508  }
   509  
   510  func roundTripYears(t *testing.T) {
   511  	years := []int16{
   512  		1901,
   513  		2022,
   514  		2155,
   515  	}
   516  
   517  	buf := make([]byte, yearSize)
   518  	for _, y := range years {
   519  		writeYear(buf, y)
   520  		assert.Equal(t, y, readYear(buf))
   521  		zero(buf)
   522  	}
   523  }
   524  
   525  func roundTripDates(t *testing.T) {
   526  	dates := []time.Time{
   527  		testDate(1000, 01, 01),
   528  		testDate(2022, 05, 24),
   529  		testDate(9999, 12, 31),
   530  	}
   531  
   532  	buf := make([]byte, dateSize)
   533  	for _, d := range dates {
   534  		writeDate(buf, d)
   535  		assert.Equal(t, d, readDate(buf))
   536  		zero(buf)
   537  	}
   538  }
   539  
   540  func roundTripTimes(t *testing.T) {
   541  	times := []int64{
   542  		-1221681866,
   543  		-11644473600,
   544  		599529660,
   545  		978220860,
   546  	}
   547  
   548  	buf := make([]byte, timeSize)
   549  	for _, d := range times {
   550  		writeTime(buf, d)
   551  		assert.Equal(t, d, readTime(buf))
   552  		zero(buf)
   553  	}
   554  }
   555  
   556  func roundTripDatetimes(t *testing.T) {
   557  	datetimes := []time.Time{
   558  		time.Date(1000, 01, 01, 0, 0, 0, 0, time.UTC),
   559  		time.UnixMicro(time.Now().UTC().UnixMicro()).UTC(),
   560  		time.Date(9999, 12, 31, 23, 59, 59, 0, time.UTC),
   561  	}
   562  
   563  	buf := make([]byte, datetimeSize)
   564  	for _, dt := range datetimes {
   565  		writeDatetime(buf, dt)
   566  		assert.Equal(t, dt, readDatetime(buf))
   567  		zero(buf)
   568  	}
   569  }
   570  
   571  func roundTripDecimal(t *testing.T) {
   572  	decimals := []decimal.Decimal{
   573  		decimalFromString("0"),
   574  		decimalFromString("1"),
   575  		decimalFromString("-1"),
   576  		decimalFromString("-3.7e0"),
   577  		decimalFromString("0.00000000000000000003e20"),
   578  		decimalFromString(".22"),
   579  		decimalFromString("-.7863294659345624"),
   580  		decimalFromString("2634193746329327479.32030573792e-19"),
   581  		decimalFromString("7742"),
   582  		decimalFromString("99999.999994"),
   583  		decimalFromString("5.5729136e3"),
   584  		decimalFromString("600e-2"),
   585  		decimalFromString("-99999.999995"),
   586  		decimalFromString("99999999999999999999999999999999999999999999999999999999999999999"),
   587  		decimalFromString("99999999999999999999999999999999999999999999999999999999999999999.1"),
   588  		decimalFromString("99999999999999999999999999999999999999999999999999999999999999999.99"),
   589  		decimalFromString("16976349273982359874209023948672021737840592720387475.2719128737543572927374503832837350563300243035038234972093785"),
   590  		decimalFromString("99999999999999999999999999999999999999999999999999999.9999999999999"),
   591  	}
   592  
   593  	for _, dec := range decimals {
   594  		buf := make([]byte, sizeOfDecimal(dec))
   595  		writeDecimal(buf, dec)
   596  		actual := readDecimal(buf)
   597  		assert.True(t, dec.Equal(actual), "%s != %s",
   598  			dec.String(), actual.String())
   599  		assert.Equal(t, dec, actual)
   600  		zero(buf)
   601  	}
   602  }
   603  
   604  func testDate(y, m, d int) (date time.Time) {
   605  	return time.Date(y, time.Month(m), d, 0, 0, 0, 0, time.UTC)
   606  }
   607  
   608  func decimalFromString(s string) decimal.Decimal {
   609  	d, err := decimal.NewFromString(s)
   610  	if err != nil {
   611  		panic(err)
   612  	}
   613  	return d
   614  }
   615  
   616  func zero(buf []byte) {
   617  	for i := range buf {
   618  		buf[i] = 0
   619  	}
   620  }