aboutsummaryrefslogtreecommitdiff
path: root/tests
diff options
context:
space:
mode:
Diffstat (limited to 'tests')
-rw-r--r--tests/test-duet-classify-path.el105
1 files changed, 105 insertions, 0 deletions
diff --git a/tests/test-duet-classify-path.el b/tests/test-duet-classify-path.el
new file mode 100644
index 0000000..b9e8264
--- /dev/null
+++ b/tests/test-duet-classify-path.el
@@ -0,0 +1,105 @@
+;;; test-duet-classify-path.el --- Tests for duet--classify-path -*- 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:
+
+;; Normal/Boundary/Error coverage for `duet--classify-path', the pure path
+;; classifier that turns a path string into a `:locality'/`:method'/`:user'/
+;; `:host'/`:port'/`:localname'/`:hop' plist. TRAMP owns the dissection; these
+;; tests verify the locality decision, the extracted fields, and graceful
+;; handling of paths TRAMP does not recognize as remote.
+
+;;; Code:
+
+(require 'test-bootstrap (expand-file-name "test-bootstrap.el"))
+
+;;; Normal cases
+
+(ert-deftest test-duet-classify-path-local-absolute ()
+ "An absolute local path classifies as local with no remote fields."
+ (let ((p (duet--classify-path "/home/cjennings/file")))
+ (should (eq 'local (plist-get p :locality)))
+ (should (null (plist-get p :method)))
+ (should (null (plist-get p :user)))
+ (should (null (plist-get p :host)))
+ (should (null (plist-get p :port)))
+ (should (null (plist-get p :hop)))
+ (should (equal "/home/cjennings/file" (plist-get p :localname)))))
+
+(ert-deftest test-duet-classify-path-ssh-host-only ()
+ "A remote ssh path with no user fills method/host/localname, user nil."
+ (let ((p (duet--classify-path "/ssh:host:/path")))
+ (should (eq 'remote (plist-get p :locality)))
+ (should (equal "ssh" (plist-get p :method)))
+ (should (null (plist-get p :user)))
+ (should (equal "host" (plist-get p :host)))
+ (should (null (plist-get p :port)))
+ (should (equal "/path" (plist-get p :localname)))))
+
+(ert-deftest test-duet-classify-path-ssh-user-host ()
+ "A user@host ssh path extracts the user."
+ (let ((p (duet--classify-path "/ssh:user@host:/path")))
+ (should (eq 'remote (plist-get p :locality)))
+ (should (equal "user" (plist-get p :user)))
+ (should (equal "host" (plist-get p :host)))
+ (should (equal "/path" (plist-get p :localname)))))
+
+;;; Boundary cases
+
+(ert-deftest test-duet-classify-path-tilde-expands ()
+ "A leading ~ in a local path expands to the home directory."
+ (let ((p (duet--classify-path "~/media")))
+ (should (eq 'local (plist-get p :locality)))
+ (should (equal (expand-file-name "~/media") (plist-get p :localname)))))
+
+(ert-deftest test-duet-classify-path-host-with-port ()
+ "A host#port path splits the port out into the :port field."
+ (let ((p (duet--classify-path "/ssh:user@host#2222:/path")))
+ (should (eq 'remote (plist-get p :locality)))
+ (should (equal "host" (plist-get p :host)))
+ (should (equal "2222" (plist-get p :port)))
+ (should (equal "/path" (plist-get p :localname)))))
+
+(ert-deftest test-duet-classify-path-sshx-and-scp-methods ()
+ "Methods other than ssh are preserved verbatim."
+ (should (equal "sshx" (plist-get (duet--classify-path "/sshx:u@h:/p") :method)))
+ (should (equal "scp" (plist-get (duet--classify-path "/scp:u@h:/p") :method))))
+
+(ert-deftest test-duet-classify-path-multi-hop ()
+ "A multi-hop path reports the final host and preserves the leading hops."
+ (let ((p (duet--classify-path "/ssh:host1|ssh:host2:/path")))
+ (should (eq 'remote (plist-get p :locality)))
+ (should (equal "host2" (plist-get p :host)))
+ (should (equal "/path" (plist-get p :localname)))
+ (should (stringp (plist-get p :hop)))
+ (should (string-match-p "host1" (plist-get p :hop)))))
+
+;;; Error / edge cases
+
+(ert-deftest test-duet-classify-path-malformed-is-local-not-error ()
+ "A TRAMP-looking string TRAMP does not accept as remote is treated as local.
+Validation of raw TRAMP entry belongs to the connection reader, not the
+classifier; classification stays total and never throws."
+ (dolist (bad '("/ssh:" "/ssh:host"))
+ (let ((p (duet--classify-path bad)))
+ (should (eq 'local (plist-get p :locality)))
+ (should (null (plist-get p :method))))))
+
+(provide 'test-duet-classify-path)
+;;; test-duet-classify-path.el ends here