package main import ( "encoding/json" "os" "os/exec" "path/filepath" "reflect" "strings" "testing" ) // polychromatic's shape (novox/hq ADR 0205, ADR 0208, ADR 0212): no package (the tray is outside the // official repositories and kept as found), the X display on its own machine, one contribution to the // window manager's configuration that is the tray's one start, nothing of the openrazer module's, and // the Go bundle serving exactly the listed polychromatic_ tools. type manifest struct { Module string `json:"module"` Version string `json:"version"` Capabilities []string `json:"capabilities"` Requires []string `json:"requires"` Tools []string `json:"tools"` Resources []map[string]any `json:"resources"` Claims []any `json:"claims"` Seats []any `json:"seats"` Shell []any `json:"shell"` Contributions []struct { Seat string `json:"seat"` Kind string `json:"kind"` Content string `json:"content"` } `json:"contributions"` Environment any `json:"environment"` Build struct { Artifacts []map[string]any `json:"artifacts"` } `json:"build"` } func readManifest(t *testing.T) (manifest, string) { t.Helper() raw, err := os.ReadFile(filepath.Join("..", "..", "module.json")) if err != nil { t.Fatal(err) } dec := json.NewDecoder(strings.NewReader(string(raw))) dec.DisallowUnknownFields() var m manifest if err := dec.Decode(&m); err != nil { t.Fatalf("module.json: %v", err) } return m, string(raw) } func TestTheToolsAgreeWithTheManifest(t *testing.T) { m, raw := readManifest(t) served := map[string]bool{} for _, tool := range tools() { served[tool.Name] = true if !strings.HasPrefix(tool.Name, "polychromatic_") || strings.TrimSpace(tool.Description) == "" { t.Errorf("%s: prefixed %s and described", tool.Name, "polychromatic_") } } for _, name := range m.Tools { if !served[name] { t.Errorf("module.json lists %s, which the bundle does not serve", name) } delete(served, name) } for name := range served { t.Errorf("the bundle serves %s, which module.json does not list", name) } if len(m.Build.Artifacts) != 1 { t.Fatalf("%v", m.Build.Artifacts) } b := m.Build.Artifacts[0] if b["kind"] != "bundle" || b["language"] != "go" || b["system"] != "arch" || b["from"] != "cmd/polychromatic-tools" || b["binary"] != "polychromatic-tools" { t.Errorf("the Go tools bundle: %v", b) } s := strings.ToLower(raw) for _, never := range []string{"/home/", "jochen", "g14", "shanks", "novox.be", "http", "password", "token"} { if strings.Contains(s, never) { t.Errorf("module.json names %q", never) } } } func TestItDeclaresNoPackageAndContributesTheTraysOneStart(t *testing.T) { m, raw := readManifest(t) if m.Module != "polychromatic" || !reflect.DeepEqual(m.Requires, []string{"x11-display"}) { t.Fatalf("%+v", m) } if m.Resources != nil || m.Capabilities != nil || m.Claims != nil || m.Seats != nil || m.Environment != nil || m.Shell != nil { t.Fatal("no package (outside the official repositories), no seat, no environment, no xinitrc start") } if len(m.Contributions) != 1 || m.Contributions[0].Seat != "node-display-session" || m.Contributions[0].Kind != "config" { t.Fatalf("%+v", m.Contributions) } var code []string for _, l := range strings.Split(m.Contributions[0].Content, "\n") { if l = strings.TrimSpace(l); l != "" && !strings.HasPrefix(l, "#") { code = append(code, l) } } if !reflect.DeepEqual(code, []string{"exec --no-startup-id " + trayWord}) { t.Fatalf("one line, the tray's start with exec (a reload must not start it again): %q", code) } for _, never := range []string{"openrazer", "preferences.json", "autostart\""} { if strings.Contains(raw, never) { t.Errorf("module.json names %s", never) } } } // The window manager's own check parses the line, as the i3 module's catalogue-wide test does with // every contribution together. func TestTheContributionParsesInI3(t *testing.T) { i3, err := exec.LookPath("i3") if err != nil { t.Skip("no i3 here to check with") } m, _ := readManifest(t) path := filepath.Join(t.TempDir(), "config") os.WriteFile(path, []byte("set $mod Mod4\n"+m.Contributions[0].Content), 0o644) if out, err := exec.Command(i3, "-C", "-c", path).CombinedOutput(); err != nil || strings.Contains(string(out), "ERROR") { t.Fatalf("i3 -C: %v %s", err, out) } }