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
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
|
;;; test-cj-window-geometry-lib.el --- Tests for the shared window-geometry helpers -*- lexical-binding: t; -*-
;;; Commentary:
;; Tests the pure helpers in `cj-window-geometry-lib.el':
;; `cj/window-direction', `cj/window-body-size',
;; `cj/cardinal-to-edge-direction', and `cj/window-at-edge'.
;;; Code:
(require 'ert)
(add-to-list 'load-path (expand-file-name "modules" user-emacs-directory))
(require 'cj-window-geometry-lib)
(ert-deftest test-cj-window-geometry--direction-right-split ()
"Normal: 2-window vertical split, right-side window -> right."
(save-window-excursion
(delete-other-windows)
(let ((right (split-window (selected-window) nil 'right)))
(should (eq (cj/window-direction right) 'right)))))
(ert-deftest test-cj-window-geometry--direction-left-split ()
"Normal: 2-window vertical split, left-side window -> left."
(save-window-excursion
(delete-other-windows)
(split-window (selected-window) nil 'right)
(should (eq (cj/window-direction (selected-window)) 'left))))
(ert-deftest test-cj-window-geometry--direction-below-split ()
"Normal: 2-window horizontal split, bottom window -> below."
(save-window-excursion
(delete-other-windows)
(let ((below (split-window (selected-window) nil 'below)))
(should (eq (cj/window-direction below) 'below)))))
(ert-deftest test-cj-window-geometry--direction-above-split ()
"Normal: 2-window horizontal split, top window -> above."
(save-window-excursion
(delete-other-windows)
(split-window (selected-window) nil 'below)
(should (eq (cj/window-direction (selected-window)) 'above))))
(ert-deftest test-cj-window-geometry--direction-single-window-default-right ()
"Boundary: single-window frame, no DEFAULT arg -> 'right."
(save-window-excursion
(delete-other-windows)
(should (eq (cj/window-direction (selected-window)) 'right))))
(ert-deftest test-cj-window-geometry--direction-single-window-with-default ()
"Boundary: single-window frame with DEFAULT='below -> 'below."
(save-window-excursion
(delete-other-windows)
(should (eq (cj/window-direction (selected-window) 'below) 'below))))
(ert-deftest test-cj-window-geometry--body-size-right-returns-body-cols ()
"Normal: right window with direction='right -> body-width in cols."
(save-window-excursion
(delete-other-windows)
(let ((right (split-window (selected-window) nil 'right)))
(should (= (cj/window-body-size right 'right)
(window-body-width right))))))
(ert-deftest test-cj-window-geometry--body-size-below-returns-body-lines ()
"Normal: below window with direction='below -> body-height in lines."
(save-window-excursion
(delete-other-windows)
(let ((below (split-window (selected-window) nil 'below)))
(should (= (cj/window-body-size below 'below)
(window-body-height below))))))
(ert-deftest test-cj-window-geometry--body-size-narrow-window ()
"Normal: deliberately narrow right window -> matching body cols."
(save-window-excursion
(delete-other-windows)
(let* ((frame-w (frame-width))
(target-cols (/ frame-w 4))
(right (split-window (selected-window) (- target-cols) 'right)))
(should (= (cj/window-body-size right 'right)
(window-body-width right))))))
(ert-deftest test-cj-window-geometry--cardinal-to-edge-right ()
"Normal: 'right -> 'rightmost."
(should (eq (cj/cardinal-to-edge-direction 'right) 'rightmost)))
(ert-deftest test-cj-window-geometry--cardinal-to-edge-left ()
"Normal: 'left -> 'leftmost."
(should (eq (cj/cardinal-to-edge-direction 'left) 'leftmost)))
(ert-deftest test-cj-window-geometry--cardinal-to-edge-below ()
"Normal: 'below -> 'bottom."
(should (eq (cj/cardinal-to-edge-direction 'below) 'bottom)))
(ert-deftest test-cj-window-geometry--cardinal-to-edge-above ()
"Normal: 'above -> 'top."
(should (eq (cj/cardinal-to-edge-direction 'above) 'top)))
(ert-deftest test-cj-window-geometry--cardinal-to-edge-unknown-returns-nil ()
"Boundary: an unknown direction symbol -> nil."
(should (null (cj/cardinal-to-edge-direction 'sideways)))
(should (null (cj/cardinal-to-edge-direction nil))))
;; ----------------------------- cj/window-at-edge -----------------------------
(ert-deftest test-cj-window-geometry--at-edge-2col-right-returns-right-column ()
"Normal: 2-column split -> the right column is the right-edge half."
(save-window-excursion
(delete-other-windows)
(let ((right (split-window (selected-window) nil 'right)))
(should (eq (cj/window-at-edge 'right) right)))))
(ert-deftest test-cj-window-geometry--at-edge-2col-left-returns-left-column ()
"Normal: 2-column split -> the left column is the left-edge half."
(save-window-excursion
(delete-other-windows)
(let ((left (selected-window)))
(split-window (selected-window) nil 'right)
(should (eq (cj/window-at-edge 'left) left)))))
(ert-deftest test-cj-window-geometry--at-edge-2row-below-returns-bottom-row ()
"Normal: 2-row split -> the bottom row is the below-edge half."
(save-window-excursion
(delete-other-windows)
(let ((below (split-window (selected-window) nil 'below)))
(should (eq (cj/window-at-edge 'below) below)))))
(ert-deftest test-cj-window-geometry--at-edge-2row-above-returns-top-row ()
"Normal: 2-row split -> the top row is the above-edge half."
(save-window-excursion
(delete-other-windows)
(let ((top (selected-window)))
(split-window (selected-window) nil 'below)
(should (eq (cj/window-at-edge 'above) top)))))
(ert-deftest test-cj-window-geometry--at-edge-single-window-returns-nil ()
"Boundary: a single-window frame has no distinct half -> nil for all sides."
(save-window-excursion
(delete-other-windows)
(dolist (dir '(right left below above))
(should (null (cj/window-at-edge dir))))))
(ert-deftest test-cj-window-geometry--at-edge-axis-mismatch-returns-nil ()
"Boundary: a 2-row split has no right/left column; a 2-col split has no row."
(save-window-excursion
(delete-other-windows)
(split-window (selected-window) nil 'below)
(should (null (cj/window-at-edge 'right)))
(should (null (cj/window-at-edge 'left))))
(save-window-excursion
(delete-other-windows)
(split-window (selected-window) nil 'right)
(should (null (cj/window-at-edge 'below)))
(should (null (cj/window-at-edge 'above)))))
(ert-deftest test-cj-window-geometry--at-edge-nested-right-split-returns-nil ()
"Boundary: when the right side is itself split into rows, no single
window forms the full-height right half -> nil."
(save-window-excursion
(delete-other-windows)
(let ((right (split-window (selected-window) nil 'right)))
(split-window right nil 'below)
(should (null (cj/window-at-edge 'right))))))
(ert-deftest test-cj-window-geometry--at-edge-unknown-direction-returns-nil ()
"Error: an unknown direction symbol -> nil even in a split frame."
(save-window-excursion
(delete-other-windows)
(split-window (selected-window) nil 'right)
(should (null (cj/window-at-edge 'sideways)))
(should (null (cj/window-at-edge nil)))))
;; ----------------------------- window-size-fraction -----------------------------
(ert-deftest test-cj-window-geometry-size-fraction-normal ()
"Normal: a window half the frame returns 0.5."
(should (= (cj/window-size-fraction 20 40) 0.5)))
(ert-deftest test-cj-window-geometry-size-fraction-clamps-high ()
"Boundary: a near-full window is clamped to the 0.95 ceiling."
(should (= (cj/window-size-fraction 40 40) 0.95)))
(ert-deftest test-cj-window-geometry-size-fraction-clamps-low ()
"Boundary: a vanishingly small window is clamped to the 0.05 floor."
(should (= (cj/window-size-fraction 0 40) 0.05)))
(ert-deftest test-cj-window-geometry-size-fraction-custom-bounds ()
"Boundary: explicit MIN-FRAC/MAX-FRAC override the defaults."
(should (= (cj/window-size-fraction 1 40 0.1 0.9) 0.1))
(should (= (cj/window-size-fraction 39 40 0.1 0.9) 0.9)))
(ert-deftest test-cj-window-geometry-size-fraction-zero-frame-nil ()
"Error: a non-positive frame size returns nil (no divide-by-zero)."
(should (null (cj/window-size-fraction 20 0)))
(should (null (cj/window-size-fraction 20 -5))))
(ert-deftest test-cj-window-geometry-size-fraction-non-number-nil ()
"Error: non-numeric arguments return nil."
(should (null (cj/window-size-fraction nil 40)))
(should (null (cj/window-size-fraction 20 nil))))
;; ----------------------------- preferred-dock-direction -----------------------------
(ert-deftest test-cj-window-geometry-dock-wide-frame-is-right ()
"Normal: a frame wide enough for both panes to clear 80 docks right."
(should (eq (cj/preferred-dock-direction 200 0.5) 'right)))
(ert-deftest test-cj-window-geometry-dock-narrow-frame-is-below ()
"Normal: an 0.5 split on a 138-col frame leaves ~68-col panes -> below."
(should (eq (cj/preferred-dock-direction 138 0.5) 'below)))
(ert-deftest test-cj-window-geometry-dock-boundary-exactly-min-is-right ()
"Boundary: when the narrower pane lands exactly on 80, dock right."
;; 161 cols, 0.5: panel 80, main 161-80-1 = 80, narrower 80 -> right.
(should (eq (cj/preferred-dock-direction 161 0.5) 'right)))
(ert-deftest test-cj-window-geometry-dock-boundary-one-under-min-is-below ()
"Boundary: one column short of the floor stacks instead."
;; 160 cols, 0.5: panel 80, main 160-80-1 = 79, narrower 79 -> below.
(should (eq (cj/preferred-dock-direction 160 0.5) 'below)))
(ert-deftest test-cj-window-geometry-dock-narrow-panel-fraction-governs ()
"Normal: a slim panel fraction makes the panel the narrower pane."
;; 200 cols, 0.3: panel 60 < 80 -> below, even though main (139) is wide.
(should (eq (cj/preferred-dock-direction 200 0.3) 'below))
;; 300 cols, 0.3: panel 90, main 209 -> right.
(should (eq (cj/preferred-dock-direction 300 0.3) 'right)))
(ert-deftest test-cj-window-geometry-dock-honors-explicit-min-cols ()
"Boundary: an explicit MIN-COLS overrides the default floor."
;; 138 cols, 0.5 -> ~68-col panes: passes a 60-floor, fails the 80-default.
(should (eq (cj/preferred-dock-direction 138 0.5 60) 'right))
(should (eq (cj/preferred-dock-direction 138 0.5 80) 'below)))
(ert-deftest test-cj-window-geometry-dock-honors-custom-default-var ()
"Boundary: the default floor reads `cj/window-dock-min-columns'."
(let ((cj/window-dock-min-columns 30))
(should (eq (cj/preferred-dock-direction 138 0.5) 'right))))
(ert-deftest test-cj-window-geometry-dock-degenerate-input-is-below ()
"Error: non-positive cols or out-of-range fraction stacks (safe fallback)."
(should (eq (cj/preferred-dock-direction 0 0.5) 'below))
(should (eq (cj/preferred-dock-direction -10 0.5) 'below))
(should (eq (cj/preferred-dock-direction 200 0) 'below))
(should (eq (cj/preferred-dock-direction 200 1) 'below))
(should (eq (cj/preferred-dock-direction nil 0.5) 'below))
(should (eq (cj/preferred-dock-direction 200 nil) 'below)))
(provide 'test-cj-window-geometry-lib)
;;; test-cj-window-geometry-lib.el ends here
|