Files
mesh-catalog/modules/xdg/cmd/xdg-tools/manifest_test.go
T
jschoubben a588eb5983
mesh/merge-gate pass: builds xdg → g14, shanks; no bus step; every machine composes with the change as it did without (4 of 4 compose)
mesh/repo-check pass: its merge-check.sh passed, each part in its toolchain: merge-check.sh (go), merge-check-typescript.sh (typescript)
mesh/delivery superseded: a newer delivery to the same trunk took over its walk
xdg: keep the folders file trusted, so only the terminal sets the folders (hq issue 346)
user-dirs.dirs is shell assignments meant to be sourced by a shell, and a setting is pasted into it as
it is, so a folder of $HOME/x"; <command>; X=" set through the verb would add a command of the
caller's. With the file trusted again, the three folders are set at the controller's terminal alone
until settings are typed and quoted at render.
2026-10-09 12:40:04 +02:00

215 lines
7.3 KiB
Go

package main
import (
"encoding/json"
"os"
"path/filepath"
"reflect"
"regexp"
"sort"
"strings"
"testing"
)
// xdg's shape: it claims no seat (the conventions are not a role anything calls), needs no
// display, owns the account's folders file whole and the machine's lowest list of default
// applications, and holds the person's own list of defaults and every autostart entry as found.
type manifest struct {
Module string `json:"module"`
Capabilities []string `json:"capabilities"`
Requires []string `json:"requires"`
Claims []any `json:"claims"`
Tools []string `json:"tools"`
Shell []any `json:"shell"`
Contributions []any `json:"contributions"`
Resources []map[string]any `json:"resources"`
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)
}
var m manifest
if err := json.Unmarshal(raw, &m); err != nil {
t.Fatal(err)
}
return m, string(raw)
}
func TestItClaimsNoSeatNeedsNoDisplayAndContributesNothing(t *testing.T) {
m, _ := readManifest(t)
if m.Module != "xdg" || m.Claims != nil || m.Requires != nil || m.Shell != nil || m.Contributions != nil {
t.Fatalf("%+v", m)
}
if !reflect.DeepEqual(m.Capabilities, []string{"package-manager"}) {
t.Fatalf("%v", m.Capabilities)
}
}
func TestItOwnsTheFilesItsSourcesHold(t *testing.T) {
m, _ := readManifest(t)
want := map[string][3]string{
"user-dirs": {"${machine:account-home}/.config/user-dirs.dirs", "0600", "user-dirs.dirs"},
"user-dirs-locale": {"${machine:account-home}/.config/user-dirs.locale", "0644", "user-dirs.locale"},
"user-dirs-update": {"${machine:account-home}/.config/user-dirs.conf", "0644", "user-dirs.conf"},
"default-applications": {MeshList, "0644", "mimeapps.list"},
}
var pkgs []string
files := 0
for _, r := range m.Resources {
id, _ := r["id"].(string)
if r["type"] == "package" {
pkgs = append(pkgs, r["package"].(string))
continue
}
w, ok := want[id]
if !ok || r["type"] != "file" {
t.Errorf("unexpected resource %v", r)
continue
}
files++
src, _ := os.ReadFile(filepath.Join("..", "..", "config", w[2]))
if r["path"] != w[0] || r["mode"] != w[1] || r["content"] != string(src) || r["into"] != nil {
t.Errorf("%s is not config/%s, whole, at %s mode %s: %v", id, w[2], w[0], w[1], r["path"])
}
home := strings.HasPrefix(w[0], "${machine:account-home}/")
if home != (r["owner"] == "${machine:account}") {
t.Errorf("%s: a file in the home is the account's, a system file root's: owner %v", id, r["owner"])
}
}
if files != len(want) {
t.Errorf("%d files, want %d", files, len(want))
}
if !reflect.DeepEqual(pkgs, []string{"xdg-user-dirs", "xdg-utils"}) {
t.Errorf("packages %v", pkgs)
}
for _, r := range m.Resources {
if p, _ := r["path"].(string); strings.Contains(p, "mimeapps.list") && strings.Contains(p, "account-home") {
t.Errorf("the person's mimeapps.list is held as found, never written: %v", r)
}
if p, _ := r["path"].(string); strings.Contains(p, "autostart") || strings.Contains(p, "xdg-desktop-portal") {
t.Errorf("autostart entries are their applications' modules', the portal is adwaita's: %v", r)
}
}
}
func TestTheFoldersFileIsXdgUserDirsOwnFormatWithThreeSettings(t *testing.T) {
raw, _ := os.ReadFile(filepath.Join("..", "..", "config", "user-dirs.dirs"))
text := string(raw)
settings := regexp.MustCompile(`\$\{setting:([a-z0-9-]+)\}`).FindAllStringSubmatch(text, -1)
var names []string
for _, s := range settings {
names = append(names, s[1])
}
sort.Strings(names)
if !reflect.DeepEqual(names, []string{"desktop-dir", "publicshare-dir", "videos-dir"}) {
t.Fatalf("the folders that differ between the workstations are the settings: %v", names)
}
lines := 0
for _, l := range strings.Split(strings.TrimSpace(text), "\n") {
if strings.HasPrefix(l, "#") {
continue
}
lines++
if !userDirLine.MatchString(l) {
t.Errorf("not xdg-user-dirs' format: %q", l)
}
}
// The eight folders GLib knows, and xdg-user-dirs' PROJECTS.
if lines != 9 {
t.Errorf("%d folders", lines)
}
if !strings.Contains(firstLines(text, 3), meshMark) {
t.Error("the header xdg_check recognises the file by")
}
conf, _ := os.ReadFile(filepath.Join("..", "..", "config", "user-dirs.conf"))
if !regexp.MustCompile(`(?m)^enabled=False$`).Match(conf) {
t.Error("xdg-user-dirs-update must be disabled, or it rewrites the mesh's file at login")
}
}
func TestTheMeshsDefaultsNameEachTypeOnceInOneGroupEach(t *testing.T) {
raw, _ := os.ReadFile(filepath.Join("..", "..", "config", "mimeapps.list"))
k := ParseKeyFile(string(raw))
if len(k.DupGroups)+len(k.DupKeys)+len(k.Unparsable) != 0 {
t.Fatalf("%+v", k)
}
if !reflect.DeepEqual(k.Order, []string{"Default Applications", "Added Associations"}) {
t.Fatalf("%v", k.Order)
}
for typ, v := range k.Groups["Default Applications"] {
if _, err := Normalise(typ); err != nil {
t.Errorf("%s: %v", typ, err)
}
for _, id := range List(v) {
if !desktopID.MatchString(id) || regexp.MustCompile(`[0-9a-f]{8}-[0-9a-f]{4}-`).MatchString(id) {
t.Errorf("%s=%s: an id one machine generated is not a default for every machine", typ, id)
}
if id == "code-oss.desktop" {
t.Errorf("%s: code-oss is installed on neither workstation", typ)
}
}
}
if k.Groups["Default Applications"]["x-scheme-handler/https"] != "firefox.desktop;" {
t.Error("the browser is the operator's")
}
}
func TestTheToolsAgreeWithTheManifest(t *testing.T) {
m, raw := readManifest(t)
served := map[string]bool{}
for _, tool := range tools(&Machine{}) {
served[tool.Name] = true
if !strings.HasPrefix(tool.Name, "xdg_") || strings.TrimSpace(tool.Description) == "" {
t.Errorf("%s", tool.Name)
}
}
if len(served) != len(m.Tools) {
t.Fatalf("%v %v", served, m.Tools)
}
for _, n := range m.Tools {
if !served[n] {
t.Errorf("module.json lists %s, which the bundle does not serve", n)
}
}
var bundle map[string]any
for _, a := range m.Build.Artifacts {
if a["kind"] == "bundle" {
bundle = a
}
}
if bundle == nil || bundle["language"] != "go" || bundle["system"] != "arch" || bundle["from"] != "cmd/xdg-tools" || bundle["binary"] != "xdg-tools" {
t.Errorf("the Go tools bundle: %v", bundle)
}
s := strings.ToLower(raw)
for _, never := range []string{"/home/", "jochen", "g14", "shanks", "novox.be", "zurag", ".hal/", "api_key"} {
if strings.Contains(s, never) {
t.Errorf("module.json names %q", never)
}
}
}
// The folders file stays trusted (unmarked), so its three settings are set at the controller's terminal
// alone. A value is pasted into it as it is, and the format is shell assignments defined to be sourced
// by a shell: `$HOME/x"; <command>; X="` would add a command of the caller's (hq issue 346). Until
// settings are typed and quoted at render, no verb may set them.
func TestTheFoldersFileStaysTrustedUntilSettingsAreQuoted(t *testing.T) {
m, _ := readManifest(t)
for _, r := range m.Resources {
if r["id"] != "user-dirs" {
continue
}
if _, marked := r["trusted"]; marked {
t.Fatal("user-dirs.dirs carries a trusted marking: its settings are the terminal's alone (hq issue 346)")
}
return
}
t.Fatal("no user-dirs resource")
}