Skip to content

Commit e5f5493

Browse files
committed
Add navigation test suite
Cover beginning-of-defun, end-of-defun, forward-sexp, backward-sexp, defun-name extraction, which-func/add-log integration, and outline-minor-mode heading navigation.
1 parent 6fb48d3 commit e5f5493

1 file changed

Lines changed: 255 additions & 0 deletions

File tree

Lines changed: 255 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,255 @@
1+
;;; clojure-ts-mode-navigation-test.el --- Clojure TS Mode: navigation test suite -*- lexical-binding: t; -*-
2+
3+
;; Copyright © 2025-2026 Bozhidar Batsov
4+
5+
;; This file is not part of GNU Emacs.
6+
7+
;; This program is free software; you can redistribute it and/or modify
8+
;; it under the terms of the GNU General Public License as published by
9+
;; the Free Software Foundation, either version 3 of the License, or
10+
;; (at your option) any later version.
11+
12+
;; This program is distributed in the hope that it will be useful,
13+
;; but WITHOUT ANY WARRANTY; without even the implied warranty of
14+
;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15+
;; GNU General Public License for more details.
16+
17+
;; You should have received a copy of the GNU General Public License
18+
;; along with this program. If not, see <https://www.gnu.org/licenses/>.
19+
20+
;;; Commentary:
21+
22+
;; Navigation test suite for clojure-ts-mode: defun movement,
23+
;; forward-sexp, defun-name, and which-func integration.
24+
25+
;;; Code:
26+
27+
(require 'clojure-ts-mode)
28+
(require 'buttercup)
29+
(require 'test-helper "test/test-helper")
30+
31+
;;;; beginning-of-defun / end-of-defun
32+
33+
(describe "navigation: beginning-of-defun"
34+
(before-all
35+
(unless (treesit-language-available-p 'clojure)
36+
(signal 'buttercup-pending "tree-sitter Clojure grammar not available")))
37+
38+
(it "moves to the start of the current defn"
39+
(with-clojure-ts-buffer "(defn foo [x]
40+
(+ x 1))
41+
42+
(defn bar [y]
43+
(* y 2))"
44+
(goto-char (point-max))
45+
(beginning-of-defun)
46+
(expect (looking-at "(defn bar") :to-be-truthy)))
47+
48+
(it "moves past multiple defuns"
49+
(with-clojure-ts-buffer "(defn a [] 1)
50+
51+
(defn b [] 2)
52+
53+
(defn c [] 3)"
54+
(goto-char (point-max))
55+
(beginning-of-defun 2)
56+
(expect (looking-at "(defn b") :to-be-truthy)))
57+
58+
(it "moves across different definition types"
59+
(with-clojure-ts-buffer "(ns test)
60+
61+
(def x 1)
62+
63+
(defn foo [] 42)
64+
65+
(defmacro bar [& body] body)"
66+
(goto-char (point-max))
67+
(beginning-of-defun)
68+
(expect (looking-at "(defmacro bar") :to-be-truthy)
69+
(beginning-of-defun)
70+
(expect (looking-at "(defn foo") :to-be-truthy)
71+
(beginning-of-defun)
72+
(expect (looking-at "(def x") :to-be-truthy))))
73+
74+
(describe "navigation: end-of-defun"
75+
(before-all
76+
(unless (treesit-language-available-p 'clojure)
77+
(signal 'buttercup-pending "tree-sitter Clojure grammar not available")))
78+
79+
(it "moves to the end of the current defn"
80+
(with-clojure-ts-buffer "(defn foo [x]
81+
(+ x 1))
82+
83+
(defn bar [y]
84+
(* y 2))"
85+
(goto-char (point-min))
86+
(end-of-defun)
87+
;; Should be past the first defn
88+
(expect (>= (point)
89+
(save-excursion
90+
(goto-char (point-min))
91+
(search-forward "(+ x 1))")
92+
(point)))
93+
:to-be-truthy)))
94+
95+
(it "moves to the end of a multi-line definition"
96+
(with-clojure-ts-buffer "(defn multi
97+
[x]
98+
(let [a 1
99+
b 2]
100+
(+ a b x)))
101+
102+
(def next-thing 1)"
103+
(goto-char (point-min))
104+
(end-of-defun)
105+
(expect (>= (point)
106+
(save-excursion
107+
(goto-char (point-min))
108+
(search-forward "(+ a b x)))")
109+
(point)))
110+
:to-be-truthy))))
111+
112+
;;;; forward-sexp
113+
114+
(describe "navigation: forward-sexp"
115+
(before-all
116+
(unless (treesit-language-available-p 'clojure)
117+
(signal 'buttercup-pending "tree-sitter Clojure grammar not available")))
118+
119+
(it "moves over a list expression"
120+
(with-clojure-ts-buffer "(+ 1 2)"
121+
(goto-char (point-min))
122+
(forward-sexp)
123+
(expect (eobp) :to-be-truthy)))
124+
125+
(it "moves over a vector"
126+
(with-clojure-ts-buffer "[1 2 3]"
127+
(goto-char (point-min))
128+
(forward-sexp)
129+
(expect (eobp) :to-be-truthy)))
130+
131+
(it "moves over a map"
132+
(with-clojure-ts-buffer "{:a 1 :b 2}"
133+
(goto-char (point-min))
134+
(forward-sexp)
135+
(expect (eobp) :to-be-truthy)))
136+
137+
(it "moves over consecutive top-level forms"
138+
(with-clojure-ts-buffer "(defn a [] 1)
139+
140+
(defn b [] 2)"
141+
(goto-char (point-min))
142+
(forward-sexp)
143+
(expect (looking-at "\n\n(defn b") :to-be-truthy)))
144+
145+
(it "moves backward over a list expression"
146+
(with-clojure-ts-buffer "(+ 1 2)"
147+
(goto-char (point-max))
148+
(backward-sexp)
149+
(expect (bobp) :to-be-truthy)))
150+
151+
(it "moves over elements inside a list"
152+
(with-clojure-ts-buffer "(foo \"hello\" [1 2])"
153+
(goto-char (point-min))
154+
(down-list)
155+
;; Now inside the list, after (
156+
(forward-sexp) ;; over foo
157+
(forward-sexp) ;; over "hello"
158+
(expect (looking-at " \\[1 2\\]") :to-be-truthy))))
159+
160+
;;;; defun-name
161+
162+
(describe "navigation: defun-name"
163+
(before-all
164+
(unless (treesit-language-available-p 'clojure)
165+
(signal 'buttercup-pending "tree-sitter Clojure grammar not available")))
166+
167+
(it "returns the name of a defn"
168+
(with-clojure-ts-buffer "(defn my-function [x] x)"
169+
(let ((node (treesit-node-at 2)))
170+
;; Navigate up to the list node
171+
(while (and node (not (string= (treesit-node-type node) "list_lit")))
172+
(setq node (treesit-node-parent node)))
173+
(expect (clojure-ts--standard-definition-node-name node)
174+
:to-equal "my-function"))))
175+
176+
(it "returns the name of a def"
177+
(with-clojure-ts-buffer "(def my-var 42)"
178+
(let ((node (treesit-node-at 2)))
179+
(while (and node (not (string= (treesit-node-type node) "list_lit")))
180+
(setq node (treesit-node-parent node)))
181+
(expect (clojure-ts--standard-definition-node-name node)
182+
:to-equal "my-var"))))
183+
184+
(it "returns the name of a ns form"
185+
(with-clojure-ts-buffer "(ns my.ns)"
186+
(let ((node (treesit-node-at 2)))
187+
(while (and node (not (string= (treesit-node-type node) "list_lit")))
188+
(setq node (treesit-node-parent node)))
189+
(expect (clojure-ts--standard-definition-node-name node)
190+
:to-equal "my.ns"))))
191+
192+
(it "returns nil for non-definition nodes"
193+
(with-clojure-ts-buffer "[1 2 3]"
194+
(let ((node (treesit-node-at 1)))
195+
(while (and node (not (string= (treesit-node-type node) "vec_lit")))
196+
(setq node (treesit-node-parent node)))
197+
(expect (clojure-ts--standard-definition-node-name node)
198+
:to-be nil)))))
199+
200+
;;;; which-func / add-log integration
201+
202+
(describe "navigation: which-func"
203+
(before-all
204+
(unless (treesit-language-available-p 'clojure)
205+
(signal 'buttercup-pending "tree-sitter Clojure grammar not available")))
206+
207+
(it "returns the current defun name via add-log-current-defun"
208+
(with-clojure-ts-buffer "(defn foo [x]
209+
(+ x 1))
210+
211+
(defn bar [y]
212+
(* y 2))"
213+
(goto-char (point-min))
214+
(search-forward "+ x")
215+
(expect (add-log-current-defun) :to-equal "foo")))
216+
217+
(it "returns the current def name via add-log-current-defun"
218+
(with-clojure-ts-buffer "(def my-config
219+
{:host \"localhost\"
220+
:port 8080})"
221+
(goto-char (point-min))
222+
(search-forward "localhost")
223+
(expect (add-log-current-defun) :to-equal "my-config"))))
224+
225+
;;;; outline integration
226+
227+
(describe "navigation: outline"
228+
(before-all
229+
(unless (treesit-language-available-p 'clojure)
230+
(signal 'buttercup-pending "tree-sitter Clojure grammar not available")))
231+
232+
(it "sets treesit-outline-predicate when outline variant is comments"
233+
(let ((clojure-ts-outline-variant 'comments))
234+
(with-clojure-ts-buffer ";;; heading\n(def x 1)"
235+
(expect treesit-outline-predicate :not :to-be nil))))
236+
237+
(it "outline-next-heading moves to the next heading"
238+
(let ((clojure-ts-outline-variant 'comments))
239+
(with-clojure-ts-buffer ";;; First heading
240+
241+
(defn foo [] 1)
242+
243+
;;; Second heading
244+
245+
(defn bar [] 2)
246+
247+
;;; Third heading"
248+
(goto-char (point-min))
249+
(outline-minor-mode 1)
250+
(outline-next-heading)
251+
(expect (looking-at ";;; Second") :to-be-truthy)
252+
(outline-next-heading)
253+
(expect (looking-at ";;; Third") :to-be-truthy)))))
254+
255+
;;; clojure-ts-mode-navigation-test.el ends here

0 commit comments

Comments
 (0)