package uid
import (
"strings"
"testing"
)
func TestParseRange(t *testing.T) {
testCases := map[string]struct {
in string
errFn func(error) bool
r Range
total uint32
}{
"identity range": {
in: "1-1/1",
r: Range{
block: Block{1, 1},
size: 1,
},
total: 1,
},
"simple range": {
in: "1-2/1",
r: Range{
block: Block{1, 2},
size: 1,
},
total: 2,
},
"wide range": {
in: "10000-999999/1000",
r: Range{
block: Block{10000, 999999},
size: 1000,
},
total: 990,
},
"overflow uint": {
in: "1000-100000000000000/1",
errFn: func(err error) bool { return strings.Contains(err.Error(), "unsigned integer overflow") },
},
"negative range": {
in: "1000-999/1",
errFn: func(err error) bool { return strings.Contains(err.Error(), "must be less than end 999") },
},
"zero block size": {
in: "1000-1000/0",
errFn: func(err error) bool { return strings.Contains(err.Error(), "block size must be a positive integer") },
},
"large block size": {
in: "1000-1001/3",
errFn: func(err error) bool { return strings.Contains(err.Error(), "must be less than or equal to the range") },
},
}
for s, testCase := range testCases {
r, err := ParseRange(testCase.in)
if testCase.errFn != nil && !testCase.errFn(err) {
t.Errorf("%s: unexpected error: %v", s, err)
continue
}
if err != nil {
continue
}
if r.block.Start != testCase.r.block.Start || r.block.End != testCase.r.block.End || r.size != testCase.r.size {
t.Errorf("%s: unexpected range: %#v", s, r)
}
if r.Size() != testCase.total {
t.Errorf("%s: unexpected total: %d", s, r.Size())
}
}
}
func TestBlock(t *testing.T) {
b := Block{Start: 100, End: 109}
if b.String() != "100/10" {
t.Errorf("unexpected block string: %s", b.String())
}
b, err := ParseBlock("100-109")
if err != nil {
t.Fatal(err)
}
if b.String() != "100/10" {
t.Errorf("unexpected block string: %s", b.String())
}
}
func TestOffset(t *testing.T) {
testCases := map[string]struct {
r Range
block Block
contained bool
offset uint32
}{
"identity range": {
r: Range{
block: Block{1, 1},
size: 1,
},
block: Block{1, 1},
contained: true,
},
"out of identity range": {
r: Range{
block: Block{1, 1},
size: 1,
},
block: Block{2, 2},
},
"out of identity range expanded": {
r: Range{
block: Block{1, 1},
size: 1,
},
block: Block{2, 3},
},
"aligned to offset": {
r: Range{
block: Block{0, 100},
size: 10,
},
block: Block{10, 19},
contained: true,
offset: 1,
},
"not aligned": {
r: Range{
block: Block{0, 100},
size: 10,
},
block: Block{11, 20},
},
}
for s, testCase := range testCases {
contained, offset := testCase.r.Offset(testCase.block)
if contained != testCase.contained {
t.Errorf("%s: unexpected contained: %t", s, contained)
continue
}
if offset != testCase.offset {
t.Errorf("%s: unexpected offset: %d", s, offset)
continue
}
if contained {
block, ok := testCase.r.BlockAt(offset)
if !ok {
t.Errorf("%s: should find block", s)
continue
}
if block != testCase.block {
t.Errorf("%s: blocks are not equivalent: %#v", s, block)
}
}
}
}