Skip to content

Instantly share code, notes, and snippets.

@jnpn
Created July 15, 2024 07:45
Show Gist options
  • Save jnpn/311f538756e80be99c2835fe20183b06 to your computer and use it in GitHub Desktop.
Save jnpn/311f538756e80be99c2835fe20183b06 to your computer and use it in GitHub Desktop.
Hackish code to run a test class or the test at point using transient (magit)
;;; django-extensions.el
;;;
;;; various helpers
;;; VARIABLES
;;; TOFIX change <project>
(defvar *project-dir* "/home/jnpn/Code/<project>")
;;; TOFIX: change <app>
(defvar *terminal-template* "xfce4-terminal --working-directory='%s' -H -T '[django.test %s]' -e 'docker compose -f docker-compose.test.yml exec -it <app> python manage.py test %s %s'")
;;; PYTHON
(defun pythonic-file-name ()
"Return python qualified name for current file."
(->> (relative-file-name)
(s-replace "/" ".")
(s-replace ".py" "")))
(defun get-class-context ()
"Return the nearest top level class name for the line at point."
(save-excursion
(let* ((python-class-re "^class \\(.+\\)\\((.*)\\):")
;;; "^class \\\(\\\[^(\\\]+\\\):"
(match (re-search-backward python-class-re nil t)))
(message (if match (match-string 1) "not ok"))
(if match (match-string-no-properties 1) nil))))
(defun get-def-context ()
"Return the nearest def name for the line at point."
(save-excursion
(let* ((python-def-re " +def \\(.+\\)\\((.*)\\):")
(match (re-search-backward python-def-re nil t)))
(message (if match (match-string 1) "not ok"))
(if match (match-string-no-properties 1) nil))))
(defun get-def-test-context ()
"Return the nearest def name for the line at point."
(save-excursion
(let* ((python-def-re " +def \\(test_.+\\)\\((.*)\\):")
(match (re-search-backward python-def-re nil t)))
(message (if match (match-string 1) "not ok"))
(if match (match-string-no-properties 1) nil))))
;;; DJANGO
(defun get-django-nose-fq-test-name ()
"Compute the fully qualified test name at point.
<path>.<class>.<method>"
(interactive)
(if-let* ((ns (pythonic-file-name)) ;;(ns (-> (path-name) slash-to-dots))
(class (get-class-context))
(def (get-def-test-context))
(fqtn (format "%s.%s.%s" ns class def)))
fqtn))
(defun get-django-nose-fq-test-class-name ()
"Compute the fully qualified test name at point.
<path>.<class>.<method>"
(interactive)
(if-let* ((ns (pythonic-file-name)) ;;(ns (-> (path-name) slash-to-dots))
(class (get-class-context)))
(format "%s.%s" ns class)))
(defun copy-django-nose-fq-test-name (args)
"Copy fqtn to system clipboard."
(interactive "P")
(let ((fqtn (get-django-nose-fq-test-name)))
(progn
(message "[copied] %s" fqtn)
(gui-select-text fqtn))))
(defun django-test-class-at-point (&optional options)
"Run the fqtn test at point."
; wip
(interactive)
(let ((hardcoded-root-dir *user-dir*)
(opt (mapconcat #'identity options " "))
(tmpl *terminal-template*)
(fqtn (get-django-nose-fq-test-class-name)))
(message "[django-test] %s [opt] %s" fqtn opt)
(async-shell-command (format tmpl hardcoded-root-dir fqtn fqtn opt))))
(defun django-test-at-point ()
"Run the fqtn test at point."
(interactive)
(let ((hardcoded-root-dir *user-dir*)
(tmpl *terminal-template*)
(fqtn (get-django-nose-fq-test-name)))
(message "[django-test] %s" fqtn)
(async-shell-command (format tmpl hardcoded-root-dir fqtn fqtn))))
;;; UI
;;; django test transient
;;; level ::= app | file | class | method @TODO
;;; args :: parallel . keep-db . failfast
(defun django-test-arguments ()
(transient-args 'django-test-transient))
(transient-define-suffix django-test-class-at-point-t (args)
"Dispatched for django-test-class-at-point."
;; :if #'magit-get-current-branch
;; :description #'magit-push--pushbranch-description
(interactive (list (django-test-arguments)))
(django-test-class-at-point args))
(transient-define-prefix django-test-transient ()
"Run django test."
[:description "Run django tests"]
["Arguments"
("-k" "Keep DB" "--keepdb")
("-f" "Fail Fast" "--failfast")
("-d" "Debug" "--pdb")]
["Test"
[("c" "class at point" django-test-class-at-point-t)
("t" "test at point"
(lambda ()
(interactive)
(django-test-at-point)))]
])
(provide 'django-extension)
;;; SAMPLES TEST
"
class TestEmacs(TestCase):
def test_1(self):
print('1')
def test_2(self):
print('2')
"
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment