1package scanner
2
3import (
4 "bytes"
5 "os"
6 "path/filepath"
7 "strings"
8 "testing"
9)
10
11// Check every checked-in binding against its generation command, including
12// external type mappings. Regeneration must not depend on the host's XML files.
13func TestVendoredProtocolsReproduce(t *testing.T) {
14 root := filepath.Join("..", "..", "protocol")
15 referenced := make(map[string]bool)
16 err := filepath.WalkDir(root, func(path string, entry os.DirEntry, err error) error {
17 if err != nil {
18 return err
19 }
20 if entry.IsDir() || entry.Name() != "generate.go" {
21 return nil
22 }
23 content, err := os.ReadFile(path)
24 if err != nil {
25 return err
26 }
27 for _, line := range strings.Split(string(content), "\n") {
28 if !strings.HasPrefix(line, "//go:generate go run ") {
29 continue
30 }
31 fields := strings.Fields(line)
32 if len(fields) < 5 || !strings.HasSuffix(fields[3], "/cmd/wlturbo-scanner") {
33 t.Fatalf("%s: expected direct go run of cmd/wlturbo-scanner", path)
34 }
35 args := fields[4:]
36 var pkg, output, input string
37 imports := make(map[string]string)
38 for i := 0; i < len(args); i++ {
39 switch args[i] {
40 case "-p", "-o", "-import":
41 if i+1 == len(args) {
42 t.Fatalf("%s: missing value for %s", path, args[i])
43 }
44 flag, value := args[i], args[i+1]
45 i++
46 switch flag {
47 case "-p":
48 pkg = value
49 case "-o":
50 output = value
51 case "-import":
52 iface, target, ok := strings.Cut(value, "=")
53 if !ok {
54 t.Fatalf("%s: invalid import %q", path, value)
55 }
56 imports[iface] = target
57 }
58 default:
59 if strings.HasPrefix(args[i], "-") || input != "" {
60 t.Fatalf("%s: unexpected generation argument %q", path, args[i])
61 }
62 input = args[i]
63 }
64 }
65 if pkg == "" || output == "" || input == "" {
66 t.Fatalf("%s: incomplete generation command", path)
67 }
68 dir := filepath.Dir(path)
69 xmlPath := filepath.Clean(filepath.Join(dir, input))
70 if referenced[xmlPath] {
71 t.Fatalf("%s generated more than once", xmlPath)
72 }
73 referenced[xmlPath] = true
74 t.Run(pkg, func(t *testing.T) {
75 s := NewScanner()
76 s.CrossPackage = imports
77 if err := s.ParseXML(xmlPath); err != nil {
78 t.Fatal(err)
79 }
80 generated, err := s.Generate(pkg)
81 if err != nil {
82 t.Fatal(err)
83 }
84 checkedIn, err := os.ReadFile(filepath.Join(dir, output))
85 if err != nil {
86 t.Fatal(err)
87 }
88 if !bytes.Equal(generated, checkedIn) {
89 t.Fatal("bindings are stale; run GOWORK=off go generate ./...")
90 }
91 })
92 }
93 return nil
94 })
95 if err != nil {
96 t.Fatal(err)
97 }
98 if len(referenced) == 0 {
99 t.Fatal("no vendored protocols found")
100 }
101 err = filepath.WalkDir(root, func(path string, entry os.DirEntry, err error) error {
102 if err != nil {
103 return err
104 }
105 if !entry.IsDir() && filepath.Ext(path) == ".xml" && !referenced[path] {
106 t.Errorf("%s has no generation command", path)
107 }
108 return nil
109 })
110 if err != nil {
111 t.Fatal(err)
112 }
113}