Files
arpack/parser/parser_test.go
T

269 lines
6.9 KiB
Go
Raw Normal View History

2026-03-19 14:52:12 +03:00
package parser
import (
"testing"
)
const sampleSource = `package messages
type Vector3 struct {
X float32 ` + "`" + `pack:"min=-500,max=500,bits=16"` + "`" + `
Y float32 ` + "`" + `pack:"min=-500,max=500,bits=16"` + "`" + `
Z float32 ` + "`" + `pack:"min=-500,max=500,bits=16"` + "`" + `
}
type MoveMessage struct {
Position Vector3
Velocity [3]float32
Waypoints []Vector3
PlayerID uint32
Name string
Active bool
}
type SpawnMessage struct {
ID uint64
Position Vector3
Tags [4]string
Data []uint8
}
`
const enumSource = `package messages
type Opcode uint16
const (
OpcodeUnknown Opcode = iota
OpcodeAuthorize
OpcodeJoinRoom
)
type EnvelopeMessage struct {
Code Opcode
Counter uint8
}
`
func TestParseSource_Primitives(t *testing.T) {
msgs, err := ParseSource(sampleSource)
if err != nil {
t.Fatalf("ParseSource: %v", err)
}
if len(msgs) != 3 {
t.Fatalf("expected 3 messages, got %d", len(msgs))
}
}
func TestParseSource_Vector3(t *testing.T) {
msgs, err := ParseSource(sampleSource)
if err != nil {
t.Fatalf("ParseSource: %v", err)
}
v3 := msgs[0]
if v3.Name != "Vector3" {
t.Fatalf("expected Vector3, got %s", v3.Name)
}
if len(v3.Fields) != 3 {
t.Fatalf("expected 3 fields, got %d", len(v3.Fields))
}
for _, f := range v3.Fields {
if f.Kind != KindPrimitive {
t.Errorf("field %s: expected KindPrimitive, got %d", f.Name, f.Kind)
}
if f.Primitive != KindFloat32 {
t.Errorf("field %s: expected KindFloat32, got %d", f.Name, f.Primitive)
}
if f.Quant == nil {
t.Errorf("field %s: expected quant info, got nil", f.Name)
continue
}
if f.Quant.Min != -500 || f.Quant.Max != 500 || f.Quant.Bits != 16 {
t.Errorf("field %s: wrong quant info %+v", f.Name, f.Quant)
}
}
}
func TestParseSource_MoveMessage(t *testing.T) {
msgs, err := ParseSource(sampleSource)
if err != nil {
t.Fatalf("ParseSource: %v", err)
}
msg := msgs[1]
if msg.Name != "MoveMessage" {
t.Fatalf("expected MoveMessage, got %s", msg.Name)
}
tests := []struct {
name string
kind FieldKind
typeName string
fixedLen int
elemKind FieldKind
}{
{"Position", KindNested, "Vector3", 0, 0},
{"Velocity", KindFixedArray, "", 3, KindPrimitive},
{"Waypoints", KindSlice, "", 0, KindNested},
{"PlayerID", KindPrimitive, "", 0, 0},
{"Name", KindPrimitive, "", 0, 0},
{"Active", KindPrimitive, "", 0, 0},
}
if len(msg.Fields) != len(tests) {
t.Fatalf("expected %d fields, got %d", len(tests), len(msg.Fields))
}
for i, tc := range tests {
f := msg.Fields[i]
if f.Name != tc.name {
t.Errorf("[%d] expected field %s, got %s", i, tc.name, f.Name)
}
if f.Kind != tc.kind {
t.Errorf("field %s: expected kind %d, got %d", tc.name, tc.kind, f.Kind)
}
if tc.typeName != "" && f.TypeName != tc.typeName {
t.Errorf("field %s: expected TypeName %s, got %s", tc.name, tc.typeName, f.TypeName)
}
if tc.fixedLen > 0 {
if f.FixedLen != tc.fixedLen {
t.Errorf("field %s: expected FixedLen %d, got %d", tc.name, tc.fixedLen, f.FixedLen)
}
if f.Elem == nil {
t.Errorf("field %s: Elem is nil", tc.name)
} else if f.Elem.Kind != tc.elemKind {
t.Errorf("field %s: Elem.Kind expected %d, got %d", tc.name, tc.elemKind, f.Elem.Kind)
}
}
if tc.kind == KindSlice {
if f.Elem == nil {
t.Errorf("field %s: Elem is nil for slice", tc.name)
} else if f.Elem.Kind != tc.elemKind {
t.Errorf("field %s: Elem.Kind expected %d, got %d", tc.name, tc.elemKind, f.Elem.Kind)
}
}
}
}
func TestParseSource_SpawnMessage(t *testing.T) {
msgs, err := ParseSource(sampleSource)
if err != nil {
t.Fatalf("ParseSource: %v", err)
}
msg := msgs[2]
if msg.Name != "SpawnMessage" {
t.Fatalf("expected SpawnMessage, got %s", msg.Name)
}
// Tags: [4]string
tags := msg.Fields[2]
if tags.Kind != KindFixedArray || tags.FixedLen != 4 {
t.Errorf("Tags: expected KindFixedArray[4], got kind=%d fixedLen=%d", tags.Kind, tags.FixedLen)
}
if tags.Elem == nil || tags.Elem.Primitive != KindString {
t.Errorf("Tags: expected string element")
}
// Data: []uint8
data := msg.Fields[3]
if data.Kind != KindSlice {
t.Errorf("Data: expected KindSlice, got %d", data.Kind)
}
if data.Elem == nil || data.Elem.Primitive != KindUint8 {
t.Errorf("Data: expected uint8 element")
}
}
func TestParseSchemaSource_Enums(t *testing.T) {
schema, err := ParseSchemaSource(enumSource)
if err != nil {
t.Fatalf("ParseSchemaSource: %v", err)
}
if len(schema.Messages) != 1 {
t.Fatalf("expected 1 message, got %d", len(schema.Messages))
}
if len(schema.Enums) != 1 {
t.Fatalf("expected 1 enum, got %d", len(schema.Enums))
}
enum := schema.Enums[0]
if enum.Name != "Opcode" {
t.Fatalf("expected enum Opcode, got %s", enum.Name)
}
if enum.Primitive != KindUint16 {
t.Fatalf("expected Opcode base kind uint16, got %d", enum.Primitive)
}
if len(enum.Values) != 3 {
t.Fatalf("expected 3 enum values, got %d", len(enum.Values))
}
if enum.Values[1].Name != "OpcodeAuthorize" || enum.Values[1].Value != "1" {
t.Fatalf("unexpected enum value %#v", enum.Values[1])
}
field := schema.Messages[0].Fields[0]
if field.Kind != KindPrimitive {
t.Fatalf("expected EnvelopeMessage.Code to be primitive, got %d", field.Kind)
}
if field.NamedType != "Opcode" {
t.Fatalf("expected named type Opcode, got %q", field.NamedType)
}
if field.Primitive != KindUint16 {
t.Fatalf("expected underlying uint16, got %d", field.Primitive)
}
}
func TestQuantTag_Errors(t *testing.T) {
cases := []struct {
src string
wantErr bool
}{
{`package p; type T struct { X float32 ` + "`" + `pack:"min=0,max=100"` + "`" + ` }`, false},
{`package p; type T struct { X float32 ` + "`" + `pack:"min=100,max=0"` + "`" + ` }`, true}, // max < min
{`package p; type T struct { X float32 ` + "`" + `pack:"min=0,max=100,bits=32"` + "`" + ` }`, true}, // bad bits
{`package p; type T struct { X int32 ` + "`" + `pack:"min=0,max=100"` + "`" + ` }`, true}, // quant на int
{`package p; type T struct { X float32 ` + "`" + `pack:"foo=1"` + "`" + ` }`, true}, // unknown key
}
for i, tc := range cases {
_, err := ParseSource(tc.src)
if tc.wantErr && err == nil {
t.Errorf("[%d] expected error, got nil", i)
}
if !tc.wantErr && err != nil {
t.Errorf("[%d] unexpected error: %v", i, err)
}
}
}
func TestWireSize(t *testing.T) {
msgs, err := ParseSource(sampleSource)
if err != nil {
t.Fatalf("ParseSource: %v", err)
}
v3 := msgs[0]
// Vector3: 3 × uint16 (квантизованные float32) = 6 байт
if v3.MinWireSize() != 6 {
t.Errorf("Vector3.MinWireSize: expected 6, got %d", v3.MinWireSize())
}
if v3.HasVariableFields() {
t.Errorf("Vector3 should not have variable fields")
}
}
func TestNestedUnknownType(t *testing.T) {
src := `package p
type Msg struct {
Pos UnknownType
}
`
_, err := ParseSource(src)
if err == nil {
t.Fatal("expected error for unknown nested type, got nil")
}
}