diff options
Diffstat (limited to 'tests')
| -rw-r--r-- | tests/test-duet-pane.el | 165 | ||||
| -rw-r--r-- | tests/test-duet-smoke.el | 9 |
2 files changed, 168 insertions, 6 deletions
diff --git a/tests/test-duet-pane.el b/tests/test-duet-pane.el new file mode 100644 index 0000000..181309b --- /dev/null +++ b/tests/test-duet-pane.el @@ -0,0 +1,165 @@ +;;; test-duet-pane.el --- Tests for the commander mode and pane layout -*- lexical-binding: t; -*- + +;; Copyright (C) 2026 Craig Jennings + +;; Author: Craig Jennings <c@cjennings.net> + +;; This program is free software: you can redistribute it and/or modify +;; it under the terms of the GNU General Public License as published by +;; the Free Software Foundation, either version 3 of the License, or +;; (at your option) any later version. + +;; This program is distributed in the hope that it will be useful, +;; but WITHOUT ANY WARRANTY; without even the implied warranty of +;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +;; GNU General Public License for more details. + +;; You should have received a copy of the GNU General Public License +;; along with this program. If not, see <http://www.gnu.org/licenses/>. + +;;; Commentary: + +;; Tests for the batch-safe core of the pane layer: the pure sibling-pane +;; selector (the dirvish#36 fix without needing a live frame), the duet-mode +;; F-key map, and minor-mode keymap precedence. The two-window resolution is +;; also exercised against a real split frame. The live two-pane launch and the +;; F-key feel in a running daemon are Manual tests. + +;;; Code: + +(require 'test-bootstrap (expand-file-name "test-bootstrap.el")) + +;;; Pure sibling-pane selection + +(ert-deftest test-duet-pane-sibling-returns-other-of-two () + "Given two panes, the sibling is the one that is not the active window." + (should (eq 'b (duet--sibling-pane 'a '(a b)))) + (should (eq 'a (duet--sibling-pane 'b '(a b))))) + +(ert-deftest test-duet-pane-sibling-errors-unless-exactly-two () + "Zero, one, or three commander panes is a clear error, not a guess." + (should-error (duet--sibling-pane 'a '(a)) :type 'user-error) + (should-error (duet--sibling-pane 'a '(a b c)) :type 'user-error)) + +(ert-deftest test-duet-pane-sibling-errors-when-window-not-a-pane () + "Asking for the sibling of a window that is not one of the panes errors." + (should-error (duet--sibling-pane 'x '(a b)) :type 'user-error)) + +;;; F-key map + +(ert-deftest test-duet-pane-fkeys-bound () + "The mc/Norton F-keys map to their DUET commands in `duet-mode-map'." + (should (eq 'duet-view (lookup-key duet-mode-map (kbd "<f3>")))) + (should (eq 'duet-edit (lookup-key duet-mode-map (kbd "<f4>")))) + (should (eq 'duet-copy (lookup-key duet-mode-map (kbd "<f5>")))) + (should (eq 'duet-move (lookup-key duet-mode-map (kbd "<f6>")))) + (should (eq 'duet-mkdir (lookup-key duet-mode-map (kbd "<f7>")))) + (should (eq 'duet-delete (lookup-key duet-mode-map (kbd "<f8>")))) + (should (eq 'duet-quit (lookup-key duet-mode-map (kbd "<f10>"))))) + +;;; Minor-mode precedence + +(ert-deftest test-duet-pane-mode-is-buffer-local () + "`duet-mode' is a buffer-local minor mode." + (with-temp-buffer + (duet-mode 1) + (should (bound-and-true-p duet-mode))) + (with-temp-buffer + (should-not (bound-and-true-p duet-mode)))) + +(ert-deftest test-duet-pane-fkey-precedence-inside-vs-outside () + "An F-key resolves to a DUET command inside a pane, but not outside one." + (with-temp-buffer + (duet-mode 1) + (should (eq 'duet-copy (key-binding (kbd "<f5>"))))) + (with-temp-buffer + (should-not (eq 'duet-copy (key-binding (kbd "<f5>")))))) + +;;; Not-yet-implemented action commands + +(ert-deftest test-duet-pane-unimplemented-actions-error () + "The transfer/file actions announce themselves until their phase lands." + (dolist (cmd '(duet-view duet-edit duet-copy duet-move duet-mkdir duet-delete)) + (should-error (funcall cmd) :type 'user-error))) + +;;; Launch, quit, and two-window resolution against a real frame + +(ert-deftest test-duet-pane-other-pane-resolves-sibling-window () + "With two commander panes, `duet--other-pane' returns the sibling window." + (let ((buf-a (generate-new-buffer " *duet-a*")) + (buf-b (generate-new-buffer " *duet-b*"))) + (unwind-protect + (progn + (delete-other-windows) + (set-window-buffer (selected-window) buf-a) + (with-current-buffer buf-a (duet-mode 1)) + (let ((win-b (split-window-right))) + (set-window-buffer win-b buf-b) + (with-current-buffer buf-b (duet-mode 1)) + (should (= 2 (length (duet--commander-windows)))) + (let ((other (duet--other-pane (selected-window)))) + (should (window-live-p other)) + (should (eq buf-b (window-buffer other)))))) + (delete-other-windows) + (kill-buffer buf-a) + (kill-buffer buf-b)))) + +(ert-deftest test-duet-launch-creates-two-commander-panes () + "Launching DUET lays out two side-by-side commander panes." + (let ((duet--saved-window-configuration nil)) + (unwind-protect + (progn + (delete-other-windows) + (duet "/tmp" "/tmp") + (should (= 2 (length (duet--commander-windows)))) + (should (window-live-p (duet--other-pane (selected-window))))) + (delete-other-windows)))) + +(ert-deftest test-duet-quit-restores-prior-layout () + "`duet-quit' restores the single-window layout DUET launched from." + (delete-other-windows) + (duet "/tmp" "/tmp") + (should (= 2 (length (duet--commander-windows)))) + (duet-quit) + (should (= 1 (length (window-list))))) + +(ert-deftest test-duet-pane-directory-reports-pane-dir () + "`duet--pane-directory' reports the directory a pane is showing." + (let ((duet--saved-window-configuration nil)) + (unwind-protect + (progn + (delete-other-windows) + (duet "/tmp" "/tmp") + (should (equal (expand-file-name "/tmp/") + (duet--pane-directory (selected-window))))) + (delete-other-windows)))) + +(ert-deftest test-duet-quit-without-launch-messages () + "Quitting with no saved layout messages rather than erroring." + (let ((duet--saved-window-configuration nil)) + (duet-quit) + (should-not duet--saved-window-configuration))) + +(ert-deftest test-duet-other-pane-defaults-to-selected-window () + "Called with no argument, `duet--other-pane' resolves from the selected window." + (let ((duet--saved-window-configuration nil)) + (unwind-protect + (progn + (delete-other-windows) + (duet "/tmp" "/tmp") + (should (window-live-p (duet--other-pane)))) + (delete-other-windows)))) + +(ert-deftest test-duet-launch-defaults-to-current-directory () + "With no directory arguments, both panes open on the current directory." + (let ((duet--saved-window-configuration nil) + (default-directory "/tmp/")) + (unwind-protect + (progn + (delete-other-windows) + (duet) + (should (= 2 (length (duet--commander-windows))))) + (delete-other-windows)))) + +(provide 'test-duet-pane) +;;; test-duet-pane.el ends here diff --git a/tests/test-duet-smoke.el b/tests/test-duet-smoke.el index 4f88a0e..07d75ea 100644 --- a/tests/test-duet-smoke.el +++ b/tests/test-duet-smoke.el @@ -28,13 +28,10 @@ (require 'test-bootstrap (expand-file-name "test-bootstrap.el")) (ert-deftest test-duet-smoke-feature-loaded () - "The package source loads and defines its entry command." + "The package source loads and defines its entry command and commander mode." (should (featurep 'duet)) - (should (commandp 'duet))) - -(ert-deftest test-duet-smoke-entry-not-yet-implemented () - "The entry command errors until the pane layout lands (Phase 4)." - (should-error (duet))) + (should (commandp 'duet)) + (should (fboundp 'duet-mode))) (provide 'test-duet-smoke) ;;; test-duet-smoke.el ends here |
