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) } }