aboutsummaryrefslogtreecommitdiff
path: root/src/libutil/tests
diff options
context:
space:
mode:
authorCarlo Nucera <carlo.nucera@protonmail.com>2020-05-26 11:14:08 -0400
committerCarlo Nucera <carlo.nucera@protonmail.com>2020-05-26 11:14:08 -0400
commit6d73c100417c68a27a23194c78f1252ca511e250 (patch)
tree04eea8818b97d46fe28ade241069a3650f25a0c6 /src/libutil/tests
parent8aa46cd340c1294c3d06cd52f85c906bdf749070 (diff)
parent3d3c219d917525b0a131c4332dd65eadfc818f49 (diff)
Merge remote-tracking branch 'origin/master' into enum-FileIngestionMethod
Diffstat (limited to 'src/libutil/tests')
-rw-r--r--src/libutil/tests/local.mk15
-rw-r--r--src/libutil/tests/tests.cc589
-rw-r--r--src/libutil/tests/url.cc266
3 files changed, 870 insertions, 0 deletions
diff --git a/src/libutil/tests/local.mk b/src/libutil/tests/local.mk
new file mode 100644
index 000000000..a297edb64
--- /dev/null
+++ b/src/libutil/tests/local.mk
@@ -0,0 +1,15 @@
+check: libutil-tests_RUN
+
+programs += libutil-tests
+
+libutil-tests_DIR := $(d)
+
+libutil-tests_INSTALL_DIR :=
+
+libutil-tests_SOURCES := $(wildcard $(d)/*.cc)
+
+libutil-tests_CXXFLAGS += -I src/libutil
+
+libutil-tests_LIBS = libutil
+
+libutil-tests_LDFLAGS := $(GTEST_LIBS)
diff --git a/src/libutil/tests/tests.cc b/src/libutil/tests/tests.cc
new file mode 100644
index 000000000..8e77ccbe1
--- /dev/null
+++ b/src/libutil/tests/tests.cc
@@ -0,0 +1,589 @@
+#include "util.hh"
+#include "types.hh"
+
+#include <gtest/gtest.h>
+
+namespace nix {
+
+/* ----------- tests for util.hh ------------------------------------------------*/
+
+ /* ----------------------------------------------------------------------------
+ * absPath
+ * --------------------------------------------------------------------------*/
+
+ TEST(absPath, doesntChangeRoot) {
+ auto p = absPath("/");
+
+ ASSERT_EQ(p, "/");
+ }
+
+
+
+
+ TEST(absPath, turnsEmptyPathIntoCWD) {
+ char cwd[PATH_MAX+1];
+ auto p = absPath("");
+
+ ASSERT_EQ(p, getcwd((char*)&cwd, PATH_MAX));
+ }
+
+ TEST(absPath, usesOptionalBasePathWhenGiven) {
+ char _cwd[PATH_MAX+1];
+ char* cwd = getcwd((char*)&_cwd, PATH_MAX);
+
+ auto p = absPath("", cwd);
+
+ ASSERT_EQ(p, cwd);
+ }
+
+ TEST(absPath, isIdempotent) {
+ char _cwd[PATH_MAX+1];
+ char* cwd = getcwd((char*)&_cwd, PATH_MAX);
+ auto p1 = absPath(cwd);
+ auto p2 = absPath(p1);
+
+ ASSERT_EQ(p1, p2);
+ }
+
+
+ TEST(absPath, pathIsCanonicalised) {
+ auto path = "/some/path/with/trailing/dot/.";
+ auto p1 = absPath(path);
+ auto p2 = absPath(p1);
+
+ ASSERT_EQ(p1, "/some/path/with/trailing/dot");
+ ASSERT_EQ(p1, p2);
+ }
+
+ /* ----------------------------------------------------------------------------
+ * canonPath
+ * --------------------------------------------------------------------------*/
+
+ TEST(canonPath, removesTrailingSlashes) {
+ auto path = "/this/is/a/path//";
+ auto p = canonPath(path);
+
+ ASSERT_EQ(p, "/this/is/a/path");
+ }
+
+ TEST(canonPath, removesDots) {
+ auto path = "/this/./is/a/path/./";
+ auto p = canonPath(path);
+
+ ASSERT_EQ(p, "/this/is/a/path");
+ }
+
+ TEST(canonPath, removesDots2) {
+ auto path = "/this/a/../is/a////path/foo/..";
+ auto p = canonPath(path);
+
+ ASSERT_EQ(p, "/this/is/a/path");
+ }
+
+ TEST(canonPath, requiresAbsolutePath) {
+ ASSERT_ANY_THROW(canonPath("."));
+ ASSERT_ANY_THROW(canonPath(".."));
+ ASSERT_ANY_THROW(canonPath("../"));
+ ASSERT_DEATH({ canonPath(""); }, "path != \"\"");
+ }
+
+ /* ----------------------------------------------------------------------------
+ * dirOf
+ * --------------------------------------------------------------------------*/
+
+ TEST(dirOf, returnsEmptyStringForRoot) {
+ auto p = dirOf("/");
+
+ ASSERT_EQ(p, "/");
+ }
+
+ TEST(dirOf, returnsFirstPathComponent) {
+ auto p1 = dirOf("/dir/");
+ ASSERT_EQ(p1, "/dir");
+ auto p2 = dirOf("/dir");
+ ASSERT_EQ(p2, "/");
+ auto p3 = dirOf("/dir/..");
+ ASSERT_EQ(p3, "/dir");
+ auto p4 = dirOf("/dir/../");
+ ASSERT_EQ(p4, "/dir/..");
+ }
+
+ /* ----------------------------------------------------------------------------
+ * baseNameOf
+ * --------------------------------------------------------------------------*/
+
+ TEST(baseNameOf, emptyPath) {
+ auto p1 = baseNameOf("");
+ ASSERT_EQ(p1, "");
+ }
+
+ TEST(baseNameOf, pathOnRoot) {
+ auto p1 = baseNameOf("/dir");
+ ASSERT_EQ(p1, "dir");
+ }
+
+ TEST(baseNameOf, relativePath) {
+ auto p1 = baseNameOf("dir/foo");
+ ASSERT_EQ(p1, "foo");
+ }
+
+ TEST(baseNameOf, pathWithTrailingSlashRoot) {
+ auto p1 = baseNameOf("/");
+ ASSERT_EQ(p1, "");
+ }
+
+ TEST(baseNameOf, trailingSlash) {
+ auto p1 = baseNameOf("/dir/");
+ ASSERT_EQ(p1, "dir");
+ }
+
+ /* ----------------------------------------------------------------------------
+ * isInDir
+ * --------------------------------------------------------------------------*/
+
+ TEST(isInDir, trivialCase) {
+ auto p1 = isInDir("/foo/bar", "/foo");
+ ASSERT_EQ(p1, true);
+ }
+
+ TEST(isInDir, notInDir) {
+ auto p1 = isInDir("/zes/foo/bar", "/foo");
+ ASSERT_EQ(p1, false);
+ }
+
+ // XXX: hm, bug or feature? :) Looking at the implementation
+ // this might be problematic.
+ TEST(isInDir, emptyDir) {
+ auto p1 = isInDir("/zes/foo/bar", "");
+ ASSERT_EQ(p1, true);
+ }
+
+ /* ----------------------------------------------------------------------------
+ * isDirOrInDir
+ * --------------------------------------------------------------------------*/
+
+ TEST(isDirOrInDir, trueForSameDirectory) {
+ ASSERT_EQ(isDirOrInDir("/nix", "/nix"), true);
+ ASSERT_EQ(isDirOrInDir("/", "/"), true);
+ }
+
+ TEST(isDirOrInDir, trueForEmptyPaths) {
+ ASSERT_EQ(isDirOrInDir("", ""), true);
+ }
+
+ TEST(isDirOrInDir, falseForDisjunctPaths) {
+ ASSERT_EQ(isDirOrInDir("/foo", "/bar"), false);
+ }
+
+ TEST(isDirOrInDir, relativePaths) {
+ ASSERT_EQ(isDirOrInDir("/foo/..", "/foo"), true);
+ }
+
+ // XXX: while it is possible to use "." or ".." in the
+ // first argument this doesn't seem to work in the second.
+ TEST(isDirOrInDir, DISABLED_shouldWork) {
+ ASSERT_EQ(isDirOrInDir("/foo/..", "/foo/."), true);
+
+ }
+
+ /* ----------------------------------------------------------------------------
+ * pathExists
+ * --------------------------------------------------------------------------*/
+
+ TEST(pathExists, rootExists) {
+ ASSERT_TRUE(pathExists("/"));
+ }
+
+ TEST(pathExists, cwdExists) {
+ ASSERT_TRUE(pathExists("."));
+ }
+
+ TEST(pathExists, bogusPathDoesNotExist) {
+ ASSERT_FALSE(pathExists("/home/schnitzel/darmstadt/pommes"));
+ }
+
+ /* ----------------------------------------------------------------------------
+ * concatStringsSep
+ * --------------------------------------------------------------------------*/
+
+ TEST(concatStringsSep, buildCommaSeparatedString) {
+ Strings strings;
+ strings.push_back("this");
+ strings.push_back("is");
+ strings.push_back("great");
+
+ ASSERT_EQ(concatStringsSep(",", strings), "this,is,great");
+ }
+
+ TEST(concatStringsSep, buildStringWithEmptySeparator) {
+ Strings strings;
+ strings.push_back("this");
+ strings.push_back("is");
+ strings.push_back("great");
+
+ ASSERT_EQ(concatStringsSep("", strings), "thisisgreat");
+ }
+
+ TEST(concatStringsSep, buildSingleString) {
+ Strings strings;
+ strings.push_back("this");
+
+ ASSERT_EQ(concatStringsSep(",", strings), "this");
+ }
+
+ /* ----------------------------------------------------------------------------
+ * hasPrefix
+ * --------------------------------------------------------------------------*/
+
+ TEST(hasPrefix, emptyStringHasNoPrefix) {
+ ASSERT_FALSE(hasPrefix("", "foo"));
+ }
+
+ TEST(hasPrefix, emptyStringIsAlwaysPrefix) {
+ ASSERT_TRUE(hasPrefix("foo", ""));
+ ASSERT_TRUE(hasPrefix("jshjkfhsadf", ""));
+ }
+
+ TEST(hasPrefix, trivialCase) {
+ ASSERT_TRUE(hasPrefix("foobar", "foo"));
+ }
+
+ /* ----------------------------------------------------------------------------
+ * hasSuffix
+ * --------------------------------------------------------------------------*/
+
+ TEST(hasSuffix, emptyStringHasNoSuffix) {
+ ASSERT_FALSE(hasSuffix("", "foo"));
+ }
+
+ TEST(hasSuffix, trivialCase) {
+ ASSERT_TRUE(hasSuffix("foo", "foo"));
+ ASSERT_TRUE(hasSuffix("foobar", "bar"));
+ }
+
+ /* ----------------------------------------------------------------------------
+ * base64Encode
+ * --------------------------------------------------------------------------*/
+
+ TEST(base64Encode, emptyString) {
+ ASSERT_EQ(base64Encode(""), "");
+ }
+
+ TEST(base64Encode, encodesAString) {
+ ASSERT_EQ(base64Encode("quod erat demonstrandum"), "cXVvZCBlcmF0IGRlbW9uc3RyYW5kdW0=");
+ }
+
+ TEST(base64Encode, encodeAndDecode) {
+ auto s = "quod erat demonstrandum";
+ auto encoded = base64Encode(s);
+ auto decoded = base64Decode(encoded);
+
+ ASSERT_EQ(decoded, s);
+ }
+
+ /* ----------------------------------------------------------------------------
+ * base64Decode
+ * --------------------------------------------------------------------------*/
+
+ TEST(base64Decode, emptyString) {
+ ASSERT_EQ(base64Decode(""), "");
+ }
+
+ TEST(base64Decode, decodeAString) {
+ ASSERT_EQ(base64Decode("cXVvZCBlcmF0IGRlbW9uc3RyYW5kdW0="), "quod erat demonstrandum");
+ }
+
+ /* ----------------------------------------------------------------------------
+ * toLower
+ * --------------------------------------------------------------------------*/
+
+ TEST(toLower, emptyString) {
+ ASSERT_EQ(toLower(""), "");
+ }
+
+ TEST(toLower, nonLetters) {
+ auto s = "!@(*$#)(@#=\\234_";
+ ASSERT_EQ(toLower(s), s);
+ }
+
+ // std::tolower() doesn't handle unicode characters. In the context of
+ // store paths this isn't relevant but doesn't hurt to record this behavior
+ // here.
+ TEST(toLower, umlauts) {
+ auto s = "ÄÖÜ";
+ ASSERT_EQ(toLower(s), "ÄÖÜ");
+ }
+
+ /* ----------------------------------------------------------------------------
+ * string2Float
+ * --------------------------------------------------------------------------*/
+
+ TEST(string2Float, emptyString) {
+ double n;
+ ASSERT_EQ(string2Float("", n), false);
+ }
+
+ TEST(string2Float, trivialConversions) {
+ double n;
+ ASSERT_EQ(string2Float("1.0", n), true);
+ ASSERT_EQ(n, 1.0);
+
+ ASSERT_EQ(string2Float("0.0", n), true);
+ ASSERT_EQ(n, 0.0);
+
+ ASSERT_EQ(string2Float("-100.25", n), true);
+ ASSERT_EQ(n, (-100.25));
+ }
+
+ /* ----------------------------------------------------------------------------
+ * string2Int
+ * --------------------------------------------------------------------------*/
+
+ TEST(string2Int, emptyString) {
+ double n;
+ ASSERT_EQ(string2Int("", n), false);
+ }
+
+ TEST(string2Int, trivialConversions) {
+ double n;
+ ASSERT_EQ(string2Int("1", n), true);
+ ASSERT_EQ(n, 1);
+
+ ASSERT_EQ(string2Int("0", n), true);
+ ASSERT_EQ(n, 0);
+
+ ASSERT_EQ(string2Int("-100", n), true);
+ ASSERT_EQ(n, (-100));
+ }
+
+ /* ----------------------------------------------------------------------------
+ * statusOk
+ * --------------------------------------------------------------------------*/
+
+ TEST(statusOk, zeroIsOk) {
+ ASSERT_EQ(statusOk(0), true);
+ ASSERT_EQ(statusOk(1), false);
+ }
+
+
+ /* ----------------------------------------------------------------------------
+ * rewriteStrings
+ * --------------------------------------------------------------------------*/
+
+ TEST(rewriteStrings, emptyString) {
+ StringMap rewrites;
+ rewrites["this"] = "that";
+
+ ASSERT_EQ(rewriteStrings("", rewrites), "");
+ }
+
+ TEST(rewriteStrings, emptyRewrites) {
+ StringMap rewrites;
+
+ ASSERT_EQ(rewriteStrings("this and that", rewrites), "this and that");
+ }
+
+ TEST(rewriteStrings, successfulRewrite) {
+ StringMap rewrites;
+ rewrites["this"] = "that";
+
+ ASSERT_EQ(rewriteStrings("this and that", rewrites), "that and that");
+ }
+
+ TEST(rewriteStrings, doesntOccur) {
+ StringMap rewrites;
+ rewrites["foo"] = "bar";
+
+ ASSERT_EQ(rewriteStrings("this and that", rewrites), "this and that");
+ }
+
+ /* ----------------------------------------------------------------------------
+ * replaceStrings
+ * --------------------------------------------------------------------------*/
+
+ TEST(replaceStrings, emptyString) {
+ ASSERT_EQ(replaceStrings("", "this", "that"), "");
+ ASSERT_EQ(replaceStrings("this and that", "", ""), "this and that");
+ }
+
+ TEST(replaceStrings, successfulReplace) {
+ ASSERT_EQ(replaceStrings("this and that", "this", "that"), "that and that");
+ }
+
+ TEST(replaceStrings, doesntOccur) {
+ ASSERT_EQ(replaceStrings("this and that", "foo", "bar"), "this and that");
+ }
+
+ /* ----------------------------------------------------------------------------
+ * trim
+ * --------------------------------------------------------------------------*/
+
+ TEST(trim, emptyString) {
+ ASSERT_EQ(trim(""), "");
+ }
+
+ TEST(trim, removesWhitespace) {
+ ASSERT_EQ(trim("foo"), "foo");
+ ASSERT_EQ(trim(" foo "), "foo");
+ ASSERT_EQ(trim(" foo bar baz"), "foo bar baz");
+ ASSERT_EQ(trim(" \t foo bar baz\n"), "foo bar baz");
+ }
+
+ /* ----------------------------------------------------------------------------
+ * chomp
+ * --------------------------------------------------------------------------*/
+
+ TEST(chomp, emptyString) {
+ ASSERT_EQ(chomp(""), "");
+ }
+
+ TEST(chomp, removesWhitespace) {
+ ASSERT_EQ(chomp("foo"), "foo");
+ ASSERT_EQ(chomp("foo "), "foo");
+ ASSERT_EQ(chomp(" foo "), " foo");
+ ASSERT_EQ(chomp(" foo bar baz "), " foo bar baz");
+ ASSERT_EQ(chomp("\t foo bar baz\n"), "\t foo bar baz");
+ }
+
+ /* ----------------------------------------------------------------------------
+ * quoteStrings
+ * --------------------------------------------------------------------------*/
+
+ TEST(quoteStrings, empty) {
+ Strings s = { };
+ Strings expected = { };
+
+ ASSERT_EQ(quoteStrings(s), expected);
+ }
+
+ TEST(quoteStrings, emptyStrings) {
+ Strings s = { "", "", "" };
+ Strings expected = { "''", "''", "''" };
+ ASSERT_EQ(quoteStrings(s), expected);
+
+ }
+
+ TEST(quoteStrings, trivialQuote) {
+ Strings s = { "foo", "bar", "baz" };
+ Strings expected = { "'foo'", "'bar'", "'baz'" };
+
+ ASSERT_EQ(quoteStrings(s), expected);
+ }
+
+ TEST(quoteStrings, quotedStrings) {
+ Strings s = { "'foo'", "'bar'", "'baz'" };
+ Strings expected = { "''foo''", "''bar''", "''baz''" };
+
+ ASSERT_EQ(quoteStrings(s), expected);
+ }
+
+ /* ----------------------------------------------------------------------------
+ * tokenizeString
+ * --------------------------------------------------------------------------*/
+
+ TEST(tokenizeString, empty) {
+ Strings expected = { };
+
+ ASSERT_EQ(tokenizeString<Strings>(""), expected);
+ }
+
+ TEST(tokenizeString, tokenizeSpacesWithDefaults) {
+ auto s = "foo bar baz";
+ Strings expected = { "foo", "bar", "baz" };
+
+ ASSERT_EQ(tokenizeString<Strings>(s), expected);
+ }
+
+ TEST(tokenizeString, tokenizeTabsWithDefaults) {
+ auto s = "foo\tbar\tbaz";
+ Strings expected = { "foo", "bar", "baz" };
+
+ ASSERT_EQ(tokenizeString<Strings>(s), expected);
+ }
+
+ TEST(tokenizeString, tokenizeTabsSpacesWithDefaults) {
+ auto s = "foo\t bar\t baz";
+ Strings expected = { "foo", "bar", "baz" };
+
+ ASSERT_EQ(tokenizeString<Strings>(s), expected);
+ }
+
+ TEST(tokenizeString, tokenizeTabsSpacesNewlineWithDefaults) {
+ auto s = "foo\t\n bar\t\n baz";
+ Strings expected = { "foo", "bar", "baz" };
+
+ ASSERT_EQ(tokenizeString<Strings>(s), expected);
+ }
+
+ TEST(tokenizeString, tokenizeTabsSpacesNewlineRetWithDefaults) {
+ auto s = "foo\t\n\r bar\t\n\r baz";
+ Strings expected = { "foo", "bar", "baz" };
+
+ ASSERT_EQ(tokenizeString<Strings>(s), expected);
+
+ auto s2 = "foo \t\n\r bar \t\n\r baz";
+ Strings expected2 = { "foo", "bar", "baz" };
+
+ ASSERT_EQ(tokenizeString<Strings>(s2), expected2);
+ }
+
+ TEST(tokenizeString, tokenizeWithCustomSep) {
+ auto s = "foo\n,bar\n,baz\n";
+ Strings expected = { "foo\n", "bar\n", "baz\n" };
+
+ ASSERT_EQ(tokenizeString<Strings>(s, ","), expected);
+ }
+
+ /* ----------------------------------------------------------------------------
+ * get
+ * --------------------------------------------------------------------------*/
+
+ TEST(get, emptyContainer) {
+ StringMap s = { };
+ auto expected = std::nullopt;
+
+ ASSERT_EQ(get(s, "one"), expected);
+ }
+
+ TEST(get, getFromContainer) {
+ StringMap s;
+ s["one"] = "yi";
+ s["two"] = "er";
+ auto expected = "yi";
+
+ ASSERT_EQ(get(s, "one"), expected);
+ }
+
+ /* ----------------------------------------------------------------------------
+ * filterANSIEscapes
+ * --------------------------------------------------------------------------*/
+
+ TEST(filterANSIEscapes, emptyString) {
+ auto s = "";
+ auto expected = "";
+
+ ASSERT_EQ(filterANSIEscapes(s), expected);
+ }
+
+ TEST(filterANSIEscapes, doesntChangePrintableChars) {
+ auto s = "09 2q304ruyhr slk2-19024 kjsadh sar f";
+
+ ASSERT_EQ(filterANSIEscapes(s), s);
+ }
+
+ TEST(filterANSIEscapes, filtersColorCodes) {
+ auto s = "\u001b[30m A \u001b[31m B \u001b[32m C \u001b[33m D \u001b[0m";
+
+ ASSERT_EQ(filterANSIEscapes(s, true, 2), " A" );
+ ASSERT_EQ(filterANSIEscapes(s, true, 3), " A " );
+ ASSERT_EQ(filterANSIEscapes(s, true, 4), " A " );
+ ASSERT_EQ(filterANSIEscapes(s, true, 5), " A B" );
+ ASSERT_EQ(filterANSIEscapes(s, true, 8), " A B C" );
+ }
+
+ TEST(filterANSIEscapes, expandsTabs) {
+ auto s = "foo\tbar\tbaz";
+
+ ASSERT_EQ(filterANSIEscapes(s, true), "foo bar baz" );
+ }
+}
diff --git a/src/libutil/tests/url.cc b/src/libutil/tests/url.cc
new file mode 100644
index 000000000..80646ad3e
--- /dev/null
+++ b/src/libutil/tests/url.cc
@@ -0,0 +1,266 @@
+#include "url.hh"
+#include <gtest/gtest.h>
+
+namespace nix {
+
+/* ----------- tests for url.hh --------------------------------------------------*/
+
+ string print_map(std::map<string, string> m) {
+ std::map<string, string>::iterator it;
+ string s = "{ ";
+ for (it = m.begin(); it != m.end(); ++it) {
+ s += "{ ";
+ s += it->first;
+ s += " = ";
+ s += it->second;
+ s += " } ";
+ }
+ s += "}";
+ return s;
+ }
+
+
+ std::ostream& operator<<(std::ostream& os, const ParsedURL& p) {
+ return os << "\n"
+ << "url: " << p.url << "\n"
+ << "base: " << p.base << "\n"
+ << "scheme: " << p.scheme << "\n"
+ << "authority: " << p.authority.value() << "\n"
+ << "path: " << p.path << "\n"
+ << "query: " << print_map(p.query) << "\n"
+ << "fragment: " << p.fragment << "\n";
+ }
+
+ TEST(parseURL, parsesSimpleHttpUrl) {
+ auto s = "http://www.example.org/file.tar.gz";
+ auto parsed = parseURL(s);
+
+ ParsedURL expected {
+ .url = "http://www.example.org/file.tar.gz",
+ .base = "http://www.example.org/file.tar.gz",
+ .scheme = "http",
+ .authority = "www.example.org",
+ .path = "/file.tar.gz",
+ .query = (StringMap) { },
+ .fragment = "",
+ };
+
+ ASSERT_EQ(parsed, expected);
+ }
+
+ TEST(parseURL, parsesSimpleHttpsUrl) {
+ auto s = "https://www.example.org/file.tar.gz";
+ auto parsed = parseURL(s);
+
+ ParsedURL expected {
+ .url = "https://www.example.org/file.tar.gz",
+ .base = "https://www.example.org/file.tar.gz",
+ .scheme = "https",
+ .authority = "www.example.org",
+ .path = "/file.tar.gz",
+ .query = (StringMap) { },
+ .fragment = "",
+ };
+
+ ASSERT_EQ(parsed, expected);
+ }
+
+ TEST(parseURL, parsesSimpleHttpUrlWithQueryAndFragment) {
+ auto s = "https://www.example.org/file.tar.gz?download=fast&when=now#hello";
+ auto parsed = parseURL(s);
+
+ ParsedURL expected {
+ .url = "https://www.example.org/file.tar.gz",
+ .base = "https://www.example.org/file.tar.gz",
+ .scheme = "https",
+ .authority = "www.example.org",
+ .path = "/file.tar.gz",
+ .query = (StringMap) { { "download", "fast" }, { "when", "now" } },
+ .fragment = "hello",
+ };
+
+ ASSERT_EQ(parsed, expected);
+ }
+
+ TEST(parseURL, parsesSimpleHttpUrlWithComplexFragment) {
+ auto s = "http://www.example.org/file.tar.gz?field=value#?foo=bar%23";
+ auto parsed = parseURL(s);
+
+ ParsedURL expected {
+ .url = "http://www.example.org/file.tar.gz",
+ .base = "http://www.example.org/file.tar.gz",
+ .scheme = "http",
+ .authority = "www.example.org",
+ .path = "/file.tar.gz",
+ .query = (StringMap) { { "field", "value" } },
+ .fragment = "?foo=bar#",
+ };
+
+ ASSERT_EQ(parsed, expected);
+ }
+
+
+ TEST(parseURL, parseIPv4Address) {
+ auto s = "http://127.0.0.1:8080/file.tar.gz?download=fast&when=now#hello";
+ auto parsed = parseURL(s);
+
+ ParsedURL expected {
+ .url = "http://127.0.0.1:8080/file.tar.gz",
+ .base = "https://127.0.0.1:8080/file.tar.gz",
+ .scheme = "http",
+ .authority = "127.0.0.1:8080",
+ .path = "/file.tar.gz",
+ .query = (StringMap) { { "download", "fast" }, { "when", "now" } },
+ .fragment = "hello",
+ };
+
+ ASSERT_EQ(parsed, expected);
+ }
+
+ TEST(parseURL, parseIPv6Address) {
+ auto s = "http://[2a02:8071:8192:c100:311d:192d:81ac:11ea]:8080";
+ auto parsed = parseURL(s);
+
+ ParsedURL expected {
+ .url = "http://[2a02:8071:8192:c100:311d:192d:81ac:11ea]:8080",
+ .base = "http://[2a02:8071:8192:c100:311d:192d:81ac:11ea]:8080",
+ .scheme = "http",
+ .authority = "[2a02:8071:8192:c100:311d:192d:81ac:11ea]:8080",
+ .path = "",
+ .query = (StringMap) { },
+ .fragment = "",
+ };
+
+ ASSERT_EQ(parsed, expected);
+
+ }
+
+ TEST(parseURL, parseEmptyQueryParams) {
+ auto s = "http://127.0.0.1:8080/file.tar.gz?&&&&&";
+ auto parsed = parseURL(s);
+ ASSERT_EQ(parsed.query, (StringMap) { });
+ }
+
+ TEST(parseURL, parseUserPassword) {
+ auto s = "http://user:pass@www.example.org:8080/file.tar.gz";
+ auto parsed = parseURL(s);
+
+ ParsedURL expected {
+ .url = "http://user:pass@www.example.org/file.tar.gz",
+ .base = "http://user:pass@www.example.org/file.tar.gz",
+ .scheme = "http",
+ .authority = "user:pass@www.example.org:8080",
+ .path = "/file.tar.gz",
+ .query = (StringMap) { },
+ .fragment = "",
+ };
+
+
+ ASSERT_EQ(parsed, expected);
+ }
+
+ TEST(parseURL, parseFileURLWithQueryAndFragment) {
+ auto s = "file:///none/of/your/business";
+ auto parsed = parseURL(s);
+
+ ParsedURL expected {
+ .url = "",
+ .base = "",
+ .scheme = "file",
+ .authority = "",
+ .path = "/none/of/your/business",
+ .query = (StringMap) { },
+ .fragment = "",
+ };
+
+ ASSERT_EQ(parsed, expected);
+
+ }
+
+ TEST(parseURL, parsedUrlsIsEqualToItself) {
+ auto s = "http://www.example.org/file.tar.gz";
+ auto url = parseURL(s);
+
+ ASSERT_TRUE(url == url);
+ }
+
+ TEST(parseURL, parseFTPUrl) {
+ auto s = "ftp://ftp.nixos.org/downloads/nixos.iso";
+ auto parsed = parseURL(s);
+
+ ParsedURL expected {
+ .url = "ftp://ftp.nixos.org/downloads/nixos.iso",
+ .base = "ftp://ftp.nixos.org/downloads/nixos.iso",
+ .scheme = "ftp",
+ .authority = "ftp.nixos.org",
+ .path = "/downloads/nixos.iso",
+ .query = (StringMap) { },
+ .fragment = "",
+ };
+
+ ASSERT_EQ(parsed, expected);
+ }
+
+ TEST(parseURL, parsesAnythingInUriFormat) {
+ auto s = "whatever://github.com/NixOS/nixpkgs.git";
+ auto parsed = parseURL(s);
+ }
+
+ TEST(parseURL, parsesAnythingInUriFormatWithoutDoubleSlash) {
+ auto s = "whatever:github.com/NixOS/nixpkgs.git";
+ auto parsed = parseURL(s);
+ }
+
+ TEST(parseURL, emptyStringIsInvalidURL) {
+ ASSERT_THROW(parseURL(""), Error);
+ }
+
+ /* ----------------------------------------------------------------------------
+ * decodeQuery
+ * --------------------------------------------------------------------------*/
+
+ TEST(decodeQuery, emptyStringYieldsEmptyMap) {
+ auto d = decodeQuery("");
+ ASSERT_EQ(d, (StringMap) { });
+ }
+
+ TEST(decodeQuery, simpleDecode) {
+ auto d = decodeQuery("yi=one&er=two");
+ ASSERT_EQ(d, ((StringMap) { { "yi", "one" }, { "er", "two" } }));
+ }
+
+ TEST(decodeQuery, decodeUrlEncodedArgs) {
+ auto d = decodeQuery("arg=%3D%3D%40%3D%3D");
+ ASSERT_EQ(d, ((StringMap) { { "arg", "==@==" } }));
+ }
+
+ TEST(decodeQuery, decodeArgWithEmptyValue) {
+ auto d = decodeQuery("arg=");
+ ASSERT_EQ(d, ((StringMap) { { "arg", ""} }));
+ }
+
+ /* ----------------------------------------------------------------------------
+ * percentDecode
+ * --------------------------------------------------------------------------*/
+
+ TEST(percentDecode, decodesUrlEncodedString) {
+ string s = "==@==";
+ string d = percentDecode("%3D%3D%40%3D%3D");
+ ASSERT_EQ(d, s);
+ }
+
+ TEST(percentDecode, multipleDecodesAreIdempotent) {
+ string once = percentDecode("%3D%3D%40%3D%3D");
+ string twice = percentDecode(once);
+
+ ASSERT_EQ(once, twice);
+ }
+
+ TEST(percentDecode, trailingPercent) {
+ string s = "==@==%";
+ string d = percentDecode("%3D%3D%40%3D%3D%25");
+
+ ASSERT_EQ(d, s);
+ }
+
+}