Files
mesh-catalog/modules/xdg/cmd/xdg-tools/manifest_test.go
T
jochen 785d32407b xdg: own the account's folders and the machine's default applications
The workstations' XDG conventions had no owner: xdg-user-dirs-update rewrote
the folders file at every login, both machines' default-application lists
named an editor neither has, and the laptop kept two dead links of the
retired predecessor. The module adopts the operator's folders (three as
settings, as the machines differ), disables the update so it cannot undo the
mesh's file, and writes the machine's own mimeapps list, the last one read,
so the person's choices in their own list always win. Autostart is listed,
not owned: each entry is its application's module's.
2026-10-05 11:50:34 +02:00

197 lines
6.6 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)
}
}
}