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
}