f7f37035c8
Today, with the tests inside a `tests` intermingled with the corresponding library's source code, we have a few problems: - We have to be careful that wildcards don't end up with tests being built as part of Nix proper, or test headers being installed as part of Nix proper. - Tests in libraries but not executables is not right: - It means each executable runs the previous unit tests again, because it needs the libraries. - It doesn't work right on Windows, which doesn't want you to load a DLL just for the side global variable . It could be made to work with the dlopen equivalent, but that's gross! This reorg solves these problems. There is a remaining problem which is that sibbling headers (like `hash.hh` the test header vs `hash.hh` the main `libnixutil` header) end up shadowing each other. This PR doesn't solve that. That is left as future work for a future PR. Co-authored-by: Valentin Gagarin <valentin.gagarin@tweag.io> (cherry picked from commit 91b6833686a6a6d9eac7f3f66393ec89ef1d3b57) (cherry picked from commit a61e42adb528b3d40ce43e07c79368d779a8b624)
339 lines
10 KiB
C++
339 lines
10 KiB
C++
#include "url.hh"
|
|
#include <gtest/gtest.h>
|
|
|
|
namespace nix {
|
|
|
|
/* ----------- tests for url.hh --------------------------------------------------*/
|
|
|
|
std::string print_map(std::map<std::string, std::string> m) {
|
|
std::map<std::string, std::string>::iterator it;
|
|
std::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, parsesFilePlusHttpsUrl) {
|
|
auto s = "file+https://www.example.org/video.mp4";
|
|
auto parsed = parseURL(s);
|
|
|
|
ParsedURL expected {
|
|
.url = "file+https://www.example.org/video.mp4",
|
|
.base = "https://www.example.org/video.mp4",
|
|
.scheme = "file+https",
|
|
.authority = "www.example.org",
|
|
.path = "/video.mp4",
|
|
.query = (StringMap) { },
|
|
.fragment = "",
|
|
};
|
|
|
|
ASSERT_EQ(parsed, expected);
|
|
}
|
|
|
|
TEST(parseURL, rejectsAuthorityInUrlsWithFileTransportation) {
|
|
auto s = "file://www.example.org/video.mp4";
|
|
ASSERT_THROW(parseURL(s), Error);
|
|
}
|
|
|
|
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, parseScopedRFC4007IPv6Address) {
|
|
auto s = "http://[fe80::818c:da4d:8975:415c\%enp0s25]:8080";
|
|
auto parsed = parseURL(s);
|
|
|
|
ParsedURL expected {
|
|
.url = "http://[fe80::818c:da4d:8975:415c\%enp0s25]:8080",
|
|
.base = "http://[fe80::818c:da4d:8975:415c\%enp0s25]:8080",
|
|
.scheme = "http",
|
|
.authority = "[fe80::818c:da4d:8975:415c\%enp0s25]:8080",
|
|
.path = "",
|
|
.query = (StringMap) { },
|
|
.fragment = "",
|
|
};
|
|
|
|
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) {
|
|
std::string s = "==@==";
|
|
std::string d = percentDecode("%3D%3D%40%3D%3D");
|
|
ASSERT_EQ(d, s);
|
|
}
|
|
|
|
TEST(percentDecode, multipleDecodesAreIdempotent) {
|
|
std::string once = percentDecode("%3D%3D%40%3D%3D");
|
|
std::string twice = percentDecode(once);
|
|
|
|
ASSERT_EQ(once, twice);
|
|
}
|
|
|
|
TEST(percentDecode, trailingPercent) {
|
|
std::string s = "==@==%";
|
|
std::string d = percentDecode("%3D%3D%40%3D%3D%25");
|
|
|
|
ASSERT_EQ(d, s);
|
|
}
|
|
|
|
|
|
/* ----------------------------------------------------------------------------
|
|
* percentEncode
|
|
* --------------------------------------------------------------------------*/
|
|
|
|
TEST(percentEncode, encodesUrlEncodedString) {
|
|
std::string s = percentEncode("==@==");
|
|
std::string d = "%3D%3D%40%3D%3D";
|
|
ASSERT_EQ(d, s);
|
|
}
|
|
|
|
TEST(percentEncode, keepArgument) {
|
|
std::string a = percentEncode("abd / def");
|
|
std::string b = percentEncode("abd / def", "/");
|
|
ASSERT_EQ(a, "abd%20%2F%20def");
|
|
ASSERT_EQ(b, "abd%20/%20def");
|
|
}
|
|
|
|
TEST(percentEncode, inverseOfDecode) {
|
|
std::string original = "%3D%3D%40%3D%3D";
|
|
std::string once = percentEncode(original);
|
|
std::string back = percentDecode(once);
|
|
|
|
ASSERT_EQ(back, original);
|
|
}
|
|
|
|
TEST(percentEncode, trailingPercent) {
|
|
std::string s = percentEncode("==@==%");
|
|
std::string d = "%3D%3D%40%3D%3D%25";
|
|
|
|
ASSERT_EQ(d, s);
|
|
}
|
|
|
|
}
|