aboutsummaryrefslogtreecommitdiff
path: root/tests/test-duet-classify-path.el
blob: b9e826411cf10c070bb8f423cdc66462e9d5ebbb (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
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