5 (defmacro js2-deftest (name buffer-contents &rest body)
6 `(ert-deftest ,(intern (format "js2-%s" name)) ()
9 (insert ,buffer-contents))
13 (fundamental-mode)))))
15 (put 'js2-deftest 'lisp-indent-function 'defun)
17 (defun js2-test-string-to-ast (s)
18 (ert-with-test-buffer (:name 'origin)
21 (should (null js2-mode-buffer-dirty-p))
24 (defun* js2-test-parse-string (code-string &key syntax-error errors-count
26 (let ((ast (js2-test-string-to-ast code-string)))
28 (let ((errors (js2-ast-root-errors ast)))
29 (should (= (or errors-count 1) (length errors)))
30 (destructuring-bind (_ pos len) (first errors)
31 (should (string= syntax-error (substring code-string
32 (1- pos) (+ pos len -1))))))
33 (should (= 0 (length (js2-ast-root-errors ast))))
34 (ert-with-test-buffer (:name 'copy)
36 (skip-chars-backward " \t\n")
37 (should (string= (or reference code-string)
38 (buffer-substring-no-properties
39 (point-min) (point))))))))
41 (defmacro* js2-deftest-parse (name code-string &key bind syntax-error errors-count
43 "Parse CODE-STRING. If SYNTAX-ERROR is nil, print syntax tree
44 with `js2-print-tree' and assert the result to be equal to
45 REFERENCE, if present, or the original string. If SYNTAX-ERROR
46 is passed, expect syntax error highlighting substring equal to
47 SYNTAX-ERROR value. BIND defines bindings to apply them around
49 `(ert-deftest ,(intern (format "js2-%s" name)) ()
50 (let ,(append bind '((js2-basic-offset 2)))
51 (js2-test-parse-string ,code-string
52 :syntax-error ,syntax-error
53 :errors-count ,errors-count
54 :reference ,reference))))
56 (put 'js2-deftest-parse 'lisp-indent-function 'defun)
60 (js2-deftest-parse variable-assignment
63 (js2-deftest-parse empty-object-literal
66 (js2-deftest-parse empty-array-literal
69 (js2-deftest-parse comma-after-regexp
72 (js2-deftest-parse return-statement
73 "function foo() {\n return 2;\n}")
75 (js2-deftest-parse function-statement
76 "function foo() {\n}")
78 (js2-deftest-parse function-expression-statements-are-verboten
79 "function() {}" :syntax-error "function")
81 (js2-deftest-parse member-expr-as-function-name
82 "function a.b.c[2](x, y) {\n}"
83 :bind ((js2-allow-member-expr-as-function-name t)))
85 (js2-deftest-parse named-function-expression
86 "a = function b() {};")
88 ;;; Callers of `js2-valid-prop-name-token'
90 (js2-deftest-parse parse-property-access-when-not-keyword
93 (js2-deftest-parse parse-property-access-when-keyword
95 :bind ((js2-allow-keywords-as-property-names t)))
97 (js2-deftest-parse parse-property-access-when-keyword-no-xml
99 :bind ((js2-allow-keywords-as-property-names t)
100 (js2-compiler-xml-available nil)))
102 (js2-deftest-parse parse-object-literal-when-not-keyword
105 (js2-deftest-parse parse-object-literal-when-keyword
107 :bind ((js2-allow-keywords-as-property-names t)))
109 ;;; 'of' contextual keyword
111 (js2-deftest-parse parse-array-comp-loop-with-of
112 "[a for (a of [])];")
114 (js2-deftest-parse parse-for-of
115 "for (var a of []) {\n}")
117 (js2-deftest-parse of-can-be-var-name
120 (js2-deftest-parse of-can-be-function-name
121 "function of() {\n}")
123 ;;; Destructuring binding
125 (js2-deftest-parse destruct-in-declaration
126 "var {a, b} = {a: 1, b: 2};")
128 (js2-deftest-parse destruct-in-arguments
129 "function f({a: aa, b: bb}) {\n}")
131 (js2-deftest-parse destruct-in-array-comp-loop
132 "[a + b for ([a, b] in [[0, 1], [1, 2]])];")
134 (js2-deftest-parse destruct-in-catch-clause
135 "try {\n} catch ({a, b}) {\n a + b;\n}")
137 ;;; Function parameters
139 (js2-deftest-parse function-with-default-parameters
140 "function foo(a = 1, b = a + 1) {\n}")
142 (js2-deftest-parse function-with-no-default-after-default
143 "function foo(a = 1, b) {\n}"
146 (js2-deftest-parse function-with-destruct-after-default
147 "function foo(a = 1, {b, c}) {\n}"
150 (js2-deftest-parse function-with-rest-parameter
151 "function foo(a, b, ...rest) {\n}")
153 (js2-deftest-parse function-with-param-after-rest-parameter
154 "function foo(a, ...b, rest) {\n}"
155 :syntax-error "rest")
157 (js2-deftest-parse function-with-destruct-after-rest-parameter
158 "function foo(a, ...b, {}) {\n}"
161 (js2-deftest-parse function-with-rest-after-default-parameter
162 "function foo(a = 1, ...rest) {\n}")
166 (js2-deftest-parse arrow-function-with-empty-args-and-no-curlies
167 "() => false;" :reference "() => {false};")
169 (js2-deftest-parse arrow-function-with-args-and-curlies
170 "(a, b = 1, ...c) => { c;\n};")
172 (js2-deftest-parse parenless-arrow-function-prohibits-rest
173 "...b => {b + 1;};" :syntax-error "b" :errors-count 2)
175 (js2-deftest-parse parenless-arrow-function-prohibits-destructuring
176 "[a, b] => {a + b;};" :syntax-error "]" :errors-count 5)
178 ;;; Automatic semicolon insertion
180 (js2-deftest-parse no-auto-semi-insertion-after-if
183 (js2-deftest-parse auto-semi-insertion-after-function
184 "a = function() {}" :reference "a = function() {};")
186 (js2-deftest-parse auto-semi-one-variable-per-line
187 "x\ny" :reference "x;\ny;")
191 (js2-deftest-parse labeled-stmt-node
192 "foo:\nbar:\n x = y + 1;")
194 (js2-deftest no-label-node-inside-expr "x = y:"
195 (let (js2-parse-interruptable-p)
197 (let ((assignment (js2-expr-stmt-node-expr (car (js2-scope-kids js2-mode-ast)))))
198 (should (js2-name-node-p (js2-assign-node-right assignment)))))
202 (js2-deftest ast-symbol-table-includes-fn-node "function foo() {}"
204 (let ((entry (js2-scope-get-symbol js2-mode-ast 'foo)))
205 (should (= (js2-symbol-decl-type entry) js2-FUNCTION))
206 (should (equal (js2-symbol-name entry) "foo"))
207 (should (js2-function-node-p (js2-symbol-ast-node entry)))))
209 (js2-deftest fn-symbol-table-includes-nested-fn "function foo() {
214 (let* ((scope (js2-node-at-point (point-min)))
215 (fn-entry (js2-scope-get-symbol scope 'bar))
216 (var-entry (js2-scope-get-symbol scope 'x)))
217 (should (= (js2-symbol-decl-type fn-entry) js2-FUNCTION))
218 (should (js2-function-node-p (js2-symbol-ast-node fn-entry)))
219 (should (= (js2-symbol-decl-type var-entry) js2-VAR))
220 (should (js2-name-node-p (js2-symbol-ast-node var-entry)))))
224 (js2-deftest get-token "(1+1)"
226 (should (eq js2-LP (js2-next-token)))
227 (should (eq js2-NUMBER (js2-next-token)))
228 (should (eq js2-ADD (js2-next-token)))
229 (should (eq js2-NUMBER (js2-next-token)))
230 (should (eq js2-RP (js2-next-token))))
232 (js2-deftest unget-token "()"
234 (should (eq js2-LP (js2-next-token)))
236 (should (eq js2-LP (js2-next-token)))
237 (should (eq js2-RP (js2-next-token))))
239 (js2-deftest get-token-or-eol "x\n++;"
241 (should (eq js2-NAME (js2-next-token)))
242 (should (eq js2-EOL (js2-peek-token-or-eol)))
243 (should (eq js2-INC (js2-next-token)))
244 (should (eq js2-SEMI (js2-peek-token-or-eol))))
246 (js2-deftest unget-token-over-eol-and-comment "x\n//abc\ny"
248 (should (eq js2-NAME (js2-next-token)))
249 (should (eq js2-NAME (js2-next-token)))
250 (should (equal "y" (js2-current-token-string)))
252 (should (eq js2-NAME (js2-current-token-type)))
253 (should (equal "x" (js2-current-token-string))))
255 (js2-deftest ts-seek "(1+2)"
257 (should (eq js2-LP (js2-next-token)))
258 (should (eq js2-NUMBER (js2-next-token)))
260 (let ((state (make-js2-ts-state)))
261 (should (eq js2-NUMBER (js2-next-token)))
262 (should (eq js2-ADD (js2-next-token)))
264 (should (eq 1 js2-ti-lookahead))
265 (should (eq js2-NUMBER (js2-next-token)))
266 (should (eq 1 (js2-token-number
267 (js2-current-token))))))
271 (js2-deftest for-node-with-error-len "for "
273 (let ((node (js2-node-at-point (point-min))))
274 (should (= (js2-node-len (js2-node-parent node)) 4))))
276 (js2-deftest function-without-parens-error "function b {}"
277 ;; Should finish the parse.