]> code.delx.au - gnu-emacs-elpa/blobdiff - test/context-coloring-test.el
Merge branch 'plugins'
[gnu-emacs-elpa] / test / context-coloring-test.el
index 3eb66bdeb104f04bd3371ad9b4d4c0ea50e46715..559128af2a726fb5270be8ea12e829405c090c2d 100644 (file)
@@ -1,6 +1,6 @@
 ;;; context-coloring-test.el --- Tests for context coloring  -*- lexical-binding: t; -*-
 
-;; Copyright (C) 2014-2015  Free Software Foundation, Inc.
+;; Copyright (C) 2014-2016  Free Software Foundation, Inc.
 
 ;; This file is part of GNU Emacs.
 
@@ -27,8 +27,9 @@
 
 (require 'cl-lib)
 (require 'context-coloring)
+(require 'context-coloring-javascript)
+(require 'context-coloring-emacs-lisp)
 (require 'ert)
-(require 'js2-mode)
 
 
 ;;; Test running utilities
@@ -44,8 +45,7 @@
     (buffer-string)))
 
 (defmacro context-coloring-test-with-fixture (fixture &rest body)
-  "With the relative FIXTURE, evaluate BODY in a temporary
-buffer."
+  "With relative FIXTURE, evaluate BODY in a temporary buffer."
   `(with-temp-buffer
      (progn
        (insert (context-coloring-test-read-file ,fixture))
@@ -59,18 +59,16 @@ buffer."
                                                    &key extension
                                                    &key no-fixture
                                                    &key enable-context-coloring-mode
-                                                   &key get-args
                                                    &key before-each
                                                    &key after-each)
   "Define a deftest defmacro for tests prefixed with NAME.  MODE
 is called to set up tests' environments.  EXTENSION denotes the
 suffix for tests' fixture files.  If NO-FIXTURE is non-nil, don't
 use a fixture.  If ENABLE-CONTEXT-COLORING-MODE is non-nil,
-`context-coloring-mode' is activated before tests.  GET-ARGS
-provides arguments to apply to BEFORE-EACH, AFTER-EACH, and each
-tests' body, before and after functions.  Functions BEFORE-EACH
-and AFTER-EACH run before the major mode is activated before each
-test, and after each test, even if an error is signaled."
+`context-coloring-mode' is activated before tests.  Functions
+BEFORE-EACH and AFTER-EACH run before the major mode is activated
+before each test, and after each test, even if an error is
+signaled."
   (declare (indent defun))
   (let ((macro-name (intern (format "context-coloring-test-deftest%s"
                                     (cond
@@ -86,41 +84,41 @@ test, and after each test, even if an error is signaled."
        ;; Commas in nested backquotes are not evaluated.  Binding the variables
        ;; here is probably the cleanest workaround.
        (let ((mode ,mode)
-             (get-args ',(cond
-                          (get-args get-args)
-                          (t '(lambda () (list)))))
-             (args (make-symbol "args"))
              (before-each ',before-each)
              (after-each ',after-each)
              (test-name (intern (format ,(format "%s-%%s"
                                                  (cond
                                                   (name)
-                                                  (t "sync"))) name)))
+                                                  (t "generic"))) name)))
              (fixture (cond
                        (fixture (format "./fixtures/%s" fixture))
                        (,no-fixture "./fixtures/empty")
                        (t (format ,(format "./fixtures/%%s.%s" extension) name)))))
          ,@`((let ((enable-context-coloring-mode ,enable-context-coloring-mode))
                `(ert-deftest ,test-name ()
-                  (let ((,args (funcall ,get-args)))
-                    (context-coloring-test-with-fixture
-                     ,fixture
-                     (when ,before-each (apply ,before-each ,args))
-                     (,mode)
-                     (when ,before (apply ,before ,args))
-                     (when ,enable-context-coloring-mode (context-coloring-mode))
-                     (unwind-protect
-                         (progn
-                           (apply ,body ,args))
-                       (when ,after (apply ,after ,args))
-                       (when ,after-each (apply ,after-each ,args))))))))))))
+                  (context-coloring-test-with-fixture
+                   ,fixture
+                   (when ,before-each (funcall ,before-each))
+                   (,mode)
+                   (when ,before (funcall ,before))
+                   (when ,enable-context-coloring-mode (context-coloring-mode))
+                   (unwind-protect
+                       (progn
+                         (funcall ,body))
+                     (when ,after (funcall ,after))
+                     (when ,after-each (funcall ,after-each)))))))))))
 
 (context-coloring-test-define-deftest nil
   :mode #'fundamental-mode
   :no-fixture t)
 
+(defun context-coloring-test-js2-mode ()
+  "Enable js2-mode and parse synchronously."
+  (js2-mode)
+  (js2-reparse))
+
 (context-coloring-test-define-deftest javascript
-  :mode #'js2-mode
+  :mode #'context-coloring-test-js2-mode
   :extension "js"
   :enable-context-coloring-mode t
   :before-each (lambda ()
@@ -136,18 +134,6 @@ test, and after each test, even if an error is signaled."
   :mode #'fundamental-mode
   :no-fixture t)
 
-(context-coloring-test-define-deftest define-theme
-  :mode #'fundamental-mode
-  :no-fixture t
-  :get-args (lambda ()
-              (list (context-coloring-test-get-next-theme)))
-  :after-each (lambda (theme)
-                (setq context-coloring-maximum-face 7)
-                (setq context-coloring-original-maximum-face
-                      context-coloring-maximum-face)
-                (disable-theme theme)
-                (context-coloring-test-kill-buffer "*Warnings*")))
-
 
 ;;; Assertion functions
 
@@ -193,15 +179,6 @@ test, and after each test, even if an error is signaled."
              "but it did")
             buffer expected)))))))
 
-(defun context-coloring-test-assert-no-message (buffer)
-  "Assert that BUFFER has no message."
-  (when (get-buffer buffer)
-    (ert-fail (format (concat "Expected buffer `%s' to have no messages, "
-                              "but it did: `%s'")
-                      buffer
-                      (with-current-buffer buffer
-                        (buffer-string))))))
-
 (defun context-coloring-test-assert-error (body error-message)
   "Assert that BODY signals ERROR-MESSAGE."
   (let ((error-signaled-p nil))
@@ -226,29 +203,38 @@ test, and after each test, even if an error is signaled."
   (let ((name (intern (format "context-coloring-test-%s-mode" name))))
     `(define-derived-mode ,name fundamental-mode "Testing")))
 
+(defvar context-coloring-test-caused-p nil
+  "If non-nil, coloring was caused.")
+
 (defmacro context-coloring-test-assert-causes-coloring (&rest body)
   "Assert that BODY causes coloring."
-  (let ((colorized-p (make-symbol "colorized-p")))
-    `(let (,colorized-p)
-       (advice-add #'context-coloring-colorize
-                   :after (lambda ()
-                            (setq ,colorized-p t))
-                   '((name . assert-causes-coloring)))
-       ,@body
-       (when (not ,colorized-p)
-         (ert-fail "Expected to have colorized, but it didn't.")))))
+  `(progn
+     ;; Gross, but I want this to pass on 24.3.
+     (ad-add-advice #'context-coloring-colorize
+                    '(assert-causes-coloring
+                      nil t
+                      (advice . (lambda ()
+                                  (setq context-coloring-test-caused-p t))))
+                    'after
+                    0)
+     (ad-activate #'context-coloring-colorize)
+     ,@body
+     (when (not context-coloring-test-caused-p)
+       (ert-fail "Expected to have colorized, but it didn't."))))
 
 (defun context-coloring-test-cleanup-assert-causes-coloring ()
-  (advice-remove #'context-coloring-colorize 'assert-causes-coloring))
+  "Undo `context-coloring-test-assert-causes-coloring'."
+  (ad-unadvise #'context-coloring-colorize)
+  (setq context-coloring-test-caused-p nil))
 
 (context-coloring-test-define-derived-mode mode-startup)
 
 (context-coloring-test-deftest mode-startup
   (lambda ()
-    (context-coloring-define-dispatch
+    (puthash
      'mode-startup
-     :modes '(context-coloring-test-mode-startup-mode)
-     :colorizer #'ignore)
+     (list :modes '(context-coloring-test-mode-startup-mode))
+     context-coloring-dispatch-hash-table)
     (context-coloring-test-mode-startup-mode)
     (context-coloring-test-assert-causes-coloring
      (context-coloring-mode)))
@@ -259,12 +245,12 @@ test, and after each test, even if an error is signaled."
 
 (context-coloring-test-deftest change-detection
   (lambda ()
-    (context-coloring-define-dispatch
+    (puthash
      'idle-change
-     :modes '(context-coloring-test-change-detection-mode)
-     :colorizer #'ignore
-     :setup #'context-coloring-setup-idle-change-detection
-     :teardown #'context-coloring-teardown-idle-change-detection)
+     (list :modes '(context-coloring-test-change-detection-mode)
+           :setup #'context-coloring-setup-idle-change-detection
+           :teardown #'context-coloring-teardown-idle-change-detection)
+     context-coloring-dispatch-hash-table)
     (context-coloring-test-change-detection-mode)
     (context-coloring-mode)
     (context-coloring-test-assert-causes-coloring
@@ -279,426 +265,103 @@ test, and after each test, even if an error is signaled."
   (lambda ()
     (context-coloring-mode)
     (context-coloring-test-assert-message
-     "Context coloring is not available for this major mode"
-     "*Messages*")))
-
-(context-coloring-test-deftest derived-mode
-  (lambda ()
-    (lisp-interaction-mode)
-    (context-coloring-mode)
-    (context-coloring-test-assert-not-message
-     "Context coloring is not available for this major mode"
+     "Context coloring is unavailable here"
      "*Messages*")))
 
-(context-coloring-test-define-derived-mode define-dispatch-error)
-
-(context-coloring-test-deftest define-dispatch-error
+(context-coloring-test-deftest unavailable-message-ignored
   (lambda ()
-    (context-coloring-test-assert-error
-     (lambda ()
-       (context-coloring-define-dispatch
-        'define-dispatch-no-modes))
-     "No mode or predicate defined for dispatch")
-    (context-coloring-test-assert-error
-     (lambda ()
-       (context-coloring-define-dispatch
-        'define-dispatch-no-strategy
-        :modes '(context-coloring-test-define-dispatch-error-mode)))
-     "No colorizer defined for dispatch")))
+    (minibuffer-with-setup-hook
+        (lambda ()
+          (context-coloring-mode)
+          (context-coloring-test-assert-not-message
+           "Context coloring is unavailable here"
+           "*Messages*"))
+      (execute-kbd-macro
+       (vconcat
+        [?\C-u]
+        [?\M-!])))))
 
 (context-coloring-test-define-derived-mode disable-mode)
 
 (context-coloring-test-deftest disable-mode
   (lambda ()
     (let (torn-down)
-      (context-coloring-define-dispatch
+      (puthash
        'disable-mode
-       :modes '(context-coloring-test-disable-mode-mode)
-       :colorizer #'ignore
-       :teardown (lambda ()
-                   (setq torn-down t)))
+       (list :modes '(context-coloring-test-disable-mode-mode)
+             :teardown (lambda ()
+                         (setq torn-down t)))
+       context-coloring-dispatch-hash-table)
       (context-coloring-test-disable-mode-mode)
       (context-coloring-mode)
       (context-coloring-mode -1)
       (when (not torn-down)
         (ert-fail "Expected teardown function to have been called, but it wasn't.")))))
 
+(defun context-coloring-test-assert-maximum-face (expected)
+  "Assert that `context-coloring-maximum-face' is EXPECTED."
+  (when (not (= context-coloring-maximum-face expected))
+    (ert-fail (format "Expected maximum face to be %s, but it was %s"
+                      expected context-coloring-maximum-face))))
 
-;;; Theme tests
-
-(defvar context-coloring-test-theme-index 0
-  "Unique index for unique theme names.")
-
-(defun context-coloring-test-get-next-theme ()
-  "Return a unique symbol for a throwaway theme."
-  (prog1
-      (intern (format "context-coloring-test-theme-%s"
-                      context-coloring-test-theme-index))
-    (setq context-coloring-test-theme-index
-          (+ context-coloring-test-theme-index 1))))
-
-(defun context-coloring-test-assert-face (level foreground &optional negate)
-  "Assert that a face for LEVEL exists and that its `:foreground'
-is FOREGROUND, or the inverse if NEGATE is non-nil."
-  (let* ((face (context-coloring-level-face level))
-         actual-foreground)
-    (when (not (or negate
-                   face))
-      (ert-fail (format (concat "Expected face for level `%s' to exist; "
-                                "but it didn't")
-                        level)))
-    (setq actual-foreground (face-attribute face :foreground))
-    (when (funcall (if negate #'identity #'not)
-                   (string-equal foreground actual-foreground))
-      (ert-fail (format (concat "Expected face for level `%s' "
-                                "%sto have foreground `%s'; "
-                                "but it %s.")
-                        level
-                        (if negate "not " "") foreground
-                        (if negate
-                            "did" (format "was `%s'" actual-foreground)))))))
-
-(defun context-coloring-test-assert-not-face (&rest arguments)
-  "Assert that LEVEL does not have a face with `:foreground'
-FOREGROUND.  Apply ARGUMENTS to
-`context-coloring-test-assert-face', see that function."
-  (apply #'context-coloring-test-assert-face
-         (append arguments '(t))))
-
-(defun context-coloring-test-assert-theme-originally-set-p
-    (settings &optional negate)
-  "Assert that `context-coloring-theme-originally-set-p' will
-return t for a theme with SETTINGS, or the inverse if NEGATE is
-non-nil."
-  (let ((theme (context-coloring-test-get-next-theme)))
-    (put theme 'theme-settings settings)
-    (when (funcall (if negate #'identity #'not)
-                   (context-coloring-theme-originally-set-p theme))
-      (ert-fail (format (concat "Expected theme `%s' with settings `%s' "
-                                "%sto be considered to have defined a level, "
-                                "but it %s.")
-                        theme settings
-                        (if negate "not " "")
-                        (if negate "was" "wasn't"))))))
-
-(defun context-coloring-test-assert-not-theme-originally-set-p (&rest arguments)
-  "Assert that `context-coloring-theme-originally-set-p' does not
-return t for a theme with SETTINGS.  Apply ARGUMENTS to
-`context-coloring-test-assert-theme-originally-set-p', see that
-function."
-  (apply #'context-coloring-test-assert-theme-originally-set-p
-         (append arguments '(t))))
-
-(context-coloring-test-deftest theme-originally-set-p
-  (lambda ()
-    (context-coloring-test-assert-theme-originally-set-p
-     '((theme-face context-coloring-level-0-face)))
-    (context-coloring-test-assert-theme-originally-set-p
-     '((theme-face face)
-       (theme-face context-coloring-level-0-face)))
-    (context-coloring-test-assert-theme-originally-set-p
-     '((theme-face context-coloring-level-0-face)
-       (theme-face face)))
-    (context-coloring-test-assert-not-theme-originally-set-p
-     '((theme-face face)))))
-
-(defun context-coloring-test-assert-theme-settings-highest-level
-    (settings expected-level)
-  "Assert that a theme with SETTINGS has the highest level
-EXPECTED-LEVEL."
-  (let ((theme (context-coloring-test-get-next-theme)))
-    (put theme 'theme-settings settings)
-    (context-coloring-test-assert-theme-highest-level theme expected-level)))
-
-(defun context-coloring-test-assert-theme-highest-level
-    (theme expected-level &optional negate)
-  "Assert that THEME has the highest level EXPECTED-LEVEL, or the
-inverse if NEGATE is non-nil."
-  (let ((highest-level (context-coloring-theme-highest-level theme)))
-    (when (funcall (if negate #'identity #'not) (eq highest-level expected-level))
-      (ert-fail (format (concat "Expected theme with settings `%s' "
-                                "%sto have a highest level of `%s', "
-                                "but it %s.")
-                        (get theme 'theme-settings)
-                        (if negate "not " "") expected-level
-                        (if negate "did" (format "was %s" highest-level)))))))
-
-(defun context-coloring-test-assert-theme-not-highest-level (&rest arguments)
-  "Assert that THEME's highest level is not EXPECTED-LEVEL.
-Apply ARGUMENTS to
-`context-coloring-test-assert-theme-highest-level', see that
-function."
-  (apply #'context-coloring-test-assert-theme-highest-level
-         (append arguments '(t))))
-
-(context-coloring-test-deftest theme-highest-level
+(deftheme context-coloring-test-custom-theme)
+
+(context-coloring-test-define-derived-mode custom-theme)
+
+(context-coloring-test-deftest custom-theme
   (lambda ()
-    (context-coloring-test-assert-theme-settings-highest-level
-     '((theme-face foo))
-     -1)
-    (context-coloring-test-assert-theme-settings-highest-level
-     '((theme-face context-coloring-level-0-face))
-     0)
-    (context-coloring-test-assert-theme-settings-highest-level
-     '((theme-face context-coloring-level-1-face))
-     1)
-    (context-coloring-test-assert-theme-settings-highest-level
-     '((theme-face context-coloring-level-1-face)
-       (theme-face context-coloring-level-0-face))
-     1)
-    (context-coloring-test-assert-theme-settings-highest-level
-     '((theme-face context-coloring-level-0-face)
-       (theme-face context-coloring-level-1-face))
-     1)))
-
-(defun context-coloring-test-kill-buffer (buffer)
-  "Kill BUFFER if it exists."
-  (when (get-buffer buffer) (kill-buffer buffer)))
-
-(defun context-coloring-test-deftheme (theme)
-  "Dynamically define theme THEME."
-  (eval (macroexpand `(deftheme ,theme))))
-
-(context-coloring-test-deftest-define-theme additive
-  (lambda (theme)
-    (context-coloring-test-deftheme theme)
-    (context-coloring-define-theme
-     theme
-     :colors '("#aaaaaa"
-               "#bbbbbb"))
-    (context-coloring-test-assert-no-message "*Warnings*")
-    (enable-theme theme)
-    (context-coloring-test-assert-no-message "*Warnings*")
-    (context-coloring-test-assert-face 0 "#aaaaaa")
-    (context-coloring-test-assert-face 1 "#bbbbbb")))
-
-(defun context-coloring-test-assert-defined-warning (theme)
-  "Assert that a warning about colors already being defined for
-theme THEME is signaled."
-  (context-coloring-test-assert-message
-   (format (concat "Warning (emacs): Context coloring colors for theme "
-                   "`%s' are already defined")
-           theme)
-   "*Warnings*"))
-
-(context-coloring-test-deftest-define-theme unintentional-override
-  (lambda (theme)
-    (context-coloring-test-deftheme theme)
-    (custom-theme-set-faces
-     theme
-     '(context-coloring-level-0-face ((t (:foreground "#aaaaaa"))))
-     '(context-coloring-level-1-face ((t (:foreground "#bbbbbb")))))
-    (context-coloring-define-theme
-     theme
-     :colors '("#cccccc"
-               "#dddddd"))
-    (context-coloring-test-assert-defined-warning theme)
-    (context-coloring-test-kill-buffer "*Warnings*")
-    (enable-theme theme)
-    (context-coloring-test-assert-defined-warning theme)
-    (context-coloring-test-assert-face 0 "#cccccc")
-    (context-coloring-test-assert-face 1 "#dddddd")))
-
-(context-coloring-test-deftest-define-theme intentional-override
-  (lambda (theme)
-    (context-coloring-test-deftheme theme)
-    (custom-theme-set-faces
-     theme
-     '(context-coloring-level-0-face ((t (:foreground "#aaaaaa"))))
-     '(context-coloring-level-1-face ((t (:foreground "#bbbbbb")))))
-    (context-coloring-define-theme
-     theme
-     :override t
-     :colors '("#cccccc"
-               "#dddddd"))
-    (context-coloring-test-assert-no-message "*Warnings*")
-    (enable-theme theme)
-    (context-coloring-test-assert-no-message "*Warnings*")
-    (context-coloring-test-assert-face 0 "#cccccc")
-    (context-coloring-test-assert-face 1 "#dddddd")))
-
-(context-coloring-test-deftest-define-theme pre-recede
-  (lambda (theme)
-    (context-coloring-define-theme
-     theme
-     :recede t
-     :colors '("#aaaaaa"
-               "#bbbbbb"))
-    (context-coloring-test-deftheme theme)
-    (custom-theme-set-faces
-     theme
-     '(context-coloring-level-0-face ((t (:foreground "#cccccc"))))
-     '(context-coloring-level-1-face ((t (:foreground "#dddddd")))))
-    (enable-theme theme)
-    (context-coloring-test-assert-no-message "*Warnings*")
-    (context-coloring-test-assert-face 0 "#cccccc")
-    (context-coloring-test-assert-face 1 "#dddddd")))
-
-(context-coloring-test-deftest-define-theme pre-recede-delayed-application
-  (lambda (theme)
-    (context-coloring-define-theme
-     theme
-     :recede t
-     :colors '("#aaaaaa"
-               "#bbbbbb"))
-    (context-coloring-test-deftheme theme)
-    (enable-theme theme)
-    (context-coloring-test-assert-no-message "*Warnings*")
-    (context-coloring-test-assert-face 0 "#aaaaaa")
-    (context-coloring-test-assert-face 1 "#bbbbbb")))
-
-(context-coloring-test-deftest-define-theme post-recede
-  (lambda (theme)
-    (context-coloring-test-deftheme theme)
     (custom-theme-set-faces
-     theme
-     '(context-coloring-level-0-face ((t (:foreground "#aaaaaa"))))
-     '(context-coloring-level-1-face ((t (:foreground "#bbbbbb")))))
-    (context-coloring-define-theme
-     theme
-     :recede t
-     :colors '("#cccccc"
-               "#dddddd"))
-    (context-coloring-test-assert-no-message "*Warnings*")
-    (context-coloring-test-assert-face 0 "#aaaaaa")
-    (context-coloring-test-assert-face 1 "#bbbbbb")
-    (enable-theme theme)
-    (context-coloring-test-assert-no-message "*Warnings*")
-    (context-coloring-test-assert-face 0 "#aaaaaa")
-    (context-coloring-test-assert-face 1 "#bbbbbb")))
-
-(context-coloring-test-deftest-define-theme recede-not-defined
-  (lambda (theme)
-    (context-coloring-test-deftheme theme)
-    (custom-theme-set-faces
-     theme
-     '(foo-face ((t (:foreground "#ffffff")))))
-    (context-coloring-define-theme
-     theme
-     :recede t
-     :colors '("#aaaaaa"
-               "#bbbbbb"))
-    (context-coloring-test-assert-no-message "*Warnings*")
-    (context-coloring-test-assert-face 0 "#aaaaaa")
-    (context-coloring-test-assert-face 1 "#bbbbbb")
-    (enable-theme theme)
-    (context-coloring-test-assert-no-message "*Warnings*")
-    (context-coloring-test-assert-face 0 "#aaaaaa")
-    (context-coloring-test-assert-face 1 "#bbbbbb")))
-
-(context-coloring-test-deftest-define-theme unintentional-obstinance
-  (lambda (theme)
-    (context-coloring-define-theme
-     theme
-     :colors '("#aaaaaa"
-               "#bbbbbb"))
-    (context-coloring-test-deftheme theme)
-    (custom-theme-set-faces
-     theme
-     '(context-coloring-level-0-face ((t (:foreground "#cccccc"))))
-     '(context-coloring-level-1-face ((t (:foreground "#dddddd")))))
-    (enable-theme theme)
-    (context-coloring-test-assert-defined-warning theme)
-    (context-coloring-test-assert-face 0 "#aaaaaa")
-    (context-coloring-test-assert-face 1 "#bbbbbb")))
-
-(context-coloring-test-deftest-define-theme intentional-obstinance
-  (lambda (theme)
-    (context-coloring-define-theme
-     theme
-     :override t
-     :colors '("#aaaaaa"
-               "#bbbbbb"))
-    (context-coloring-test-deftheme theme)
-    (custom-theme-set-faces
-     theme
-     '(context-coloring-level-0-face ((t (:foreground "#cccccc"))))
-     '(context-coloring-level-1-face ((t (:foreground "#dddddd")))))
-    (enable-theme theme)
-    (context-coloring-test-assert-no-message "*Warnings*")
-    (context-coloring-test-assert-face 0 "#aaaaaa")
-    (context-coloring-test-assert-face 1 "#bbbbbb")))
-
-(defun context-coloring-test-assert-maximum-face (maximum &optional negate)
-  "Assert that `context-coloring-maximum-face' is MAXIMUM, or the
-inverse if NEGATE is non-nil."
-  (when (funcall (if negate #'identity #'not)
-                 (eq context-coloring-maximum-face maximum))
-    (ert-fail (format (concat "Expected `context-coloring-maximum-face' "
-                              "%sto be `%s', "
-                              "but it %s.")
-                      (if negate "not " "") maximum
-                      (if negate
-                          "was"
-                        (format "was `%s'" context-coloring-maximum-face))))))
-
-(defun context-coloring-test-assert-not-maximum-face (&rest arguments)
-  "Assert that `context-coloring-maximum-face' is not MAXIMUM.
-Apply ARGUMENTS to `context-coloring-test-assert-maximum-face',
-see that function."
-  (apply #'context-coloring-test-assert-maximum-face
-         (append arguments '(t))))
-
-(context-coloring-test-deftest-define-theme disable-cascade
-  (lambda (theme)
-    (let ((maximum-face-value 9999))
-      (setq context-coloring-maximum-face maximum-face-value)
-      (context-coloring-test-deftheme theme)
-      (context-coloring-define-theme
-       theme
-       :colors '("#aaaaaa"
-                 "#bbbbbb"))
-      (let ((second-theme (context-coloring-test-get-next-theme)))
-        (context-coloring-test-deftheme second-theme)
-        (context-coloring-define-theme
-         second-theme
-         :colors '("#cccccc"
-                   "#dddddd"
-                   "#eeeeee"))
-        (let ((third-theme (context-coloring-test-get-next-theme)))
-          (context-coloring-test-deftheme third-theme)
-          (context-coloring-define-theme
-           third-theme
-           :colors '("#111111"
-                     "#222222"
-                     "#333333"
-                     "#444444"))
-          (enable-theme theme)
-          (enable-theme second-theme)
-          (enable-theme third-theme)
-          (disable-theme third-theme)
-          (context-coloring-test-assert-face 0 "#cccccc")
-          (context-coloring-test-assert-face 1 "#dddddd")
-          (context-coloring-test-assert-face 2 "#eeeeee")
-          (context-coloring-test-assert-maximum-face 2))
-        (disable-theme second-theme)
-        (context-coloring-test-assert-face 0 "#aaaaaa")
-        (context-coloring-test-assert-face 1 "#bbbbbb")
-        (context-coloring-test-assert-maximum-face 1))
-      (disable-theme theme)
-      (context-coloring-test-assert-not-face 0 "#aaaaaa")
-      (context-coloring-test-assert-not-face 1 "#bbbbbb")
-      (context-coloring-test-assert-maximum-face
-       maximum-face-value))))
+     'context-coloring-test-custom-theme
+     '(context-coloring-level-0-face ((t :foreground "#aaaaaa")))
+     '(context-coloring-level-1-face ((t :foreground "#bbbbbb"))))
+    (custom-set-faces
+     '(context-coloring-level-0-face ((t :foreground "#aaaaaa"))))
+    (enable-theme 'context-coloring-test-custom-theme)
+    (puthash
+     'theme
+     (list :modes '(context-coloring-test-custom-theme-mode))
+     context-coloring-dispatch-hash-table)
+    (context-coloring-test-custom-theme-mode)
+    (context-coloring-colorize)
+    (context-coloring-test-assert-maximum-face 1)
+    ;; This theme should now be ignored in favor of the `user' theme.
+    (custom-theme-reset-faces
+     'context-coloring-test-custom-theme
+     '(context-coloring-level-0-face nil)
+     '(context-coloring-level-1-face nil))
+    (context-coloring-colorize)
+    ;; Maximum face for `user'.
+    (context-coloring-test-assert-maximum-face 0)
+    ;; Now `user' should be ignored too.
+    (custom-reset-faces
+     '(context-coloring-level-0-face nil))
+    (context-coloring-colorize)
+    ;; Expect the package's defaults.
+    (context-coloring-test-assert-maximum-face
+     context-coloring-default-maximum-face))
+  :after (lambda ()
+           (custom-reset-faces
+            '(context-coloring-level-0-face nil))
+           (disable-theme 'context-coloring-test-custom-theme)))
 
 
 ;;; Coloring tests
 
+(defun context-coloring-test-face-to-level (face)
+  "Convert FACE symbol to its corresponding level, or nil."
+  (when face
+    (let* ((face-string (symbol-name face))
+           (matches (string-match
+                     context-coloring-level-face-regexp
+                     face-string)))
+      (when matches
+        (string-to-number (match-string 1 face-string))))))
+
 (defun context-coloring-test-assert-position-level (position level)
   "Assert that POSITION has LEVEL."
-  (let ((face (get-text-property position 'face))
-        actual-level)
-    (when (not (and face
-                    (let* ((face-string (symbol-name face))
-                           (matches (string-match
-                                     context-coloring-level-face-regexp
-                                     face-string)))
-                      (when matches
-                        (setq actual-level (string-to-number
-                                            (substring face-string
-                                                       (match-beginning 1)
-                                                       (match-end 1))))
-                        (= level actual-level)))))
+  (let* ((face (get-text-property position 'face))
+         (actual-level (context-coloring-test-face-to-level face)))
+    (when (not (= level actual-level))
       (ert-fail (format (concat "Expected level at position %s, "
                                 "which is \"%s\", to be %s; "
                                 "but it was %s")
@@ -812,7 +475,7 @@ other non-letters are guaranteed to always be discarded."
   (lambda ()
     (context-coloring-test-assert-coloring "
 (xxxxxxxx () {
-    111 1 1 00000001xxx11
+    111 1 1 0000001xxx11
 }());")))
 
 (context-coloring-test-deftest-javascript block-scopes
@@ -822,6 +485,16 @@ other non-letters are guaranteed to always be discarded."
     11 111 2
         222 12
         222 22
+        22222 12
+    2
+}());
+
+(xxxxxxxx () {
+    'xxx xxxxxx';
+    11 111 2
+        222 12
+        222 22
+        22222 22
     2
 }());"))
   :before (lambda ()
@@ -911,6 +584,59 @@ ssssssssssss0"))
   ;; As long as `add-text-properties' doesn't signal an error, this test passes.
   (lambda ()))
 
+(defun context-coloring-test-assert-javascript-elevated-level ()
+  "Assert that the \"initial-level.js\" file has elevated scope."
+  (context-coloring-test-assert-coloring "
+
+111 1 1 0000001xxx11"))
+
+(defun context-coloring-test-assert-javascript-global-level ()
+  "Assert that the \"initial-level.js\" file has global scope."
+  (context-coloring-test-assert-coloring "
+
+000 0 0 0000000xxx00"))
+
+(context-coloring-test-deftest-javascript initial-level
+  (lambda ()
+    (context-coloring-test-assert-javascript-elevated-level))
+  :fixture "initial-level.js"
+  :before (lambda ()
+            (setq context-coloring-initial-level 1))
+  :after (lambda ()
+           (setq context-coloring-initial-level 0)))
+
+(defun context-coloring-test-setup-top-level-scope (string)
+  "Make STRING the first line and colorize again."
+  (goto-char (point-min))
+  (kill-whole-line 0)
+  (insert string)
+  ;; Reparsing triggers recoloring.
+  (js2-reparse))
+
+(context-coloring-test-deftest-javascript top-level-scope
+  (lambda ()
+    (let ((positive-indicators
+           (list "#!/usr/bin/env node"
+                 "/*jslint node: true */"
+                 "// jshint node: true"
+                 "/*eslint-env node */"
+                 "module.exports"
+                 "module.exports.a"
+                 "exports.a"
+                 "require('a')"))
+          (negative-indicators
+           (list "// Blah blah jshint blah."
+                 "module"
+                 "exports"
+                 "var require; require('a')")))
+      (dolist (indicator positive-indicators)
+        (context-coloring-test-setup-top-level-scope indicator)
+        (context-coloring-test-assert-javascript-elevated-level))
+      (dolist (indicator negative-indicators)
+        (context-coloring-test-setup-top-level-scope indicator)
+        (context-coloring-test-assert-javascript-global-level))))
+  :fixture "initial-level.js")
+
 (context-coloring-test-deftest-emacs-lisp defun
   (lambda ()
     (context-coloring-test-assert-coloring "
@@ -1005,6 +731,28 @@ ssssssssssss0"))
 1111 cc ccccccc
     1sss11")))
 
+(context-coloring-test-deftest-emacs-lisp empty-varlist
+  (lambda ()
+    (context-coloring-test-assert-coloring "
+1111111 1 11
+1111111 111
+
+1111 1cc
+      11
+1111111 111")))
+
+(context-coloring-test-deftest-emacs-lisp varlist-spacing
+  (lambda ()
+    (context-coloring-test-assert-coloring "
+(111 (
+      (1 (222222 ()))))
+
+(111111 ( 1 1 )
+  1 1)
+
+(111111111 0 ( (1) )
+  1)")))
+
 (context-coloring-test-deftest-emacs-lisp let*
   (lambda ()
     (context-coloring-test-assert-coloring "
@@ -1018,7 +766,18 @@ ssssssssssss0"))
          22 02
          22 222
     2222 1 1 2 2 2 000022
-  1111 1 1 1 0 0 000011")))
+  1111 1 1 1 0 0 000011"))
+  :fixture "let-star.el")
+
+(context-coloring-test-deftest-emacs-lisp macroexp-let2
+  (lambda ()
+    (context-coloring-test-assert-coloring "
+1111 11111
+  222222222-2222 00000000-00000000-0 2 111
+    2 11121
+
+(11111111-1111 00000000-00000000-0)
+(11111111-1111)")))
 
 (context-coloring-test-deftest-emacs-lisp cond
   (lambda ()