github.com/cockroachdb/cockroach@v20.2.0-alpha.1+incompatible/pkg/sql/opt/constraint/span_test.go (about) 1 // Copyright 2018 The Cockroach Authors. 2 // 3 // Use of this software is governed by the Business Source License 4 // included in the file licenses/BSL.txt. 5 // 6 // As of the Change Date specified in that file, in accordance with 7 // the Business Source License, use of this software will be governed 8 // by the Apache License, Version 2.0, included in the file 9 // licenses/APL.txt. 10 // 11 // This file implements data structures used by index constraints generation. 12 13 package constraint 14 15 import ( 16 "fmt" 17 "math" 18 "testing" 19 20 "github.com/cockroachdb/cockroach/pkg/settings/cluster" 21 "github.com/cockroachdb/cockroach/pkg/sql/sem/tree" 22 ) 23 24 func TestSpanSet(t *testing.T) { 25 testCases := []struct { 26 start Key 27 startBoundary SpanBoundary 28 end Key 29 endBoundary SpanBoundary 30 expected string 31 }{ 32 { // 0 33 MakeKey(tree.NewDInt(1)), IncludeBoundary, 34 MakeKey(tree.NewDInt(5)), IncludeBoundary, 35 "[/1 - /5]", 36 }, 37 { // 1 38 MakeCompositeKey(tree.NewDString("cherry"), tree.NewDInt(5)), IncludeBoundary, 39 MakeCompositeKey(tree.NewDString("mango"), tree.NewDInt(1)), ExcludeBoundary, 40 "[/'cherry'/5 - /'mango'/1)", 41 }, 42 { // 2 43 MakeCompositeKey(tree.NewDInt(5), tree.NewDInt(1)), ExcludeBoundary, 44 MakeKey(tree.NewDInt(5)), IncludeBoundary, 45 "(/5/1 - /5]", 46 }, 47 { // 3 48 MakeKey(tree.NewDInt(5)), IncludeBoundary, 49 MakeCompositeKey(tree.NewDInt(5), tree.NewDInt(1)), ExcludeBoundary, 50 "[/5 - /5/1)", 51 }, 52 { // 4 53 MakeKey(tree.DNull), IncludeBoundary, 54 MakeCompositeKey(tree.NewDInt(5), tree.NewDInt(1)), ExcludeBoundary, 55 "[/NULL - /5/1)", 56 }, 57 } 58 59 for i, tc := range testCases { 60 t.Run(fmt.Sprintf("%d", i), func(t *testing.T) { 61 var sp Span 62 sp.Init(tc.start, tc.startBoundary, tc.end, tc.endBoundary) 63 if sp.String() != tc.expected { 64 t.Errorf("expected: %s, actual: %s", tc.expected, sp.String()) 65 } 66 }) 67 } 68 69 testPanic := func(t *testing.T, fn func(), expected string) { 70 t.Helper() 71 defer func() { 72 if r := recover(); r == nil { 73 t.Errorf("panic expected with message: %s", expected) 74 } else if fmt.Sprint(r) != expected { 75 t.Errorf("expected: %s, actual: %v", expected, r) 76 } 77 }() 78 fn() 79 } 80 81 var sp Span 82 // Create exclusive empty start boundary. 83 testPanic(t, func() { 84 sp.Init(EmptyKey, ExcludeBoundary, MakeKey(tree.DNull), IncludeBoundary) 85 }, "an empty start boundary must be inclusive") 86 87 // Create exclusive empty end boundary. 88 testPanic(t, func() { 89 sp.Init(MakeKey(tree.DNull), IncludeBoundary, EmptyKey, ExcludeBoundary) 90 }, "an empty end boundary must be inclusive") 91 } 92 93 func TestSpanUnconstrained(t *testing.T) { 94 // Test unconstrained span. 95 unconstrained := Span{} 96 if !unconstrained.IsUnconstrained() { 97 t.Errorf("default span is not unconstrained") 98 } 99 100 if unconstrained.String() != "[ - ]" { 101 t.Errorf("unexpected string value for unconstrained span: %s", unconstrained.String()) 102 } 103 104 unconstrained.startBoundary = IncludeBoundary 105 unconstrained.start = MakeKey(tree.DNull) 106 if !unconstrained.IsUnconstrained() { 107 t.Errorf("span beginning with NULL is not unconstrained") 108 } 109 110 // Test constrained span's IsUnconstrained method. 111 var sp Span 112 sp.Init(MakeKey(tree.NewDInt(5)), IncludeBoundary, MakeKey(tree.NewDInt(5)), IncludeBoundary) 113 if sp.IsUnconstrained() { 114 t.Errorf("IsUnconstrained should have returned false") 115 } 116 } 117 118 func TestSpanSingleKey(t *testing.T) { 119 testCases := []struct { 120 start Key 121 startBoundary SpanBoundary 122 end Key 123 endBoundary SpanBoundary 124 expected bool 125 }{ 126 { // 0 127 MakeKey(tree.NewDInt(1)), IncludeBoundary, 128 MakeKey(tree.NewDInt(1)), IncludeBoundary, 129 true, 130 }, 131 { // 1 132 MakeKey(tree.NewDInt(1)), IncludeBoundary, 133 MakeKey(tree.NewDInt(2)), IncludeBoundary, 134 false, 135 }, 136 { // 2 137 MakeKey(tree.NewDInt(1)), IncludeBoundary, 138 MakeKey(tree.NewDInt(1)), ExcludeBoundary, 139 false, 140 }, 141 { // 3 142 MakeKey(tree.NewDInt(1)), ExcludeBoundary, 143 MakeKey(tree.NewDInt(1)), IncludeBoundary, 144 false, 145 }, 146 { // 4 147 EmptyKey, IncludeBoundary, 148 MakeKey(tree.NewDInt(1)), IncludeBoundary, 149 false, 150 }, 151 { // 5 152 MakeKey(tree.NewDInt(1)), IncludeBoundary, 153 EmptyKey, IncludeBoundary, 154 false, 155 }, 156 { // 6 157 MakeKey(tree.NewDInt(1)), IncludeBoundary, 158 MakeKey(tree.DNull), IncludeBoundary, 159 false, 160 }, 161 { // 7 162 MakeKey(tree.NewDString("a")), IncludeBoundary, 163 MakeKey(tree.NewDString("ab")), IncludeBoundary, 164 false, 165 }, 166 { // 8 167 MakeCompositeKey(tree.NewDString("cherry"), tree.NewDInt(1)), IncludeBoundary, 168 MakeCompositeKey(tree.NewDString("cherry"), tree.NewDInt(1)), IncludeBoundary, 169 true, 170 }, 171 { // 9 172 MakeCompositeKey(tree.NewDString("cherry"), tree.NewDInt(1)), IncludeBoundary, 173 MakeCompositeKey(tree.NewDString("mango"), tree.NewDInt(1)), IncludeBoundary, 174 false, 175 }, 176 { // 10 177 MakeCompositeKey(tree.NewDString("cherry")), IncludeBoundary, 178 MakeCompositeKey(tree.NewDString("cherry"), tree.NewDInt(1)), IncludeBoundary, 179 false, 180 }, 181 { // 11 182 MakeCompositeKey(tree.NewDString("cherry"), tree.NewDInt(1), tree.DNull), IncludeBoundary, 183 MakeCompositeKey(tree.NewDString("cherry"), tree.NewDInt(1), tree.DNull), IncludeBoundary, 184 true, 185 }, 186 } 187 188 for i, tc := range testCases { 189 st := cluster.MakeTestingClusterSettings() 190 evalCtx := tree.MakeTestingEvalContext(st) 191 192 t.Run(fmt.Sprintf("%d", i), func(t *testing.T) { 193 var sp Span 194 sp.Init(tc.start, tc.startBoundary, tc.end, tc.endBoundary) 195 if sp.HasSingleKey(&evalCtx) != tc.expected { 196 t.Errorf("expected: %v, actual: %v", tc.expected, !tc.expected) 197 } 198 }) 199 } 200 } 201 202 func TestSpanCompare(t *testing.T) { 203 keyCtx := testKeyContext(1, 2) 204 205 testComp := func(t *testing.T, left, right Span, expected int) { 206 t.Helper() 207 if actual := left.Compare(keyCtx, &right); actual != expected { 208 format := "left: %s, right: %s, expected: %v, actual: %v" 209 t.Errorf(format, left.String(), right.String(), expected, actual) 210 } 211 } 212 213 one := MakeKey(tree.NewDInt(1)) 214 two := MakeKey(tree.NewDInt(2)) 215 oneone := MakeCompositeKey(tree.NewDInt(1), tree.NewDInt(1)) 216 twoone := MakeCompositeKey(tree.NewDInt(2), tree.NewDInt(1)) 217 218 var spans [17]Span 219 220 // [ - /2) 221 spans[0].Init(EmptyKey, IncludeBoundary, two, ExcludeBoundary) 222 223 // [ - /2/1) 224 spans[1].Init(EmptyKey, IncludeBoundary, twoone, ExcludeBoundary) 225 226 // [ - /2/1] 227 spans[2].Init(EmptyKey, IncludeBoundary, twoone, IncludeBoundary) 228 229 // [ - /2] 230 spans[3].Init(EmptyKey, IncludeBoundary, two, IncludeBoundary) 231 232 // [ - ] 233 spans[4] = Span{} 234 235 // [/1 - /2/1) 236 spans[5].Init(one, IncludeBoundary, twoone, ExcludeBoundary) 237 238 // [/1 - /2/1] 239 spans[6].Init(one, IncludeBoundary, twoone, IncludeBoundary) 240 241 // [/1 - ] 242 spans[7].Init(one, IncludeBoundary, EmptyKey, IncludeBoundary) 243 244 // [/1/1 - /2) 245 spans[8].Init(oneone, IncludeBoundary, two, ExcludeBoundary) 246 247 // [/1/1 - /2] 248 spans[9].Init(oneone, IncludeBoundary, two, IncludeBoundary) 249 250 // [/1/1 - ] 251 spans[10].Init(oneone, IncludeBoundary, EmptyKey, IncludeBoundary) 252 253 // (/1/1 - /2) 254 spans[11].Init(oneone, ExcludeBoundary, two, ExcludeBoundary) 255 256 // (/1/1 - /2] 257 spans[12].Init(oneone, ExcludeBoundary, two, IncludeBoundary) 258 259 // (/1/1 - ] 260 spans[13].Init(oneone, ExcludeBoundary, EmptyKey, IncludeBoundary) 261 262 // (/1 - /2/1) 263 spans[14].Init(one, ExcludeBoundary, twoone, ExcludeBoundary) 264 265 // (/1 - /2/1] 266 spans[15].Init(one, ExcludeBoundary, twoone, IncludeBoundary) 267 268 // (/1 - ] 269 spans[16].Init(one, ExcludeBoundary, EmptyKey, IncludeBoundary) 270 271 for i := 0; i < len(spans)-1; i++ { 272 testComp(t, spans[i], spans[i+1], -1) 273 testComp(t, spans[i+1], spans[i], 1) 274 testComp(t, spans[i], spans[i], 0) 275 testComp(t, spans[i+1], spans[i+1], 0) 276 } 277 278 keyCtx = testKeyContext(-1, 2) 279 280 // [ - /1) 281 spans[0].Init(EmptyKey, IncludeBoundary, one, ExcludeBoundary) 282 283 // [ - /1/1) 284 spans[1].Init(EmptyKey, IncludeBoundary, oneone, ExcludeBoundary) 285 286 // [ - /1/1] 287 spans[2].Init(EmptyKey, IncludeBoundary, oneone, IncludeBoundary) 288 289 // [ - /1] 290 spans[3].Init(EmptyKey, IncludeBoundary, one, IncludeBoundary) 291 292 // [ - ] 293 spans[4] = Span{} 294 295 // [/2 - /1/1) 296 spans[5].Init(two, IncludeBoundary, oneone, ExcludeBoundary) 297 298 // [/2 - /1/1] 299 spans[6].Init(two, IncludeBoundary, oneone, IncludeBoundary) 300 301 // [/2 - ] 302 spans[7].Init(two, IncludeBoundary, EmptyKey, IncludeBoundary) 303 304 // [/2/1 - /1) 305 spans[8].Init(twoone, IncludeBoundary, one, ExcludeBoundary) 306 307 // [/2/1 - /1] 308 spans[9].Init(twoone, IncludeBoundary, one, IncludeBoundary) 309 310 // [/2/1 - ] 311 spans[10].Init(twoone, IncludeBoundary, EmptyKey, IncludeBoundary) 312 313 // (/2/1 - /1) 314 spans[11].Init(twoone, ExcludeBoundary, one, ExcludeBoundary) 315 316 // (/2/1 - /1] 317 spans[12].Init(twoone, ExcludeBoundary, one, IncludeBoundary) 318 319 // (/2/1 - ] 320 spans[13].Init(twoone, ExcludeBoundary, EmptyKey, IncludeBoundary) 321 322 // (/2 - /1/1) 323 spans[14].Init(two, ExcludeBoundary, oneone, ExcludeBoundary) 324 325 // (/2 - /1/1] 326 spans[15].Init(two, ExcludeBoundary, oneone, IncludeBoundary) 327 328 // (/2 - ] 329 spans[16].Init(two, ExcludeBoundary, EmptyKey, IncludeBoundary) 330 331 for i := 0; i < len(spans)-1; i++ { 332 testComp(t, spans[i], spans[i+1], -1) 333 testComp(t, spans[i+1], spans[i], 1) 334 testComp(t, spans[i], spans[i], 0) 335 testComp(t, spans[i+1], spans[i+1], 0) 336 } 337 } 338 339 func TestSpanCompareStarts(t *testing.T) { 340 keyCtx := testKeyContext(1, 2) 341 342 test := func(left, right Span, expected int) { 343 t.Helper() 344 if actual := left.CompareStarts(keyCtx, &right); actual != expected { 345 format := "left: %s, right: %s, expected: %v, actual: %v" 346 t.Errorf(format, left.String(), right.String(), expected, actual) 347 } 348 } 349 350 one := MakeKey(tree.NewDInt(1)) 351 two := MakeKey(tree.NewDInt(2)) 352 five := MakeKey(tree.NewDInt(5)) 353 nine := MakeKey(tree.NewDInt(9)) 354 355 var onefive Span 356 onefive.Init(one, IncludeBoundary, five, IncludeBoundary) 357 var twonine Span 358 twonine.Init(two, ExcludeBoundary, nine, ExcludeBoundary) 359 360 // Same span. 361 test(onefive, onefive, 0) 362 363 // Different spans. 364 test(onefive, twonine, -1) 365 test(twonine, onefive, 1) 366 } 367 368 func TestSpanCompareEnds(t *testing.T) { 369 keyCtx := testKeyContext(1, 2) 370 371 test := func(left, right Span, expected int) { 372 t.Helper() 373 if actual := left.CompareEnds(keyCtx, &right); actual != expected { 374 format := "left: %s, right: %s, expected: %v, actual: %v" 375 t.Errorf(format, left.String(), right.String(), expected, actual) 376 } 377 } 378 379 one := MakeKey(tree.NewDInt(1)) 380 two := MakeKey(tree.NewDInt(2)) 381 five := MakeKey(tree.NewDInt(5)) 382 nine := MakeKey(tree.NewDInt(9)) 383 384 var onefive Span 385 onefive.Init(one, IncludeBoundary, five, IncludeBoundary) 386 var twonine Span 387 twonine.Init(two, ExcludeBoundary, nine, ExcludeBoundary) 388 389 // Same span. 390 test(onefive, onefive, 0) 391 392 // Different spans. 393 test(onefive, twonine, -1) 394 test(twonine, onefive, 1) 395 } 396 397 func TestSpanStartsAfter(t *testing.T) { 398 keyCtx := testKeyContext(1, 2) 399 400 test := func(left, right Span, expected, expectedStrict bool) { 401 t.Helper() 402 if actual := left.StartsAfter(keyCtx, &right); actual != expected { 403 format := "left: %s, right: %s, expected: %v, actual: %v" 404 t.Errorf(format, left.String(), right.String(), expected, actual) 405 } 406 if actual := left.StartsStrictlyAfter(keyCtx, &right); actual != expectedStrict { 407 format := "left: %s, right: %s, expected: %v, actual: %v" 408 t.Errorf(format, left.String(), right.String(), expectedStrict, actual) 409 } 410 } 411 412 // Same span. 413 var banana Span 414 banana.Init( 415 MakeCompositeKey(tree.DNull, tree.NewDInt(100)), IncludeBoundary, 416 MakeCompositeKey(tree.NewDString("banana"), tree.NewDInt(50)), IncludeBoundary, 417 ) 418 test(banana, banana, false, false) 419 420 // Right span's start equal to left span's end. 421 var cherry Span 422 cherry.Init( 423 MakeCompositeKey(tree.NewDString("banana"), tree.NewDInt(50)), ExcludeBoundary, 424 MakeKey(tree.NewDString("cherry")), ExcludeBoundary, 425 ) 426 test(banana, cherry, false, false) 427 test(cherry, banana, true, false) 428 429 // Right span's start greater than left span's end, and inverse. 430 var cherry2 Span 431 cherry2.Init( 432 MakeCompositeKey(tree.NewDString("cherry"), tree.NewDInt(0)), IncludeBoundary, 433 MakeKey(tree.NewDString("mango")), ExcludeBoundary, 434 ) 435 test(cherry, cherry2, false, false) 436 test(cherry2, cherry, true, true) 437 } 438 439 func TestSpanIntersect(t *testing.T) { 440 keyCtx := testKeyContext(1, 2) 441 testInt := func(left, right Span, expected string) { 442 t.Helper() 443 sp := left 444 ok := sp.TryIntersectWith(keyCtx, &right) 445 446 var actual string 447 if ok { 448 actual = sp.String() 449 } 450 451 if actual != expected { 452 format := "left: %s, right: %s, expected: %v, actual: %v" 453 t.Errorf(format, left.String(), right.String(), expected, actual) 454 } 455 } 456 457 // Same span. 458 var banana Span 459 banana.Init( 460 MakeCompositeKey(tree.DNull, tree.NewDInt(100)), IncludeBoundary, 461 MakeCompositeKey(tree.NewDString("banana"), tree.NewDInt(50)), IncludeBoundary, 462 ) 463 testInt(banana, banana, "[/NULL/100 - /'banana'/50]") 464 465 // One span immediately after the other. 466 var grape Span 467 grape.Init( 468 MakeCompositeKey(tree.NewDString("banana"), tree.NewDInt(50)), ExcludeBoundary, 469 MakeCompositeKey(tree.NewDString("grape")), ExcludeBoundary, 470 ) 471 testInt(banana, grape, "") 472 testInt(grape, banana, "") 473 474 // Partial overlap. 475 var apple Span 476 apple.Init( 477 MakeCompositeKey(tree.NewDString("apple"), tree.NewDInt(200)), ExcludeBoundary, 478 MakeCompositeKey(tree.NewDString("cherry"), tree.NewDInt(300)), ExcludeBoundary, 479 ) 480 testInt(banana, apple, "(/'apple'/200 - /'banana'/50]") 481 testInt(apple, banana, "(/'apple'/200 - /'banana'/50]") 482 483 // One span is subset of other. 484 var mango Span 485 mango.Init( 486 MakeCompositeKey(tree.NewDString("apple"), tree.NewDInt(200)), ExcludeBoundary, 487 MakeCompositeKey(tree.NewDString("mango")), ExcludeBoundary, 488 ) 489 testInt(apple, mango, "(/'apple'/200 - /'cherry'/300)") 490 testInt(mango, apple, "(/'apple'/200 - /'cherry'/300)") 491 testInt(Span{}, mango, "(/'apple'/200 - /'mango')") 492 testInt(mango, Span{}, "(/'apple'/200 - /'mango')") 493 494 // Spans are disjoint. 495 var pear Span 496 pear.Init( 497 MakeCompositeKey(tree.NewDString("mango"), tree.NewDInt(0)), IncludeBoundary, 498 MakeCompositeKey(tree.NewDString("pear"), tree.NewDInt(10)), IncludeBoundary, 499 ) 500 testInt(mango, pear, "") 501 testInt(pear, mango, "") 502 503 // Ensure that if TryIntersectWith results in empty set, that it does not 504 // update either span. 505 mango2 := mango 506 pear2 := pear 507 mango2.TryIntersectWith(keyCtx, &pear2) 508 if mango2.Compare(keyCtx, &mango) != 0 { 509 t.Errorf("mango2 was incorrectly updated during TryIntersectWith") 510 } 511 if pear2.Compare(keyCtx, &pear) != 0 { 512 t.Errorf("pear2 was incorrectly updated during TryIntersectWith") 513 } 514 515 // Partial overlap on second key. 516 pear2.Init( 517 MakeCompositeKey(tree.NewDString("pear"), tree.NewDInt(5), tree.DNull), ExcludeBoundary, 518 MakeCompositeKey(tree.NewDString("raspberry"), tree.NewDInt(100)), IncludeBoundary, 519 ) 520 testInt(pear, pear2, "(/'pear'/5/NULL - /'pear'/10]") 521 testInt(pear2, pear, "(/'pear'/5/NULL - /'pear'/10]") 522 523 // Unconstrained (uninitialized) span. 524 testInt(banana, Span{}, "[/NULL/100 - /'banana'/50]") 525 testInt(Span{}, banana, "[/NULL/100 - /'banana'/50]") 526 } 527 528 func TestSpanUnion(t *testing.T) { 529 keyCtx := testKeyContext(1, 2) 530 531 testUnion := func(left, right Span, expected string) { 532 t.Helper() 533 sp := left 534 ok := sp.TryUnionWith(keyCtx, &right) 535 536 var actual string 537 if ok { 538 actual = sp.String() 539 } 540 541 if actual != expected { 542 format := "left: %s, right: %s, expected: %v, actual: %v" 543 t.Errorf(format, left.String(), right.String(), expected, actual) 544 } 545 } 546 547 // Same span. 548 var banana Span 549 banana.Init( 550 MakeCompositeKey(tree.DNull, tree.NewDInt(100)), IncludeBoundary, 551 MakeCompositeKey(tree.NewDString("banana"), tree.NewDInt(50)), IncludeBoundary, 552 ) 553 testUnion(banana, banana, "[/NULL/100 - /'banana'/50]") 554 555 // Partial overlap. 556 var apple Span 557 apple.Init( 558 MakeCompositeKey(tree.NewDString("apple"), tree.NewDInt(200)), ExcludeBoundary, 559 MakeCompositeKey(tree.NewDString("cherry"), tree.NewDInt(300)), ExcludeBoundary, 560 ) 561 testUnion(banana, apple, "[/NULL/100 - /'cherry'/300)") 562 testUnion(apple, banana, "[/NULL/100 - /'cherry'/300)") 563 564 // One span is subset of other. 565 var mango Span 566 mango.Init( 567 MakeCompositeKey(tree.NewDString("apple"), tree.NewDInt(200)), ExcludeBoundary, 568 MakeCompositeKey(tree.NewDString("mango")), ExcludeBoundary, 569 ) 570 testUnion(apple, mango, "(/'apple'/200 - /'mango')") 571 testUnion(mango, apple, "(/'apple'/200 - /'mango')") 572 testUnion(Span{}, mango, "[ - ]") 573 testUnion(mango, Span{}, "[ - ]") 574 575 // Spans are disjoint. 576 var pear Span 577 pear.Init( 578 MakeCompositeKey(tree.NewDString("mango"), tree.NewDInt(0)), IncludeBoundary, 579 MakeCompositeKey(tree.NewDString("pear"), tree.NewDInt(10)), IncludeBoundary, 580 ) 581 testUnion(mango, pear, "") 582 testUnion(pear, mango, "") 583 584 // Ensure that if TryUnionWith fails to merge, that it does not update 585 // either span. 586 mango2 := mango 587 pear2 := pear 588 mango2.TryUnionWith(keyCtx, &pear2) 589 if mango2.Compare(keyCtx, &mango) != 0 { 590 t.Errorf("mango2 was incorrectly updated during TryUnionWith") 591 } 592 if pear2.Compare(keyCtx, &pear) != 0 { 593 t.Errorf("pear2 was incorrectly updated during TryUnionWith") 594 } 595 596 // Partial overlap on second key. 597 pear2.Init( 598 MakeCompositeKey(tree.NewDString("pear"), tree.NewDInt(5), tree.DNull), ExcludeBoundary, 599 MakeCompositeKey(tree.NewDString("raspberry"), tree.NewDInt(100)), IncludeBoundary, 600 ) 601 testUnion(pear, pear2, "[/'mango'/0 - /'raspberry'/100]") 602 testUnion(pear, pear2, "[/'mango'/0 - /'raspberry'/100]") 603 604 // Unconstrained (uninitialized) span. 605 testUnion(banana, Span{}, "[ - ]") 606 testUnion(Span{}, banana, "[ - ]") 607 } 608 609 func TestSpanPreferInclusive(t *testing.T) { 610 keyCtx := testKeyContext(1, 2) 611 612 testCases := []struct { 613 start Key 614 startBoundary SpanBoundary 615 end Key 616 endBoundary SpanBoundary 617 expected string 618 }{ 619 { // 0 620 MakeKey(tree.NewDInt(1)), IncludeBoundary, 621 MakeKey(tree.NewDInt(5)), IncludeBoundary, 622 "[/1 - /5]", 623 }, 624 { // 1 625 MakeKey(tree.NewDInt(1)), IncludeBoundary, 626 MakeKey(tree.NewDInt(5)), ExcludeBoundary, 627 "[/1 - /4]", 628 }, 629 { // 2 630 MakeKey(tree.NewDInt(1)), ExcludeBoundary, 631 MakeKey(tree.NewDInt(5)), IncludeBoundary, 632 "[/2 - /5]", 633 }, 634 { // 3 635 MakeKey(tree.NewDInt(1)), ExcludeBoundary, 636 MakeKey(tree.NewDInt(5)), ExcludeBoundary, 637 "[/2 - /4]", 638 }, 639 { // 4 640 MakeCompositeKey(tree.NewDInt(1), tree.NewDInt(math.MaxInt64)), ExcludeBoundary, 641 MakeCompositeKey(tree.NewDInt(2), tree.NewDInt(math.MinInt64)), ExcludeBoundary, 642 "(/1/9223372036854775807 - /2/-9223372036854775808)", 643 }, 644 { // 5 645 MakeCompositeKey(tree.NewDString("cherry"), tree.NewDInt(5)), ExcludeBoundary, 646 MakeCompositeKey(tree.NewDString("mango"), tree.NewDInt(1)), ExcludeBoundary, 647 "[/'cherry'/6 - /'mango'/0]", 648 }, 649 { // 6 650 MakeCompositeKey(tree.NewDInt(1), tree.NewDString("cherry")), ExcludeBoundary, 651 MakeCompositeKey(tree.NewDInt(2), tree.NewDString("mango")), ExcludeBoundary, 652 "[/1/e'cherry\\x00' - /2/'mango')", 653 }, 654 } 655 656 for i, tc := range testCases { 657 t.Run(fmt.Sprintf("%d", i), func(t *testing.T) { 658 var sp Span 659 sp.Init(tc.start, tc.startBoundary, tc.end, tc.endBoundary) 660 sp.PreferInclusive(keyCtx) 661 if sp.String() != tc.expected { 662 t.Errorf("expected: %s, actual: %s", tc.expected, sp.String()) 663 } 664 }) 665 } 666 }