package common import ( "fmt" "testing" ) // TestItem implements Identifiable for testing type TestItem struct { ID int32 `json:"id"` Name string `json:"name"` Category string `json:"category"` } func (t *TestItem) GetID() int32 { return t.ID } // TestMasterList tests the basic functionality of the generic master list func TestMasterList(t *testing.T) { ml := NewMasterList[int32, *TestItem]() // Test initial state if !ml.IsEmpty() { t.Error("New master list should be empty") } if ml.Size() != 0 { t.Error("New master list should have size 0") } // Test adding items item1 := &TestItem{ID: 1, Name: "Item One", Category: "A"} item2 := &TestItem{ID: 2, Name: "Item Two", Category: "B"} item3 := &TestItem{ID: 3, Name: "Item Three", Category: "A"} if !ml.Add(item1) { t.Error("Should successfully add item1") } if !ml.Add(item2) { t.Error("Should successfully add item2") } if !ml.Add(item3) { t.Error("Should successfully add item3") } // Test duplicate addition if ml.Add(item1) { t.Error("Should not add duplicate item") } // Test size if ml.Size() != 3 { t.Errorf("Expected size 3, got %d", ml.Size()) } if ml.IsEmpty() { t.Error("List should not be empty") } // Test retrieval retrieved := ml.Get(1) if retrieved == nil || retrieved.Name != "Item One" { t.Error("Failed to retrieve item1") } // Test safe retrieval retrievedSafe, exists := ml.GetSafe(1) if !exists || retrievedSafe.Name != "Item One" { t.Error("Failed to safely retrieve item1") } _, exists = ml.GetSafe(999) if exists { t.Error("Should not find non-existent item") } // Test existence if !ml.Exists(1) { t.Error("Item 1 should exist") } if ml.Exists(999) { t.Error("Item 999 should not exist") } // Test update updatedItem := &TestItem{ID: 1, Name: "Updated Item One", Category: "A"} if err := ml.Update(updatedItem); err != nil { t.Errorf("Should successfully update item: %v", err) } retrieved = ml.Get(1) if retrieved.Name != "Updated Item One" { t.Error("Item was not updated correctly") } // Test update non-existent item nonExistent := &TestItem{ID: 999, Name: "Non Existent", Category: "Z"} if err := ml.Update(nonExistent); err == nil { t.Error("Should fail to update non-existent item") } // Test AddOrUpdate newItem := &TestItem{ID: 4, Name: "Item Four", Category: "C"} if !ml.AddOrUpdate(newItem) { t.Error("Should successfully add new item with AddOrUpdate") } updateExisting := &TestItem{ID: 1, Name: "Double Updated Item One", Category: "A"} if !ml.AddOrUpdate(updateExisting) { t.Error("Should successfully update existing item with AddOrUpdate") } retrieved = ml.Get(1) if retrieved.Name != "Double Updated Item One" { t.Error("Item was not updated correctly with AddOrUpdate") } if ml.Size() != 4 { t.Errorf("Expected size 4 after AddOrUpdate, got %d", ml.Size()) } // Test removal if !ml.Remove(2) { t.Error("Should successfully remove item2") } if ml.Remove(2) { t.Error("Should not remove already removed item") } if ml.Size() != 3 { t.Errorf("Expected size 3 after removal, got %d", ml.Size()) } // Test GetAll all := ml.GetAll() if len(all) != 3 { t.Errorf("Expected 3 items in GetAll, got %d", len(all)) } // Verify we can modify the returned map without affecting the original all[999] = &TestItem{ID: 999, Name: "Should not affect original", Category: "Z"} if ml.Exists(999) { t.Error("Modifying returned map should not affect original list") } // Test GetAllSlice slice := ml.GetAllSlice() if len(slice) != 3 { t.Errorf("Expected 3 items in GetAllSlice, got %d", len(slice)) } // Test GetAllIDs ids := ml.GetAllIDs() if len(ids) != 3 { t.Errorf("Expected 3 IDs in GetAllIDs, got %d", len(ids)) } // Test Clear ml.Clear() if !ml.IsEmpty() { t.Error("List should be empty after Clear") } if ml.Size() != 0 { t.Error("List should have size 0 after Clear") } } // TestMasterListSearch tests search functionality func TestMasterListSearch(t *testing.T) { ml := NewMasterList[int32, *TestItem]() // Add test items items := []*TestItem{ {ID: 1, Name: "Alpha", Category: "A"}, {ID: 2, Name: "Beta", Category: "B"}, {ID: 3, Name: "Gamma", Category: "A"}, {ID: 4, Name: "Delta", Category: "C"}, {ID: 5, Name: "Alpha Two", Category: "A"}, } for _, item := range items { ml.Add(item) } // Test Filter categoryA := ml.Filter(func(item *TestItem) bool { return item.Category == "A" }) if len(categoryA) != 3 { t.Errorf("Expected 3 items in category A, got %d", len(categoryA)) } // Test Find found, exists := ml.Find(func(item *TestItem) bool { return item.Name == "Beta" }) if !exists || found.ID != 2 { t.Error("Should find Beta with ID 2") } notFound, exists := ml.Find(func(item *TestItem) bool { return item.Name == "Nonexistent" }) if exists || notFound != nil { t.Error("Should not find nonexistent item") } // Test Count count := ml.Count(func(item *TestItem) bool { return item.Category == "A" }) if count != 3 { t.Errorf("Expected count of 3 for category A, got %d", count) } // Test ForEach var visitedIDs []int32 ml.ForEach(func(id int32, item *TestItem) { visitedIDs = append(visitedIDs, id) }) if len(visitedIDs) != 5 { t.Errorf("Expected to visit 5 items, visited %d", len(visitedIDs)) } } // TestMasterListConcurrency tests thread safety (basic test) func TestMasterListConcurrency(t *testing.T) { ml := NewMasterList[int32, *TestItem]() // Test WithReadLock ml.Add(&TestItem{ID: 1, Name: "Test", Category: "A"}) var foundItem *TestItem ml.WithReadLock(func(items map[int32]*TestItem) { foundItem = items[1] }) if foundItem == nil || foundItem.Name != "Test" { t.Error("WithReadLock should provide access to internal map") } // Test WithWriteLock ml.WithWriteLock(func(items map[int32]*TestItem) { items[2] = &TestItem{ID: 2, Name: "Added via WriteLock", Category: "B"} }) if !ml.Exists(2) { t.Error("Item added via WithWriteLock should exist") } retrieved := ml.Get(2) if retrieved.Name != "Added via WriteLock" { t.Error("Item added via WithWriteLock not found correctly") } } // BenchmarkMasterList tests performance of basic operations func BenchmarkMasterList(b *testing.B) { ml := NewMasterList[int32, *TestItem]() // Pre-populate for benchmarks for i := int32(0); i < 1000; i++ { ml.Add(&TestItem{ ID: i, Name: fmt.Sprintf("Item %d", i), Category: fmt.Sprintf("Category %d", i%10), }) } b.Run("Get", func(b *testing.B) { for i := 0; i < b.N; i++ { ml.Get(int32(i % 1000)) } }) b.Run("Add", func(b *testing.B) { for i := 0; i < b.N; i++ { ml.AddOrUpdate(&TestItem{ ID: int32(1000 + i), Name: fmt.Sprintf("Bench Item %d", i), Category: "Bench", }) } }) b.Run("Filter", func(b *testing.B) { for i := 0; i < b.N; i++ { ml.Filter(func(item *TestItem) bool { return item.Category == "Category 5" }) } }) }