summaryrefslogtreecommitdiff
path: root/tests/test-video-audio-recording--label-sinks.el
diff options
context:
space:
mode:
authorCraig Jennings <c@cjennings.net>2026-02-26 22:41:46 -0600
committerCraig Jennings <c@cjennings.net>2026-02-26 22:41:46 -0600
commita46f8af939b112b603a2c95b2e83a1932b208e20 (patch)
treec976afe867bfe7e57a3f425b911e2f654d913168 /tests/test-video-audio-recording--label-sinks.el
parent8de47fd766fe57c7f89960ee110b209a946024cb (diff)
test(recording): add tests for label-devices, label-sinks, get-sink-apps
Fill test gaps from quality-engineer review: 3 new test files (28 tests) and error cases for get-available-mics and get-available-sinks (+4 tests).
Diffstat (limited to 'tests/test-video-audio-recording--label-sinks.el')
-rw-r--r--tests/test-video-audio-recording--label-sinks.el111
1 files changed, 111 insertions, 0 deletions
diff --git a/tests/test-video-audio-recording--label-sinks.el b/tests/test-video-audio-recording--label-sinks.el
new file mode 100644
index 00000000..6bec9349
--- /dev/null
+++ b/tests/test-video-audio-recording--label-sinks.el
@@ -0,0 +1,111 @@
+;;; test-video-audio-recording--label-sinks.el --- Tests for sink labeling -*- lexical-binding: t; -*-
+
+;;; Commentary:
+;; Unit tests for cj/recording--label-sinks.
+;; Verifies that sink labels include app names for active sinks,
+;; e.g. "JDS Labs [in use] (Firefox)" and sort correctly.
+
+;;; Code:
+
+(require 'ert)
+
+;; Stub dependencies before loading the module
+(defvar cj/custom-keymap (make-sparse-keymap)
+ "Stub keymap for testing.")
+
+(require 'video-audio-recording)
+
+;;; Helpers
+
+(defun test-label-sinks--stub (sink-apps-alist sinks-short-output)
+ "Return a cl-letf binding list that stubs get-sink-apps and sinks short.
+SINK-APPS-ALIST is the return value for `cj/recording--get-sink-apps'.
+SINKS-SHORT-OUTPUT is the raw pactl list sinks short output."
+ ;; We use cl-letf in each test to stub both get-sink-apps and
+ ;; shell-command-to-string (for the sinks short call inside label-sinks).
+ `(((symbol-function 'cj/recording--get-sink-apps)
+ (lambda () ',sink-apps-alist))
+ ((symbol-function 'shell-command-to-string)
+ (lambda (_cmd) ,sinks-short-output))))
+
+;;; Normal Cases
+
+(ert-deftest test-video-audio-recording--label-sinks-normal-appends-app-names ()
+ "Test that active sinks show app names in parentheses."
+ (cl-letf (((symbol-function 'cj/recording--get-sink-apps)
+ (lambda () '(("65" "Firefox"))))
+ ((symbol-function 'shell-command-to-string)
+ (lambda (_cmd) "65\tjds-labs\tmodule\ts16le\tRUNNING\n")))
+ (let ((result (cj/recording--label-sinks
+ '(("jds-labs" "JDS Labs" "RUNNING" "no")))))
+ (should (= 1 (length result)))
+ (should (string-match-p "JDS Labs \\[in use\\] (Firefox)" (caar result))))))
+
+(ert-deftest test-video-audio-recording--label-sinks-normal-multiple-apps ()
+ "Test that multiple apps are comma-separated."
+ (cl-letf (((symbol-function 'cj/recording--get-sink-apps)
+ (lambda () '(("65" "Firefox" "Spotify"))))
+ ((symbol-function 'shell-command-to-string)
+ (lambda (_cmd) "65\tjds-labs\tmodule\ts16le\tRUNNING\n")))
+ (let ((result (cj/recording--label-sinks
+ '(("jds-labs" "JDS Labs" "RUNNING" "no")))))
+ (should (string-match-p "(Firefox, Spotify)" (caar result))))))
+
+(ert-deftest test-video-audio-recording--label-sinks-normal-no-apps ()
+ "Test that sinks without apps have no parenthesized suffix."
+ (cl-letf (((symbol-function 'cj/recording--get-sink-apps)
+ (lambda () nil))
+ ((symbol-function 'shell-command-to-string)
+ (lambda (_cmd) "65\tjds-labs\tmodule\ts16le\tSUSPENDED\n")))
+ (let ((result (cj/recording--label-sinks
+ '(("jds-labs" "JDS Labs" "SUSPENDED" "no")))))
+ (should (string-match-p "JDS Labs \\[available\\]$" (caar result))))))
+
+(ert-deftest test-video-audio-recording--label-sinks-normal-sort-order ()
+ "Test that sinks sort: in use → ready → available → muted."
+ (cl-letf (((symbol-function 'cj/recording--get-sink-apps)
+ (lambda () '(("65" "Firefox"))))
+ ((symbol-function 'shell-command-to-string)
+ (lambda (_cmd)
+ "65\tsink-run\tmodule\ts16le\tRUNNING\n73\tsink-idle\tmodule\ts16le\tIDLE\n80\tsink-sus\tmodule\ts16le\tSUSPENDED\n")))
+ (let ((result (cj/recording--label-sinks
+ '(("sink-sus" "Suspended" "SUSPENDED" "no")
+ ("sink-run" "Running" "RUNNING" "no")
+ ("sink-idle" "Idle" "IDLE" "no")))))
+ (should (equal '("sink-run" "sink-idle" "sink-sus")
+ (mapcar #'cdr result))))))
+
+(ert-deftest test-video-audio-recording--label-sinks-normal-muted-sink ()
+ "Test that muted sinks get [muted] label and no apps shown."
+ (cl-letf (((symbol-function 'cj/recording--get-sink-apps)
+ (lambda () nil))
+ ((symbol-function 'shell-command-to-string)
+ (lambda (_cmd) "65\tmuted-sink\tmodule\ts16le\tSUSPENDED\n")))
+ (let ((result (cj/recording--label-sinks
+ '(("muted-sink" "Muted Sink" "SUSPENDED" "yes")))))
+ (should (string-match-p "\\[muted\\]" (caar result))))))
+
+;;; Boundary Cases
+
+(ert-deftest test-video-audio-recording--label-sinks-boundary-empty ()
+ "Test that empty sink list returns empty alist."
+ (cl-letf (((symbol-function 'cj/recording--get-sink-apps)
+ (lambda () nil))
+ ((symbol-function 'shell-command-to-string)
+ (lambda (_cmd) "")))
+ (should (null (cj/recording--label-sinks nil)))))
+
+(ert-deftest test-video-audio-recording--label-sinks-boundary-sink-not-in-short ()
+ "Test that sink not found in sinks short still gets label (no apps)."
+ (cl-letf (((symbol-function 'cj/recording--get-sink-apps)
+ (lambda () '(("65" "Firefox"))))
+ ((symbol-function 'shell-command-to-string)
+ (lambda (_cmd) "")))
+ (let ((result (cj/recording--label-sinks
+ '(("unknown-sink" "Unknown" "IDLE" "no")))))
+ (should (= 1 (length result)))
+ ;; No app suffix since index lookup returned nil
+ (should (string-match-p "Unknown \\[ready\\]$" (caar result))))))
+
+(provide 'test-video-audio-recording--label-sinks)
+;;; test-video-audio-recording--label-sinks.el ends here