Files
arpack/parser/parser_test.go
T
2026-03-19 14:52:12 +03:00

269 lines
6.9 KiB
Go
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
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")
}
}