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`, ``, `00`, } { 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") } } } } }