mirror of
https://github.com/Mezeporta/Erupe.git
synced 2026-03-23 08:03:51 +01:00
- Add network/packetid_test.go with tests for PacketID type, constants, String() method, ranges, uniqueness, and sequential verification - Add network/mhfpacket/msg_sys_core_test.go with round-trip tests for MsgSysAck (including large payloads), MsgSysNop, and MsgSysEnd - Expand common/stringstack/stringstack_test.go with Lock/Unlock tests achieving 100% coverage
456 lines
8.5 KiB
Go
456 lines
8.5 KiB
Go
package stringstack
|
|
|
|
import (
|
|
"testing"
|
|
)
|
|
|
|
func TestNew(t *testing.T) {
|
|
s := New()
|
|
if s == nil {
|
|
t.Fatal("New() returned nil")
|
|
}
|
|
if len(s.stack) != 0 {
|
|
t.Errorf("New() stack length = %d, want 0", len(s.stack))
|
|
}
|
|
}
|
|
|
|
func TestStringStack_Set(t *testing.T) {
|
|
s := New()
|
|
s.Set("first")
|
|
|
|
if len(s.stack) != 1 {
|
|
t.Errorf("Set() stack length = %d, want 1", len(s.stack))
|
|
}
|
|
if s.stack[0] != "first" {
|
|
t.Errorf("stack[0] = %q, want %q", s.stack[0], "first")
|
|
}
|
|
}
|
|
|
|
func TestStringStack_Set_Replaces(t *testing.T) {
|
|
s := New()
|
|
s.Push("item1")
|
|
s.Push("item2")
|
|
s.Push("item3")
|
|
|
|
// Set should replace the entire stack
|
|
s.Set("new_item")
|
|
|
|
if len(s.stack) != 1 {
|
|
t.Errorf("Set() stack length = %d, want 1", len(s.stack))
|
|
}
|
|
if s.stack[0] != "new_item" {
|
|
t.Errorf("stack[0] = %q, want %q", s.stack[0], "new_item")
|
|
}
|
|
}
|
|
|
|
func TestStringStack_Push(t *testing.T) {
|
|
s := New()
|
|
s.Push("first")
|
|
s.Push("second")
|
|
s.Push("third")
|
|
|
|
if len(s.stack) != 3 {
|
|
t.Errorf("Push() stack length = %d, want 3", len(s.stack))
|
|
}
|
|
if s.stack[0] != "first" {
|
|
t.Errorf("stack[0] = %q, want %q", s.stack[0], "first")
|
|
}
|
|
if s.stack[1] != "second" {
|
|
t.Errorf("stack[1] = %q, want %q", s.stack[1], "second")
|
|
}
|
|
if s.stack[2] != "third" {
|
|
t.Errorf("stack[2] = %q, want %q", s.stack[2], "third")
|
|
}
|
|
}
|
|
|
|
func TestStringStack_Pop(t *testing.T) {
|
|
s := New()
|
|
s.Push("first")
|
|
s.Push("second")
|
|
s.Push("third")
|
|
|
|
// Pop should return LIFO (last in, first out)
|
|
val, err := s.Pop()
|
|
if err != nil {
|
|
t.Errorf("Pop() error = %v, want nil", err)
|
|
}
|
|
if val != "third" {
|
|
t.Errorf("Pop() = %q, want %q", val, "third")
|
|
}
|
|
|
|
val, err = s.Pop()
|
|
if err != nil {
|
|
t.Errorf("Pop() error = %v, want nil", err)
|
|
}
|
|
if val != "second" {
|
|
t.Errorf("Pop() = %q, want %q", val, "second")
|
|
}
|
|
|
|
val, err = s.Pop()
|
|
if err != nil {
|
|
t.Errorf("Pop() error = %v, want nil", err)
|
|
}
|
|
if val != "first" {
|
|
t.Errorf("Pop() = %q, want %q", val, "first")
|
|
}
|
|
|
|
if len(s.stack) != 0 {
|
|
t.Errorf("stack length = %d, want 0 after popping all items", len(s.stack))
|
|
}
|
|
}
|
|
|
|
func TestStringStack_Pop_Empty(t *testing.T) {
|
|
s := New()
|
|
|
|
val, err := s.Pop()
|
|
if err == nil {
|
|
t.Error("Pop() on empty stack should return error")
|
|
}
|
|
if val != "" {
|
|
t.Errorf("Pop() on empty stack returned %q, want empty string", val)
|
|
}
|
|
|
|
expectedError := "no items on stack"
|
|
if err.Error() != expectedError {
|
|
t.Errorf("Pop() error = %q, want %q", err.Error(), expectedError)
|
|
}
|
|
}
|
|
|
|
func TestStringStack_LIFO_Behavior(t *testing.T) {
|
|
s := New()
|
|
items := []string{"A", "B", "C", "D", "E"}
|
|
|
|
for _, item := range items {
|
|
s.Push(item)
|
|
}
|
|
|
|
// Pop should return in reverse order (LIFO)
|
|
for i := len(items) - 1; i >= 0; i-- {
|
|
val, err := s.Pop()
|
|
if err != nil {
|
|
t.Fatalf("Pop() error = %v", err)
|
|
}
|
|
if val != items[i] {
|
|
t.Errorf("Pop() = %q, want %q", val, items[i])
|
|
}
|
|
}
|
|
}
|
|
|
|
func TestStringStack_PushAfterPop(t *testing.T) {
|
|
s := New()
|
|
s.Push("first")
|
|
s.Push("second")
|
|
|
|
val, _ := s.Pop()
|
|
if val != "second" {
|
|
t.Errorf("Pop() = %q, want %q", val, "second")
|
|
}
|
|
|
|
s.Push("third")
|
|
|
|
val, _ = s.Pop()
|
|
if val != "third" {
|
|
t.Errorf("Pop() = %q, want %q", val, "third")
|
|
}
|
|
|
|
val, _ = s.Pop()
|
|
if val != "first" {
|
|
t.Errorf("Pop() = %q, want %q", val, "first")
|
|
}
|
|
}
|
|
|
|
func TestStringStack_EmptyStrings(t *testing.T) {
|
|
s := New()
|
|
s.Push("")
|
|
s.Push("text")
|
|
s.Push("")
|
|
|
|
val, err := s.Pop()
|
|
if err != nil {
|
|
t.Errorf("Pop() error = %v", err)
|
|
}
|
|
if val != "" {
|
|
t.Errorf("Pop() = %q, want empty string", val)
|
|
}
|
|
|
|
val, err = s.Pop()
|
|
if err != nil {
|
|
t.Errorf("Pop() error = %v", err)
|
|
}
|
|
if val != "text" {
|
|
t.Errorf("Pop() = %q, want %q", val, "text")
|
|
}
|
|
|
|
val, err = s.Pop()
|
|
if err != nil {
|
|
t.Errorf("Pop() error = %v", err)
|
|
}
|
|
if val != "" {
|
|
t.Errorf("Pop() = %q, want empty string", val)
|
|
}
|
|
}
|
|
|
|
func TestStringStack_LongStrings(t *testing.T) {
|
|
s := New()
|
|
longString := ""
|
|
for i := 0; i < 1000; i++ {
|
|
longString += "A"
|
|
}
|
|
|
|
s.Push(longString)
|
|
val, err := s.Pop()
|
|
|
|
if err != nil {
|
|
t.Errorf("Pop() error = %v", err)
|
|
}
|
|
if val != longString {
|
|
t.Error("Pop() returned different string than pushed")
|
|
}
|
|
if len(val) != 1000 {
|
|
t.Errorf("Pop() string length = %d, want 1000", len(val))
|
|
}
|
|
}
|
|
|
|
func TestStringStack_ManyItems(t *testing.T) {
|
|
s := New()
|
|
count := 1000
|
|
|
|
// Push many items
|
|
for i := 0; i < count; i++ {
|
|
s.Push("item")
|
|
}
|
|
|
|
if len(s.stack) != count {
|
|
t.Errorf("stack length = %d, want %d", len(s.stack), count)
|
|
}
|
|
|
|
// Pop all items
|
|
for i := 0; i < count; i++ {
|
|
_, err := s.Pop()
|
|
if err != nil {
|
|
t.Errorf("Pop()[%d] error = %v", i, err)
|
|
}
|
|
}
|
|
|
|
// Should be empty now
|
|
if len(s.stack) != 0 {
|
|
t.Errorf("stack length = %d, want 0 after popping all", len(s.stack))
|
|
}
|
|
|
|
// Next pop should error
|
|
_, err := s.Pop()
|
|
if err == nil {
|
|
t.Error("Pop() on empty stack should return error")
|
|
}
|
|
}
|
|
|
|
func TestStringStack_SetAfterOperations(t *testing.T) {
|
|
s := New()
|
|
s.Push("a")
|
|
s.Push("b")
|
|
s.Push("c")
|
|
s.Pop()
|
|
s.Push("d")
|
|
|
|
// Set should clear everything
|
|
s.Set("reset")
|
|
|
|
if len(s.stack) != 1 {
|
|
t.Errorf("stack length = %d, want 1 after Set", len(s.stack))
|
|
}
|
|
|
|
val, err := s.Pop()
|
|
if err != nil {
|
|
t.Errorf("Pop() error = %v", err)
|
|
}
|
|
if val != "reset" {
|
|
t.Errorf("Pop() = %q, want %q", val, "reset")
|
|
}
|
|
}
|
|
|
|
func TestStringStack_SpecialCharacters(t *testing.T) {
|
|
s := New()
|
|
specialStrings := []string{
|
|
"Hello\nWorld",
|
|
"Tab\tSeparated",
|
|
"Quote\"Test",
|
|
"Backslash\\Test",
|
|
"Unicode: テスト",
|
|
"Emoji: 😀",
|
|
"",
|
|
" ",
|
|
" spaces ",
|
|
}
|
|
|
|
for _, str := range specialStrings {
|
|
s.Push(str)
|
|
}
|
|
|
|
// Pop in reverse order
|
|
for i := len(specialStrings) - 1; i >= 0; i-- {
|
|
val, err := s.Pop()
|
|
if err != nil {
|
|
t.Errorf("Pop() error = %v", err)
|
|
}
|
|
if val != specialStrings[i] {
|
|
t.Errorf("Pop() = %q, want %q", val, specialStrings[i])
|
|
}
|
|
}
|
|
}
|
|
|
|
func BenchmarkStringStack_Push(b *testing.B) {
|
|
s := New()
|
|
b.ResetTimer()
|
|
for i := 0; i < b.N; i++ {
|
|
s.Push("test string")
|
|
}
|
|
}
|
|
|
|
func BenchmarkStringStack_Pop(b *testing.B) {
|
|
s := New()
|
|
// Pre-populate
|
|
for i := 0; i < 10000; i++ {
|
|
s.Push("test string")
|
|
}
|
|
|
|
b.ResetTimer()
|
|
for i := 0; i < b.N; i++ {
|
|
if len(s.stack) == 0 {
|
|
// Repopulate
|
|
for j := 0; j < 10000; j++ {
|
|
s.Push("test string")
|
|
}
|
|
}
|
|
_, _ = s.Pop()
|
|
}
|
|
}
|
|
|
|
func BenchmarkStringStack_PushPop(b *testing.B) {
|
|
s := New()
|
|
b.ResetTimer()
|
|
for i := 0; i < b.N; i++ {
|
|
s.Push("test")
|
|
_, _ = s.Pop()
|
|
}
|
|
}
|
|
|
|
func BenchmarkStringStack_Set(b *testing.B) {
|
|
s := New()
|
|
b.ResetTimer()
|
|
for i := 0; i < b.N; i++ {
|
|
s.Set("test string")
|
|
}
|
|
}
|
|
|
|
func TestStringStack_Lock(t *testing.T) {
|
|
s := New()
|
|
|
|
// Initially not locked
|
|
if s.Locked {
|
|
t.Error("New StringStack should not be locked")
|
|
}
|
|
|
|
// Lock it
|
|
s.Lock()
|
|
if !s.Locked {
|
|
t.Error("Lock() should set Locked to true")
|
|
}
|
|
|
|
// Lock again (should be idempotent)
|
|
s.Lock()
|
|
if !s.Locked {
|
|
t.Error("Lock() on already locked stack should remain locked")
|
|
}
|
|
}
|
|
|
|
func TestStringStack_Unlock(t *testing.T) {
|
|
s := New()
|
|
|
|
// Lock then unlock
|
|
s.Lock()
|
|
if !s.Locked {
|
|
t.Error("Lock() should set Locked to true")
|
|
}
|
|
|
|
s.Unlock()
|
|
if s.Locked {
|
|
t.Error("Unlock() should set Locked to false")
|
|
}
|
|
|
|
// Unlock again (should be idempotent)
|
|
s.Unlock()
|
|
if s.Locked {
|
|
t.Error("Unlock() on already unlocked stack should remain unlocked")
|
|
}
|
|
}
|
|
|
|
func TestStringStack_LockUnlockCycle(t *testing.T) {
|
|
s := New()
|
|
|
|
// Multiple lock/unlock cycles
|
|
for i := 0; i < 5; i++ {
|
|
s.Lock()
|
|
if !s.Locked {
|
|
t.Errorf("Cycle %d: Lock() should set Locked to true", i)
|
|
}
|
|
|
|
s.Unlock()
|
|
if s.Locked {
|
|
t.Errorf("Cycle %d: Unlock() should set Locked to false", i)
|
|
}
|
|
}
|
|
}
|
|
|
|
func TestStringStack_LockDoesNotAffectOperations(t *testing.T) {
|
|
s := New()
|
|
s.Push("item1")
|
|
s.Lock()
|
|
|
|
// Lock is just a flag - operations still work
|
|
s.Push("item2")
|
|
if len(s.stack) != 2 {
|
|
t.Error("Push() should work on locked stack")
|
|
}
|
|
|
|
val, err := s.Pop()
|
|
if err != nil {
|
|
t.Errorf("Pop() on locked stack returned error: %v", err)
|
|
}
|
|
if val != "item2" {
|
|
t.Errorf("Pop() = %q, want %q", val, "item2")
|
|
}
|
|
|
|
s.Set("reset")
|
|
if len(s.stack) != 1 || s.stack[0] != "reset" {
|
|
t.Error("Set() should work on locked stack")
|
|
}
|
|
}
|
|
|
|
func TestStringStack_NewUnlocked(t *testing.T) {
|
|
s := New()
|
|
if s.Locked != false {
|
|
t.Error("New() should create an unlocked StringStack")
|
|
}
|
|
}
|
|
|
|
func TestStringStack_UnlockOnUnlocked(t *testing.T) {
|
|
s := New()
|
|
|
|
// Unlock on already unlocked should be safe
|
|
s.Unlock()
|
|
if s.Locked {
|
|
t.Error("Unlock() on unlocked stack should keep it unlocked")
|
|
}
|
|
}
|
|
|
|
func TestStringStack_LockOnLocked(t *testing.T) {
|
|
s := New()
|
|
s.Lock()
|
|
|
|
// Lock on already locked should be safe
|
|
s.Lock()
|
|
if !s.Locked {
|
|
t.Error("Lock() on locked stack should keep it locked")
|
|
}
|
|
}
|