diff options
Diffstat (limited to 'test/lisp/auth-source-pass-tests.el')
-rw-r--r-- | test/lisp/auth-source-pass-tests.el | 532 |
1 files changed, 399 insertions, 133 deletions
diff --git a/test/lisp/auth-source-pass-tests.el b/test/lisp/auth-source-pass-tests.el index 9b6b5687cab..f5147a7ce07 100644 --- a/test/lisp/auth-source-pass-tests.el +++ b/test/lisp/auth-source-pass-tests.el @@ -1,6 +1,6 @@ ;;; auth-source-pass-tests.el --- Tests for auth-source-pass.el -*- lexical-binding: t; -*- -;; Copyright (C) 2013, 2017 Free Software Foundation, Inc. +;; Copyright (C) 2013, 2017-2022 Free Software Foundation, Inc. ;; Author: Damien Cassou <damien.cassou@gmail.com> @@ -49,126 +49,375 @@ '(("key1" . "val1") ("key2" . "val2")))))) +(ert-deftest auth-source-pass-parse-with-colons-in-data () + (let ((content "pass\n--\nkey1 :val1\nkey2: please: keep my space after colon\n\n")) + (should (equal (auth-source-pass--parse-data content) + '(("key1" . "val1") + ("key2" . "please: keep my space after colon")))))) + (defvar auth-source-pass--debug-log nil - "Contains a list of all messages passed to `auth-source-do-debug`.") + "Contains a list of all messages passed to `auth-source-do-debug'.") + +(defun auth-source-pass--have-message-matching (regexp) + "Return non-nil iff at least one `auth-source-do-debug' match REGEXP." + (seq-find (lambda (message) + (string-match regexp message)) + auth-source-pass--debug-log)) + +(defun auth-source-pass--explain--have-message-matching (regexp) + "Explainer function for `auth-source-pass--have-message-matching'. +REGEXP is the same as in `auth-source-pass--have-message-matching'." + `(regexp + ,regexp + messages + ,(mapconcat #'identity auth-source-pass--debug-log "\n- "))) -(defun auth-source-pass--should-have-message-containing (regexp) - "Assert that at least one `auth-source-do-debug` matched REGEXP." - (should (seq-find (lambda (message) - (string-match regexp message)) - auth-source-pass--debug-log))) +(put #'auth-source-pass--have-message-matching 'ert-explainer #'auth-source-pass--explain--have-message-matching) (defun auth-source-pass--debug (&rest msg) - "Format MSG and add that to `auth-source-pass--debug-log`. -This function is intended to be set to `auth-source-debug`." + "Format MSG and add that to `auth-source-pass--debug-log'. +This function is intended to be set to `auth-source-debug'." (add-to-list 'auth-source-pass--debug-log (apply #'format msg) t)) +(defvar auth-source-pass--parse-log nil) + (defmacro auth-source-pass--with-store (store &rest body) "Use STORE as password-store while executing BODY." (declare (indent 1)) - `(cl-letf (((symbol-function 'auth-source-pass-parse-entry) (lambda (entry) (cdr (cl-find entry ,store :key #'car :test #'string=))) ) - ((symbol-function 'auth-source-pass-entries) (lambda () (mapcar #'car ,store))) - ((symbol-function 'auth-source-pass--entry-valid-p) (lambda (_entry) t))) + `(cl-letf (((symbol-function 'auth-source-pass-parse-entry) + (lambda (entry) + (add-to-list 'auth-source-pass--parse-log entry) + (cdr (cl-find entry ,store :key #'car :test #'string=)))) + ((symbol-function 'auth-source-pass-entries) (lambda () (mapcar #'car ,store)))) (let ((auth-source-debug #'auth-source-pass--debug) - (auth-source-pass--debug-log nil)) + (auth-source-pass--debug-log nil) + (auth-source-pass--parse-log nil)) ,@body))) -(ert-deftest auth-source-pass-find-match-matching-at-entry-name () - (auth-source-pass--with-store '(("foo")) - (should (equal (auth-source-pass--find-match "foo" nil) - "foo")))) - -(ert-deftest auth-source-pass-find-match-matching-at-entry-name-part () - (auth-source-pass--with-store '(("foo")) - (should (equal (auth-source-pass--find-match "https://foo" nil) - "foo")))) - -(ert-deftest auth-source-pass-find-match-matching-at-entry-name-ignoring-user () - (auth-source-pass--with-store '(("foo")) - (should (equal (auth-source-pass--find-match "https://SomeUser@foo" nil) - "foo")))) - -(ert-deftest auth-source-pass-find-match-matching-at-entry-name-with-user () - (auth-source-pass--with-store '(("SomeUser@foo")) - (should (equal (auth-source-pass--find-match "https://SomeUser@foo" nil) - "SomeUser@foo")))) - -(ert-deftest auth-source-pass-find-match-matching-at-entry-name-prefer-full () - (auth-source-pass--with-store '(("SomeUser@foo") ("foo")) - (should (equal (auth-source-pass--find-match "https://SomeUser@foo" nil) - "SomeUser@foo")))) - -(ert-deftest auth-source-pass-find-match-matching-at-entry-name-prefer-full-reversed () - (auth-source-pass--with-store '(("foo") ("SomeUser@foo")) - (should (equal (auth-source-pass--find-match "https://SomeUser@foo" nil) - "SomeUser@foo")))) - -(ert-deftest auth-source-pass-find-match-matching-at-entry-name-without-subdomain () +(defun auth-source-pass--explain-match-entry-p (entry hostname &optional user port) + "Explainer function for `auth-source-pass-match-entry-p'. + +ENTRY, HOSTNAME, USER and PORT are the same as in +`auth-source-pass-match-entry-p'." + `(entry + ,entry + store + ,(auth-source-pass-entries) + matching-entries + ,(auth-source-pass--matching-entries hostname user port))) + +(put 'auth-source-pass-match-entry-p 'ert-explainer #'auth-source-pass--explain-match-entry-p) + +(defun auth-source-pass--includes-sorted-entries (entries hostname &optional user port) + "Return non-nil iff ENTRIES matching the parameters are found in store. +ENTRIES should be sorted from most specific to least specific. + +HOSTNAME, USER and PORT are passed unchanged to +`auth-source-pass--matching-entries'." + (if (seq-empty-p entries) + t + (and + (auth-source-pass-match-entry-p (car entries) hostname user port) + (auth-source-pass--includes-sorted-entries (cdr entries) hostname user port)))) + +(defun auth-source-pass--explain-includes-sorted-entries (entries hostname &optional user port) + "Explainer function for `auth-source-pass--includes-sorted-entries'. + +ENTRIES, HOSTNAME, USER and PORT are the same as in +`auth-source-pass--includes-sorted-entries'." + `(store + ,(auth-source-pass-entries) + matching-entries + ,(auth-source-pass--matching-entries hostname user port) + entries + ,entries)) + +(put 'auth-source-pass--includes-sorted-entries 'ert-explainer #'auth-source-pass--explain-includes-sorted-entries) + +(defun auth-source-pass--explain-match-any-entry-p (hostname &optional user port) + "Explainer function for `auth-source-pass-match-any-entry-p'. + +HOSTNAME, USER and PORT are the same as in `auth-source-pass-match-any-entry-p'." + `(store + ,(auth-source-pass-entries) + matching-entries + ,(auth-source-pass--matching-entries hostname user port))) + +(put 'auth-source-pass-match-any-entry-p 'ert-explainer #'auth-source-pass--explain-match-any-entry-p) + +(defun auth-source-pass--matching-entries (hostname &optional user port) + "Return password-store entries matching HOSTNAME, USER, PORT. + +The result is a list of lists of password-store entries. Each +sublist contains the password-store entries whose names match a +suffix in `auth-source-pass--generate-entry-suffixes'. The +result is ordered the same way as the suffixes." + (let ((entries (auth-source-pass-entries))) + (mapcar (lambda (suffix) (auth-source-pass--entries-matching-suffix suffix entries)) + (auth-source-pass--generate-entry-suffixes hostname user port)))) + +(defun auth-source-pass-match-entry-p (entry hostname &optional user port) + "Return non-nil iff an ENTRY matching the parameters is found in store. + +HOSTNAME, USER and PORT are passed unchanged to +`auth-source-pass--matching-entries'." + (cl-find-if + (lambda (entries) (cl-find entry entries :test #'string=)) + (auth-source-pass--matching-entries hostname user port))) + +(defun auth-source-pass-match-any-entry-p (hostname &optional user port) + "Return non-nil iff there is at least one entry matching the parameters. + +HOSTNAME, USER and PORT are passed unchanged to +`auth-source-pass--matching-entries'." + (cl-find-if #'identity (auth-source-pass--matching-entries hostname user port))) + +(ert-deftest auth-source-pass-any-host () + (auth-source-pass--with-store '(("foo" ("port" . "foo-port") ("host" . "foo-user")) + ("bar")) + (should-not (auth-source-pass-search :host t)))) + +(ert-deftest auth-source-pass-undefined-host () + (auth-source-pass--with-store '(("foo" ("port" . "foo-port") ("host" . "foo-user")) + ("bar")) + (should-not (auth-source-pass-search :host nil)))) + +(ert-deftest auth-source-pass-not-found () + (auth-source-pass--with-store '(("foo" ("port" . "foo-port") ("host" . "foo-user")) + ("bar")) + (should-not (auth-source-pass-search :host "baz")))) + +(ert-deftest auth-source-pass--disambiguate-extract-host-from-hostname () + ;; no user or port + (should (equal (cl-first (auth-source-pass--disambiguate "foo")) "foo")) + ;; only user + (should (equal (cl-first (auth-source-pass--disambiguate "user@foo")) "foo")) + ;; only port + (should (equal (cl-first (auth-source-pass--disambiguate "https://foo")) "foo")) + (should (equal (cl-first (auth-source-pass--disambiguate "foo:80")) "foo")) + ;; both user and port + (should (equal (cl-first (auth-source-pass--disambiguate "https://user@foo")) "foo")) + (should (equal (cl-first (auth-source-pass--disambiguate "user@foo:80")) "foo")) + ;; all of the above with a trailing path + (should (equal (cl-first (auth-source-pass--disambiguate "foo/path")) "foo")) + (should (equal (cl-first (auth-source-pass--disambiguate "user@foo/path")) "foo")) + (should (equal (cl-first (auth-source-pass--disambiguate "https://foo/path")) "foo")) + (should (equal (cl-first (auth-source-pass--disambiguate "foo:80/path")) "foo")) + (should (equal (cl-first (auth-source-pass--disambiguate "https://user@foo/path")) "foo")) + (should (equal (cl-first (auth-source-pass--disambiguate "user@foo:80/path")) "foo"))) + +(ert-deftest auth-source-pass--disambiguate-extract-user-from-hostname () + ;; no user or port + (should (equal (cl-second (auth-source-pass--disambiguate "foo")) nil)) + ;; only user + (should (equal (cl-second (auth-source-pass--disambiguate "user@foo")) "user")) + ;; only port + (should (equal (cl-second (auth-source-pass--disambiguate "https://foo")) nil)) + (should (equal (cl-second (auth-source-pass--disambiguate "foo:80")) nil)) + ;; both user and port + (should (equal (cl-second (auth-source-pass--disambiguate "https://user@foo")) "user")) + (should (equal (cl-second (auth-source-pass--disambiguate "user@foo:80")) "user")) + ;; all of the above with a trailing path + (should (equal (cl-second (auth-source-pass--disambiguate "foo/path")) nil)) + (should (equal (cl-second (auth-source-pass--disambiguate "user@foo/path")) "user")) + (should (equal (cl-second (auth-source-pass--disambiguate "https://foo/path")) nil)) + (should (equal (cl-second (auth-source-pass--disambiguate "foo:80/path")) nil)) + (should (equal (cl-second (auth-source-pass--disambiguate "https://user@foo/path")) "user")) + (should (equal (cl-second (auth-source-pass--disambiguate "user@foo:80/path")) "user"))) + +(ert-deftest auth-source-pass--disambiguate-prefer-user-parameter () + ;; no user or port + (should (equal (cl-second (auth-source-pass--disambiguate "foo" "user2")) "user2")) + ;; only user + (should (equal (cl-second (auth-source-pass--disambiguate "user@foo" "user2")) "user2")) + ;; only port + (should (equal (cl-second (auth-source-pass--disambiguate "https://foo" "user2")) "user2")) + (should (equal (cl-second (auth-source-pass--disambiguate "foo:80" "user2")) "user2")) + ;; both user and port + (should (equal (cl-second (auth-source-pass--disambiguate "https://user@foo" "user2")) "user2")) + (should (equal (cl-second (auth-source-pass--disambiguate "user@foo:80" "user2")) "user2")) + ;; all of the above with a trailing path + (should (equal (cl-second (auth-source-pass--disambiguate "foo/path" "user2")) "user2")) + (should (equal (cl-second (auth-source-pass--disambiguate "user@foo/path" "user2")) "user2")) + (should (equal (cl-second (auth-source-pass--disambiguate "https://foo/path" "user2")) "user2")) + (should (equal (cl-second (auth-source-pass--disambiguate "foo:80/path" "user2")) "user2")) + (should (equal (cl-second (auth-source-pass--disambiguate "https://user@foo/path" "user2")) "user2")) + (should (equal (cl-second (auth-source-pass--disambiguate "user@foo:80/path" "user2")) "user2"))) + +(ert-deftest auth-source-pass--disambiguate-extract-port-from-hostname () + ;; no user or port + (should (equal (cl-third (auth-source-pass--disambiguate "foo")) "443")) + ;; only user + (should (equal (cl-third (auth-source-pass--disambiguate "user@foo")) "443")) + ;; only port + (should (equal (cl-third (auth-source-pass--disambiguate "https://foo")) "443")) + (should (equal (cl-third (auth-source-pass--disambiguate "foo:80")) "80")) + ;; both user and port + (should (equal (cl-third (auth-source-pass--disambiguate "https://user@foo")) "443")) + (should (equal (cl-third (auth-source-pass--disambiguate "user@foo:80")) "80")) + ;; all of the above with a trailing path + (should (equal (cl-third (auth-source-pass--disambiguate "foo/path")) "443")) + (should (equal (cl-third (auth-source-pass--disambiguate "user@foo/path")) "443")) + (should (equal (cl-third (auth-source-pass--disambiguate "https://foo/path")) "443")) + (should (equal (cl-third (auth-source-pass--disambiguate "foo:80/path")) "80")) + (should (equal (cl-third (auth-source-pass--disambiguate "https://user@foo/path")) "443")) + (should (equal (cl-third (auth-source-pass--disambiguate "user@foo:80/path")) "80"))) + +(ert-deftest auth-source-pass--disambiguate-prefer-port-parameter () + ;; no user or port + (should (equal (cl-third (auth-source-pass--disambiguate "foo" "user2" "8080")) "8080")) + ;; only user + (should (equal (cl-third (auth-source-pass--disambiguate "user@foo" "user2" "8080")) "8080")) + ;; only port + (should (equal (cl-third (auth-source-pass--disambiguate "https://foo" "user2" "8080")) "8080")) + (should (equal (cl-third (auth-source-pass--disambiguate "foo:80" "user2" "8080")) "8080")) + ;; both user and port + (should (equal (cl-third (auth-source-pass--disambiguate "https://user@foo" "user2" "8080")) "8080")) + (should (equal (cl-third (auth-source-pass--disambiguate "user@foo:80" "user2" "8080")) "8080")) + ;; all of the above with a trailing path + (should (equal (cl-third (auth-source-pass--disambiguate "foo/path" "user2" "8080")) "8080")) + (should (equal (cl-third (auth-source-pass--disambiguate "user@foo/path" "user2" "8080")) "8080")) + (should (equal (cl-third (auth-source-pass--disambiguate "https://foo/path" "user2" "8080")) "8080")) + (should (equal (cl-third (auth-source-pass--disambiguate "foo:80/path" "user2" "8080")) "8080")) + (should (equal (cl-third (auth-source-pass--disambiguate "https://user@foo/path" "user2" "8080")) "8080")) + (should (equal (cl-third (auth-source-pass--disambiguate "user@foo:80/path" "user2" "8080")) "8080"))) + +(ert-deftest auth-source-pass-find-match-minimal-parsing () + (let ((store-contents + '(("baz" ("secret" . "baz password")) + ("baz:123" ("secret" . "baz:123 password")) + ("baz/foo" ("secret" . "baz/foo password")) + ("foo@baz" ("secret" . "foo@baz password")) + ("baz:123/foo" ("secret" . "baz:123/foo password")) + ("foo@baz:123" ("secret" . "foo@baz:123 password")) + ("bar.baz" ("secret" . "bar.baz password")) + ("bar.baz:123" ("secret" . "bar.baz:123 password")) + ("bar.baz/foo" ("secret" . "bar.baz/foo password")) + ("foo@bar.baz" ("secret" . "foo@bar.baz password")) + ("bar.baz:123/foo" ("secret" . "bar.baz:123/foo password")) + ("foo@bar.baz:123" ("secret" . "foo@bar.baz:123 password"))))) + (auth-source-pass--with-store store-contents + (auth-source-pass--find-match "bar.baz" "foo" "123") + (should (equal auth-source-pass--parse-log '("foo@bar.baz:123")))) + (auth-source-pass--with-store store-contents + (auth-source-pass--find-match "bar.baz" "foo" nil) + (should (equal auth-source-pass--parse-log '("foo@bar.baz")))) + (auth-source-pass--with-store store-contents + (auth-source-pass--find-match "bar.baz" nil "123") + (should (equal auth-source-pass--parse-log '("bar.baz:123")))) + (auth-source-pass--with-store store-contents + (auth-source-pass--find-match "bar.baz" nil nil) + (should (equal auth-source-pass--parse-log '("bar.baz")))) + (auth-source-pass--with-store store-contents + (auth-source-pass--find-match "baz" nil nil) + (should (equal auth-source-pass--parse-log '("baz")))) + (auth-source-pass--with-store + '(("dir1/bar.com" ("key" . "val")) + ("dir2/bar.com" ("key" . "val")) + ("dir3/bar.com" ("key" . "val"))) + (auth-source-pass--find-match "bar.com" nil nil) + (should (= (length auth-source-pass--parse-log) 1))))) + +(ert-deftest auth-source-pass--find-match-return-parsed-data () + (auth-source-pass--with-store '(("bar.com" ("key" . "val"))) + (should (consp (auth-source-pass--find-match "bar.com" nil nil)))) + (auth-source-pass--with-store '(("dir1/bar.com" ("key1" . "val1")) ("dir2/bar.com" ("key2" . "val2"))) + (should (consp (auth-source-pass--find-match "bar.com" nil nil))))) + +(ert-deftest auth-source-pass--matching-entries () (auth-source-pass--with-store '(("bar.com")) - (should (equal (auth-source-pass--find-match "foo.bar.com" nil) - "bar.com")))) - -(ert-deftest auth-source-pass-find-match-matching-at-entry-name-without-subdomain-with-user () - (auth-source-pass--with-store '(("someone@bar.com")) - (should (equal (auth-source-pass--find-match "foo.bar.com" "someone") - "someone@bar.com")))) - -(ert-deftest auth-source-pass-find-match-matching-at-entry-name-without-subdomain-with-bad-user () - (auth-source-pass--with-store '(("someoneelse@bar.com")) - (should (equal (auth-source-pass--find-match "foo.bar.com" "someone") - nil)))) - -(ert-deftest auth-source-pass-find-match-matching-at-entry-name-without-subdomain-prefer-full () - (auth-source-pass--with-store '(("bar.com") ("foo.bar.com")) - (should (equal (auth-source-pass--find-match "foo.bar.com" nil) - "foo.bar.com")))) - -(ert-deftest auth-source-pass-dont-match-at-folder-name () - (auth-source-pass--with-store '(("foo.bar.com/foo")) - (should (equal (auth-source-pass--find-match "foo.bar.com" nil) - nil)))) - -(ert-deftest auth-source-pass-search-with-user-first () + (should (auth-source-pass-match-entry-p "bar.com" "bar.com")) + ;; match even if sub-domain is asked for + (should (auth-source-pass-match-entry-p "bar.com" "foo.bar.com")) + ;; match even if a user is asked for + (should (auth-source-pass-match-entry-p "bar.com" "bar.com" "user")) + ;; match even if user as an @ sign + (should (auth-source-pass-match-entry-p "bar.com" "bar.com" "user@someplace")) + ;; match even if a port is asked for + (should (auth-source-pass-match-entry-p "bar.com" "bar.com" nil "8080")) + ;; match even if a user and a port are asked for + (should (auth-source-pass-match-entry-p "bar.com" "bar.com" "user" "8080")) + ;; don't match if a '.' is replaced with another character + (auth-source-pass--with-store '(("barXcom")) + (should-not (auth-source-pass-match-any-entry-p "bar.com" nil nil))))) + +(ert-deftest auth-source-pass--matching-entries-find-entries-with-a-username () + (auth-source-pass--with-store '(("user@foo")) + (should (auth-source-pass-match-entry-p "user@foo" "foo" "user"))) + ;; match even if sub-domain is asked for + (auth-source-pass--with-store '(("user@bar.com")) + (should (auth-source-pass-match-entry-p "user@bar.com" "foo.bar.com" "user"))) + ;; don't match if no user is asked for + (auth-source-pass--with-store '(("user@foo")) + (should-not (auth-source-pass-match-any-entry-p "foo"))) + ;; don't match if user is different + (auth-source-pass--with-store '(("user1@foo")) + (should-not (auth-source-pass-match-any-entry-p "foo" "user2"))) + ;; don't match if sub-domain is asked for but user is different + (auth-source-pass--with-store '(("user1@bar.com")) + (should-not (auth-source-pass-match-any-entry-p "foo.bar.com" "user2")))) + +(ert-deftest auth-source-pass--matching-entries-find-entries-with-a-port () + (auth-source-pass--with-store '(("bar.com:8080")) + (should (auth-source-pass-match-entry-p "bar.com:8080" "bar.com" nil "8080")))) + +(ert-deftest auth-source-pass--matching-entries-find-entries-with-a-port-when-passed-multiple-ports () + (auth-source-pass--with-store '(("bar.com:8080")) + (should (auth-source-pass-match-entry-p "bar.com:8080" "bar.com" nil '("http" "https" "80" "8080"))))) + +(ert-deftest auth-source-pass--matching-entries-find-entries-with-slash () + ;; match if entry filename matches user + (auth-source-pass--with-store '(("foo.com/user")) + (should (auth-source-pass-match-entry-p "foo.com/user" "foo.com" "user"))) + ;; match with port if entry filename matches user + (auth-source-pass--with-store '(("foo.com:8080/user")) + (should (auth-source-pass-match-entry-p "foo.com:8080/user" "foo.com" "user" "8080"))) + ;; don't match if entry filename doesn't match user + (auth-source-pass--with-store '(("foo.com/baz")) + (should-not (auth-source-pass-match-any-entry-p "foo.com" "user")))) + +(ert-deftest auth-source-pass-matching-entries-with-custom-separator () + (let ((auth-source-pass-port-separator "#")) + (auth-source-pass--with-store '(("bar.com#443/someone")) + (should (auth-source-pass-match-entry-p "bar.com#443/someone" "bar.com" "someone" "443"))))) + +(ert-deftest auth-source-pass--matching-entries-sort-results () + (auth-source-pass--with-store '(("user@foo") ("foo")) + (should (auth-source-pass--includes-sorted-entries '("user@foo" "foo") "foo" "user"))) + ;; same, but store is reversed (auth-source-pass--with-store '(("foo") ("user@foo")) - (should (equal (auth-source-pass--find-match "foo" "user") - "user@foo")) - (auth-source-pass--should-have-message-containing "Found 1 match"))) - -(ert-deftest auth-source-pass-give-priority-to-desired-user () - (auth-source-pass--with-store '(("foo") ("subdir/foo" ("user" . "someone"))) - (should (equal (auth-source-pass--find-match "foo" "someone") - "subdir/foo")) - (auth-source-pass--should-have-message-containing "Found 2 matches") - (auth-source-pass--should-have-message-containing "matching user field"))) - -(ert-deftest auth-source-pass-give-priority-to-desired-user-reversed () - (auth-source-pass--with-store '(("foo" ("user" . "someone")) ("subdir/foo")) - (should (equal (auth-source-pass--find-match "foo" "someone") - "foo")) - (auth-source-pass--should-have-message-containing "Found 2 matches") - (auth-source-pass--should-have-message-containing "matching user field"))) - -(ert-deftest auth-source-pass-return-first-when-several-matches () - (auth-source-pass--with-store '(("foo") ("subdir/foo")) - (should (equal (auth-source-pass--find-match "foo" nil) - "foo")) - (auth-source-pass--should-have-message-containing "Found 2 matches") - (auth-source-pass--should-have-message-containing "the first one"))) - -(ert-deftest auth-source-pass-make-divansantana-happy () - (auth-source-pass--with-store '(("host.com")) - (should (equal (auth-source-pass--find-match "smtp.host.com" "myusername@host.co.za") - "host.com")))) - -(ert-deftest auth-source-pass-hostname () - (should (equal (auth-source-pass--hostname "https://foo.bar") "foo.bar")) - (should (equal (auth-source-pass--hostname "http://foo.bar") "foo.bar")) - (should (equal (auth-source-pass--hostname "https://SomeUser@foo.bar") "foo.bar"))) - -(ert-deftest auth-source-pass-hostname-with-user () - (should (equal (auth-source-pass--hostname-with-user "https://foo.bar") "foo.bar")) - (should (equal (auth-source-pass--hostname-with-user "http://foo.bar") "foo.bar")) - (should (equal (auth-source-pass--hostname-with-user "https://SomeUser@foo.bar") "SomeUser@foo.bar"))) + (should (auth-source-pass--includes-sorted-entries '("user@foo" "foo") "foo" "user"))) + ;; with sub-domain + (auth-source-pass--with-store '(("bar.com") ("foo.bar.com")) + (should (auth-source-pass--includes-sorted-entries '("foo.bar.com" "bar.com") "foo.bar.com"))) + ;; matching user in the entry data takes priority + (auth-source-pass--with-store '(("dir1/bar.com") ("dir2/bar.com" ("user" . "user"))) + (should (auth-source-pass--includes-sorted-entries + '("dir2/bar.com" "dir1/bar.com") + "bar.com" "user"))) + ;; same, but store is reversed + (auth-source-pass--with-store '(("dir2/bar.com" ("user" . "user")) ("dir1/bar.com")) + (should (auth-source-pass--includes-sorted-entries + '("dir2/bar.com" "dir1/bar.com") + "bar.com" "user")))) + +(ert-deftest auth-source-pass-all-supported-organizations () + ;; test every possible entry to store this data: user=rms host=gnu.org port=22 + (dolist (entry '(;; only host name + "gnu.org" + ;; hostname + user + "gnu.org/rms" "rms@gnu.org" + ;; hostname + port + "gnu.org:22" + ;; hostname + user + port + "gnu.org:22/rms" "rms@gnu.org:22" + ;; all of the above in a random folder + "a/b/gnu.org" + "a/b/gnu.org/rms" "a/b/rms@gnu.org" + "a/b/gnu.org:22" + "a/b/gnu.org:22/rms" "a/b/rms@gnu.org:22")) + (auth-source-pass--with-store `((,entry)) + (should (auth-source-pass-match-entry-p entry "gnu.org" "rms" "22"))))) (defmacro auth-source-pass--with-store-find-foo (store &rest body) "Use STORE while executing BODY. \"foo\" is the matched entry." @@ -180,47 +429,64 @@ This function is intended to be set to `auth-source-debug`." ,@body))) (ert-deftest auth-source-pass-build-result-return-parameters () - (auth-source-pass--with-store-find-foo '(("foo")) + (auth-source-pass--with-store-find-foo + '(("foo" ("secret" . "foo password"))) (let ((result (auth-source-pass--build-result "foo" 512 "user"))) + (should (equal (plist-get result :host) "foo")) (should (equal (plist-get result :port) 512)) (should (equal (plist-get result :user) "user"))))) (ert-deftest auth-source-pass-build-result-return-entry-values () (auth-source-pass--with-store-find-foo '(("foo" ("port" . 512) ("user" . "anuser"))) (let ((result (auth-source-pass--build-result "foo" nil nil))) + (should (equal (plist-get result :host) "foo")) (should (equal (plist-get result :port) 512)) (should (equal (plist-get result :user) "anuser"))))) (ert-deftest auth-source-pass-build-result-entry-takes-precedence () - (auth-source-pass--with-store-find-foo '(("foo" ("port" . 512) ("user" . "anuser"))) + (auth-source-pass--with-store-find-foo '(("foo" ("host" . "bar") ("port" . 512) ("user" . "anuser"))) (let ((result (auth-source-pass--build-result "foo" 1024 "anotheruser"))) + (should (equal (plist-get result :host) "bar")) (should (equal (plist-get result :port) 512)) (should (equal (plist-get result :user) "anuser"))))) -(ert-deftest auth-source-pass-only-return-entries-that-can-be-open () - (cl-letf (((symbol-function 'auth-source-pass-entries) - (lambda () '("foo.site.com" "bar.site.com" - "mail/baz.site.com/scott"))) - ((symbol-function 'auth-source-pass--entry-valid-p) - ;; only foo.site.com and "mail/baz.site.com/scott" are valid - (lambda (entry) (member entry '("foo.site.com" - "mail/baz.site.com/scott"))))) - (should (equal (auth-source-pass--find-all-by-entry-name "foo.site.com" "someuser") - '("foo.site.com"))) - (should (equal (auth-source-pass--find-all-by-entry-name "bar.site.com" "someuser") - '())) - (should (equal (auth-source-pass--find-all-by-entry-name "baz.site.com" "scott") - '("mail/baz.site.com/scott"))))) - -(ert-deftest auth-source-pass-entry-is-not-valid-when-unreadable () - (cl-letf (((symbol-function 'auth-source-pass--read-entry) - (lambda (entry) - ;; only foo is a valid entry - (if (string-equal entry "foo") - "password" - nil)))) - (should (auth-source-pass--entry-valid-p "foo")) - (should-not (auth-source-pass--entry-valid-p "bar")))) +(ert-deftest auth-source-pass-build-result-with-multiple-hosts () + (auth-source-pass--with-store-find-foo + '(("foo" ("secret" . "foo password"))) + (let ((result (auth-source-pass--build-result '("bar" "foo") 512 "user"))) + (should (equal (plist-get result :host) "foo")) + (should (equal (plist-get result :port) 512)) + (should (equal (plist-get result :user) "user"))))) + +(ert-deftest auth-source-pass-build-result-with-multiple-hosts-no-match () + (auth-source-pass--with-store-find-foo + '(("foo" ("secret" . "foo password"))) + (should-not (auth-source-pass--build-result '("bar" "baz") 512 "user")))) + +(ert-deftest auth-source-pass-can-start-from-auth-source-search () + (auth-source-pass--with-store '(("gitlab.com" ("user" . "someone"))) + (auth-source-pass-enable) + (let ((result (car (auth-source-search :host "gitlab.com")))) + (should (equal (plist-get result :user) "someone")) + (should (equal (plist-get result :host) "gitlab.com"))))) + +(ert-deftest auth-source-pass-prints-meaningful-debug-log () + (auth-source-pass--with-store '() + (auth-source-pass--find-match "gitlab.com" nil nil) + (should (auth-source-pass--have-message-matching + "entries matching hostname=\"gitlab.com\"")) + (should (auth-source-pass--have-message-matching + "corresponding suffixes to search for: .*\"gitlab.com\"")) + (should (auth-source-pass--have-message-matching + "found no entries matching \"gitlab.com\""))) + (auth-source-pass--with-store '(("gitlab.com")) + (auth-source-pass--find-match "gitlab.com" nil nil) + (should (auth-source-pass--have-message-matching + "found 1 entry matching \"gitlab.com\": \"gitlab.com\""))) + (auth-source-pass--with-store '(("a/gitlab.com") ("b/gitlab.com")) + (auth-source-pass--find-match "gitlab.com" nil nil) + (should (auth-source-pass--have-message-matching + "found 2 entries matching \"gitlab.com\": (\"a/gitlab.com\" \"b/gitlab.com\")")))) (provide 'auth-source-pass-tests) |