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 }