aboutsummaryrefslogtreecommitdiff
path: root/tests/test-music-config--radio.el
diff options
context:
space:
mode:
authorCraig Jennings <c@cjennings.net>2026-07-18 14:22:52 -0500
committerCraig Jennings <c@cjennings.net>2026-07-18 14:22:52 -0500
commit97523e6d47964296c9684cb36065dafd0d6c0a1e (patch)
treeb101fcac7a3ca1d8e72a59e8cf7936541bdf8178 /tests/test-music-config--radio.el
parent38ce367d92e66e8a8e91e12af7a935097fb6f00b (diff)
downloaddotemacs-97523e6d47964296c9684cb36065dafd0d6c0a1e.tar.gz
dotemacs-97523e6d47964296c9684cb36065dafd0d6c0a1e.zip
feat(music): tag completion, aligned listings, numbered playlist rows
The radio tag search now completes over popular tags from radio-browser's /json/tags endpoint (station-count order, capped at 500, cached per session), so the prompt offers real tags instead of a blind guess. Free-form input still works, and a failed fetch degrades to plain input. Station listings align into columns: the votes field pads to a fixed width, and each annotation pads out to the widest candidate name. Playlist rows carry a numeric overlay prefix, rebuilt after every change by a debounced after-change hook, so the cursor stays visible on cover-art thumbnails and each row's position is readable. Overlays leave the buffer text to EMMS. Also fixed: the search now trims queries before they hit the API (a trailing space used to reach it as %20 and match nothing).
Diffstat (limited to 'tests/test-music-config--radio.el')
-rw-r--r--tests/test-music-config--radio.el59
1 files changed, 59 insertions, 0 deletions
diff --git a/tests/test-music-config--radio.el b/tests/test-music-config--radio.el
index 3923a599..db917a03 100644
--- a/tests/test-music-config--radio.el
+++ b/tests/test-music-config--radio.el
@@ -134,5 +134,64 @@
(should (= (length cands) 2))
(should (= (length (delete-dups (copy-sequence keys))) 2))))
+;;; --------------------------- query whitespace --------------------------------
+
+(ert-deftest test-music-radio-search-and-play-trims-query ()
+ "Normal: surrounding whitespace on the query is stripped before the search.
+A trailing space in the minibuffer otherwise reaches the API as %20 and
+matches nothing."
+ (let (captured)
+ (cl-letf (((symbol-function 'cj/emms--setup) #'ignore)
+ ((symbol-function 'cj/music-radio--search)
+ (lambda (query _field) (setq captured query) nil)))
+ (should-error (cj/music-radio--search-and-play " jazz " "tag")
+ :type 'user-error))
+ (should (equal captured "jazz"))))
+
+(ert-deftest test-music-radio-search-and-play-whitespace-only-no-search ()
+ "Error: a whitespace-only query errors out before any network search."
+ (let (searched)
+ (cl-letf (((symbol-function 'cj/emms--setup) #'ignore)
+ ((symbol-function 'cj/music-radio--search)
+ (lambda (&rest _) (setq searched t) nil)))
+ (should-error (cj/music-radio--search-and-play " " "tag")
+ :type 'user-error))
+ (should-not searched)))
+
+;;; --------------------------- column alignment --------------------------------
+
+(ert-deftest test-music-radio-format-candidate-votes-column-fixed-width ()
+ "Normal: the votes field pads to a fixed width so the tags column aligns
+across stations with different vote counts."
+ (let* ((low (cj/music-radio--format-candidate
+ '(:codec "MP3" :bitrate 128 :countrycode "US" :votes 7 :tags "jazz")))
+ (high (cj/music-radio--format-candidate
+ '(:codec "MP3" :bitrate 128 :countrycode "US" :votes 174208 :tags "jazz"))))
+ (should (= (string-match "jazz" low) (string-match "jazz" high)))))
+
+(ert-deftest test-music-radio-affixate-aligns-annotation-column ()
+ "Normal: every annotation starts at the same display column regardless of
+how long the station name is."
+ (let* ((candidates '(("Short" . (:codec "MP3" :bitrate 128 :countrycode "US"
+ :votes 5 :tags "a"))
+ ("A Much Longer Station Name" . (:codec "AAC" :bitrate 64
+ :countrycode "FR" :votes 9 :tags "b"))))
+ (triples (cj/music-radio--affixate (mapcar #'car candidates) candidates))
+ (cols (mapcar (lambda (triple)
+ (let ((cand (nth 0 triple))
+ (suffix (nth 2 triple)))
+ (string-match "[^ ]" suffix)
+ (+ (string-width cand) (match-beginning 0))))
+ triples)))
+ (should (= (length triples) 2))
+ (should (apply #'= cols))))
+
+(ert-deftest test-music-radio-affixate-done-sentinel-no-annotation ()
+ "Boundary: the [done] sentinel has no station and gets an empty suffix."
+ (let* ((candidates '(("[done]") ("Station" . (:codec "MP3" :bitrate 128
+ :countrycode "US" :votes 1 :tags "x"))))
+ (triples (cj/music-radio--affixate (mapcar #'car candidates) candidates)))
+ (should (equal (nth 2 (car triples)) ""))))
+
(provide 'test-music-config--radio)
;;; test-music-config--radio.el ends here