aboutsummaryrefslogtreecommitdiff
path: root/tests/testutil-reconcile-open-repos.el
blob: b81e1b48c62fe2adae441f2dd5e7cd67069d52f8 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
;;; testutil-reconcile-open-repos.el --- Test helpers for reconcile-open-repos -*- lexical-binding: t; -*-

;;; Commentary:
;; Provides helper macros and functions for testing reconcile-open-repos.
;; Creates temporary directory trees with fake .git dirs and mocks git commands.

;;; Code:

(require 'cl-lib)

(defmacro reconcile-test-with-temp-dirs (dir-spec &rest body)
  "Create a temp directory tree per DIR-SPEC, bind `test-root', then run BODY.
DIR-SPEC is a list of relative paths.  Paths ending in / create directories;
others create files.  A path containing `.git/' creates the .git dir automatically.

Example:
  (reconcile-test-with-temp-dirs
   (\"repo-a/.git/\" \"repo-b/subdir/\" \"not-a-repo/readme.txt\")
   ...use test-root...)"
  (declare (indent 1))
  `(let ((test-root (make-temp-file "reconcile-test-" t)))
     (unwind-protect
         (progn
           (dolist (path ',dir-spec)
             (let ((full (expand-file-name path test-root)))
               (if (string-suffix-p "/" path)
                   (make-directory full t)
                 (progn
                   (make-directory (file-name-directory full) t)
                   (write-region "" nil full)))))
           ,@body)
       (delete-directory test-root t))))

(defmacro reconcile-test-with-shell-mocks (shell-cmd-fn shell-cmd-to-str-fn &rest body)
  "Run BODY with `shell-command' and `shell-command-to-string' overridden.
SHELL-CMD-FN receives (command) and returns an exit code integer.
SHELL-CMD-TO-STR-FN receives (command) and returns a string."
  (declare (indent 2))
  `(cl-letf (((symbol-function 'shell-command)
              (lambda (cmd &rest _) (funcall ,shell-cmd-fn cmd)))
             ((symbol-function 'shell-command-to-string)
              (lambda (cmd) (funcall ,shell-cmd-to-str-fn cmd))))
     ,@body))

(defvar reconcile-test-git-calls nil
  "List of git argv lists observed during reconcile tests.")

(defmacro reconcile-test-with-git-mock (handler &rest body)
  "Run BODY with `process-file' mocked for git.
HANDLER receives the argv list and returns either an exit code integer or a
plist with :exit and :output."
  (declare (indent 1))
  `(let ((reconcile-test-git-calls nil))
     (cl-letf (((symbol-function 'process-file)
                (lambda (program _infile destination _display &rest args)
                  (unless (string= program "git")
                    (error "Unexpected program: %s" program))
                  (push args reconcile-test-git-calls)
                  (let* ((result (funcall ,handler args))
                         (plist-result (and (consp result) (keywordp (car result))))
                         (exit (if plist-result (plist-get result :exit) result))
                         (output (if plist-result (plist-get result :output) "")))
                    (when (and destination output)
                      (let ((stdout-dest (if (consp destination)
                                             (car destination)
                                           destination)))
                        (cond
                         ((bufferp stdout-dest)
                          (with-current-buffer stdout-dest (insert output)))
                         ((eq stdout-dest t)
                          (insert output)))))
                    exit))))
       ,@body)))

(defvar reconcile-test-magit-calls nil
  "List of directories passed to magit-status during tests.")

(defmacro reconcile-test-with-magit-mock (&rest body)
  "Run BODY with `magit-status' mocked to record calls."
  (declare (indent 0))
  `(let ((reconcile-test-magit-calls nil))
     (cl-letf (((symbol-function 'magit-status)
                (lambda (dir &rest _) (push dir reconcile-test-magit-calls))))
       ,@body)))

(provide 'testutil-reconcile-open-repos)
;;; testutil-reconcile-open-repos.el ends here