package parser import ( "eq2emu/internal/common" "testing" ) func TestBasicParsing(t *testing.T) { pml := ` ` packets, err := Parse(pml) if err != nil { t.Fatalf("Parse failed: %v", err) } packet := packets["Test"] if packet == nil { t.Fatal("Test packet not found") } // Check fields if len(packet.Fields) != 3 { t.Errorf("Expected 3 fields, got %d", len(packet.Fields)) } if packet.Fields["player_id"].Type != common.TypeInt32 { t.Error("player_id should be TypeInt32") } if packet.Fields["player_name"].Type != common.TypeString16 { t.Error("player_name should be TypeString16") } if packet.Fields["skin_color"].Type != common.TypeColor { t.Error("skin_color should be TypeColor") } // Check order order := packet.Orders[1] expected := []string{"player_id", "player_name", "skin_color"} if !equalSlices(order, expected) { t.Errorf("Expected order %v, got %v", expected, order) } } func TestMultipleVersions(t *testing.T) { pml := ` ` packets, err := Parse(pml) if err != nil { t.Fatalf("Parse failed: %v", err) } packet := packets["MultiVersion"] if packet == nil { t.Fatal("MultiVersion packet not found") } // Check both versions exist if len(packet.Orders) != 2 { t.Errorf("Expected 2 versions, got %d", len(packet.Orders)) } v1Order := packet.Orders[1] v562Order := packet.Orders[562] if len(v1Order) != 2 { t.Errorf("Version 1 should have 2 fields, got %d", len(v1Order)) } if len(v562Order) != 3 { t.Errorf("Version 562 should have 3 fields, got %d", len(v562Order)) } } func TestArrayParsing(t *testing.T) { pml := ` ` packets, err := Parse(pml) if err != nil { t.Fatalf("Parse failed: %v", err) } packet := packets["ArrayTest"] itemsField := packet.Fields["items"] if itemsField.Type != common.TypeArray { t.Error("items should be TypeArray") } if itemsField.Condition != "var:item_count" { t.Errorf("Expected condition 'var:item_count', got '%s'", itemsField.Condition) } if itemsField.SubDef == nil { t.Fatal("SubDef should not be nil") } // Check substruct fields if len(itemsField.SubDef.Fields) != 2 { t.Errorf("Expected 2 substruct fields, got %d", len(itemsField.SubDef.Fields)) } if itemsField.SubDef.Fields["item_id"].Type != common.TypeInt32 { t.Error("item_id should be TypeInt32") } } func TestConditionalParsing(t *testing.T) { pml := ` ` packets, err := Parse(pml) if err != nil { t.Fatalf("Parse failed: %v", err) } packet := packets["ConditionalTest"] if packet.Fields["guild_name"].Condition != "flag:has_guild" { t.Errorf("guild_name condition wrong: %s", packet.Fields["guild_name"].Condition) } if packet.Fields["enhancement"].Condition != "item_type!=0" { t.Errorf("enhancement condition wrong: %s", packet.Fields["enhancement"].Condition) } if packet.Fields["aura"].Condition != "special_flags&0x01" { t.Errorf("aura condition wrong: %s", packet.Fields["aura"].Condition) } } func TestCommaFieldNames(t *testing.T) { pml := ` ` packets, err := Parse(pml) if err != nil { t.Fatalf("Parse failed: %v", err) } packet := packets["CommaTest"] expectedFields := []string{"player_id", "account_id", "pos_x", "pos_y", "pos_z"} if len(packet.Fields) != len(expectedFields) { t.Errorf("Expected %d fields, got %d", len(expectedFields), len(packet.Fields)) } for _, field := range expectedFields { if _, exists := packet.Fields[field]; !exists { t.Errorf("Field %s not found", field) } } } func TestSubstructReference(t *testing.T) { pml := ` ` parser := NewParser(pml) packets, err := parser.Parse() if err != nil { t.Fatalf("Parse failed: %v", err) } packet := packets["SubstructTest"] itemsField := packet.Fields["items"] if itemsField.SubDef == nil { t.Fatal("SubDef should not be nil for referenced substruct") } if len(itemsField.SubDef.Fields) != 2 { t.Errorf("Expected 2 substruct fields, got %d", len(itemsField.SubDef.Fields)) } } func TestFieldAttributes(t *testing.T) { pml := ` ` packets, err := Parse(pml) if err != nil { t.Fatalf("Parse failed: %v", err) } packet := packets["AttributeTest"] if packet.Fields["data_array"].Length != 10 { t.Errorf("Expected size 10, got %d", packet.Fields["data_array"].Length) } if packet.Fields["optional_text"].Condition != "var:has_text" { t.Errorf("Expected condition 'var:has_text', got '%s'", packet.Fields["optional_text"].Condition) } } func TestComments(t *testing.T) { pml := ` ` packets, err := Parse(pml) if err != nil { t.Fatalf("Parse failed: %v", err) } packet := packets["CommentTest"] if len(packet.Fields) != 2 { t.Errorf("Comments should not affect parsing, expected 2 fields, got %d", len(packet.Fields)) } } func TestErrorHandling(t *testing.T) { testCases := []struct { name string pml string }{ {"Unclosed tag", ""}, {"Invalid XML", ""}, {"Missing quotes", ""}, } for _, tc := range testCases { t.Run(tc.name, func(t *testing.T) { _, err := Parse(tc.pml) if err == nil { t.Error("Expected error but got none") } }) } } func BenchmarkSimplePacket(b *testing.B) { pml := ` ` b.ResetTimer() for i := 0; i < b.N; i++ { _, err := Parse(pml) if err != nil { b.Fatal(err) } } } func BenchmarkComplexPacket(b *testing.B) { pml := ` ` b.ResetTimer() for i := 0; i < b.N; i++ { _, err := Parse(pml) if err != nil { b.Fatal(err) } } } func BenchmarkLargePacket(b *testing.B) { // Generate a large packet definition pmlBuilder := `` for i := 0; i < 100; i++ { pmlBuilder += `` } pmlBuilder += `` b.ResetTimer() for i := 0; i < b.N; i++ { _, err := Parse(pmlBuilder) if err != nil { b.Fatal(err) } } } func BenchmarkWithSubstructs(b *testing.B) { pml := ` ` b.ResetTimer() for i := 0; i < b.N; i++ { parser := NewParser(pml) _, err := parser.Parse() if err != nil { b.Fatal(err) } } } // Helper function to compare slices func equalSlices(a, b []string) bool { if len(a) != len(b) { return false } for i, v := range a { if v != b[i] { return false } } return true }