Phil Hagelberg: 1 Add assert-ok helper for linting tests. 3 files changed, 76 insertions(+), 78 deletions(-)
Copy & paste the following snippet into your terminal to import this patchset into git:
curl -s https://lists.sr.ht/~xerool/fennel-ls/patches/55283/mbox | git am -3Learn more about email & git
Also factor out FAITH_TEST flag so you can use it to run an entire module, not just individual tests. --- Makefile | 2 + test/init.fnl | 11 ++-- test/lint.fnl | 141 ++++++++++++++++++++++++-------------------------- 3 files changed, 76 insertions(+), 78 deletions(-) diff --git a/Makefile b/Makefile index 87a539e..6f0a3a4 100644 --- a/Makefile +++ b/Makefile @@ -50,6 +50,8 @@ count: install: $(EXE) mkdir -p $(DESTDIR)$(BINDIR) && cp $< $(DESTDIR)$(BINDIR)/ +# to run one module: make test FAITH_TEST=test.lint +# to run one test: make test FAITH_TEST="test.lint test-unset-var" test: $(EXE) TESTING=1 $(FENNEL) $(FENNELFLAGS) test/init.fnl diff --git a/test/init.fnl b/test/init.fnl index f0267c1..ac90da5 100644 --- a/test/init.fnl +++ b/test/init.fnl @@ -4,10 +4,13 @@ (set debug.getinfo (or fennel.getinfo debug.getinfo)) (set debug.traceback (or fennel.traceback debug.traceback)) -(case (os.getenv "FAITH_TEST") - target (let [(module function) (target:match "([^ ]+) ([^ ]+)")] - (tset package.loaded module {function (. (require module) function)}) - (faith.run [module])) +(case (string.match (or (os.getenv "FAITH_TEST") "") + "([^ ]+) ?([^ ]*)") + (module "") (faith.run [module]) + (module function) (do + (tset package.loaded module + {function (. (require module) function)}) + (faith.run [module])) _ (faith.run [:test.json-rpc :test.string-processing diff --git a/test/lint.fnl b/test/lint.fnl index f627a13..df41437 100644 --- a/test/lint.fnl +++ b/test/lint.fnl @@ -20,9 +20,9 @@ (= e.range.end.character d.range.end.character)))) i))) -(fn check [file-contents expected unexpected] +(fn check [file-contents expected ?unexpected] (let [{: diagnostics} (create-client file-contents)] - (each [_ e (ipairs unexpected)] + (each [_ e (ipairs (or ?unexpected []))] (let [i (find diagnostics e)] (faith.= nil i (.. "Lint matching " (view e) "\n" "from: " (view file-contents) "\n" @@ -36,52 +36,51 @@ :escape-newlines? true}))) (table.remove diagnostics i))))) +(fn assert-ok [file-contents] + (let [{: diagnostics} (create-client file-contents)] + (faith.= nil (next diagnostics) (view diagnostics)))) + (fn test-unused [] (check "(local x 10)" [{:message "unused definition: x" :code 301 :range {:start {:character 7 :line 0} - :end {:character 8 :line 0}}}] []) + :end {:character 8 :line 0}}}]) (check "(fn x [])" [{:message "unused definition: x" :code 301 :range {:start {:character 4 :line 0} - :end {:character 5 :line 0}}}] []) + :end {:character 5 :line 0}}}]) (check "(let [(x y) (values 1 2)] x)" [{:code 301 :range {:start {:character 9 :line 0} - :end {:character 10 :line 0}}}] []) + :end {:character 10 :line 0}}}]) ;; setting a var without reading (check "(var x 1) (set x 2) (set [x] [3])" [{:code 301 :range {:start {:character 5 :line 0} - :end {:character 6 :line 0}}}] []) + :end {:character 6 :line 0}}}]) ;; setting a field without reading is okay - (check "(fn [a b] (set a.x 10) (fn b.f []))" [] [{}]) - (check "(case {:b 1} (where (or {:a x} {:b x})) x)" [] [{}]) + (assert-ok "(fn [a b] (set a.x 10) (fn b.f []))") + (assert-ok "(case {:b 1} (where (or {:a x} {:b x})) x)") - (check "(fn foo [a] nil) (foo)" [{:message "unused definition: a"}] []) - (check "(λ foo [a] nil) (foo)" [{:message "unused definition: a"}] []) - (check "(lambda foo [a] nil) (foo)" [{:message "unused definition: a"}] []) + (check "(fn foo [a] nil) (foo)" [{:message "unused definition: a"}]) + (check "(λ foo [a] nil) (foo)" [{:message "unused definition: a"}]) + (check "(lambda foo [a] nil) (foo)" [{:message "unused definition: a"}]) nil) (fn test-ampersand [] - (check "(let [[x & y] [1 2 3]] - (print x (. y 1) (. y 2)))" - [] [{:message "unused definition: &"} {}]) - (check "(let [{1 x & y} [1 2 3]] - (print x (. y 2) (. y 3)))" - [] [{:message "unused definition: &"} {}]) - (check "(let [[x &as y] [1 2 3]] - (print x (. y 2) (. y 3)))" - [] [{:message "unused definition: &as"} {}]) - (check "(let [{1 x &as y} [1 2 3]] - (print x (. y 2) (. y 3)))" - [] [{:message "unused definition: &as"} {}]) - (check "(fn [x & more] - (print x more))" - [] [{:message "unused definition: &"} {}]) + (assert-ok "(let [[x & y] [1 2 3]] + (print x (. y 1) (. y 2)))") + (assert-ok "(let [{1 x & y} [1 2 3]] + (print x (. y 2) (. y 3)))") + (assert-ok "(let [[x &as y] [1 2 3]] + (print x (. y 2) (. y 3)))") + (assert-ok "(let [{1 x &as y} [1 2 3]] + (print x (. y 2) (. y 3)))") + (assert-ok "(fn [x & more] + (print x more))") nil) (fn test-unknown-module-field [] @@ -120,45 +119,39 @@ [{:message "unnecessary : call: use (x:find)" :code 303 :range {:start {:character 15 :line 0} - :end {:character 29 :line 0}}}] []) + :end {:character 29 :line 0}}}]) ;; no warning from macros - (check "(let [x :haha y :find] (-> x (: y :a)) - (let [x :haha] (-> x (: :find :a))" - [] [{:code 303}]) + (assert-ok "(let [x :haha y :find] (-> x (: y :a)) + (let [x :haha] (-> x (: :find :a))))") ;; no warning when its an expression, or when string has spaces - (check "(let [x :haha] - (: x \"bar baz\") (: x 1) (: x x))" - [] [{:code 303}]) + (assert-ok "(let [x :haha] + (: x \"bar baz\") (: x 1) (: x x))") nil) (fn test-unpack-into-op [] (check "(+ (unpack [1 2 3]))" - [{:code 304}] []) + [{:code 304}]) (check "(.. (table.unpack [\"hello\" \"world\"]))" - [{:code 304 :message #($:find "table.concat")}] []) + [{:code 304 :message #($:find "table.concat")}]) (check "(* (table.unpack [\"hello\" \"world\"]))" - [{:code 304 :message #(not ($:find "table%.concat"))}] - [{:code 304 :message #($:find "table.concat")}]) + [{:code 304 :message #(not ($:find "table%.concat"))}]) ;; only when lexical - (check "(-> [1 2 3] unpack +)" - [] [{:code 304}]) + (assert-ok "(-> [1 2 3] table.unpack +)") nil) (fn test-unset-var [] (check "(var x nil) (print x)" [{:code 305 :range {:start {:character 5 :line 0} - :end {:character 6 :line 0}}}] []) + :end {:character 6 :line 0}}}]) - (check "(var x 1) (set x 2) (print x)" - [] [{}]) - (check "(local x 10) (?. x)" - [] [{:code 305}]) + (assert-ok "(var x 1) (set x 2) (print x)") + (assert-ok "(local x 10) (?. x)") nil) ;; missing test for 306 @@ -167,85 +160,84 @@ (check "(+ 1 2 3 (values 4 5) 6)" [{:code 307 :range {:start {:line 0 :character 9} - :end {:line 0 :character 21}}}] - []) + :end {:line 0 :character 21}}}]) ;; not in a statement, should be covered by another lint - (check "(let [x 10] (values 4 5) x)" - [] [{:code 307}]) - (check "(do (values 4 5) (_G.unpack 6 7) (table.unpack 8 9) 10)" - [] [{:code 307}]) + (assert-ok "(let [x 10] (values 4 5) x)") + (assert-ok "(do (values 4 5) (_G.unpack 6 7) (table.unpack 8 9) 10)") nil) (fn test-unnecessary-tset [] ;; valid, if you're targeting older Fennels - (check "(local [tbl key] [{} :k]) (tset tbl key 249)" [] [{}]) + (assert-ok "(local [tbl key] [{} :k]) (tset tbl key 249)") ;; never a good use of tset (check "(local tbl {}) (tset tbl :key 9)" [{:code 309 :codeDescription "unnecessary-tset" :message "unnecessary tset" :range {:start {:character 15 :line 0} - :end {:character 32 :line 0}}}] [])) + :end {:character 32 :line 0}}}]) + nil) (fn test-unnecessary-do [] ;; multi-arg do - (check "(do (print :x) 11)" [] [{}]) + (assert-ok "(do (print :x) 11)") ;; unnecessary do (check "(do 9)" [{:message "unnecessary do" :code 310 :codeDescription "unnecessary-do-values" :range {:start {:character 0 :line 0} - :end {:character 6 :line 0}}}] []) + :end {:character 6 :line 0}}}]) ;; unnecessary values (check "(print :hey (values :lol))" [{:code 310 :codeDescription "unnecessary-do-values" :message "unnecessary values" :range {:start {:character 12 :line 0} - :end {:character 25 :line 0}}}] - [])) + :end {:character 25 :line 0}}}]) + nil) (fn test-redundant-do [] ;; good do - (check "(case 134 x (do (print :x x) 11))" [] [{}]) + (assert-ok "(case 134 x (do (print :x x) 11))") ;; unnecessary one - (set _G.dbg true) (check "(let [x 29] (do (print 9) x))" [{:code 311 :codeDescription "redundant-do" :message "redundant do" :range {:start {:character 12 :line 0} - :end {:character 28 :line 0}}}] [])) + :end {:character 28 :line 0}}}]) + nil) (fn test-match-should-case [] - ;; OK: most basic pinning - (check "(let [x 99] (match 99 x :yep!))" [] [{}]) + ;; most basic pinning + (assert-ok "(let [x 99] (match 99 x :yep!))") ;; pinning inside where clause - (check "(let [x 99] - (match 98 - y (print y) - (where x (= 0 (math.fmod x 2))) (print x)))" [] [{}]) - ;; OK: nested pinning - (check "(let [x 99] + (assert-ok "(let [x 99] + (match 98 + y (print y) + (where x (= 0 (math.fmod x 2))) (print x)))") + ;; nested pinning + (assert-ok "(let [x 99] (match [{:x 32}] [{: x}] (print x)))" [] [{}]) - ;; OK: values pattern - (check "(let [x 99] - (match 49 - (x _ 9) (print :values-ref)))" [] [{}]) + ;; values pattern + (assert-ok "(let [x 99] + (match 49 + (x _ 9) (print :values-ref)))") ;; warn: basic no pinning (check "(match 91 z (print :yeah2 z))" [{:message "no pinned patterns; use case instead of match" :code 308 :range {:start {:character 1 :line 0} - :end {:character 6 :line 0}}}] []) + :end {:character 6 :line 0}}}]) ;; warn: nested no pinning (check "(match [32] [lol] (print :nested-no-pin lol))" [{:message "no pinned patterns; use case instead of match" :code 308 :range {:start {:character 1 :line 0} - :end {:character 6 :line 0}}}] [])) + :end {:character 6 :line 0}}}]) + nil) ;; TODO lints: ;; duplicate keys in kv table @@ -269,4 +261,5 @@ : test-unset-var : test-match-should-case : test-unpack-into-op - : test-unpack-in-middle} + : test-unpack-in-middle + } -- 2.39.5