1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
|
;;; test-music-config--radio-tags.el --- Tests for radio-browser tag pre-population -*- coding: utf-8; lexical-binding: t; -*-
;;
;; Author: Craig Jennings <c@cjennings.net>
;;
;;; Commentary:
;; The tag-search prompt completes over the popular tags fetched from
;; radio-browser's /json/tags endpoint (cached per session). These tests cover
;; the pure pieces: the endpoint URL, the parse (trim + drop-empty + dedupe,
;; since the source data is user-generated and dirty), and the session cache.
;; The network GET is mocked at the boundary.
;;; Code:
(require 'ert)
(require 'cl-lib)
(defvar cj/custom-keymap (make-sparse-keymap)
"Stub keymap for testing.")
(require 'music-config)
(defconst test-music-radio-tags--fixture
(concat "[{\"name\":\"jazz \",\"stationcount\":300},"
"{\"name\":\" jazz\",\"stationcount\":5},"
"{\"name\":\"\",\"stationcount\":2},"
"{\"name\":\"rock\",\"stationcount\":100}]")
"A recorded /json/tags response with whitespace, empty, and duplicate names.")
;;; Normal Cases
(ert-deftest test-music-radio-tags-url-shape ()
"Normal: the tags URL targets /json/tags ordered by station count with the limit."
(let* ((cj/music-radio-tag-limit 500)
(u (cj/music-radio--tags-url "de1.api.radio-browser.info")))
(should (string-match-p "/json/tags" u))
(should (string-match-p "order=stationcount" u))
(should (string-match-p "limit=500" u))))
(ert-deftest test-music-radio-parse-tags-trims-dedupes-drops-empty ()
"Normal: tag names come back trimmed, deduped, and without empties."
(should (equal (cj/music-radio--parse-tags test-music-radio-tags--fixture)
'("jazz" "rock"))))
(ert-deftest test-music-radio-available-tags-caches-per-session ()
"Normal: the fetch runs once; later calls serve the cache."
(let ((cj/music-radio--tags-cache nil)
(calls 0))
(cl-letf (((symbol-function 'cj/music-radio--http-get)
(lambda (_url) (cl-incf calls) test-music-radio-tags--fixture)))
(should (equal (cj/music-radio--available-tags) '("jazz" "rock")))
(should (equal (cj/music-radio--available-tags) '("jazz" "rock")))
(should (= calls 1)))))
;;; Boundary Cases
(ert-deftest test-music-radio-parse-tags-empty-array ()
"Boundary: an empty tag array parses to nil."
(should-not (cj/music-radio--parse-tags "[]")))
;;; Error Cases
(ert-deftest test-music-radio-available-tags-fetch-failure-returns-nil-and-retries ()
"Error: a failed fetch yields nil, leaves the cache empty, and retries next call."
(let ((cj/music-radio--tags-cache nil)
(calls 0))
(cl-letf (((symbol-function 'cj/music-radio--http-get)
(lambda (_url) (cl-incf calls) nil)))
(should-not (cj/music-radio--available-tags))
(should-not cj/music-radio--tags-cache)
(should-not (cj/music-radio--available-tags))
(should (= calls 2)))))
(ert-deftest test-music-radio-parse-tags-malformed-user-errors ()
"Error: a non-JSON body signals user-error, not a raw parse error."
(should-error (cj/music-radio--parse-tags "<html>502</html>")
:type 'user-error))
(provide 'test-music-config--radio-tags)
;;; test-music-config--radio-tags.el ends here
|