aboutsummaryrefslogtreecommitdiff
path: root/tests/test-media-utils.el
diff options
context:
space:
mode:
authorCraig Jennings <c@cjennings.net>2026-05-23 03:42:53 -0500
committerCraig Jennings <c@cjennings.net>2026-05-23 03:42:53 -0500
commit14896ac779ec2b63af4eb7bf1930cf40a6b9988b (patch)
treead5a355c014e650efbb86e09308de5cf89be91e3 /tests/test-media-utils.el
parent9dc7590eaa804bbca3aa924304989dbc26a69af3 (diff)
downloaddotemacs-14896ac779ec2b63af4eb7bf1930cf40a6b9988b.tar.gz
dotemacs-14896ac779ec2b63af4eb7bf1930cf40a6b9988b.zip
test(media-utils): cover player discovery and play/download commands
media-utils.el had no tests. I added eight: cj/get-available-media-players filtering by executable-find, cj/media-play-it building a direct command versus the yt-dlp -g stream-URL wrap (plus the missing-player error), and cj/yt-dl-it erroring when yt-dlp or tsp is absent and queueing through tsp + yt-dlp when both are present. Every external boundary is mocked, so nothing launches.
Diffstat (limited to 'tests/test-media-utils.el')
-rw-r--r--tests/test-media-utils.el105
1 files changed, 105 insertions, 0 deletions
diff --git a/tests/test-media-utils.el b/tests/test-media-utils.el
new file mode 100644
index 00000000..85ee826f
--- /dev/null
+++ b/tests/test-media-utils.el
@@ -0,0 +1,105 @@
+;;; test-media-utils.el --- Tests for media-utils.el -*- lexical-binding: t; -*-
+
+;;; Commentary:
+;; Coverage for the media playback/download helpers. All external boundaries
+;; are mocked: `executable-find' decides which players are present, and
+;; `start-process' / `start-process-shell-command' capture the command instead
+;; of launching anything. The tests assert the integration logic — which
+;; players are reported available, and how the play/download command strings
+;; are built — not that mpv/yt-dlp themselves work.
+
+;;; Code:
+
+(require 'ert)
+(require 'cl-lib)
+(require 'media-utils)
+
+;; media-utils.el declares videos-dir with a bare (defvar videos-dir), which is
+;; only file-local; declare it special here so the let-binding below is dynamic
+;; and reaches cj/yt-dl-it (which reads videos-dir for default-directory).
+(defvar videos-dir nil)
+
+;; ---------------------- cj/get-available-media-players -----------------------
+
+(ert-deftest test-media-get-available-players-filters-by-executable ()
+ "Normal: only players whose :command is on PATH are reported."
+ (cl-letf (((symbol-function 'executable-find)
+ (lambda (cmd) (and (member cmd '("mpv" "vlc")) cmd))))
+ (let ((result (cj/get-available-media-players)))
+ (should (memq 'mpv result))
+ (should (memq 'vlc result))
+ (should-not (memq 'mplayer result)))))
+
+(ert-deftest test-media-get-available-players-none-installed ()
+ "Boundary: with nothing on PATH, the list is empty."
+ (cl-letf (((symbol-function 'executable-find) (lambda (_) nil)))
+ (should-not (cj/get-available-media-players))))
+
+;; ----------------------------- cj/media-play-it ------------------------------
+
+(ert-deftest test-media-play-it-direct-playback-command ()
+ "Normal: a player that needs no stream URL gets a plain command, no yt-dlp."
+ (let (captured cj/default-media-player)
+ (setq cj/default-media-player 'mpv)
+ (cl-letf (((symbol-function 'executable-find) (lambda (_) "/usr/bin/mpv"))
+ ((symbol-function 'start-process-shell-command)
+ (lambda (_n _b cmd) (setq captured cmd) 'proc))
+ ((symbol-function 'set-process-sentinel) #'ignore)
+ ((symbol-function 'message) #'ignore)
+ ((symbol-function 'cj/log-silently) #'ignore))
+ (cj/media-play-it "https://example.com/v"))
+ (should (string-match-p "mpv" captured))
+ (should (string-match-p "example\\.com" captured))
+ (should-not (string-match-p "yt-dlp" captured))))
+
+(ert-deftest test-media-play-it-stream-url-wraps-yt-dlp ()
+ "Normal: a player needing a stream URL wraps the URL in a yt-dlp -g call."
+ (let (captured cj/default-media-player)
+ (setq cj/default-media-player 'vlc)
+ (cl-letf (((symbol-function 'executable-find) (lambda (_) "/usr/bin/vlc"))
+ ((symbol-function 'start-process-shell-command)
+ (lambda (_n _b cmd) (setq captured cmd) 'proc))
+ ((symbol-function 'set-process-sentinel) #'ignore)
+ ((symbol-function 'message) #'ignore)
+ ((symbol-function 'cj/log-silently) #'ignore))
+ (cj/media-play-it "https://example.com/v"))
+ (should (string-match-p "yt-dlp" captured))
+ (should (string-match-p "-g" captured))
+ (should (string-match-p "-f 22/18/best" captured))))
+
+(ert-deftest test-media-play-it-missing-player-errors ()
+ "Error: an unavailable player command signals an error before launching."
+ (let (cj/default-media-player)
+ (setq cj/default-media-player 'mpv)
+ (cl-letf (((symbol-function 'executable-find) (lambda (_) nil)))
+ (should-error (cj/media-play-it "https://example.com/v")))))
+
+;; ------------------------------- cj/yt-dl-it ---------------------------------
+
+(ert-deftest test-media-yt-dl-it-errors-without-yt-dlp ()
+ "Error: a missing yt-dlp aborts the download."
+ (cl-letf (((symbol-function 'executable-find)
+ (lambda (cmd) (unless (equal cmd "yt-dlp") "/usr/bin/x"))))
+ (should-error (cj/yt-dl-it "https://example.com/v"))))
+
+(ert-deftest test-media-yt-dl-it-errors-without-tsp ()
+ "Error: yt-dlp present but tsp missing aborts the download."
+ (cl-letf (((symbol-function 'executable-find)
+ (lambda (cmd) (unless (equal cmd "tsp") "/usr/bin/x"))))
+ (should-error (cj/yt-dl-it "https://example.com/v"))))
+
+(ert-deftest test-media-yt-dl-it-builds-tsp-yt-dlp-process ()
+ "Normal: with both tools present, the URL is queued via tsp + yt-dlp."
+ (let (captured (videos-dir "/tmp/videos"))
+ (cl-letf (((symbol-function 'executable-find) (lambda (_) "/usr/bin/x"))
+ ((symbol-function 'start-process)
+ (lambda (&rest args) (setq captured args) 'proc))
+ ((symbol-function 'set-process-sentinel) #'ignore)
+ ((symbol-function 'message) #'ignore))
+ (cj/yt-dl-it "https://example.com/v"))
+ (should (member "tsp" captured))
+ (should (member "yt-dlp" captured))
+ (should (member "https://example.com/v" captured))))
+
+(provide 'test-media-utils)
+;;; test-media-utils.el ends here