Files
mesh-catalog/modules/picom/cmd/picom-tools/picom_test.go
T
jochen bb7dd1be5b picom: the compositor as a module, claiming node-compositor (hq ADR 0208)
Owns its configuration, moved to picom's window rules; started once from the
session's xinitrc slot; Go tools restart, rules, window-opacity and toggle, which
find the operator's X session from the window manager's environment.
2026-10-04 13:10:58 +02:00

132 lines
4.7 KiB
Go

package main
import (
"errors"
"os"
"path/filepath"
"strings"
"testing"
)
// A pid above the kernel's largest, so a signal a test sends reaches nothing.
const nobody = 4194400
func TestTheModulesOwnConfigurationReadsAsRulesInOrder(t *testing.T) {
raw, err := os.ReadFile(filepath.Join("..", "..", "files", "picom.conf"))
if err != nil {
t.Fatal(err)
}
r := parseRules("picom.conf", string(raw), nil)
if r.Global["backend"] != "glx" || r.Global["vsync"] != "true" || r.Global["shadow"] != "false" {
t.Fatalf("global options: %v", r.Global)
}
if len(r.Rules) != 5 {
t.Fatalf("five rules: %+v", r.Rules)
}
focused, unfocused := r.Rules[2], r.Rules[3]
if focused.Match != "class_g = 'XTerm' && focused" || focused.Options["opacity"] != "0.95" ||
unfocused.Match != "class_g = 'XTerm' && !focused" || unfocused.Options["opacity"] != "0.75" {
t.Fatalf("the terminal rules: %+v %+v", focused, unfocused)
}
if last := r.Rules[4]; last.Match != "fullscreen" || last.Options["opacity"] != "1" {
t.Fatalf("full screen is opaque, and last so it wins: %+v", last)
}
if len(r.Legacy) != 0 {
t.Fatalf("the module's file sets no option the rules supersede: %v", r.Legacy)
}
if _, inGlobal := r.Global["match"]; inGlobal {
t.Fatal("a rule's key leaked into the global options")
}
}
func TestTodaysFileIsReportedForTheOptionsItsRulesWouldIgnore(t *testing.T) {
conf := "inactive-opacity = 1.0;\nopacity-rule = [ \"95:class_g = 'XTerm'\" ];\nrules = (\n { match = \"focused\"; opacity = 1; }\n);\n"
r := parseRules("x", conf, []int{7})
if len(r.Rules) != 1 || r.Rules[0].Match != "focused" || len(r.Running) != 1 {
t.Fatalf("%+v", r)
}
if strings.Join(r.Legacy, ",") != "opacity-rule,inactive-opacity" {
t.Fatalf("legacy: %v", r.Legacy)
}
}
func TestAWindowIdIsHexOrDecimalAndNeverZero(t *testing.T) {
for in, want := range map[string]string{"0x3C00012": "0x3c00012", "62914578": "0x3c00012"} {
if got, err := windowID(in); err != nil || got != want {
t.Errorf("%s: %s, %v", in, got, err)
}
}
for _, bad := range []string{"0", "0x0", "window", "-1", "0x1ffffffff"} {
if _, err := windowID(bad); err == nil {
t.Errorf("%s was accepted", bad)
}
}
}
func TestOpacityIsAPercentOfTheFullCardinal(t *testing.T) {
if opacityCardinal(0) != 0 || opacityCardinal(100) != 0xffffffff || opacityCardinal(75) != 3221225471 {
t.Fatalf("%d %d %d", opacityCardinal(0), opacityCardinal(100), opacityCardinal(75))
}
r := parseWindow("0x1", "_NET_WM_WINDOW_OPACITY(CARDINAL) = 3221225471\nWM_CLASS(STRING) = \"xterm\", \"XTerm\"\n_NET_WM_NAME(UTF8_STRING) = \"op@host: ~\"\n")
if r.Opacity == nil || *r.Opacity != 75 || r.Class != "XTerm" || r.Title != "op@host: ~" {
t.Fatalf("%+v", r)
}
if r := parseWindow("0x1", "_NET_WM_WINDOW_OPACITY: not found.\n"); r.Opacity != nil {
t.Fatalf("no value of its own: %+v", r)
}
}
func TestSettingTheFocusedWindowsOpacityAsksXpropAndNamesTheRuleThatOutranksIt(t *testing.T) {
root := fakeMachine(t)
fakeProcess(t, nobody, "i3", "DISPLAY=:1")
conf := filepath.Join(root, "home", ".config", "picom")
if err := os.MkdirAll(conf, 0o755); err != nil {
t.Fatal(err)
}
src, _ := os.ReadFile(filepath.Join("..", "..", "files", "picom.conf"))
if err := os.WriteFile(filepath.Join(conf, "picom.conf"), src, 0o644); err != nil {
t.Fatal(err)
}
bin := fakeBinaries(t, map[string]string{"xprop": `echo "xprop $* DISPLAY=$DISPLAY" >> "$LOG"
case "$*" in
"-root _NET_ACTIVE_WINDOW") echo "_NET_ACTIVE_WINDOW(WINDOW): window id # 0x3c00012" ;;
*WM_CLASS*) printf '_NET_WM_WINDOW_OPACITY(CARDINAL) = 2147483648\nWM_CLASS(STRING) = "xterm", "XTerm"\n' ;;
esac`})
t.Setenv("LOG", filepath.Join(bin, "log"))
r, err := WindowOpacity("", 50)
if err != nil {
t.Fatal(err)
}
if r.Window != "0x3c00012" || r.Opacity == nil || *r.Opacity != 50 || !strings.Contains(r.Note, "XTerm") {
t.Fatalf("%+v", r)
}
log, _ := os.ReadFile(filepath.Join(bin, "log"))
if !strings.Contains(string(log), "xprop -id 0x3c00012 -f _NET_WM_WINDOW_OPACITY 32c -set _NET_WM_WINDOW_OPACITY 2147483648 DISPLAY=:1") {
t.Fatalf("xprop was asked:\n%s", log)
}
}
func TestWithoutASessionTheToolsThatDrawSaySo(t *testing.T) {
fakeMachine(t)
if _, err := WindowOpacity("", -1); !errors.Is(err, ErrNoSession) {
t.Fatalf("window opacity: %v", err)
}
on := true
if _, err := Toggle(&on); !errors.Is(err, ErrNoSession) {
t.Fatalf("toggle on: %v", err)
}
}
func TestARunningPicomIsToldToReinitialiseNotRestarted(t *testing.T) {
fakeMachine(t)
fakeProcess(t, nobody, "picom", "DISPLAY=:1")
r, err := Restart(false)
if err != nil || r.Action != "reinitialised" {
t.Fatalf("%+v, %v", r, err)
}
on := true
if r, err := Toggle(&on); err != nil || !r.Compositing || r.PIDs[0] != nobody {
t.Fatalf("on while running: %+v, %v", r, err)
}
}