@@ -7,6 +7,7 @@ package spanset
77
88import (
99 "reflect"
10+ "strings"
1011 "testing"
1112
1213 "github.com/cockroachdb/cockroach/pkg/keys"
@@ -394,3 +395,162 @@ func TestSpanSetWriteImpliesRead(t *testing.T) {
394395 t .Errorf ("expected to be allowed to read rwSpan, error: %+v" , err )
395396 }
396397}
398+
399+ // makeSpanHelper accepts strings like: "a-d", and returns a span with
400+ // startKey = a, and endKey = d. It also accepts `X` which represents nil. For
401+ // example, "X-d" returns a span with a nil startKey, and endKey = d.
402+ func makeSpanHelper (t * testing.T , s string ) roachpb.Span {
403+ parts := strings .Split (s , "-" )
404+ require .Len (t , parts , 2 )
405+
406+ var start roachpb.Key
407+ var end roachpb.Key
408+
409+ if parts [0 ] != "X" {
410+ start = roachpb .Key (parts [0 ])
411+ }
412+
413+ if parts [1 ] != "X" {
414+ end = roachpb .Key (parts [1 ])
415+ }
416+
417+ return roachpb.Span {
418+ Key : start ,
419+ EndKey : end ,
420+ }
421+ }
422+
423+ // Test that Contains correctly determines if s1 contains s2, including
424+ // support for spans with nil start/end keys.
425+ func TestContains (t * testing.T ) {
426+ defer leaktest .AfterTest (t )()
427+
428+ testCases := []struct {
429+ name string
430+ s1 roachpb.Span
431+ s2 roachpb.Span
432+ expected bool
433+ }{
434+ // s1 equals s2.
435+ {s1 : makeSpanHelper (t , "a-c" ), s2 : makeSpanHelper (t , "a-c" ), expected : true },
436+ // s1 contains s2.
437+ {s1 : makeSpanHelper (t , "a-d" ), s2 : makeSpanHelper (t , "b-c" ), expected : true },
438+ // s1 contains point s2.
439+ {s1 : makeSpanHelper (t , "a-d" ), s2 : makeSpanHelper (t , "a-X" ), expected : true },
440+ // Point s1 contains point s2.
441+ {s1 : makeSpanHelper (t , "a-X" ), s2 : makeSpanHelper (t , "a-X" ), expected : true },
442+ // s1 contains point s2 with nil startKey.
443+ {s1 : makeSpanHelper (t , "a-d" ), s2 : makeSpanHelper (t , "X-d" ), expected : true },
444+ // Point s1 contains point s2 with nil startKey.
445+ {s1 : makeSpanHelper (t , "a-X" ), s2 : roachpb.Span {EndKey : roachpb .Key ("a" ).Next ()}, expected : true },
446+ // s1 does not contain s2.
447+ {s1 : makeSpanHelper (t , "a-c" ), s2 : makeSpanHelper (t , "d-f" ), expected : false },
448+ {s1 : makeSpanHelper (t , "a-c" ), s2 : makeSpanHelper (t , "b-d" ), expected : false },
449+ {s1 : makeSpanHelper (t , "b-c" ), s2 : makeSpanHelper (t , "a-d" ), expected : false },
450+ // s1 does not contain s2 point.
451+ {s1 : makeSpanHelper (t , "a-c" ), s2 : makeSpanHelper (t , "d-X" ), expected : false },
452+ // Point s1 does not contain s2.
453+ {s1 : makeSpanHelper (t , "a-X" ), s2 : makeSpanHelper (t , "b-d" ), expected : false },
454+ // Point s1 does not contain point s2.
455+ {s1 : makeSpanHelper (t , "a-X" ), s2 : makeSpanHelper (t , "b-X" ), expected : false },
456+ // s1 does not contain point s2 with nil startKey.
457+ {s1 : makeSpanHelper (t , "a-d" ), s2 : makeSpanHelper (t , "X-e" ), expected : false },
458+ // Point s1 does not contain point s2 with nil startKey.
459+ {s1 : makeSpanHelper (t , "a-X" ), s2 : makeSpanHelper (t , "X-b" ), expected : false },
460+ }
461+
462+ for _ , tc := range testCases {
463+ t .Run (tc .name , func (t * testing.T ) {
464+ require .Equal (t , tc .expected , Contains (tc .s1 , TrickySpan (tc .s2 )))
465+ })
466+ }
467+ }
468+
469+ // Test that Overlaps correctly determines if s1 overlaps s2, including
470+ // support for spans with nil start/end keys.
471+ func TestOverlaps (t * testing.T ) {
472+ defer leaktest .AfterTest (t )()
473+
474+ testCases := []struct {
475+ name string
476+ s1 roachpb.Span
477+ s2 roachpb.Span
478+ expected bool
479+ }{
480+ // s1 equals s2.
481+ {s1 : makeSpanHelper (t , "a-c" ), s2 : makeSpanHelper (t , "a-c" ), expected : true },
482+ // s1 overlaps s2.
483+ {s1 : makeSpanHelper (t , "a-c" ), s2 : makeSpanHelper (t , "b-d" ), expected : true },
484+ // s1 contains s2.
485+ {s1 : makeSpanHelper (t , "a-d" ), s2 : makeSpanHelper (t , "b-c" ), expected : true },
486+ // s2 contains s1.
487+ {s1 : makeSpanHelper (t , "b-c" ), s2 : makeSpanHelper (t , "a-d" ), expected : true },
488+ // s1 overlaps point s2.
489+ {s1 : makeSpanHelper (t , "a-d" ), s2 : makeSpanHelper (t , "a-X" ), expected : true },
490+ // s1 overlaps point s2 with nil startKey.
491+ {s1 : makeSpanHelper (t , "a-d" ), s2 : makeSpanHelper (t , "X-d" ), expected : true },
492+ // Point s1 overlaps point s2 with nil startKey.
493+ {s1 : makeSpanHelper (t , "a-X" ), s2 : roachpb.Span {EndKey : roachpb .Key ("a" ).Next ()}, expected : true },
494+ // Point s1 overlaps point s2.
495+ {s1 : makeSpanHelper (t , "a-X" ), s2 : makeSpanHelper (t , "a-X" ), expected : true },
496+ // s1 doesn't overlap s2.
497+ {s1 : makeSpanHelper (t , "a-c" ), s2 : makeSpanHelper (t , "d-f" ), expected : false },
498+ {s1 : makeSpanHelper (t , "a-c" ), s2 : makeSpanHelper (t , "c-d" ), expected : false },
499+ // s1 doesn't overlap point s2.
500+ {s1 : makeSpanHelper (t , "a-c" ), s2 : makeSpanHelper (t , "c-X" ), expected : false },
501+ // s1 doesn't overlap point s2 with nil startKey.
502+ {s1 : makeSpanHelper (t , "a-c" ), s2 : makeSpanHelper (t , "X-a" ), expected : false },
503+ {s1 : makeSpanHelper (t , "a-c" ), s2 : makeSpanHelper (t , "X-d" ), expected : false },
504+ }
505+
506+ for _ , tc := range testCases {
507+ t .Run ("" , func (t * testing.T ) {
508+ require .Equal (t , tc .expected , Overlaps (tc .s1 , TrickySpan (tc .s2 )))
509+ })
510+ }
511+ }
512+
513+ // Test that PartiallyOverlaps correctly determines if s1 partially overlaps s2,
514+ // including support for spans with nil start/end keys.
515+ func TestPartiallyOverlaps (t * testing.T ) {
516+ defer leaktest .AfterTest (t )()
517+
518+ testCases := []struct {
519+ name string
520+ s1 roachpb.Span
521+ s2 roachpb.Span
522+ expected bool
523+ }{
524+ // s1 equals s2.
525+ {s1 : makeSpanHelper (t , "a-c" ), s2 : makeSpanHelper (t , "a-c" ), expected : false },
526+ // s1 partially overlaps s2.
527+ {s1 : makeSpanHelper (t , "a-c" ), s2 : makeSpanHelper (t , "b-d" ), expected : true },
528+ {s1 : makeSpanHelper (t , "b-d" ), s2 : makeSpanHelper (t , "a-c" ), expected : true },
529+ // s1 contains s2.
530+ {s1 : makeSpanHelper (t , "a-d" ), s2 : makeSpanHelper (t , "b-c" ), expected : false },
531+ // s2 contains s1.
532+ {s1 : makeSpanHelper (t , "b-c" ), s2 : makeSpanHelper (t , "a-d" ), expected : false },
533+ // s1 contains point s2.
534+ {s1 : makeSpanHelper (t , "a-d" ), s2 : makeSpanHelper (t , "a-X" ), expected : false },
535+ // s1 contains point s2 with nil startKey.
536+ {s1 : makeSpanHelper (t , "a-d" ), s2 : makeSpanHelper (t , "X-d" ), expected : false },
537+ // Point s1 contains point s2 with nil startKey.
538+ {s1 : makeSpanHelper (t , "a-X" ), s2 : roachpb.Span {EndKey : roachpb .Key ("a" ).Next ()}, expected : false },
539+ // Point s1 contains point s2.
540+ {s1 : makeSpanHelper (t , "a-X" ), s2 : makeSpanHelper (t , "a-X" ), expected : false },
541+ // s1 doesn't overlap s2.
542+ {s1 : makeSpanHelper (t , "a-c" ), s2 : makeSpanHelper (t , "d-f" ), expected : false },
543+ {s1 : makeSpanHelper (t , "a-c" ), s2 : makeSpanHelper (t , "c-d" ), expected : false },
544+ // s1 doesn't overlap point s2.
545+ {s1 : makeSpanHelper (t , "a-c" ), s2 : makeSpanHelper (t , "c-X" ), expected : false },
546+ // s1 doesn't overlap point s2 with nil startKey.
547+ {s1 : makeSpanHelper (t , "a-c" ), s2 : makeSpanHelper (t , "X-a" ), expected : false },
548+ {s1 : makeSpanHelper (t , "a-c" ), s2 : makeSpanHelper (t , "X-d" ), expected : false },
549+ }
550+
551+ for _ , tc := range testCases {
552+ t .Run ("" , func (t * testing.T ) {
553+ require .Equal (t , tc .expected , PartiallyOverlaps (tc .s1 , TrickySpan (tc .s2 )))
554+ })
555+ }
556+ }
0 commit comments