|
| 1 | +;;; tree-sitter-tests-utils.el --- Utils for tree-sitter-tests.el -*- lexical-binding: t; coding: utf-8 -*- |
| 2 | + |
| 3 | +;; Copyright (C) 2019-2022 Tuấn-Anh Nguyễn |
| 4 | +;; |
| 5 | +;; Author: Tuấn-Anh Nguyễn <ubolonton@gmail.com> |
| 6 | +;; SPDX-License-Identifier: MIT |
| 7 | + |
| 8 | +;;; Commentary: |
| 9 | + |
| 10 | +;; Utils for `tree-sitter-tests'. |
| 11 | + |
| 12 | +;;; Code: |
| 13 | + |
| 14 | +(setq tsc-dyn-get-from nil) |
| 15 | +(require 'tree-sitter) |
| 16 | +(require 'tree-sitter-debug) |
| 17 | + |
| 18 | +(defvar tree-sitter-langs--testing) |
| 19 | +;;; Disable grammar downloading. |
| 20 | +(let ((tree-sitter-langs--testing t)) |
| 21 | + (require 'tree-sitter-langs)) |
| 22 | +;;; Build the grammars, if necessary. |
| 23 | +(dolist (lang-symbol '(rust python javascript c)) |
| 24 | + (tree-sitter-langs-ensure lang-symbol)) |
| 25 | + |
| 26 | +;; XXX: Bash grammar failed 'tree-sitter test' on Windows: 'Escaped newlines'. |
| 27 | +(with-demoted-errors "Failed to ensure bash grammar %s" |
| 28 | + (tree-sitter-langs-ensure 'bash)) |
| 29 | + |
| 30 | +(require 'ert) |
| 31 | +(require 'generator) |
| 32 | + |
| 33 | +(eval-when-compile |
| 34 | + (require 'subr-x) |
| 35 | + (require 'cl-lib)) |
| 36 | + |
| 37 | +;;; ---------------------------------------------------------------------------- |
| 38 | +;;; Helpers. |
| 39 | + |
| 40 | +(defun tsc-test-make-parser (lang-symbol) |
| 41 | + "Return a new parser for LANG-SYMBOL." |
| 42 | + (let ((parser (tsc-make-parser)) |
| 43 | + (language (tree-sitter-require lang-symbol))) |
| 44 | + (tsc-set-language parser language) |
| 45 | + parser)) |
| 46 | + |
| 47 | +(defun tsc-test-full-path (relative-path) |
| 48 | + "Return full path from project RELATIVE-PATH." |
| 49 | + (concat (file-name-directory (locate-library "tree-sitter-tests.el")) |
| 50 | + relative-path)) |
| 51 | + |
| 52 | +(defun tsc-test-tree-sexp (sexp &optional reset) |
| 53 | + "Check that the current syntax tree's sexp representation is SEXP. |
| 54 | +If RESET is non-nil, also do another full parse and check again." |
| 55 | + (should (equal (read (tsc-tree-to-sexp tree-sitter-tree)) sexp)) |
| 56 | + (when reset |
| 57 | + (setq tree-sitter-tree nil) |
| 58 | + (tree-sitter--do-parse) |
| 59 | + (tsc-test-tree-sexp sexp))) |
| 60 | + |
| 61 | +(defun tsc-test-use-lang (lang-symbol) |
| 62 | + "Turn on `tree-sitter-mode' in the current buffer, using language LANG-SYMBOL." |
| 63 | + (setq tree-sitter-language (tree-sitter-require lang-symbol)) |
| 64 | + (ignore-errors |
| 65 | + (setq tree-sitter-hl-default-patterns |
| 66 | + (tree-sitter-langs--hl-default-patterns lang-symbol))) |
| 67 | + (add-hook 'tree-sitter-after-first-parse-hook |
| 68 | + (lambda () (should (not (null tree-sitter-tree))))) |
| 69 | + (tree-sitter-mode)) |
| 70 | + |
| 71 | +(defun tsc--listify (x) |
| 72 | + (if (listp x) |
| 73 | + x |
| 74 | + (list x))) |
| 75 | + |
| 76 | +(defun tsc--hl-at (pos face) |
| 77 | + "Return t if text at POS is highlighted with FACE." |
| 78 | + (memq face (tsc--listify (get-text-property pos 'face)))) |
| 79 | + |
| 80 | +(defun tsc-test-no-op (&rest _args)) |
| 81 | + |
| 82 | +(defvar tsc-test-no-op |
| 83 | + (byte-compile #'tsc-test-no-op)) |
| 84 | + |
| 85 | +(defun tsc-test-render-node (type named-p start-byte end-byte field depth) |
| 86 | + (when named-p |
| 87 | + (message "%s%s%S (%s . %s)" (make-string (* 2 depth) ?\ ) |
| 88 | + (if field |
| 89 | + (format "%s " field) |
| 90 | + "") |
| 91 | + type start-byte end-byte))) |
| 92 | + |
| 93 | +(defmacro tsc-test-with (lang-symbol var &rest body) |
| 94 | + "Eval BODY with VAR bound to a new parser for LANG-SYMBOL." |
| 95 | + (declare (indent 2)) |
| 96 | + `(let ((,var (tsc-test-make-parser ',lang-symbol))) |
| 97 | + ,@body)) |
| 98 | + |
| 99 | +(defmacro tsc-test-with-file (relative-path &rest body) |
| 100 | + "Eval BODY in a temp buffer filled with content of the file at RELATIVE-PATH." |
| 101 | + (declare (indent 1)) |
| 102 | + `(with-temp-buffer |
| 103 | + (let ((coding-system-for-read 'utf-8)) |
| 104 | + (insert-file-contents (tsc-test-full-path ,relative-path))) |
| 105 | + ,@body)) |
| 106 | + |
| 107 | +(defmacro tsc-test-lang-with-file (lang-symbol relative-path &rest body) |
| 108 | + "Eval BODY in a temp buffer filled with content of the file at RELATIVE-PATH. |
| 109 | +`tree-sitter-mode' is turned on, using the given language LANG-SYMBOL." |
| 110 | + (declare (indent 2)) |
| 111 | + `(tsc-test-with-file ,relative-path |
| 112 | + (tsc-test-use-lang ',lang-symbol) |
| 113 | + ,@body)) |
| 114 | + |
| 115 | +(defmacro tsc-test-with-advice (symbol where function &rest body) |
| 116 | + "Eval BODY while advising SYMBOL with FUNCTION at WHERE." |
| 117 | + (declare (indent 3)) |
| 118 | + `(progn |
| 119 | + (advice-add ,symbol ,where ,function) |
| 120 | + (unwind-protect |
| 121 | + ,@body |
| 122 | + (advice-remove ,symbol ,function)))) |
| 123 | + |
| 124 | +(defmacro tsc-test-capture-messages (&rest body) |
| 125 | + `(with-temp-buffer |
| 126 | + (let ((buf (current-buffer))) |
| 127 | + (tsc-test-with-advice 'message :override |
| 128 | + (lambda (fmt &rest args) |
| 129 | + (with-current-buffer buf |
| 130 | + (insert (apply #'format-message fmt args) "\n"))) |
| 131 | + ,@body) |
| 132 | + (with-current-buffer buf |
| 133 | + (buffer-string))))) |
| 134 | + |
| 135 | +;; Local Variables: |
| 136 | +;; no-byte-compile: t |
| 137 | +;; End: |
| 138 | + |
| 139 | +(provide 'tree-sitter-tests-utils) |
| 140 | +;;; tree-sitter-tests-utils.el ends here |
0 commit comments