summaryrefslogtreecommitdiff
path: root/tests/test-modeline-config-string-cut-middle.el
blob: 40cc0bcccdf7437649d7c90369aeb60c9afe99c8 (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
;;; test-modeline-config-string-cut-middle.el --- Tests for cj/modeline-string-cut-middle -*- lexical-binding: t; -*-

;;; Commentary:
;; Tests for the cj/modeline-string-cut-middle function from modeline-config.el
;;
;; This function truncates a string in the middle with "..." when conditions
;; are met (narrow window, multi-window, string exceeds truncation length).
;; Example: "my-very-long-name.el" → "my-ver...me.el"
;;
;; We mock cj/modeline-string-truncate-p to isolate the string manipulation
;; logic from window state checks.

;;; Code:

(require 'ert)

;; Add modules directory to load path
(add-to-list 'load-path (expand-file-name "modules" user-emacs-directory))

;; Stub dependencies before loading the module
(unless (boundp 'cj/buffer-status-colors)
  (defvar cj/buffer-status-colors
    '((unmodified . "#FFFFFF")
      (modified   . "#00FF00")
      (read-only  . "#FF0000")
      (overwrite  . "#FFD700"))))

(require 'modeline-config)

;;; Test Helpers

(defmacro with-truncation-enabled (&rest body)
  "Execute BODY with truncation forced on.
Mocks `cj/modeline-string-truncate-p' to always return t."
  `(cl-letf (((symbol-function 'cj/modeline-string-truncate-p)
              (lambda (_str) t)))
     ,@body))

(defmacro with-truncation-disabled (&rest body)
  "Execute BODY with truncation forced off.
Mocks `cj/modeline-string-truncate-p' to always return nil."
  `(cl-letf (((symbol-function 'cj/modeline-string-truncate-p)
              (lambda (_str) nil)))
     ,@body))

;;; Normal Cases

(ert-deftest test-modeline-config-string-cut-middle-normal-truncates-long-string ()
  "Should truncate a long string in the middle with '...'."
  (with-truncation-enabled
    (let* ((cj/modeline-string-truncate-length 12)
           (result (cj/modeline-string-cut-middle "my-very-long-name.el")))
      (should (string-match-p "\\.\\.\\." result))
      (should (< (length result) (length "my-very-long-name.el"))))))

(ert-deftest test-modeline-config-string-cut-middle-normal-preserves-start-and-end ()
  "Should keep the beginning and end of the string."
  (with-truncation-enabled
    (let* ((cj/modeline-string-truncate-length 12)
           (result (cj/modeline-string-cut-middle "my-very-long-name.el")))
      (should (string-prefix-p "my-ver" result))
      (should (string-suffix-p "me.el" result)))))

(ert-deftest test-modeline-config-string-cut-middle-normal-result-length ()
  "Truncated result should be truncate-length + 3 (for '...')."
  (with-truncation-enabled
    (let* ((cj/modeline-string-truncate-length 12)
           (result (cj/modeline-string-cut-middle "abcdefghijklmnopqrstuvwxyz")))
      ;; half=6, so 6 chars + "..." + 6 chars = 15
      (should (= (length result) 15)))))

(ert-deftest test-modeline-config-string-cut-middle-normal-no-truncation-when-disabled ()
  "Should return string unchanged when truncation is disabled."
  (with-truncation-disabled
    (let ((result (cj/modeline-string-cut-middle "my-very-long-name.el")))
      (should (string= result "my-very-long-name.el")))))

(ert-deftest test-modeline-config-string-cut-middle-normal-short-string-unchanged ()
  "Short string should pass through unchanged when truncation is disabled."
  (with-truncation-disabled
    (let ((result (cj/modeline-string-cut-middle "init.el")))
      (should (string= result "init.el")))))

;;; Boundary Cases

(ert-deftest test-modeline-config-string-cut-middle-boundary-empty-string ()
  "Empty string should pass through unchanged."
  (with-truncation-disabled
    (let ((result (cj/modeline-string-cut-middle "")))
      (should (string= result "")))))

(ert-deftest test-modeline-config-string-cut-middle-boundary-single-char ()
  "Single character string should pass through unchanged."
  (with-truncation-disabled
    (let ((result (cj/modeline-string-cut-middle "x")))
      (should (string= result "x")))))

(ert-deftest test-modeline-config-string-cut-middle-boundary-odd-truncate-length ()
  "Odd truncation length should floor the half correctly."
  (with-truncation-enabled
    (let* ((cj/modeline-string-truncate-length 11)
           (result (cj/modeline-string-cut-middle "abcdefghijklmnopqrstuvwxyz")))
      ;; half = (floor 11 2) = 5, so 5 + "..." + 5 = 13
      (should (= (length result) 13))
      (should (string= (substring result 0 5) "abcde"))
      (should (string= (substring result -5) "vwxyz")))))

(ert-deftest test-modeline-config-string-cut-middle-boundary-truncate-length-2 ()
  "Minimum practical truncation length of 2."
  (with-truncation-enabled
    (let* ((cj/modeline-string-truncate-length 2)
           (result (cj/modeline-string-cut-middle "abcdefghij")))
      ;; half = (floor 2 2) = 1, so 1 + "..." + 1 = 5
      (should (= (length result) 5))
      (should (string= result "a...j")))))

(ert-deftest test-modeline-config-string-cut-middle-boundary-unicode-filename ()
  "Should handle unicode characters in filename."
  (with-truncation-enabled
    (let* ((cj/modeline-string-truncate-length 10)
           (result (cj/modeline-string-cut-middle "überlangerDateiname.el")))
      (should (string-match-p "\\.\\.\\." result))
      (should (< (length result) (length "überlangerDateiname.el"))))))

(ert-deftest test-modeline-config-string-cut-middle-boundary-dots-in-filename ()
  "Should handle filenames with dots (common in elisp)."
  (with-truncation-enabled
    (let* ((cj/modeline-string-truncate-length 12)
           (result (cj/modeline-string-cut-middle "test-custom-whitespace-collapse.el")))
      (should (string-match-p "\\.\\.\\." result)))))

;;; Error Cases

(ert-deftest test-modeline-config-string-cut-middle-error-nil-input ()
  "Nil input should pass through (truncate-p returns nil for non-strings)."
  (with-truncation-disabled
    (should (null (cj/modeline-string-cut-middle nil)))))

(ert-deftest test-modeline-config-string-cut-middle-error-number-input ()
  "Number input should pass through (truncate-p returns nil for non-strings)."
  (with-truncation-disabled
    (should (= (cj/modeline-string-cut-middle 42) 42))))

(provide 'test-modeline-config-string-cut-middle)
;;; test-modeline-config-string-cut-middle.el ends here