Files
2026-09-04 13:03:45 -04:00

131 lines
3.2 KiB
Go

package utils
import (
"fmt"
"os"
"os/exec"
"path/filepath"
"testing"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
)
func TestTryLockRejectsSecondHolder(t *testing.T) {
t.Setenv("XDG_RUNTIME_DIR", t.TempDir())
held, err := TryLock(SelectionOverlayLock)
require.NoError(t, err)
_, err = TryLock(SelectionOverlayLock)
assert.ErrorIs(t, err, ErrLockHeld)
held.Release()
reacquired, err := TryLock(SelectionOverlayLock)
require.NoError(t, err)
reacquired.Release()
}
func TestTryLockSeparatesNames(t *testing.T) {
t.Setenv("XDG_RUNTIME_DIR", t.TempDir())
first, err := TryLock("dms-test-a")
require.NoError(t, err)
defer first.Release()
second, err := TryLock("dms-test-b")
require.NoError(t, err)
second.Release()
}
func TestTryLockSeparatesWaylandDisplays(t *testing.T) {
t.Setenv("XDG_RUNTIME_DIR", t.TempDir())
t.Setenv("WAYLAND_DISPLAY", "wayland-1")
first, err := TryLock(SelectionOverlayLock)
require.NoError(t, err)
defer first.Release()
t.Setenv("WAYLAND_DISPLAY", "wayland-2")
second, err := TryLock(SelectionOverlayLock)
require.NoError(t, err)
second.Release()
}
func TestTryLockWithoutWaylandDisplay(t *testing.T) {
t.Setenv("XDG_RUNTIME_DIR", t.TempDir())
t.Setenv("WAYLAND_DISPLAY", "")
os.Unsetenv("WAYLAND_DISPLAY")
unset, err := TryLock(SelectionOverlayLock)
require.NoError(t, err)
assert.Equal(t, fmt.Sprintf("%s-%d-wayland-0.lock", SelectionOverlayLock, os.Getuid()), filepath.Base(lockPath(SelectionOverlayLock)))
t.Setenv("WAYLAND_DISPLAY", "wayland-1")
other, err := TryLock(SelectionOverlayLock)
require.NoError(t, err)
other.Release()
os.Unsetenv("WAYLAND_DISPLAY")
_, err = TryLock(SelectionOverlayLock)
assert.ErrorIs(t, err, ErrLockHeld)
unset.Release()
}
func TestDisplayScopeStaysASingleName(t *testing.T) {
cases := []struct{ display, want string }{
{"", "wayland-0"},
{"/", "wayland-0"},
{"..", "wayland-0"},
{"wayland-1", "wayland-1"},
{"/run/user/1000/wayland-2", "wayland-2"},
{"/run/user/1000/wayland-3/", "wayland-3"},
}
for _, tc := range cases {
t.Setenv("WAYLAND_DISPLAY", tc.display)
assert.Equal(t, tc.want, displayScope(), tc.display)
}
}
func TestTryLockExcludesOtherProcesses(t *testing.T) {
if _, err := exec.LookPath("flock"); err != nil {
t.Skip("flock not available")
}
t.Setenv("XDG_RUNTIME_DIR", t.TempDir())
held, err := TryLock(SelectionOverlayLock)
require.NoError(t, err)
path := lockPath(SelectionOverlayLock)
assert.Error(t, exec.Command("flock", "-n", "-x", path, "-c", "true").Run())
held.Release()
assert.NoError(t, exec.Command("flock", "-n", "-x", path, "-c", "true").Run())
}
func TestLockSelectionOverlayReportsHolder(t *testing.T) {
t.Setenv("XDG_RUNTIME_DIR", t.TempDir())
held, err := LockSelectionOverlay()
require.NoError(t, err)
require.NotNil(t, held)
defer held.Release()
lock, err := LockSelectionOverlay()
assert.Nil(t, lock)
assert.ErrorIs(t, err, ErrOverlayActive)
assert.Contains(t, err.Error(), fmt.Sprintf("pid %d", os.Getpid()))
}
func TestLockSelectionOverlayFallsBackWhenUnavailable(t *testing.T) {
t.Setenv("XDG_RUNTIME_DIR", filepath.Join(t.TempDir(), "missing"))
lock, err := LockSelectionOverlay()
assert.NoError(t, err)
assert.Nil(t, lock)
lock.Release()
}