diff options
| -rw-r--r-- | tests/test-music-config-helpers-untested.el | 224 |
1 files changed, 224 insertions, 0 deletions
diff --git a/tests/test-music-config-helpers-untested.el b/tests/test-music-config-helpers-untested.el new file mode 100644 index 00000000..4ba0940a --- /dev/null +++ b/tests/test-music-config-helpers-untested.el @@ -0,0 +1,224 @@ +;;; test-music-config-helpers-untested.el --- Tests for previously-uncovered music-config helpers -*- coding: utf-8; lexical-binding: t; -*- +;; +;; Author: Craig Jennings <c@cjennings.net> +;; +;;; Commentary: +;; The sibling test files cover the bulk of music-config's pure +;; helpers. This file fills the remaining gap: assertion guards, +;; the M3U-file picker, the playlist-file setter, the EMMS lazy +;; setup, and the simpler interactive commands (`playlist-clear', +;; `add-directory-recursive', `find-track-in-playlist'). EMMS +;; primitives are stubbed so the tests don't touch the player. +;; +;;; Code: + +(require 'ert) +(require 'cl-lib) +(require 'testutil-general) + +;; Stub the project-local keymap before music-config loads. +(defvar-keymap cj/custom-keymap :doc "Stub keymap for testing") + +;; Pull EMMS in from elpa so music-config's `require' calls succeed. +(let ((emms-dir (car (file-expand-wildcards + (expand-file-name "elpa/emms-*" user-emacs-directory))))) + (when emms-dir + (add-to-list 'load-path emms-dir))) + +(require 'emms) +(require 'emms-playlist-mode) +(require 'music-config) + +(defun test-mc-untested--setup () + "Per-test setup: clean state + temp dir for any FS fixtures." + (cj/create-test-base-dir) + (let ((buf (get-buffer-create cj/music-playlist-buffer-name))) + (with-current-buffer buf + (emms-playlist-mode) + (setq emms-playlist-buffer-p t) + (setq cj/music-playlist-file nil)) + (setq emms-playlist-buffer buf) + buf)) + +(defun test-mc-untested--teardown () + "Per-test cleanup." + (when-let ((buf (get-buffer cj/music-playlist-buffer-name))) + (with-current-buffer buf + (setq cj/music-playlist-file nil)) + (kill-buffer buf)) + (cj/delete-test-base-dir)) + +;;; ---------- cj/music--assert-m3u-files-exist ---------- + +(ert-deftest test-mc-assert-m3u-files-normal-returns-files () + "Normal: when get-m3u-files returns a non-empty list, return it." + (cl-letf (((symbol-function 'cj/music--get-m3u-files) + (lambda () '(("rock.m3u" . "/tmp/rock.m3u") + ("jazz.m3u" . "/tmp/jazz.m3u"))))) + (should (equal (cj/music--assert-m3u-files-exist) + '(("rock.m3u" . "/tmp/rock.m3u") + ("jazz.m3u" . "/tmp/jazz.m3u")))))) + +(ert-deftest test-mc-assert-m3u-files-error-empty-signals-user-error () + "Error: an empty M3U file list signals user-error." + (cl-letf (((symbol-function 'cj/music--get-m3u-files) (lambda () nil))) + (should-error (cj/music--assert-m3u-files-exist) :type 'user-error))) + +;;; ---------- cj/music--sync-playlist-file ---------- + +(ert-deftest test-mc-sync-playlist-file-sets-buffer-local () + "Normal: sync sets the buffer-local playlist file and resets point to bob. + +The EMMS playlist buffer is read-only via `emms-playlist-mode', so the +test prelude inserts filler with `inhibit-read-only' bound." + (test-mc-untested--setup) + (unwind-protect + (with-current-buffer cj/music-playlist-buffer-name + (let ((inhibit-read-only t)) + (insert "filler\n")) + (goto-char (point-max)) + (cj/music--sync-playlist-file "/tmp/whatever.m3u") + (should (equal cj/music-playlist-file "/tmp/whatever.m3u")) + (should (= (point) (point-min)))) + (test-mc-untested--teardown))) + +;;; ---------- cj/music--select-m3u-file ---------- + +(ert-deftest test-mc-select-m3u-file-normal-returns-chosen-path () + "Normal: pick a file name -> returns its full path." + (cl-letf (((symbol-function 'cj/music--get-m3u-files) + (lambda () '(("rock.m3u" . "/tmp/rock.m3u") + ("jazz.m3u" . "/tmp/jazz.m3u")))) + ((symbol-function 'completing-read) + (lambda (&rest _) "jazz.m3u"))) + (should (equal (cj/music--select-m3u-file "Pick: ") + "/tmp/jazz.m3u")))) + +(ert-deftest test-mc-select-m3u-file-boundary-cancel-returns-nil () + "Boundary: picking \"(Cancel)\" returns nil." + (cl-letf (((symbol-function 'cj/music--get-m3u-files) + (lambda () '(("rock.m3u" . "/tmp/rock.m3u")))) + ((symbol-function 'completing-read) + (lambda (&rest _) "(Cancel)"))) + (should (null (cj/music--select-m3u-file "Pick: "))))) + +(ert-deftest test-mc-select-m3u-file-error-no-files-signals-user-error () + "Error: no M3U files available -> the underlying assertion errors." + (cl-letf (((symbol-function 'cj/music--get-m3u-files) (lambda () nil))) + (should-error (cj/music--select-m3u-file "Pick: ") :type 'user-error))) + +;;; ---------- cj/emms--setup ---------- + +(ert-deftest test-mc-emms-setup-noop-when-already-loaded () + "Normal: when emms is already a feature, setup does not re-require." + (let ((called nil)) + (cl-letf (((symbol-function 'featurep) + (lambda (sym) (eq sym 'emms))) + ((symbol-function 'require) + (lambda (&rest _) (setq called t) t))) + (cj/emms--setup)) + (should-not called))) + +(ert-deftest test-mc-emms-setup-requires-emms-when-absent () + "Boundary: when emms isn't yet loaded, setup requires it." + (let ((required nil)) + (cl-letf (((symbol-function 'featurep) + (lambda (sym) (not (eq sym 'emms)))) + ((symbol-function 'require) + (lambda (feat &rest _) (setq required feat) t))) + (cj/emms--setup)) + (should (eq required 'emms)))) + +;;; ---------- cj/music-playlist-clear ---------- + +(ert-deftest test-mc-playlist-clear-resets-state-and-stops-playback () + "Normal: clear stops emms, empties the playlist, nils the file reference." + (test-mc-untested--setup) + (unwind-protect + (let ((stop-called nil) + (clear-called nil)) + (with-current-buffer cj/music-playlist-buffer-name + (setq cj/music-playlist-file "/tmp/in-flight.m3u")) + (cl-letf (((symbol-function 'emms-stop) + (lambda () (setq stop-called t))) + ((symbol-function 'emms-playlist-clear) + (lambda () (setq clear-called t))) + ((symbol-function 'message) #'ignore)) + (cj/music-playlist-clear)) + (should stop-called) + (should clear-called) + (with-current-buffer cj/music-playlist-buffer-name + (should (null cj/music-playlist-file)))) + (test-mc-untested--teardown))) + +;;; ---------- cj/music-add-directory-recursive ---------- + +(ert-deftest test-mc-add-directory-recursive-normal-calls-emms () + "Normal: with an existing directory, the recursive add reaches emms." + (test-mc-untested--setup) + (unwind-protect + (let* ((dir cj/test-base-dir) + (called-with nil)) + (cl-letf (((symbol-function 'emms-add-directory-tree) + (lambda (d) (setq called-with d))) + ((symbol-function 'message) #'ignore)) + (cj/music-add-directory-recursive dir)) + (should (equal (file-name-as-directory called-with) + (file-name-as-directory dir)))) + (test-mc-untested--teardown))) + +(ert-deftest test-mc-add-directory-recursive-error-not-a-directory () + "Error: a non-directory path signals user-error." + (let ((tmp (make-temp-file "test-mc-"))) + (unwind-protect + (should-error (cj/music-add-directory-recursive tmp) :type 'user-error) + (delete-file tmp)))) + +;;; ---------- cj/music--find-track-in-playlist ---------- + +(ert-deftest test-mc-find-track-in-playlist-finds-match () + "Normal: a track present in the playlist returns its buffer position." + (test-mc-untested--setup) + (unwind-protect + (with-current-buffer cj/music-playlist-buffer-name + (let ((inhibit-read-only t)) + (erase-buffer) + (insert "line-1\n") + (let ((p1 (point))) + (insert "line-2\n") + (let ((p2 (point))) + (insert "line-3\n") + (let ((calls 0)) + (cl-letf (((symbol-function 'emms-playlist-track-at) + (lambda (_) + (cl-incf calls) + ;; Return synthetic tracks per line. + (pcase calls + (1 '((type . file) (name . "/a/one.mp3"))) + (2 '((type . file) (name . "/a/two.mp3"))) + (3 '((type . file) (name . "/a/three.mp3")))))) + ((symbol-function 'emms-track-name) + (lambda (track) (alist-get 'name track)))) + ;; "/a/two.mp3" sits on line 2 (between p1 and p2). + (let ((pos (cj/music--find-track-in-playlist "/a/two.mp3"))) + (should (integerp pos)) + (should (and (>= pos p1) (< pos p2)))))))))) + (test-mc-untested--teardown))) + +(ert-deftest test-mc-find-track-in-playlist-not-found-returns-nil () + "Boundary: a track absent from the playlist returns nil." + (test-mc-untested--setup) + (unwind-protect + (with-current-buffer cj/music-playlist-buffer-name + (let ((inhibit-read-only t)) + (erase-buffer) + (insert "line-1\n")) + (cl-letf (((symbol-function 'emms-playlist-track-at) + (lambda (_) '((type . file) (name . "/x/other.mp3")))) + ((symbol-function 'emms-track-name) + (lambda (track) (alist-get 'name track)))) + (should-not (cj/music--find-track-in-playlist "/never/exists.mp3")))) + (test-mc-untested--teardown))) + +(provide 'test-music-config-helpers-untested) +;;; test-music-config-helpers-untested.el ends here |
