]> code.delx.au - gnu-emacs-elpa/blobdiff - packages/js2-mode/tests/parser.el
Merge commit '0cda39255827f283e7578cd469ae42daad9556a2' from js2-mode
[gnu-emacs-elpa] / packages / js2-mode / tests / parser.el
index dc8c001cac36fb209ee02ff6ba4c0ab51cd9527d..b4aa68337b5a94dfed74a284c0dc968f6bde7fb6 100644 (file)
@@ -1,6 +1,6 @@
 ;;; tests/parser.el --- Some tests for js2-mode.
 
-;; Copyright (C) 2009, 2011-2013  Free Software Foundation, Inc.
+;; Copyright (C) 2009, 2011-2016  Free Software Foundation, Inc.
 
 ;; This file is part of GNU Emacs.
 
              ,@body)
          (fundamental-mode)))))
 
+(defun js2-mode--and-parse ()
+  (js2-mode)
+  (js2-reparse))
+
 (defun js2-test-string-to-ast (s)
   (insert s)
-  (js2-mode)
+  (js2-mode--and-parse)
   (should (null js2-mode-buffer-dirty-p))
   js2-mode-ast)
 
 (cl-defun js2-test-parse-string (code-string &key syntax-error errors-count
-                                             reference)
+                                             reference warnings-count)
   (ert-with-test-buffer (:name 'origin)
     (let ((ast (js2-test-string-to-ast code-string)))
       (if syntax-error
           (skip-chars-backward " \t\n")
           (should (string= (or reference code-string)
                            (buffer-substring-no-properties
-                            (point-min) (point)))))))))
+                            (point-min) (point)))))
+        (when warnings-count
+          (should (= warnings-count
+                     (length (js2-ast-root-warnings ast)))))))))
 
 (cl-defmacro js2-deftest-parse (name code-string &key bind syntax-error errors-count
-                                     reference)
+                                     reference warnings-count)
   "Parse CODE-STRING.  If SYNTAX-ERROR is nil, print syntax tree
 with `js2-print-tree' and assert the result to be equal to
 REFERENCE, if present, or the original string.  If SYNTAX-ERROR
@@ -73,6 +80,7 @@ the test."
        (js2-test-parse-string ,code-string
                               :syntax-error ,syntax-error
                               :errors-count ,errors-count
+                              :warnings-count ,warnings-count
                               :reference ,reference))))
 
 ;;; Basics
@@ -126,6 +134,9 @@ the test."
 (js2-deftest-parse let-expression-statement
   "let (x = 42) x;")
 
+(js2-deftest-parse void
+  "void 0;")
+
 ;;; Callers of `js2-valid-prop-name-token'
 
 (js2-deftest-parse parse-property-access-when-not-keyword
@@ -158,6 +169,12 @@ the test."
 (js2-deftest-parse parse-for-of
   "for (var a of []) {\n}")
 
+(js2-deftest-parse of-can-be-name
+  "void of;")
+
+(js2-deftest-parse of-can-be-object-name
+  "of.z;")
+
 (js2-deftest-parse of-can-be-var-name
   "var of = 3;")
 
@@ -167,16 +184,49 @@ the test."
 ;;; Destructuring binding
 
 (js2-deftest-parse destruct-in-declaration
-  "var {a, b} = {a: 1, b: 2};")
+  "var {a, b} = {a: 1, b: 2};"
+  :warnings-count 0)
 
 (js2-deftest-parse destruct-in-arguments
-  "function f({a: aa, b: bb}) {\n}")
+  "function f({a: aa, b: bb}) {\n}"
+  :warnings-count 0)
 
 (js2-deftest-parse destruct-in-array-comp-loop
   "[a + b for ([a, b] in [[0, 1], [1, 2]])];")
 
 (js2-deftest-parse destruct-in-catch-clause
-  "try {\n} catch ({a, b}) {\n  a + b;\n}")
+  "try {\n} catch ({a, b}) {\n  a + b;\n}"
+  :warnings-count 0)
+
+(js2-deftest-parse destruct-with-initializer-in-object
+  "var {a, b = 2, c} = {};\nb;"
+  :warnings-count 0)
+
+(js2-deftest-parse destruct-with-initializer-in-array
+  "var [a, b = 2, c] = [];\nb;"
+  :warnings-count 0)
+
+(js2-deftest-parse destruct-non-name-target-is-error
+  "var {1=1} = {};" :syntax-error "1" :errors-count 1)
+
+(js2-deftest-parse destruct-with-initializer-in-function-params
+  "function f({a, b = 1, c}, [d, e = 1, f]) {\n}")
+
+(js2-deftest-parse destruct-with-default-in-function-params
+  "function f({x = 1, y = 2} = {}, [x, y] = [1, 2]) {\n}")
+
+(js2-deftest-parse destruct-name-conflict-is-error-in-object
+  "\"use strict\";\nvar {a=1,a=2} = {};" :syntax-error "a" :errors-count 1)
+
+(js2-deftest destruct-name-conflict-is-warning-in-array "\"use strict\";\nvar [a=1,a=2] = [];"
+  (js2-mode--and-parse)
+  (should (equal '("msg.var.redecl" "a")
+                 (caar js2-parsed-warnings))))
+
+(js2-deftest initializer-outside-destruct-is-error "({a=1});"
+  (js2-mode--and-parse)
+  (should (equal "msg.init.no.destruct"
+                 (car (caar js2-parsed-errors)))))
 
 ;;; Object literals
 
@@ -189,6 +239,11 @@ the test."
 (js2-deftest-parse object-literal-method
   "var x = {f(y) {  return y;\n}};")
 
+(js2-deftest object-literal-method-own-name-in-scope "({f(){f();}});"
+  (js2-mode--and-parse)
+  (should (equal '("msg.undeclared.variable" "f")
+                 (caar js2-parsed-warnings))))
+
 (js2-deftest-parse object-literal-getter-method
   "var x = {get f() {  return 42;\n}};")
 
@@ -205,7 +260,7 @@ the test."
   "var x = {get [foo + bar]() {  return 42;\n}};")
 
 (js2-deftest-parse object-literal-generator
-  "var x = {*foo() {  yield 42;\n}};")
+  "var x = {*foo() {  yield* 42;\n}};")
 
 (js2-deftest-parse object-literal-computed-generator-key
   "var x = {*[foo + bar]() {  yield 42;\n}};")
@@ -213,11 +268,11 @@ the test."
 ;;; Function definition
 
 (js2-deftest function-redeclaring-var "var gen = 3; function gen() {};"
-  (js2-mode)
+  (js2-mode--and-parse)
   (should (= (length (js2-ast-root-warnings js2-mode-ast)) 1)))
 
 (js2-deftest function-expression-var-same-name "var gen = function gen() {};"
-  (js2-mode)
+  (js2-mode--and-parse)
   (should (null (js2-ast-root-warnings js2-mode-ast))))
 
 ;;; Function parameters
@@ -290,14 +345,29 @@ the test."
   "'use strict';\nvar number = 0644;"
   :syntax-error "0644" :errors-count 1)
 
+(js2-deftest-parse function-strict-octal-allow-0o
+  "'use strict';\n0o644;" :reference "'use strict';\n420;")
+
 (js2-deftest-parse function-strict-duplicate-keys
   "'use strict';\nvar object = {a: 1, a: 2, 'a': 3, ['a']: 4, 1: 5, '1': 6, [1 + 1]: 7};"
   :syntax-error "a" :errors-count 4) ; "a" has 3 dupes, "1" has 1 dupe.
 
-;; errors... or lackthereof.
+(js2-deftest-parse function-strict-duplicate-getter
+  "'use strict';\nvar a = {get x() {}, get x() {}};"
+  :syntax-error "x" :errors-count 1)
+
+(js2-deftest-parse function-strict-duplicate-setter
+  "'use strict';\nvar a = {set x() {}, set x() {}};"
+  :syntax-error "x" :errors-count 1)
+
+;;; Lack of errors in strict mode
+
 (js2-deftest-parse function-strict-const-scope
   "'use strict';\nconst a;\nif (1) {\n  const a;\n}")
 
+(js2-deftest-parse function-strict-no-getter-setter-duplicate
+  "'use strict';\nvar a = {get x() {}, set x() {}};")
+
 ;;; Spread operator
 
 (js2-deftest-parse spread-in-array-literal
@@ -306,6 +376,26 @@ the test."
 (js2-deftest-parse spread-in-function-call
   "f(3, ...[t(2), t(3)], 42, ...[t(4)]);")
 
+(js2-deftest-parse rest-in-array-destructure
+  "let [x, y, z, ...w] = [1, ...a, ...b, c];")
+
+(js2-deftest-parse comma-after-rest-in-array
+  "let [...x,] = [1, 2, 3];"
+  :syntax-error "," :errors-count 1)
+
+(js2-deftest-parse elem-after-rest-in-array
+  "let [...x, y] = [1, 2, 3];"
+  :syntax-error "," :errors-count 2)
+
+(js2-deftest-parse array-destructure-expr-default
+  "let [[x] = [3]] = y;")
+
+(js2-deftest-parse spread-in-object-literal
+  "f({x, y, ...z});")
+
+(js2-deftest-parse rest-in-object-literal
+  "const {x, y, ...z} = f();")
+
 ;;; Arrow functions
 
 (js2-deftest-parse arrow-function-with-empty-args-and-no-curlies
@@ -344,7 +434,7 @@ the test."
 
 (js2-deftest no-label-node-inside-expr "x = y:"
   (let (js2-parse-interruptable-p)
-    (js2-mode))
+    (js2-mode--and-parse))
   (let ((assignment (js2-expr-stmt-node-expr (car (js2-scope-kids js2-mode-ast)))))
     (should (js2-name-node-p (js2-assign-node-right assignment)))))
 
@@ -387,6 +477,79 @@ the test."
 (js2-deftest-parse parse-generator-comp-with-yield-inside-function-is-ok
   "(for (x of []) function*() {  yield x;\n});")
 
+;;; Async
+
+(js2-deftest-parse async-function-statement
+  "async function foo() {\n}")
+
+(js2-deftest-parse async-function-statement-inside-block
+  "if (true) {\n  async function foo() {\n  }\n}")
+
+(js2-deftest-parse async-function-expression-statements-are-verboten
+  "async function() {}" :syntax-error "(")
+
+(js2-deftest-parse async-named-function-expression
+  "a = async function b() {};")
+
+(js2-deftest-parse async-arrow-function-expression
+  "a = async (b) => {  b;\n};")
+
+(js2-deftest-parse async-method-in-object-literal
+  "({async f() {}});")
+
+(js2-deftest-parse async-method-in-class-body
+  "class C {\n  async foo() {}\n}")
+
+(js2-deftest-parse static-async-method-in-class-body
+  "class C {\n  static async foo() {}\n}")
+
+(js2-deftest-parse async-method-allow-await
+  "({async f() {  await x;\n}});")
+
+;;; Await
+
+(js2-deftest-parse await-is-ok "async function foo() {\n  await bar();\n}")
+
+(js2-deftest-parse await-inside-assignment-is-ok
+                   "async function foo() {\n  var result = await bar();\n}")
+
+(js2-deftest-parse await-inside-array-is-ok
+                   "async function foo() {\n  var results = [await bar(), await baz()];\n}")
+
+(js2-deftest-parse await-inside-non-async-function-is-not-ok
+                   "function foo() {\n  await bar();\n}"
+                   :syntax-error "await")
+
+(js2-deftest-parse await-inside-non-async-arrow-function-is-not-ok
+                   "a = () => {  await bar();\n}"
+                   :syntax-error "await")
+
+;;; 'async' and 'await' are contextual keywords
+
+(js2-deftest-parse async-can-be-name
+  "void async;")
+
+(js2-deftest-parse async-can-be-object-name
+  "async.z;")
+
+(js2-deftest-parse async-can-be-var-name
+  "var async = 3;")
+
+(js2-deftest-parse async-can-be-function-name
+  "function async() {\n}")
+
+(js2-deftest-parse await-can-be-name
+  "void await;")
+
+(js2-deftest-parse await-can-be-object-name
+  "await.z;")
+
+(js2-deftest-parse await-can-be-var-name
+  "var await = 3;")
+
+(js2-deftest-parse await-can-be-function-name
+  "function await() {\n}")
+
 ;;; Numbers
 
 (js2-deftest-parse decimal-starting-with-zero "081;" :reference "81;")
@@ -639,7 +802,7 @@ the test."
     (should export-node)
     (should (js2-var-decl-node-p (js2-export-node-declaration export-node)))))
 
-(js2-deftest export-class-declaration "export class Foo {};"
+(js2-deftest export-class-declaration "export class Foo {}"
   (js2-init-scanner)
   (js2-push-scope (make-js2-scope :pos 0))
   (should (js2-match-token js2-EXPORT))
@@ -647,7 +810,7 @@ the test."
     (should export-node)
     (should (js2-class-node-p (js2-export-node-declaration export-node)))))
 
-(js2-deftest export-function-declaration "export default function doStuff() {};"
+(js2-deftest export-function-declaration "export default function doStuff() {}"
   (js2-init-scanner)
   (js2-push-scope (make-js2-scope :pos 0))
   (should (js2-match-token js2-EXPORT))
@@ -655,7 +818,7 @@ the test."
     (should export-node)
     (should (js2-export-node-default export-node))))
 
-(js2-deftest export-generator-declaration "export default function* one() {};"
+(js2-deftest export-generator-declaration "export default function* one() {}"
   (js2-init-scanner)
   (js2-push-scope (make-js2-scope :pos 0))
   (should (js2-match-token js2-EXPORT))
@@ -672,24 +835,43 @@ the test."
     (should (js2-export-node-default export-node))))
 
 (js2-deftest export-function-no-semicolon "export default function foo() {}"
-  (js2-mode)
+  (js2-mode--and-parse)
   (should (equal nil js2-parsed-warnings)))
 (js2-deftest export-default-function-no-semicolon "export function foo() {}"
-  (js2-mode)
+  (js2-mode--and-parse)
   (should (equal nil js2-parsed-warnings)))
 (js2-deftest export-anything-else-does-require-a-semicolon "export var obj = {}"
-  (js2-mode)
+  (js2-mode--and-parse)
   (should (not (equal nil js2-parsed-warnings))))
 
+(js2-deftest export-default-async-function-no-semicolon "export default async function foo() {}"
+  (js2-mode--and-parse)
+  (should (equal nil js2-parsed-warnings)))
+(js2-deftest export-async-function-no-semicolon "export async function foo() {}"
+  (js2-mode--and-parse)
+  (should (equal nil js2-parsed-warnings)))
+
 (js2-deftest-parse parse-export-rexport "export * from 'other/lib';")
 (js2-deftest-parse parse-export-export-named-list "export {foo, bar as bang};")
 (js2-deftest-parse parse-re-export-named-list "export {foo, bar as bang} from 'other/lib';")
 (js2-deftest-parse parse-export-const-declaration "export const PI = Math.PI;")
 (js2-deftest-parse parse-export-let-declaration "export let foo = [1];")
-(js2-deftest-parse parse-export-function-declaration "export default function doStuff() {};")
-(js2-deftest-parse parse-export-generator-declaration "export default function* one() {};")
+(js2-deftest-parse parse-export-function-declaration "export default function doStuff() {\n}")
+(js2-deftest-parse parse-export-generator-declaration "export default function* one() {\n}")
 (js2-deftest-parse parse-export-assignment-expression "export default a = b;")
 
+(js2-deftest-parse parse-export-function-declaration-no-semi
+  "export function f() {\n}")
+
+(js2-deftest-parse parse-export-class-declaration-no-semi
+  "export class C {\n}")
+
+(js2-deftest-parse parse-export-async-function-allow-await
+  "export async function f() {\n  await f();\n}")
+
+(js2-deftest-parse parse-export-default-async-function-allow-await
+  "export default async function f() {\n  await f();\n}")
+
 ;;; Strings
 
 (js2-deftest-parse string-literal
@@ -749,10 +931,13 @@ the test."
 (js2-deftest-parse parse-class-keywordlike-method
   "class C {\n  delete() {}\n  if() {}\n}")
 
+(js2-deftest-parse parse-harmony-class-allow-semicolon-element
+  "class Foo {;}" :reference "class Foo {\n}")
+
 ;;; Scopes
 
 (js2-deftest ast-symbol-table-includes-fn-node "function foo() {}"
-  (js2-mode)
+  (js2-mode--and-parse)
   (let ((entry (js2-scope-get-symbol js2-mode-ast 'foo)))
     (should (= (js2-symbol-decl-type entry) js2-FUNCTION))
     (should (equal (js2-symbol-name entry) "foo"))
@@ -762,7 +947,7 @@ the test."
   function bar() {}
   var x;
 }"
-  (js2-mode)
+  (js2-mode--and-parse)
   (let* ((scope (js2-node-at-point (point-min)))
          (fn-entry (js2-scope-get-symbol scope 'bar))
          (var-entry (js2-scope-get-symbol scope 'x)))
@@ -780,36 +965,26 @@ the test."
     (should (funcall predicate (js2-get-defining-scope scope variable)))))
 
 (js2-deftest for-node-is-declaration-scope "for (let i = 0; i; ++i) {};"
-  (js2-mode)
+  (js2-mode--and-parse)
   (js2-test-scope-of-nth-variable-satisifies-predicate "i" 0 #'js2-for-node-p))
 
-(js2-deftest const-scope-sloppy-script "{const a;} a;"
-  (js2-mode)
-  (js2-test-scope-of-nth-variable-satisifies-predicate "a" 0 #'js2-script-node-p)
-  (js2-test-scope-of-nth-variable-satisifies-predicate "a" 1 #'js2-script-node-p))
-
-(js2-deftest const-scope-strict-script "'use strict'; { const a; } a;"
-  (js2-mode)
+(js2-deftest const-scope-inside-script "{ const a; } a;"
+  (js2-mode--and-parse)
   (js2-test-scope-of-nth-variable-satisifies-predicate "a" 0 #'js2-block-node-p)
   (js2-test-scope-of-nth-variable-satisifies-predicate "a" 1 #'null))
 
-(js2-deftest const-scope-sloppy-function "function f() { { const a; } a; }"
-  (js2-mode)
-  (js2-test-scope-of-nth-variable-satisifies-predicate "a" 0 #'js2-function-node-p)
-  (js2-test-scope-of-nth-variable-satisifies-predicate "a" 1 #'js2-function-node-p))
-
-(js2-deftest const-scope-strict-function "function f() { 'use strict'; { const a; } a; }"
-  (js2-mode)
+(js2-deftest const-scope-inside-function "function f() { { const a; } a; }"
+  (js2-mode--and-parse)
   (js2-test-scope-of-nth-variable-satisifies-predicate "a" 0 #'js2-block-node-p)
   (js2-test-scope-of-nth-variable-satisifies-predicate "a" 1 #'null))
 
 (js2-deftest array-comp-is-result-scope "[x * 2 for (x in y)];"
-  (js2-mode)
+  (js2-mode--and-parse)
   (js2-test-scope-of-nth-variable-satisifies-predicate "x" 0 #'js2-comp-loop-node-p))
 
 (js2-deftest array-comp-has-parent-scope
              "var a,b=[for (i of [[1,2]]) for (j of i) j * a];"
-  (js2-mode)
+  (js2-mode--and-parse)
   (search-forward "for")
   (forward-char -3)
   (let ((node (js2-node-at-point)))
@@ -879,23 +1054,23 @@ the test."
 ;;; Error handling
 
 (js2-deftest for-node-with-error-len "for "
-  (js2-mode)
+  (js2-mode--and-parse)
   (let ((node (js2-node-at-point (point-min))))
     (should (= (js2-node-len (js2-node-parent node)) 4))))
 
 (js2-deftest function-without-parens-error "function b {}"
   ;; Should finish the parse.
-  (js2-mode))
+  (js2-mode--and-parse))
 
 ;;; Comments
 
 (js2-deftest comment-node-length "//"
-  (js2-mode)
+  (js2-mode--and-parse)
   (let ((node (js2-node-at-point (point-min))))
     (should (= (js2-node-len node) 2))))
 
 (js2-deftest comment-node-length-newline "//\n"
-  (js2-mode)
+  (js2-mode--and-parse)
   (let ((node (js2-node-at-point (point-min))))
     (should (= (js2-node-len node) 3))))
 
@@ -934,7 +1109,7 @@ the test."
          (insert ,buffer-contents))
        (unwind-protect
            (progn
-             (js2-mode)
+             (js2-mode--and-parse)
              (should (equal ,summary (js2--variables-summary
                                       (js2--classify-variables)))))
          (fundamental-mode)))))