summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--modules/custom-ordering.el96
-rw-r--r--tests/test-custom-ordering-number-lines.el181
-rw-r--r--tests/test-custom-ordering-reverse-lines.el131
-rw-r--r--tests/test-custom-ordering-toggle-quotes.el155
4 files changed, 562 insertions, 1 deletions
diff --git a/modules/custom-ordering.el b/modules/custom-ordering.el
index 034216d6..abc9995a 100644
--- a/modules/custom-ordering.el
+++ b/modules/custom-ordering.el
@@ -4,9 +4,14 @@
;; Text transformation and sorting utilities for reformatting data structures.
;;
-;; Main functions:
+;; Array/list formatting:
;; - arrayify/listify - convert lines to comma-separated format (with/without quotes, brackets)
;; - unarrayify - convert arrays back to separate lines
+;;
+;; Line manipulation:
+;; - toggle-quotes - swap double ↔ single quotes
+;; - reverse-lines - reverse line order
+;; - number-lines - add line numbers with custom format (supports zero-padding)
;; - alphabetize-region - sort words alphabetically
;; - comma-separated-text-to-lines - split CSV text into lines
;;
@@ -15,6 +20,8 @@
;;; Code:
+(require 'cl-lib)
+
;; cj/custom-keymap defined in keybindings.el
(eval-when-compile (defvar cj/custom-keymap))
(defvar cj/ordering-map)
@@ -89,6 +96,90 @@ START and END identify the active region."
(delete-region start end)
(insert insertion)))
+(defun cj/--toggle-quotes (start end)
+ "Internal implementation: Toggle between double and single quotes.
+START and END define the region to operate on.
+Swaps all double quotes with single quotes and vice versa.
+Returns the transformed string without modifying the buffer."
+ (when (> start end)
+ (error "Invalid region: start (%d) is greater than end (%d)" start end))
+ (let ((text (buffer-substring start end)))
+ (with-temp-buffer
+ (insert text)
+ (goto-char (point-min))
+ ;; Use a placeholder to avoid double-swapping
+ (while (search-forward "\"" nil t)
+ (replace-match "\001" nil t))
+ (goto-char (point-min))
+ (while (search-forward "'" nil t)
+ (replace-match "\"" nil t))
+ (goto-char (point-min))
+ (while (search-forward "\001" nil t)
+ (replace-match "'" nil t))
+ (buffer-string))))
+
+(defun cj/toggle-quotes (start end)
+ "Toggle between double and single quotes in region between START and END.
+START and END identify the active region."
+ (interactive "r")
+ (let ((insertion (cj/--toggle-quotes start end)))
+ (delete-region start end)
+ (insert insertion)))
+
+(defun cj/--reverse-lines (start end)
+ "Internal implementation: Reverse the order of lines in region.
+START and END define the region to operate on.
+Returns the transformed string without modifying the buffer."
+ (when (> start end)
+ (error "Invalid region: start (%d) is greater than end (%d)" start end))
+ (let ((lines (split-string (buffer-substring start end) "\n")))
+ (mapconcat #'identity (nreverse lines) "\n")))
+
+(defun cj/reverse-lines (start end)
+ "Reverse the order of lines in region between START and END.
+START and END identify the active region."
+ (interactive "r")
+ (let ((insertion (cj/--reverse-lines start end)))
+ (delete-region start end)
+ (insert insertion)))
+
+(defun cj/--number-lines (start end format-string zero-pad)
+ "Internal implementation: Number lines in region with custom format.
+START and END define the region to operate on.
+FORMAT-STRING is the format for each line, with N as placeholder for number.
+ Example: \"N. \" produces \"1. \", \"2. \", etc.
+ Example: \"[N] \" produces \"[1] \", \"[2] \", etc.
+ZERO-PAD when non-nil pads numbers with zeros for alignment.
+ Example with 100 lines: \"001\", \"002\", ..., \"100\".
+Returns the transformed string without modifying the buffer."
+ (when (> start end)
+ (error "Invalid region: start (%d) is greater than end (%d)" start end))
+ (let* ((lines (split-string (buffer-substring start end) "\n"))
+ (line-count (length lines))
+ (width (if zero-pad (length (number-to-string line-count)) 1))
+ (format-spec (if zero-pad (format "%%0%dd" width) "%d")))
+ (mapconcat
+ (lambda (pair)
+ (let* ((num (car pair))
+ (line (cdr pair))
+ (num-str (format format-spec num)))
+ (concat (replace-regexp-in-string "N" num-str format-string) line)))
+ (cl-loop for line in lines
+ for i from 1
+ collect (cons i line))
+ "\n")))
+
+(defun cj/number-lines (start end format-string zero-pad)
+ "Number lines in region between START and END with custom format.
+START and END identify the active region.
+FORMAT-STRING is the format for each line, with N as placeholder for number.
+ Example: \"N. \" produces \"1. \", \"2. \", etc.
+ZERO-PAD when non-nil (prefix argument) pads numbers with zeros."
+ (interactive "r\nMFormat string (use N for number): \nP")
+ (let ((insertion (cj/--number-lines start end format-string zero-pad)))
+ (delete-region start end)
+ (insert insertion)))
+
(defun cj/--alphabetize-region (start end)
"Internal implementation: Alphabetize words in region.
START and END define the region to operate on.
@@ -154,6 +245,9 @@ Returns the transformed string without modifying the buffer."
"l" #'cj/listify
"j" #'cj/arrayify-json
"p" #'cj/arrayify-python
+ "q" #'cj/toggle-quotes
+ "r" #'cj/reverse-lines
+ "n" #'cj/number-lines
"A" #'cj/alphabetize-region
"L" #'cj/comma-separated-text-to-lines)
diff --git a/tests/test-custom-ordering-number-lines.el b/tests/test-custom-ordering-number-lines.el
new file mode 100644
index 00000000..adda84f0
--- /dev/null
+++ b/tests/test-custom-ordering-number-lines.el
@@ -0,0 +1,181 @@
+;;; test-custom-ordering-number-lines.el --- Tests for cj/--number-lines -*- lexical-binding: t; -*-
+
+;;; Commentary:
+;; Tests for the cj/--number-lines function from custom-ordering.el
+;;
+;; This function numbers lines in a region with a customizable format.
+;; The format string uses "N" as a placeholder for the line number.
+;; Optionally supports zero-padding for alignment.
+;;
+;; Examples:
+;; Input: "apple\nbanana\ncherry"
+;; Format: "N. "
+;; Output: "1. apple\n2. banana\n3. cherry"
+;;
+;; With zero-padding and 100 lines:
+;; "001. line\n002. line\n...\n100. line"
+;;
+;; We test the NON-INTERACTIVE implementation (cj/--number-lines) to avoid
+;; mocking user input. This follows our testing best practice of
+;; separating business logic from UI interaction.
+
+;;; Code:
+
+(require 'ert)
+(require 'testutil-general)
+(require 'cl-lib)
+
+;; Add modules directory to load path
+(add-to-list 'load-path (expand-file-name "modules" user-emacs-directory))
+
+;; Stub dependencies before loading the module
+(defvar cj/custom-keymap (make-sparse-keymap)
+ "Stub keymap for testing.")
+
+;; Now load the actual production module
+(require 'custom-ordering)
+
+;;; Test Helpers
+
+(defun test-number-lines (input-text format-string zero-pad)
+ "Test cj/--number-lines on INPUT-TEXT.
+FORMAT-STRING is the format template.
+ZERO-PAD enables zero-padding.
+Returns the transformed string."
+ (with-temp-buffer
+ (insert input-text)
+ (cj/--number-lines (point-min) (point-max) format-string zero-pad)))
+
+;;; Normal Cases - Standard Format "N. "
+
+(ert-deftest test-number-lines-standard-format ()
+ "Should number lines with standard format."
+ (let ((result (test-number-lines "apple\nbanana\ncherry" "N. " nil)))
+ (should (string= result "1. apple\n2. banana\n3. cherry"))))
+
+(ert-deftest test-number-lines-two-lines ()
+ "Should number two lines."
+ (let ((result (test-number-lines "first\nsecond" "N. " nil)))
+ (should (string= result "1. first\n2. second"))))
+
+(ert-deftest test-number-lines-single-line ()
+ "Should number single line."
+ (let ((result (test-number-lines "only" "N. " nil)))
+ (should (string= result "1. only"))))
+
+;;; Normal Cases - Alternative Formats
+
+(ert-deftest test-number-lines-parenthesis-format ()
+ "Should number with parenthesis format."
+ (let ((result (test-number-lines "a\nb\nc" "N) " nil)))
+ (should (string= result "1) a\n2) b\n3) c"))))
+
+(ert-deftest test-number-lines-bracket-format ()
+ "Should number with bracket format."
+ (let ((result (test-number-lines "x\ny\nz" "[N] " nil)))
+ (should (string= result "[1] x\n[2] y\n[3] z"))))
+
+(ert-deftest test-number-lines-no-space-format ()
+ "Should number without space."
+ (let ((result (test-number-lines "a\nb" "N." nil)))
+ (should (string= result "1.a\n2.b"))))
+
+(ert-deftest test-number-lines-custom-format ()
+ "Should number with custom format."
+ (let ((result (test-number-lines "foo\nbar" "Item N: " nil)))
+ (should (string= result "Item 1: foo\nItem 2: bar"))))
+
+;;; Normal Cases - Zero Padding
+
+(ert-deftest test-number-lines-zero-pad-single-digit ()
+ "Should not pad when max is single digit."
+ (let ((result (test-number-lines "a\nb\nc" "N. " t)))
+ (should (string= result "1. a\n2. b\n3. c"))))
+
+(ert-deftest test-number-lines-zero-pad-double-digit ()
+ "Should pad to 2 digits when max is 10-99."
+ (let* ((lines (make-list 12 "line"))
+ (input (mapconcat #'identity lines "\n"))
+ (result (test-number-lines input "N. " t))
+ (result-lines (split-string result "\n")))
+ (should (string-prefix-p "01. " (nth 0 result-lines)))
+ (should (string-prefix-p "09. " (nth 8 result-lines)))
+ (should (string-prefix-p "10. " (nth 9 result-lines)))
+ (should (string-prefix-p "12. " (nth 11 result-lines)))))
+
+(ert-deftest test-number-lines-zero-pad-triple-digit ()
+ "Should pad to 3 digits when max is 100+."
+ (let* ((lines (make-list 105 "x"))
+ (input (mapconcat #'identity lines "\n"))
+ (result (test-number-lines input "N. " t))
+ (result-lines (split-string result "\n")))
+ (should (string-prefix-p "001. " (nth 0 result-lines)))
+ (should (string-prefix-p "099. " (nth 98 result-lines)))
+ (should (string-prefix-p "100. " (nth 99 result-lines)))
+ (should (string-prefix-p "105. " (nth 104 result-lines)))))
+
+;;; Boundary Cases
+
+(ert-deftest test-number-lines-empty-string ()
+ "Should handle empty string."
+ (let ((result (test-number-lines "" "N. " nil)))
+ (should (string= result "1. "))))
+
+(ert-deftest test-number-lines-empty-lines ()
+ "Should number empty lines."
+ (let ((result (test-number-lines "\n\n" "N. " nil)))
+ (should (string= result "1. \n2. \n3. "))))
+
+(ert-deftest test-number-lines-with-existing-numbers ()
+ "Should number lines that already have content."
+ (let ((result (test-number-lines "1. old\n2. old" "N. " nil)))
+ (should (string= result "1. 1. old\n2. 2. old"))))
+
+(ert-deftest test-number-lines-multiple-N-in-format ()
+ "Should replace multiple N occurrences."
+ (let ((result (test-number-lines "a\nb" "N-N. " nil)))
+ (should (string= result "1-1. a\n2-2. b"))))
+
+(ert-deftest test-number-lines-long-content ()
+ "Should number lines with long content."
+ (let* ((long-line (make-string 100 ?x))
+ (input (format "%s\n%s" long-line long-line))
+ (result (test-number-lines input "N. " nil)))
+ (should (string-prefix-p "1. " result))
+ (should (string-match "2\\. " result))))
+
+;;; Normal Cases - No Zero Padding vs Zero Padding
+
+(ert-deftest test-number-lines-comparison-no-pad-vs-pad ()
+ "Should show difference between no padding and padding."
+ (let* ((input "a\nb\nc\nd\ne\nf\ng\nh\ni\nj")
+ (no-pad (test-number-lines input "N. " nil))
+ (with-pad (test-number-lines input "N. " t))
+ (no-pad-lines (split-string no-pad "\n"))
+ (with-pad-lines (split-string with-pad "\n")))
+ ;; Without padding: "1. ", "10. "
+ (should (string-prefix-p "1. " (nth 0 no-pad-lines)))
+ (should (string-prefix-p "10. " (nth 9 no-pad-lines)))
+ ;; With padding: "01. ", "10. "
+ (should (string-prefix-p "01. " (nth 0 with-pad-lines)))
+ (should (string-prefix-p "10. " (nth 9 with-pad-lines)))))
+
+;;; Error Cases
+
+(ert-deftest test-number-lines-start-greater-than-end ()
+ "Should error when start > end."
+ (should-error
+ (with-temp-buffer
+ (insert "line1\nline2")
+ (cj/--number-lines (point-max) (point-min) "N. " nil))
+ :type 'error))
+
+(ert-deftest test-number-lines-empty-region ()
+ "Should handle empty region (start == end)."
+ (with-temp-buffer
+ (insert "line1\nline2")
+ (let ((pos (/ (+ (point-min) (point-max)) 2)))
+ (should (string= "1. " (cj/--number-lines pos pos "N. " nil))))))
+
+(provide 'test-custom-ordering-number-lines)
+;;; test-custom-ordering-number-lines.el ends here
diff --git a/tests/test-custom-ordering-reverse-lines.el b/tests/test-custom-ordering-reverse-lines.el
new file mode 100644
index 00000000..3c71362d
--- /dev/null
+++ b/tests/test-custom-ordering-reverse-lines.el
@@ -0,0 +1,131 @@
+;;; test-custom-ordering-reverse-lines.el --- Tests for cj/--reverse-lines -*- lexical-binding: t; -*-
+
+;;; Commentary:
+;; Tests for the cj/--reverse-lines function from custom-ordering.el
+;;
+;; This function reverses the order of lines in a region.
+;; The first line becomes last, last becomes first, etc.
+;;
+;; Examples:
+;; Input: "line1\nline2\nline3"
+;; Output: "line3\nline2\nline1"
+;;
+;; We test the NON-INTERACTIVE implementation (cj/--reverse-lines) to avoid
+;; mocking region selection. This follows our testing best practice of
+;; separating business logic from UI interaction.
+
+;;; Code:
+
+(require 'ert)
+(require 'testutil-general)
+
+;; Add modules directory to load path
+(add-to-list 'load-path (expand-file-name "modules" user-emacs-directory))
+
+;; Stub dependencies before loading the module
+(defvar cj/custom-keymap (make-sparse-keymap)
+ "Stub keymap for testing.")
+
+;; Now load the actual production module
+(require 'custom-ordering)
+
+;;; Test Helpers
+
+(defun test-reverse-lines (input-text)
+ "Test cj/--reverse-lines on INPUT-TEXT.
+Returns the transformed string."
+ (with-temp-buffer
+ (insert input-text)
+ (cj/--reverse-lines (point-min) (point-max))))
+
+;;; Normal Cases
+
+(ert-deftest test-reverse-lines-three-lines ()
+ "Should reverse three lines."
+ (let ((result (test-reverse-lines "line1\nline2\nline3")))
+ (should (string= result "line3\nline2\nline1"))))
+
+(ert-deftest test-reverse-lines-two-lines ()
+ "Should reverse two lines."
+ (let ((result (test-reverse-lines "first\nsecond")))
+ (should (string= result "second\nfirst"))))
+
+(ert-deftest test-reverse-lines-many-lines ()
+ "Should reverse many lines."
+ (let ((result (test-reverse-lines "a\nb\nc\nd\ne")))
+ (should (string= result "e\nd\nc\nb\na"))))
+
+(ert-deftest test-reverse-lines-with-content ()
+ "Should reverse lines with actual content."
+ (let ((result (test-reverse-lines "apple banana\ncherry date\negg fig")))
+ (should (string= result "egg fig\ncherry date\napple banana"))))
+
+(ert-deftest test-reverse-lines-bidirectional ()
+ "Should reverse back and forth correctly."
+ (let* ((original "line1\nline2\nline3")
+ (reversed (test-reverse-lines original))
+ (back (test-reverse-lines reversed)))
+ (should (string= reversed "line3\nline2\nline1"))
+ (should (string= back original))))
+
+;;; Boundary Cases
+
+(ert-deftest test-reverse-lines-empty-string ()
+ "Should handle empty string."
+ (let ((result (test-reverse-lines "")))
+ (should (string= result ""))))
+
+(ert-deftest test-reverse-lines-single-line ()
+ "Should handle single line (no change)."
+ (let ((result (test-reverse-lines "single line")))
+ (should (string= result "single line"))))
+
+(ert-deftest test-reverse-lines-empty-lines ()
+ "Should reverse including empty lines."
+ (let ((result (test-reverse-lines "a\n\nb")))
+ (should (string= result "b\n\na"))))
+
+(ert-deftest test-reverse-lines-trailing-newline ()
+ "Should handle trailing newline."
+ (let ((result (test-reverse-lines "line1\nline2\n")))
+ (should (string= result "\nline2\nline1"))))
+
+(ert-deftest test-reverse-lines-only-newlines ()
+ "Should reverse lines that are only newlines."
+ (let ((result (test-reverse-lines "\n\n\n")))
+ (should (string= result "\n\n\n"))))
+
+(ert-deftest test-reverse-lines-numbers ()
+ "Should reverse numbered lines."
+ (let ((result (test-reverse-lines "1\n2\n3\n4\n5")))
+ (should (string= result "5\n4\n3\n2\n1"))))
+
+(ert-deftest test-reverse-lines-very-long ()
+ "Should reverse very long list."
+ (let* ((lines (mapcar #'number-to-string (number-sequence 1 100)))
+ (input (mapconcat #'identity lines "\n"))
+ (result (test-reverse-lines input))
+ (result-lines (split-string result "\n")))
+ (should (= 100 (length result-lines)))
+ (should (string= "100" (car result-lines)))
+ (should (string= "1" (car (last result-lines))))))
+
+;;; Error Cases
+
+(ert-deftest test-reverse-lines-start-greater-than-end ()
+ "Should error when start > end."
+ (should-error
+ (with-temp-buffer
+ (insert "line1\nline2")
+ (cj/--reverse-lines (point-max) (point-min)))
+ :type 'error))
+
+(ert-deftest test-reverse-lines-empty-region ()
+ "Should handle empty region (start == end)."
+ (with-temp-buffer
+ (insert "line1\nline2")
+ (let ((pos (/ (+ (point-min) (point-max)) 2)))
+ (should (string= "" (cj/--reverse-lines pos pos))))))
+
+(provide 'test-custom-ordering-reverse-lines)
+;;; test-custom-ordering-reverse-lines.el ends here
diff --git a/tests/test-custom-ordering-toggle-quotes.el b/tests/test-custom-ordering-toggle-quotes.el
new file mode 100644
index 00000000..e11305ee
--- /dev/null
+++ b/tests/test-custom-ordering-toggle-quotes.el
@@ -0,0 +1,155 @@
+;;; test-custom-ordering-toggle-quotes.el --- Tests for cj/--toggle-quotes -*- lexical-binding: t; -*-
+
+;;; Commentary:
+;; Tests for the cj/--toggle-quotes function from custom-ordering.el
+;;
+;; This function toggles between double quotes and single quotes.
+;; All " become ' and all ' become ".
+;;
+;; Examples:
+;; Input: "apple", "banana"
+;; Output: 'apple', 'banana'
+;;
+;; Input: 'hello', 'world'
+;; Output: "hello", "world"
+;;
+;; We test the NON-INTERACTIVE implementation (cj/--toggle-quotes) to avoid
+;; mocking region selection. This follows our testing best practice of
+;; separating business logic from UI interaction.
+
+;;; Code:
+
+(require 'ert)
+(require 'testutil-general)
+
+;; Add modules directory to load path
+(add-to-list 'load-path (expand-file-name "modules" user-emacs-directory))
+
+;; Stub dependencies before loading the module
+(defvar cj/custom-keymap (make-sparse-keymap)
+ "Stub keymap for testing.")
+
+;; Now load the actual production module
+(require 'custom-ordering)
+
+;;; Test Helpers
+
+(defun test-toggle-quotes (input-text)
+ "Test cj/--toggle-quotes on INPUT-TEXT.
+Returns the transformed string."
+ (with-temp-buffer
+ (insert input-text)
+ (cj/--toggle-quotes (point-min) (point-max))))
+
+;;; Normal Cases - Double to Single
+
+(ert-deftest test-toggle-quotes-double-to-single ()
+ "Should convert double quotes to single quotes."
+ (let ((result (test-toggle-quotes "\"apple\", \"banana\"")))
+ (should (string= result "'apple', 'banana'"))))
+
+(ert-deftest test-toggle-quotes-single-double-quote ()
+ "Should convert single double quote."
+ (let ((result (test-toggle-quotes "\"")))
+ (should (string= result "'"))))
+
+(ert-deftest test-toggle-quotes-multiple-double-quotes ()
+ "Should convert multiple double quotes."
+ (let ((result (test-toggle-quotes "\"hello\" \"world\" \"test\"")))
+ (should (string= result "'hello' 'world' 'test'"))))
+
+;;; Normal Cases - Single to Double
+
+(ert-deftest test-toggle-quotes-single-to-double ()
+ "Should convert single quotes to double quotes."
+ (let ((result (test-toggle-quotes "'apple', 'banana'")))
+ (should (string= result "\"apple\", \"banana\""))))
+
+(ert-deftest test-toggle-quotes-single-single-quote ()
+ "Should convert single single quote."
+ (let ((result (test-toggle-quotes "'")))
+ (should (string= result "\""))))
+
+(ert-deftest test-toggle-quotes-multiple-single-quotes ()
+ "Should convert multiple single quotes."
+ (let ((result (test-toggle-quotes "'hello' 'world' 'test'")))
+ (should (string= result "\"hello\" \"world\" \"test\""))))
+
+;;; Normal Cases - Mixed Quotes
+
+(ert-deftest test-toggle-quotes-mixed ()
+ "Should toggle mixed quotes."
+ (let ((result (test-toggle-quotes "\"double\" 'single'")))
+ (should (string= result "'double' \"single\""))))
+
+(ert-deftest test-toggle-quotes-bidirectional ()
+ "Should toggle back and forth correctly."
+ (let* ((original "\"apple\", \"banana\"")
+ (toggled (test-toggle-quotes original))
+ (back (test-toggle-quotes toggled)))
+ (should (string= toggled "'apple', 'banana'"))
+ (should (string= back original))))
+
+;;; Normal Cases - With Text Content
+
+(ert-deftest test-toggle-quotes-preserves-content ()
+ "Should preserve content while toggling quotes."
+ (let ((result (test-toggle-quotes "var x = \"hello world\";")))
+ (should (string= result "var x = 'hello world';"))))
+
+(ert-deftest test-toggle-quotes-sql-style ()
+ "Should toggle SQL-style quotes."
+ (let ((result (test-toggle-quotes "SELECT * FROM users WHERE name='John'")))
+ (should (string= result "SELECT * FROM users WHERE name=\"John\""))))
+
+(ert-deftest test-toggle-quotes-multiline ()
+ "Should toggle quotes across multiple lines."
+ (let ((result (test-toggle-quotes "\"line1\"\n\"line2\"\n\"line3\"")))
+ (should (string= result "'line1'\n'line2'\n'line3'"))))
+
+;;; Boundary Cases
+
+(ert-deftest test-toggle-quotes-empty-string ()
+ "Should handle empty string."
+ (let ((result (test-toggle-quotes "")))
+ (should (string= result ""))))
+
+(ert-deftest test-toggle-quotes-no-quotes ()
+ "Should handle text with no quotes."
+ (let ((result (test-toggle-quotes "hello world")))
+ (should (string= result "hello world"))))
+
+(ert-deftest test-toggle-quotes-only-double-quotes ()
+ "Should handle string with only double quotes."
+ (let ((result (test-toggle-quotes "\"\"\"\"")))
+ (should (string= result "''''"))))
+
+(ert-deftest test-toggle-quotes-only-single-quotes ()
+ "Should handle string with only single quotes."
+ (let ((result (test-toggle-quotes "''''")))
+ (should (string= result "\"\"\"\""))))
+
+(ert-deftest test-toggle-quotes-adjacent-quotes ()
+ "Should handle adjacent quotes."
+ (let ((result (test-toggle-quotes "\"\"''")))
+ (should (string= result "''\"\""))))
+
+;;; Error Cases
+
+(ert-deftest test-toggle-quotes-start-greater-than-end ()
+ "Should error when start > end."
+ (should-error
+ (with-temp-buffer
+ (insert "\"hello\"")
+ (cj/--toggle-quotes (point-max) (point-min)))
+ :type 'error))
+
+(ert-deftest test-toggle-quotes-empty-region ()
+ "Should handle empty region (start == end)."
+ (with-temp-buffer
+ (insert "\"hello\"")
+ (let ((pos (/ (+ (point-min) (point-max)) 2)))
+ (should (string= "" (cj/--toggle-quotes pos pos))))))
+
+(provide 'test-custom-ordering-toggle-quotes)
+;;; test-custom-ordering-toggle-quotes.el ends here