Added example usage code for MultiIndex. Added unit tests for MultiIndex

This commit is contained in:
Mattias Hansson 2025-10-14 20:57:24 +02:00
parent 63e321fd20
commit a962e4acb7
2 changed files with 244 additions and 0 deletions

View file

@ -0,0 +1,202 @@
package utils
import (
"testing"
)
type TestUser struct {
ID string
Name string
Email string
}
func TestMultiIndex_AddAndFind(t *testing.T) {
idx := NewMultiIndex[TestUser](2)
user := TestUser{"1", "John Doe", "john@example.com"}
idx.AddItem(user, [][]string{
{"john@example.com"},
{"john", "doe"},
})
found, ok := idx.FindItem(0, []string{"john@example.com"})
if !ok {
t.Fatal("expected to find user by email")
}
if found.ID != "1" {
t.Errorf("got ID %s, want 1", found.ID)
}
found, ok = idx.FindItem(1, []string{"john", "doe"})
if !ok {
t.Fatal("expected to find user by name")
}
if found.Name != "John Doe" {
t.Errorf("got Name %s, want John Doe", found.Name)
}
}
func TestMultiIndex_NotFound(t *testing.T) {
idx := NewMultiIndex[TestUser](1)
idx.AddItem(TestUser{"1", "John", "john@example.com"}, [][]string{
{"john@example.com"},
})
_, ok := idx.FindItem(0, []string{"jane@example.com"})
if ok {
t.Error("expected not found")
}
}
func TestMultiIndex_WrongCompositeKey(t *testing.T) {
idx := NewMultiIndex[TestUser](1)
idx.AddItem(TestUser{"1", "John Doe", "john@example.com"}, [][]string{
{"john", "doe"},
})
_, ok := idx.FindItem(0, []string{"john", "smith"})
if ok {
t.Error("expected not found with wrong composite key")
}
_, ok = idx.FindItem(0, []string{"john"})
if ok {
t.Error("expected not found with partial key")
}
}
func TestMultiIndex_KeyCollisionHandling(t *testing.T) {
idx := NewMultiIndex[TestUser](1)
idx.AddItem(TestUser{"1", "User1", "user1@example.com"}, [][]string{
{"ab", "cd"},
})
idx.AddItem(TestUser{"2", "User2", "user2@example.com"}, [][]string{
{"abc", "d"},
})
found, ok := idx.FindItem(0, []string{"ab", "cd"})
if !ok || found.ID != "1" {
t.Error("collision: wrong user for ['ab', 'cd']")
}
found, ok = idx.FindItem(0, []string{"abc", "d"})
if !ok || found.ID != "2" {
t.Error("collision: wrong user for ['abc', 'd']")
}
}
func TestMultiIndex_InvalidIndex(t *testing.T) {
idx := NewMultiIndex[TestUser](2)
idx.AddItem(TestUser{"1", "John", "john@example.com"}, [][]string{
{"john@example.com"},
{"john"},
})
_, ok := idx.FindItem(-1, []string{"john@example.com"})
if ok {
t.Error("expected not found for negative index")
}
_, ok = idx.FindItem(5, []string{"john@example.com"})
if ok {
t.Error("expected not found for out of range index")
}
}
func TestMultiIndex_Items(t *testing.T) {
idx := NewMultiIndex[TestUser](1)
users := []TestUser{
{"1", "John", "john@example.com"},
{"2", "Jane", "jane@example.com"},
{"3", "Bob", "bob@example.com"},
}
for _, u := range users {
idx.AddItem(u, [][]string{{u.Email}})
}
items := idx.Items()
if len(items) != 3 {
t.Fatalf("got %d items, want 3", len(items))
}
for i, u := range users {
if items[i].ID != u.ID {
t.Errorf("item %d: got ID %s, want %s", i, items[i].ID, u.ID)
}
}
}
func TestMultiIndex_ItemsIsCopy(t *testing.T) {
idx := NewMultiIndex[TestUser](1)
idx.AddItem(TestUser{"1", "John", "john@example.com"}, [][]string{
{"john@example.com"},
})
items := idx.Items()
items[0].Name = "Modified"
original, _ := idx.FindItem(0, []string{"john@example.com"})
if original.Name != "John" {
t.Error("Items() should return a copy, not affect internal state")
}
}
func TestMultiIndex_PanicOnWrongKeysLength(t *testing.T) {
defer func() {
if r := recover(); r == nil {
t.Error("expected panic on wrong searchKeys length")
}
}()
idx := NewMultiIndex[TestUser](2)
idx.AddItem(TestUser{"1", "John", "john@example.com"}, [][]string{
{"john@example.com"},
// missing second index key
})
}
func TestMultiIndex_MultipleItemsSameIndex(t *testing.T) {
idx := NewMultiIndex[TestUser](2)
idx.AddItem(TestUser{"1", "John Doe", "john@example.com"}, [][]string{
{"john@example.com"},
{"john", "doe"},
})
idx.AddItem(TestUser{"2", "Jane Doe", "jane@example.com"}, [][]string{
{"jane@example.com"},
{"jane", "doe"},
})
john, ok := idx.FindItem(1, []string{"john", "doe"})
if !ok || john.ID != "1" {
t.Error("failed to find John by name")
}
jane, ok := idx.FindItem(1, []string{"jane", "doe"})
if !ok || jane.ID != "2" {
t.Error("failed to find Jane by name")
}
}
func TestMultiIndex_EmptyIndex(t *testing.T) {
idx := NewMultiIndex[TestUser](1)
_, ok := idx.FindItem(0, []string{"anything"})
if ok {
t.Error("expected not found in empty index")
}
items := idx.Items()
if len(items) != 0 {
t.Errorf("expected 0 items, got %d", len(items))
}
}

42
main.go
View file

@ -2,6 +2,7 @@ package main
import ( import (
"c65gm/internal/preproc" "c65gm/internal/preproc"
"c65gm/internal/utils"
"flag" "flag"
"fmt" "fmt"
"os" "os"
@ -35,7 +36,48 @@ const (
ShowLineView ShowLineView
) )
func testMultiIndex() {
type User struct {
ID string
FirstName string
LastName string
Email string
}
// 2 indexes: [0]=email only, [1]=firstname+lastname
idx := utils.NewMultiIndex[User](2)
idx.AddItem(User{"1", "John", "Doe", "john@example.com"}, [][]string{
{"john@example.com"},
{"john", "doe"},
})
idx.AddItem(User{"2", "Jane", "Smith", "jane@example.com"}, [][]string{
{"jane@example.com"},
{"jane", "smith"},
})
// Search by email (index 0, single string)
user, found := idx.FindItem(0, []string{"john@example.com"})
fmt.Println(user, found) // {1 John Doe john@example.com} true
// Search by name (index 1, two strings)
user, found = idx.FindItem(1, []string{"jane", "smith"})
fmt.Println(user, found) // {2 Jane Smith jane@example.com} true
// Wrong composite key fails
user, found = idx.FindItem(1, []string{"jane", "doe"})
fmt.Println(found) // false
// All items
fmt.Println(idx.Items()) // [{1 John Doe john@example.com} {2 Jane Smith jane@example.com}]
}
func main() { func main() {
testMultiIndex()
os.Exit(1)
fmt.Println("c65cm - A 6502 Cross-Compiler for the ACME Cross-Assembler.") fmt.Println("c65cm - A 6502 Cross-Compiler for the ACME Cross-Assembler.")
fmt.Println("Copyright (C) 1999, 2025 Mattias Hansson. v0.7") fmt.Println("Copyright (C) 1999, 2025 Mattias Hansson. v0.7")
fmt.Println("Distributed under GPL. External library github.com/armon/go-radix under MIT.") fmt.Println("Distributed under GPL. External library github.com/armon/go-radix under MIT.")