From 839457702f48dbe21b54e1912afc3a52242ce08e Mon Sep 17 00:00:00 2001 From: Acid Date: Wed, 22 Apr 2026 02:49:21 -0400 Subject: [PATCH] added some tests --- linear/stack.go | 29 +++-- linear/stack_test.go | 16 --- tests/queue_test.go | 242 +++++++++++++++++++++++++++++++++++++ tests/stack_test.go | 278 +++++++++++++++++++++++++++++++++++++++++++ 4 files changed, 537 insertions(+), 28 deletions(-) delete mode 100644 linear/stack_test.go create mode 100644 tests/queue_test.go create mode 100644 tests/stack_test.go diff --git a/linear/stack.go b/linear/stack.go index e421239..582b404 100644 --- a/linear/stack.go +++ b/linear/stack.go @@ -6,26 +6,26 @@ import ( // Stack -> creates a Stack with no size type Stack[T any] struct { - Capacity int - Container []T + capacity int + container []T } // StackFixed -> creates Stack with a fixed size func StackFixed[T any](value int) *Stack[T] { return &Stack[T]{ - Capacity: value, - Container: make([]T, 0, value), + capacity: value, + container: make([]T, 0, value), } } // Push -> Appends value to stack returns error // If using StackFixed errors when over capacity func (s *Stack[T]) Push(value T) error { - if s.Capacity > 0 && (len(s.Container) >= s.Capacity) { + if s.capacity > 0 && (len(s.container) >= s.capacity) { return errors.New("Error max capasity exeded") } - s.Container = append(s.Container, value) + s.container = append(s.container, value) return nil } @@ -33,27 +33,32 @@ func (s *Stack[T]) Push(value T) error { func (s *Stack[T]) Pop() (T, error) { var zero T - if len(s.Container) <= 0 { + if len(s.container) <= 0 { return zero, errors.New("Error Empty Stack") } - last := s.Container[len(s.Container)-1] - s.Container = s.Container[:len(s.Container)-1] + last := s.container[len(s.container)-1] + s.container = s.container[:len(s.container)-1] return last, nil } // Clear -> clears the stack func (s *Stack[T]) Clear() { - s.Container = []T{} + s.container = []T{} } // Peek -> returns top item func (s *Stack[T]) Peek() T { - return s.Container[len(s.Container)-1] + return s.container[len(s.container)-1] } // First -> returns bottom item func (s *Stack[T]) First() T { - return s.Container[0] + return s.container[0] +} + +// Size -> returns number of items in stack +func (s *Stack[T]) Size() int { + return len(s.container) } diff --git a/linear/stack_test.go b/linear/stack_test.go deleted file mode 100644 index b041abd..0000000 --- a/linear/stack_test.go +++ /dev/null @@ -1,16 +0,0 @@ -package linear - -import ( - "testing" -) - -func TestPush(t *testing.T) { - s := Stack[int]{} - s.Push(1) - s.Push(2) - s.Push(3) - - if len(s.Container) != 3 { - t.Errorf("expected 2 items, got %d", len(s.Container)) - } -} diff --git a/tests/queue_test.go b/tests/queue_test.go new file mode 100644 index 0000000..8745c0b --- /dev/null +++ b/tests/queue_test.go @@ -0,0 +1,242 @@ +package tests + +import ( + "testing" + + "datastructures/linear" +) + +// --- map type --- + +func TestQueueWithMaps(t *testing.T) { + q := linear.QueueFixed[map[string]int](3) + + m1 := map[string]int{"a": 1} + m2 := map[string]int{"b": 2, "c": 3} + var nilMap map[string]int + + q.Add(m1) + q.Add(m2) + q.Add(nilMap) + + if q.Size() != 3 { + t.Fatalf("expected size 3, got %d", q.Size()) + } + + got, ok := q.Peek() + if !ok || got["a"] != 1 { + t.Errorf("Peek returned wrong map: %v", got) + } + + pulled, err := q.Pull() + if err != nil || pulled["a"] != 1 { + t.Errorf("Pull returned wrong map: %v err: %v", pulled, err) + } + + if q.Size() != 2 { + t.Errorf("expected size 2 after Pull, got %d", q.Size()) + } +} + +func TestQueueMapMutationAfterEnqueue(t *testing.T) { + q := linear.QueueFixed[map[string]int](2) + + m := map[string]int{"x": 10} + q.Add(m) + + // mutate original map after enqueue — queue holds a reference + m["x"] = 999 + + peeked, _ := q.Peek() + if peeked["x"] != 999 { + t.Logf("map mutation not reflected (value copied): got %d", peeked["x"]) + } else { + t.Logf("map mutation reflected (reference held): got %d", peeked["x"]) + } +} + +func TestQueueMapOverCapacity(t *testing.T) { + q := linear.QueueFixed[map[string]int](1) + q.Add(map[string]int{"a": 1}) + + err := q.Add(map[string]int{"b": 2}) + if err == nil { + t.Error("expected error when adding to full map queue, got nil") + } +} + +// --- struct (object) type --- + +type Person struct { + Name string + Age int +} + +func TestQueueWithStructs(t *testing.T) { + q := linear.QueueFixed[Person](3) + + q.Add(Person{"Alice", 30}) + q.Add(Person{"Bob", 25}) + q.Add(Person{}) // zero value struct + + if q.Size() != 3 { + t.Fatalf("expected size 3, got %d", q.Size()) + } + + first, err := q.Pull() + if err != nil || first.Name != "Alice" { + t.Errorf("expected Alice, got %v", first) + } + + last, err := q.Cull() + if err != nil || last.Name != "" { + t.Errorf("expected zero-value struct at tail, got %v", last) + } +} + +func TestQueueStructOverCapacity(t *testing.T) { + q := linear.QueueFixed[Person](2) + q.Add(Person{"A", 1}) + q.Add(Person{"B", 2}) + + err := q.Add(Person{"C", 3}) + if err == nil { + t.Error("expected error adding struct beyond capacity, got nil") + } +} + +// --- pointer type --- + +func TestQueueWithPointers(t *testing.T) { + q := linear.QueueFixed[*Person](3) + + p1 := &Person{"Alice", 30} + p2 := &Person{"Bob", 25} + + q.Add(p1) + q.Add(p2) + q.Add(nil) // nil pointer + + if q.Size() != 3 { + t.Fatalf("expected size 3, got %d", q.Size()) + } + + got, ok := q.Peek() + if !ok || got != p1 { + t.Errorf("Peek: expected p1 pointer, got %v", got) + } +} + +func TestQueueNilPointerPull(t *testing.T) { + q := linear.QueueFixed[*Person](2) + q.Add(nil) + + got, err := q.Pull() + if err != nil { + t.Fatalf("unexpected error pulling nil pointer: %v", err) + } + if got != nil { + t.Errorf("expected nil pointer back, got %v", got) + } +} + +func TestQueuePointerMutationAfterEnqueue(t *testing.T) { + q := linear.QueueFixed[*Person](1) + + p := &Person{"Alice", 30} + q.Add(p) + + p.Name = "Mutated" + + peeked, _ := q.Peek() + if peeked.Name != "Mutated" { + t.Errorf("expected mutation to be reflected via pointer, got %s", peeked.Name) + } +} + +// --- slice type --- + +func TestQueueWithSlices(t *testing.T) { + q := linear.QueueFixed[[]int](3) + + q.Add([]int{1, 2, 3}) + q.Add([]int{}) // empty slice + q.Add(nil) // nil slice + + if q.Size() != 3 { + t.Fatalf("expected size 3, got %d", q.Size()) + } + + first, err := q.Pull() + if err != nil || len(first) != 3 || first[0] != 1 { + t.Errorf("unexpected first slice: %v", first) + } +} + +func TestQueueSliceMutationAfterEnqueue(t *testing.T) { + q := linear.QueueFixed[[]int](1) + + s := []int{1, 2, 3} + q.Add(s) + + s[0] = 999 + + peeked, _ := q.Peek() + if peeked[0] != 999 { + t.Logf("slice mutation not reflected (copied): got %d", peeked[0]) + } else { + t.Logf("slice mutation reflected (shared backing array): got %d", peeked[0]) + } +} + +func TestQueueSliceOverCapacity(t *testing.T) { + q := linear.QueueFixed[[]int](1) + q.Add([]int{1}) + + err := q.Add([]int{2}) + if err == nil { + t.Error("expected error adding slice beyond capacity, got nil") + } +} + +// --- empty queue edge cases across all types --- + +func TestQueuePullEmptyMap(t *testing.T) { + q := linear.QueueFixed[map[string]int](2) + _, err := q.Pull() + if err == nil { + t.Error("expected error pulling from empty map queue") + } +} + +func TestQueuePullEmptyPointer(t *testing.T) { + q := linear.QueueFixed[*Person](2) + _, err := q.Pull() + if err == nil { + t.Error("expected error pulling from empty pointer queue") + } +} + +func TestQueuePullEmptySlice(t *testing.T) { + q := linear.QueueFixed[[]int](2) + _, err := q.Pull() + if err == nil { + t.Error("expected error pulling from empty slice queue") + } +} + +func TestQueueCullEmptyStruct(t *testing.T) { + q := linear.QueueFixed[Person](2) + _, err := q.Cull() + if err == nil { + t.Error("expected error culling from empty struct queue") + } +} + +func TestQueuePeekEmptyPointer(t *testing.T) { + q := linear.QueueFixed[*Person](2) + val, ok := q.Peek() + if ok || val != nil { + t.Errorf("expected (nil, false) from empty pointer queue Peek, got (%v, %v)", val, ok) + } +} diff --git a/tests/stack_test.go b/tests/stack_test.go new file mode 100644 index 0000000..f95babb --- /dev/null +++ b/tests/stack_test.go @@ -0,0 +1,278 @@ +package tests + +import ( + "testing" + + "datastructures/linear" +) + +// --- map type --- + +func TestStackWithMaps(t *testing.T) { + s := linear.StackFixed[map[string]int](3) + + m1 := map[string]int{"a": 1} + m2 := map[string]int{"b": 2, "c": 3} + var nilMap map[string]int + + s.Push(m1) + s.Push(m2) + s.Push(nilMap) + + if s.Size() != 3 { + t.Fatalf("expected 3 items, got %d", s.Size()) + } + + top := s.Peek() + if top != nil { + t.Errorf("expected nil map on top, got %v", top) + } + + popped, err := s.Pop() + if err != nil || popped != nil { + t.Errorf("expected nil map from Pop, got %v err: %v", popped, err) + } + + if s.Size() != 2 { + t.Errorf("expected 2 items after Pop, got %d", s.Size()) + } +} + +func TestStackMapMutationAfterPush(t *testing.T) { + s := linear.StackFixed[map[string]int](2) + + m := map[string]int{"x": 10} + s.Push(m) + + m["x"] = 999 + + top := s.Peek() + if top["x"] != 999 { + t.Logf("map mutation not reflected (value copied): got %d", top["x"]) + } else { + t.Logf("map mutation reflected (reference held): got %d", top["x"]) + } +} + +func TestStackMapOverCapacity(t *testing.T) { + s := linear.StackFixed[map[string]int](1) + s.Push(map[string]int{"a": 1}) + + err := s.Push(map[string]int{"b": 2}) + if err == nil { + t.Error("expected error pushing map beyond capacity, got nil") + } +} + +// --- struct (object) type --- + +func TestStackWithStructs(t *testing.T) { + s := linear.StackFixed[Person](3) + + s.Push(Person{"Alice", 30}) + s.Push(Person{"Bob", 25}) + s.Push(Person{}) // zero value + + if s.Size() != 3 { + t.Fatalf("expected 3 items, got %d", s.Size()) + } + + top := s.Peek() + if top.Name != "" { + t.Errorf("expected zero-value struct on top, got %v", top) + } + + bottom := s.First() + if bottom.Name != "Alice" { + t.Errorf("expected Alice at bottom, got %v", bottom) + } + + popped, err := s.Pop() + if err != nil || popped.Name != "" { + t.Errorf("expected zero-value struct from Pop, got %v", popped) + } +} + +func TestStackStructOverCapacity(t *testing.T) { + s := linear.StackFixed[Person](2) + s.Push(Person{"A", 1}) + s.Push(Person{"B", 2}) + + err := s.Push(Person{"C", 3}) + if err == nil { + t.Error("expected error pushing struct beyond capacity, got nil") + } +} + +func TestStackClearStructs(t *testing.T) { + s := linear.StackFixed[Person](3) + s.Push(Person{"Alice", 30}) + s.Push(Person{"Bob", 25}) + + s.Clear() + + if s.Size() != 0 { + t.Errorf("expected empty stack after Clear, got %d items", s.Size()) + } +} + +// --- pointer type --- + +func TestStackWithPointers(t *testing.T) { + s := linear.StackFixed[*Person](3) + + p1 := &Person{"Alice", 30} + p2 := &Person{"Bob", 25} + + s.Push(p1) + s.Push(p2) + s.Push(nil) + + if s.Size() != 3 { + t.Fatalf("expected 3 items, got %d", s.Size()) + } + + top := s.Peek() + if top != nil { + t.Errorf("expected nil pointer on top, got %v", top) + } + + bottom := s.First() + if bottom != p1 { + t.Errorf("expected p1 at bottom, got %v", bottom) + } +} + +func TestStackNilPointerPop(t *testing.T) { + s := linear.StackFixed[*Person](2) + s.Push(nil) + + got, err := s.Pop() + if err != nil { + t.Fatalf("unexpected error popping nil pointer: %v", err) + } + if got != nil { + t.Errorf("expected nil pointer back, got %v", got) + } +} + +func TestStackPointerMutationAfterPush(t *testing.T) { + s := linear.StackFixed[*Person](1) + + p := &Person{"Alice", 30} + s.Push(p) + + p.Name = "Mutated" + + top := s.Peek() + if top.Name != "Mutated" { + t.Errorf("expected mutation reflected via pointer, got %s", top.Name) + } +} + +// --- slice type --- + +func TestStackWithSlices(t *testing.T) { + s := linear.StackFixed[[]int](3) + + s.Push([]int{1, 2, 3}) + s.Push([]int{}) + s.Push(nil) + + if s.Size() != 3 { + t.Fatalf("expected 3 items, got %d", s.Size()) + } + + top := s.Peek() + if top != nil { + t.Errorf("expected nil slice on top, got %v", top) + } + + bottom := s.First() + if len(bottom) != 3 || bottom[0] != 1 { + t.Errorf("expected [1 2 3] at bottom, got %v", bottom) + } +} + +func TestStackSliceMutationAfterPush(t *testing.T) { + s := linear.StackFixed[[]int](1) + + sl := []int{1, 2, 3} + s.Push(sl) + + sl[0] = 999 + + top := s.Peek() + if top[0] != 999 { + t.Logf("slice mutation not reflected (copied): got %d", top[0]) + } else { + t.Logf("slice mutation reflected (shared backing array): got %d", top[0]) + } +} + +func TestStackSliceOverCapacity(t *testing.T) { + s := linear.StackFixed[[]int](1) + s.Push([]int{1}) + + err := s.Push([]int{2}) + if err == nil { + t.Error("expected error pushing slice beyond capacity, got nil") + } +} + +// --- empty stack edge cases --- + +func TestStackPopEmpty(t *testing.T) { + s := linear.StackFixed[map[string]int](2) + _, err := s.Pop() + if err == nil { + t.Error("expected error popping from empty map stack") + } +} + +func TestStackPopEmptyPointer(t *testing.T) { + s := linear.StackFixed[*Person](2) + _, err := s.Pop() + if err == nil { + t.Error("expected error popping from empty pointer stack") + } +} + +func TestStackPopEmptySlice(t *testing.T) { + s := linear.StackFixed[[]int](2) + _, err := s.Pop() + if err == nil { + t.Error("expected error popping from empty slice stack") + } +} + +func TestStackPopEmptyStruct(t *testing.T) { + s := linear.StackFixed[Person](2) + _, err := s.Pop() + if err == nil { + t.Error("expected error popping from empty struct stack") + } +} + +// Peek and First have no bounds check — they panic on empty stacks. +// These tests document that behavior. + +func TestStackPeekEmptyPanics(t *testing.T) { + defer func() { + if r := recover(); r == nil { + t.Error("expected panic from Peek on empty stack, got none") + } + }() + s := linear.StackFixed[*Person](2) + s.Peek() +} + +func TestStackFirstEmptyPanics(t *testing.T) { + defer func() { + if r := recover(); r == nil { + t.Error("expected panic from First on empty stack, got none") + } + }() + s := linear.StackFixed[*Person](2) + s.First() +}