;;; test-duet-classify-path.el --- Tests for duet--classify-path -*- lexical-binding: t; -*- ;; Copyright (C) 2026 Craig Jennings ;; Author: Craig Jennings ;; 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 . ;;; 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