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
|
;;; test-prog-json--json-format-buffer.el --- Tests for cj/json-format-buffer -*- lexical-binding: t -*-
;;; Commentary:
;; Tests for the cj/json-format-buffer function in prog-json.el.
;; Tests both the jq path and the built-in fallback path.
;;; Code:
(require 'ert)
(require 'json)
(require 'prog-json)
;;; Normal Cases — jq path
(ert-deftest test-prog-json--json-format-buffer-normal-formats-object ()
"Compact JSON object is pretty-printed with sorted keys."
(with-temp-buffer
(insert "{\"zebra\":1,\"alpha\":2}")
(cj/json-format-buffer)
(should (string= (string-trim (buffer-string))
"{\n \"alpha\": 2,\n \"zebra\": 1\n}"))))
(ert-deftest test-prog-json--json-format-buffer-normal-formats-array ()
"Compact JSON array is pretty-printed."
(with-temp-buffer
(insert "[1,2,3]")
(cj/json-format-buffer)
(should (string= (string-trim (buffer-string))
"[\n 1,\n 2,\n 3\n]"))))
(ert-deftest test-prog-json--json-format-buffer-normal-nested ()
"Nested JSON is pretty-printed with sorted keys at all levels."
(with-temp-buffer
(insert "{\"b\":{\"d\":1,\"c\":2},\"a\":3}")
(cj/json-format-buffer)
(should (string-match-p "\"a\": 3" (buffer-string)))
(should (string-match-p "\"c\": 2" (buffer-string)))
;; "a" should appear before "b" (sorted)
(should (< (string-match "\"a\"" (buffer-string))
(string-match "\"b\"" (buffer-string))))))
(ert-deftest test-prog-json--json-format-buffer-normal-already-formatted ()
"Already-formatted JSON is unchanged."
(let ((formatted "{\n \"alpha\": 1,\n \"beta\": 2\n}\n"))
(with-temp-buffer
(insert formatted)
(cj/json-format-buffer)
(should (string= (buffer-string) formatted)))))
;;; Boundary Cases
(ert-deftest test-prog-json--json-format-buffer-boundary-empty-object ()
"Empty JSON object formats cleanly."
(with-temp-buffer
(insert "{}")
(cj/json-format-buffer)
(should (string= (string-trim (buffer-string)) "{}"))))
(ert-deftest test-prog-json--json-format-buffer-boundary-empty-array ()
"Empty JSON array formats cleanly."
(with-temp-buffer
(insert "[]")
(cj/json-format-buffer)
(should (string= (string-trim (buffer-string)) "[]"))))
(ert-deftest test-prog-json--json-format-buffer-boundary-scalar-string ()
"Bare JSON string scalar formats without error."
(with-temp-buffer
(insert "\"hello\"")
(cj/json-format-buffer)
(should (string= (string-trim (buffer-string)) "\"hello\""))))
(ert-deftest test-prog-json--json-format-buffer-boundary-unicode ()
"JSON with unicode characters is preserved."
(with-temp-buffer
(insert "{\"emoji\":\"\\u2764\",\"name\":\"café\"}")
(cj/json-format-buffer)
(should (string-match-p "café" (buffer-string)))))
;;; Fallback path — built-in formatter
(ert-deftest test-prog-json--json-format-buffer-fallback-formats-without-jq ()
"Falls back to built-in formatter when jq is not found."
(cl-letf (((symbol-function 'executable-find) (lambda (_) nil)))
(with-temp-buffer
(insert "{\"b\":1,\"a\":2}")
(cj/json-format-buffer)
;; Built-in formatter should pretty-print (key order may vary)
(should (string-match-p "\"a\"" (buffer-string)))
(should (string-match-p "\"b\"" (buffer-string)))
;; Should be multi-line (formatted, not compact)
(should (> (count-lines (point-min) (point-max)) 1)))))
;;; Error Cases
(ert-deftest test-prog-json--json-format-buffer-error-invalid-json ()
"Invalid JSON produces an error, does not silently corrupt buffer."
(with-temp-buffer
(insert "{not valid json}")
(let ((original (buffer-string)))
;; jq will fail on invalid JSON — buffer should not be emptied
(condition-case _err
(cj/json-format-buffer)
(error nil))
;; Buffer should still have content (not wiped)
(should (> (length (buffer-string)) 0)))))
(provide 'test-prog-json--json-format-buffer)
;;; test-prog-json--json-format-buffer.el ends here
|