diff options
| author | Danilo M. <danix@danix.xyz> | 2026-10-19 09:52:43 +0200 |
|---|---|---|
| committer | Danilo M. <danix@danix.xyz> | 2026-10-19 09:52:43 +0200 |
| commit | 7a4d76c5db3e7668796486a0a4d9db583f89b8e5 (patch) | |
| tree | 61fc40d7d9fe67b2639b04ca72f1d39356218a76 /internal/notify/sounds_test.go | |
| parent | 73bd9ea2e297a88ae8de11414819cf45e5fc0bb2 (diff) | |
| download | notifyd-7a4d76c5db3e7668796486a0a4d9db583f89b8e5.tar.gz notifyd-7a4d76c5db3e7668796486a0a4d9db583f89b8e5.zip | |
feat(notify): resolve sound-file, sound-name and suppress-sound hints
sound-name is looked up in a sound theme, its Inherits chain and
freedesktop, with the naming spec's trailing-component fallback. A
sound-file must be an absolute path to an existing file, else it is
treated as absent so a sound-name in the same notification still applies.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Diffstat (limited to 'internal/notify/sounds_test.go')
| -rw-r--r-- | internal/notify/sounds_test.go | 115 |
1 files changed, 115 insertions, 0 deletions
diff --git a/internal/notify/sounds_test.go b/internal/notify/sounds_test.go new file mode 100644 index 0000000..060bbbe --- /dev/null +++ b/internal/notify/sounds_test.go @@ -0,0 +1,115 @@ +// Copyright (C) 2026 Danilo M. <danix@danix.xyz> +// +// This program is free software; you can redistribute it and/or modify +// it under the terms of the GNU General Public License version 2 as +// published by the Free Software Foundation. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. + +package notify + +import ( + "os" + "path/filepath" + "testing" + + "github.com/godbus/dbus/v5" +) + +// soundTree makes $XDG_DATA_HOME/sounds/<theme>/stereo/<file> for each entry +// and an index.theme per theme with the given Inherits, and points +// XDG_DATA_HOME there with XDG_DATA_DIRS empty-but-set to another temp dir. +func soundTree(t *testing.T, inherits map[string]string, files ...string) string { + t.Helper() + home := t.TempDir() + t.Setenv("XDG_DATA_HOME", home) + t.Setenv("XDG_DATA_DIRS", t.TempDir()) + for theme, inh := range inherits { + dir := filepath.Join(home, "sounds", theme) + if err := os.MkdirAll(filepath.Join(dir, "stereo"), 0o755); err != nil { + t.Fatal(err) + } + body := "[Sound Theme]\nName=" + theme + "\n" + if inh != "" { + body += "Inherits=" + inh + "\n" + } + if err := os.WriteFile(filepath.Join(dir, "index.theme"), []byte(body), 0o644); err != nil { + t.Fatal(err) + } + } + for _, f := range files { + p := filepath.Join(home, "sounds", f) + if err := os.MkdirAll(filepath.Dir(p), 0o755); err != nil { + t.Fatal(err) + } + if err := os.WriteFile(p, []byte("x"), 0o644); err != nil { + t.Fatal(err) + } + } + return filepath.Join(home, "sounds") +} + +func TestLookupSound(t *testing.T) { + root := soundTree(t, + map[string]string{"mine": "parent", "parent": "", "freedesktop": ""}, + "mine/stereo/bell.oga", + "mine/stereo/bell.wav", + "parent/stereo/message-new-instant.ogg", + "freedesktop/stereo/dialog-warning.oga", + "freedesktop/stereo/message.oga", + ) + cases := []struct{ name, want string }{ + {"bell", root + "/mine/stereo/bell.oga"}, // direct, .oga before .wav + {"message-new-instant", root + "/parent/stereo/message-new-instant.ogg"}, // inherited + {"dialog-warning", root + "/freedesktop/stereo/dialog-warning.oga"}, // freedesktop fallback + {"message-new-email", root + "/freedesktop/stereo/message.oga"}, // name fallback + {"nothing-here", ""}, + } + for _, c := range cases { + if got := LookupSound(c.name, "mine"); got != c.want { + t.Errorf("LookupSound(%q) = %q, want %q", c.name, got, c.want) + } + } +} + +func TestLookupSoundInheritsCycle(t *testing.T) { + soundTree(t, map[string]string{"a": "b", "b": "a"}) + if got := LookupSound("bell", "a"); got != "" { + t.Errorf("got %q, want empty", got) + } +} + +func TestSoundFromHints(t *testing.T) { + root := soundTree(t, map[string]string{"freedesktop": ""}, "freedesktop/stereo/bell.oga") + file := filepath.Join(t.TempDir(), "ding.wav") + if err := os.WriteFile(file, []byte("x"), 0o644); err != nil { + t.Fatal(err) + } + v := dbus.MakeVariant + cases := []struct { + name string + hints map[string]dbus.Variant + sound string + silent bool + }{ + {"none", map[string]dbus.Variant{}, "", false}, + {"name", map[string]dbus.Variant{"sound-name": v("bell")}, root + "/freedesktop/stereo/bell.oga", false}, + {"file wins", map[string]dbus.Variant{"sound-name": v("bell"), "sound-file": v(file)}, file, false}, + {"relative file rejected", map[string]dbus.Variant{"sound-file": v("ding.wav")}, "", false}, + {"missing file rejected", map[string]dbus.Variant{"sound-file": v(file + ".gone")}, "", false}, + {"bad file falls to name", map[string]dbus.Variant{"sound-file": v("x"), "sound-name": v("bell")}, root + "/freedesktop/stereo/bell.oga", false}, + {"suppress", map[string]dbus.Variant{"suppress-sound": v(true), "sound-name": v("bell")}, root + "/freedesktop/stereo/bell.oga", true}, + {"wrong types", map[string]dbus.Variant{"suppress-sound": v("yes"), "sound-name": v(3)}, "", false}, + } + for _, c := range cases { + t.Run(c.name, func(t *testing.T) { + sound, silent := SoundFromHints(c.hints, "freedesktop") + if sound != c.sound || silent != c.silent { + t.Errorf("got (%q, %v), want (%q, %v)", sound, silent, c.sound, c.silent) + } + }) + } +} |
