From 002215f2ee94252edd66908963a66b01f62c36d1 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 Three 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-file command runs all tests in the current file. It is bound to "C-c C-t f". 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-file): New function. (go-ts-mode-test-package): New function. * etc/NEWS: Mention the change. (Bug#70939) --- etc/NEWS | 16 +++++++ lisp/progmodes/go-ts-mode.el | 90 +++++++++++++++++++++++++++++++++++- 2 files changed, 105 insertions(+), 1 deletion(-) diff --git a/etc/NEWS b/etc/NEWS index 3b18972860f..73fcb46fad2 100644 --- a/etc/NEWS +++ b/etc/NEWS @@ -1389,6 +1389,22 @@ 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 t' in 'go-ts-mode'. + +The 'go-ts-mode-test-file' command runs all unit tests in the current +file. It is bound to 'C-c C-t f' 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-t 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 2d3e6aac090..8d23b230c3f 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) @@ -242,7 +248,10 @@ 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 f" #'go-ts-mode-test-file + "C-c C-t p" #'go-ts-mode-test-package) ;;;###autoload (define-derived-mode go-ts-mode prog-mode "Go" @@ -375,6 +384,85 @@ 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 the 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 the `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) + (if name + (format "^%s$" name) + (error "No test function found"))) + +(defun go-ts-mode--get-functions-in-range (start end) + "Return a list with the names of all defuns in the range START to END." + (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))) + (cond ((or (not node) + (> start node-end) + (< end node-start)) + nil) + ((or (not (equal (treesit-node-type node) "function_declaration")) + (not (string-prefix-p "Test" name))) + (go-ts-mode--get-functions-in-range (treesit-node-end node) end)) + (t + (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." + (let* ((range (if (region-active-p) + (list (region-beginning) (region-end)) + (list (point) (point)))) + (funcs (apply #'go-ts-mode--get-functions-in-range range))) + (if funcs + (string-join funcs "|") + (error "No test function found")))) + +(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-file () + "Run all the unit tests in the current file." + (interactive) + (let ((defuns (go-ts-mode--get-functions-in-range (point-min) (point-max)))) + (if defuns + (go-ts-mode--compile-test (string-join defuns "|")) + (error "No test functions found in the current file")))) + +(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