1 ;;; vc-tests.el --- Tests of different backends of vc.el
3 ;; Copyright (C) 2014-2016 Free Software Foundation, Inc.
5 ;; Author: Michael Albinus <michael.albinus@gmx.de>
7 ;; This program is free software: you can redistribute it and/or
8 ;; modify it under the terms of the GNU General Public License as
9 ;; published by the Free Software Foundation, either version 3 of the
10 ;; License, or (at your option) any later version.
12 ;; This program is distributed in the hope that it will be useful, but
13 ;; WITHOUT ANY WARRANTY; without even the implied warranty of
14 ;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15 ;; General Public License for more details.
17 ;; You should have received a copy of the GNU General Public License
18 ;; along with this program. If not, see `http://www.gnu.org/licenses/'.
22 ;; For every supported VC on the machine, different test cases are
23 ;; generated automatically.
25 ;; Functions to be tested (see Commentary of vc.el). Mandatory
26 ;; functions are marked with `*', optional functions are marked with `-':
30 ;; * revision-granularity DONE
32 ;; STATE-QUERYING FUNCTIONS
34 ;; * registered (file) DONE
35 ;; * state (file) DONE
36 ;; - dir-status (dir update-function)
37 ;; - dir-status-files (dir files default-state update-function)
38 ;; - dir-extra-headers (dir)
39 ;; - dir-printer (fileinfo)
40 ;; - status-fileinfo-extra (file)
41 ;; * working-revision (file) DONE
42 ;; - latest-on-branch-p (file)
43 ;; * checkout-model (files) DONE
44 ;; - mode-line-string (file)
46 ;; STATE-CHANGING FUNCTIONS
48 ;; * create-repo (backend) DONE
49 ;; * register (files &optional comment) DONE
50 ;; - responsible-p (file)
51 ;; - receive-file (file rev)
52 ;; - unregister (file) DONE
53 ;; * checkin (files comment)
54 ;; * find-revision (file rev buffer)
55 ;; * checkout (file &optional rev)
56 ;; * revert (file &optional contents-done)
58 ;; - merge-file (file rev1 rev2)
60 ;; - merge-news (file)
62 ;; - steal-lock (file &optional revision)
63 ;; - modify-change-comment (files rev comment)
64 ;; - mark-resolved (files)
65 ;; - find-admin-dir (file)
69 ;; * print-log (files buffer &optional shortlog start-revision limit)
70 ;; * log-outgoing (backend remote-location)
71 ;; * log-incoming (backend remote-location)
73 ;; - show-log-entry (revision)
74 ;; - comment-history (file)
75 ;; - update-changelog (files)
76 ;; * diff (files &optional async rev1 rev2 buffer)
77 ;; - revision-completion-table (files)
78 ;; - annotate-command (file buf &optional rev)
80 ;; - annotate-current-time ()
81 ;; - annotate-extract-revision-at-line ()
82 ;; - region-history (FILE BUFFER LFROM LTO)
83 ;; - region-history-mode ()
87 ;; - create-tag (dir name branchp)
88 ;; - retrieve-tag (dir name update)
92 ;; - make-version-backups-p (file)
94 ;; - ignore (file &optional directory)
95 ;; - ignore-completion-table
96 ;; - previous-revision (file rev)
97 ;; - next-revision (file rev)
100 ;; - delete-file (file)
101 ;; - rename-file (old new)
102 ;; - find-file-hook ()
104 ;; - extra-dir-menu ()
105 ;; - conflicted-files (dir)
112 ;; The working horses.
114 (defvar vc-test--cleanup-hook nil
115 "Functions for cleanup at the end of an ert test.
116 Don't set it globally, the functions shall be let-bound.")
118 (defun vc-test--revision-granularity-function (backend)
119 "Run the `vc-revision-granularity' backend function."
120 (funcall (intern (downcase (format "vc-%s-revision-granularity" backend)))))
122 (defun vc-test--create-repo-function (backend)
123 "Run the `vc-create-repo' backend function.
124 For backends which dont support it, it is emulated."
130 (make-temp-name "vc-test") temporary-file-directory)))
131 (make-directory (expand-file-name "module" tmp-dir) 'parents)
132 (make-directory (expand-file-name "CVSROOT" tmp-dir) 'parents)
133 (if (not (fboundp 'w32-application-type))
134 (shell-command-to-string (format "cvs -Q -d:local:%s co module"
136 (let ((cvs-prog (executable-find "cvs"))
138 ;; If CVS executable is an MSYS program, reformat the file
139 ;; name of TMP-DIR to have the /d/foo/bar form supported by
140 ;; MSYS programs. (FIXME What about Cygwin cvs.exe?)
141 (if (eq (w32-application-type cvs-prog) 'msys)
143 (concat "/" (substring tmp-dir 0 1) (substring tmp-dir 2))))
144 (shell-command-to-string (format "cvs -Q -d:local:%s co module"
146 (rename-file "module/CVS" default-directory)
147 (delete-directory "module" 'recursive)
148 ;; We must cleanup the "remote" CVS repo as well.
149 (add-hook 'vc-test--cleanup-hook
150 `(lambda () (delete-directory ,tmp-dir 'recursive)))))
153 (let ((archive-name (format "%s--%s" user-mail-address (random))))
155 "no arch user id set" (shell-command-to-string "tla my-id"))
156 (shell-command-to-string
157 (format "tla my-id \"<%s>\"" user-mail-address)))
158 (shell-command-to-string
159 (format "tla make-archive %s %s" archive-name default-directory))
160 (shell-command-to-string
161 (format "tla my-default-archive %s" archive-name))))
164 (let ((archive-name "foo.mtn"))
165 (shell-command-to-string
167 "mtn db init --db=%s"
168 (expand-file-name archive-name default-directory)))
169 (shell-command-to-string
170 (format "mtn --db=%s --branch=foo setup ." archive-name))))
172 (t (vc-create-repo backend))))
174 (defun vc-test--create-repo (backend)
175 "Create a test repository in `default-directory', a temporary directory."
177 (let ((vc-handled-backends `(,backend))
179 (file-name-as-directory
181 (make-temp-name "vc-test") temporary-file-directory)))
182 vc-test--cleanup-hook)
188 'vc-test--cleanup-hook
189 `(lambda () (delete-directory ,default-directory 'recursive)))
191 ;; Check the revision granularity.
192 (should (memq (vc-test--revision-granularity-function backend)
195 ;; Create empty repository.
196 (make-directory default-directory)
197 (should (file-directory-p default-directory))
198 (vc-test--create-repo-function backend)
199 (should (eq (vc-responsible-backend default-directory) backend)))
202 (ignore-errors (run-hooks 'vc-test--cleanup-hook)))))
204 ;; FIXME Why isn't there `vc-unregister'?
205 (defun vc-test--unregister-function (backend file)
206 "Run the `vc-unregister' backend function.
207 For backends which dont support it, `vc-not-supported' is signalled."
210 (let ((symbol (intern (downcase (format "vc-%s-unregister" backend)))))
211 (if (functionp symbol)
212 (funcall symbol file)
213 ;; CVS, SVN, SCCS, SRC and Mtn are not supported.
214 (signal 'vc-not-supported (list 'unregister backend))))
216 ;; FIXME This shall be called in `vc-unregister'.
217 (vc-file-clearprops file)))
219 (defun vc-test--register (backend)
220 "Register and unregister a file.
221 This checks also `vc-backend' and `vc-reponsible-backend'."
223 (let ((vc-handled-backends `(,backend))
225 (file-name-as-directory
227 (make-temp-name "vc-test") temporary-file-directory)))
228 vc-test--cleanup-hook)
234 'vc-test--cleanup-hook
235 `(lambda () (delete-directory ,default-directory 'recursive)))
237 ;; Create empty repository.
238 (make-directory default-directory)
239 (vc-test--create-repo-function backend)
240 ;; For file oriented backends CVS, RCS and SVN the backend is
241 ;; returned, and the directory is registered already.
242 ;; FIXME is this correct?
243 (should (if (vc-backend default-directory)
244 (vc-registered default-directory)
245 (not (vc-registered default-directory))))
246 (should (eq (vc-responsible-backend default-directory) backend))
248 (let ((tmp-name1 (expand-file-name "foo" default-directory))
250 ;; Register files. Check for it.
251 (write-region "foo" nil tmp-name1 nil 'nomessage)
252 (should (file-exists-p tmp-name1))
253 (should-not (vc-backend tmp-name1))
254 (should (eq (vc-responsible-backend tmp-name1) backend))
255 (should-not (vc-registered tmp-name1))
257 (write-region "bla" nil tmp-name2 nil 'nomessage)
258 (should (file-exists-p tmp-name2))
259 (should-not (vc-backend tmp-name2))
260 (should (eq (vc-responsible-backend tmp-name2) backend))
261 (should-not (vc-registered tmp-name2))
263 (vc-register (list backend (list tmp-name1 tmp-name2)))
264 (should (file-exists-p tmp-name1))
265 (should (eq (vc-backend tmp-name1) backend))
266 (should (eq (vc-responsible-backend tmp-name1) backend))
267 (should (vc-registered tmp-name1))
269 (should (file-exists-p tmp-name2))
270 (should (eq (vc-backend tmp-name2) backend))
271 (should (eq (vc-responsible-backend tmp-name2) backend))
272 (should (vc-registered tmp-name2))
274 ;; FIXME `vc-backend' accepts also a list of files,
275 ;; `vc-responsible-backend' doesn't. Is this right?
276 (should (vc-backend (list tmp-name1 tmp-name2)))
278 ;; Unregister the files.
281 (vc-test--unregister-function backend tmp-name1)
282 (should-not (vc-backend tmp-name1))
283 (should-not (vc-registered tmp-name1))
284 (vc-test--unregister-function backend tmp-name2)
285 (should-not (vc-backend tmp-name2))
286 (should-not (vc-registered tmp-name2)))
287 ;; CVS, SVN, SCCS, SRC and Mtn are not supported.
289 (t (signal (car err) (cdr err))))
291 ;; The files shall still exist.
292 (should (file-exists-p tmp-name1))
293 (should (file-exists-p tmp-name2))))
296 (ignore-errors (run-hooks 'vc-test--cleanup-hook)))))
298 (defun vc-test--state (backend)
299 "Check the different states of a file."
301 (let ((vc-handled-backends `(,backend))
303 (file-name-as-directory
305 (make-temp-name "vc-test") temporary-file-directory)))
306 vc-test--cleanup-hook)
312 'vc-test--cleanup-hook
313 `(lambda () (delete-directory ,default-directory 'recursive)))
315 ;; Create empty repository. Check repository state.
316 (make-directory default-directory)
317 (vc-test--create-repo-function backend)
321 ;; unregistered: CVS SCCS SRC
322 ;; up-to-date: Bzr SVN
323 (message "vc-state1 %s" (vc-state default-directory))
324 (should (eq (vc-state default-directory)
325 (vc-state default-directory backend)))
326 (should (memq (vc-state default-directory)
327 '(nil added unregistered up-to-date)))
329 (let ((tmp-name (expand-file-name "foo" default-directory)))
330 ;; Check state of an empty file.
332 ;; nil: Hg Mtn SRC SVN
334 ;; unregistered: RCS SCCS
335 ;; up-to-date: Bzr CVS
336 (message "vc-state2 %s" (vc-state tmp-name))
337 (should (eq (vc-state tmp-name) (vc-state tmp-name backend)))
338 (should (memq (vc-state tmp-name)
339 '(nil added unregistered up-to-date)))
341 ;; Write a new file. Check state.
342 (write-region "foo" nil tmp-name nil 'nomessage)
346 ;; unregistered: Hg RCS SCCS SRC SVN
347 ;; up-to-date: Bzr CVS
348 (message "vc-state3 %s" (vc-state tmp-name))
349 (should (eq (vc-state tmp-name) (vc-state tmp-name backend)))
350 (should (memq (vc-state tmp-name)
351 '(nil added unregistered up-to-date)))
353 ;; Register a file. Check state.
355 (list backend (list (file-name-nondirectory tmp-name))))
358 ;; unregistered: Hg RCS SCCS SRC SVN
359 ;; up-to-date: Bzr CVS
360 (message "vc-state4 %s" (vc-state tmp-name))
361 (should (eq (vc-state tmp-name) (vc-state tmp-name backend)))
362 (should (memq (vc-state tmp-name) '(added unregistered up-to-date)))
364 ;; Unregister the file. Check state.
367 (vc-test--unregister-function backend tmp-name)
370 ;; unregistered: Hg RCS
371 ;; unsupported: CVS Mtn SCCS SRC SVN
373 (message "vc-state5 %s" (vc-state tmp-name))
374 (should (eq (vc-state tmp-name) (vc-state tmp-name backend)))
375 (should (memq (vc-state tmp-name)
376 '(added unregistered up-to-date))))
377 (vc-not-supported (message "vc-state5 unsupported"))
378 (t (signal (car err) (cdr err))))))
381 (ignore-errors (run-hooks 'vc-test--cleanup-hook)))))
383 (defun vc-test--working-revision (backend)
384 "Check the working revision of a repository."
386 (let ((vc-handled-backends `(,backend))
388 (file-name-as-directory
390 (make-temp-name "vc-test") temporary-file-directory)))
391 vc-test--cleanup-hook)
397 'vc-test--cleanup-hook
398 `(lambda () (delete-directory ,default-directory 'recursive)))
400 ;; Create empty repository. Check working revision of
401 ;; repository, should be nil.
402 (make-directory default-directory)
403 (vc-test--create-repo-function backend)
405 ;; nil: CVS Git Mtn RCS SCCS
406 ;; "0": Bzr Hg SRC SVN
408 "vc-working-revision1 %s" (vc-working-revision default-directory))
409 (should (eq (vc-working-revision default-directory)
410 (vc-working-revision default-directory backend)))
411 (should (member (vc-working-revision default-directory) '(nil "0")))
413 (let ((tmp-name (expand-file-name "foo" default-directory)))
414 ;; Check initial working revision, should be nil until
417 ;; nil: CVS Git Mtn RCS SCCS SVN
419 (message "vc-working-revision2 %s" (vc-working-revision tmp-name))
420 (should (eq (vc-working-revision tmp-name)
421 (vc-working-revision tmp-name backend)))
422 (should (member (vc-working-revision tmp-name) '(nil "0")))
424 ;; Write a new file. Check working revision.
425 (write-region "foo" nil tmp-name nil 'nomessage)
427 ;; nil: CVS Git Mtn RCS SCCS SVN
429 (message "vc-working-revision3 %s" (vc-working-revision tmp-name))
430 (should (eq (vc-working-revision tmp-name)
431 (vc-working-revision tmp-name backend)))
432 (should (member (vc-working-revision tmp-name) '(nil "0")))
434 ;; Register a file. Check working revision.
436 (list backend (list (file-name-nondirectory tmp-name))))
439 ;; "0": Bzr CVS Hg SRC SVN
441 (message "vc-working-revision4 %s" (vc-working-revision tmp-name))
442 (should (eq (vc-working-revision tmp-name)
443 (vc-working-revision tmp-name backend)))
444 (should (member (vc-working-revision tmp-name) '(nil "0" "1.1")))
446 ;; Unregister the file. Check working revision.
449 (vc-test--unregister-function backend tmp-name)
453 ;; unsupported: CVS Mtn SCCS SRC SVN
455 "vc-working-revision5 %s" (vc-working-revision tmp-name))
456 (should (eq (vc-working-revision tmp-name)
457 (vc-working-revision tmp-name backend)))
458 (should (member (vc-working-revision tmp-name) '(nil "0"))))
459 (vc-not-supported (message "vc-working-revision5 unsupported"))
460 (t (signal (car err) (cdr err))))))
463 (ignore-errors (run-hooks 'vc-test--cleanup-hook)))))
465 (defun vc-test--checkout-model (backend)
466 "Check the checkout model of a repository."
468 (let ((vc-handled-backends `(,backend))
470 (file-name-as-directory
472 (make-temp-name "vc-test") temporary-file-directory)))
473 vc-test--cleanup-hook)
479 'vc-test--cleanup-hook
480 `(lambda () (delete-directory ,default-directory 'recursive)))
482 ;; Create empty repository. Check repository checkout model.
483 (make-directory default-directory)
484 (vc-test--create-repo-function backend)
486 ;; Surprisingly, none of the backends returns 'announce.
488 ;; implicit: Bzr CVS Git Hg Mtn SRC SVN
491 "vc-checkout-model1 %s"
492 (vc-checkout-model backend default-directory))
493 (should (memq (vc-checkout-model backend default-directory)
494 '(announce implicit locking)))
496 (let ((tmp-name (expand-file-name "foo" default-directory)))
497 ;; Check checkout model of an empty file.
500 ;; implicit: Bzr CVS Git Hg Mtn SRC SVN
503 "vc-checkout-model2 %s" (vc-checkout-model backend tmp-name))
504 (should (memq (vc-checkout-model backend tmp-name)
505 '(announce implicit locking)))
507 ;; Write a new file. Check checkout model.
508 (write-region "foo" nil tmp-name nil 'nomessage)
511 ;; implicit: Bzr CVS Git Hg Mtn SRC SVN
514 "vc-checkout-model3 %s" (vc-checkout-model backend tmp-name))
515 (should (memq (vc-checkout-model backend tmp-name)
516 '(announce implicit locking)))
518 ;; Register a file. Check checkout model.
520 (list backend (list (file-name-nondirectory tmp-name))))
523 ;; implicit: Bzr CVS Git Hg Mtn SRC SVN
526 "vc-checkout-model4 %s" (vc-checkout-model backend tmp-name))
527 (should (memq (vc-checkout-model backend tmp-name)
528 '(announce implicit locking)))
530 ;; Unregister the file. Check checkout model.
533 (vc-test--unregister-function backend tmp-name)
536 ;; implicit: Bzr Git Hg
537 ;; unsupported: CVS Mtn SCCS SRC SVN
539 "vc-checkout-model5 %s" (vc-checkout-model backend tmp-name))
540 (should (memq (vc-checkout-model backend tmp-name)
541 '(announce implicit locking))))
542 (vc-not-supported (message "vc-checkout-model5 unsupported"))
543 (t (signal (car err) (cdr err))))))
546 (ignore-errors (run-hooks 'vc-test--cleanup-hook)))))
548 ;; Create the test cases.
550 (defun vc-test--rcs-enabled ()
551 (executable-find "rcs"))
553 (defun vc-test--cvs-enabled ()
554 (executable-find "cvs"))
556 (defvar vc-svn-program)
557 (defun vc-test--svn-enabled ()
558 (executable-find vc-svn-program))
560 (defun vc-test--sccs-enabled ()
561 (executable-find "sccs"))
563 (defvar vc-src-program)
564 (defun vc-test--src-enabled ()
565 (executable-find vc-src-program))
567 (defvar vc-bzr-program)
568 (defun vc-test--bzr-enabled ()
569 (executable-find vc-bzr-program))
571 (defvar vc-git-program)
572 (defun vc-test--git-enabled ()
573 (executable-find vc-git-program))
575 (defvar vc-hg-program)
576 (defun vc-test--hg-enabled ()
577 (executable-find vc-hg-program))
579 (defvar vc-mtn-program)
580 (defun vc-test--mtn-enabled ()
581 (executable-find vc-mtn-program))
584 (defvar vc-arch-program)
585 (defun vc-test--arch-enabled ()
586 (executable-find vc-arch-program))
588 ;; Create the test cases.
589 (dolist (backend vc-handled-backends)
590 (let ((backend-string (downcase (symbol-name backend))))
591 (require (intern (format "vc-%s" backend-string)))
593 ;; Check, whether the backend is supported.
594 `(when (funcall ',(intern (format "vc-test--%s-enabled" backend-string)))
597 ,(intern (format "vc-test-%s00-create-repo" backend-string)) ()
598 ,(format "Check `vc-create-repo' for the %s backend."
600 (vc-test--create-repo ',backend))
603 ,(intern (format "vc-test-%s01-register" backend-string)) ()
605 "Check `vc-register' and `vc-registered' for the %s backend."
609 (ert-test-most-recent-result
612 (format "vc-test-%s00-create-repo" backend-string))))))
613 (vc-test--register ',backend))
616 ,(intern (format "vc-test-%s02-state" backend-string)) ()
617 ,(format "Check `vc-state' for the %s backend." backend-string)
618 ;; FIXME make this pass.
619 :expected-result ,(if (equal backend 'SRC) :failed :passed)
622 (ert-test-most-recent-result
625 (format "vc-test-%s01-register" backend-string))))))
626 (vc-test--state ',backend))
629 ,(intern (format "vc-test-%s03-working-revision" backend-string)) ()
630 ,(format "Check `vc-working-revision' for the %s backend."
634 (ert-test-most-recent-result
637 (format "vc-test-%s01-register" backend-string))))))
638 (vc-test--working-revision ',backend))
641 ,(intern (format "vc-test-%s04-checkout-model" backend-string)) ()
642 ,(format "Check `vc-checkout-model' for the %s backend."
644 ;; FIXME make this pass.
645 :expected-result ,(if (equal backend 'RCS) :failed :passed)
648 (ert-test-most-recent-result
651 (format "vc-test-%s01-register" backend-string))))))
652 (vc-test--checkout-model ',backend))))))
655 ;;; vc-tests.el ends here