projectile icon indicating copy to clipboard operation
projectile copied to clipboard

Feature request: Test for separate functions or files

Open Mariownyou opened this issue 3 years ago • 2 comments

Expected behaviour

I want to execute the at my cursor point. For example I’m in file test.py and my cursor pointing at def test_test. I want to execute this test.

Ideally you need to parse function and class name and concat it to file path then return them in some function. In this case user can define test command and use your parsed data. This approach will allow users to create test commands for different languages or projects.

Please consider this feature it will be very helpful:)

Mariownyou avatar Apr 13 '22 22:04 Mariownyou

Testing the test at point sounds a bit tricky, but this is what I do for running tests for the current file, I add advice around projectile-update-project-type to allow registration of a test-file-fn property for each project type:

  (cl-defun lw-projectile-update-project-type-override
      (old-fn
       project-type
       &key precedence
       (marker-files nil marker-files-specified)
       (project-file nil project-file-specified)
       (compilation-dir nil compilation-dir-specified)
       (configure nil configure-specified)
       (compile nil compile-specified)
       (install nil install-specified)
       (package nil package-specified)
       (test nil test-specified)
       (run nil run-specified)
       (test-suffix nil test-suffix-specified)
       (test-prefix nil test-prefix-specified)
       (src-dir nil src-dir-specified)
       (test-dir nil test-dir-specified)
       (related-files-fn nil related-files-fn-specified)
       (test-file-fn nil test-file-fn-specified)
       (repl-fn nil repl-fn-specified))
    (apply old-fn
           (append (list project-type)
                   (when marker-files-specified `(:marker-files ,marker-files))
                   (when project-file-specified `(:project-file ,project-file))
                   (when compilation-dir-specified
                     `(:compilation-dir ,compilation-dir))
                   (when configure-specified `(:configure ,configure))
                   (when compile-specified `(:compile ,compile))
                   (when install-specified `(:install ,install))
                   (when package-specified `(:package ,package))
                   (when test-specified `(:test ,test))
                   (when run-specified `(:run ,run))
                   (when test-suffix-specified `(:test-suffix ,test-suffix))
                   (when test-prefix-specified `(:test-prefix ,test-prefix))
                   (when src-dir-specified `(:src-dir ,src-dir))
                   (when test-dir-specified `(:test-dir ,test-dir))
                   (when related-files-fn-specified
                     `(:related-files-fn ,related-files-fn))
                   `(:precedence ,precedence)))
    (setq projectile-project-types
          (--map-when (eq (car it) project-type)
                      (cons project-type
                            (projectile--combine-plists
                             (cdr it)
                             (append (when test-file-fn
                                       (list 'test-file-fn test-file-fn))
                                     (when repl-fn (list 'repl-fn repl-fn)))))
                      projectile-project-types)))

  (advice-add 'projectile-update-project-type
              :around
              #'lw-projectile-update-project-type-override)

  (defun lw-projectile-test-file ()
    "Run the test file for the current buffer, as opposed to all tests."
    (interactive)
    (when-let* ((test-file-fn
                 (projectile-project-type-attribute
                  (projectile-project-type) 'test-file-fn))
                (current-file (buffer-file-name))
                (target-file (if (projectile-test-file-p current-file) current-file (projectile-find-implementation-or-test current-file)))
                (command-str (funcall test-file-fn target-file)))
      (projectile--run-project-cmd command-str
                                   (make-hash-table)
                                   :show-prompt 0
                                   :prompt-prefix "Test command: "
                                   :save-buffers t)))

(define-key projectile-mode-map (kbd "C-c C-f") #'lw-projectile-test-file)

Not particularly pretty, but from here I can add strategies for running individual test files for certain project types, e.g. for sbt:

(defun lw-jvm-get-file-package (&optional directory)
  (mapconcat 'identity
             (split-string
              (replace-regexp-in-string ".*src\\(/\\(main\\|test\\)\\)?\\(/scala\\)?"
                                        "" (or directory default-directory)) "/" t) "."))

(defun lw-sbt-test-file-fn (file-name)
    (interactive)
    (concat (if (executable-find "sbtn") "sbtn" "sbt") " 'testOnly "
            (lw-jvm-get-file-package (f-dirname file-name))
            "." (f-no-ext (f-filename file-name)) "'"))

(projectile-update-project-type
   'sbt
   :test-file-fn #'lw-sbt-test-file-fn)

From here I can C-c C-f from from either the implementation or test file to run tests for that particular file. I hope this is helpful.

LaurenceWarne avatar Apr 19 '22 13:04 LaurenceWarne

I guess the main problem with such feature is that we'll have to have two test commands for each project type - one that runs all the tests and one that can run a single test. It's not hard to do, but I'm not sure if it's worth a generic solution if most people can easily hack together something for their particular use-case.

bbatsov avatar Oct 25 '22 09:10 bbatsov