summaryrefslogtreecommitdiff
path: root/test/lisp/url
diff options
context:
space:
mode:
Diffstat (limited to 'test/lisp/url')
-rw-r--r--test/lisp/url/url-auth-tests.el255
-rw-r--r--test/lisp/url/url-expand-tests.el105
-rw-r--r--test/lisp/url/url-future-tests.el57
-rw-r--r--test/lisp/url/url-parse-tests.el167
-rw-r--r--test/lisp/url/url-util-tests.el51
5 files changed, 635 insertions, 0 deletions
diff --git a/test/lisp/url/url-auth-tests.el b/test/lisp/url/url-auth-tests.el
new file mode 100644
index 00000000000..bc30f3518e4
--- /dev/null
+++ b/test/lisp/url/url-auth-tests.el
@@ -0,0 +1,255 @@
+;;; url-auth-tests.el --- Test suite for url-auth.
+
+;; Copyright (C) 2015-2016 Free Software Foundation, Inc.
+
+;; Author: Jarno Malmari <jarno@malmari.fi>
+
+;; This file is part of GNU Emacs.
+
+;; GNU Emacs 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.
+
+;; GNU Emacs 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 GNU Emacs. If not, see <http://www.gnu.org/licenses/>.
+
+;;; Commentary:
+
+;; Test HTTP authentication methods.
+
+;;; Code:
+
+(require 'ert)
+(require 'url-auth)
+
+(defvar url-auth-test-challenges nil
+ "List of challenges for testing.
+Each challenge is a plist. Values are as presented by the
+server's WWW-Authenticate header field.")
+
+;; Set explicitly for easier modification for re-runs.
+(setq url-auth-test-challenges
+ (list
+ (list :qop "auth"
+ :nonce "uBr3+qkQBybTr/dKWkmpUqVO7SaEwWYzyTKO7g==$"
+ :uri "/random/path"
+ :method "GET"
+ :realm "Some test realm"
+ :cnonce "YWU4NDcxYWMxMDAxMjlkMjAwMDE4MjI5MDAwMGY4NGQ="
+ :nc "00000001"
+ :username "jytky"
+ :password "xi5Ac2HEfKt1lKKO05DCSqsK0u7hqqtsT"
+ :expected-ha1 "af521db3a83abd91262fead04fa31892"
+ :expected-ha2 "e490a6a147c79404b365d1f6059ddda5"
+ :expected-response "ecb6396e93b9e09e31f19264cfd8f854")
+ (list :nonce "a1be8a3065e00c5bf190ad499299aea5"
+ :opaque "d7c2a27230fc8c74bb6e06be8c9cd189"
+ :realm "The Test Realm"
+ :username "user"
+ :password "passwd"
+ :uri "/digest-auth/auth/user/passwd"
+ :method "GET"
+ :expected-ha1 "19c41161a8720edaeb7922ef8531137d"
+ :expected-ha2 "b44272ea65ee4af7fb26c5dba58f6863"
+ :expected-response "46c47a6d8e1fa95a3efcf49724af3fe7")
+ (list :nonce "servernonce"
+ :username "user"
+ :password "passwd"
+ :realm "The Test Realm 1"
+ :uri "/digest-auth/auth/user/passwd"
+ :method "GET"
+ :expected-ha1 "00f848f943c9a05dd06c932a7334f120"
+ :expected-ha2 "b44272ea65ee4af7fb26c5dba58f6863"
+ :expected-response "b8a48cdc9aa9e514509a5a5c53d4e8cf")
+ (list :nonce "servernonce"
+ :username "user"
+ :password "passwd"
+ :realm "The Test Realm 2"
+ :uri "/digest-auth/auth/user/passwd"
+ :method "GET"
+ :expected-ha1 "74d6abd3651d6b8260733d8a4c37ec1a"
+ :expected-ha2 "b44272ea65ee4af7fb26c5dba58f6863"
+ :expected-response "0d84884d967e04440efc77e9e2b5b561")))
+
+(ert-deftest url-auth-test-digest-create-key ()
+ "Check user credentials in their hashed form."
+ (dolist (challenge url-auth-test-challenges)
+ (let ((key (url-digest-auth-create-key (plist-get challenge :username)
+ (plist-get challenge :password)
+ (plist-get challenge :realm)
+ (plist-get challenge :method)
+ (plist-get challenge :uri))))
+ (should (= (length key) 2))
+ (should (string= (nth 0 key) (plist-get challenge :expected-ha1)))
+ (should (string= (nth 1 key) (plist-get challenge :expected-ha2)))
+ )))
+
+(ert-deftest url-auth-test-digest-auth-retrieve-cache ()
+ "Check how the entry point retrieves cached authentication.
+Essential is how realms and paths are matched."
+
+ (let* ((url-digest-auth-storage
+ '(("example.org:80"
+ ("/path/auth1" "auth1user" "key")
+ ("/path" "pathuser" "key")
+ ("/" "rootuser" "key")
+ ("realm1" "realm1user" "key")
+ ("realm2" "realm2user" "key")
+ ("/path/auth2" "auth2user" "key"))
+ ("example.org:443"
+ ("realm" "secure_user" "key"))
+ ("rootless.org:80" ; no "/" entry for this on purpose
+ ("/path" "pathuser" "key")
+ ("realm" "realmuser" "key"))))
+ (attrs (list (cons "nonce" "servernonce")))
+ auth)
+
+ (dolist (row (list
+ ;; If :expected-user is `nil' it indicates
+ ;; authentication information shouldn't be found.
+
+ ;; non-existent server
+ (list :url "http://other.com/path"
+ :realm nil :expected-user nil)
+
+ ;; unmatched port
+ (list :url "http://example.org:444/path"
+ :realm nil :expected-user nil)
+
+ ;; root, no realm
+ (list :url "http://example.org/"
+ :realm nil :expected-user "rootuser")
+
+ ;; root, no realm, explicit port
+ (list :url "http://example.org:80/"
+ :realm nil :expected-user "rootuser")
+
+ (list :url "http://example.org/unknown"
+ :realm nil :expected-user "rootuser")
+
+ ;; realm specified, overrides any path
+ (list :url "http://example.org/"
+ :realm "realm1" :expected-user "realm1user")
+
+ ;; realm specified, overrides any path
+ (list :url "http://example.org/"
+ :realm "realm2" :expected-user "realm2user")
+
+ ;; authentication determined by path
+ (list :url "http://example.org/path/auth1/query"
+ :realm nil :expected-user "auth1user")
+
+ ;; /path shadows /path/auth2, hence pathuser is expected
+ (list :url "http://example.org/path/auth2/query"
+ :realm nil :expected-user "pathuser")
+
+ (list :url "https://example.org/path"
+ :realm nil :expected-user "secure_user")
+
+ ;; not really secure user but using the same port
+ (list :url "http://example.org:443/path"
+ :realm nil :expected-user "secure_user")
+
+ ;; preferring realm user over path, even though no
+ ;; realm specified (not sure why)
+ (list :url "http://rootless.org/"
+ :realm nil :expected-user "realmuser")
+ ;; second variant for the same case
+ (list :url "http://rootless.org/unknown/path"
+ :realm nil :expected-user "realmuser")
+
+ ;; path match
+ (list :url "http://rootless.org/path/query?q=a"
+ :realm nil :expected-user "pathuser")
+
+ ;; path match, realm match, prefer realm
+ (list :url "http://rootless.org/path/query?q=a"
+ :realm "realm" :expected-user "realmuser")
+ ))
+ (setq auth (url-digest-auth (plist-get row :url)
+ nil nil
+ (plist-get row :realm) attrs))
+ (if (plist-get row :expected-user)
+ (progn (should auth)
+ (should (string-match ".*username=\"\\(.*?\\)\".*" auth))
+ (should (string= (match-string 1 auth)
+ (plist-get row :expected-user))))
+ (should-not auth)))))
+
+(ert-deftest url-auth-test-digest-auth ()
+ "Check common authorization string contents.
+Challenges with qop are not checked for response since a unique
+cnonce is used for generating them which is not mocked by the
+test and cannot be passed by arguments to `url-digest-auth'."
+ (dolist (challenge url-auth-test-challenges)
+ (let* ((attrs (append
+ (list (cons "nonce" (plist-get challenge :nonce)))
+ (if (plist-get challenge :qop)
+ (list (cons "qop" (plist-get challenge :qop))))))
+ (url (concat "http://example.org" (plist-get challenge :uri)))
+ url-digest-auth-storage
+ auth)
+ ;; Add authentication info to cache so `url-digest-auth' can
+ ;; complete without prompting minibuffer input.
+ (setq url-digest-auth-storage
+ (list
+ (list "example.org:80"
+ (cons (or (plist-get challenge :realm) "/")
+ (cons (plist-get challenge :username)
+ (url-digest-auth-create-key
+ (plist-get challenge :username)
+ (plist-get challenge :password)
+ (plist-get challenge :realm)
+ (plist-get challenge :method)
+ (plist-get challenge :uri)))))))
+ (setq auth (url-digest-auth (url-generic-parse-url url) nil nil
+ (plist-get challenge :realm) attrs))
+ (should auth)
+ (should (string-prefix-p "Digest " auth))
+ (should (string-match ".*username=\"\\(.*?\\)\".*" auth))
+ (should (string= (match-string 1 auth)
+ (plist-get challenge :username)))
+ (should (string-match ".*realm=\"\\(.*?\\)\".*" auth))
+ (should (string= (match-string 1 auth)
+ (plist-get challenge :realm)))
+
+ (if (plist-member challenge :qop)
+ (progn
+ ;; We don't know these, just check that they exists.
+ (should (string-match-p ".*response=\".*?\".*" auth))
+ ;; url-digest-auth doesn't return these AFAICS.
+;;; (should (string-match-p ".*nc=\".*?\".*" auth))
+;;; (should (string-match-p ".*cnonce=\".*?\".*" auth))
+ )
+ (should (string-match ".*response=\"\\(.*?\\)\".*" auth))
+ (should (string= (match-string 1 auth)
+ (plist-get challenge :expected-response))))
+ )))
+
+(ert-deftest url-auth-test-digest-auth-opaque ()
+ "Check that `opaque' value is added to result when presented by
+the server."
+ (let* ((url-digest-auth-storage
+ '(("example.org:80" ("/" "user" "key"))))
+ (attrs (list (cons "nonce" "anynonce")))
+ auth)
+ ;; Get authentication info from cache without `opaque'.
+ (setq auth (url-digest-auth "http://example.org/path" nil nil nil attrs))
+ (should auth)
+ (should-not (string-match-p "opaque=" auth))
+
+ ;; Add `opaque' to attributes.
+ (push (cons "opaque" "opaque-value") attrs)
+ (setq auth (url-digest-auth "http://example.org/path" nil nil nil attrs))
+ (should auth)
+ (should (string-match ".*opaque=\"\\(.*?\\)\".*" auth))
+ (should (string= (match-string 1 auth) "opaque-value"))))
+
+(provide 'url-auth-tests)
+;;; url-auth-tests.el ends here
diff --git a/test/lisp/url/url-expand-tests.el b/test/lisp/url/url-expand-tests.el
new file mode 100644
index 00000000000..6d1d54d4ffc
--- /dev/null
+++ b/test/lisp/url/url-expand-tests.el
@@ -0,0 +1,105 @@
+;;; url-expand-tests.el --- Test suite for relative URI/URL resolution.
+
+;; Copyright (C) 2012-2016 Free Software Foundation, Inc.
+
+;; Author: Alain Schneble <a.s@realize.ch>
+;; Version: 1.0
+
+;; This file is part of GNU Emacs.
+
+;; GNU Emacs 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.
+
+;; GNU Emacs 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 GNU Emacs. If not, see <http://www.gnu.org/licenses/>.
+
+;;; Commentary:
+
+;; Test cases covering URI reference resolution as described in RFC3986,
+;; section 5. Reference Resolution and especially the relative resolution
+;; rules specified in section 5.2. Relative Resolution.
+
+;; Each test calls `url-expand-file-name', typically with a relative
+;; reference URI and a base URI as string and compares the result (Actual)
+;; against a manually specified URI (Expected)
+
+;;; Code:
+
+(require 'url-expand)
+(require 'ert)
+
+(ert-deftest url-expand-file-name/relative-resolution-normal-examples ()
+ "RFC 3986, Section 5.4 Reference Resolution Examples / Section 5.4.1. Normal Examples"
+ (should (equal (url-expand-file-name "g:h" "http://a/b/c/d;p?q") "g:h"))
+ (should (equal (url-expand-file-name "g" "http://a/b/c/d;p?q") "http://a/b/c/g"))
+ (should (equal (url-expand-file-name "./g" "http://a/b/c/d;p?q") "http://a/b/c/g"))
+ (should (equal (url-expand-file-name "g/" "http://a/b/c/d;p?q") "http://a/b/c/g/"))
+ (should (equal (url-expand-file-name "/g" "http://a/b/c/d;p?q") "http://a/g"))
+ (should (equal (url-expand-file-name "//g" "http://a/b/c/d;p?q") "http://g"))
+ (should (equal (url-expand-file-name "?y" "http://a/b/c/d;p?q") "http://a/b/c/d;p?y"))
+ (should (equal (url-expand-file-name "g?y" "http://a/b/c/d;p?q") "http://a/b/c/g?y"))
+ (should (equal (url-expand-file-name "#s" "http://a/b/c/d;p?q") "http://a/b/c/d;p?q#s"))
+ (should (equal (url-expand-file-name "g#s" "http://a/b/c/d;p?q") "http://a/b/c/g#s"))
+ (should (equal (url-expand-file-name "g?y#s" "http://a/b/c/d;p?q") "http://a/b/c/g?y#s"))
+ (should (equal (url-expand-file-name ";x" "http://a/b/c/d;p?q") "http://a/b/c/;x"))
+ (should (equal (url-expand-file-name "g;x" "http://a/b/c/d;p?q") "http://a/b/c/g;x"))
+ (should (equal (url-expand-file-name "g;x?y#s" "http://a/b/c/d;p?q") "http://a/b/c/g;x?y#s"))
+ (should (equal (url-expand-file-name "" "http://a/b/c/d;p?q") "http://a/b/c/d;p?q"))
+ (should (equal (url-expand-file-name "." "http://a/b/c/d;p?q") "http://a/b/c/"))
+ (should (equal (url-expand-file-name "./" "http://a/b/c/d;p?q") "http://a/b/c/"))
+ (should (equal (url-expand-file-name ".." "http://a/b/c/d;p?q") "http://a/b/"))
+ (should (equal (url-expand-file-name "../" "http://a/b/c/d;p?q") "http://a/b/"))
+ (should (equal (url-expand-file-name "../g" "http://a/b/c/d;p?q") "http://a/b/g"))
+ (should (equal (url-expand-file-name "../.." "http://a/b/c/d;p?q") "http://a/"))
+ (should (equal (url-expand-file-name "../../" "http://a/b/c/d;p?q") "http://a/"))
+ (should (equal (url-expand-file-name "../../g" "http://a/b/c/d;p?q") "http://a/g")))
+
+(ert-deftest url-expand-file-name/relative-resolution-absolute-examples ()
+ "RFC 3986, Section 5.4 Reference Resolution Examples / Section 5.4.2. Abnormal Examples"
+ (should (equal (url-expand-file-name "../../../g" "http://a/b/c/d;p?q") "http://a/g"))
+ (should (equal (url-expand-file-name "../../../../g" "http://a/b/c/d;p?q") "http://a/g"))
+
+ (should (equal (url-expand-file-name "/./g" "http://a/b/c/d;p?q") "http://a/g"))
+ (should (equal (url-expand-file-name "/../g" "http://a/b/c/d;p?q") "http://a/g"))
+ (should (equal (url-expand-file-name "g." "http://a/b/c/d;p?q") "http://a/b/c/g."))
+ (should (equal (url-expand-file-name ".g" "http://a/b/c/d;p?q") "http://a/b/c/.g"))
+ (should (equal (url-expand-file-name "g.." "http://a/b/c/d;p?q") "http://a/b/c/g.."))
+ (should (equal (url-expand-file-name "..g" "http://a/b/c/d;p?q") "http://a/b/c/..g"))
+
+ (should (equal (url-expand-file-name "./../g" "http://a/b/c/d;p?q") "http://a/b/g"))
+ (should (equal (url-expand-file-name "./g/." "http://a/b/c/d;p?q") "http://a/b/c/g/"))
+ (should (equal (url-expand-file-name "g/./h" "http://a/b/c/d;p?q") "http://a/b/c/g/h"))
+ (should (equal (url-expand-file-name "g/../h" "http://a/b/c/d;p?q") "http://a/b/c/h"))
+ (should (equal (url-expand-file-name "g;x=1/./y" "http://a/b/c/d;p?q") "http://a/b/c/g;x=1/y"))
+ (should (equal (url-expand-file-name "g;x=1/../y" "http://a/b/c/d;p?q") "http://a/b/c/y"))
+
+ (should (equal (url-expand-file-name "g?y/./x" "http://a/b/c/d;p?q") "http://a/b/c/g?y/./x"))
+ (should (equal (url-expand-file-name "g?y/../x" "http://a/b/c/d;p?q") "http://a/b/c/g?y/../x"))
+ (should (equal (url-expand-file-name "g#s/./x" "http://a/b/c/d;p?q") "http://a/b/c/g#s/./x"))
+ (should (equal (url-expand-file-name "g#s/../x" "http://a/b/c/d;p?q") "http://a/b/c/g#s/../x"))
+
+ (should (equal (url-expand-file-name "http:g" "http://a/b/c/d;p?q") "http:g")) ; for strict parsers
+ )
+
+(ert-deftest url-expand-file-name/relative-resolution-additional-examples ()
+ "Reference Resolution Examples / Arbitrary Examples"
+ (should (equal (url-expand-file-name "" "http://host/foobar") "http://host/foobar"))
+ (should (equal (url-expand-file-name "?y" "http://a/b/c/d") "http://a/b/c/d?y"))
+ (should (equal (url-expand-file-name "?y" "http://a/b/c/d/") "http://a/b/c/d/?y"))
+ (should (equal (url-expand-file-name "?y#fragment" "http://a/b/c/d;p?q") "http://a/b/c/d;p?y#fragment"))
+ (should (equal (url-expand-file-name "#bar" "http://host") "http://host#bar"))
+ (should (equal (url-expand-file-name "#bar" "http://host/") "http://host/#bar"))
+ (should (equal (url-expand-file-name "#bar" "http://host/foo") "http://host/foo#bar"))
+ (should (equal (url-expand-file-name "foo#bar" "http://host/foobar") "http://host/foo#bar"))
+ (should (equal (url-expand-file-name "foo#bar" "http://host/foobar/") "http://host/foobar/foo#bar")))
+
+(provide 'url-expand-tests)
+
+;;; url-expand-tests.el ends here
diff --git a/test/lisp/url/url-future-tests.el b/test/lisp/url/url-future-tests.el
new file mode 100644
index 00000000000..87298cc1b96
--- /dev/null
+++ b/test/lisp/url/url-future-tests.el
@@ -0,0 +1,57 @@
+;;; url-future-tests.el --- Test suite for url-future.
+
+;; Copyright (C) 2011-2016 Free Software Foundation, Inc.
+
+;; Author: Teodor Zlatanov <tzz@lifelogs.com>
+;; Keywords: data
+
+;; This file is part of GNU Emacs.
+
+;; GNU Emacs 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.
+
+;; GNU Emacs 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 GNU Emacs. If not, see <http://www.gnu.org/licenses/>.
+
+;;; Code:
+
+(require 'ert)
+(require 'url-future)
+
+(ert-deftest url-future-tests ()
+ (let* (saver
+ (text "running future")
+ (good (make-url-future :value (lambda () (format text))
+ :callback (lambda (f) (set 'saver f))))
+ (bad (make-url-future :value (lambda () (/ 1 0))
+ :errorback (lambda (&rest d) (set 'saver d))))
+ (tocancel (make-url-future :value (lambda () (/ 1 0))
+ :callback (lambda (f) (set 'saver f))
+ :errorback (lambda (&rest d)
+ (set 'saver d)))))
+ (should (equal good (url-future-call good)))
+ (should (equal good saver))
+ (should (equal text (url-future-value good)))
+ (should (url-future-completed-p good))
+ (should-error (url-future-call good))
+ (setq saver nil)
+ (should (equal bad (url-future-call bad)))
+ (should-error (url-future-call bad))
+ (should (equal saver (list bad '(arith-error))))
+ (should (url-future-errored-p bad))
+ (setq saver nil)
+ (should (equal (url-future-cancel tocancel) tocancel))
+ (should-error (url-future-call tocancel))
+ (should (null saver))
+ (should (url-future-cancelled-p tocancel))))
+
+(provide 'url-future-tests)
+
+;;; url-future-tests.el ends here
diff --git a/test/lisp/url/url-parse-tests.el b/test/lisp/url/url-parse-tests.el
new file mode 100644
index 00000000000..77c5320e351
--- /dev/null
+++ b/test/lisp/url/url-parse-tests.el
@@ -0,0 +1,167 @@
+;;; url-parse-tests.el --- Test suite for URI/URL parsing.
+
+;; Copyright (C) 2012-2016 Free Software Foundation, Inc.
+
+;; Author: Alain Schneble <a.s@realize.ch>
+;; Version: 1.0
+
+;; This file is part of GNU Emacs.
+
+;; GNU Emacs 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.
+
+;; GNU Emacs 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 GNU Emacs. If not, see <http://www.gnu.org/licenses/>.
+
+;;; Commentary:
+
+;; Test cases covering generic URI syntax as described in RFC3986,
+;; section 3. Syntax Components and 4. Usage. See also appendix
+;; A. Collected ABNF for URI, as the example given here are all
+;; productions of this grammar.
+
+;; Each tests parses a given URI string - whether relative or absolute -
+;; using `url-generic-parse-url' and compares the constructed
+;; URL-struct (Actual) against a manually `url-parse-make-urlobj'-
+;; constructed URL-struct (Expected).
+
+;;; Code:
+
+(require 'url-parse)
+(require 'ert)
+
+(ert-deftest url-generic-parse-url/generic-uri-examples ()
+ "RFC 3986, section 1.1.2. Examples / Example illustrating several URI schemes and variations in their common syntax components"
+ (should (equal (url-generic-parse-url "ftp://ftp.is.co.za/rfc/rfc1808.txt") (url-parse-make-urlobj "ftp" nil nil "ftp.is.co.za" nil "/rfc/rfc1808.txt" nil nil t)))
+ (should (equal (url-generic-parse-url "http://www.ietf.org/rfc/rfc2396.txt") (url-parse-make-urlobj "http" nil nil "www.ietf.org" nil "/rfc/rfc2396.txt" nil nil t)))
+ (should (equal (url-generic-parse-url "ldap://[2001:db8::7]/c=GB?objectClass?one") (url-parse-make-urlobj "ldap" nil nil "[2001:db8::7]" nil "/c=GB?objectClass?one" nil nil t)))
+ (should (equal (url-generic-parse-url "mailto:John.Doe@example.com") (url-parse-make-urlobj "mailto" nil nil nil nil "John.Doe@example.com" nil nil nil)))
+ (should (equal (url-generic-parse-url "news:comp.infosystems.www.servers.unix") (url-parse-make-urlobj "news" nil nil nil nil "comp.infosystems.www.servers.unix" nil nil nil)))
+ (should (equal (url-generic-parse-url "tel:+1-816-555-1212") (url-parse-make-urlobj "tel" nil nil nil nil "+1-816-555-1212" nil nil nil)))
+ (should (equal (url-generic-parse-url "telnet://192.0.2.16:80/") (url-parse-make-urlobj "telnet" nil nil "192.0.2.16" 80 "/" nil nil t)))
+ (should (equal (url-generic-parse-url "urn:oasis:names:specification:docbook:dtd:xml:4.1.2") (url-parse-make-urlobj "urn" nil nil nil nil "oasis:names:specification:docbook:dtd:xml:4.1.2" nil nil nil))))
+
+(ert-deftest url-generic-parse-url/generic-uri ()
+ "RFC 3986, section 3. Syntax Components / generic URI syntax"
+ ;; empty path
+ (should (equal (url-generic-parse-url "http://host#") (url-parse-make-urlobj "http" nil nil "host" nil "" "" nil t)))
+ (should (equal (url-generic-parse-url "http://host#fragment") (url-parse-make-urlobj "http" nil nil "host" nil "" "fragment" nil t)))
+ (should (equal (url-generic-parse-url "http://host?#") (url-parse-make-urlobj "http" nil nil "host" nil "?" "" nil t)))
+ (should (equal (url-generic-parse-url "http://host?query#") (url-parse-make-urlobj "http" nil nil "host" nil "?query" "" nil t)))
+ (should (equal (url-generic-parse-url "http://host?#fragment") (url-parse-make-urlobj "http" nil nil "host" nil "?" "fragment" nil t)))
+ (should (equal (url-generic-parse-url "http://host?query#fragment") (url-parse-make-urlobj "http" nil nil "host" nil "?query" "fragment" nil t)))
+ ;; absolute path /
+ (should (equal (url-generic-parse-url "http://host/#") (url-parse-make-urlobj "http" nil nil "host" nil "/" "" nil t)))
+ (should (equal (url-generic-parse-url "http://host/#fragment") (url-parse-make-urlobj "http" nil nil "host" nil "/" "fragment" nil t)))
+ (should (equal (url-generic-parse-url "http://host/?#") (url-parse-make-urlobj "http" nil nil "host" nil "/?" "" nil t)))
+ (should (equal (url-generic-parse-url "http://host/?query#") (url-parse-make-urlobj "http" nil nil "host" nil "/?query" "" nil t)))
+ (should (equal (url-generic-parse-url "http://host/?#fragment") (url-parse-make-urlobj "http" nil nil "host" nil "/?" "fragment" nil t)))
+ (should (equal (url-generic-parse-url "http://host/?query#fragment") (url-parse-make-urlobj "http" nil nil "host" nil "/?query" "fragment" nil t)))
+ ;; absolute path /foo
+ (should (equal (url-generic-parse-url "http://host/foo#") (url-parse-make-urlobj "http" nil nil "host" nil "/foo" "" nil t)))
+ (should (equal (url-generic-parse-url "http://host/foo#fragment") (url-parse-make-urlobj "http" nil nil "host" nil "/foo" "fragment" nil t)))
+ (should (equal (url-generic-parse-url "http://host/foo?#") (url-parse-make-urlobj "http" nil nil "host" nil "/foo?" "" nil t)))
+ (should (equal (url-generic-parse-url "http://host/foo?query#") (url-parse-make-urlobj "http" nil nil "host" nil "/foo?query" "" nil t)))
+ (should (equal (url-generic-parse-url "http://host/foo?#fragment") (url-parse-make-urlobj "http" nil nil "host" nil "/foo?" "fragment" nil t)))
+ (should (equal (url-generic-parse-url "http://host/foo?query#fragment") (url-parse-make-urlobj "http" nil nil "host" nil "/foo?query" "fragment" nil t)))
+ ;; absolute path /foo/
+ (should (equal (url-generic-parse-url "http://host/foo/#") (url-parse-make-urlobj "http" nil nil "host" nil "/foo/" "" nil t)))
+ (should (equal (url-generic-parse-url "http://host/foo/#fragment") (url-parse-make-urlobj "http" nil nil "host" nil "/foo/" "fragment" nil t)))
+ (should (equal (url-generic-parse-url "http://host/foo/?#") (url-parse-make-urlobj "http" nil nil "host" nil "/foo/?" "" nil t)))
+ (should (equal (url-generic-parse-url "http://host/foo/?query#") (url-parse-make-urlobj "http" nil nil "host" nil "/foo/?query" "" nil t)))
+ (should (equal (url-generic-parse-url "http://host/foo/?#fragment") (url-parse-make-urlobj "http" nil nil "host" nil "/foo/?" "fragment" nil t)))
+ (should (equal (url-generic-parse-url "http://host/foo/?query#fragment") (url-parse-make-urlobj "http" nil nil "host" nil "/foo/?query" "fragment" nil t)))
+ ;; absolute path /foo/bar
+ (should (equal (url-generic-parse-url "http://host/foo/bar#") (url-parse-make-urlobj "http" nil nil "host" nil "/foo/bar" "" nil t)))
+ (should (equal (url-generic-parse-url "http://host/foo/bar#fragment") (url-parse-make-urlobj "http" nil nil "host" nil "/foo/bar" "fragment" nil t)))
+ (should (equal (url-generic-parse-url "http://host/foo/bar?#") (url-parse-make-urlobj "http" nil nil "host" nil "/foo/bar?" "" nil t)))
+ (should (equal (url-generic-parse-url "http://host/foo/bar?query#") (url-parse-make-urlobj "http" nil nil "host" nil "/foo/bar?query" "" nil t)))
+ (should (equal (url-generic-parse-url "http://host/foo/bar?#fragment") (url-parse-make-urlobj "http" nil nil "host" nil "/foo/bar?" "fragment" nil t)))
+ (should (equal (url-generic-parse-url "http://host/foo/bar?query#fragment") (url-parse-make-urlobj "http" nil nil "host" nil "/foo/bar?query" "fragment" nil t)))
+ ;; absolute path /foo/bar/
+ (should (equal (url-generic-parse-url "http://host/foo/bar/#") (url-parse-make-urlobj "http" nil nil "host" nil "/foo/bar/" "" nil t)))
+ (should (equal (url-generic-parse-url "http://host/foo/bar/#fragment") (url-parse-make-urlobj "http" nil nil "host" nil "/foo/bar/" "fragment" nil t)))
+ (should (equal (url-generic-parse-url "http://host/foo/bar/?#") (url-parse-make-urlobj "http" nil nil "host" nil "/foo/bar/?" "" nil t)))
+ (should (equal (url-generic-parse-url "http://host/foo/bar/?query#") (url-parse-make-urlobj "http" nil nil "host" nil "/foo/bar/?query" "" nil t)))
+ (should (equal (url-generic-parse-url "http://host/foo/bar/?#fragment") (url-parse-make-urlobj "http" nil nil "host" nil "/foo/bar/?" "fragment" nil t)))
+ (should (equal (url-generic-parse-url "http://host/foo/bar/?query#fragment") (url-parse-make-urlobj "http" nil nil "host" nil "/foo/bar/?query" "fragment" nil t)))
+ ;; for more examples of URIs without fragments, see tests covering section 4.3. Absolute URI
+ )
+
+(ert-deftest url-generic-parse-url/network-path-reference ()
+ "RFC 3986, section 4.2. Relative Reference / network-path reference: a relative reference that begins with two slash characters"
+ (should (equal (url-generic-parse-url "//host") (url-parse-make-urlobj nil nil nil "host" nil "" nil nil t)))
+ (should (equal (url-generic-parse-url "//host/") (url-parse-make-urlobj nil nil nil "host" nil "/" nil nil t)))
+ (should (equal (url-generic-parse-url "//host/foo") (url-parse-make-urlobj nil nil nil "host" nil "/foo" nil nil t)))
+ (should (equal (url-generic-parse-url "//host/foo/bar") (url-parse-make-urlobj nil nil nil "host" nil "/foo/bar" nil nil t)))
+ (should (equal (url-generic-parse-url "//host/foo/bar/") (url-parse-make-urlobj nil nil nil "host" nil "/foo/bar/" nil nil t))))
+
+(ert-deftest url-generic-parse-url/absolute-path-reference ()
+ "RFC 3986, section 4.2. Relative Reference / absolute-path reference: a relative reference that begins with a single slash character"
+ (should (equal (url-generic-parse-url "/") (url-parse-make-urlobj nil nil nil nil nil "/" nil nil nil)))
+ (should (equal (url-generic-parse-url "/foo") (url-parse-make-urlobj nil nil nil nil nil "/foo" nil nil nil)))
+ (should (equal (url-generic-parse-url "/foo/bar") (url-parse-make-urlobj nil nil nil nil nil "/foo/bar" nil nil nil)))
+ (should (equal (url-generic-parse-url "/foo/bar/") (url-parse-make-urlobj nil nil nil nil nil "/foo/bar/" nil nil nil)))
+ (should (equal (url-generic-parse-url "/foo/bar#") (url-parse-make-urlobj nil nil nil nil nil "/foo/bar" "" nil nil)))
+ (should (equal (url-generic-parse-url "/foo/bar/#") (url-parse-make-urlobj nil nil nil nil nil "/foo/bar/" "" nil nil))))
+
+(ert-deftest url-generic-parse-url/relative-path-reference ()
+ "RFC 3986, section 4.2. Relative Reference / relative-path reference: a relative reference that does not begin with a slash character"
+ (should (equal (url-generic-parse-url "foo") (url-parse-make-urlobj nil nil nil nil nil "foo" nil nil nil)))
+ (should (equal (url-generic-parse-url "foo/bar") (url-parse-make-urlobj nil nil nil nil nil "foo/bar" nil nil nil)))
+ (should (equal (url-generic-parse-url "foo/bar/") (url-parse-make-urlobj nil nil nil nil nil "foo/bar/" nil nil nil)))
+ (should (equal (url-generic-parse-url "./foo") (url-parse-make-urlobj nil nil nil nil nil "./foo" nil nil nil)))
+ (should (equal (url-generic-parse-url "./foo/bar") (url-parse-make-urlobj nil nil nil nil nil "./foo/bar" nil nil nil)))
+ (should (equal (url-generic-parse-url "./foo/bar/") (url-parse-make-urlobj nil nil nil nil nil "./foo/bar/" nil nil nil)))
+ (should (equal (url-generic-parse-url "../foo") (url-parse-make-urlobj nil nil nil nil nil "../foo" nil nil nil)))
+ (should (equal (url-generic-parse-url "../foo/bar") (url-parse-make-urlobj nil nil nil nil nil "../foo/bar" nil nil nil)))
+ (should (equal (url-generic-parse-url "../foo/bar/") (url-parse-make-urlobj nil nil nil nil nil "../foo/bar/" nil nil nil)))
+ (should (equal (url-generic-parse-url "./this:that") (url-parse-make-urlobj nil nil nil nil nil "./this:that" nil nil nil)))
+ ;; for more examples of relative-path references, see tests covering section 4.4. Same-Document Reference
+ )
+
+(ert-deftest url-generic-parse-url/absolute-uri ()
+ "RFC 3986, section 4.3. Absolute URI / absolute URI: absolute form of a URI without a fragment identifier"
+ ;; empty path
+ (should (equal (url-generic-parse-url "http://host") (url-parse-make-urlobj "http" nil nil "host" nil "" nil nil t)))
+ (should (equal (url-generic-parse-url "http://host?") (url-parse-make-urlobj "http" nil nil "host" nil "?" nil nil t)))
+ (should (equal (url-generic-parse-url "http://host?query") (url-parse-make-urlobj "http" nil nil "host" nil "?query" nil nil t)))
+ ;; absolute path /
+ (should (equal (url-generic-parse-url "http://host/") (url-parse-make-urlobj "http" nil nil "host" nil "/" nil nil t)))
+ (should (equal (url-generic-parse-url "http://host/?") (url-parse-make-urlobj "http" nil nil "host" nil "/?" nil nil t)))
+ (should (equal (url-generic-parse-url "http://host/?query") (url-parse-make-urlobj "http" nil nil "host" nil "/?query" nil nil t)))
+ ;; absolute path /foo
+ (should (equal (url-generic-parse-url "http://host/foo") (url-parse-make-urlobj "http" nil nil "host" nil "/foo" nil nil t)))
+ (should (equal (url-generic-parse-url "http://host/foo?") (url-parse-make-urlobj "http" nil nil "host" nil "/foo?" nil nil t)))
+ (should (equal (url-generic-parse-url "http://host/foo?query") (url-parse-make-urlobj "http" nil nil "host" nil "/foo?query" nil nil t)))
+ ;; absolute path /foo/
+ (should (equal (url-generic-parse-url "http://host/foo/") (url-parse-make-urlobj "http" nil nil "host" nil "/foo/" nil nil t)))
+ (should (equal (url-generic-parse-url "http://host/foo/?") (url-parse-make-urlobj "http" nil nil "host" nil "/foo/?" nil nil t)))
+ (should (equal (url-generic-parse-url "http://host/foo/?query") (url-parse-make-urlobj "http" nil nil "host" nil "/foo/?query" nil nil t)))
+ ;; absolute path /foo/bar
+ (should (equal (url-generic-parse-url "http://host/foo/bar") (url-parse-make-urlobj "http" nil nil "host" nil "/foo/bar" nil nil t)))
+ (should (equal (url-generic-parse-url "http://host/foo/bar?") (url-parse-make-urlobj "http" nil nil "host" nil "/foo/bar?" nil nil t)))
+ (should (equal (url-generic-parse-url "http://host/foo/bar?query") (url-parse-make-urlobj "http" nil nil "host" nil "/foo/bar?query" nil nil t)))
+ ;; absolute path /foo/bar/
+ (should (equal (url-generic-parse-url "http://host/foo/bar/") (url-parse-make-urlobj "http" nil nil "host" nil "/foo/bar/" nil nil t)))
+ (should (equal (url-generic-parse-url "http://host/foo/bar/?") (url-parse-make-urlobj "http" nil nil "host" nil "/foo/bar/?" nil nil t)))
+ (should (equal (url-generic-parse-url "http://host/foo/bar/?query") (url-parse-make-urlobj "http" nil nil "host" nil "/foo/bar/?query" nil nil t)))
+ ;; example mentioned in RFC3986, section 5.4. Reference Resolution Examples
+ (should (equal (url-generic-parse-url "http://a/b/c/d;p?q") (url-parse-make-urlobj "http" nil nil "a" nil "/b/c/d;p?q" nil nil t))))
+
+(ert-deftest url-generic-parse-url/same-document-reference ()
+ "RFC 3986, section 4.4. Same-Document Reference / same-document reference: empty or number sign (\"#\") followed by a fragment identifier"
+ (should (equal (url-generic-parse-url "") (url-parse-make-urlobj nil nil nil nil nil "" nil nil nil)))
+ (should (equal (url-generic-parse-url "#") (url-parse-make-urlobj nil nil nil nil nil "" "" nil nil)))
+ (should (equal (url-generic-parse-url "#foo") (url-parse-make-urlobj nil nil nil nil nil "" "foo" nil nil))))
+
+(provide 'url-parse-tests)
+
+;;; url-parse-tests.el ends here
diff --git a/test/lisp/url/url-util-tests.el b/test/lisp/url/url-util-tests.el
new file mode 100644
index 00000000000..2f1de5103d6
--- /dev/null
+++ b/test/lisp/url/url-util-tests.el
@@ -0,0 +1,51 @@
+;;; url-util-tests.el --- Test suite for url-util.
+
+;; Copyright (C) 2012-2016 Free Software Foundation, Inc.
+
+;; Author: Teodor Zlatanov <tzz@lifelogs.com>
+;; Keywords: data
+
+;; This file is part of GNU Emacs.
+
+;; GNU Emacs 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.
+
+;; GNU Emacs 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 GNU Emacs. If not, see <http://www.gnu.org/licenses/>.
+
+;;; Code:
+
+(require 'ert)
+(require 'url-util)
+
+(ert-deftest url-util-tests ()
+ (let ((tests
+ '(("key1=val1&key2=val2&key3=val1&key3=val2&key4&key5"
+ ((key1 val1) (key2 "val2") (key3 val1 val2) (key4) (key5 "")))
+ ("key1=val1;key2=val2;key3=val1;key3=val2;key4;key5"
+ ((key1 "val1") (key2 val2) (key3 val1 val2) ("key4") (key5 "")) t)
+ ("key1=val1;key2=val2;key3=val1;key3=val2;key4=;key5="
+ ((key1 val1) (key2 val2) ("key3" val1 val2) (key4) (key5 "")) t t)))
+ test)
+ (while tests
+ (setq test (car tests)
+ tests (cdr tests))
+ (should (equal (apply 'url-build-query-string (cdr test)) (car test)))))
+ (should (equal (url-parse-query-string
+ "key1=val1&key2=val2&key3=val1&key3=val2&key4=&key5")
+ '(("key5" "")
+ ("key4" "")
+ ("key3" "val2" "val1")
+ ("key2" "val2")
+ ("key1" "val1")))))
+
+(provide 'url-util-tests)
+
+;;; url-util-tests.el ends here