1package main
2
3import (
4 "os"
5 "strings"
6 "testing"
7)
8
9func testModules(t *testing.T) []*Module {
10 t.Helper()
11 old, err := os.Getwd()
12 if err != nil {
13 t.Fatal(err)
14 }
15 if err = os.Chdir("../.."); err != nil {
16 t.Fatal(err)
17 }
18 defer func() {
19 if err := os.Chdir(old); err != nil {
20 t.Fatal(err)
21 }
22 }()
23 ms, err := loadModules()
24 if err != nil {
25 t.Fatal(err)
26 }
27 return ms
28}
29func TestResolveLayouts(t *testing.T) {
30 ms := testModules(t)
31 expected := map[string]int{"Setup": 40, "Screen": 40, "Rectangle": 8, "Point": 4, "Arc": 12, "Visualtype": 24, "Format": 8, "Depth": 8, "ClientMessageData": 20}
32 for _, typ := range ms[0].Types {
33 if want, ok := expected[typ.GoType]; ok {
34 if typ.Size != want {
35 t.Errorf("%s size=%d want %d", typ.GoType, typ.Size, want)
36 }
37 delete(expected, typ.GoType)
38 }
39 if typ.GoType == "Rectangle" {
40 for i, want := range []int{0, 2, 4, 6} {
41 if typ.Fields[i].Off != want {
42 t.Errorf("rectangle field %d offset", i)
43 }
44 }
45 }
46 }
47 if len(expected) != 0 {
48 t.Fatal("missing types", expected)
49 }
50 for _, name := range []string{"Window", "Atom", "Cursor", "Pixmap", "Font"} {
51 found := false
52 for _, e := range ms[0].Enums {
53 if e.Name == name {
54 found = e.Existing
55 }
56 }
57 if !found {
58 t.Errorf("%s must reuse XID type", name)
59 }
60 }
61 for _, m := range ms {
62 if err := packetSizeChecks(m); err != nil {
63 t.Fatal(err)
64 }
65 }
66}
67func TestResolveRejectsCollisions(t *testing.T) {
68 for _, body := range []string{
69 `<struct name="A"/><enum name="A"><item name="B"><value>0</value></item></enum>`,
70 `<xidtype name="A"/><xidtype name="a"/>`,
71 `<enum name="A"><item name="B"><value>0</value></item></enum><enum name="A"><item name="C"><value>0</value></item></enum>`,
72 } {
73 n, err := parseXML("collision.xml", strings.NewReader(`<xcb header="test">`+body+`</xcb>`))
74 if err != nil {
75 t.Fatal(err)
76 }
77 _, err = resolveModules([]*Node{n})
78 if err == nil || !strings.Contains(err.Error(), "collision.xml:1:") || !strings.Contains(err.Error(), "collision") {
79 t.Fatalf("got %v", err)
80 }
81 }
82}
83func TestNaming(t *testing.T) {
84 for in, want := range map[string]string{"WINDOW": "Window", "data_len": "DataLen", "ClientIdSpec": "ClientIdSpec", "2d": "X2d", "BOOL32": "Bool32"} {
85 if got := goName(in); got != want {
86 t.Errorf("%s => %s want %s", in, got, want)
87 }
88 }
89 if paramName("type") != "type_" {
90 t.Fatal("keyword parameter")
91 }
92}
93
94func TestRenderExpr(t *testing.T) {
95 n, err := parseXML("expr.xml", strings.NewReader(`<xcb header="test"><request name="R" opcode="1"><exprfield name="x" type="CARD32"><op op="*"><fieldref>n</fieldref><value>4</value></op></exprfield></request></xcb>`))
96 if err != nil {
97 t.Fatal(err)
98 }
99 got, err := renderExpr(n.Children[0].Children[0].Children[0], func(s string) string { return "int(v." + goName(s) + ")" }, nil)
100 if err != nil || got != "(int(v.N) * 4)" {
101 t.Fatalf("%s %v", got, err)
102 }
103}
104
105func TestFixedRequests(t *testing.T) {
106 ms := testModules(t)
107 for _, m := range ms {
108 requests, err := resolveRequests(m)
109 if err != nil {
110 t.Fatal(err)
111 }
112 for _, r := range requests {
113 decl, err := requestDecl(m, r)
114 if err != nil {
115 t.Fatal(err)
116 }
117 if !strings.Contains(decl, "if p==nil { return 0 }") {
118 t.Fatal("missing sticky-error guard")
119 }
120 if m.Header == "xproto" && r.Name == "MapWindow" {
121 if r.Fixed != 4 || len(r.Params) != 1 || r.Fields[0].Off != 0 {
122 t.Fatal("MapWindow layout")
123 }
124 }
125 if m.Header == "xfixes" && r.Name == "QueryVersion" {
126 if r.Fixed != 8 || r.DataByte != nil || r.Fields[1].Off != 4 {
127 t.Fatal("extension layout")
128 }
129 }
130 }
131 }
132}
133
134func TestListResolution(t *testing.T) {
135 for _, m := range testModules(t) {
136 rs, err := resolveRequests(m)
137 if err != nil {
138 t.Fatal(err)
139 }
140 for _, r := range rs {
141 switch r.Name {
142 case "InternAtom":
143 if r.Derived["name_len"] != "name" || len(r.Params) != 2 {
144 t.Fatal("InternAtom derived length")
145 }
146 case "ChangeProperty":
147 if len(r.Derived) != 0 || len(r.Params) != 7 {
148 t.Fatal("ChangeProperty explicit expression fields")
149 }
150 case "AddGlyphs":
151 if r.Derived["glyphs_len"] != "" {
152 t.Fatal("shared count must remain explicit")
153 }
154 case "QueryClientIds":
155 if r.Derived["num_specs"] != "specs" || r.Params[0].GoType != "[]ClientIdSpec" {
156 t.Fatal("fixed struct list")
157 }
158 case "SetFontPath":
159 if r.Params[0].GoType != "[]Str" || !r.Lists[0].Type.Variable {
160 t.Fatal("variable struct list")
161 }
162 }
163 }
164 }
165}