package main
import (
"os"
"strings"
"testing"
)
func testModules(t *testing.T) []*Module {
t.Helper()
old, err := os.Getwd()
if err != nil {
t.Fatal(err)
}
if err = os.Chdir("../.."); err != nil {
t.Fatal(err)
}
defer func() {
if err := os.Chdir(old); err != nil {
t.Fatal(err)
}
}()
ms, err := loadModules()
if err != nil {
t.Fatal(err)
}
return ms
}
func TestResolveLayouts(t *testing.T) {
ms := testModules(t)
expected := map[string]int{"Setup": 40, "Screen": 40, "Rectangle": 8, "Point": 4, "Arc": 12, "Visualtype": 24, "Format": 8, "Depth": 8, "ClientMessageData": 20}
for _, typ := range ms[0].Types {
if want, ok := expected[typ.GoType]; ok {
if typ.Size != want {
t.Errorf("%s size=%d want %d", typ.GoType, typ.Size, want)
}
delete(expected, typ.GoType)
}
if typ.GoType == "Rectangle" {
for i, want := range []int{0, 2, 4, 6} {
if typ.Fields[i].Off != want {
t.Errorf("rectangle field %d offset", i)
}
}
}
}
if len(expected) != 0 {
t.Fatal("missing types", expected)
}
for _, name := range []string{"Window", "Atom", "Cursor", "Pixmap", "Font"} {
found := false
for _, e := range ms[0].Enums {
if e.Name == name {
found = e.Existing
}
}
if !found {
t.Errorf("%s must reuse XID type", name)
}
}
for _, m := range ms {
if err := packetSizeChecks(m); err != nil {
t.Fatal(err)
}
}
}
func TestResolveRejectsCollisions(t *testing.T) {
for _, body := range []string{
`- 0
`,
``,
`- 0
- 0
`,
} {
n, err := parseXML("collision.xml", strings.NewReader(``+body+``))
if err != nil {
t.Fatal(err)
}
_, err = resolveModules([]*Node{n})
if err == nil || !strings.Contains(err.Error(), "collision.xml:1:") || !strings.Contains(err.Error(), "collision") {
t.Fatalf("got %v", err)
}
}
}
func TestNaming(t *testing.T) {
for in, want := range map[string]string{"WINDOW": "Window", "data_len": "DataLen", "ClientIdSpec": "ClientIdSpec", "2d": "X2d", "BOOL32": "Bool32"} {
if got := goName(in); got != want {
t.Errorf("%s => %s want %s", in, got, want)
}
}
if paramName("type") != "type_" {
t.Fatal("keyword parameter")
}
}
func TestRenderExpr(t *testing.T) {
n, err := parseXML("expr.xml", strings.NewReader(`n4`))
if err != nil {
t.Fatal(err)
}
got, err := renderExpr(n.Children[0].Children[0].Children[0], func(s string) string { return "int(v." + goName(s) + ")" }, nil)
if err != nil || got != "(int(v.N) * 4)" {
t.Fatalf("%s %v", got, err)
}
}
func TestFixedRequests(t *testing.T) {
ms := testModules(t)
for _, m := range ms {
requests, err := resolveRequests(m)
if err != nil {
t.Fatal(err)
}
for _, r := range requests {
decl, err := requestDecl(m, r)
if err != nil {
t.Fatal(err)
}
if !strings.Contains(decl, "if p==nil { return 0 }") {
t.Fatal("missing sticky-error guard")
}
if m.Header == "xproto" && r.Name == "MapWindow" {
if r.Fixed != 4 || len(r.Params) != 1 || r.Fields[0].Off != 0 {
t.Fatal("MapWindow layout")
}
}
if m.Header == "xfixes" && r.Name == "QueryVersion" {
if r.Fixed != 8 || r.DataByte != nil || r.Fields[1].Off != 4 {
t.Fatal("extension layout")
}
}
}
}
}
func TestListResolution(t *testing.T) {
for _, m := range testModules(t) {
rs, err := resolveRequests(m)
if err != nil {
t.Fatal(err)
}
for _, r := range rs {
switch r.Name {
case "InternAtom":
if r.Derived["name_len"] != "name" || len(r.Params) != 2 {
t.Fatal("InternAtom derived length")
}
case "ChangeProperty":
if len(r.Derived) != 0 || len(r.Params) != 7 {
t.Fatal("ChangeProperty explicit expression fields")
}
case "AddGlyphs":
if r.Derived["glyphs_len"] != "" {
t.Fatal("shared count must remain explicit")
}
case "QueryClientIds":
if r.Derived["num_specs"] != "specs" || r.Params[0].GoType != "[]ClientIdSpec" {
t.Fatal("fixed struct list")
}
case "SetFontPath":
if r.Params[0].GoType != "[]Str" || !r.Lists[0].Type.Variable {
t.Fatal("variable struct list")
}
}
}
}
}