1package server
2
3import (
4 "bufio"
5 "os"
6 "path/filepath"
7 "strings"
8 "testing"
9
10 "github.com/bnema/go-wayland-bindings/spec"
11)
12
13// TestEquivalence regenerates every protocol listed in the //go:generate lines
14// of the baseline purego-libwayland protocol/gen.go and requires byte-identical
15// output. It runs only when WGB_OLD_PUREGO points at a baseline checkout.
16func TestEquivalence(t *testing.T) {
17 root := os.Getenv("WGB_OLD_PUREGO")
18 if root == "" {
19 t.Skip("WGB_OLD_PUREGO not set")
20 }
21 protoDir := filepath.Join(root, "protocol")
22 f, err := os.Open(filepath.Join(protoDir, "gen.go"))
23 if err != nil {
24 t.Fatal(err)
25 }
26 defer f.Close()
27
28 const prefix = "//go:generate go run ../cmd/wlgen "
29 n := 0
30 sc := bufio.NewScanner(f)
31 sc.Buffer(make([]byte, 0, 64*1024), 1024*1024)
32 for sc.Scan() {
33 line := sc.Text()
34 if !strings.HasPrefix(line, prefix) {
35 continue
36 }
37 args := strings.Fields(strings.TrimPrefix(line, prefix))
38 n++
39 t.Run(line[len(prefix):], func(t *testing.T) { checkLine(t, protoDir, args) })
40 }
41 if err := sc.Err(); err != nil {
42 t.Fatal(err)
43 }
44 if n == 0 {
45 t.Fatal("no //go:generate lines found")
46 }
47}
48
49func loadXML(t *testing.T, path string) *spec.Protocol {
50 t.Helper()
51 b, err := os.ReadFile(path)
52 if err != nil {
53 t.Fatal(err)
54 }
55 p, err := spec.Parse(b)
56 if err != nil {
57 t.Fatalf("%s: %v", path, err)
58 }
59 return p
60}
61
62func checkLine(t *testing.T, protoDir string, args []string) {
63 opts := Options{Imports: map[string]string{}, Owners: map[string]string{}, Tool: "wlgen"}
64 var out, xmlPath string
65 var importXML []string
66 for i := 0; i < len(args); i++ {
67 switch args[i] {
68 case "-package", "-out", "-import", "-import-xml":
69 if i+1 >= len(args) {
70 t.Fatalf("flag %s missing value", args[i])
71 }
72 v := args[i+1]
73 i++
74 switch args[i-1] {
75 case "-package":
76 opts.Package = v
77 case "-out":
78 out = v
79 case "-import":
80 a, path, ok := strings.Cut(v, "=")
81 if !ok {
82 t.Fatalf("invalid -import %q", v)
83 }
84 opts.Imports[a] = path
85 case "-import-xml":
86 importXML = append(importXML, v)
87 }
88 default:
89 xmlPath = args[i]
90 }
91 }
92 if opts.Package == "" || out == "" || xmlPath == "" {
93 t.Fatalf("incomplete generate line: %v", args)
94 }
95 for _, s := range importXML {
96 a, path, ok := strings.Cut(s, "=")
97 if !ok || opts.Imports[a] == "" {
98 t.Fatalf("invalid -import-xml %q", s)
99 }
100 for _, it := range loadXML(t, filepath.Join(protoDir, path)).Interfaces {
101 opts.Owners[it.Name] = a
102 }
103 }
104 got, err := Generate(loadXML(t, filepath.Join(protoDir, xmlPath)), opts)
105 if err != nil {
106 t.Fatal(err)
107 }
108 want, err := os.ReadFile(filepath.Join(protoDir, out))
109 if err != nil {
110 t.Fatal(err)
111 }
112 if string(got) != string(want) {
113 t.Errorf("generated output differs from %s (got %d bytes, want %d)", out, len(got), len(want))
114 }
115}