From b5cae72d8f824f235f351821f7d7052b66bc2513 Mon Sep 17 00:00:00 2001 From: Craig Jennings Date: Mon, 2 Mar 2026 19:46:38 -0600 Subject: feat(json,yaml): add tree-sitter modes, formatting, and jq integration New prog-json module: json-ts-mode with jq formatting (C-; f) and jq-interactively (C-c C-q). Upgraded prog-yaml to yaml-ts-mode with prettier formatting. Both use treesit-auto for grammar management. Includes 18 new tests (10 JSON, 8 YAML), 185/185 passing. --- tests/test-prog-json--json-format-buffer.el | 109 ++++++++++++++++++++++++++++ 1 file changed, 109 insertions(+) create mode 100644 tests/test-prog-json--json-format-buffer.el (limited to 'tests/test-prog-json--json-format-buffer.el') diff --git a/tests/test-prog-json--json-format-buffer.el b/tests/test-prog-json--json-format-buffer.el new file mode 100644 index 00000000..227eafb9 --- /dev/null +++ b/tests/test-prog-json--json-format-buffer.el @@ -0,0 +1,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 -- cgit v1.2.3