blob: cd83e65b391da555c3f911da37b0fea9d09826ae (
plain)
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
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
|
;;; test-music-config--playlist-open-position.el --- Tests for playlist landing position -*- coding: utf-8; lexical-binding: t; -*-
;;
;; Author: Craig Jennings <c@cjennings.net>
;;
;;; Commentary:
;; Opening the playlist lands point by one rule: the beginning of the playing
;; track's line when a song is playing, else the top of the list. The old
;; behavior keyed off EMMS's selected track, which stays set while stopped, so
;; the playlist opened deep in the list at a stale position. The decision is
;; a pure helper; the window landing (point + upper-third recenter) is tested
;; with recenter stubbed at the display boundary.
;;; Code:
(require 'ert)
(require 'cl-lib)
(defvar cj/custom-keymap (make-sparse-keymap)
"Stub keymap for testing.")
;; Declare the emms vars special HERE too: the module's bare (defvar
;; emms-player-playing-p) marks them special only for code compiled in
;; that file, so a plain `let' in this lexical-binding test file would
;; bind them lexically and the module would never see the value (the
;; scope-shadowing trap from the testing rules).
(defvar emms-player-playing-p)
(defvar emms-playlist-selected-marker)
(require 'music-config)
(defmacro test-music-open-pos--with-buffer (var &rest body)
"Run BODY with VAR bound to a temp 3-track playlist-shaped buffer."
(declare (indent 1))
`(let ((,var (generate-new-buffer " *test-open-pos*")))
(unwind-protect
(progn
(with-current-buffer ,var
(insert "track one\ntrack two\ntrack three\n"))
,@body)
(when (buffer-live-p ,var) (kill-buffer ,var)))))
(defun test-music-open-pos--marker (buffer line offset)
"Marker in BUFFER at LINE (1-based) plus OFFSET chars."
(with-current-buffer buffer
(save-excursion
(goto-char (point-min))
(forward-line (1- line))
(forward-char offset)
(point-marker))))
;;; Normal Cases
(ert-deftest test-music-playlist-open-position-playing-lands-on-playing-line-start ()
"Normal: playing -> the playing track's line, at its beginning (even when
the marker sits mid-line)."
(test-music-open-pos--with-buffer buf
(let ((emms-player-playing-p t)
(emms-playlist-selected-marker (test-music-open-pos--marker buf 2 4)))
(should (= (cj/music--playlist-open-position buf)
(with-current-buffer buf
(save-excursion (goto-char (point-min)) (forward-line 1) (point))))))))
(ert-deftest test-music-playlist-open-position-stopped-lands-at-top ()
"Normal: not playing -> top of the list, even though EMMS still has a
stale selected track."
(test-music-open-pos--with-buffer buf
(let ((emms-player-playing-p nil)
(emms-playlist-selected-marker (test-music-open-pos--marker buf 3 0)))
(should (= (cj/music--playlist-open-position buf) 1)))))
;;; Boundary Cases
(ert-deftest test-music-playlist-open-position-playing-no-marker-lands-at-top ()
"Boundary: playing but no usable marker -> top of the list."
(test-music-open-pos--with-buffer buf
(let ((emms-player-playing-p t)
(emms-playlist-selected-marker nil))
(should (= (cj/music--playlist-open-position buf) 1)))))
(ert-deftest test-music-playlist-open-position-marker-in-other-buffer-lands-at-top ()
"Boundary: a marker pointing into a different buffer is ignored."
(test-music-open-pos--with-buffer buf
(with-temp-buffer
(insert "elsewhere\n")
(let ((emms-player-playing-p t)
(emms-playlist-selected-marker (point-marker)))
(should (= (cj/music--playlist-open-position buf) 1))))))
(ert-deftest test-music-playlist-open-position-empty-buffer ()
"Boundary: an empty playlist lands at point-min without error."
(let ((buf (generate-new-buffer " *test-open-pos-empty*")))
(unwind-protect
(let ((emms-player-playing-p nil)
(emms-playlist-selected-marker nil))
(should (= (cj/music--playlist-open-position buf) 1)))
(kill-buffer buf))))
;;; Landing (window boundary stubbed)
(ert-deftest test-music-playlist-land-point-playing-recenter-upper-third ()
"Normal: landing on a playing row sets window point to its line start and
recenters into the upper third."
(test-music-open-pos--with-buffer buf
(let ((emms-player-playing-p t)
(emms-playlist-selected-marker (test-music-open-pos--marker buf 2 4))
(recenter-arg 'not-called))
(save-window-excursion
(set-window-buffer (selected-window) buf)
(cl-letf (((symbol-function 'recenter)
(lambda (&optional arg &rest _) (setq recenter-arg arg))))
(cj/music--playlist-land-point (selected-window) buf))
(should (= (window-point (selected-window))
(with-current-buffer buf
(save-excursion (goto-char (point-min)) (forward-line 1) (point)))))
(should (integerp recenter-arg))
(should (>= recenter-arg 1))))))
(ert-deftest test-music-playlist-land-point-stopped-top-no-recenter ()
"Normal: landing while stopped puts window point at the top; no recenter."
(test-music-open-pos--with-buffer buf
(let ((emms-player-playing-p nil)
(emms-playlist-selected-marker nil)
(recenter-called nil))
(save-window-excursion
(set-window-buffer (selected-window) buf)
(cl-letf (((symbol-function 'recenter)
(lambda (&rest _) (setq recenter-called t))))
(cj/music--playlist-land-point (selected-window) buf))
(should (= (window-point (selected-window)) 1))
(should-not recenter-called)))))
;;; hl-line in the playlist buffer
(ert-deftest test-music-playlist-ensure-enables-hl-line ()
"Normal: the playlist buffer gets hl-line-mode so the current row is
findable even when the cursor sits on album art."
(let (created)
(cl-letf (((symbol-function 'emms-playlist-mode) #'ignore))
(unwind-protect
(progn
(setq created (cj/music--ensure-playlist-buffer))
(with-current-buffer created
(should hl-line-mode)))
(when (buffer-live-p created) (kill-buffer created))))))
(provide 'test-music-config--playlist-open-position)
;;; test-music-config--playlist-open-position.el ends here
|