Skip to content

Commit b21188c

Browse files
authored
Rewrite indentation testing code (#26)
Benefits of new solution: 1. Faster (runs indentation tests in parallel) - On GitHub Actions, the tests now finish >10 seconds quicker, but we will see a greater benefit when I add more indentation tests (hopefully soon). 2. Less code 3. Adding new indentation test cases doesn't require editing the indent_test.clj Clojure file anymore 4. Fixed issues with the test vimrc so tests now work on newer Vim versions (previously they only worked on Vim 8.1 and below) 5. Can now set different config options per-test 6. Indentation tests now all pass on my computer Now we're in a good position to start adding more indentation tests.
1 parent 61c73fc commit b21188c

File tree

22 files changed

+94
-129
lines changed

22 files changed

+94
-129
lines changed

Diff for: .github/workflows/clojure.yml

+1-1
Original file line numberDiff line numberDiff line change
@@ -29,7 +29,7 @@ jobs:
2929
env:
3030
cache-name: cache-m2
3131
with:
32-
path: ~/.m2
32+
path: ~/.m2/repository
3333
key: ${{ runner.os }}-build-${{ env.cache-name }}-${{ hashFiles('**/project.clj') }}
3434
restore-keys: |
3535
${{ runner.os }}-build-${{ env.cache-name }}-

Diff for: clj/.clj-kondo/config.edn

+1-2
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,2 @@
1-
{:lint-as {vim.test/with-tempfile clojure.core/fn
2-
vim.test/defpredicates clojure.core/def
1+
{:lint-as {vim.test/defpredicates clojure.core/def
32
vim.test/defsyntaxtest clojure.core/def}}

Diff for: clj/resources/indent-test-cases/test-basic-sexp-indent.txt renamed to clj/resources/indent-test-cases/basic-sexp/in.clj

-2
Original file line numberDiff line numberDiff line change
@@ -3,5 +3,3 @@
33
tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam,
44
quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo
55
consequat.")
6-
7-
;; vim:ft=clojure:

Diff for: clj/resources/indent-test-cases/basic-sexp/out.clj

+5
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
(ns test-basic-sexp-indent
2+
"Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod
3+
tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam,
4+
quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo
5+
consequat.")

Diff for: clj/resources/indent-test-cases/test-dispatch-macro-indent.in renamed to clj/resources/indent-test-cases/dispach-macro/in.clj

-2
Original file line numberDiff line numberDiff line change
@@ -27,5 +27,3 @@ bar))
2727

2828
(#_(foo bar)
2929
a)
30-
31-
;; vim:ft=clojure:

Diff for: clj/resources/indent-test-cases/test-dispatch-macro-indent.out renamed to clj/resources/indent-test-cases/dispach-macro/out.clj

-2
Original file line numberDiff line numberDiff line change
@@ -27,5 +27,3 @@
2727

2828
(#_(foo bar)
2929
a)
30-
31-
;; vim:ft=clojure:
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
{:indent? false
2+
:extra-cmds ["normal! gg"
3+
"exec \"normal! /α\\<CR>s\\<C-O>Oa\\<Esc>/β\\<CR>s\\<CR>\\<CR>\\<C-H>\\<C-H>\\<C-H>\\<C-H>\\<C-H>\\<C-H>\\<C-H>b\\<CR>c\\<CR>\\<CR>d\\<Esc>\""]}

Diff for: clj/resources/indent-test-cases/test-special-case-indent.in renamed to clj/resources/indent-test-cases/letfn/in.clj

-2
Original file line numberDiff line numberDiff line change
@@ -35,5 +35,3 @@
3535
(six-times [y]
3636
(* (twice y) 3))]
3737
(foo #{:foo :bar :biz} :foo))
38-
39-
;; vim:ft=clojure:

Diff for: clj/resources/indent-test-cases/test-special-case-indent.out renamed to clj/resources/indent-test-cases/letfn/out.clj

-2
Original file line numberDiff line numberDiff line change
@@ -35,5 +35,3 @@
3535
(six-times [y]
3636
(* (twice y) 3))]
3737
(foo #{:foo :bar :biz} :foo))
38-
39-
;; vim:ft=clojure:
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,3 @@
11
(let [Δt (if foo
22
bar
33
baz)])
4-
5-
;; vim:ft=clojure:
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
(let [Δt (if foo
2+
bar
3+
baz)])

Diff for: clj/resources/indent-test-cases/test-reader-conditional-indent.in renamed to clj/resources/indent-test-cases/reader-conditional/in.clj

-2
Original file line numberDiff line numberDiff line change
@@ -9,5 +9,3 @@
99

1010
#?@(:clj [5 6 7 8]
1111
:cljs [1 2 3 4])))
12-
13-
;; vim:ft=clojure:

Diff for: clj/resources/indent-test-cases/test-reader-conditional-indent.out renamed to clj/resources/indent-test-cases/reader-conditional/out.clj

-2
Original file line numberDiff line numberDiff line change
@@ -9,5 +9,3 @@
99

1010
#?@(:clj [5 6 7 8]
1111
:cljs [1 2 3 4])))
12-
13-
;; vim:ft=clojure:
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
{:indent? false
2+
:extra-cmds ["normal! gg"
3+
"exec \"normal! /α\\<CR>:call GetClojureIndent()\\<CR>rxj:call GetClojureIndent()\\<CR>ry\""]}

Diff for: clj/test/vim/helpers.clj

+21
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
(ns vim.helpers
2+
(:require [clojure.edn :as edn]
3+
[clojure.java.shell :as shell])
4+
(:import [java.io File FileReader PushbackReader]))
5+
6+
(defn read-edn-file [^File file]
7+
(when (.exists file)
8+
(with-open [rdr (FileReader. file)]
9+
(edn/read (PushbackReader. rdr)))))
10+
11+
(def ^:dynamic *vim* "vim")
12+
13+
(defn vim!
14+
"Run commands on a file in Vim."
15+
[^File file cmds & {:keys [vimrc], :or {vimrc "NONE"}}]
16+
(let [cmds (mapcat (fn [cmd] ["-c" cmd]) cmds)
17+
args (concat ["--clean" "-N" "-u" (str vimrc)] cmds ["-c" "quitall!" "--" (str file)])
18+
ret (apply shell/sh *vim* args)]
19+
(when (pos? (:exit ret))
20+
(throw (ex-info "Failed to run Vim command"
21+
(assoc ret :vim *vim*, :args args))))))

Diff for: clj/test/vim/indent_test.clj

+39-36
Original file line numberDiff line numberDiff line change
@@ -1,40 +1,43 @@
11
(ns vim.indent-test
2-
(:require [clojure.test :refer [deftest]]
3-
[vim.test :refer [test-indent]]))
2+
(:require [clojure.test :refer [deftest testing is]]
3+
[clojure.string :as str]
4+
[clojure.java.io :as io]
5+
[vim.helpers :as h])
6+
(:import [java.io File]))
47

5-
(deftest test-basic-sexp-indent
6-
(test-indent "works as expected with basic S-expressions"
7-
:in "test-basic-sexp-indent.txt"
8-
:out "test-basic-sexp-indent.txt"))
8+
(defn get-test-cases [^File test-case-dir]
9+
(into []
10+
(comp
11+
(filter #(.isDirectory ^File %))
12+
(map #(.getName ^File %)))
13+
(.listFiles test-case-dir)))
914

10-
(deftest test-multibyte-indent
11-
(test-indent "with multibyte characters"
12-
:in "test-multibyte-indent.txt"
13-
:out "test-multibyte-indent.txt"))
15+
(defn run-test-case [test-case-dir test-case]
16+
(testing (str "Preparation for " test-case)
17+
(let [input (io/file test-case-dir test-case "in.clj")
18+
expected (io/file test-case-dir test-case "out.clj")
19+
actual (File/createTempFile test-case ".clj")
20+
config (let [f (io/file test-case-dir test-case "config.edn")]
21+
(or (h/read-edn-file f) {}))
22+
cmds (concat (:extra-cmds config)
23+
(when (:indent? config true) ["normal! gg=G"])
24+
["write"])]
25+
(io/make-parents actual)
26+
(io/copy input actual)
27+
(h/vim! actual cmds :vimrc (io/file "vim/test-runtime.vim"))
28+
{:test-case test-case
29+
:expected (slurp expected)
30+
:expected-file expected
31+
:actual (slurp actual)
32+
:actual-file actual})))
1433

15-
(deftest test-inherit-indent
16-
(test-indent "is inherited from previous element"
17-
:in "test-inherit-indent.in"
18-
:out "test-inherit-indent.out"
19-
:keys "\\<CR>s\\<C-O>Oa\\<Esc>/β\\<CR>s\\<CR>\\<CR>\\<C-H>\\<C-H>\\<C-H>\\<C-H>\\<C-H>\\<C-H>\\<C-H>b\\<CR>c\\<CR>\\<CR>d\\<Esc>"))
20-
21-
(deftest test-side-effects-in-indentexpr
22-
(test-indent "GetClojureIndent does not move cursor"
23-
:in "test-side-effects-in-indentexpr.in"
24-
:out "test-side-effects-in-indentexpr.out"
25-
:keys "\\<CR>:call GetClojureIndent()\\<CR>rxj:call GetClojureIndent()\\<CR>ry"))
26-
27-
(deftest test-reader-conditional-indent
28-
(test-indent "reader conditionals are indented like maps"
29-
:in "test-reader-conditional-indent.in"
30-
:out "test-reader-conditional-indent.out"))
31-
32-
(deftest test-dispatch-macro-indent
33-
(test-indent "dispatch macro indentation is handled correctly"
34-
:in "test-dispatch-macro-indent.in"
35-
:out "test-dispatch-macro-indent.out"))
36-
37-
(deftest test-special-case-indent
38-
(test-indent "special case indentation is handled correctly"
39-
:in "test-special-case-indent.in"
40-
:out "test-special-case-indent.out"))
34+
;; TODO: do this parallisation more intelligently with agents.
35+
(deftest test-indent
36+
"Runs all indentation tests in parallel"
37+
(let [test-case-dir (io/file (io/resource "indent-test-cases"))
38+
test-cases (get-test-cases test-case-dir)]
39+
(doseq [{:keys [test-case expected expected-file actual actual-file]}
40+
(pmap (partial run-test-case test-case-dir) test-cases)]
41+
(testing test-case
42+
(is (= expected actual)
43+
(format "(not= \"%s\"\n \"%s\")" expected-file actual-file))))))

Diff for: clj/test/vim/test.clj

+16-61
Original file line numberDiff line numberDiff line change
@@ -9,34 +9,25 @@
99
(:import [java.io File]
1010
[java.util List]))
1111

12-
(defmacro with-tempfile
13-
{:requires [File]}
14-
[[tmp-sym] & body]
15-
`(let [~tmp-sym (File/createTempFile "vim-clojure-static" ".tmp")]
16-
(try
17-
~@body
18-
(finally
19-
(.delete ~tmp-sym)))))
20-
2112
(defn vim-exec
2213
"Spit buf into file, then execute vim-expr after Vim loads the file. The
23-
value of vim-expr is evaluated as EDN and returned."
14+
value of vim-expr is evaluated as EDN and returned."
2415
[file buf vim-expr & opts]
25-
(let [{:keys [pre]} (apply hash-map opts)]
26-
(with-tempfile [tmp]
27-
(io/make-parents file)
28-
(spit file buf)
29-
(spit tmp (str "let @x = " vim-expr))
30-
(let [{:keys [exit err]}
31-
(shell/sh "vim" "-N" "-u" "vim/test-runtime.vim"
32-
"-c" (or pre "execute")
33-
"-c" (str "source " tmp)
34-
"-c" (str "call writefile([@x], " (pr-str (str tmp)) ")")
35-
"-c" "quitall!"
36-
file)]
37-
(when-not (zero? exit)
38-
(throw (RuntimeException. ^String err))))
39-
(edn/read-string (slurp tmp)))))
16+
(let [{:keys [pre]} (apply hash-map opts)
17+
tmp (File/createTempFile "vim-clojure-static" ".tmp")]
18+
(io/make-parents file)
19+
(spit file buf)
20+
(spit tmp (str "let @x = " vim-expr))
21+
(let [{:keys [exit err]}
22+
(shell/sh "vim" "-N" "-u" "vim/test-runtime.vim"
23+
"-c" (or pre "execute")
24+
"-c" (str "source " tmp)
25+
"-c" (str "call writefile([@x], " (pr-str (str tmp)) ")")
26+
"-c" "quitall!"
27+
file)]
28+
(when-not (zero? exit)
29+
(throw (RuntimeException. ^String err))))
30+
(edn/read-string (slurp tmp))))
4031

4132
(defn syn-id-names
4233
"Map lines of clojure text to vim synID names at each column as keywords:
@@ -115,42 +106,6 @@
115106
[coll#]
116107
(boolean (some (partial not= ~kw) coll#)))))
117108

118-
(defmacro with-transform-test
119-
"Copy contents of `in` to a tempfile, execute body with tempfile bound to
120-
tmp-sym, then finally compare the transformed contents of the tempfile with
121-
the contents of `out`.
122-
123-
`in` and `out` are urls that will be passed to clojure.java.io/resource."
124-
{:requires [#'test/testing #'with-tempfile]}
125-
[string {:keys [in out]} [tmp-sym :as tmp-binding] & body]
126-
`(test/testing ~string
127-
(with-tempfile ~tmp-binding
128-
(try
129-
(spit ~tmp-sym (slurp (~io/resource (str "indent-test-cases/" ~in))))
130-
~@body
131-
(catch Throwable e#
132-
(spit ~tmp-sym e#))
133-
(finally
134-
(test/is (= (slurp ~tmp-sym)
135-
(slurp (~io/resource (str "indent-test-cases/" ~out))))))))))
136-
137-
(defmacro test-indent
138-
{:requires [#'with-transform-test]}
139-
[string & opts]
140-
(let [{:keys [in out pre keys]} (apply hash-map opts)
141-
test-file (str "tmp/test-indent-" (string/replace string #"[^\w-]" "-") ".clj")
142-
vim-expr (if keys
143-
(format "TypeKeys(%s)" (string/replace (pr-str keys) "\\\\" "\\"))
144-
"IndentFile()")]
145-
`(with-transform-test ~string
146-
{:in ~in :out ~out}
147-
[tmp#]
148-
;; FIXME: Too much file IO
149-
(~io/make-parents ~test-file)
150-
(spit ~test-file "")
151-
(~vim-exec ~test-file (slurp tmp#) ~vim-expr ~@(when pre [:pre pre]))
152-
(spit tmp# (slurp ~test-file)))))
153-
154109
(defn benchmark [n file buf & exprs]
155110
(vim-exec file buf (format "Benchmark(%d, %s)"
156111
n

Diff for: clj/vim/test-runtime.vim

+2-13
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,9 @@
11
" Authors: Sung Pae <[email protected]>
22

3-
execute 'set rtp=' . expand('%:p:h:h:h') . ',$VIMRUNTIME'
3+
let &rtp = getcwd() . '/..,' . &rtp
44
filetype plugin indent on
5-
syntax on
5+
syntax enable
66
set synmaxcol=0 backspace=2
7-
setfiletype clojure
87

98
function! EDN(value)
109
" Changing the quotes may make this valid EDN
@@ -20,16 +19,6 @@ function! ClojureSynIDNames()
2019
return EDN(names)
2120
endfunction
2221

23-
function! TypeKeys(keys)
24-
execute 'normal! ' . a:keys
25-
write
26-
endfunction
27-
28-
function! IndentFile()
29-
normal! gg=G
30-
write
31-
endfunction
32-
3322
function! Time(n, expr)
3423
let start = reltime()
3524
let i = 0

0 commit comments

Comments
 (0)