branch: externals/matlab-mode commit decea985e47ad62ff2308fbd253b8d13bfc78104 Author: John Ciolfi <john.ciolfi...@gmail.com> Commit: John Ciolfi <john.ciolfi...@gmail.com>
matlab-ts-mode: update tests to use ert, fix electric pair issue With the latest matlab tree-sitter parser, items like s = ' are now (correctly) have ERROR nodes. This updates the electric-pair handling to support that. --- contributing/treesit-mode-how-to.org | 591 +++------------ matlab-ts-mode.el | 11 +- tests/metest.el | 2 +- tests/t-utils.el | 804 +++++++++++++-------- tests/test-matlab-ts-mode-comments.el | 31 +- tests/test-matlab-ts-mode-electric-pair.el | 33 +- tests/test-matlab-ts-mode-fill-paragraph.el | 29 +- tests/test-matlab-ts-mode-font-lock.el | 90 +-- tests/test-matlab-ts-mode-imenu.el | 29 +- tests/test-matlab-ts-mode-indent.el | 52 +- tests/test-matlab-ts-mode-on-save-fixes.el | 34 +- tests/test-matlab-ts-mode-outline.el | 33 +- tests/test-matlab-ts-mode-page.el | 33 +- .../show_paren_string.m | 7 +- .../show_paren_string_expected.org | 93 ++- tests/test-matlab-ts-mode-show-paren.el | 27 +- tests/test-matlab-ts-mode-syntax-table.el | 28 +- tests/test-matlab-ts-mode-thing-settings.el | 34 +- tests/test-matlab-ts-mode-treesit-defun-name.el | 32 +- 19 files changed, 941 insertions(+), 1052 deletions(-) diff --git a/contributing/treesit-mode-how-to.org b/contributing/treesit-mode-how-to.org index d9e47e7669..fd6497a52c 100644 --- a/contributing/treesit-mode-how-to.org +++ b/contributing/treesit-mode-how-to.org @@ -369,58 +369,47 @@ To run your tests in a build system, use #+end_src #+begin_src emacs-lisp - ;;; test-LANGUAGE-ts-mode-font-lock.el --- Test LANGUAGE-ts-mode font-lock -*- lexical-binding: t -*- - - ;;; Commentary: - - ;;; Code: - (require 't-utils) (require 'language-ts-mode) - (cl-defun test-language-ts-mode-font-lock (&optional lang-file) - "Test font-lock using ./test-language-ts-mode-font-lock-files/NAME.lang. - Compare ./test-language-ts-mode-font-lock-files/NAME.lang against - ./test-language-ts-mode-font-lock-files/NAME_expected.txt, where + (defvar test-LANGUAGE-ts-mode-font-lock--file nil) + + (defun test-LANGUAGE-ts-mode-font-lock--file (lang-file) + "Test an individual LANG-FILE. + This is provided for debugging. + M-: (test-LANGUAGE-ts-mode-font-lock--file \"test-LANGUAGE-ts-mode-font-lock-files/LANG-FILE\")" + (let ((test-LANGUAGE-ts-mode-font-lock--file lang-file)) + (ert-run-tests-interactively "test-LANGUAGE-ts-mode-font-lock"))) + + (ert-deftest test-LANGUAGE-ts-mode-font-lock () + "Test font-lock using ./test-LANGUAGE-ts-mode-font-lock-files/NAME.lang. + Compare font of ./test-LANGUAGE-ts-mode-font-lock-files/NAME.lang against + ./test-LANGUAGE-ts-mode-font-lock-files/NAME_expected.txt, where NAME_expected.txt is of same length as NAME.lang where each source character in NAME.lang is replaced with a character code representing the font-lock face used for said source character. The mapping is defined - by the code-to-face alist setup by this function. If LANG-FILE is not - provided, loop comparing all - ./test-language-ts-mode-font-lock-files/NAME.lang files. + by the code-to-face alist setup by this function. This loops + on all ./test-LANGUAGE-ts-mode-font-lock-files/NAME.lang files. - To add a test, create - ./test-language-ts-mode-font-lock-files/NAME.lang + To add a test, createp + ./test-LANGUAGE-ts-mode-font-lock-files/NAME.lang and run this function. The baseline is saved for you as - ./test-language-ts-mode-font-lock-files/NAME_expected.lang~ + ./test-LANGUAGE-ts-mode-font-lock-files/NAME_expected.txt~ after validating it, rename it to - ./test-language-ts-mode-font-lock-files/NAME_expected.lang" - - (let ((test-name "test-language-ts-mode-font-lock")) - (when (not (t-utils-is-treesit-available 'language test-name)) - (cl-return-from test-language-ts-mode-font-lock)) - - (let* ((lang-files (t-utils-get-files (concat test-name "-files") "\\.lang$" nil lang-file)) - (code-to-face '( - ("b" . font-lock-bracket-face) - ("B" . font-lock-builtin-face) - ("c" . font-lock-comment-face) - ("C" . font-lock-comment-delimiter-face) - ("d" . default) - ("D" . font-lock-delimiter-face) - ("f" . font-lock-function-name-face) - ("h" . font-lock-doc-face) - ("k" . font-lock-keyword-face) - ("n" . font-lock-constant-face) - ("s" . font-lock-string-face) - ("P" . font-lock-property-name-face) - ("t" . font-lock-type-face) - ("v" . font-lock-variable-name-face) - ("w" . font-lock-warning-face) - ))) - (t-utils-test-font-lock test-name lang-files code-to-face)) - ;; return "success" for M-: (test-language-ts-mode-font-lock) - "success")) + ./test-LANGUAGE-ts-mode-font-lock-files/NAME_expected.txt" + + (let ((test-name "test-LANGUAGE-ts-mode-font-lock")) + (when (t-utils-is-treesit-available 'LANGUAGE test-name) + (let* ((LANGUAGE-ts-mode-font-lock-level 4) + (lang-files (t-utils-get-files (concat test-name "-files") "\\.lang\\'" nil + test-LANGUAGE-ts-mode-font-lock--file)) + (code-to-face '( + ("b" . font-lock-bracket-face) + ("B" . font-lock-builtin-face) + ("c" . font-lock-comment-face) + ;; <add more as needed> + ))) + (t-utils-test-font-lock test-name lang-files code-to-face))))) (provide 'test-language-ts-mode-font-lock) ;;; test-language-ts-mode-font-lock.el ends here @@ -728,21 +717,24 @@ We use a similar pattern for our indent tests: where test-LANGUAGE-ts-mode-indent.el contains: #+begin_src emacs-lisp - ;;; test-LANGUAGE-ts-mode-indent.el --- Test LANGUAGE-ts-mode indent -*- lexical-binding: t -*- - - ;;; Commentary: - - ;;; Code: - (require 't-utils) (require 'LANGUAGE-ts-mode) - (cl-defun test-LANGUAGE-ts-mode-indent (&optional lang-file) + (defvar test-LANGUAGE-ts-mode-indent--file nil) + + (defun test-LANGUAGE-ts-mode-indent--file (lang-file) + "Test an individual LANG-FILE. + This is provided for debugging. + M-: (test-LANGUAGE-ts-mode-indent--file \"test-LANGUAGE-ts-mode-indent-files/LANG-FILE\")" + (let ((test-LANGUAGE-ts-mode-indent--file lang-file)) + (ert-run-tests-interactively "test-LANGUAGE-ts-mode-indent"))) + + (ert-deftest test-LANGUAGE-ts-mode-indent () "Test indent using ./test-LANGUAGE-ts-mode-indent-files/NAME.lang. Compare indent of ./test-LANGUAGE-ts-mode-indent-files/NAME.lang against ./test-LANGUAGE-ts-mode-indent-files/NAME_expected.lang. Indent is done two - ways as described in `t-utils-test-indent'. If LANG-FILE is not provided, - loop comparing all ./test-LANGUAGE-ts-mode-indent-files/NAME.lang files. + ways as described in `t-utils-test-indent'. This loops + on all ./test-LANGUAGE-ts-mode-indent-files/NAME.lang files. To add a test, create ./test-LANGUAGE-ts-mode-indent-files/NAME.lang @@ -751,29 +743,12 @@ where test-LANGUAGE-ts-mode-indent.el contains: after validating it, rename it to ./test-LANGUAGE-ts-mode-indent-files/NAME_expected.lang" - (let ((test-name "test-LANGUAGE-ts-mode-indent") - (LANGUAGE-ts-mode--indent-assert t)) - - (when (not (t-utils-is-treesit-available 'LANGUAGE test-name)) - (cl-return-from test-LANGUAGE-ts-mode-font-lock)) - - (let ((lang-files (t-utils-get-files (concat test-name "-files") "\\.lang$" - "_expected\\.lang$" ;; skip our *_expected.lang baselines - lang-file)) - (line-manipulator (lambda () - ;; Workaround - ;; https://github.com/acristoffers/tree-sitter-LANGUAGE/issues/32 - (goto-char (point-min)) - (while (not (eobp)) - (let* ((node (treesit-node-at (point))) - (parent (and node (treesit-node-parent node)))) - (when (string= (treesit-node-type parent) "ERROR") - (insert " "))) - (forward-line))))) - - (t-utils-test-indent test-name lang-files line-manipulator))) - ;; return "success" for M-: (test-LANGUAGE-ts-mode-font-lock) - "success") + (let ((test-name "test-LANGUAGE-ts-mode-indent")) + (when (t-utils-is-treesit-available 'LANGUAGE test-name) + (let ((lang-files (t-utils-get-files (concat test-name "-files") "\\.lang\\'" + "_expected\\.lang\\'" ;; skip our *_expected.lang baselines + test-LANGUAGE-ts-mode-indent--file))) + (t-utils-test-indent test-name lang-files))))) #+end_src @@ -814,7 +789,7 @@ directory recursively. large number of LANGUAGE files has good probablity of hitting this. If parent doesn't have a previous sibling, we'll get "error (void-function stirng-match-p)." -Here's our sweep test: +Our indent sweep test: #+begin_src emacs-lisp (require 't-utils) @@ -1073,22 +1048,25 @@ This is good practice because these are fundamental to Emacs. We follow a similar pattern for writing syntax table tests. #+begin_src emacs-lisp - ;;; test-LANGUAGE-ts-mode-syntax-table.el --- -*- lexical-binding: t -*- - - ;;; Commentary: - - ;;; Code: - (require 't-utils) (require 'LANGUAGE-ts-mode) - (cl-defun test-LANGUAGE-ts-mode-syntax-table (&optional lang-file) + (defvar test-LANGUAGE-ts-mode-syntax-table--file nil) + + (defun test-LANGUAGE-ts-mode-syntax-table--file (lang-file) + "Test an individual LANG-FILE. + This is provided for debugging. + M-: (test-LANGUAGE-ts-mode-syntax-table--file \"test-LANGUAGE-ts-mode-syntax-table-files/LANG-FILE\")" + (let ((test-LANGUAGE-ts-mode-syntax-table--file lang-file)) + (ert-run-tests-interactively "test-LANGUAGE-ts-mode-syntax-table"))) + + (ert-deftest test-LANGUAGE-ts-mode-syntax-table () "Test syntax-table using ./test-LANGUAGE-ts-mode-syntax-table-files/NAME.lang. Compare ./test-LANGUAGE-ts-mode-syntax-table-files/NAME.lang against ./test-LANGUAGE-ts-mode-syntax-table-files/NAME_expected.txt, where - NAME_expected.txt gives the `syntax-ppss` value of each character in - NAME.lang. If LANG-FILE is not provided, loop comparing all - ./test-LANGUAGE-ts-mode-indent-files/NAME.lang files. + NAME_expected.txt gives the `syntax-ppss' value of each character in + NAME.lang. This loops on all ./test-LANGUAGE-ts-mode-syntax-table-files/NAME.lang + files. To add a test, create ./test-LANGUAGE-ts-mode-syntax-table-files/NAME.lang @@ -1098,18 +1076,10 @@ We follow a similar pattern for writing syntax table tests. ./test-LANGUAGE-ts-mode-syntax-table-files/NAME_expected.lang" (let ((test-name "test-LANGUAGE-ts-mode-syntax-table")) - (when (not (t-utils-is-treesit-available 'LANGUAGE test-name)) - (cl-return-from test-LANGUAGE-ts-mode-syntax-table)) - - (let ((lang-files (t-utils-get-files (concat test-name "-files") "\\.lang$" nil lang-file))) - (t-utils-test-syntax-table test-name lang-files))) - - ;; return "success" for M-: (test-LANGUAGE-ts-mode-font-lock) - "success") - - (provide 'test-LANGUAGE-ts-mode-syntax-table) - ;;; test-LANGUAGE-ts-mode-syntax-table.el ends here - + (when (t-utils-is-treesit-available 'LANGUAGE test-name) + (let ((lang-files (t-utils-get-files (concat test-name "-files") "\\.lang\\'" nil + test-LANGUAGE-ts-mode-syntax-table--file))) + (t-utils-test-syntax-table test-name lang-files))))) #+end_src * Setup: treesit-thing-settings @@ -1456,31 +1426,36 @@ where =tests/test-LANUGAGE-ts-mode-show-paren.el= contains: (require 't-utils) (require 'LANGUAGE-ts-mode) - (cl-defun test-LANGUAGE-ts-mode-show-paren (&optional lang-file) - "Test defun movement using ./test-LANGUAGE-ts-mode-show-paren-files/NAME.EXT. - Using ./test-LANGUAGE-ts-mode-show-paren-files/NAME.EXT, compare defun - movement against + (defvar test-LANGUAGE-ts-mode-show-paren--file nil) + + (defun test-LANGUAGE-ts-mode-show-paren--file (lang-file) + "Test an individual LANG-FILE. + This is provided for debugging. + M-: (test-LANGUAGE-ts-mode-show-paren--file \"test-LANGUAGE-ts-mode-show-paren-files/LANG-FILE\")" + (let ((test-LANGUAGE-ts-mode-show-paren--file lang-file)) + (ert-run-tests-interactively "test-LANGUAGE-ts-mode-show-paren"))) + + (ert-deftest test-LANGUAGE-ts-mode-show-paren () + "Test show paren mode using ./test-LANGUAGE-ts-mode-show-paren-files/NAME.lang. + Using ./test-LANGUAGE-ts-mode-show-paren-files/NAME.lang, result of + `LANGUAGE-ts-mode--show-paren-or-block' for `show-paren-mode' against ./test-LANGUAGE-ts-mode-show-paren-files/NAME_expected.org. If LANG-FILE is not provided, loop comparing all - ./test-LANGUAGE-ts-mode-show-paren-files/NAME.EXT files. + ./test-LANGUAGE-ts-mode-show-paren-files/NAME.lang files. To add a test, create - ./test-LANGUAGE-ts-mode-show-paren-files/NAME.EXT + ./test-LANGUAGE-ts-mode-show-paren-files/NAME.lang and run this function. The baseline is saved for you as ./test-LANGUAGE-ts-mode-show-paren-files/NAME_expected.org~ after validating it, rename it to ./test-LANGUAGE-ts-mode-show-paren-files/NAME_expected.org" (let ((test-name "test-LANGUAGE-ts-mode-show-paren")) + (when (t-utils-is-treesit-available 'LANGUAGE test-name) - (when (not (t-utils-is-treesit-available 'LANGUAGE test-name)) - (cl-return-from test-LANGUAGE-ts-mode-font-lock)) - - (let ((lang-files (t-utils-get-files (concat test-name "-files") "\\.EXT$" nil lang-file))) - (t-utils-test-xr test-name lang-files))) - "success") - - (provide 'test-LANGUAGE-ts-mode-show-paren) + (let ((lang-files (t-utils-get-files (concat test-name "-files") "\\.lang\\'" nil + test-LANGUAGE-ts-mode-show-paren--file))) + (t-utils-test-xr test-name lang-files))))) #+end_src Each =tests/test-LANUGAGE-ts-mode-show-paren-files/show_paren_ITEM.EXT= file looks like the @@ -1587,395 +1562,11 @@ well worth writing a tree-sitter mode. * Appendix: t-utils.el -#+begin_src emacs-lisp - ;;; t-utils.el --- Test utilities -*- lexical-binding: t -*- - ;; - ;; Copyright 2025 Free Software Foundation, Inc. - ;; - ;; This program is free software; you can redistribute it and/or modify - ;; it under the terms of the GNU General Public License as published by - ;; the Free Software Foundation; either version 3, or (at your option) - ;; any later version. - ;; - ;; This program is distributed in the hope that it will be useful, - ;; but WITHOUT ANY WARRANTY; without even the implied warranty of - ;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - ;; GNU General Public License for more details. - ;; - ;; You should have received a copy of the GNU General Public License - ;; along with GNU Emacs; see the file COPYING. If not, write to - ;; the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. - ;; - - ;;; Commentary: - ;; - ;; Test utilities used by test-*.el files. - ;; +See [[file:../tests/t-utils.el]]. For now copy this to your repository. It would be nice to integrate +t-utils.el into the Emacs ert package, perhaps ert-ts.el? Alternatively, we could create a separate +ELPA package for it? - ;;; Code: - - (require 'cl-seq) - - ;; Add abs-path of ".." to load-path so we can require packages from above us. - (let* ((lf (or load-file-name (buffer-file-name (current-buffer)))) - (d1 (file-name-directory lf)) - (parent-dir (expand-file-name (file-name-directory (directory-file-name d1))))) - (add-to-list 'load-path parent-dir t)) - - (defun t-utils-trim () - "Trim trailing whitespace and lines with utf-8-unix encoding." - (setq buffer-file-coding-system 'utf-8-unix) - (let ((delete-trailing-lines t)) - (delete-trailing-whitespace (point-min) (point-max)))) - - (defun t-utils-get-files (subdir base-regexp &optional skip-regexp file-to-use) - "Return list of full paths, /path/to/SUBDIR/FILE. - The FILE basenames returned match BASE-REGEXP. - Files matching optional SKIP-REGEXP are ignored. - Optional FILE-TO-USE narrow the list of full paths to that file - and the result is a list of one file. - - For example, - (t-utils-get-files \"test-LANGUAGE-ts-mode-files\" - \"*\\.lang$\" \"_expected\\.lang$\" file-to-use) - will return a list of /path/to/test-NAME/*.lang files, skipping - all *_expected.lang files when file-to-use is nil." - - (let ((files (cl-delete-if (lambda (file) - (and skip-regexp - (string-match skip-regexp file))) - (directory-files subdir t base-regexp)))) - (when file-to-use - (let ((true-file-to-use (file-truename file-to-use))) - (when (not (member true-file-to-use files)) - (if (file-exists-p true-file-to-use) - (error "File %s, resolved to %s, is not a valid selection. - It should be one of %S" file-to-use true-file-to-use files) - (error "File %s does not exist" file-to-use))) - (setq files (list true-file-to-use)))) - files)) - - (defun t-utils-is-treesit-available (language test-name) - "Is tree-sitter ready for LANGUAGE? - If not available a message saying skipping TEST-NAME is displayed." - (let ((available (and (>= emacs-major-version 30) ;; treesit package comes with Emacs 30 - (progn - (require 'treesit) - (when (fboundp 'treesit-ready-p) - (treesit-ready-p language t)))))) - (when (not available) - (message "skipping-test: %s - %S tree sitter not available." test-name language)) - available)) - - (defun t-utils-run (&optional match) - "Run test files in current directory matching regexp, MATCH. - If optional MATCH is non-nil, only run test file names whose - non-directory part matches the regexp, MATCH. For example, - \"^test-foo.*\\\\.el$\" would run tell t-run to run \"test-foo*.el$\" - files. The default MATCH is \"^test-.*\\\\.el$\"" - (when (not match) - (setq match "^test-.*\\.el$")) - - (dolist (test-file (directory-files "." t match)) - (when (not (load-file test-file)) - (error "Failed to load %s" test-file)) - (let ((test-fun (intern - (replace-regexp-in-string "\\.el" "" (file-name-nondirectory test-file))))) - (funcall test-fun)))) - - (defun t-utils--took (start-time) - "Return \"- took N seconds\". - N is `current-time' minus START-TIME." - (format "- took %.2f seconds" (float-time (time-subtract (current-time) start-time)))) - - (defun t-utils-test-font-lock (test-name lang-files code-to-face) - "Test font-lock using on each lang-file in LANG-FILES list. - Foreach file in LANG-FILES compare the file against NAME_expected.txt, where - NAME the file name minus the extension. NAME_expected.txt is of same - length as the file and has a character for each face setup by font-lock. - CODE_TO_FACE is an alist where each elment is (CHAR . FACE). - TEST-NAME is used when displaying messages. - - If NAME_expected.txt does not exists or doesn't match the results we - got, a NAME_expected.txt~ will be generated. After reviewing - NAME_expected.txt~, you should rename it to NAME_expected.txt or fix - your code and rerun the test. - - For example, suppose our LANG-FILE contains - int foo(void) { - return 1; - } - our NAME_expected.txt will contain: - kkk fffDkkkkD b - kkkkkk nD - D - where int and void are keywords, etc. and CODE-TO-FACE contains: - \\='((\"b\" . font-lock-bracket-face) - (\"d\" . default) - (\"D\" . font-lock-delimiter-face) - (\"f\" . font-lock-function-name-face) - (\"k\" . font-lock-keyword-face) - (\"n\" . font-lock-constant-face))" - - (let ((face-to-code (mapcar (lambda (pair) - (cons (cdr pair) (car pair))) - code-to-face))) - (dolist (lang-file lang-files) - (save-excursion - (let ((start-time (current-time))) - (message "START: %s %s" test-name lang-file) - - (when (boundp 'treesit-font-lock-level) - (setq treesit-font-lock-level 4)) - - (find-file lang-file) - - ;; Force font lock to throw catchable errors. - (font-lock-mode 1) - (font-lock-flush (point-min) (point-max)) - (font-lock-ensure (point-min) (point-max)) - - (goto-char (point-min)) - (let* ((got "") - (expected-file (replace-regexp-in-string "\\.[^.]+$" "_expected.txt" - lang-file)) - (got-file (concat expected-file "~")) - (expected (when (file-exists-p expected-file) - (with-temp-buffer - (insert-file-contents-literally expected-file) - (buffer-string))))) - (while (not (eobp)) - (let* ((face (if (face-at-point) (face-at-point) 'default)) - (code (if (looking-at "\\([ \t\n]\\)") - (match-string 1) - (cdr (assoc face face-to-code))))) - (when (not code) - (error "Face, %S, is not in code-to-face alist" face)) - (setq got (concat got code)) - (forward-char) - (when (looking-at "\n") - (setq got (concat got "\n")) - (forward-char)))) - - (when (not (string= got expected)) - (let ((coding-system-for-write 'raw-text-unix)) - (write-region got nil got-file)) - (when (not expected) - (error "Baseline for %s does not exists. \ - See %s and if it looks good rename it to %s" - lang-file got-file expected-file)) - (when (= (length got) (length expected)) - (let* ((diff-idx (1- (compare-strings got nil nil expected nil nil))) - (got-code (substring got diff-idx (1+ diff-idx))) - (got-face (cdr (assoc got-code code-to-face))) - (expected-code (substring expected diff-idx (1+ diff-idx))) - (expected-face (cdr (assoc expected-code code-to-face)))) - (error "Baseline for %s does not match, got: %s, expected: %s. \ - Difference at column %d: got code-to-face (\"%s\" . %S), expected code-to-face (\"%s\" . %S)" - lang-file got-file expected-file - diff-idx - got-code got-face - expected-code expected-face))) - (error "Baseline for %s does not match, lengths are different, got: %s, expected: %s" - lang-file got-file expected-file)) - (kill-buffer)) - (message "PASS: %s %s %s" test-name lang-file (t-utils--took start-time))))))) - - (defun t-utils--test-indent-typing (lang-file lang-file-mode - expected expected-file - &optional line-manipulator) - "Exercise indent by simulating the creation of LANG-FILE via typing. - This compares the simulation of typing LANG-FILE against the - EXPECTED content in EXPECTED-FILE - - The typing occurs in a buffer named \"typing__NAME.EXT\" where NAME.EXT - is the basename of LANG-FILE. - - The typing buffer is initialized with the string-trim'd version of the - non-empty lines of LANG-FILE. If optional LINE-MANIPULATOR function is - specified, it is called with the typing buffer as the current - buffer. LINE-MANIPULATOR should only adjust whitespace in the lines. It - should not add newlines to the buffer. LINE-MANIPULATOR is called from - within a `save-excursion', so your function doesn't need to do that. - - After initializating the typing buffer, it's mode is set to - LANG-FILE-MODE. Each line is then indented via `indent-for-tab-command' - and blank lines are inserted by calling `newline'.`" - - (let* ((typing-lang-file-name (concat "typing__" (file-name-nondirectory lang-file))) - (contents (with-temp-buffer - (insert-file-contents-literally lang-file) - (buffer-substring (point-min) (point-max)))) - (lines (split-string (string-trim contents) "\n"))) - (with-current-buffer (get-buffer-create typing-lang-file-name) - (erase-buffer) - (funcall lang-file-mode) - - ;; Insert the non-empty lines into typing-lang-file-name buffer - (dolist (line lines) - (setq line (string-trim line)) - (when (not (string= line "")) - (insert line "\n"))) - - (goto-char (point-min)) - - (when line-manipulator - (save-excursion - (funcall line-manipulator))) - - ;; Now indent each line and insert the empty ("") lines into typing-lang-file-buffer - ;; as we indent. This exercises the RET and TAB behaviors which cause different - ;; tree-sitter nodes to be provided to the indent engine rules. - (while (not (eobp)) - - (call-interactively #'indent-for-tab-command) ;; TAB on code just added - - ;; While next line in our original contents is a newline insert "\n" - (while (let ((next-line (nth (line-number-at-pos (point)) lines))) - (and next-line (string-match-p "^[ \t\r]*$" next-line))) - (goto-char (line-end-position)) - ;; RET to add blank line - (call-interactively #'newline) - ;; TAB on the same blank line can result in different tree-sitter nodes than - ;; the RET, so exercise that. - (call-interactively #'indent-for-tab-command)) - (forward-line)) - - (t-utils-trim) - - (let ((typing-got (buffer-substring (point-min) (point-max)))) - (set-buffer-modified-p nil) - (kill-buffer) - (when (not (string= typing-got expected)) - (let ((coding-system-for-write 'raw-text-unix) - (typing-got-file (replace-regexp-in-string "\\.\\([^.]+\\)$" - "_typing.\\1~" - lang-file))) - (write-region typing-got nil typing-got-file) - (error "Typing %s line-by-line does not match %s, we got %s" lang-file expected-file - typing-got-file))))))) - - (defun t-utils-test-indent (test-name lang-files &optional line-manipulator) - "Test indent on each file in LANG-FILES list. - Compare indent of each NAME.EXT in LANG-FILES against NAME_expected.EXT. - TEST-NAME is used in messages. - - If NAME_expected.EXT does not exist or the indent of NAME.EXT doesn't - match NAME_expected.txt, NAME_expected.EXT~ will be created. You are - then instructured to validate the indent and rename NAME_expected.EXT~ - to NAME_expected.EXT. - - To add a test for TEST-NAME.el, in it's corresponding TEST-NAME-files/ - directory, create TEST-NAME-files/NAME.EXT, then run the test. Follow - the messages to accept the generated baseline after validating it. - - Two methods are used to indent each file in LANG-FILES, - 1. (indent-region (point-min) (point-man)) - 2. Simulation of typing lang-file to exercise TAB and RET, - see `t-utils--test-indent-typing'. In tree-sitter modes, TAB and RET - need to be handled and this verifies they are handled. - - See `t-utils--test-indent-type' for LINE-MANIPULATOR." - - (dolist (lang-file lang-files) - (let* ((expected-file (replace-regexp-in-string "\\.\\([^.]+\\)$" "_expected.\\1" lang-file)) - (expected (when (file-exists-p expected-file) - (with-temp-buffer - (insert-file-contents-literally expected-file) - (buffer-string)))) - lang-file-major-mode) - - ;; Indent lang-file - (save-excursion - (let ((start-time (current-time))) - (message "START: %s <indent-region> %s" test-name lang-file) - (find-file lang-file) - (setq lang-file-major-mode major-mode) - (indent-region (point-min) (point-max)) - (t-utils-trim) - (let ((got (buffer-substring (point-min) (point-max))) - (got-file (concat expected-file "~"))) - (set-buffer-modified-p nil) - (kill-buffer) - (when (not (string= got expected)) - (let ((coding-system-for-write 'raw-text-unix)) - (write-region got nil got-file)) - (when (not expected) - (error "Baseline for %s does not exists - if %s looks good rename it to %s" - lang-file got-file expected-file)) - (error "Baseline for %s does not match, got: %s, expected: %s" - lang-file got-file expected-file))) - (message "PASS: %s <indent-region> %s %s" test-name lang-file - (t-utils--took start-time)))) - - ;; Now, simulate typing lang-file and indent it (exercise TAB and RET) - (let ((start-time (current-time))) - (message "START: %s <indent-via-typing> %s" test-name lang-file) - (t-utils--test-indent-typing lang-file lang-file-major-mode - expected expected-file - line-manipulator) - (message "PASS: %s <indent-via-typing> %s %s" test-name lang-file - (t-utils--took start-time)))))) - - (defun t-utils-test-syntax-table (test-name lang-files) - "Test syntax-table on each file in LANG-FILES list. - Compare syntax-table of each NAME.EXT in LANG-FILES against NAME_expected.txt. - TEST-NAME is used in messages. - - If NAME_expected.txt does not exist or the syntax-table of NAME.txt doesn't - match NAME_expected.txt, NAME_expected.txt~ will be created. You are - then instructured to validate the syntax-table and rename NAME_expected.txt~ - to NAME_expected.txt. - - To add a test for TEST-NAME.el, in it's corresponding TEST-NAME-files/ - directory, create TEST-NAME-files/NAME.EXT, then run the test. Follow - the messages to accept the generated baseline after validating it." - - (dolist (lang-file lang-files) - (save-excursion - (let ((start-time (current-time))) - (message "START: %s %s" test-name lang-file) - - (find-file lang-file) - (goto-char (point-min)) - - (let* ((got "") - (expected-file (replace-regexp-in-string "\\.[^.]+$" "_expected.txt" lang-file)) - (got-file (concat expected-file "~")) - (expected (when (file-exists-p expected-file) - (with-temp-buffer - (insert-file-contents-literally expected-file) - (buffer-string))))) - (while (not (eobp)) - (when (looking-at "^") - (setq got (concat got (format "Line:%d: %s\n" - (line-number-at-pos) - (buffer-substring-no-properties (point) - (line-end-position)))))) - - (let ((char (buffer-substring-no-properties (point) (1+ (point))))) - (when (string= char "\n") - (setq char "\\n")) - (setq got (concat got (format " %2s: %S\n" char (syntax-ppss (point)))))) - - (forward-char)) - - (when (not (string= got expected)) - (let ((coding-system-for-write 'raw-text-unix)) - (write-region got nil got-file)) - (when (not expected) - (error "Baseline for %s does not exists. \ - See %s and if it looks good rename it to %s" - lang-file got-file expected-file)) - (error "Baseline for %s does not match, got: %s, expected: %s" - lang-file got-file expected-file)) - (kill-buffer)) - (message "PASS: %s %s %s" test-name lang-file (t-utils--took start-time)))))) - - (provide 't-utils) - ;;; t-utils.el ends here - -#+end_src +TODO extract help from t-utils.el and place here. * Issues diff --git a/matlab-ts-mode.el b/matlab-ts-mode.el index 4d65a5781c..ebd90d38a8 100644 --- a/matlab-ts-mode.el +++ b/matlab-ts-mode.el @@ -1336,6 +1336,7 @@ Enable/disable `matlab-sections-minor-mode' based on file content." ;;; Electric Pair Mode, M-x electric-pair-mode (declare-function electric-pair-default-inhibit "elec-pair") + (defun matlab-ts-mode--electric-pair-inhibit-predicate (char) "Return non-nil if `electric-pair-mode' should not pair this CHAR. Do not pair the transpose operator, (\\='), but pair it when used as a @@ -1362,8 +1363,14 @@ single quote string." ;; Case: string delimiter ;; double up if starting a new string => return nil - ((string= "'" type-back1) - (not (string= "string" (treesit-node-type (treesit-node-parent node-back1))))) + ((string= "'" type-back1 ) + (let ((parent-back1-type (treesit-node-type (treesit-node-parent node-back1)))) + ;; When we type + ;; s = ' + ;; we'll get a syntax error from the parse-tree. Older versions of the + ;; matlab tree-sitter would return string so we keep that condition. + (not (or (string= "ERROR" parent-back1-type) + (string= "string" parent-back1-type))))) ;; Case: inside a single quote string ;; s = 'foobar' diff --git a/tests/metest.el b/tests/metest.el index db67edc7a2..d0c1fc4b1d 100644 --- a/tests/metest.el +++ b/tests/metest.el @@ -83,7 +83,7 @@ (when (not (eq system-type 'windows-nt)) (metest-fill-paragraph)) - ;; test-*.el + ;; Run test-*.el. t-utils-run must be last because it will exit emacs when noninteractive. (when (>= emacs-major-version 30) ;; TODO - should we eliminate this version check? (t-utils-run))) diff --git a/tests/t-utils.el b/tests/t-utils.el index 0cebd2b1d5..517c86f66d 100644 --- a/tests/t-utils.el +++ b/tests/t-utils.el @@ -21,12 +21,25 @@ ;; ;; Test utilities used by test-*.el files. ;; +;; t-utils.el uses the ert package. Many of t-utils functions operate on a set of input files and +;; compare them against baselines. For example, `t-utils-test-font-lock' loops over a set of files, +;; NAME.EXT, and compares them against NAME_expected.EXT. The ert package does not provide a +;; looping facility. Therefore, t-utils internally performs the looping. This makes reporting a +;; little off. One test is really a number of tests defined by the test input files. To debug a +;; specifice input file, the caller of the t-utils needs to setup for debugging. See +;; `t-utils-test-font-lock' below for this setup. +;; +;; Tip: type \"m\" on the colored dots in the *ert* buffer to see the messages for that ert test +;; and the messages contain the sub-tests from the test loop for that ert test. +;; + ;;; Code: (require 'cl-macs) (require 'cl-seq) (require 'diff) +(require 'ert) (require 'outline) (require 'treesit) @@ -51,7 +64,7 @@ and the result is a list of one file. For example, (t-utils-get-files \"test-LANGUAGE-ts-mode-files\" - \"*\\.lang$\" \"_expected\\.lang$\" file-to-use) + \"\\\\.lang\\\\\\='\" \"_expected\\\\.lang\\\\\\='\" file-to-use) will return a list of /path/to/test-NAME/*.lang files, skipping all *_expected.lang files when file-to-use is nil." @@ -71,7 +84,8 @@ It should be one of %S" file-to-use true-file-to-use files) (defun t-utils-is-treesit-available (language test-name) "Is tree-sitter ready for LANGUAGE? -If not available a message saying skipping TEST-NAME is displayed." +If not available a message saying skipping TEST-NAME is displayed +and nil is returned." (let ((available (and (>= emacs-major-version 30) ;; treesit package comes with Emacs 30 (progn (require 'treesit) @@ -85,21 +99,84 @@ If not available a message saying skipping TEST-NAME is displayed." "Run test files in current directory matching regexp, MATCH. If optional MATCH is non-nil, only run test file names whose non-directory part matches the regexp, MATCH. For example, -\"^test-foo.*\\\\.el$\" would run tell t-run to run \"test-foo*.el$\" -files. The default MATCH is \"^test-.*\\\\.el$\"" +\"^test-foo.*\\\\.el\\\\\\='\" would run tell t-utils-run to run +\"test-foo*.el\" files. The default MATCH is +\"^test-.*\\\\.el\\\\\\='\". + +It is assumed each matched test contains `ert-deftest' that has the same +name as the test file. These test names are then run using `ert'." + (when (not match) - (setq match "^test-.*\\.el$")) + (setq match "^test-.*\\.el\\'")) - (dolist (test-file (directory-files "." t match)) - (when (not (load-file test-file)) - (error "Failed to load %s" test-file)) - (let ((test-fun (intern - (replace-regexp-in-string "\\.el" "" (file-name-nondirectory test-file))))) - (funcall test-fun)))) + (let ((tests '())) + + (dolist (test-file (directory-files "." t match)) + (when (not (load-file test-file)) + (error "Failed to load %s" test-file)) + (push (replace-regexp-in-string "\\.el" "" (file-name-nondirectory test-file)) tests)) + + (let ((test-selector (rx-to-string `(seq bos (or ,@tests) eos)))) + (if noninteractive + (ert-run-tests-batch-and-exit test-selector) + (ert-run-tests-interactively test-selector))))) (defvar-local t-utils--buf-file nil "Name of file associated with t-utils temporary buffers.") +(defun t-utils--took (start-time) + "Return \"- took N seconds\". +N is `current-time' minus START-TIME." + (format "- took %.2f seconds" (float-time (time-subtract (current-time) start-time)))) + +(defun t-utils--baseline-check (test-name start-time + lang-file got got-file expected expected-file + &optional checker-fun) + "Validate GOT string matches EXPECTED for LANG-FILE of TEST-NAME. +GOT-FILE is equal to EXPECTED-FILE with a tilde prefix. GOT-FILE will +be created if (string= GOT EXPECTED) is nil. EXPECTED-FILE is the +baseline file for EXPECTED. START-TIME is when we started the test and +is used in displaying the test took time. + +Optional CHECKER-FUN if specified is called with LANG-FILE GOT GOT-FILE +EXPECTED EXPECTED-FILE and can return a specialized error message or +nil to use the standard error message. + +Returns nil on success, otherwise an error message list of strings if +baseline check fails." + + (let (error-msg) + (when (not (string= got expected)) + (let ((coding-system-for-write 'raw-text-unix)) + (write-region got nil got-file)) + + (when checker-fun + (setq error-msg (funcall checker-fun lang-file got got-file expected expected-file))) + + (when (not error-msg) + (if (not expected) + (setq error-msg (list + (format "Baseline for %s does not exists." lang-file) + (format "Got: %s" got-file) + (format "If got looks good, rename it to: %s" expected-file))) + (setq error-msg (list + (format "Baseline for %s does not match expected." lang-file) + (format "Got: %s" got-file ) + (format "Expected: %s" expected-file)))))) + ;; When run noninteractively, having errors show up like compiler messages aids in finding + ;; them. For example, run the test and pipe to a log file, then view the log file in + ;; `compilation-minor-mode'. + (when error-msg + (message "%s:1: error: test failed" lang-file) + (dolist (msg error-msg) + (message "-> %s" msg))) + + ;; Report the status of the test. + (message "%s: %s %s %s" + (if error-msg "FAIL" "PASS") + test-name lang-file (t-utils--took start-time)) + error-msg)) + (defun t-utils--insert-file-for-test (file &optional file-major-mode) "Insert FILE into current temporary buffer for testing. If optional FILE-MAJOR-MODE function is provided, run that, otherwise" @@ -124,11 +201,6 @@ If optional FILE-MAJOR-MODE function is provided, run that, otherwise" ;; Stash away the real buffer file for later use (and return it). (setq-local t-utils--buf-file file)) -(defun t-utils--took (start-time) - "Return \"- took N seconds\". -N is `current-time' minus START-TIME." - (format "- took %.2f seconds" (float-time (time-subtract (current-time) start-time)))) - (defun t-utils--get-buf-file () "Return the file corresponding to the buffer under test." (cond ((and (local-variable-if-set-p 't-utils--buf-file) @@ -198,7 +270,7 @@ Returns diff of START-CONTENTS and END-CONTENTS." Verify that diff is setup correctly, check `diff-command', etc. You can run `t-utils--diff-check' to debug")))) -(defun t-utils-diff-strings (start-contents end-contents) +(defun t-utils--diff-strings (start-contents end-contents) "Return diff of START-CONTENTS and END-CONTENTS." ;; Do a one time diff on sample start/end contents vs expected result @@ -316,7 +388,7 @@ You can run `t-utils--diff-check' to debug")))) (setq result (concat result " Buffer modified:\n" " #+begin_src diff\n" - (t-utils-diff-strings start-contents end-contents) + (t-utils--diff-strings start-contents end-contents) " #+end_src diff\n") debug-msg (concat debug-msg ", buffer modified"))) @@ -406,75 +478,82 @@ my_test.c. The result is compared against test-defun-movement/my_test_expected.org. If my_test_expected.org does not exist or result doesn't match the existing my_test_expected.org, my_test_expected.org~ is generated and if it looks correct, you should -rename it to my_test_expected.org." +rename it to my_test_expected.org. - (dolist (lang-file lang-files) - (with-temp-buffer - (t-utils--insert-file-for-test lang-file) - (let* ((start-time (current-time)) - (expected-file (replace-regexp-in-string "\\.[^.]+$" "_expected.org" - lang-file)) - (expected (when (file-exists-p expected-file) - (with-temp-buffer - (insert-file-contents-literally expected-file) - (buffer-string)))) - (got "#+startup: showall\n") - (got-file (concat expected-file "~"))) - - (message "START: %s %s" test-name lang-file) - - (while (re-search-forward "(t-utils-xr" nil t) - (re-search-backward "(") - (forward-list) - (let* ((xr-end-point (point))) - (setq t-utils--xr-impl-result-active t) - (unwind-protect - (progn - ;; `eval-last-sexp' on (t-utils-xr COMMANDS) calls - ;; `elisp--eval-last-sexp-print-value' which will (prin1 value output) where - ;; output is t which means send to echo area. We don't want to print value which - ;; is nil in our case, so we override elisp--eval-last-sexp-print-value locally - ;; during this eval. - (advice-add #'elisp--eval-last-sexp-print-value :override - #'t-utils--eval-sexp-print-advice) - - (eval-last-sexp nil) - (setq got (concat got t-utils--xr-impl-result) - t-utils--xr-impl-result-active nil - t-utils--xr-impl-result nil)) - (progn - (setq t-utils--xr-impl-result-active nil - t-utils--xr-impl-result nil) - (advice-remove #'elisp--eval-last-sexp-print-value - #'t-utils--eval-sexp-print-advice))) - - ;; look for next (t-utils-xr COMMANDS) - (goto-char xr-end-point))) +TODO should example test setup, see t-utils-test-font-lock." - (kill-buffer) + (let ((error-msgs '())) + (dolist (lang-file lang-files) + (with-temp-buffer + + (t-utils--insert-file-for-test lang-file) + + (let* ((start-time (current-time)) + (expected-file (replace-regexp-in-string "\\.[^.]+\\'" "_expected.org" + lang-file)) + (expected (when (file-exists-p expected-file) + (with-temp-buffer + (insert-file-contents-literally expected-file) + (buffer-string)))) + (got "#+startup: showall\n") + (got-file (concat expected-file "~"))) + + (message "START: %s %s" test-name lang-file) + + (condition-case err + (while (re-search-forward "(t-utils-xr" nil t) + (re-search-backward "(") + (forward-list) + (let* ((xr-end-point (point))) + (setq t-utils--xr-impl-result-active t) + (unwind-protect + (progn + ;; `eval-last-sexp' on (t-utils-xr COMMANDS) calls + ;; `elisp--eval-last-sexp-print-value' which will (prin1 value output) where + ;; output is t which means send to echo area. We don't want to print value + ;; which is nil in our case, so we override + ;; elisp--eval-last-sexp-print-value locally during this eval. + (advice-add #'elisp--eval-last-sexp-print-value :override + #'t-utils--eval-sexp-print-advice) + + (eval-last-sexp nil) + (setq got (concat got t-utils--xr-impl-result) + t-utils--xr-impl-result-active nil + t-utils--xr-impl-result nil)) + (progn + (setq t-utils--xr-impl-result-active nil + t-utils--xr-impl-result nil) + (advice-remove #'elisp--eval-last-sexp-print-value + #'t-utils--eval-sexp-print-advice))) + + ;; look for next (t-utils-xr COMMANDS) + (goto-char xr-end-point))) + (error + (error "Failure in %s at point %d: %s" lang-file (point) (error-message-string err)) + )) + + (kill-buffer) - (when (string= got "") - (error "No (t-utils-xr COMMANDS) found in %s" lang-file)) + (when (string= got "") + (error "No (t-utils-xr COMMANDS) found in %s" lang-file)) - (when (not (string= got expected)) - (let ((coding-system-for-write 'raw-text-unix)) - (write-region got nil got-file)) - (when (not expected) - (error "Baseline for %s does not exists. \ -See %s and if it looks good rename it to %s" - lang-file got-file expected-file)) - (error "Baseline for %s does not match, got: %s, expected: %s" - lang-file got-file expected-file)) + (let ((error-msg (t-utils--baseline-check test-name start-time + lang-file got got-file expected expected-file))) + (when error-msg + (push error-msg error-msgs)))))) - (message "PASS: %s %s %s" test-name lang-file (t-utils--took start-time)))))) + ;; Validate t-utils-test-xr result + (setq error-msgs (reverse error-msgs)) + (should (equal error-msgs '())))) (defun t-utils-test-font-lock (test-name lang-files code-to-face) "Test font-lock using on each lang-file in LANG-FILES list. -Foreach file in LANG-FILES compare the file against NAME_expected.txt, where -NAME the file name minus the extension. NAME_expected.txt is of same -length as the file and has a character for each face setup by font-lock. -CODE_TO_FACE is an alist where each elment is (CHAR . FACE). -TEST-NAME is used when displaying messages. +Foreach lang-file NAME.EXT in LANG-FILES compare the file against +NAME_expected.txt, where NAME the file name minus the lang-file +extension, EXT. NAME_expected.txt is of same length as the file and has +a character for each face setup by font-lock. CODE_TO_FACE is an alist +where each elment is (CHAR . FACE). TEST-NAME is used when displaying +messages. If NAME_expected.txt does not exists or doesn't match the results we got, a NAME_expected.txt~ will be generated. After reviewing @@ -497,11 +576,55 @@ where int and void are keywords, etc. and CODE-TO-FACE contains: (\"k\" . font-lock-keyword-face) (\"n\" . font-lock-constant-face)) -TODO give example calling test-name.el (and for others)" +Example test setup: + + ./LANGUAGE-ts-mode.el + ./tests/test-LANUGAGE-ts-mode-font-lock.el + ./tests/test-LANUGAGE-ts-mode-font-lock-files/NAME1.EXT + ./tests/test-LANUGAGE-ts-mode-font-lock-files/NAME1_expected.txt + ./tests/test-LANUGAGE-ts-mode-font-lock-files/NAME2.EXT + ./tests/test-LANUGAGE-ts-mode-font-lock-files/NAME2_expected.txt + .... + +Where ./tests/test-LANUGAGE-ts-mode-font-lock.el contains: + + (defvar test-LANGUAGE-ts-mode-font-lock--file nil) + + (defun test-LANGUAGE-ts-mode-font-lock--file (lang-file) + \"Test font-lock on LANG-FILE.\" + (let ((test-LANGUAGE-ts-mode-font-lock--file lang-file)) + (ert-run-tests-interactively \"test-LANGUAGE-ts-mode-font-lock\"))) + + (ert-deftest test-LANGUAGE-ts-mode-font-lock () + + (let* ((lang-files (t-utils-get-files + (concat test-name \"-files\") + \"\\.EXT\\\\\\='\" nil + test-LANGUAGE-ts-mode-font-lock--file)) + (code-to-face \\='( + (\"b\" . font-lock-bracket-face) + (\"B\" . font-lock-builtin-face) + (\"c\" . font-lock-comment-face) + .... + ))) + (t-utils-test-font-lock test-name lang-files code-to-face))) + +To loop over all NAME*.EXT font-lock test files, interactively + + \\[ert] RET test-LANGUAGE-ts-mode-font-lock RET + +In the *ert* buffer, you can type \"m\" at the point of the test (where +the color marker is) to see messages that were displayed by your test. + +To debug a specific font-lock test file + + M-: (test-LANGUAGE-ts-mode-font-lock--file \ +\"test-LANUGAGE-ts-mode-font-lock-files/NAME.EXT\")" (let ((face-to-code (mapcar (lambda (pair) (cons (cdr pair) (car pair))) - code-to-face))) + code-to-face)) + (error-msgs '())) (dolist (lang-file lang-files) (with-temp-buffer (t-utils--insert-file-for-test lang-file) @@ -514,7 +637,7 @@ TODO give example calling test-name.el (and for others)" (font-lock-ensure (point-min) (point-max)) (goto-char (point-min)) - (let* ((expected-file (replace-regexp-in-string "\\.[^.]+$" "_expected.txt" + (let* ((expected-file (replace-regexp-in-string "\\.[^.]+\\'" "_expected.txt" lang-file)) (expected (when (file-exists-p expected-file) (with-temp-buffer @@ -538,49 +661,41 @@ TODO give example calling test-name.el (and for others)" (kill-buffer) - (when (not (string= got expected)) - (let ((coding-system-for-write 'raw-text-unix)) - (write-region got nil got-file)) - (when (not expected) - (error "Baseline for %s does not exists. \ -See %s and if it looks good rename it to %s" - lang-file got-file expected-file)) - (when (= (length got) (length expected)) - (let* ((diff-idx (1- (compare-strings got nil nil expected nil nil))) - (got-code (substring got diff-idx (1+ diff-idx))) - (got-face (cdr (assoc got-code code-to-face))) - (expected-code (substring expected diff-idx (1+ diff-idx))) - (expected-face (cdr (assoc expected-code code-to-face)))) - (error "Baseline for %s does not match, got: %s, expected: %s. \ -Difference at column %d: got code-to-face (\"%s\" . %S), expected code-to-face (\"%s\" . %S)" - lang-file got-file expected-file - diff-idx - got-code got-face - expected-code expected-face))) - (error "Baseline for %s does not match, lengths are different, got: %s, expected: %s" - lang-file got-file expected-file))) - (message "PASS: %s %s %s" test-name lang-file (t-utils--took start-time))))))) + (let ((error-msg + (t-utils--baseline-check + test-name start-time + lang-file got got-file expected expected-file + (lambda (lang-file got got-file expected expected-file) + (when (= (length got) (length expected)) + (let* ((diff-idx (1- (compare-strings got nil nil expected + nil nil))) + (got-code (substring got diff-idx (1+ diff-idx))) + (got-face (cdr (assoc got-code code-to-face))) + (expected-code (substring expected diff-idx (1+ diff-idx))) + (expected-face (cdr (assoc expected-code code-to-face)))) + (list (format "Baseline for %s does not match" lang-file) + (format "Got: %s" got-file) + (format "Expected: %s" expected-file) + (format "Difference at column %d: \ +got code-to-face (\"%s\" . %S), expected code-to-face (\"%s\" . %S)" + diff-idx + got-code got-face + expected-code expected-face)))))))) + (when error-msg + (push error-msg error-msgs))))))) + ;; Validate t-utils-test-font-lock result + (setq error-msgs (reverse error-msgs)) + (should (equal error-msgs '())))) (defun t-utils--test-indent-typing (lang-file lang-file-mode expected expected-file &optional line-manipulator) "Exercise indent by simulating the creation of LANG-FILE via typing. This compares the simulation of typing LANG-FILE against the -EXPECTED content in EXPECTED-FILE - -The typing occurs in a buffer named \"typing__NAME.EXT\" where NAME.EXT -is the basename of LANG-FILE. - -The typing buffer is initialized with the string-trim'd version of the -non-empty lines of LANG-FILE. If optional LINE-MANIPULATOR function is -specified, it is called with the typing buffer as the current -buffer. LINE-MANIPULATOR should only adjust whitespace in the lines. It -should not add newlines to the buffer. LINE-MANIPULATOR is called from -within a `save-excursion', so your function doesn't need to do that. +EXPECTED content in EXPECTED-FILE. -After initializating the typing buffer, it's mode is set to -LANG-FILE-MODE. Each line is then indented via `indent-for-tab-command' -and blank lines are inserted by calling `newline'.`" +LANG-FILE-MODE is the mode to use for LANG-FILE. See +See `t-utils-test-indent' for LINE-MANIPULATOR." (let* ((typing-lang-file-name (concat "typing__" (file-name-nondirectory lang-file))) (contents (with-temp-buffer @@ -623,17 +738,22 @@ and blank lines are inserted by calling `newline'.`" (t-utils--trim) - (let ((typing-got (buffer-substring (point-min) (point-max)))) + (let ((typing-got (buffer-substring (point-min) (point-max))) + error-msg) (set-buffer-modified-p nil) (kill-buffer) (when (not (string= typing-got expected)) (let ((coding-system-for-write 'raw-text-unix) - (typing-got-file (replace-regexp-in-string "\\.\\([^.]+\\)$" + (typing-got-file (replace-regexp-in-string "\\.\\([^.]+\\)\\'" "_typing.\\1~" lang-file))) (write-region typing-got nil typing-got-file) - (error "Typing %s line-by-line does not match %s, we got %s" lang-file expected-file - typing-got-file))))))) + (setq error-msg + (list + (format "Typing %s line-by-line does not match %s" lang-file expected-file) + (format "Got: %s" typing-got-file))))) + ;; result is nil or an error message list of strings + error-msg)))) (defun t-utils-test-indent (test-name lang-files &optional line-manipulator error-nodes-regexp) "Test indent on each file in LANG-FILES list. @@ -645,12 +765,13 @@ match NAME_expected.txt, NAME_expected.EXT~ will be created. You are then instructured to validate the indent and rename NAME_expected.EXT~ to NAME_expected.EXT. -To add a test for TEST-NAME.el which call this function, in the +To add a test for TEST-NAME.el which calls this function, in the corresponding TEST-NAME-files/ directory, create TEST-NAME-files/NAME.EXT, then run the test. Follow the messages to accept the generated baseline after validating it. Two methods are used to indent each file in LANG-FILES, + 1. (indent-region (point-min) (point-man)) 2. Indent via typing simulation. If lang-file has no error nodes in the @@ -658,59 +779,119 @@ Two methods are used to indent each file in LANG-FILES, TAB and RET, see `t-utils--test-indent-typing'. In tree-sitter modes, TAB and RET need to be handled and this verifies they are handled. Error nodes are identified by using - ERROR-NODES-REGEXP which defaults to \"^ERROR$\". + ERROR-NODES-REGEXP which defaults to \"\\\\`ERROR\\\\\\='\". + + The typing occurs in a temporary buffer partially named + \"typing__NAME.EXT\" where NAME.EXT is the basename of LANG-FILE. + + The typing buffer is initialized with the string-trim'd version of + the non-empty lines of LANG-FILE. If optional LINE-MANIPULATOR + function is specified, it is called with the typing buffer as the + current buffer. LINE-MANIPULATOR should only adjust whitespace in + the lines. It should not add newlines to the buffer. + LINE-MANIPULATOR is called from within a `save-excursion', so your + function doesn't need to do that. + + In the typing buffer, each line is indented via + `indent-for-tab-command' and blank lines are inserted by calling + `newline'.` + +Example test setup: + + ./LANGUAGE-ts-mode.el + ./tests/test-LANUGAGE-ts-mode-indent.el + ./tests/test-LANUGAGE-ts-mode-indent-files/NAME1.EXT + ./tests/test-LANUGAGE-ts-mode-indent-files/NAME1_expected.EXT + ./tests/test-LANUGAGE-ts-mode-indent-files/NAME2.EXT + ./tests/test-LANUGAGE-ts-mode-indent-files/NAME2_expected.EXT + +Where ./tests/test-LANUGAGE-ts-mode-indent.el contains: + + (defvar test-LANGUAGE-ts-mode-indent--file nil) + + (defun test-LANGUAGE-ts-mode-indent--file (lang-file) + \"Test indent on LANG-FILE.\" + (let ((test-LANGUAGE-ts-mode-indent--file lang-file)) + (ert-run-tests-interactively \"test-LANGUAGE-ts-mode-indent\"))) + + (ert-deftest test-LANGUAGE-ts-mode-indent () + (let ((test-name \"test-LANGUAGE-ts-mode-indent\")) + (when (t-utils-is-treesit-available \\='LANGUAGE test-name) + (let ((lang-files (t-utils-get-files (concat test-name \"-files\") \"\\.EXT\\\\\\='\" + \"_expected\\.EXT\\\\\\='\" ;; skip our *_expected.EXT baselines + test-LANGUAGE-ts-mode-indent--file)) + (line-manipulator nil)) + (t-utils-test-indent test-name lang-files line-manipulator))))) + +To loop over all NAME*.EXT indent test files, interactively + + \\[ert] RET test-LANGUAGE-ts-mode-indent RET + +In the *ert* buffer, you can type \"m\" at the point of the test (where +the color marker is) to see messages that were displayed by your test. + +To debug a specific indent test file + + M-: (test-LANGUAGE-ts-mode-indent--file \ +\"test-LANUGAGE-ts-mode-indent-files/NAME.EXT\")" -See `t-utils--test-indent-type' for LINE-MANIPULATOR." (when (not error-nodes-regexp) (setq error-nodes-regexp (rx bos "ERROR" eos))) - (dolist (lang-file lang-files) - (let* ((expected-file (replace-regexp-in-string "\\.\\([^.]+\\)$" "_expected.\\1" lang-file)) - (expected (when (file-exists-p expected-file) - (with-temp-buffer - (insert-file-contents-literally expected-file) - (buffer-string)))) - lang-file-major-mode - error-node) - - ;; Indent lang-file - (with-temp-buffer - (let ((start-time (current-time))) - (t-utils--insert-file-for-test lang-file) - (setq error-node (treesit-search-subtree - (treesit-buffer-root-node) error-nodes-regexp nil t)) - (message "START: %s <indent-region> %s" test-name lang-file) - (setq lang-file-major-mode major-mode) - (indent-region (point-min) (point-max)) - (t-utils--trim) - (let ((got (buffer-substring (point-min) (point-max))) - (got-file (concat expected-file "~"))) - (set-buffer-modified-p nil) - (kill-buffer) - (when (not (string= got expected)) - (let ((coding-system-for-write 'raw-text-unix)) - (write-region got nil got-file)) - (when (not expected) - (error "Baseline for %s does not exists - if %s looks good rename it to %s" - lang-file got-file expected-file)) - (error "Baseline for %s does not match, got: %s, expected: %s" - lang-file got-file expected-file))) - (message "PASS: %s <indent-region> %s %s" test-name lang-file - (t-utils--took start-time)))) - - ;; Now, simulate typing lang-file and indent it (exercise TAB and RET) - (when (not error-node) - (let ((start-time (current-time))) + (let ((error-msgs '())) + (dolist (lang-file lang-files) + (let* ((expected-file (replace-regexp-in-string "\\.\\([^.]+\\)\\'" "_expected.\\1" + lang-file)) + (expected (when (file-exists-p expected-file) + (with-temp-buffer + (insert-file-contents-literally expected-file) + (buffer-string)))) + lang-file-major-mode + error-node) + + ;; Indent lang-file + (with-temp-buffer + (let ((start-time (current-time))) + (t-utils--insert-file-for-test lang-file) + (setq error-node (treesit-search-subtree + (treesit-buffer-root-node) error-nodes-regexp nil t)) + + (message "START: %s <indent-region> %s" test-name lang-file) + (setq lang-file-major-mode major-mode) + (indent-region (point-min) (point-max)) + (t-utils--trim) + (let ((got (buffer-substring (point-min) (point-max))) + (got-file (concat expected-file "~"))) + (set-buffer-modified-p nil) + (kill-buffer) + + (let ((indent-error-msg (t-utils--baseline-check + (concat test-name " <indent-region>") start-time + lang-file got got-file expected expected-file))) + (when indent-error-msg + (push indent-error-msg error-msgs)))))) + + ;; Now, simulate typing lang-file and indent it (exercise TAB and RET) + (when (not error-node) (message "START: %s <indent-via-typing> %s" test-name lang-file) - (t-utils--test-indent-typing lang-file lang-file-major-mode - expected expected-file - line-manipulator) - (message "PASS: %s <indent-via-typing> %s %s" test-name lang-file - (t-utils--took start-time))))))) + (let ((start-time (current-time)) + (typing-error-msg (t-utils--test-indent-typing lang-file lang-file-major-mode + expected expected-file + line-manipulator))) + (message "%s: %s <indent-via-typing> %s %s" test-name lang-file + (if typing-error-msg "FAIL" "PASS") + (t-utils--took start-time)) + (when typing-error-msg + (push typing-error-msg error-msgs)))) + )) + ;; Validate t-utils-test-indent result + (setq error-msgs (reverse error-msgs)) + (should (equal error-msgs '())))) (defun t-utils--check-parse (lang-file error-nodes-regexp syntax-checker-fun check-valid-parse) "Return (parse-error . invalid-successful-parse) pair of strings. +This looks for ERROR-NODES-REGEXP in the tree-sitter parse tree. See `t-utils-sweep-test-indent' for a description of LANG-FILE ERROR-NODES-REGEXP SYNTAX-CHECKER-FUN CHECK-VALID-PARSE." @@ -947,49 +1128,52 @@ to NAME_expected.txt. To add a test for TEST-NAME.el which call this function, in the corresponding TEST-NAME-files/ directory, create TEST-NAME-files/NAME.EXT, then run the test. Follow the messages to -accept the generated baseline after validating it." +accept the generated baseline after validating it. - (dolist (lang-file lang-files) - (with-temp-buffer +TODO should example test setup, see t-utils-test-font-lock." - (let ((start-time (current-time))) - (message "START: %s %s" test-name lang-file) + (let ((error-msgs '())) + (dolist (lang-file lang-files) + (with-temp-buffer - (t-utils--insert-file-for-test lang-file) + (let ((start-time (current-time))) + (message "START: %s %s" test-name lang-file) - (let* ((got "") - (expected-file (replace-regexp-in-string "\\.[^.]+$" "_expected.txt" lang-file)) - (got-file (concat expected-file "~")) - (expected (when (file-exists-p expected-file) - (with-temp-buffer - (insert-file-contents-literally expected-file) - (buffer-string))))) - (forward-line) ;; skip the mode line specification - (while (not (eobp)) - (when (looking-at "^") - (setq got (concat got (format "Line:%d: %s\n" - (line-number-at-pos) - (buffer-substring-no-properties (point) - (line-end-position)))))) - - (let ((char (buffer-substring-no-properties (point) (1+ (point))))) - (when (string= char "\n") - (setq char "\\n")) - (setq got (concat got (format " %2s: %S\n" char (syntax-ppss (point)))))) - - (forward-char)) + (t-utils--insert-file-for-test lang-file) - (kill-buffer) - (when (not (string= got expected)) - (let ((coding-system-for-write 'raw-text-unix)) - (write-region got nil got-file)) - (when (not expected) - (error "Baseline for %s does not exists. \ -See %s and if it looks good rename it to %s" - lang-file got-file expected-file)) - (error "Baseline for %s does not match, got: %s, expected: %s" - lang-file got-file expected-file))) - (message "PASS: %s %s %s" test-name lang-file (t-utils--took start-time)))))) + (let* ((got "") + (expected-file (replace-regexp-in-string "\\.[^.]+\\'" "_expected.txt" lang-file)) + (got-file (concat expected-file "~")) + (expected (when (file-exists-p expected-file) + (with-temp-buffer + (insert-file-contents-literally expected-file) + (buffer-string))))) + (forward-line) ;; skip the mode line specification + (while (not (eobp)) + (when (looking-at "^") + (setq got (concat got (format + "Line:%d: %s\n" + (line-number-at-pos) + (buffer-substring-no-properties (point) + (line-end-position)))))) + + (let ((char (buffer-substring-no-properties (point) (1+ (point))))) + (when (string= char "\n") + (setq char "\\n")) + (setq got (concat got (format " %2s: %S\n" char (syntax-ppss (point)))))) + + (forward-char)) + + (kill-buffer) + + (let ((error-msg (t-utils--baseline-check + test-name start-time + lang-file got got-file expected expected-file))) + (when error-msg + (push error-msg error-msgs))))))) + ;; Validate t-utils-test-syntax-table result + (setq error-msgs (reverse error-msgs)) + (should (equal error-msgs '())))) (defun t-utils-test-treesit-defun-name (test-name lang-files) "Test `treesit-defun-name-function' setup. @@ -1005,49 +1189,53 @@ to NAME_expected.txt. To add a test for TEST-NAME.el which call this function, in the corresponding TEST-NAME-files/ directory, create TEST-NAME-files/NAME.EXT, then run the test. Follow the messages to -accept the generated baseline after validating it." +accept the generated baseline after validating it. - (dolist (lang-file lang-files) - (with-temp-buffer +TODO should example test setup, see t-utils-test-font-lock." - (let ((start-time (current-time))) - (message "START: %s %s" test-name lang-file) + (let ((error-msgs '())) + (dolist (lang-file lang-files) + (with-temp-buffer - (t-utils--insert-file-for-test lang-file) + (let ((start-time (current-time))) + (message "START: %s %s" test-name lang-file) - (let* ((root (treesit-buffer-root-node)) - (expected-file (replace-regexp-in-string "\\.[^.]+$" "_expected.txt" lang-file)) - (expected (when (file-exists-p expected-file) - (with-temp-buffer - (insert-file-contents-literally expected-file) - (buffer-string)))) - (got "") - (got-file (concat expected-file "~"))) + (t-utils--insert-file-for-test lang-file) - (treesit-search-subtree - root - (lambda (node) - (let ((defun-name (funcall treesit-defun-name-function node)) - (node-type (replace-regexp-in-string "\n" "\\n" (treesit-node-type node))) - (node-start (treesit-node-start node)) - (node-end (treesit-node-end node))) - (setq got (concat - got - (format "Node %25s at %4d to %4d: defun-name = %s\n" - node-type node-start node-end (if defun-name defun-name "nil"))))) - nil)) + (let* ((root (treesit-buffer-root-node)) + (expected-file (replace-regexp-in-string "\\.[^.]+\\'" "_expected.txt" lang-file)) + (expected (when (file-exists-p expected-file) + (with-temp-buffer + (insert-file-contents-literally expected-file) + (buffer-string)))) + (got "") + (got-file (concat expected-file "~"))) - (kill-buffer) - (when (not (string= got expected)) - (let ((coding-system-for-write 'raw-text-unix)) - (write-region got nil got-file)) - (when (not expected) - (error "Baseline for %s does not exists. \ -See %s and if it looks good rename it to %s" - lang-file got-file expected-file)) - (error "Baseline for %s does not match, got: %s, expected: %s" - lang-file got-file expected-file))) - (message "PASS: %s %s %s" test-name lang-file (t-utils--took start-time)))))) + (treesit-search-subtree + root + (lambda (node) + (let ((defun-name (funcall treesit-defun-name-function node)) + (node-type (replace-regexp-in-string "\n" "\\n" (treesit-node-type node))) + (node-start (treesit-node-start node)) + (node-end (treesit-node-end node))) + (setq got (concat + got + (format "Node %25s at %4d to %4d: defun-name = %s\n" + node-type node-start node-end + (if defun-name defun-name "nil"))))) + nil)) + + (kill-buffer) + + (let ((error-msg (t-utils--baseline-check + test-name start-time + lang-file got got-file expected expected-file))) + (when error-msg + (push error-msg error-msgs))))))) + + ;; Validate t-utils-test-treesit-defun-name result + (setq error-msgs (reverse error-msgs)) + (should (equal error-msgs '())))) (defun t-utils-test-imenu (test-name lang-files) "Test imenu support. @@ -1062,39 +1250,40 @@ to NAME_expected.txt. To add a test for TEST-NAME.el which call this function, in the corresponding TEST-NAME-files/ directory, create TEST-NAME-files/NAME.EXT, then run the test. Follow the messages to -accept the generated baseline after validating it." +accept the generated baseline after validating it. - (dolist (lang-file lang-files) - (with-temp-buffer +TODO should example test setup, see t-utils-test-font-lock." - (let ((start-time (current-time))) - (message "START: %s %s" test-name lang-file) + (let ((error-msgs '())) + (dolist (lang-file lang-files) + (with-temp-buffer - (t-utils--insert-file-for-test lang-file) + (let ((start-time (current-time))) + (message "START: %s %s" test-name lang-file) - (let* ((index (funcall imenu-create-index-function)) - (expected-file (replace-regexp-in-string "\\.[^.]+$" "_expected.txt" lang-file)) - (expected (when (file-exists-p expected-file) - (with-temp-buffer - (insert-file-contents-literally expected-file) - (buffer-string)))) - (got (concat (string-join - (mapcar (lambda (el) (substring-no-properties (car el))) index) - "\n") - "\n")) - (got-file (concat expected-file "~"))) + (t-utils--insert-file-for-test lang-file) - (kill-buffer) - (when (not (string= got expected)) - (let ((coding-system-for-write 'raw-text-unix)) - (write-region got nil got-file)) - (when (not expected) - (error "Baseline for %s does not exists. \ -See %s and if it looks good rename it to %s" - lang-file got-file expected-file)) - (error "Baseline for %s does not match, got: %s, expected: %s" - lang-file got-file expected-file))) - (message "PASS: %s %s %s" test-name lang-file (t-utils--took start-time)))))) + (let* ((index (funcall imenu-create-index-function)) + (expected-file (replace-regexp-in-string "\\.[^.]+\\'" "_expected.txt" lang-file)) + (expected (when (file-exists-p expected-file) + (with-temp-buffer + (insert-file-contents-literally expected-file) + (buffer-string)))) + (got (concat (string-join + (mapcar (lambda (el) (substring-no-properties (car el))) index) + "\n") + "\n")) + (got-file (concat expected-file "~"))) + + (kill-buffer) + (let ((error-msg (t-utils--baseline-check + test-name start-time + lang-file got got-file expected expected-file))) + (when error-msg + (push error-msg error-msgs))))))) + ;; Validate t-utils-test-imenu result + (setq error-msgs (reverse error-msgs)) + (should (equal error-msgs '())))) (defun t-utils-test-outline-search-function (test-name lang-files) "Test setup for `outline-minor-mode'. @@ -1109,48 +1298,51 @@ to NAME_expected.txt. To add a test for TEST-NAME.el which call this function, in the corresponding TEST-NAME-files/ directory, create TEST-NAME-files/NAME.EXT, then run the test. Follow the messages to -accept the generated baseline after validating it." +accept the generated baseline after validating it. - (dolist (lang-file lang-files) - (with-temp-buffer +TODO should example test setup, see t-utils-test-font-lock." - (let ((start-time (current-time)) - (lang-file-base (file-name-nondirectory lang-file))) - (message "START: %s %s" test-name lang-file) + (let ((error-msgs '())) + (dolist (lang-file lang-files) + (with-temp-buffer - (t-utils--insert-file-for-test lang-file) + (let ((start-time (current-time)) + (lang-file-base (file-name-nondirectory lang-file))) - (let* ((expected-file (replace-regexp-in-string "\\.[^.]+$" "_expected.txt" lang-file)) - (expected (when (file-exists-p expected-file) - (with-temp-buffer - (insert-file-contents-literally expected-file) - (buffer-string)))) - (got "Section heading lines\n\n") - (got-file (concat expected-file "~"))) + (message "START: %s %s" test-name lang-file) - (while (not (eobp)) - (let ((next-heading (funcall outline-search-function))) - (if next-heading - (let ((heading-info (format "%s:%d: %s\n" - lang-file-base - (line-number-at-pos) - (buffer-substring-no-properties - (line-beginning-position) (line-end-position))))) - (setq got (concat got heading-info)) - (forward-line)) - (goto-char (point-max))))) + (t-utils--insert-file-for-test lang-file) + + (let* ((expected-file (replace-regexp-in-string "\\.[^.]+\\'" "_expected.txt" lang-file)) + (expected (when (file-exists-p expected-file) + (with-temp-buffer + (insert-file-contents-literally expected-file) + (buffer-string)))) + (got "Section heading lines\n\n") + (got-file (concat expected-file "~"))) + + (while (not (eobp)) + (let ((next-heading (funcall outline-search-function))) + (if next-heading + (let ((heading-info (format "%s:%d: %s\n" + lang-file-base + (line-number-at-pos) + (buffer-substring-no-properties + (line-beginning-position) (line-end-position))))) + (setq got (concat got heading-info)) + (forward-line)) + (goto-char (point-max))))) + + (kill-buffer) + (let ((error-msg (t-utils--baseline-check + test-name start-time + lang-file got got-file expected expected-file))) + (when error-msg + (push error-msg error-msgs))))))) + ;; Validate t-utils-test-outline-search-function result + (setq error-msgs (reverse error-msgs)) + (should (equal error-msgs '())))) - (kill-buffer) - (when (not (string= got expected)) - (let ((coding-system-for-write 'raw-text-unix)) - (write-region got nil got-file)) - (when (not expected) - (error "Baseline for %s does not exists. \ -See %s and if it looks good rename it to %s" - lang-file got-file expected-file)) - (error "Baseline for %s does not match, got: %s, expected: %s" - lang-file got-file expected-file))) - (message "PASS: %s %s %s" test-name lang-file (t-utils--took start-time)))))) (provide 't-utils) ;;; t-utils.el ends here diff --git a/tests/test-matlab-ts-mode-comments.el b/tests/test-matlab-ts-mode-comments.el index 00864a2dd1..706edf7f5d 100644 --- a/tests/test-matlab-ts-mode-comments.el +++ b/tests/test-matlab-ts-mode-comments.el @@ -30,13 +30,21 @@ (require 't-utils) (require 'matlab-ts-mode) -(cl-defun test-matlab-ts-mode-comments (&optional m-file) - "Test defun movement using ./test-matlab-ts-mode-comments-files/NAME.m. +(defvar test-matlab-ts-mode-comments--file nil) + +(defun test-matlab-ts-mode-comments--file (m-file) + "Test an individual M-FILE. +This is provided for debugging. + M-: (test-matlab-ts-mode-comments--file \"test-matlab-ts-mode-comments-files/M-FILE\")" + (let ((test-matlab-ts-mode-comments--file m-file)) + (ert-run-tests-interactively "test-matlab-ts-mode-comments"))) + +(ert-deftest test-matlab-ts-mode-comments () + "Test comments using ./test-matlab-ts-mode-comments-files/NAME.m. Using ./test-matlab-ts-mode-comments-files/NAME.m, compare comment -keybindings against -./test-matlab-ts-mode-comments-files/NAME_expected.org. If M-FILE is -not provided, loop comparing all -./test-matlab-ts-mode-comments-files/NAME.m files. +key bindings against +./test-matlab-ts-mode-comments-files/NAME_expected.org. This loops +on all ./test-matlab-ts-mode-comments-files/NAME.m files. To add a test, create ./test-matlab-ts-mode-comments-files/NAME.m @@ -46,13 +54,10 @@ after validating it, rename it to ./test-matlab-ts-mode-comments-files/NAME_expected.org" (let ((test-name "test-matlab-ts-mode-comments")) - - (when (not (t-utils-is-treesit-available 'matlab test-name)) - (cl-return-from test-matlab-ts-mode-comments)) - - (let ((m-files (t-utils-get-files (concat test-name "-files") "\\.m$" nil m-file))) - (t-utils-test-xr test-name m-files))) - "success") + (when (t-utils-is-treesit-available 'matlab test-name) + (let ((m-files (t-utils-get-files (concat test-name "-files") "\\.m\\'" nil + test-matlab-ts-mode-comments--file))) + (t-utils-test-xr test-name m-files))))) (provide 'test-matlab-ts-mode-comments) ;;; test-matlab-ts-mode-comments.el ends here diff --git a/tests/test-matlab-ts-mode-electric-pair.el b/tests/test-matlab-ts-mode-electric-pair.el index 90024e08c1..697fb08069 100644 --- a/tests/test-matlab-ts-mode-electric-pair.el +++ b/tests/test-matlab-ts-mode-electric-pair.el @@ -30,13 +30,21 @@ (require 't-utils) (require 'matlab-ts-mode) -(cl-defun test-matlab-ts-mode-electric-pair (&optional m-file) - "Test defun movement using ./test-matlab-ts-mode-electric-pair-files/NAME.m. -Using ./test-matlab-ts-mode-electric-pair-files/NAME.m, compare defun -movement against -./test-matlab-ts-mode-electric-pair-files/NAME_expected.org. If M-FILE is -not provided, loop comparing all -./test-matlab-ts-mode-electric-pair-files/NAME.m files. +(defvar test-matlab-ts-mode-electric-pair--file nil) + +(defun test-matlab-ts-mode-electric-pair--file (m-file) + "Test an individual M-FILE. +This is provided for debugging. + M-: (test-matlab-ts-mode-electric-pair--file \"test-matlab-ts-mode-electric-pair-files/M-FILE\")" + (let ((test-matlab-ts-mode-electric-pair--file m-file)) + (ert-run-tests-interactively "test-matlab-ts-mode-electric-pair"))) + +(ert-deftest test-matlab-ts-mode-electric-pair () + "Test electric pair using ./test-matlab-ts-mode-electric-pair-files/NAME.m. +Using ./test-matlab-ts-mode-electric-pair-files/NAME.m, run +`matlab-ts-mode--electric-pair-inhibit-predicate' compare result against +./test-matlab-ts-mode-electric-pair-files/NAME_expected.org. This loops +on all ./test-matlab-ts-mode-comments-files/NAME.m files. To add a test, create ./test-matlab-ts-mode-electric-pair-files/NAME.m @@ -46,13 +54,10 @@ after validating it, rename it to ./test-matlab-ts-mode-electric-pair-files/NAME_expected.org" (let ((test-name "test-matlab-ts-mode-electric-pair")) - - (when (not (t-utils-is-treesit-available 'matlab test-name)) - (cl-return-from test-matlab-ts-mode-electric-pair)) - - (let ((m-files (t-utils-get-files (concat test-name "-files") "\\.m$" nil m-file))) - (t-utils-test-xr test-name m-files))) - "success") + (when (t-utils-is-treesit-available 'matlab test-name) + (let ((m-files (t-utils-get-files (concat test-name "-files") "\\.m\\'" nil + test-matlab-ts-mode-electric-pair--file))) + (t-utils-test-xr test-name m-files))))) (provide 'test-matlab-ts-mode-electric-pair) ;;; test-matlab-ts-mode-electric-pair.el ends here diff --git a/tests/test-matlab-ts-mode-fill-paragraph.el b/tests/test-matlab-ts-mode-fill-paragraph.el index f6490de6b5..3f2e59b0bd 100644 --- a/tests/test-matlab-ts-mode-fill-paragraph.el +++ b/tests/test-matlab-ts-mode-fill-paragraph.el @@ -30,13 +30,22 @@ (require 't-utils) (require 'matlab-ts-mode) -(cl-defun test-matlab-ts-mode-fill-paragraph (&optional m-file) - "Test defun movement using ./test-matlab-ts-mode-fill-paragraph-files/NAME.m. -Using ./test-matlab-ts-mode-fill-paragraph-files/NAME.m, compare comment -keybindings against -./test-matlab-ts-mode-fill-paragraph-files/NAME_expected.org. If M-FILE is -not provided, loop comparing all -./test-matlab-ts-mode-fill-paragraph-files/NAME.m files. +(defvar test-matlab-ts-mode-fill-paragraph--file nil) + +(defun test-matlab-ts-mode-fill-paragraph--file (m-file) + "Test an individual M-FILE. +This is provided for debugging. + M-: (test-matlab-ts-mode-fill-paragraph--file + \"test-matlab-ts-mode-fill-paragraph-files/M-FILE\")" + (let ((test-matlab-ts-mode-fill-paragraph--file m-file)) + (ert-run-tests-interactively "test-matlab-ts-mode-fill-paragraph"))) + +(ert-deftest test-matlab-ts-mode-fill-paragraph () + "Test fill paragraph using ./test-matlab-ts-mode-fill-paragraph-files/NAME.m. +Using ./test-matlab-ts-mode-fill-paragraph-files/NAME.m, run +`fill-paragraph' and compare result against +./test-matlab-ts-mode-fill-paragraph-files/NAME_expected.org. This loops +on all ./test-matlab-ts-mode-comments-files/NAME.m files. To add a test, create ./test-matlab-ts-mode-fill-paragraph-files/NAME.m @@ -50,9 +59,9 @@ after validating it, rename it to (when (not (t-utils-is-treesit-available 'matlab test-name)) (cl-return-from test-matlab-ts-mode-fill-paragraph)) - (let ((m-files (t-utils-get-files (concat test-name "-files") "\\.m$" nil m-file))) - (t-utils-test-xr test-name m-files))) - "success") + (let ((m-files (t-utils-get-files (concat test-name "-files") "\\.m\\'" nil + test-matlab-ts-mode-fill-paragraph--file))) + (t-utils-test-xr test-name m-files)))) (provide 'test-matlab-ts-mode-fill-paragraph) ;;; test-matlab-ts-mode-fill-paragraph.el ends here diff --git a/tests/test-matlab-ts-mode-font-lock.el b/tests/test-matlab-ts-mode-font-lock.el index 5514a24e89..c788fe943d 100644 --- a/tests/test-matlab-ts-mode-font-lock.el +++ b/tests/test-matlab-ts-mode-font-lock.el @@ -28,58 +28,64 @@ (require 't-utils) (require 'matlab-ts-mode) -(cl-defun test-matlab-ts-mode-font-lock (&optional m-file) +(defvar test-matlab-ts-mode-font-lock--file nil) + +(defun test-matlab-ts-mode-font-lock--file (m-file) + "Test an individual M-FILE. +This is provided for debugging. + M-: (test-matlab-ts-mode-font-lock--file \"test-matlab-ts-mode-font-lock-files/M-FILE\")" + (let ((test-matlab-ts-mode-font-lock--file m-file)) + (ert-run-tests-interactively "test-matlab-ts-mode-font-lock"))) + +(ert-deftest test-matlab-ts-mode-font-lock () "Test font-lock using ./test-matlab-ts-mode-font-lock-files/NAME.m. -Compare ./test-matlab-ts-mode-font-lock-files/NAME.m against +Compare font of ./test-matlab-ts-mode-font-lock-files/NAME.m against ./test-matlab-ts-mode-font-lock-files/NAME_expected.txt, where NAME_expected.txt is of same length as NAME.m where each source character in NAME.m is replaced with a character code representing the font-lock face used for said source character. The mapping is defined -by the code-to-face alist setup by this function. If M-FILE is not -provided, loop comparing all -./test-matlab-ts-mode-font-lock-files/NAME.m files. +by the code-to-face alist setup by this function. This loops +on all ./test-matlab-ts-mode-font-lock-files/NAME.m files. -To add a test, create +To add a test, createp ./test-matlab-ts-mode-font-lock-files/NAME.m and run this function. The baseline is saved for you as - ./test-matlab-ts-mode-font-lock-files/NAME_expected.m~ + ./test-matlab-ts-mode-font-lock-files/NAME_expected.txt~ after validating it, rename it to - ./test-matlab-ts-mode-font-lock-files/NAME_expected.m" - - (let ((test-name "test-matlab-ts-mode-font-lock") - (matlab-ts-mode-font-lock-level 4)) - (when (not (t-utils-is-treesit-available 'matlab test-name)) - (cl-return-from test-matlab-ts-mode-font-lock)) + ./test-matlab-ts-mode-font-lock-files/NAME_expected.txt" - (let* ((m-files (t-utils-get-files (concat test-name "-files") "\\.m$" nil m-file)) - (code-to-face '( - ("!" . matlab-ts-mode-system-command-face) - ("a" . matlab-ts-mode-command-arg-face) - ("b" . font-lock-bracket-face) - ("B" . font-lock-builtin-face) - ("c" . font-lock-comment-face) - ("C" . font-lock-comment-delimiter-face) - ("d" . default) - ("D" . font-lock-delimiter-face) - ("E" . font-lock-escape-face) - ("f" . font-lock-function-name-face) - ("F" . font-lock-function-call-face) - ("h" . font-lock-doc-face) ;; function doc help comment - ("H" . matlab-ts-mode-comment-heading-face) - ("k" . font-lock-keyword-face) - ("M" . matlab-ts-mode-comment-to-do-marker-face) - ("n" . matlab-ts-mode-number-face) - ("s" . font-lock-string-face) - ("S" . matlab-ts-mode-string-delimiter-face) - ("o" . matlab-ts-mode-operator-face) - ("p" . matlab-ts-mode-pragma-face) - ("P" . matlab-ts-mode-property-face) - ("t" . font-lock-type-face) - ("v" . font-lock-variable-name-face) - ("w" . font-lock-warning-face) - ))) - (t-utils-test-font-lock test-name m-files code-to-face)) - "success")) + (let ((test-name "test-matlab-ts-mode-font-lock")) + (when (t-utils-is-treesit-available 'matlab test-name) + (let* ((matlab-ts-mode-font-lock-level 4) + (m-files (t-utils-get-files (concat test-name "-files") "\\.m\\'" nil + test-matlab-ts-mode-font-lock--file)) + (code-to-face '( + ("!" . matlab-ts-mode-system-command-face) + ("a" . matlab-ts-mode-command-arg-face) + ("b" . font-lock-bracket-face) + ("B" . font-lock-builtin-face) + ("c" . font-lock-comment-face) + ("C" . font-lock-comment-delimiter-face) + ("d" . default) + ("D" . font-lock-delimiter-face) + ("E" . font-lock-escape-face) + ("f" . font-lock-function-name-face) + ("F" . font-lock-function-call-face) + ("h" . font-lock-doc-face) ;; function doc help comment + ("H" . matlab-ts-mode-comment-heading-face) + ("k" . font-lock-keyword-face) + ("M" . matlab-ts-mode-comment-to-do-marker-face) + ("n" . matlab-ts-mode-number-face) + ("s" . font-lock-string-face) + ("S" . matlab-ts-mode-string-delimiter-face) + ("o" . matlab-ts-mode-operator-face) + ("p" . matlab-ts-mode-pragma-face) + ("P" . matlab-ts-mode-property-face) + ("t" . font-lock-type-face) + ("v" . font-lock-variable-name-face) + ("w" . font-lock-warning-face) + ))) + (t-utils-test-font-lock test-name m-files code-to-face))))) (provide 'test-matlab-ts-mode-font-lock) ;;; test-matlab-ts-mode-font-lock.el ends here diff --git a/tests/test-matlab-ts-mode-imenu.el b/tests/test-matlab-ts-mode-imenu.el index 3066cceaa5..b5919a845b 100644 --- a/tests/test-matlab-ts-mode-imenu.el +++ b/tests/test-matlab-ts-mode-imenu.el @@ -30,12 +30,20 @@ (require 't-utils) (require 'matlab-ts-mode) -(cl-defun test-matlab-ts-mode-imenu (&optional m-file) - "Test defun movement using ./test-matlab-ts-mode-imenu-files/NAME.m. +(defvar test-matlab-ts-mode-imenu--file nil) + +(defun test-matlab-ts-mode-imenu--file (m-file) + "Test an individual M-FILE. +This is provided for debugging. + M-: (test-matlab-ts-mode-imenu--file \"test-matlab-ts-mode-imenu-files/M-FILE\")" + (let ((test-matlab-ts-mode-imenu--file m-file)) + (ert-run-tests-interactively "test-matlab-ts-mode-imenu"))) + +(ert-deftest test-matlab-ts-mode-imenu () + "Test imenu using ./test-matlab-ts-mode-imenu-files/NAME.m. Using ./test-matlab-ts-mode-imenu-files/NAME.m, compare imenu results -against ./test-matlab-ts-mode-imenu-files/NAME_expected.txt. If M-FILE -is not provided, loop comparing all -./test-matlab-ts-mode-imenu-files/NAME.m files. +against ./test-matlab-ts-mode-imenu-files/NAME_expected.txt. This loops +on all ./test-matlab-ts-mode-imenu-files/NAME.m files. To add a test, create ./test-matlab-ts-mode-imenu-files/NAME.m @@ -45,13 +53,10 @@ after validating it, rename it to ./test-matlab-ts-mode-imenu-files/NAME_expected.txt" (let ((test-name "test-matlab-ts-mode-imenu")) - - (when (not (t-utils-is-treesit-available 'matlab test-name)) - (cl-return-from test-matlab-ts-mode-imenu)) - - (let ((m-files (t-utils-get-files (concat test-name "-files") "\\.m$" nil m-file))) - (t-utils-test-imenu test-name m-files))) - "success") + (when (t-utils-is-treesit-available 'matlab test-name) + (let ((m-files (t-utils-get-files (concat test-name "-files") "\\.m\\'" nil + test-matlab-ts-mode-imenu--file))) + (t-utils-test-imenu test-name m-files))))) (provide 'test-matlab-ts-mode-imenu) ;;; test-matlab-ts-mode-imenu.el ends here diff --git a/tests/test-matlab-ts-mode-indent.el b/tests/test-matlab-ts-mode-indent.el index a6acaf0848..9861acb9a8 100644 --- a/tests/test-matlab-ts-mode-indent.el +++ b/tests/test-matlab-ts-mode-indent.el @@ -30,12 +30,21 @@ (require 't-utils) (require 'matlab-ts-mode) -(cl-defun test-matlab-ts-mode-indent (&optional m-file) +(defvar test-matlab-ts-mode-indent--file nil) + +(defun test-matlab-ts-mode-indent--file (m-file) + "Test an individual M-FILE. +This is provided for debugging. + M-: (test-matlab-ts-mode-indent--file \"test-matlab-ts-mode-indent-files/M-FILE\")" + (let ((test-matlab-ts-mode-indent--file m-file)) + (ert-run-tests-interactively "test-matlab-ts-mode-indent"))) + +(ert-deftest test-matlab-ts-mode-indent () "Test indent using ./test-matlab-ts-mode-indent-files/NAME.m. Compare indent of ./test-matlab-ts-mode-indent-files/NAME.m against ./test-matlab-ts-mode-indent-files/NAME_expected.m. Indent is done two -ways as described in `t-utils-test-indent'. If M-FILE is not provided, -loop comparing all ./test-matlab-ts-mode-indent-files/NAME.m files. +ways as described in `t-utils-test-indent'. This loops +on all ./test-matlab-ts-mode-indent-files/NAME.m files. To add a test, create ./test-matlab-ts-mode-indent-files/NAME.m @@ -44,28 +53,23 @@ and run this function. The baseline is saved for you as after validating it, rename it to ./test-matlab-ts-mode-indent-files/NAME_expected.m" - (let ((test-name "test-matlab-ts-mode-indent") - (matlab-ts-mode--indent-assert t)) - - (when (not (t-utils-is-treesit-available 'matlab test-name)) - (cl-return-from test-matlab-ts-mode-indent)) - - (let ((m-files (t-utils-get-files (concat test-name "-files") "\\.m$" - "_expected\\.m$" ;; skip our *_expected.m baselines - m-file)) - (line-manipulator (lambda () - ;; Workaround - ;; https://github.com/acristoffers/tree-sitter-matlab/issues/32 - (goto-char (point-min)) - (while (not (eobp)) - (let* ((node (treesit-node-at (point))) - (parent (and node (treesit-node-parent node)))) - (when (string= (treesit-node-type parent) "ERROR") - (insert " "))) - (forward-line))))) + (let ((test-name "test-matlab-ts-mode-indent")) + (when (t-utils-is-treesit-available 'matlab test-name) + (let ((m-files (t-utils-get-files (concat test-name "-files") "\\.m\\'" + "_expected\\.m\\'" ;; skip our *_expected.m baselines + test-matlab-ts-mode-indent--file)) + (line-manipulator (lambda () + ;; Workaround + ;; https://github.com/acristoffers/tree-sitter-matlab/issues/32 + (goto-char (point-min)) + (while (not (eobp)) + (let* ((node (treesit-node-at (point))) + (parent (and node (treesit-node-parent node)))) + (when (string= (treesit-node-type parent) "ERROR") + (insert " "))) + (forward-line))))) - (t-utils-test-indent test-name m-files line-manipulator))) - "success") + (t-utils-test-indent test-name m-files line-manipulator))))) (provide 'test-matlab-ts-mode-indent) ;;; test-matlab-ts-mode-indent.el ends here diff --git a/tests/test-matlab-ts-mode-on-save-fixes.el b/tests/test-matlab-ts-mode-on-save-fixes.el index 8bf5145874..7ed2642e24 100644 --- a/tests/test-matlab-ts-mode-on-save-fixes.el +++ b/tests/test-matlab-ts-mode-on-save-fixes.el @@ -30,13 +30,22 @@ (require 't-utils) (require 'matlab-ts-mode) -(cl-defun test-matlab-ts-mode-on-save-fixes (&optional m-file) - "Test defun movement using ./test-matlab-ts-mode-on-save-fixes-files/NAME.m. -Using ./test-matlab-ts-mode-on-save-fixes-files/NAME.m, compare defun -movement against -./test-matlab-ts-mode-on-save-fixes-files/NAME_expected.org. If M-FILE is -not provided, loop comparing all -./test-matlab-ts-mode-on-save-fixes-files/NAME.m files. +(defvar test-matlab-ts-mode-on-save-fixes--file nil) + +(defun test-matlab-ts-mode-on-save-fixes--file (m-file) + "Test an individual M-FILE. +This is provided for debugging. + M-: (test-matlab-ts-mode-on-save-fixes--file \"test-matlab-ts-mode-on-save-fixes-files/M-FILE\")" + (let ((test-matlab-ts-mode-on-save-fixes--file m-file)) + (ert-run-tests-interactively "test-matlab-ts-mode-on-save-fixes"))) + +(ert-deftest test-matlab-ts-mode-on-save-fixes () + "Test fix of fcn name using ./test-matlab-ts-mode-on-save-fixes-files/NAME.m. +Using ./test-matlab-ts-mode-on-save-fixes-files/NAME.m, set the +buffer name to \"tmp__NAME.m\" and validate +`matlab-ts-mode-on-save-fix-name' returns expected result found in +./test-matlab-ts-mode-on-save-fixes-files/NAME_expected.org. This loops +on all ./test-matlab-ts-mode-on-save-fixes-files/NAME.m files. To add a test, create ./test-matlab-ts-mode-on-save-fixes-files/NAME.m @@ -46,13 +55,10 @@ after validating it, rename it to ./test-matlab-ts-mode-on-save-fixes-files/NAME_expected.org" (let ((test-name "test-matlab-ts-mode-on-save-fixes")) - - (when (not (t-utils-is-treesit-available 'matlab test-name)) - (cl-return-from test-matlab-ts-mode-on-save-fixes)) - - (let ((m-files (t-utils-get-files (concat test-name "-files") "\\.m$" nil m-file))) - (t-utils-test-xr test-name m-files))) - "success") + (when (t-utils-is-treesit-available 'matlab test-name) + (let ((m-files (t-utils-get-files (concat test-name "-files") "\\.m\\'" nil + test-matlab-ts-mode-on-save-fixes--file))) + (t-utils-test-xr test-name m-files))))) (provide 'test-matlab-ts-mode-on-save-fixes) ;;; test-matlab-ts-mode-on-save-fixes.el ends here diff --git a/tests/test-matlab-ts-mode-outline.el b/tests/test-matlab-ts-mode-outline.el index 18ce7f5574..e87f6b2bee 100644 --- a/tests/test-matlab-ts-mode-outline.el +++ b/tests/test-matlab-ts-mode-outline.el @@ -30,13 +30,21 @@ (require 't-utils) (require 'matlab-ts-mode) -(cl-defun test-matlab-ts-mode-outline (&optional m-file) - "Test defun movement using ./test-matlab-ts-mode-outline-files/NAME.m. -Using ./test-matlab-ts-mode-outline-files/NAME.m, compare defun -movement against -./test-matlab-ts-mode-outline-files/NAME_expected.txt. If M-FILE is -not provided, loop comparing all -./test-matlab-ts-mode-outline-files/NAME.m files. +(defvar test-matlab-ts-mode-outline--file nil) + +(defun test-matlab-ts-mode-outline--file (m-file) + "Test an individual M-FILE. +This is provided for debugging. + M-: (test-matlab-ts-mode-outline--file \"test-matlab-ts-mode-outline-files/M-FILE\")" + (let ((test-matlab-ts-mode-outline--file m-file)) + (ert-run-tests-interactively "test-matlab-ts-mode-outline"))) + +(ert-deftest test-matlab-ts-mode-outline () + "Test outline mode using ./test-matlab-ts-mode-outline-files/NAME.m. +Using ./test-matlab-ts-mode-outline-files/NAME.m, call `outline-search-function' +and compare result agains +./test-matlab-ts-mode-outline-files/NAME_expected.txt. This loops +on all ./test-matlab-ts-mode-outline-files/NAME.m files. To add a test, create ./test-matlab-ts-mode-outline-files/NAME.m @@ -46,13 +54,10 @@ after validating it, rename it to ./test-matlab-ts-mode-outline-files/NAME_expected.txt" (let ((test-name "test-matlab-ts-mode-outline")) - - (when (not (t-utils-is-treesit-available 'matlab test-name)) - (cl-return-from test-matlab-ts-mode-outline)) - - (let ((m-files (t-utils-get-files (concat test-name "-files") "\\.m$" nil m-file))) - (t-utils-test-outline-search-function test-name m-files))) - "success") + (when (t-utils-is-treesit-available 'matlab test-name) + (let ((m-files (t-utils-get-files (concat test-name "-files") "\\.m\\'" nil + test-matlab-ts-mode-outline--file))) + (t-utils-test-outline-search-function test-name m-files))))) (provide 'test-matlab-ts-mode-outline) ;;; test-matlab-ts-mode-outline.el ends here diff --git a/tests/test-matlab-ts-mode-page.el b/tests/test-matlab-ts-mode-page.el index 989ca10f75..95a2f2adca 100644 --- a/tests/test-matlab-ts-mode-page.el +++ b/tests/test-matlab-ts-mode-page.el @@ -30,13 +30,21 @@ (require 't-utils) (require 'matlab-ts-mode) -(cl-defun test-matlab-ts-mode-page (&optional m-file) - "Test defun movement using ./test-matlab-ts-mode-page-files/NAME.m. -Using ./test-matlab-ts-mode-page-files/NAME.m, compare comment -keybindings against -./test-matlab-ts-mode-page-files/NAME_expected.org. If M-FILE is -not provided, loop comparing all -./test-matlab-ts-mode-page-files/NAME.m files. +(defvar test-matlab-ts-mode-page--file nil) + +(defun test-matlab-ts-mode-page--file (m-file) + "Test an individual M-FILE. +This is provided for debugging. + M-: (test-matlab-ts-mode-page--file \"test-matlab-ts-mode-page-files/M-FILE\")" + (let ((test-matlab-ts-mode-page--file m-file)) + (ert-run-tests-interactively "test-matlab-ts-mode-page"))) + +(ert-deftest test-matlab-ts-mode-page () + "Test page movement using ./test-matlab-ts-mode-page-files/NAME.m. +Using ./test-matlab-ts-mode-page-files/NAME.m, compare `forward-page' +and `backward-page' against +./test-matlab-ts-mode-page-files/NAME_expected.org. This loops +on all ./test-matlab-ts-mode-page-files/NAME.m files. To add a test, create ./test-matlab-ts-mode-page-files/NAME.m @@ -46,13 +54,10 @@ after validating it, rename it to ./test-matlab-ts-mode-page-files/NAME_expected.org" (let ((test-name "test-matlab-ts-mode-page")) - - (when (not (t-utils-is-treesit-available 'matlab test-name)) - (cl-return-from test-matlab-ts-mode-page)) - - (let ((m-files (t-utils-get-files (concat test-name "-files") "\\.m$" nil m-file))) - (t-utils-test-xr test-name m-files))) - "success") + (when (t-utils-is-treesit-available 'matlab test-name) + (let ((m-files (t-utils-get-files (concat test-name "-files") "\\.m\\'" nil + test-matlab-ts-mode-page--file))) + (t-utils-test-xr test-name m-files))))) (provide 'test-matlab-ts-mode-page) ;;; test-matlab-ts-mode-page.el ends here diff --git a/tests/test-matlab-ts-mode-show-paren-files/show_paren_string.m b/tests/test-matlab-ts-mode-show-paren-files/show_paren_string.m index e6e994fa84..a19959c132 100644 --- a/tests/test-matlab-ts-mode-show-paren-files/show_paren_string.m +++ b/tests/test-matlab-ts-mode-show-paren-files/show_paren_string.m @@ -19,8 +19,7 @@ s3 = "<foo ' bar>"; % (t-utils-xr (re-search-forward ">") (prin1 (matlab-ts-mode--show-paren-or-block))) s4 = "<foo ' bar>"; -% (t-utils-xr (re-search-forward "<") "C-b" "C-b" (prin1 (matlab-ts-mode--show-paren-or-block))) -s5 = "<asdf +% (t-utils-xr (re-search-forward "-end-quote") (kill-line) (re-search-backward "<") "C-b" (prin1 (matlab-ts-mode--show-paren-or-block)) "C-e" (insert (char-to-string 34))) +s5 = "<asdf-end-quote" -% (t-utils-xr (re-search-forward ">") (prin1 (matlab-ts-mode--show-paren-or-block))) -s6 = asdf>" +% comment with a (") for s5. diff --git a/tests/test-matlab-ts-mode-show-paren-files/show_paren_string_expected.org b/tests/test-matlab-ts-mode-show-paren-files/show_paren_string_expected.org index 2f4561c21c..4e26ee4d80 100644 --- a/tests/test-matlab-ts-mode-show-paren-files/show_paren_string_expected.org +++ b/tests/test-matlab-ts-mode-show-paren-files/show_paren_string_expected.org @@ -180,50 +180,75 @@ * Executing commands from show_paren_string.m:22:2: - (t-utils-xr (re-search-forward "<") "C-b" "C-b" (prin1 (matlab-ts-mode--show-paren-or-block))) + (t-utils-xr (re-search-forward "-end-quote") (kill-line) (re-search-backward "<") "C-b" (prin1 (matlab-ts-mode--show-paren-or-block)) "C-e" (insert (char-to-string 34))) -- Invoking : (re-search-forward "<") - Start point : 801 - Moved to point: 809 - : 23:7: s5 = "<asdf - : ^ +- Invoking : (re-search-forward "-end-quote") + Start point : 876 + Moved to point: 898 + : 23:21: s5 = "<asdf-end-quote" + : ^ No buffer modifications -- Invoking : "C-b" = backward-char - Start point : 809 - Moved to point: 808 - : 23:6: s5 = "<asdf +- Invoking : (kill-line) + Start point : 898 + No point movement + Buffer modified: + #+begin_src diff +--- start_contents ++++ end_contents +@@ -20,6 +20,6 @@ + s4 = "<foo ' bar>"; + + % (t-utils-xr (re-search-forward "-end-quote") (kill-line) (re-search-backward "<") "C-b" (prin1 (matlab-ts-mode--show-paren-or-block)) "C-e" (insert (char-to-string 34))) +-s5 = "<asdf-end-quote" ++s5 = "<asdf-end-quote + + % comment with a (") for s5. + #+end_src diff + +- Invoking : (re-search-backward "<") + Start point : 898 + Moved to point: 883 + : 23:6: s5 = "<asdf-end-quote : ^ No buffer modifications - Invoking : "C-b" = backward-char - Start point : 808 - Moved to point: 807 - : 23:5: s5 = "<asdf + Start point : 883 + Moved to point: 882 + : 23:5: s5 = "<asdf-end-quote : ^ No buffer modifications - Invoking : (prin1 (matlab-ts-mode--show-paren-or-block)) - Start point : 807 + Start point : 882 No point movement standard-output: - (807 808 nil nil t) - No buffer modifications - -* Executing commands from show_paren_string.m:25:2: - - (t-utils-xr (re-search-forward ">") (prin1 (matlab-ts-mode--show-paren-or-block))) - -- Invoking : (re-search-forward ">") - Start point : 899 - Moved to point: 910 - : 26:10: s6 = asdf>" - : ^ - No buffer modifications - -- Invoking : (prin1 (matlab-ts-mode--show-paren-or-block)) - Start point : 910 - No point movement - standard-output: - (910 911 nil nil t) - No buffer modifications + (882 883 nil nil t) + No buffer modifications + +- Invoking : "C-e" = move-end-of-line + Start point : 882 + Moved to point: 898 + : 23:21: s5 = "<asdf-end-quote + : ^ + No buffer modifications + +- Invoking : (insert (char-to-string 34)) + Start point : 898 + Moved to point: 899 + : 23:22: s5 = "<asdf-end-quote" + : ^ + Buffer modified: + #+begin_src diff +--- start_contents ++++ end_contents +@@ -20,6 +20,6 @@ + s4 = "<foo ' bar>"; + + % (t-utils-xr (re-search-forward "-end-quote") (kill-line) (re-search-backward "<") "C-b" (prin1 (matlab-ts-mode--show-paren-or-block)) "C-e" (insert (char-to-string 34))) +-s5 = "<asdf-end-quote ++s5 = "<asdf-end-quote" + + % comment with a (") for s5. + #+end_src diff diff --git a/tests/test-matlab-ts-mode-show-paren.el b/tests/test-matlab-ts-mode-show-paren.el index b5e5897cda..abb3246c53 100644 --- a/tests/test-matlab-ts-mode-show-paren.el +++ b/tests/test-matlab-ts-mode-show-paren.el @@ -30,10 +30,19 @@ (require 't-utils) (require 'matlab-ts-mode) -(cl-defun test-matlab-ts-mode-show-paren (&optional m-file) - "Test defun movement using ./test-matlab-ts-mode-show-paren-files/NAME.m. -Using ./test-matlab-ts-mode-show-paren-files/NAME.m, compare defun -movement against +(defvar test-matlab-ts-mode-show-paren--file nil) + +(defun test-matlab-ts-mode-show-paren--file (m-file) + "Test an individual M-FILE. +This is provided for debugging. + M-: (test-matlab-ts-mode-show-paren--file \"test-matlab-ts-mode-show-paren-files/M-FILE\")" + (let ((test-matlab-ts-mode-show-paren--file m-file)) + (ert-run-tests-interactively "test-matlab-ts-mode-show-paren"))) + +(ert-deftest test-matlab-ts-mode-show-paren () + "Test show paren mode using ./test-matlab-ts-mode-show-paren-files/NAME.m. +Using ./test-matlab-ts-mode-show-paren-files/NAME.m, result of +`matlab-ts-mode--show-paren-or-block' for `show-paren-mode' against ./test-matlab-ts-mode-show-paren-files/NAME_expected.org. If M-FILE is not provided, loop comparing all ./test-matlab-ts-mode-show-paren-files/NAME.m files. @@ -46,13 +55,11 @@ after validating it, rename it to ./test-matlab-ts-mode-show-paren-files/NAME_expected.org" (let ((test-name "test-matlab-ts-mode-show-paren")) + (when (t-utils-is-treesit-available 'matlab test-name) - (when (not (t-utils-is-treesit-available 'matlab test-name)) - (cl-return-from test-matlab-ts-mode-show-paren)) - - (let ((m-files (t-utils-get-files (concat test-name "-files") "\\.m$" nil m-file))) - (t-utils-test-xr test-name m-files))) - "success") + (let ((m-files (t-utils-get-files (concat test-name "-files") "\\.m\\'" nil + test-matlab-ts-mode-show-paren--file))) + (t-utils-test-xr test-name m-files))))) (provide 'test-matlab-ts-mode-show-paren) ;;; test-matlab-ts-mode-show-paren.el ends here diff --git a/tests/test-matlab-ts-mode-syntax-table.el b/tests/test-matlab-ts-mode-syntax-table.el index 569b56cd92..82d0ee5aef 100644 --- a/tests/test-matlab-ts-mode-syntax-table.el +++ b/tests/test-matlab-ts-mode-syntax-table.el @@ -28,13 +28,22 @@ (require 't-utils) (require 'matlab-ts-mode) -(cl-defun test-matlab-ts-mode-syntax-table (&optional m-file) +(defvar test-matlab-ts-mode-syntax-table--file nil) + +(defun test-matlab-ts-mode-syntax-table--file (m-file) + "Test an individual M-FILE. +This is provided for debugging. + M-: (test-matlab-ts-mode-syntax-table--file \"test-matlab-ts-mode-syntax-table-files/M-FILE\")" + (let ((test-matlab-ts-mode-syntax-table--file m-file)) + (ert-run-tests-interactively "test-matlab-ts-mode-syntax-table"))) + +(ert-deftest test-matlab-ts-mode-syntax-table () "Test syntax-table using ./test-matlab-ts-mode-syntax-table-files/NAME.m. Compare ./test-matlab-ts-mode-syntax-table-files/NAME.m against ./test-matlab-ts-mode-syntax-table-files/NAME_expected.txt, where -NAME_expected.txt gives the `syntax-ppss` value of each character in -NAME.m. If M-FILE is not provided, loop comparing all -./test-matlab-ts-mode-indent-files/NAME.m files. +NAME_expected.txt gives the `syntax-ppss' value of each character in +NAME.m. This loops on all ./test-matlab-ts-mode-syntax-table-files/NAME.m +files. To add a test, create ./test-matlab-ts-mode-syntax-table-files/NAME.m @@ -44,13 +53,10 @@ after validating it, rename it to ./test-matlab-ts-mode-syntax-table-files/NAME_expected.m" (let ((test-name "test-matlab-ts-mode-syntax-table")) - (when (not (t-utils-is-treesit-available 'matlab test-name)) - (cl-return-from test-matlab-ts-mode-syntax-table)) - - (let ((m-files (t-utils-get-files (concat test-name "-files") "\\.m$" nil m-file))) - (t-utils-test-syntax-table test-name m-files))) - - "success") + (when (t-utils-is-treesit-available 'matlab test-name) + (let ((m-files (t-utils-get-files (concat test-name "-files") "\\.m\\'" nil + test-matlab-ts-mode-syntax-table--file))) + (t-utils-test-syntax-table test-name m-files))))) (provide 'test-matlab-ts-mode-syntax-table) ;;; test-matlab-ts-mode-syntax-table.el ends here diff --git a/tests/test-matlab-ts-mode-thing-settings.el b/tests/test-matlab-ts-mode-thing-settings.el index 3e63072a14..ae1c05a8ea 100644 --- a/tests/test-matlab-ts-mode-thing-settings.el +++ b/tests/test-matlab-ts-mode-thing-settings.el @@ -30,13 +30,22 @@ (require 't-utils) (require 'matlab-ts-mode) -(cl-defun test-matlab-ts-mode-thing-settings (&optional m-file) - "Test defun movement using ./test-matlab-ts-mode-thing-settings-files/NAME.m. -Using ./test-matlab-ts-mode-thing-settings-files/NAME.m, compare defun -movement against -./test-matlab-ts-mode-thing-settings-files/NAME_expected.org. If M-FILE is -not provided, loop comparing all -./test-matlab-ts-mode-thing-settings-files/NAME.m files. +(defvar test-matlab-ts-mode-thing-settings--file nil) + +(defun test-matlab-ts-mode-thing-settings--file (m-file) + "Test an individual M-FILE. +This is provided for debugging. + M-: (test-matlab-ts-mode-thing-settings--file + \"test-matlab-ts-mode-thing-settings-files/M-FILE\")" + (let ((test-matlab-ts-mode-thing-settings--file m-file)) + (ert-run-tests-interactively "test-matlab-ts-mode-thing-settings"))) + +(ert-deftest test-matlab-ts-mode-thing-settings () + "Test thing settings using ./test-matlab-ts-mode-thing-settings-files/NAME.m. +Using ./test-matlab-ts-mode-thing-settings-files/NAME.m, compare +movement commands, e.g. `forward-sentace' that use treesit thing +settings. ./test-matlab-ts-mode-thing-settings-files/NAME_expected.org. +This loops on all ./test-matlab-ts-mode-thing-settings-files/NAME.m files. To add a test, create ./test-matlab-ts-mode-thing-settings-files/NAME.m @@ -46,13 +55,10 @@ after validating it, rename it to ./test-matlab-ts-mode-thing-settings-files/NAME_expected.org" (let ((test-name "test-matlab-ts-mode-thing-settings")) - - (when (not (t-utils-is-treesit-available 'matlab test-name)) - (cl-return-from test-matlab-ts-mode-thing-settings)) - - (let ((m-files (t-utils-get-files (concat test-name "-files") "\\.m$" nil m-file))) - (t-utils-test-xr test-name m-files))) - "success") + (when (t-utils-is-treesit-available 'matlab test-name) + (let ((m-files (t-utils-get-files (concat test-name "-files") "\\.m\\'" nil + test-matlab-ts-mode-thing-settings--file))) + (t-utils-test-xr test-name m-files))))) (provide 'test-matlab-ts-mode-thing-settings) ;;; test-matlab-ts-mode-thing-settings.el ends here diff --git a/tests/test-matlab-ts-mode-treesit-defun-name.el b/tests/test-matlab-ts-mode-treesit-defun-name.el index 90830a746d..8af291c7d7 100644 --- a/tests/test-matlab-ts-mode-treesit-defun-name.el +++ b/tests/test-matlab-ts-mode-treesit-defun-name.el @@ -30,13 +30,22 @@ (require 't-utils) (require 'matlab-ts-mode) -(cl-defun test-matlab-ts-mode-treesit-defun-name (&optional m-file) - "Test defun movement using ./test-matlab-ts-mode-treesit-defun-name-files/NAME.m. +(defvar test-matlab-ts-mode-treesit-defun-name--file nil) + +(defun test-matlab-ts-mode-treesit-defun-name--file (m-file) + "Test an individual M-FILE. +This is provided for debugging. + M-: (test-matlab-ts-mode-treesit-defun-name--file + \"test-matlab-ts-mode-treesit-defun-name-files/M-FILE\")" + (let ((test-matlab-ts-mode-treesit-defun-name--file m-file)) + (ert-run-tests-interactively "test-matlab-ts-mode-treesit-defun-name"))) + +(ert-deftest test-matlab-ts-mode-treesit-defun-name () + "Test defun setup using ./test-matlab-ts-mode-treesit-defun-name-files/NAME.m. Using ./test-matlab-ts-mode-treesit-defun-name-files/NAME.m, compare defun -movement against -./test-matlab-ts-mode-treesit-defun-name-files/NAME_expected.txt. If M-FILE is -not provided, loop comparing all -./test-matlab-ts-mode-treesit-defun-name-files/NAME.m files. +setup against +./test-matlab-ts-mode-treesit-defun-name-files/NAME_expected.txt. This loops +on all ./test-matlab-ts-mode-treesit-defun-name-files/NAME.m files. To add a test, create ./test-matlab-ts-mode-treesit-defun-name-files/NAME.m @@ -46,13 +55,10 @@ after validating it, rename it to ./test-matlab-ts-mode-treesit-defun-name-files/NAME_expected.txt" (let ((test-name "test-matlab-ts-mode-treesit-defun-name")) - - (when (not (t-utils-is-treesit-available 'matlab test-name)) - (cl-return-from test-matlab-ts-mode-defun-name)) - - (let ((m-files (t-utils-get-files (concat test-name "-files") "\\.m$" nil m-file))) - (t-utils-test-treesit-defun-name test-name m-files))) - "success") + (when (t-utils-is-treesit-available 'matlab test-name) + (let ((m-files (t-utils-get-files (concat test-name "-files") "\\.m\\'" nil + test-matlab-ts-mode-treesit-defun-name--file))) + (t-utils-test-treesit-defun-name test-name m-files))))) (provide 'test-matlab-ts-mode-treesit-defun-name) ;;; test-matlab-ts-mode-treesit-defun-name.el ends here