;;; cider-eldoc-tests.el ;; Copyright © 2012-2018 Tim King, Bozhidar Batsov ;; Author: Tim King ;; Bozhidar Batsov ;; Artur Malabarba ;; This file is NOT part of GNU Emacs. ;; This program is free software: you can redistribute it and/or ;; modify it under the terms of the GNU General Public License as ;; published by the Free Software Foundation, either version 3 of the ;; License, or (at your option) any later version. ;; ;; This program is distributed in the hope that it will be useful, but ;; WITHOUT ANY WARRANTY; without even the implied warranty of ;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU ;; General Public License for more details. ;; ;; You should have received a copy of the GNU General Public License ;; along with this program. If not, see `http://www.gnu.org/licenses/'. ;;; Commentary: ;; This file is part of CIDER ;;; Code: (require 'buttercup) (require 'cider-eldoc) (describe "cider--find-rest-args-position" (it "returns the position of & in the arglist vector" (expect (cider--find-rest-args-position ["fmt" "&" "arg"]) :to-equal 1) (expect (cider--find-rest-args-position ["fmt" "arg"]) :to-equal nil))) (describe "cider--eldoc-format-class-names" :var (class-names) (before-all (setq class-names '("java.lang.String" "java.lang.StringBuffer" "java.lang.CharSequence" "java.lang.StringBuilder"))) (it "returns a formatted class names prefix string" (expect (cider--eldoc-format-class-names '("java.lang.String")) :to-equal "java.lang.String") (expect (cider--eldoc-format-class-names '("A" "B")) :to-equal "(A B)")) (it "respects the value of `cider-eldoc-max-class-names-to-display'" (let ((cider-eldoc-max-class-names-to-display 1)) (expect (cider--eldoc-format-class-names '("A" "B")) :to-equal "(A & 1 more)"))) (describe "when cider-eldoc-ns-function is set to cider-abbreviate-ns" (it "abbreviates the class names" (let ((cider-eldoc-ns-function #'cider-abbreviate-ns)) (expect (cider--eldoc-format-class-names '("java.lang.String")) :to-equal "j.l.String") (expect (cider--eldoc-format-class-names class-names) :to-equal "(j.l.String j.l.StringBuffer j.l.CharSequence & 1 more)")))) (describe "when cider-eldoc-ns-function is set to cider-last-ns-segment" (it "keeps only the last ns segment" (let ((cider-eldoc-ns-function #'cider-last-ns-segment)) (expect (cider--eldoc-format-class-names '("java.lang.String")) :to-equal "String") (expect (cider--eldoc-format-class-names class-names) :to-equal "(String StringBuffer CharSequence & 1 more)"))))) (describe "cider-eldoc-format-thing" :var (class-names) (before-all (setq class-names '("java.lang.String" "java.lang.StringBuffer" "java.lang.CharSequence" "java.lang.StringBuilder"))) (describe "when ns is given and it exists" (it "returns formatted eldoc strings of form ns/symbol" (expect (cider-eldoc-format-thing "clojure.core" "map" "map" 'function) :to-equal "clojure.core/map")) (describe "when the given ns doesnt exist" (it "returns eldoc formatted symbol" (let ((cider-eldoc-ns-function (lambda (ns) nil))) (expect (cider-eldoc-format-thing "non-existent-ns" "" "my-map" 'function) :to-equal "my-map") (expect (cider-eldoc-format-thing "" "" "my-map" 'function) :to-equal "my-map") (expect (cider-eldoc-format-thing class-names "" ".length" 'function) :to-equal ".length"))))) (describe "when the given Java interop form belongs to a single class" (it "returns eldoc formatted thing" (expect (cider-eldoc-format-thing "java.lang.String" "" ".startsWith" 'function) :to-equal "java.lang.String/.startsWith"))) (describe "when the given Java interop form belongs to multiple classes" (it "joins the class list into a string" (expect (cider-eldoc-format-thing class-names "" ".length" 'function) :to-equal "(java.lang.String java.lang.StringBuffer java.lang.CharSequence & 1 more)/.length"))) (describe "when cider-eldoc-ns-function is set to cider-abbreviate-ns" (it "abbreviates the class names" (let ((cider-eldoc-ns-function #'cider-abbreviate-ns)) (expect (cider-eldoc-format-thing "clojure.core" "map" "map" 'function) :to-equal "c.core/map") (expect (cider-eldoc-format-thing '("java.lang.String") "" ".startsWith" 'function) :to-equal "j.l.String/.startsWith") (expect (cider-eldoc-format-thing class-names "" ".length" 'function) :to-equal "(j.l.String j.l.StringBuffer j.l.CharSequence & 1 more)/.length")))) (describe "when cider-eldoc-ns-function is set to cider-last-ns-segment" (it "keeps only the last ns segment" (let ((cider-eldoc-ns-function #'cider-last-ns-segment)) (expect (cider-eldoc-format-thing "clojure.core" "map" "map" 'function) :to-equal "core/map") (expect (cider-eldoc-format-thing '("java.lang.String") "" ".startsWith" 'function) :to-equal "String/.startsWith") (expect (cider-eldoc-format-thing class-names "" ".length" 'function) :to-equal "(String StringBuffer CharSequence & 1 more)/.length"))))) (describe "cider-eldoc-beginning-of-sexp" (it "moves to the beginning of the sexp" (with-temp-buffer (save-excursion (insert "(a (b b) (c c) d)")) (search-forward "d") (cider-eldoc-beginning-of-sexp) (expect (point) :to-equal 2) (expect (char-after) :to-equal ?a))) (it "returns the number sexp the point was over or after" (with-temp-buffer (save-excursion (insert "(a (b b) (c c) d)")) (search-forward "d") (expect (cider-eldoc-beginning-of-sexp) :to-equal 4) (search-forward "a") (expect (cider-eldoc-beginning-of-sexp) :to-equal 1))) (it "returns nil if the maximum number of sexps to skip is exceeded" (with-temp-buffer (save-excursion (insert "(a (b b) (c c) d)")) (search-forward "d") (let ((cider-eldoc-max-num-sexps-to-skip 2)) (expect (cider-eldoc-beginning-of-sexp) :to-equal nil) (expect (point) :to-equal 4))))) (describe "cider--eldoc-remove-dot" (it "removes the \".\" from the namespace qualified symbols" (expect (cider--eldoc-remove-dot "java.lang.String/.length") :to-equal "java.lang.String/length") (expect (cider--eldoc-remove-dot "clojure.string/blank?") :to-equal "clojure.string/blank?") (expect (cider--eldoc-remove-dot ".length") :to-equal ".length") (expect (cider--eldoc-remove-dot "map") :to-equal "map"))) (describe "cider-eldoc-info-in-current-sexp" (before-all (spy-on 'cider-connected-p :and-return-value t) (spy-on 'cider-eldoc-info :and-call-fake (lambda (thing) (pcase thing ("map" '("clojure.core" "map" (("f") ("f" "coll")))) ("inc" '("clojure.core" "inc" (("x")))))))) (it "considers sym-at-point before the sym-at-sexp-beginning" (with-temp-buffer (clojure-mode) (save-excursion (insert "(map inc [1 2 3])")) ;; whem cursor is on map, display its eldoc (search-forward "map") (expect (cider-eldoc-info-in-current-sexp) :to-equal '("eldoc-info" ("clojure.core" "map" (("f") ("f" "coll"))) "thing" "map" "pos" 0)) ;; when cursor is on inc, display its eldoc (search-forward "inc") (expect (cider-eldoc-info-in-current-sexp) :to-equal '("eldoc-info" ("clojure.core" "inc" (("x"))) "thing" "inc" "pos" 0)) ;; eldoc can be nil (search-forward "1") (expect (cider-eldoc-info-in-current-sexp) :to-equal nil) ;; when cursor is at the end of sexp, display eldoc of first symbol (search-forward "]") (expect (cider-eldoc-info-in-current-sexp) :to-equal '("eldoc-info" ("clojure.core" "map" (("f") ("f" "coll"))) "thing" "map" "pos" 2)))) (it "respects the value of `cider-eldoc-display-for-symbol-at-point'" (let ((cider-eldoc-display-for-symbol-at-point nil)) (with-temp-buffer (clojure-mode) (save-excursion (insert "(map inc [1 2 3])")) ;; whem cursor is on map, display its eldoc (search-forward "map") (expect (cider-eldoc-info-in-current-sexp) :to-equal '("eldoc-info" ("clojure.core" "map" (("f") ("f" "coll"))) "thing" "map" "pos" 0)) ;; when cursor is on inc, still display eldoc of map (search-forward "inc") (expect (cider-eldoc-info-in-current-sexp) :to-equal '("eldoc-info" ("clojure.core" "map" (("f") ("f" "coll"))) "thing" "map" "pos" 1)) ;; eldoc can be nil (search-forward "1") (expect (cider-eldoc-info-in-current-sexp) :to-equal nil) ;; when cursor is at the end of sexp, display eldoc of first symbol (search-forward "]") (expect (cider-eldoc-info-in-current-sexp) :to-equal '("eldoc-info" ("clojure.core" "map" (("f") ("f" "coll"))) "thing" "map" "pos" 2))))) (describe "interop forms" (before-all (spy-on 'cider-connected-p :and-return-value t) (spy-on 'cider-eldoc-info :and-call-fake (lambda (thing) (pcase thing (".length" '(("java.lang.String" "java.lang.StringBuffer" "java.lang.CharSequence" "java.lang.StringBuilder") ".length" (("this")))) ("java.lang.String/length" '(("java.lang.String") ".length" (("this")))))))) (describe "when class name is not given before interop forms" (it "includes all possible class names in eldoc" (with-temp-buffer (clojure-mode) (save-excursion (insert "(.length \"abc\")")) (search-forward ".length") (expect (cider-eldoc-info-in-current-sexp) :to-equal '("eldoc-info" (("java.lang.String" "java.lang.StringBuffer" "java.lang.CharSequence" "java.lang.StringBuilder") ".length" (("this"))) "thing" ".length" "pos" 0))))) (describe "when class name is given before interop forms" (it "includes just the given class name in eldoc" (with-temp-buffer (clojure-mode) (save-excursion (insert "(java.lang.String/.length \"abc\")")) (search-forward ".length") (expect (cider-eldoc-info-in-current-sexp) :to-equal '("eldoc-info" (("java.lang.String") ".length" (("this"))) "thing" "java.lang.String/.length" "pos" 0))))))) (describe "cider-eldoc-format-sym-doc" :var (eldoc-echo-area-use-multiline-p) (before-all (spy-on 'window-width :and-return-value 177)) (it "returns the formated eldoc string" (expect (cider-eldoc-format-sym-doc "kubaru.core/plane" "kubaru.core" "Simple docstring.") :to-equal "kubaru.core/plane: Simple docstring.")) (describe "specifications for eldoc-echo-area-use-multiline-p" (describe "when its value is t" (before-each (setq eldoc-echo-area-use-multiline-p t)) (it "does not truncate anything" (expect (cider-eldoc-format-sym-doc "kubaru.core/plane" "kubaru.core" "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa") :to-equal "kubaru.core/plane: aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa") (expect (cider-eldoc-format-sym-doc "kubaru.core/plane" "kubaru.core" "Line 1.\nLine 2.\nLine 3.") :to-equal "kubaru.core/plane: Line 1.\nLine 2.\nLine 3."))) (describe "when its value is truncate-sym-name-if-fit" (before-each (setq eldoc-echo-area-use-multiline-p 'truncate-sym-name-if-fit)) (it "doesn't truncate anything if docstring doesn't fit" (expect (cider-eldoc-format-sym-doc "kubaru.core/plane" "kubaru.core" "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa") :to-equal "kubaru.core/plane: aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa")) (it "truncates the symbol name with cider-abbreviate-ns" (expect (cider-eldoc-format-sym-doc "kubaru.core/plane" "kubaru.core" "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa") :to-equal "k.core/plane: aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa")) (it "truncates the symbol name with cider-last-ns-segment" (expect (cider-eldoc-format-sym-doc "kubaru.core/plane" "kubaru.core" "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa") :to-equal "core/plane: aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa")) (it "leaves out the namespace if the var is in current namespace" (spy-on 'cider-current-ns :and-return-value "kubaru.core") (expect (cider-eldoc-format-sym-doc "kubaru.core/plane" "kubaru.core" "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa") :to-equal "plane: aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa")) ;; this case would be different when it is nil (it "returns as is if truncating the symbol doesn't make it fit" ;; notice that the T is not deleted (expect (cider-eldoc-format-sym-doc "kubaru.core/plane" "kubaru.core" "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaT") :to-equal "kubaru.core/plane: aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaT")) (describe "when the docstring spans multiple lines" (it "returns it as is" (expect (cider-eldoc-format-sym-doc "kubaru.core/plane" "kubaru.core" "Line 1.\nLine 2.\nLine 3.") :to-equal "kubaru.core/plane: Line 1.\nLine 2.\nLine 3.")))) (describe "when its value is nil" (before-each (setq eldoc-echo-area-use-multiline-p nil)) (it "leaves out the symbol name and truncates the docstring" ;; notice the missing T from the result (expect (cider-eldoc-format-sym-doc "kubaru.core/plane" "kubaru.core" "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaT") :to-equal "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa")) (describe "when the docstring spans multiple lines" (it "returns tries to display the var with the first line" (expect (cider-eldoc-format-sym-doc "kubaru.core/plane" "kubaru.core" "Line 1.\nLine 2.\nLine 3.") :to-equal "kubaru.core/plane: Line 1.")))))) (describe "cider--eldoc-add-datomic-query-inputs-to-arglists" (it "adds the datomic query inputs of the query at point to the arglist" (spy-on 'cider-second-sexp-in-list :and-return-value t) (spy-on 'cider-sync-request:eldoc-datomic-query :and-return-value '(dict "inputs" (("$" "?first-name")))) (expect (cider--eldoc-add-datomic-query-inputs-to-arglists '(("query" "&" "inputs"))) :to-equal '(("query" "$" "?first-name")))))