Skip to content

Commit 3437db5

Browse files
authored
fix: validate capacity in NewCircular and NewPriority (#53)
* test: add failing tests for invalid capacity values NewCircular with capacity 0 does not panic on construction but later panics on first Offer with a cryptic index error. NewCircular with -1 panics inside make. NewPriority with WithCapacity(-1) panics in a slice expression. All three should fail fast with a clear message at construction. Refs #42 * fix: panic with a clear message on invalid capacity NewCircular accepted capacity <= 0 either silently (0) or via a cryptic make/index panic (-1). NewPriority accepted negative capacity via WithCapacity, then panicked inside a slice expression. Validate capacity right after options resolution and panic with a clear message, matching the existing nil-lessFunc check in NewPriority. Fixes #42
1 parent 398ff53 commit 3437db5

4 files changed

Lines changed: 62 additions & 0 deletions

File tree

circular.go

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -44,6 +44,10 @@ func NewCircular[T comparable](
4444
o.apply(&options)
4545
}
4646

47+
if *options.capacity <= 0 {
48+
panic("capacity must be positive")
49+
}
50+
4751
elems := make([]T, *options.capacity)
4852

4953
copy(elems, givenElems)

circular_test.go

Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,41 @@ func TestCircular(t *testing.T) {
2424
t.Run("Reset", testCircularReset)
2525
t.Run("Iterator", testCircularIterator)
2626
t.Run("MarshalJSON", testCircularMarshalJSON)
27+
t.Run("NonPositiveCapacity", testCircularNonPositiveCapacity)
28+
}
29+
30+
func testCircularNonPositiveCapacity(t *testing.T) {
31+
t.Parallel()
32+
33+
cases := []struct {
34+
name string
35+
capacity int
36+
}{
37+
{name: "Zero", capacity: 0},
38+
{name: "Negative", capacity: -1},
39+
}
40+
41+
for _, tc := range cases {
42+
tc := tc
43+
44+
t.Run(tc.name, func(t *testing.T) {
45+
t.Parallel()
46+
47+
defer func() {
48+
p := recover()
49+
if p == nil {
50+
t.Fatalf("expected panic for capacity %d", tc.capacity)
51+
}
52+
53+
msg, ok := p.(string)
54+
if !ok || msg != "capacity must be positive" {
55+
t.Fatalf("expected panic 'capacity must be positive', got %v", p)
56+
}
57+
}()
58+
59+
_ = queue.NewCircular[int](nil, tc.capacity)
60+
})
61+
}
2762
}
2863

2964
func testCircularCapacityOptionOverwrites(t *testing.T) {

priority.go

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -98,6 +98,10 @@ func NewPriority[T comparable](
9898
o.apply(&options)
9999
}
100100

101+
if options.capacity != nil && *options.capacity < 0 {
102+
panic("negative capacity")
103+
}
104+
101105
heapElems := make([]T, len(elems))
102106

103107
copy(heapElems, elems)

priority_test.go

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,25 @@ func TestPriority(t *testing.T) {
2929
t.Run("Peek", testPriorityPeek)
3030
t.Run("Reset", testPriorityReset)
3131
t.Run("MarshalJSON", testPriorityMarshalJSON)
32+
t.Run("NegativeCapacity", testPriorityNegativeCapacity)
33+
}
34+
35+
func testPriorityNegativeCapacity(t *testing.T) {
36+
t.Parallel()
37+
38+
defer func() {
39+
p := recover()
40+
if p == nil {
41+
t.Fatal("expected panic for negative capacity")
42+
}
43+
44+
msg, ok := p.(string)
45+
if !ok || msg != "negative capacity" {
46+
t.Fatalf("expected panic 'negative capacity', got %v", p)
47+
}
48+
}()
49+
50+
_ = queue.NewPriority([]int{1, 2}, lessInt, queue.WithCapacity(-1))
3251
}
3352

3453
func testPriorityNilLessFunc(t *testing.T) {

0 commit comments

Comments
 (0)