128 lines
3.6 KiB
Go
128 lines
3.6 KiB
Go
package trim
|
|
|
|
import (
|
|
"strings"
|
|
"testing"
|
|
)
|
|
|
|
func TestParseSelectorSingleID(t *testing.T) {
|
|
selector, err := ParseSelector("1")
|
|
if err != nil {
|
|
t.Fatalf("parse failed: %v", err)
|
|
}
|
|
assertIDs(t, selector, []int{1})
|
|
assertContains(t, selector, map[int]bool{1: true, 2: false, 0: false, -1: false})
|
|
}
|
|
|
|
func TestParseSelectorInclusiveRange(t *testing.T) {
|
|
selector, err := ParseSelector("1-3")
|
|
if err != nil {
|
|
t.Fatalf("parse failed: %v", err)
|
|
}
|
|
assertIDs(t, selector, []int{1, 2, 3})
|
|
}
|
|
|
|
func TestParseSelectorCommaSeparatedCombination(t *testing.T) {
|
|
selector, err := ParseSelector("1-3,8,10-12")
|
|
if err != nil {
|
|
t.Fatalf("parse failed: %v", err)
|
|
}
|
|
assertIDs(t, selector, []int{1, 2, 3, 8, 10, 11, 12})
|
|
}
|
|
|
|
func TestParseSelectorWhitespaceTolerance(t *testing.T) {
|
|
selector, err := ParseSelector(" 1 - 3 , 8 , 10 - 12 ")
|
|
if err != nil {
|
|
t.Fatalf("parse failed: %v", err)
|
|
}
|
|
assertIDs(t, selector, []int{1, 2, 3, 8, 10, 11, 12})
|
|
}
|
|
|
|
func TestParseSelectorDuplicatesAndOverlapsNormalizeUnion(t *testing.T) {
|
|
selector, err := ParseSelector("1-4,2,4,3-6,6")
|
|
if err != nil {
|
|
t.Fatalf("parse failed: %v", err)
|
|
}
|
|
assertIDs(t, selector, []int{1, 2, 3, 4, 5, 6})
|
|
assertContains(t, selector, map[int]bool{1: true, 5: true, 6: true, 7: false})
|
|
}
|
|
|
|
func TestParseSelectorDeterministicNormalizedOutput(t *testing.T) {
|
|
left, err := ParseSelector("8,1-3,2,10-12")
|
|
if err != nil {
|
|
t.Fatalf("parse left failed: %v", err)
|
|
}
|
|
right, err := ParseSelector("10-12,3,2,1,8")
|
|
if err != nil {
|
|
t.Fatalf("parse right failed: %v", err)
|
|
}
|
|
|
|
leftIDs := left.IDs()
|
|
rightIDs := right.IDs()
|
|
if !equalInts(leftIDs, rightIDs) {
|
|
t.Fatalf("normalized IDs mismatch: %v vs %v", leftIDs, rightIDs)
|
|
}
|
|
}
|
|
|
|
func TestParseSelectorFailures(t *testing.T) {
|
|
tests := []struct {
|
|
name string
|
|
selector string
|
|
wantError string
|
|
}{
|
|
{name: "empty", selector: "", wantError: "cannot be empty"},
|
|
{name: "whitespace only", selector: " ", wantError: "cannot be empty"},
|
|
{name: "zero", selector: "0", wantError: "must be positive"},
|
|
{name: "negative", selector: "-1", wantError: "must be positive"},
|
|
{name: "range includes zero", selector: "0-2", wantError: "must be positive"},
|
|
{name: "descending range", selector: "10-1", wantError: "descending range"},
|
|
{name: "empty element", selector: "1,,2", wantError: "cannot be empty"},
|
|
{name: "trailing comma", selector: "1,", wantError: "cannot be empty"},
|
|
{name: "malformed alpha", selector: "abc", wantError: "malformed element"},
|
|
{name: "malformed range", selector: "1-2-3", wantError: "malformed element"},
|
|
{name: "missing end", selector: "1-", wantError: "malformed element"},
|
|
{name: "missing start", selector: "-2", wantError: "must be positive"},
|
|
}
|
|
|
|
for _, test := range tests {
|
|
t.Run(test.name, func(t *testing.T) {
|
|
_, err := ParseSelector(test.selector)
|
|
if err == nil {
|
|
t.Fatalf("expected error for %q", test.selector)
|
|
}
|
|
if !strings.Contains(err.Error(), test.wantError) {
|
|
t.Fatalf("error = %q, want substring %q", err.Error(), test.wantError)
|
|
}
|
|
})
|
|
}
|
|
}
|
|
|
|
func assertIDs(t *testing.T, selector Selector, want []int) {
|
|
t.Helper()
|
|
got := selector.IDs()
|
|
if !equalInts(got, want) {
|
|
t.Fatalf("IDs = %v, want %v", got, want)
|
|
}
|
|
}
|
|
|
|
func assertContains(t *testing.T, selector Selector, checks map[int]bool) {
|
|
t.Helper()
|
|
for id, want := range checks {
|
|
if got := selector.Contains(id); got != want {
|
|
t.Fatalf("Contains(%d) = %t, want %t", id, got, want)
|
|
}
|
|
}
|
|
}
|
|
|
|
func equalInts(left []int, right []int) bool {
|
|
if len(left) != len(right) {
|
|
return false
|
|
}
|
|
for index := range left {
|
|
if left[index] != right[index] {
|
|
return false
|
|
}
|
|
}
|
|
return true
|
|
}
|