leibowitz
Experimental Common Lisp object storage abstraction for Unix file systems
leibowitz/tests/cli.lisp
Download raw file: tests/cli.lisp
;;; Integration tests for the command line
(in-package :leibowitz/tests)
(define-test cli)
(defmacro define-cli-test (name (main) &body body)
(check-type main symbol)
`(define-test ,name :parent cli
(let (;; NOTE: each of these variables should be unbound at
;; startup, however capturing them like this binds them to
;; NIL.
*data-directory*
*cache-directory*
*base-directory*
*library*
*webserver*
(*default-pathname-defaults*
(ensure-directories-exist
(pathname
(format NIL "/tmp/leibowitz_cli_test_cwd-tmp~36R/"
(random (expt 36 8))))))
(home (user-homedir-pathname))
(config (uiop:xdg-config-home))
(cache (uiop:xdg-cache-home))
(data (uiop:xdg-data-home)))
(labels ((,main (&rest cli)
(leibowitz.cli:main :test-harness-p T :test-argv cli))
(setenv (key val)
(nix:setenv key (namestring val))))
;; Set this process's copy of $HOME to the new value of
;; `*default-pathname-defaults*' for the duration of each
;; test case. $XDG_CONFIG_HOME, $XDG_CACHE_HOME, and
;; $XDG_DATA_HOME are set as well to the appropriate
;; subdirectories thereof. This fools the likes of
;; `user-homedir-pathname' and `uiop:xdg-*-home' into
;; thinking that we're running as normal in the user's home
;; directory for the duration of these tests, allowing us to
;; screw around without stepping on the their toes.
(setenv "HOME" *default-pathname-defaults*)
(setenv "XDG_CONFIG_HOME" (merge-pathnames ".config/"))
(setenv "XDG_CACHE_HOME" (merge-pathnames ".cache/"))
(setenv "XDG_DATA_HOME" (merge-pathnames ".local/share/"))
(unwind-protect
,@body
(setenv "HOME" home)
(setenv "XDG_CONFIG_HOME" config)
(setenv "XDG_CACHE_HOME" cache)
(setenv "XDG_DATA_HOME" data)
(uiop:delete-directory-tree *default-pathname-defaults* :validate T))))))
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;;; Program context
(define-cli-test infer-resource-files-without-root (run)
(run)
(is #'equal (uiop:xdg-data-home "leibowitz/") *data-directory*)
(is #'equal (uiop:xdg-cache-home "leibowitz/") *cache-directory*)
(is #'equal (user-homedir-pathname) *base-directory*)
(of-type 'library *library*)
(false *webserver*))
(define-cli-test infer-resource-files-with-root (run)
(run "-r" ".")
(is #'equal (merge-pathnames ".leibowitz/") *data-directory*)
(is #'equal (merge-pathnames ".leibowitz/cache/") *cache-directory*)
(is #'equal *default-pathname-defaults* *base-directory*)
(of-type 'library *library*)
(false *webserver*))
(define-cli-test help-and-return-error-on-no-subcommand (run)
)
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;;; Subcommand: help
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;;; Subcommand: info
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;;; Subcommand: index
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;;; Subcommand: web
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;;; Subcommand: find
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;;; Subcommand: show
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;;; Subcommand: tag
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;;; Subcommand: tags
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;;; Subcommand: untag
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;;; Subcommand: untags
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;;; Subcommand: mv
(define-cli-test mv-simple-case-absolute-paths (run)
(let* ((src (namestring (mktmp (user-homedir-pathname))))
(dst (format NIl "~A_renamed" src)))
(run "index" src)
(run "mv" src dst)
(true (get-datum *library* dst))
(false (get-datum *library* src))))
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;;; Subcommand: cp
;;; FIXME: I'm really repeating myself here, the only thing I should
;;; be testing is that -f does indeed pass :overwrite.
(define-cli-test cp-simple-case-absolute-paths (run)
(let* ((src (namestring (mktmp (user-homedir-pathname))))
(dst (format NIL "~A_copy" src)))
(run "index" src)
(run "cp" src dst)
(true (get-datum *library* src))
(true (get-datum *library* dst))))
(define-cli-test cp-relative-path-for-destination (run)
(let* ((src (namestring (mktmp (user-homedir-pathname)))))
(run "index" src)
(run "cp" src "hi")
(true (get-datum *library* (truename "hi")))))
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;;; Subcommand: rm
;; FIXME So much repetition from the core tests!
(define-cli-test remove-non-indexed-files-no-options (run)
(let ((f1 (namestring (mktmp (user-homedir-pathname))))
(f2 (namestring (mktmp (user-homedir-pathname)))))
(true (probe-file f1))
(true (probe-file f2))
(fail (run "rm" f1 f2) 'datum-not-indexed)
(true (probe-file f1))
(true (probe-file f2))))
(define-cli-test remove-indexed-files-no-options (run)
(let ((f (namestring (mktmp (user-homedir-pathname)))))
(run "index" f)
(true (probe-file f))
(true (get-datum *library* f))
(run "rm" f)
(false (probe-file f))
(false (get-datum *library* f))))
(define-cli-test remove-indexed-file-not-on-disk (run)
(let ((f (namestring (mktmp (user-homedir-pathname)))))
(run "index" f)
(delete-file f)
(run "rm" f)
(false (get-datum *library* f))))
(define-cli-test attempt-to-remove-nonexistent-file (run)
(let ((f1 (namestring (mktmp (user-homedir-pathname))))
(f2 (namestring (mktmp (user-homedir-pathname)))))
(run "index" f1)
(run "index" f2)
(fail (run "rm" f1 f2 "hopefully/no/such/file/or/directory")
;; FIXME: del-datum is idempotent and I prefer it that
;; way.... but it also makes the most sense for it to throw this
;; in order to remove the burden of error checking from the
;; caller
'no-such-datum-in-disk-or-db)
(true (probe-file f1))
(true (probe-file f2))
(true (get-datum *library* f1))
(true (get-datum *library* f2))))
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;;; Subcommand: ls
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;;; Subcommand: show-tag
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;;; Subcommand: ls-tag
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;;; Subcommand: mv-tag
(define-cli-test mv-tag (run)
(run "index" (namestring (mktmp (user-homedir-pathname)))) ;; initialize db
(add-tag *library* "src")
(run "mv-tag" "src" "dst")
(false (get-tag *library* "src"))
(true (get-tag *library* "dst")))
(define-cli-test mv-tag-overwrite (run)
(run "index" (namestring (mktmp (user-homedir-pathname)))) ;; initialize db
(add-tag *library* "src")
(add-tag *library* "dst")
(fail (run "mv-tag" "src" "dst"))
(true (get-tag *library* "src"))
(true (get-tag *library* "dst"))
(run "mv-tag" "-f" "src" "dst")
(false (get-tag *library* "src"))
(true (get-tag *library* "dst")))
(define-cli-test mv-tag-merge (run)
(run "index" (namestring (mktmp (user-homedir-pathname)))) ;; initialize db
(add-tag *library* "src")
(add-tag *library* "dst")
(fail (run "mv-tag" "src" "dst"))
(true (get-tag *library* "src"))
(true (get-tag *library* "dst"))
(run "mv-tag" "-m" "src" "dst")
(false (get-tag *library* "src"))
(true (get-tag *library* "dst")))
(define-cli-test mv-tag-both-args (run)
(run "index" (namestring (mktmp (user-homedir-pathname)))) ;; initialize db
(fail (run "mv-tag" "-o" "-m" "src" "dst")))
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;;; Subcommand: cp-tag
(define-cli-test cp-tag (run)
(run "index" (namestring (mktmp (user-homedir-pathname)))) ;; initialize db
(add-tag *library* "src")
(run "cp-tag" "src" "dst")
(true (get-tag *library* "src"))
(true (get-tag *library* "dst")))
(define-cli-test cp-tag-overwrite (run)
(run "index" (namestring (mktmp (user-homedir-pathname)))) ;; initialize db
(add-tag *library* "src")
(add-tag *library* "dst")
(fail (run "cp-tag" "src" "dst"))
(true (get-tag *library* "src"))
(true (get-tag *library* "dst"))
(run "cp-tag" "-f" "src" "dst")
(true (get-tag *library* "src"))
(true (get-tag *library* "dst")))
(define-cli-test cp-tag-merge (run)
(run "index" (namestring (mktmp (user-homedir-pathname)))) ;; initialize db
(add-tag *library* "src")
(add-tag *library* "dst")
(fail (run "cp-tag" "src" "dst"))
(true (get-tag *library* "src"))
(true (get-tag *library* "dst"))
(run "cp-tag" "-m" "src" "dst")
(true (get-tag *library* "src"))
(true (get-tag *library* "dst")))
(define-cli-test cp-tag-both-args (run)
(run "index" (namestring (mktmp (user-homedir-pathname)))) ;; initialize db
(fail (run "cp-tag" "-o" "-m" "src" "dst")))
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;;; Subcommand: rm-tag
(define-cli-test remove-tag (run)
(let ((path (namestring (mktmp (user-homedir-pathname)))))
(run "index" path)
(add-datum-tags *library* path '("some tag"))
(is #'= 1 (length (get-datum-tags *library* path)))
(true (get-tag *library* "some tag"))
(run "rm-tag" "some tag")
(false (get-tag *library* "some tag"))
(false (get-datum-tags *library* path))))