1 ;;; context-coloring-test.el --- Tests for context coloring -*- lexical-binding: t; -*-
3 ;; Copyright (C) 2014-2015 Free Software Foundation, Inc.
5 ;; This file is part of GNU Emacs.
7 ;; This program is free software; you can redistribute it and/or modify
8 ;; it under the terms of the GNU General Public License as published by
9 ;; the Free Software Foundation, either version 3 of the License, or
10 ;; (at your option) any later version.
12 ;; This program is distributed in the hope that it will be useful,
13 ;; but WITHOUT ANY WARRANTY; without even the implied warranty of
14 ;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 ;; GNU General Public License for more details.
17 ;; You should have received a copy of the GNU General Public License
18 ;; along with this program. If not, see <http://www.gnu.org/licenses/>.
22 ;; Tests for context coloring.
24 ;; Use with `make test'.
29 (require 'context-coloring)
34 ;;; Test running utilities
36 (defconst context-coloring-test-path
37 (file-name-directory (or load-file-name buffer-file-name))
38 "This file's directory.")
40 (defun context-coloring-test-read-file (path)
41 "Return the file's contents from PATH as a string."
43 (insert-file-contents (expand-file-name path context-coloring-test-path))
46 (defmacro context-coloring-test-with-fixture (fixture &rest body)
47 "With the relative FIXTURE, evaluate BODY in a temporary
51 (insert (context-coloring-test-read-file ,fixture))
54 (defun context-coloring-test-with-temp-buffer-async (callback)
55 "Create a temporary buffer, and evaluate CALLBACK there. A
56 teardown callback is passed to CALLBACK for it to invoke when it
58 (let ((previous-buffer (current-buffer))
59 (temp-buffer (generate-new-buffer " *temp*")))
60 (set-buffer temp-buffer)
64 (and (buffer-name temp-buffer)
65 (kill-buffer temp-buffer))
66 (set-buffer previous-buffer)))))
68 (defun context-coloring-test-with-fixture-async (fixture callback)
69 "With the relative FIXTURE, evaluate CALLBACK in a temporary
70 buffer. A teardown callback is passed to CALLBACK for it to
71 invoke when it is done."
72 (context-coloring-test-with-temp-buffer-async
73 (lambda (done-with-temp-buffer)
74 (insert (context-coloring-test-read-file fixture))
78 (funcall done-with-temp-buffer))))))
81 ;;; Test defining utilities
83 (cl-defmacro context-coloring-test-define-deftest (name
88 &key post-colorization
89 &key enable-context-coloring-mode
93 "Define a deftest defmacro for tests prefixed with NAME. MODE
94 is called to set up tests' environments. EXTENSION denotes the
95 suffix for tests' fixture files. If NO-FIXTURE is non-nil, don't
96 use a fixture. If ASYNC is non-nil, pass a callback to the
97 defined tests' bodies for them to call when they are done. If
98 POST-COLORIZATION is non-nil, the tests run after
99 `context-coloring-colorize' finishes asynchronously. If
100 ENABLE-CONTEXT-COLORING-MODE is non-nil, `context-coloring-mode'
101 is activated before tests. GET-ARGS provides arguments to apply
102 to BEFORE-EACH, AFTER-EACH, and each tests' body, before and
103 after functions. Functions BEFORE-EACH and AFTER-EACH run before
104 the major mode is activated before each test, and after each
105 test, even if an error is signaled."
106 (declare (indent defun))
107 (let ((macro-name (intern (format "context-coloring-test-deftest%s"
109 ;; No name means no dash.
111 (t (format "-%s" name)))))))
112 `(cl-defmacro ,macro-name (name
117 ,(format "Define a test for `%s' suffixed with NAME.
119 Function BODY makes assertions.
122 Functions BEFORE and AFTER run before and after the test, even if
123 an error is signaled.
125 BODY is run after `context-coloring-mode' is activated, or after
126 initial colorization if colorization should occur."
130 There is no fixture, unless FIXTURE is specified.")
133 The default fixture has a filename matching NAME (plus the
134 filetype extension, \"%s\"), unless FIXTURE is specified to
137 (declare (indent defun))
138 ;; Commas in nested backquotes are not evaluated. Binding the variables
139 ;; here is probably the cleanest workaround.
143 (t '(lambda () (list)))))
144 (args (make-symbol "args"))
145 (before-each ',before-each)
146 (after-each ',after-each)
147 (test-name (intern (format ,(format "%s-%%s"
152 (fixture (format "./fixtures/%s" fixture))
153 (,no-fixture "./fixtures/empty")
154 (t (format ,(format "./fixtures/%%s.%s" extension) name)))))
156 ((or async post-colorization)
157 `((let ((post-colorization ,post-colorization))
158 `(ert-deftest-async ,test-name (done)
159 (let ((,args (funcall ,get-args)))
160 (context-coloring-test-with-fixture-async
162 (lambda (done-with-fixture)
163 (when ,before-each (apply ,before-each ,args))
165 (when ,before (apply ,before ,args))
168 (context-coloring-colorize
173 (when ,after (apply ,after ,args))
174 (when ,after-each (apply ,after-each ,args))
175 (funcall done-with-fixture))
178 ;; Leave error handling up to the user.
181 (when ,after (apply ,after ,args))
182 (when ,after-each (apply ,after-each ,args))
183 (funcall done-with-fixture)
187 `((let ((enable-context-coloring-mode ,enable-context-coloring-mode))
188 `(ert-deftest ,test-name ()
189 (let ((,args (funcall ,get-args)))
190 (context-coloring-test-with-fixture
192 (when ,before-each (apply ,before-each ,args))
194 (when ,before (apply ,before ,args))
195 (when ,enable-context-coloring-mode (context-coloring-mode))
199 (when ,after (apply ,after ,args))
200 (when ,after-each (apply ,after-each ,args))))))))))))))
202 (context-coloring-test-define-deftest nil
203 :mode #'fundamental-mode
206 (context-coloring-test-define-deftest async
207 :mode #'fundamental-mode
211 (context-coloring-test-define-deftest js
214 :post-colorization t)
216 (context-coloring-test-define-deftest js2
219 :enable-context-coloring-mode t
220 :before-each (lambda ()
221 (setq js2-mode-show-parse-errors nil)
222 (setq js2-mode-show-strict-warnings nil)))
224 (defmacro context-coloring-test-deftest-js-js2 (&rest args)
225 "Simultaneously define the same test for js and js2 (with
227 (declare (indent defun))
229 (context-coloring-test-deftest-js ,@args)
230 (context-coloring-test-deftest-js2 ,@args)))
232 (context-coloring-test-define-deftest emacs-lisp
233 :mode #'emacs-lisp-mode
235 :enable-context-coloring-mode t)
237 (context-coloring-test-define-deftest eval-expression
238 :mode #'fundamental-mode
241 (context-coloring-test-define-deftest define-theme
242 :mode #'fundamental-mode
245 (list (context-coloring-test-get-next-theme)))
246 :after-each (lambda (theme)
247 (setq context-coloring-maximum-face 7)
248 (setq context-coloring-original-maximum-face
249 context-coloring-maximum-face)
250 (disable-theme theme)
251 (context-coloring-test-kill-buffer "*Warnings*")))
254 ;;; Assertion functions
256 (defun context-coloring-test-get-last-message ()
257 "Get the last message in the current messages bufffer."
258 (let ((messages (split-string
259 (buffer-substring-no-properties
263 (car (nthcdr (- (length messages) 2) messages))))
265 (defun context-coloring-test-assert-message (expected buffer)
266 "Assert that message EXPECTED is at the end of BUFFER."
267 (when (null (get-buffer buffer))
271 "Expected buffer `%s' to have message \"%s\", "
272 "but the buffer did not have any messages.")
274 (with-current-buffer buffer
275 (let ((message (context-coloring-test-get-last-message)))
276 (when (not (equal message expected))
280 "Expected buffer `%s' to have message \"%s\", "
281 "but instead it was \"%s\"")
285 (defun context-coloring-test-assert-not-message (expected buffer)
286 "Assert that message EXPECTED is not at the end of BUFFER."
287 (when (get-buffer buffer)
288 (with-current-buffer buffer
289 (let ((message (context-coloring-test-get-last-message)))
290 (when (equal message expected)
294 "Expected buffer `%s' not to have message \"%s\", "
296 buffer expected)))))))
298 (defun context-coloring-test-assert-no-message (buffer)
299 "Assert that BUFFER has no message."
300 (when (get-buffer buffer)
301 (ert-fail (format (concat "Expected buffer `%s' to have no messages, "
304 (with-current-buffer buffer
307 (defun context-coloring-test-assert-error (body error-message)
308 "Assert that BODY signals ERROR-MESSAGE."
309 (let ((error-signaled-p nil))
314 (setq error-signaled-p t)
315 (when (not (string-equal (cadr err) error-message))
316 (ert-fail (format (concat "Expected the error \"%s\" to be thrown, "
317 "but instead it was \"%s\".")
320 (when (not error-signaled-p)
321 (ert-fail "Expected an error to be thrown, but there wasn't."))))
324 ;;; Miscellaneous tests
326 (defun context-coloring-test-assert-trimmed (result expected)
327 "Assert that RESULT is trimmed like EXPECTED."
328 (when (not (string-equal result expected))
329 (ert-fail "Expected string to be trimmed, but it wasn't.")))
331 (context-coloring-test-deftest trim
333 (context-coloring-test-assert-trimmed (context-coloring-trim "") "")
334 (context-coloring-test-assert-trimmed (context-coloring-trim " ") "")
335 (context-coloring-test-assert-trimmed (context-coloring-trim "a") "a")
336 (context-coloring-test-assert-trimmed (context-coloring-trim " a") "a")
337 (context-coloring-test-assert-trimmed (context-coloring-trim "a ") "a")
338 (context-coloring-test-assert-trimmed (context-coloring-trim " a ") "a")))
340 (context-coloring-test-deftest-async mode-startup
344 'context-coloring-colorize-hook
346 ;; If this runs we are implicitly successful; this test only confirms
347 ;; that colorization occurs on mode startup.
349 (context-coloring-mode))
351 ;; TODO: This won't run if there is a timeout. Will probably have to
352 ;; roll our own `ert-deftest-async'.
353 (setq context-coloring-colorize-hook nil)))
355 (defmacro context-coloring-test-define-derived-mode (name)
356 "Define a derived mode exclusively for any test with NAME."
357 (let ((name (intern (format "context-coloring-test-%s-mode" name))))
358 `(define-derived-mode ,name fundamental-mode "Testing")))
360 (context-coloring-test-define-derived-mode change-detection)
362 ;; Simply cannot figure out how to trigger an idle timer; would much rather test
363 ;; that. But (current-idle-time) always returns nil in these tests.
364 (context-coloring-test-deftest-async change-detection
366 (context-coloring-define-dispatch
368 :modes '(context-coloring-test-change-detection-mode)
370 :command "node test/binaries/noop")
371 (context-coloring-test-change-detection-mode)
373 'context-coloring-colorize-hook
375 (setq context-coloring-colorize-hook nil)
377 'context-coloring-colorize-hook
381 (set-window-buffer (selected-window) (current-buffer))
382 (context-coloring-maybe-colorize-with-buffer (current-buffer))))
383 (context-coloring-mode))
385 (setq context-coloring-colorize-hook nil)))
387 (context-coloring-test-deftest check-version
389 (when (not (context-coloring-check-version "2.1.3" "3.0.1"))
390 (ert-fail "Expected version 3.0.1 to satisfy 2.1.3, but it didn't."))
391 (when (context-coloring-check-version "3.0.1" "2.1.3")
392 (ert-fail "Expected version 2.1.3 not to satisfy 3.0.1, but it did."))))
394 (context-coloring-test-deftest unsupported-mode
396 (context-coloring-mode)
397 (context-coloring-test-assert-message
398 "Context coloring is not available for this major mode"
401 (context-coloring-test-deftest derived-mode
403 (lisp-interaction-mode)
404 (context-coloring-mode)
405 (context-coloring-test-assert-not-message
406 "Context coloring is not available for this major mode"
409 (context-coloring-test-define-derived-mode define-dispatch-error)
411 (context-coloring-test-deftest define-dispatch-error
413 (context-coloring-test-assert-error
415 (context-coloring-define-dispatch
416 'define-dispatch-no-modes))
417 "No mode or predicate defined for dispatch")
418 (context-coloring-test-assert-error
420 (context-coloring-define-dispatch
421 'define-dispatch-no-strategy
422 :modes '(context-coloring-test-define-dispatch-error-mode)))
423 "No colorizer or command defined for dispatch")))
425 (context-coloring-test-define-derived-mode missing-executable)
427 (context-coloring-test-deftest missing-executable
429 (context-coloring-define-dispatch
431 :modes '(context-coloring-test-missing-executable-mode)
433 :executable "__should_not_exist__")
434 (context-coloring-test-missing-executable-mode)
435 (context-coloring-mode)))
437 (context-coloring-test-define-derived-mode unsupported-version)
439 (context-coloring-test-deftest-async unsupported-version
441 (context-coloring-define-dispatch
443 :modes '(context-coloring-test-unsupported-version-mode)
445 :command "node test/binaries/outta-date"
447 (context-coloring-test-unsupported-version-mode)
449 'context-coloring-check-scopifier-version-hook
453 ;; Normally the executable would be something like "outta-date"
454 ;; rather than "node".
455 (context-coloring-test-assert-message
456 "Update to the minimum version of \"node\" (v2.1.3)"
459 (context-coloring-mode))
461 (setq context-coloring-check-scopifier-version-hook nil)))
463 (context-coloring-test-define-derived-mode disable-mode)
465 (context-coloring-test-deftest-async disable-mode
468 (context-coloring-define-dispatch
470 :modes '(context-coloring-test-disable-mode-mode)
472 :command "node test/binaries/noop"
477 (context-coloring-test-disable-mode-mode)
478 (context-coloring-mode)
479 (context-coloring-mode -1)
480 (when (not torn-down)
481 (ert-fail "Expected teardown function to have been called, but it wasn't.")))
487 (defvar context-coloring-test-theme-index 0
488 "Unique index for unique theme names.")
490 (defun context-coloring-test-get-next-theme ()
491 "Return a unique symbol for a throwaway theme."
493 (intern (format "context-coloring-test-theme-%s"
494 context-coloring-test-theme-index))
495 (setq context-coloring-test-theme-index
496 (+ context-coloring-test-theme-index 1))))
498 (defun context-coloring-test-assert-face (level foreground &optional negate)
499 "Assert that a face for LEVEL exists and that its `:foreground'
500 is FOREGROUND, or the inverse if NEGATE is non-nil."
501 (let* ((face (context-coloring-level-face level))
503 (when (not (or negate
505 (ert-fail (format (concat "Expected face for level `%s' to exist; "
508 (setq actual-foreground (face-attribute face :foreground))
509 (when (funcall (if negate #'identity #'not)
510 (string-equal foreground actual-foreground))
511 (ert-fail (format (concat "Expected face for level `%s' "
512 "%sto have foreground `%s'; "
515 (if negate "not " "") foreground
517 "did" (format "was `%s'" actual-foreground)))))))
519 (defun context-coloring-test-assert-not-face (&rest arguments)
520 "Assert that LEVEL does not have a face with `:foreground'
521 FOREGROUND. Apply ARGUMENTS to
522 `context-coloring-test-assert-face', see that function."
523 (apply #'context-coloring-test-assert-face
524 (append arguments '(t))))
526 (defun context-coloring-test-assert-theme-originally-set-p
527 (settings &optional negate)
528 "Assert that `context-coloring-theme-originally-set-p' will
529 return t for a theme with SETTINGS, or the inverse if NEGATE is
531 (let ((theme (context-coloring-test-get-next-theme)))
532 (put theme 'theme-settings settings)
533 (when (funcall (if negate #'identity #'not)
534 (context-coloring-theme-originally-set-p theme))
535 (ert-fail (format (concat "Expected theme `%s' with settings `%s' "
536 "%sto be considered to have defined a level, "
539 (if negate "not " "")
540 (if negate "was" "wasn't"))))))
542 (defun context-coloring-test-assert-not-theme-originally-set-p (&rest arguments)
543 "Assert that `context-coloring-theme-originally-set-p' does not
544 return t for a theme with SETTINGS. Apply ARGUMENTS to
545 `context-coloring-test-assert-theme-originally-set-p', see that
547 (apply #'context-coloring-test-assert-theme-originally-set-p
548 (append arguments '(t))))
550 (context-coloring-test-deftest theme-originally-set-p
552 (context-coloring-test-assert-theme-originally-set-p
553 '((theme-face context-coloring-level-0-face)))
554 (context-coloring-test-assert-theme-originally-set-p
556 (theme-face context-coloring-level-0-face)))
557 (context-coloring-test-assert-theme-originally-set-p
558 '((theme-face context-coloring-level-0-face)
560 (context-coloring-test-assert-not-theme-originally-set-p
561 '((theme-face face)))))
563 (defun context-coloring-test-assert-theme-settings-highest-level
564 (settings expected-level)
565 "Assert that a theme with SETTINGS has the highest level
567 (let ((theme (context-coloring-test-get-next-theme)))
568 (put theme 'theme-settings settings)
569 (context-coloring-test-assert-theme-highest-level theme expected-level)))
571 (defun context-coloring-test-assert-theme-highest-level
572 (theme expected-level &optional negate)
573 "Assert that THEME has the highest level EXPECTED-LEVEL, or the
574 inverse if NEGATE is non-nil."
575 (let ((highest-level (context-coloring-theme-highest-level theme)))
576 (when (funcall (if negate #'identity #'not) (eq highest-level expected-level))
577 (ert-fail (format (concat "Expected theme with settings `%s' "
578 "%sto have a highest level of `%s', "
580 (get theme 'theme-settings)
581 (if negate "not " "") expected-level
582 (if negate "did" (format "was %s" highest-level)))))))
584 (defun context-coloring-test-assert-theme-not-highest-level (&rest arguments)
585 "Assert that THEME's highest level is not EXPECTED-LEVEL.
587 `context-coloring-test-assert-theme-highest-level', see that
589 (apply #'context-coloring-test-assert-theme-highest-level
590 (append arguments '(t))))
592 (context-coloring-test-deftest theme-highest-level
594 (context-coloring-test-assert-theme-settings-highest-level
597 (context-coloring-test-assert-theme-settings-highest-level
598 '((theme-face context-coloring-level-0-face))
600 (context-coloring-test-assert-theme-settings-highest-level
601 '((theme-face context-coloring-level-1-face))
603 (context-coloring-test-assert-theme-settings-highest-level
604 '((theme-face context-coloring-level-1-face)
605 (theme-face context-coloring-level-0-face))
607 (context-coloring-test-assert-theme-settings-highest-level
608 '((theme-face context-coloring-level-0-face)
609 (theme-face context-coloring-level-1-face))
612 (defun context-coloring-test-kill-buffer (buffer)
613 "Kill BUFFER if it exists."
614 (when (get-buffer buffer) (kill-buffer buffer)))
616 (defun context-coloring-test-deftheme (theme)
617 "Dynamically define theme THEME."
618 (eval (macroexpand `(deftheme ,theme))))
620 (context-coloring-test-deftest-define-theme additive
622 (context-coloring-test-deftheme theme)
623 (context-coloring-define-theme
627 (context-coloring-test-assert-no-message "*Warnings*")
629 (context-coloring-test-assert-no-message "*Warnings*")
630 (context-coloring-test-assert-face 0 "#aaaaaa")
631 (context-coloring-test-assert-face 1 "#bbbbbb")))
633 (defun context-coloring-test-assert-defined-warning (theme)
634 "Assert that a warning about colors already being defined for
635 theme THEME is signaled."
636 (context-coloring-test-assert-message
637 (format (concat "Warning (emacs): Context coloring colors for theme "
638 "`%s' are already defined")
642 (context-coloring-test-deftest-define-theme unintentional-override
644 (context-coloring-test-deftheme theme)
645 (custom-theme-set-faces
647 '(context-coloring-level-0-face ((t (:foreground "#aaaaaa"))))
648 '(context-coloring-level-1-face ((t (:foreground "#bbbbbb")))))
649 (context-coloring-define-theme
653 (context-coloring-test-assert-defined-warning theme)
654 (context-coloring-test-kill-buffer "*Warnings*")
656 (context-coloring-test-assert-defined-warning theme)
657 (context-coloring-test-assert-face 0 "#cccccc")
658 (context-coloring-test-assert-face 1 "#dddddd")))
660 (context-coloring-test-deftest-define-theme intentional-override
662 (context-coloring-test-deftheme theme)
663 (custom-theme-set-faces
665 '(context-coloring-level-0-face ((t (:foreground "#aaaaaa"))))
666 '(context-coloring-level-1-face ((t (:foreground "#bbbbbb")))))
667 (context-coloring-define-theme
672 (context-coloring-test-assert-no-message "*Warnings*")
674 (context-coloring-test-assert-no-message "*Warnings*")
675 (context-coloring-test-assert-face 0 "#cccccc")
676 (context-coloring-test-assert-face 1 "#dddddd")))
678 (context-coloring-test-deftest-define-theme pre-recede
680 (context-coloring-define-theme
685 (context-coloring-test-deftheme theme)
686 (custom-theme-set-faces
688 '(context-coloring-level-0-face ((t (:foreground "#cccccc"))))
689 '(context-coloring-level-1-face ((t (:foreground "#dddddd")))))
691 (context-coloring-test-assert-no-message "*Warnings*")
692 (context-coloring-test-assert-face 0 "#cccccc")
693 (context-coloring-test-assert-face 1 "#dddddd")))
695 (context-coloring-test-deftest-define-theme pre-recede-delayed-application
697 (context-coloring-define-theme
702 (context-coloring-test-deftheme theme)
704 (context-coloring-test-assert-no-message "*Warnings*")
705 (context-coloring-test-assert-face 0 "#aaaaaa")
706 (context-coloring-test-assert-face 1 "#bbbbbb")))
708 (context-coloring-test-deftest-define-theme post-recede
710 (context-coloring-test-deftheme theme)
711 (custom-theme-set-faces
713 '(context-coloring-level-0-face ((t (:foreground "#aaaaaa"))))
714 '(context-coloring-level-1-face ((t (:foreground "#bbbbbb")))))
715 (context-coloring-define-theme
720 (context-coloring-test-assert-no-message "*Warnings*")
721 (context-coloring-test-assert-face 0 "#aaaaaa")
722 (context-coloring-test-assert-face 1 "#bbbbbb")
724 (context-coloring-test-assert-no-message "*Warnings*")
725 (context-coloring-test-assert-face 0 "#aaaaaa")
726 (context-coloring-test-assert-face 1 "#bbbbbb")))
728 (context-coloring-test-deftest-define-theme recede-not-defined
730 (context-coloring-test-deftheme theme)
731 (custom-theme-set-faces
733 '(foo-face ((t (:foreground "#ffffff")))))
734 (context-coloring-define-theme
739 (context-coloring-test-assert-no-message "*Warnings*")
740 (context-coloring-test-assert-face 0 "#aaaaaa")
741 (context-coloring-test-assert-face 1 "#bbbbbb")
743 (context-coloring-test-assert-no-message "*Warnings*")
744 (context-coloring-test-assert-face 0 "#aaaaaa")
745 (context-coloring-test-assert-face 1 "#bbbbbb")))
747 (context-coloring-test-deftest-define-theme unintentional-obstinance
749 (context-coloring-define-theme
753 (context-coloring-test-deftheme theme)
754 (custom-theme-set-faces
756 '(context-coloring-level-0-face ((t (:foreground "#cccccc"))))
757 '(context-coloring-level-1-face ((t (:foreground "#dddddd")))))
759 (context-coloring-test-assert-defined-warning theme)
760 (context-coloring-test-assert-face 0 "#aaaaaa")
761 (context-coloring-test-assert-face 1 "#bbbbbb")))
763 (context-coloring-test-deftest-define-theme intentional-obstinance
765 (context-coloring-define-theme
770 (context-coloring-test-deftheme theme)
771 (custom-theme-set-faces
773 '(context-coloring-level-0-face ((t (:foreground "#cccccc"))))
774 '(context-coloring-level-1-face ((t (:foreground "#dddddd")))))
776 (context-coloring-test-assert-no-message "*Warnings*")
777 (context-coloring-test-assert-face 0 "#aaaaaa")
778 (context-coloring-test-assert-face 1 "#bbbbbb")))
780 (defun context-coloring-test-assert-maximum-face (maximum &optional negate)
781 "Assert that `context-coloring-maximum-face' is MAXIMUM, or the
782 inverse if NEGATE is non-nil."
783 (when (funcall (if negate #'identity #'not)
784 (eq context-coloring-maximum-face maximum))
785 (ert-fail (format (concat "Expected `context-coloring-maximum-face' "
788 (if negate "not " "") maximum
791 (format "was `%s'" context-coloring-maximum-face))))))
793 (defun context-coloring-test-assert-not-maximum-face (&rest arguments)
794 "Assert that `context-coloring-maximum-face' is not MAXIMUM.
795 Apply ARGUMENTS to `context-coloring-test-assert-maximum-face',
797 (apply #'context-coloring-test-assert-maximum-face
798 (append arguments '(t))))
800 (context-coloring-test-deftest-define-theme disable-cascade
802 (let ((maximum-face-value 9999))
803 (setq context-coloring-maximum-face maximum-face-value)
804 (context-coloring-test-deftheme theme)
805 (context-coloring-define-theme
809 (let ((second-theme (context-coloring-test-get-next-theme)))
810 (context-coloring-test-deftheme second-theme)
811 (context-coloring-define-theme
816 (let ((third-theme (context-coloring-test-get-next-theme)))
817 (context-coloring-test-deftheme third-theme)
818 (context-coloring-define-theme
825 (enable-theme second-theme)
826 (enable-theme third-theme)
827 (disable-theme third-theme)
828 (context-coloring-test-assert-face 0 "#cccccc")
829 (context-coloring-test-assert-face 1 "#dddddd")
830 (context-coloring-test-assert-face 2 "#eeeeee")
831 (context-coloring-test-assert-maximum-face 2))
832 (disable-theme second-theme)
833 (context-coloring-test-assert-face 0 "#aaaaaa")
834 (context-coloring-test-assert-face 1 "#bbbbbb")
835 (context-coloring-test-assert-maximum-face 1))
836 (disable-theme theme)
837 (context-coloring-test-assert-not-face 0 "#aaaaaa")
838 (context-coloring-test-assert-not-face 1 "#bbbbbb")
839 (context-coloring-test-assert-maximum-face
840 maximum-face-value))))
845 (defun context-coloring-test-assert-position-level (position level)
846 "Assert that POSITION has LEVEL."
847 (let ((face (get-text-property position 'face))
850 (let* ((face-string (symbol-name face))
851 (matches (string-match
852 context-coloring-level-face-regexp
855 (setq actual-level (string-to-number
856 (substring face-string
859 (= level actual-level)))))
860 (ert-fail (format (concat "Expected level at position %s, "
861 "which is \"%s\", to be %s; "
864 (buffer-substring-no-properties position (1+ position)) level
867 (defun context-coloring-test-assert-position-face (position face-regexp)
868 "Assert that the face at POSITION satisfies FACE-REGEXP."
869 (let ((face (get-text-property position 'face)))
871 ;; Pass a non-string to do an `equal' check (against a symbol or nil).
872 (unless (stringp face-regexp)
873 (not (equal face-regexp face)))
874 ;; Otherwise do the matching.
875 (when (stringp face-regexp)
876 (not (string-match-p face-regexp (symbol-name face)))))
877 (ert-fail (format (concat "Expected face at position %s, "
878 "which is \"%s\", to be %s; "
881 (buffer-substring-no-properties position (1+ position)) face-regexp
884 (defun context-coloring-test-assert-position-comment (position)
885 "Assert that the face at POSITION is a comment."
886 (context-coloring-test-assert-position-face
887 position "\\`font-lock-comment\\(-delimiter\\)?-face\\'"))
889 (defun context-coloring-test-assert-position-constant-comment (position)
890 "Assert that the face at POSITION is a constant comment."
891 (context-coloring-test-assert-position-face position '(font-lock-constant-face
892 font-lock-comment-face)))
894 (defun context-coloring-test-assert-position-string (position)
895 "Assert that the face at POSITION is a string."
896 (context-coloring-test-assert-position-face position 'font-lock-string-face))
898 (defun context-coloring-test-assert-position-nil (position)
899 "Assert that the face at POSITION is nil."
900 (context-coloring-test-assert-position-face position nil))
902 (defun context-coloring-test-assert-coloring (map)
903 "Assert that the current buffer's coloring will match MAP.
905 MAP's newlines should correspond to the current fixture.
907 The following characters appearing in MAP assert coloring for
908 corresponding points in the fixture:
910 0-9: Level equals number.
911 C: Face is constant comment.
916 Any other characters are discarded. Characters \"x\" and any
917 other non-letters are guaranteed to always be discarded."
918 ;; Omit the superfluous, formatting-related leading newline. Can't use
919 ;; `save-excursion' here because if an assertion fails it will cause future
920 ;; tests to get messed up.
921 (goto-char (point-min))
922 (let* ((map (substring map 1))
926 (while (< index (length map))
927 (setq char-string (substring map index (1+ index)))
928 (setq char (string-to-char char-string))
937 (context-coloring-test-assert-position-level
938 (point) (string-to-number char-string))
940 ;; 'C' = Constant comment
942 (context-coloring-test-assert-position-constant-comment (point))
946 (context-coloring-test-assert-position-comment (point))
950 (context-coloring-test-assert-position-nil (point))
954 (context-coloring-test-assert-position-string (point))
958 (setq index (1+ index)))))
960 (context-coloring-test-deftest-js-js2 function-scopes
962 (context-coloring-test-assert-coloring "
963 000 0 0 11111111 11 110
965 111 1 1 22222222 22 221
969 (context-coloring-test-deftest-js-js2 global
971 (context-coloring-test-assert-coloring "
973 111 1 1 00000001xxx11
976 (context-coloring-test-deftest-js2 block-scopes
978 (context-coloring-test-assert-coloring "
986 (setq context-coloring-js-block-scopes t))
988 (setq context-coloring-js-block-scopes nil)))
990 (context-coloring-test-deftest-js-js2 catch
992 (context-coloring-test-assert-coloring "
1002 (context-coloring-test-deftest-js-js2 key-names
1004 (context-coloring-test-assert-coloring "
1012 (context-coloring-test-deftest-js-js2 property-lookup
1014 (context-coloring-test-assert-coloring "
1021 (context-coloring-test-deftest-js-js2 key-values
1023 (context-coloring-test-assert-coloring "
1033 (context-coloring-test-deftest-js-js2 syntactic-comments-and-strings
1035 (context-coloring-test-assert-coloring "
1040 :fixture "comments-and-strings.js")
1042 (context-coloring-test-deftest-js-js2 syntactic-comments
1044 (context-coloring-test-assert-coloring "
1049 :fixture "comments-and-strings.js"
1051 (setq context-coloring-syntactic-strings nil))
1053 (setq context-coloring-syntactic-strings t)))
1055 (context-coloring-test-deftest-js-js2 syntactic-strings
1057 (context-coloring-test-assert-coloring "
1062 :fixture "comments-and-strings.js"
1064 (setq context-coloring-syntactic-comments nil))
1066 (setq context-coloring-syntactic-comments t)))
1068 (context-coloring-test-deftest-js2 unterminated-comment
1069 ;; As long as `add-text-properties' doesn't signal an error, this test passes.
1072 (context-coloring-test-deftest-emacs-lisp defun
1074 (context-coloring-test-assert-coloring "
1075 111111 000 1111 111 111111111 1111
1076 11 111 111 111 000011
1084 (context-coloring-test-deftest-emacs-lisp defadvice
1086 (context-coloring-test-assert-coloring "
1087 1111111111 0 1111111 111111 11111 111 111111111
1091 (context-coloring-test-deftest-emacs-lisp lambda
1093 (context-coloring-test-assert-coloring "
1094 00000000 1111111 1111
1095 11111111 11 2222222 2222
1096 222 22 12 2221 111 0 00")))
1098 (context-coloring-test-deftest-emacs-lisp quote
1100 (context-coloring-test-assert-coloring "
1101 (xxxxx 0000000 00 00000)
1102 (xxx () (xxxxxxxxx (,0000)))
1107 111111 1 1111111111 11 111 1 111 1 00001 10000 11 00001 1 10000
1115 (xxxxxx () 111111 11111)")))
1117 (context-coloring-test-deftest-emacs-lisp splice
1119 (context-coloring-test-assert-coloring "
1121 111111 00001 100001)")))
1123 (context-coloring-test-deftest-emacs-lisp comment
1125 ;; Just check that the comment isn't parsed syntactically.
1126 (context-coloring-test-assert-coloring "
1128 (xx (x xxxxx-xxxx xx) cccccccccc
1129 11 00000-0000 11))) cccccccccc")))
1131 (context-coloring-test-deftest-emacs-lisp string
1133 (context-coloring-test-assert-coloring "
1135 (xxxxxx x x sss 1 0 sssss 0 1 sssssss11")))
1137 (context-coloring-test-deftest-emacs-lisp ignored
1139 (context-coloring-test-assert-coloring "
1141 (x x 1 11 11 111 111 11 11 11 1 111 (1 1 1)))")))
1143 (context-coloring-test-deftest-emacs-lisp sexp
1145 (context-coloring-test-assert-coloring "
1151 (context-coloring-test-deftest-emacs-lisp let
1153 (context-coloring-test-assert-coloring "
1166 (context-coloring-test-deftest-emacs-lisp let*
1168 (context-coloring-test-assert-coloring "
1172 1111 1 1 1 0 0 00001
1178 2222 1 1 2 2 2 000022
1179 1111 1 1 1 0 0 000011")))
1181 (context-coloring-test-deftest-emacs-lisp cond
1183 (context-coloring-test-assert-coloring "
1193 (context-coloring-test-deftest-emacs-lisp condition-case
1195 (context-coloring-test-assert-coloring "
1199 1111111 111111 111 000011
1201 (111111111-1111-111111-11111 111
1204 (11111 (xxx () 222))
1207 (context-coloring-test-deftest-emacs-lisp dolist
1209 (context-coloring-test-assert-coloring "
1211 2222222 2222 1111 2222222
1212 3333333 33 33 222 1111 2222223321")))
1214 (defun context-coloring-test-insert-unread-space ()
1215 "Simulate the insertion of a space as if by a user."
1216 (setq unread-command-events (cons '(t . 32)
1217 unread-command-events)))
1219 (defun context-coloring-test-remove-faces ()
1220 "Remove all faces in the current buffer."
1221 (remove-text-properties (point-min) (point-max) '(face nil)))
1223 (context-coloring-test-deftest-emacs-lisp iteration
1225 (let ((context-coloring-elisp-sexps-per-pause 2))
1226 (context-coloring-colorize)
1227 (context-coloring-test-assert-coloring "
1230 (context-coloring-test-remove-faces)
1231 (context-coloring-test-insert-unread-space)
1232 (context-coloring-colorize)
1233 ;; Coloring is interrupted after the first "sexp" (the comment in this
1235 (context-coloring-test-assert-coloring "
1239 (context-coloring-test-deftest-emacs-lisp changed
1241 (context-coloring-test-remove-faces)
1243 (goto-char (point-min))
1244 (forward-line (1- 3))
1246 ;; Mock `pos-visible-in-window-p' because in batch mode `get-buffer-window'
1247 ;; returns nil. Emacs must not have a window in that environment.
1248 (cl-letf (((symbol-function 'pos-visible-in-window-p)
1252 ;; First and third calls start from center. Second and
1253 ;; fourth calls are made immediately after moving past
1254 ;; the first defun in either direction "off screen".
1260 (setq calls (1+ calls)))))))
1261 (context-coloring-colorize))
1262 (context-coloring-test-assert-coloring "
1267 nnnnn n nnn nnnnnnnn")))
1269 (context-coloring-test-deftest-emacs-lisp unbalanced-parenthesis
1271 (context-coloring-test-assert-coloring "
1275 (defun context-coloring-test-eval-expression-let ()
1276 "Test that coloring works inside `eval-expression.'"
1277 (let ((input "(ignore-errors (let (a) (message a free)))"))
1279 (context-coloring-colorize)
1280 (context-coloring-test-assert-coloring "
1281 xxxx: 0000000-000000 1111 111 11111111 1 0000110")))
1283 (context-coloring-test-deftest-eval-expression let
1286 'eval-expression-minibuffer-setup-hook
1287 #'context-coloring-test-eval-expression-let)
1290 [?\C-u] ;; Don't output to stdout.
1292 (vconcat "eval-expression"))))
1295 'eval-expression-minibuffer-setup-hook
1296 #'context-coloring-test-eval-expression-let)))
1298 (provide 'context-coloring-test)
1300 ;;; context-coloring-test.el ends here