From cc6b3267e350861271e366bb3a6c2891cfa8557e Mon Sep 17 00:00:00 2001 From: Ankit R Gadiya Date: Tue, 14 May 2024 00:14:03 +0530 Subject: [PATCH] Add commands to run unit tests in go-ts-mode Two new commands are added in the go-ts-mode to run unit tests. The go-ts-mode-test-function-at-point command runs the current test function at point or all the functions in the active region when region is active. It is bound to "C-c C-t t". The go-ts-mode-test-package command runs all tests in the current package. It is bound to "C-c C-t p". * lisp/progmodes/go-ts-mode.el (go-ts-mode-build-tags): New variable. (go-ts-mode-map): New map variable. (go-ts-mode--get-build-tags-flag): New function. (go-ts-mode--compile-test): New function. (go-ts-mode--find-defun-at): New function. (go-ts-mode--get-function-regexp): New function. (go-ts-mode--get-functions-in-range): New function. (go-ts-mode--get-test-regexp-at-point): New function. (go-ts-mode-test-function-at-point): New function. (go-ts-mode-test-package): New function. * etc/NEWS: Mention the change. (Bug#70939) --- etc/NEWS | 13 +++++++ lisp/progmodes/go-ts-mode.el | 73 +++++++++++++++++++++++++++++++++++- 2 files changed, 85 insertions(+), 1 deletion(-) diff --git a/etc/NEWS b/etc/NEWS index 77b2749fe43..c978c793503 100644 --- a/etc/NEWS +++ b/etc/NEWS @@ -1236,6 +1236,19 @@ This command adds a docstring comment to the current defun. If a comment already exists, point is only moved to the comment. It is bound to 'C-c C-d' in 'go-ts-mode'. +*** New unit test commands. +Two new commands are now available to run unit tests. + +The 'go-ts-mode-test-function-at-point' command runs the unit test at +point. If a region is active, it runs all the unit tests under the +region. It is bound to 'C-c C-t' in 'go-ts-mode'. + +The 'go-ts-mode-test-package' command runs all unit tests under the +package of the current buffer. It is bound to 'C-c C-p' in 'go-ts-mode'. + +The 'go-ts-mode-build-tags' variable is available to set a list of build +tags for the test commands. + ** Man mode +++ diff --git a/lisp/progmodes/go-ts-mode.el b/lisp/progmodes/go-ts-mode.el index aef224ab3fa..f6d872b5210 100644 --- a/lisp/progmodes/go-ts-mode.el +++ b/lisp/progmodes/go-ts-mode.el @@ -46,6 +46,12 @@ go-ts-mode-indent-offset :safe 'integerp :group 'go) +(defcustom go-ts-mode-build-tags nil + "List of go build tags for the test commands." + :version "30.1" + :type '(repeat string) + :group 'go) + (defvar go-ts-mode--syntax-table (let ((table (make-syntax-table))) (modify-syntax-entry ?+ "." table) @@ -237,7 +243,9 @@ go-ts-mode--font-lock-settings (defvar-keymap go-ts-mode-map :doc "Keymap used in Go mode, powered by tree-sitter" :parent prog-mode-map - "C-c C-d" #'go-ts-mode-docstring) + "C-c C-d" #'go-ts-mode-docstring + "C-c C-t t" #'go-ts-mode-test-function-at-point + "C-c C-t p" #'go-ts-mode-test-package) ;;;###autoload (define-derived-mode go-ts-mode prog-mode "Go" @@ -370,6 +378,69 @@ go-ts-mode--comment-on-previous-line-p (<= (treesit-node-start node) point (treesit-node-end node)) (string-equal "comment" (treesit-node-type node))))) +(defun go-ts-mode--get-build-tags-flag () + "Return compile flag for build tags. +This function respects the `go-ts-mode-build-tags' variable for +specifying build tags." + (if go-ts-mode-build-tags + (format "-tags %s" (string-join go-ts-mode-build-tags ",")) + "")) + +(defun go-ts-mode--compile-test (regexp) + "Compile the tests matching REGEXP. +This function respects `go-ts-mode-build-tags' variable for specifying +build tags." + (compile (format "go test -v %s -run '%s'" + (go-ts-mode--get-build-tags-flag) + regexp))) + +(defun go-ts-mode--find-defun-at (start) + "Return the first defun node from START." + (let ((thing (or treesit-defun-type-regexp 'defun))) + (or (treesit-thing-at start thing) + (treesit-thing-next start thing)))) + +(defun go-ts-mode--get-function-regexp (name) + (format "^%s$" name)) + +(defun go-ts-mode--get-functions-in-range (start end) + "Return a list with names of all defuns in the range." + (let* ((node (go-ts-mode--find-defun-at start)) + (name (treesit-defun-name node)) + (node-start (treesit-node-start node)) + (node-end (treesit-node-end node))) + (if (or (not node) + (> start node-end) + (< end node-start)) + nil + (cons (go-ts-mode--get-function-regexp name) + (go-ts-mode--get-functions-in-range (treesit-node-end node) end))))) + +(defun go-ts-mode--get-test-regexp-at-point () + "Return a regular expression for tests at point. +If region is active, the regexp will include all the functions under the +region." + (if (region-active-p) + (string-join (go-ts-mode--get-functions-in-range (region-beginning) + (region-end)) + "|") + (go-ts-mode--get-function-regexp (treesit-defun-name (treesit-defun-at-point))))) + +(defun go-ts-mode-test-function-at-point () + "Run the unit test at point. +If the point is anywhere in the test function, that function will be +run. If the region is selected, all the functions under the region will +be run." + (interactive) + (go-ts-mode--compile-test (go-ts-mode--get-test-regexp-at-point))) + +(defun go-ts-mode-test-package () + "Run all the unit tests under the current package." + (interactive) + (compile (format "go test -v %s -run %s" + (go-ts-mode--get-build-tags-flag) + default-directory))) + ;; go.mod support. (defvar go-mod-ts-mode--syntax-table -- 2.39.2