added some tests

This commit is contained in:
Acid
2026-04-22 02:49:21 -04:00
parent 4eb50dd335
commit 839457702f
4 changed files with 537 additions and 28 deletions
+278
View File
@@ -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()
}