diff options
Diffstat (limited to 'test')
| -rw-r--r-- | test/CompareRangeLengthWrap.cpp | 97 | ||||
| -rw-r--r-- | test/FourSuite.cpp | 1196 | ||||
| -rw-r--r-- | test/MemoryManagerSuite.cpp | 554 | ||||
| -rw-r--r-- | test/SetFragment.cpp | 230 | ||||
| -rw-r--r-- | test/SetHostAuto.cpp | 223 | ||||
| -rw-r--r-- | test/SetHostIp4.cpp | 316 | ||||
| -rw-r--r-- | test/SetHostIp6.cpp | 387 | ||||
| -rw-r--r-- | test/SetHostIpFuture.cpp | 300 | ||||
| -rw-r--r-- | test/SetHostRegName.cpp | 336 | ||||
| -rw-r--r-- | test/SetPath.cpp | 450 | ||||
| -rw-r--r-- | test/SetPort.cpp | 191 | ||||
| -rw-r--r-- | test/SetQuery.cpp | 231 | ||||
| -rw-r--r-- | test/SetScheme.cpp | 230 | ||||
| -rw-r--r-- | test/SetUserInfo.cpp | 238 | ||||
| -rw-r--r-- | test/VersionSuite.cpp | 26 | ||||
| -rw-r--r-- | test/copy.cpp | 202 | ||||
| -rw-r--r-- | test/test.cpp | 4071 |
17 files changed, 6467 insertions, 2811 deletions
diff --git a/test/CompareRangeLengthWrap.cpp b/test/CompareRangeLengthWrap.cpp new file mode 100644 index 0000000..43215bf --- /dev/null +++ b/test/CompareRangeLengthWrap.cpp @@ -0,0 +1,97 @@ +/* + * uriparser - RFC 3986 URI parsing library + * + * Copyright (C) 2026, Joshua W. Windle <joshua.w.windle@gmail.com> + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library 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 + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#include <uriparser/Uri.h> +#include <gtest/gtest.h> + +#include <cstdint> +#include <cstring> + +#if !defined(_WIN32) +# include <sys/mman.h> // mmap, mprotect, munmap +# include <unistd.h> // sysconf +#endif + +extern "C" { +int uriCompareRangeA(const UriTextRangeA * a, const UriTextRangeA * b); +} + +#if !defined(_WIN32) && (UINTPTR_MAX > UINT32_MAX) +namespace { +static size_t roundUpToPageSize(size_t value, size_t pageSize) { + const size_t remainder = value % pageSize; + if (remainder == 0U) { + return value; + } + + const size_t padding = pageSize - remainder; + EXPECT_LE(padding, SIZE_MAX - value); + return value + padding; +} + +static size_t queryPageSize() { + const long pageSize = sysconf(_SC_PAGESIZE); + EXPECT_GT(pageSize, 0); + return static_cast<size_t>(pageSize); +} +} // namespace + +TEST(UriSuite, TestRangeComparisonDoesNotWrapLengthChecksOn64Bit) { + const size_t hugeLen = (static_cast<size_t>(1) << 32) + 10U; + const size_t shortLen = 10U; + const size_t pageSize = queryPageSize(); + const size_t hugeMapLen = roundUpToPageSize(hugeLen, pageSize); + const size_t shortMapLen = pageSize * 2U; + + // Reserve a huge virtual range, with access disabled by default. + char * const hugeBase = static_cast<char *>( + mmap(NULL, hugeMapLen, PROT_NONE, MAP_PRIVATE | MAP_ANONYMOUS, -1, 0)); + ASSERT_NE(hugeBase, MAP_FAILED); + // Allow access to the first page (and that only). + ASSERT_EQ(0, mprotect(hugeBase, pageSize, PROT_READ | PROT_WRITE)); + // Fill the readable prefix so the vulnerable implementation reaches + // content comparison after truncating the large length. + memset(hugeBase, 'a', pageSize); + + char * const shortBase = static_cast<char *>(mmap( + NULL, shortMapLen, PROT_READ | PROT_WRITE, MAP_PRIVATE | MAP_ANONYMOUS, -1, 0)); + ASSERT_NE(shortBase, MAP_FAILED); + // Guard the following page so any over-read beyond shortLen faults. + ASSERT_EQ(0, mprotect(shortBase + pageSize, pageSize, PROT_NONE)); + + char * const shortStart = shortBase + pageSize - shortLen; + memset(shortStart, 'a', shortLen); + + UriTextRangeA hugeRange; + hugeRange.first = hugeBase; + hugeRange.afterLast = hugeBase + hugeLen; + + UriTextRangeA shortRange; + shortRange.first = shortStart; + shortRange.afterLast = shortStart + shortLen; + + const int comparison = uriCompareRangeA(&hugeRange, &shortRange); + + EXPECT_EQ(1, comparison); + + EXPECT_EQ(0, munmap(hugeBase, hugeMapLen)); + EXPECT_EQ(0, munmap(shortBase, shortMapLen)); +} +#endif diff --git a/test/FourSuite.cpp b/test/FourSuite.cpp index 466a94c..87c671b 100644 --- a/test/FourSuite.cpp +++ b/test/FourSuite.cpp @@ -23,610 +23,688 @@ #include <uriparser/Uri.h> - - // All testcases in this file are coming from // http://cvs.4suite.org/viewcvs/4Suite/test/Lib/test_uri.py - namespace { -bool testAddOrRemoveBaseHelper(const char * ref, const char * base, - const char * expected, bool add = true, bool domainRootMode = false) { - UriParserStateA stateA; - - // Base - UriUriA baseUri; - stateA.uri = &baseUri; - int res = uriParseUriA(&stateA, base); - if (res != 0) { - return false; - } - - // Rel - UriUriA relUri; - stateA.uri = &relUri; - res = uriParseUriA(&stateA, ref); - if (res != 0) { - uriFreeUriMembersA(&baseUri); - return false; - } - - // Expected result - UriUriA expectedUri; - stateA.uri = &expectedUri; - res = uriParseUriA(&stateA, expected); - if (res != 0) { - uriFreeUriMembersA(&baseUri); - uriFreeUriMembersA(&relUri); - uriFreeUriMembersA(&expectedUri); - return false; - } - - // Transform - UriUriA transformedUri; - if (add) { - res = uriAddBaseUriA(&transformedUri, &relUri, &baseUri); - } else { - res = uriRemoveBaseUriA(&transformedUri, &relUri, &baseUri, - domainRootMode ? URI_TRUE : URI_FALSE); - } - if (res != 0) { - uriFreeUriMembersA(&baseUri); - uriFreeUriMembersA(&relUri); - uriFreeUriMembersA(&expectedUri); - uriFreeUriMembersA(&transformedUri); - return false; - } - - const bool equal = (URI_TRUE == uriEqualsUriA(&transformedUri, &expectedUri)); - if (!equal) { - char transformedUriText[1024 * 8]; - char expectedUriText[1024 * 8]; - uriToStringA(transformedUriText, &transformedUri, 1024 * 8, NULL); - uriToStringA(expectedUriText, &expectedUri, 1024 * 8, NULL); - printf("\n\n\nExpected: \"%s\"\nReceived: \"%s\"\n\n\n", expectedUriText, transformedUriText); - } - - uriFreeUriMembersA(&baseUri); - uriFreeUriMembersA(&relUri); - uriFreeUriMembersA(&expectedUri); - uriFreeUriMembersA(&transformedUri); - return equal; +bool testAddOrRemoveBaseHelper(const char * ref, const char * base, const char * expected, + bool add = true, bool domainRootMode = false) { + UriParserStateA stateA; + + // Base + UriUriA baseUri; + stateA.uri = &baseUri; + int res = uriParseUriA(&stateA, base); + if (res != 0) { + return false; + } + + // Rel + UriUriA relUri; + stateA.uri = &relUri; + res = uriParseUriA(&stateA, ref); + if (res != 0) { + uriFreeUriMembersA(&baseUri); + return false; + } + + // Expected result + UriUriA expectedUri; + stateA.uri = &expectedUri; + res = uriParseUriA(&stateA, expected); + if (res != 0) { + uriFreeUriMembersA(&baseUri); + uriFreeUriMembersA(&relUri); + uriFreeUriMembersA(&expectedUri); + return false; + } + + // Transform + UriUriA transformedUri; + if (add) { + res = uriAddBaseUriA(&transformedUri, &relUri, &baseUri); + } else { + res = uriRemoveBaseUriA(&transformedUri, &relUri, &baseUri, + domainRootMode ? URI_TRUE : URI_FALSE); + } + if (res != 0) { + uriFreeUriMembersA(&baseUri); + uriFreeUriMembersA(&relUri); + uriFreeUriMembersA(&expectedUri); + uriFreeUriMembersA(&transformedUri); + return false; + } + + const bool equal = (URI_TRUE == uriEqualsUriA(&transformedUri, &expectedUri)); + if (!equal) { + char transformedUriText[1024 * 8]; + char expectedUriText[1024 * 8]; + uriToStringA(transformedUriText, &transformedUri, 1024 * 8, NULL); + uriToStringA(expectedUriText, &expectedUri, 1024 * 8, NULL); + printf("\n\n\nExpected: \"%s\"\nReceived: \"%s\"\n\n\n", expectedUriText, + transformedUriText); + } + + uriFreeUriMembersA(&baseUri); + uriFreeUriMembersA(&relUri); + uriFreeUriMembersA(&expectedUri); + uriFreeUriMembersA(&transformedUri); + return equal; } } // namespace - TEST(FourSuite, AbsolutizeTestCases) { - const char * const BASE_URI[] = { - "http://a/b/c/d;p?q", - "http://a/b/c/d;p?q=1/2", - "http://a/b/c/d;p=1/2?q", - "fred:///s//a/b/c", - "http:///s//a/b/c"}; - - // ref, base, exptected - - // http://lists.w3.org/Archives/Public/uri/2004Feb/0114.html - ASSERT_TRUE(testAddOrRemoveBaseHelper("../c", "foo:a/b", "foo:c")); - ASSERT_TRUE(testAddOrRemoveBaseHelper("foo:.", "foo:a", "foo:")); - ASSERT_TRUE(testAddOrRemoveBaseHelper("/foo/../../../bar", "zz:abc", "zz:/bar")); - ASSERT_TRUE(testAddOrRemoveBaseHelper("/foo/../bar", "zz:abc", "zz:/bar")); - ASSERT_TRUE(testAddOrRemoveBaseHelper("foo/../../../bar", "zz:abc", "zz:bar")); - ASSERT_TRUE(testAddOrRemoveBaseHelper("foo/../bar", "zz:abc", "zz:bar")); - ASSERT_TRUE(testAddOrRemoveBaseHelper("zz:.", "zz:abc", "zz:")); - ASSERT_TRUE(testAddOrRemoveBaseHelper("/.", BASE_URI[0], "http://a/")); - ASSERT_TRUE(testAddOrRemoveBaseHelper("/.foo", BASE_URI[0], "http://a/.foo")); - ASSERT_TRUE(testAddOrRemoveBaseHelper(".foo", BASE_URI[0], "http://a/b/c/.foo")); - - // http://gbiv.com/protocols/uri/test/rel_examples1.html - // examples from RFC 2396 - ASSERT_TRUE(testAddOrRemoveBaseHelper("g:h", BASE_URI[0], "g:h")); - ASSERT_TRUE(testAddOrRemoveBaseHelper("g", BASE_URI[0], "http://a/b/c/g")); - ASSERT_TRUE(testAddOrRemoveBaseHelper("./g", BASE_URI[0], "http://a/b/c/g")); - ASSERT_TRUE(testAddOrRemoveBaseHelper("g/", BASE_URI[0], "http://a/b/c/g/")); - ASSERT_TRUE(testAddOrRemoveBaseHelper("/g", BASE_URI[0], "http://a/g")); - ASSERT_TRUE(testAddOrRemoveBaseHelper("//g", BASE_URI[0], "http://g")); - - // changed with RFC 2396bis - ASSERT_TRUE(testAddOrRemoveBaseHelper("?y", BASE_URI[0], "http://a/b/c/d;p?y")); - ASSERT_TRUE(testAddOrRemoveBaseHelper("g?y", BASE_URI[0], "http://a/b/c/g?y")); - - // changed with RFC 2396bis - ASSERT_TRUE(testAddOrRemoveBaseHelper("#s", BASE_URI[0], "http://a/b/c/d;p?q#s")); - ASSERT_TRUE(testAddOrRemoveBaseHelper("g#s", BASE_URI[0], "http://a/b/c/g#s")); - ASSERT_TRUE(testAddOrRemoveBaseHelper("g?y#s", BASE_URI[0], "http://a/b/c/g?y#s")); - ASSERT_TRUE(testAddOrRemoveBaseHelper(";x", BASE_URI[0], "http://a/b/c/;x")); - ASSERT_TRUE(testAddOrRemoveBaseHelper("g;x", BASE_URI[0], "http://a/b/c/g;x")); - ASSERT_TRUE(testAddOrRemoveBaseHelper("g;x?y#s", BASE_URI[0], "http://a/b/c/g;x?y#s")); - - // changed with RFC 2396bis - ASSERT_TRUE(testAddOrRemoveBaseHelper("", BASE_URI[0], "http://a/b/c/d;p?q")); - ASSERT_TRUE(testAddOrRemoveBaseHelper(".", BASE_URI[0], "http://a/b/c/")); - ASSERT_TRUE(testAddOrRemoveBaseHelper("./", BASE_URI[0], "http://a/b/c/")); - ASSERT_TRUE(testAddOrRemoveBaseHelper("..", BASE_URI[0], "http://a/b/")); - ASSERT_TRUE(testAddOrRemoveBaseHelper("../", BASE_URI[0], "http://a/b/")); - ASSERT_TRUE(testAddOrRemoveBaseHelper("../g", BASE_URI[0], "http://a/b/g")); - ASSERT_TRUE(testAddOrRemoveBaseHelper("../..", BASE_URI[0], "http://a/")); - ASSERT_TRUE(testAddOrRemoveBaseHelper("../../", BASE_URI[0], "http://a/")); - ASSERT_TRUE(testAddOrRemoveBaseHelper("../../g", BASE_URI[0], "http://a/g")); - ASSERT_TRUE(testAddOrRemoveBaseHelper("../../../g", BASE_URI[0], "http://a/g")); // http://a/../g - ASSERT_TRUE(testAddOrRemoveBaseHelper("../../../../g", BASE_URI[0], "http://a/g")); // http://a/../../g - - // changed with RFC 2396bis - ASSERT_TRUE(testAddOrRemoveBaseHelper("/./g", BASE_URI[0], "http://a/g")); - - // changed with RFC 2396bis - ASSERT_TRUE(testAddOrRemoveBaseHelper("/../g", BASE_URI[0], "http://a/g")); - ASSERT_TRUE(testAddOrRemoveBaseHelper("g.", BASE_URI[0], "http://a/b/c/g.")); - ASSERT_TRUE(testAddOrRemoveBaseHelper(".g", BASE_URI[0], "http://a/b/c/.g")); - ASSERT_TRUE(testAddOrRemoveBaseHelper("g..", BASE_URI[0], "http://a/b/c/g..")); - ASSERT_TRUE(testAddOrRemoveBaseHelper("..g", BASE_URI[0], "http://a/b/c/..g")); - ASSERT_TRUE(testAddOrRemoveBaseHelper("./../g", BASE_URI[0], "http://a/b/g")); - ASSERT_TRUE(testAddOrRemoveBaseHelper("./g/.", BASE_URI[0], "http://a/b/c/g/")); - ASSERT_TRUE(testAddOrRemoveBaseHelper("g/./h", BASE_URI[0], "http://a/b/c/g/h")); - ASSERT_TRUE(testAddOrRemoveBaseHelper("g/../h", BASE_URI[0], "http://a/b/c/h")); - ASSERT_TRUE(testAddOrRemoveBaseHelper("g;x=1/./y", BASE_URI[0], "http://a/b/c/g;x=1/y")); - ASSERT_TRUE(testAddOrRemoveBaseHelper("g;x=1/../y", BASE_URI[0], "http://a/b/c/y")); - ASSERT_TRUE(testAddOrRemoveBaseHelper("g?y/./x", BASE_URI[0], "http://a/b/c/g?y/./x")); - ASSERT_TRUE(testAddOrRemoveBaseHelper("g?y/../x", BASE_URI[0], "http://a/b/c/g?y/../x")); - ASSERT_TRUE(testAddOrRemoveBaseHelper("g#s/./x", BASE_URI[0], "http://a/b/c/g#s/./x")); - ASSERT_TRUE(testAddOrRemoveBaseHelper("g#s/../x", BASE_URI[0], "http://a/b/c/g#s/../x")); - ASSERT_TRUE(testAddOrRemoveBaseHelper("http:g", BASE_URI[0], "http:g")); // http://a/b/c/g - ASSERT_TRUE(testAddOrRemoveBaseHelper("http:", BASE_URI[0], "http:")); // BASE_URI[0] - - // not sure where this one originated - ASSERT_TRUE(testAddOrRemoveBaseHelper("/a/b/c/./../../g", BASE_URI[0], "http://a/a/g")); - - // http://gbiv.com/protocols/uri/test/rel_examples2.html - // slashes in base URI's query args - ASSERT_TRUE(testAddOrRemoveBaseHelper("g", BASE_URI[1], "http://a/b/c/g")); - ASSERT_TRUE(testAddOrRemoveBaseHelper("./g", BASE_URI[1], "http://a/b/c/g")); - ASSERT_TRUE(testAddOrRemoveBaseHelper("g/", BASE_URI[1], "http://a/b/c/g/")); - ASSERT_TRUE(testAddOrRemoveBaseHelper("/g", BASE_URI[1], "http://a/g")); - ASSERT_TRUE(testAddOrRemoveBaseHelper("//g", BASE_URI[1], "http://g")); - - // changed in RFC 2396bis - // ASSERT_TRUE(testAddOrRemoveBaseHelper("?y", BASE_URI[1], "http://a/b/c/?y")); - ASSERT_TRUE(testAddOrRemoveBaseHelper("?y", BASE_URI[1], "http://a/b/c/d;p?y")); - ASSERT_TRUE(testAddOrRemoveBaseHelper("g?y", BASE_URI[1], "http://a/b/c/g?y")); - ASSERT_TRUE(testAddOrRemoveBaseHelper("g?y/./x", BASE_URI[1], "http://a/b/c/g?y/./x")); - ASSERT_TRUE(testAddOrRemoveBaseHelper("g?y/../x", BASE_URI[1], "http://a/b/c/g?y/../x")); - ASSERT_TRUE(testAddOrRemoveBaseHelper("g#s", BASE_URI[1], "http://a/b/c/g#s")); - ASSERT_TRUE(testAddOrRemoveBaseHelper("g#s/./x", BASE_URI[1], "http://a/b/c/g#s/./x")); - ASSERT_TRUE(testAddOrRemoveBaseHelper("g#s/../x", BASE_URI[1], "http://a/b/c/g#s/../x")); - ASSERT_TRUE(testAddOrRemoveBaseHelper("./", BASE_URI[1], "http://a/b/c/")); - ASSERT_TRUE(testAddOrRemoveBaseHelper("../", BASE_URI[1], "http://a/b/")); - ASSERT_TRUE(testAddOrRemoveBaseHelper("../g", BASE_URI[1], "http://a/b/g")); - ASSERT_TRUE(testAddOrRemoveBaseHelper("../../", BASE_URI[1], "http://a/")); - ASSERT_TRUE(testAddOrRemoveBaseHelper("../../g", BASE_URI[1], "http://a/g")); - - // http://gbiv.com/protocols/uri/test/rel_examples3.html - // slashes in path params - // all of these changed in RFC 2396bis - ASSERT_TRUE(testAddOrRemoveBaseHelper("g", BASE_URI[2], "http://a/b/c/d;p=1/g")); - ASSERT_TRUE(testAddOrRemoveBaseHelper("./g", BASE_URI[2], "http://a/b/c/d;p=1/g")); - ASSERT_TRUE(testAddOrRemoveBaseHelper("g/", BASE_URI[2], "http://a/b/c/d;p=1/g/")); - ASSERT_TRUE(testAddOrRemoveBaseHelper("g?y", BASE_URI[2], "http://a/b/c/d;p=1/g?y")); - ASSERT_TRUE(testAddOrRemoveBaseHelper(";x", BASE_URI[2], "http://a/b/c/d;p=1/;x")); - ASSERT_TRUE(testAddOrRemoveBaseHelper("g;x", BASE_URI[2], "http://a/b/c/d;p=1/g;x")); - ASSERT_TRUE(testAddOrRemoveBaseHelper("g;x=1/./y", BASE_URI[2], "http://a/b/c/d;p=1/g;x=1/y")); - ASSERT_TRUE(testAddOrRemoveBaseHelper("g;x=1/../y", BASE_URI[2], "http://a/b/c/d;p=1/y")); - ASSERT_TRUE(testAddOrRemoveBaseHelper("./", BASE_URI[2], "http://a/b/c/d;p=1/")); - ASSERT_TRUE(testAddOrRemoveBaseHelper("../", BASE_URI[2], "http://a/b/c/")); - ASSERT_TRUE(testAddOrRemoveBaseHelper("../g", BASE_URI[2], "http://a/b/c/g")); - ASSERT_TRUE(testAddOrRemoveBaseHelper("../../", BASE_URI[2], "http://a/b/")); - ASSERT_TRUE(testAddOrRemoveBaseHelper("../../g", BASE_URI[2], "http://a/b/g")); - - // http://gbiv.com/protocols/uri/test/rel_examples4.html - // double and triple slash, unknown scheme - ASSERT_TRUE(testAddOrRemoveBaseHelper("g:h", BASE_URI[3], "g:h")); - ASSERT_TRUE(testAddOrRemoveBaseHelper("g", BASE_URI[3], "fred:///s//a/b/g")); - ASSERT_TRUE(testAddOrRemoveBaseHelper("./g", BASE_URI[3], "fred:///s//a/b/g")); - ASSERT_TRUE(testAddOrRemoveBaseHelper("g/", BASE_URI[3], "fred:///s//a/b/g/")); - ASSERT_TRUE(testAddOrRemoveBaseHelper("/g", BASE_URI[3], "fred:///g")); // may change to fred:///s//a/g - ASSERT_TRUE(testAddOrRemoveBaseHelper("//g", BASE_URI[3], "fred://g")); // may change to fred:///s//g - ASSERT_TRUE(testAddOrRemoveBaseHelper("//g/x", BASE_URI[3], "fred://g/x")); // may change to fred:///s//g/x - ASSERT_TRUE(testAddOrRemoveBaseHelper("///g", BASE_URI[3], "fred:///g")); - ASSERT_TRUE(testAddOrRemoveBaseHelper("./", BASE_URI[3], "fred:///s//a/b/")); - ASSERT_TRUE(testAddOrRemoveBaseHelper("../", BASE_URI[3], "fred:///s//a/")); - ASSERT_TRUE(testAddOrRemoveBaseHelper("../g", BASE_URI[3], "fred:///s//a/g")); - ASSERT_TRUE(testAddOrRemoveBaseHelper("../../", BASE_URI[3], "fred:///s//")); // may change to fred:///s//a/../ - ASSERT_TRUE(testAddOrRemoveBaseHelper("../../g", BASE_URI[3], "fred:///s//g")); // may change to fred:///s//a/../g - ASSERT_TRUE(testAddOrRemoveBaseHelper("../../../g", BASE_URI[3], "fred:///s/g")); // may change to fred:///s//a/../../g - ASSERT_TRUE(testAddOrRemoveBaseHelper("../../../../g", BASE_URI[3], "fred:///g")); // may change to fred:///s//a/../../../g - - // http://gbiv.com/protocols/uri/test/rel_examples5.html - // double and triple slash, well-known scheme - ASSERT_TRUE(testAddOrRemoveBaseHelper("g:h", BASE_URI[4], "g:h")); - ASSERT_TRUE(testAddOrRemoveBaseHelper("g", BASE_URI[4], "http:///s//a/b/g")); - ASSERT_TRUE(testAddOrRemoveBaseHelper("./g", BASE_URI[4], "http:///s//a/b/g")); - ASSERT_TRUE(testAddOrRemoveBaseHelper("g/", BASE_URI[4], "http:///s//a/b/g/")); - ASSERT_TRUE(testAddOrRemoveBaseHelper("/g", BASE_URI[4], "http:///g")); // may change to http:///s//a/g - ASSERT_TRUE(testAddOrRemoveBaseHelper("//g", BASE_URI[4], "http://g")); // may change to http:///s//g - ASSERT_TRUE(testAddOrRemoveBaseHelper("//g/x", BASE_URI[4], "http://g/x")); // may change to http:///s//g/x - ASSERT_TRUE(testAddOrRemoveBaseHelper("///g", BASE_URI[4], "http:///g")); - ASSERT_TRUE(testAddOrRemoveBaseHelper("./", BASE_URI[4], "http:///s//a/b/")); - ASSERT_TRUE(testAddOrRemoveBaseHelper("../", BASE_URI[4], "http:///s//a/")); - ASSERT_TRUE(testAddOrRemoveBaseHelper("../g", BASE_URI[4], "http:///s//a/g")); - ASSERT_TRUE(testAddOrRemoveBaseHelper("../../", BASE_URI[4], "http:///s//")); // may change to http:///s//a/../ - ASSERT_TRUE(testAddOrRemoveBaseHelper("../../g", BASE_URI[4], "http:///s//g")); // may change to http:///s//a/../g - ASSERT_TRUE(testAddOrRemoveBaseHelper("../../../g", BASE_URI[4], "http:///s/g")); // may change to http:///s//a/../../g - ASSERT_TRUE(testAddOrRemoveBaseHelper("../../../../g", BASE_URI[4], "http:///g")); // may change to http:///s//a/../../../g - - // from Dan Connelly's tests in http://www.w3.org/2000/10/swap/uripath.py - ASSERT_TRUE(testAddOrRemoveBaseHelper("bar:abc", "foo:xyz", "bar:abc")); - ASSERT_TRUE(testAddOrRemoveBaseHelper("../abc", "http://example/x/y/z", "http://example/x/abc")); - ASSERT_TRUE(testAddOrRemoveBaseHelper("http://example/x/abc", "http://example2/x/y/z", "http://example/x/abc")); - ASSERT_TRUE(testAddOrRemoveBaseHelper("../r", "http://ex/x/y/z", "http://ex/x/r")); - ASSERT_TRUE(testAddOrRemoveBaseHelper("q/r", "http://ex/x/y", "http://ex/x/q/r")); - ASSERT_TRUE(testAddOrRemoveBaseHelper("q/r#s", "http://ex/x/y", "http://ex/x/q/r#s")); - ASSERT_TRUE(testAddOrRemoveBaseHelper("q/r#s/t", "http://ex/x/y", "http://ex/x/q/r#s/t")); - ASSERT_TRUE(testAddOrRemoveBaseHelper("ftp://ex/x/q/r", "http://ex/x/y", "ftp://ex/x/q/r")); - ASSERT_TRUE(testAddOrRemoveBaseHelper("", "http://ex/x/y", "http://ex/x/y")); - ASSERT_TRUE(testAddOrRemoveBaseHelper("", "http://ex/x/y/", "http://ex/x/y/")); - ASSERT_TRUE(testAddOrRemoveBaseHelper("", "http://ex/x/y/pdq", "http://ex/x/y/pdq")); - ASSERT_TRUE(testAddOrRemoveBaseHelper("z/", "http://ex/x/y/", "http://ex/x/y/z/")); - ASSERT_TRUE(testAddOrRemoveBaseHelper("#Animal", "file:/swap/test/animal.rdf", "file:/swap/test/animal.rdf#Animal")); - ASSERT_TRUE(testAddOrRemoveBaseHelper("../abc", "file:/e/x/y/z", "file:/e/x/abc")); - ASSERT_TRUE(testAddOrRemoveBaseHelper("/example/x/abc", "file:/example2/x/y/z", "file:/example/x/abc")); - ASSERT_TRUE(testAddOrRemoveBaseHelper("../r", "file:/ex/x/y/z", "file:/ex/x/r")); - ASSERT_TRUE(testAddOrRemoveBaseHelper("/r", "file:/ex/x/y/z", "file:/r")); - ASSERT_TRUE(testAddOrRemoveBaseHelper("q/r", "file:/ex/x/y", "file:/ex/x/q/r")); - ASSERT_TRUE(testAddOrRemoveBaseHelper("q/r#s", "file:/ex/x/y", "file:/ex/x/q/r#s")); - ASSERT_TRUE(testAddOrRemoveBaseHelper("q/r#", "file:/ex/x/y", "file:/ex/x/q/r#")); - ASSERT_TRUE(testAddOrRemoveBaseHelper("q/r#s/t", "file:/ex/x/y", "file:/ex/x/q/r#s/t")); - ASSERT_TRUE(testAddOrRemoveBaseHelper("ftp://ex/x/q/r", "file:/ex/x/y", "ftp://ex/x/q/r")); - ASSERT_TRUE(testAddOrRemoveBaseHelper("", "file:/ex/x/y", "file:/ex/x/y")); - ASSERT_TRUE(testAddOrRemoveBaseHelper("", "file:/ex/x/y/", "file:/ex/x/y/")); - ASSERT_TRUE(testAddOrRemoveBaseHelper("", "file:/ex/x/y/pdq", "file:/ex/x/y/pdq")); - ASSERT_TRUE(testAddOrRemoveBaseHelper("z/", "file:/ex/x/y/", "file:/ex/x/y/z/")); - ASSERT_TRUE(testAddOrRemoveBaseHelper("file://meetings.example.com/cal#m1", "file:/devel/WWW/2000/10/swap/test/reluri-1.n3", "file://meetings.example.com/cal#m1")); - ASSERT_TRUE(testAddOrRemoveBaseHelper("file://meetings.example.com/cal#m1", "file:/home/connolly/w3ccvs/WWW/2000/10/swap/test/reluri-1.n3", "file://meetings.example.com/cal#m1")); - ASSERT_TRUE(testAddOrRemoveBaseHelper("./#blort", "file:/some/dir/foo", "file:/some/dir/#blort")); - ASSERT_TRUE(testAddOrRemoveBaseHelper("./#", "file:/some/dir/foo", "file:/some/dir/#")); - - // Ryan Lee - ASSERT_TRUE(testAddOrRemoveBaseHelper("./", "http://example/x/abc.efg", "http://example/x/")); - - // Graham Klyne's tests - // http://www.ninebynine.org/Software/HaskellUtils/Network/UriTest.xls - // 01-31 are from Connelly's cases - - // 32-49 - ASSERT_TRUE(testAddOrRemoveBaseHelper("./q:r", "http://ex/x/y", "http://ex/x/q:r")); - ASSERT_TRUE(testAddOrRemoveBaseHelper("./p=q:r", "http://ex/x/y", "http://ex/x/p=q:r")); - ASSERT_TRUE(testAddOrRemoveBaseHelper("?pp/rr", "http://ex/x/y?pp/qq", "http://ex/x/y?pp/rr")); - ASSERT_TRUE(testAddOrRemoveBaseHelper("y/z", "http://ex/x/y?pp/qq", "http://ex/x/y/z")); - ASSERT_TRUE(testAddOrRemoveBaseHelper("local/qual@domain.org#frag", "mailto:local", "mailto:local/qual@domain.org#frag")); - ASSERT_TRUE(testAddOrRemoveBaseHelper("more/qual2@domain2.org#frag", "mailto:local/qual1@domain1.org", "mailto:local/more/qual2@domain2.org#frag")); - ASSERT_TRUE(testAddOrRemoveBaseHelper("y?q", "http://ex/x/y?q", "http://ex/x/y?q")); - ASSERT_TRUE(testAddOrRemoveBaseHelper("/x/y?q", "http://ex?p", "http://ex/x/y?q")); - ASSERT_TRUE(testAddOrRemoveBaseHelper("c/d", "foo:a/b", "foo:a/c/d")); - ASSERT_TRUE(testAddOrRemoveBaseHelper("/c/d", "foo:a/b", "foo:/c/d")); - ASSERT_TRUE(testAddOrRemoveBaseHelper("", "foo:a/b?c#d", "foo:a/b?c")); - ASSERT_TRUE(testAddOrRemoveBaseHelper("b/c", "foo:a", "foo:b/c")); - ASSERT_TRUE(testAddOrRemoveBaseHelper("../b/c", "foo:/a/y/z", "foo:/a/b/c")); - ASSERT_TRUE(testAddOrRemoveBaseHelper("./b/c", "foo:a", "foo:b/c")); - ASSERT_TRUE(testAddOrRemoveBaseHelper("/./b/c", "foo:a", "foo:/b/c")); - ASSERT_TRUE(testAddOrRemoveBaseHelper("../../d", "foo://a//b/c", "foo://a/d")); - ASSERT_TRUE(testAddOrRemoveBaseHelper(".", "foo:a", "foo:")); - ASSERT_TRUE(testAddOrRemoveBaseHelper("..", "foo:a", "foo:")); - - // 50-57 (cf. TimBL comments -- - // http://lists.w3.org/Archives/Public/uri/2003Feb/0028.html, - // http://lists.w3.org/Archives/Public/uri/2003Jan/0008.html) - ASSERT_TRUE(testAddOrRemoveBaseHelper("abc", "http://example/x/y%2Fz", "http://example/x/abc")); - ASSERT_TRUE(testAddOrRemoveBaseHelper("../../x%2Fabc", "http://example/a/x/y/z", "http://example/a/x%2Fabc")); - ASSERT_TRUE(testAddOrRemoveBaseHelper("../x%2Fabc", "http://example/a/x/y%2Fz", "http://example/a/x%2Fabc")); - ASSERT_TRUE(testAddOrRemoveBaseHelper("abc", "http://example/x%2Fy/z", "http://example/x%2Fy/abc")); - ASSERT_TRUE(testAddOrRemoveBaseHelper("q%3Ar", "http://ex/x/y", "http://ex/x/q%3Ar")); - ASSERT_TRUE(testAddOrRemoveBaseHelper("/x%2Fabc", "http://example/x/y%2Fz", "http://example/x%2Fabc")); - ASSERT_TRUE(testAddOrRemoveBaseHelper("/x%2Fabc", "http://example/x/y/z", "http://example/x%2Fabc")); - ASSERT_TRUE(testAddOrRemoveBaseHelper("/x%2Fabc", "http://example/x/y%2Fz", "http://example/x%2Fabc")); - - // 70-77 - ASSERT_TRUE(testAddOrRemoveBaseHelper("local2@domain2", "mailto:local1@domain1?query1", "mailto:local2@domain2")); - ASSERT_TRUE(testAddOrRemoveBaseHelper("local2@domain2?query2", "mailto:local1@domain1", "mailto:local2@domain2?query2")); - ASSERT_TRUE(testAddOrRemoveBaseHelper("local2@domain2?query2", "mailto:local1@domain1?query1", "mailto:local2@domain2?query2")); - ASSERT_TRUE(testAddOrRemoveBaseHelper("?query2", "mailto:local@domain?query1", "mailto:local@domain?query2")); - ASSERT_TRUE(testAddOrRemoveBaseHelper("local@domain?query2", "mailto:?query1", "mailto:local@domain?query2")); - ASSERT_TRUE(testAddOrRemoveBaseHelper("?query2", "mailto:local@domain?query1", "mailto:local@domain?query2")); - ASSERT_TRUE(testAddOrRemoveBaseHelper("http://example/a/b?c/../d", "foo:bar", "http://example/a/b?c/../d")); - ASSERT_TRUE(testAddOrRemoveBaseHelper("http://example/a/b#c/../d", "foo:bar", "http://example/a/b#c/../d")); - - // 82-88 - ASSERT_TRUE(testAddOrRemoveBaseHelper("http:this", "http://example.org/base/uri", "http:this")); - ASSERT_TRUE(testAddOrRemoveBaseHelper("http:this", "http:base", "http:this")); - // Whole in the URI spec, see http://lists.w3.org/Archives/Public/uri/2007Aug/0003.html - // ASSERT_TRUE(testAddOrRemoveBaseHelper(".//g", "f:/a", "f://g")); // ORIGINAL - ASSERT_TRUE(testAddOrRemoveBaseHelper(".//g", "f:/a", "f:/.//g")); // FIXED ONE - ASSERT_TRUE(testAddOrRemoveBaseHelper("b/c//d/e", "f://example.org/base/a", "f://example.org/base/b/c//d/e")); - ASSERT_TRUE(testAddOrRemoveBaseHelper("m2@example.ord/c2@example.org", "mid:m@example.ord/c@example.org", "mid:m@example.ord/m2@example.ord/c2@example.org")); - ASSERT_TRUE(testAddOrRemoveBaseHelper("mini1.xml", "file:///C:/DEV/Haskell/lib/HXmlToolbox-3.01/examples/", "file:///C:/DEV/Haskell/lib/HXmlToolbox-3.01/examples/mini1.xml")); - ASSERT_TRUE(testAddOrRemoveBaseHelper("../b/c", "foo:a/y/z", "foo:a/b/c")); + const char * const BASE_URI[] = {"http://a/b/c/d;p?q", "http://a/b/c/d;p?q=1/2", + "http://a/b/c/d;p=1/2?q", "fred:///s//a/b/c", + "http:///s//a/b/c"}; + + // ref, base, expected + + // http://lists.w3.org/Archives/Public/uri/2004Feb/0114.html + ASSERT_TRUE(testAddOrRemoveBaseHelper("../c", "foo:a/b", "foo:c")); + ASSERT_TRUE(testAddOrRemoveBaseHelper("foo:.", "foo:a", "foo:")); + ASSERT_TRUE(testAddOrRemoveBaseHelper("/foo/../../../bar", "zz:abc", "zz:/bar")); + ASSERT_TRUE(testAddOrRemoveBaseHelper("/foo/../bar", "zz:abc", "zz:/bar")); + ASSERT_TRUE(testAddOrRemoveBaseHelper("foo/../../../bar", "zz:abc", "zz:bar")); + ASSERT_TRUE(testAddOrRemoveBaseHelper("foo/../bar", "zz:abc", "zz:bar")); + ASSERT_TRUE(testAddOrRemoveBaseHelper("zz:.", "zz:abc", "zz:")); + ASSERT_TRUE(testAddOrRemoveBaseHelper("/.", BASE_URI[0], "http://a/")); + ASSERT_TRUE(testAddOrRemoveBaseHelper("/.foo", BASE_URI[0], "http://a/.foo")); + ASSERT_TRUE(testAddOrRemoveBaseHelper(".foo", BASE_URI[0], "http://a/b/c/.foo")); + + // http://gbiv.com/protocols/uri/test/rel_examples1.html + // examples from RFC 2396 + ASSERT_TRUE(testAddOrRemoveBaseHelper("g:h", BASE_URI[0], "g:h")); + ASSERT_TRUE(testAddOrRemoveBaseHelper("g", BASE_URI[0], "http://a/b/c/g")); + ASSERT_TRUE(testAddOrRemoveBaseHelper("./g", BASE_URI[0], "http://a/b/c/g")); + ASSERT_TRUE(testAddOrRemoveBaseHelper("g/", BASE_URI[0], "http://a/b/c/g/")); + ASSERT_TRUE(testAddOrRemoveBaseHelper("/g", BASE_URI[0], "http://a/g")); + ASSERT_TRUE(testAddOrRemoveBaseHelper("//g", BASE_URI[0], "http://g")); + + // changed with RFC 2396bis + ASSERT_TRUE(testAddOrRemoveBaseHelper("?y", BASE_URI[0], "http://a/b/c/d;p?y")); + ASSERT_TRUE(testAddOrRemoveBaseHelper("g?y", BASE_URI[0], "http://a/b/c/g?y")); + + // changed with RFC 2396bis + ASSERT_TRUE(testAddOrRemoveBaseHelper("#s", BASE_URI[0], "http://a/b/c/d;p?q#s")); + ASSERT_TRUE(testAddOrRemoveBaseHelper("g#s", BASE_URI[0], "http://a/b/c/g#s")); + ASSERT_TRUE(testAddOrRemoveBaseHelper("g?y#s", BASE_URI[0], "http://a/b/c/g?y#s")); + ASSERT_TRUE(testAddOrRemoveBaseHelper(";x", BASE_URI[0], "http://a/b/c/;x")); + ASSERT_TRUE(testAddOrRemoveBaseHelper("g;x", BASE_URI[0], "http://a/b/c/g;x")); + ASSERT_TRUE( + testAddOrRemoveBaseHelper("g;x?y#s", BASE_URI[0], "http://a/b/c/g;x?y#s")); + + // changed with RFC 2396bis + ASSERT_TRUE(testAddOrRemoveBaseHelper("", BASE_URI[0], "http://a/b/c/d;p?q")); + ASSERT_TRUE(testAddOrRemoveBaseHelper(".", BASE_URI[0], "http://a/b/c/")); + ASSERT_TRUE(testAddOrRemoveBaseHelper("./", BASE_URI[0], "http://a/b/c/")); + ASSERT_TRUE(testAddOrRemoveBaseHelper("..", BASE_URI[0], "http://a/b/")); + ASSERT_TRUE(testAddOrRemoveBaseHelper("../", BASE_URI[0], "http://a/b/")); + ASSERT_TRUE(testAddOrRemoveBaseHelper("../g", BASE_URI[0], "http://a/b/g")); + ASSERT_TRUE(testAddOrRemoveBaseHelper("../..", BASE_URI[0], "http://a/")); + ASSERT_TRUE(testAddOrRemoveBaseHelper("../../", BASE_URI[0], "http://a/")); + ASSERT_TRUE(testAddOrRemoveBaseHelper("../../g", BASE_URI[0], "http://a/g")); + ASSERT_TRUE(testAddOrRemoveBaseHelper("../../../g", BASE_URI[0], + "http://a/g")); // http://a/../g + ASSERT_TRUE(testAddOrRemoveBaseHelper("../../../../g", BASE_URI[0], + "http://a/g")); // http://a/../../g + + // changed with RFC 2396bis + ASSERT_TRUE(testAddOrRemoveBaseHelper("/./g", BASE_URI[0], "http://a/g")); + + // changed with RFC 2396bis + ASSERT_TRUE(testAddOrRemoveBaseHelper("/../g", BASE_URI[0], "http://a/g")); + ASSERT_TRUE(testAddOrRemoveBaseHelper("g.", BASE_URI[0], "http://a/b/c/g.")); + ASSERT_TRUE(testAddOrRemoveBaseHelper(".g", BASE_URI[0], "http://a/b/c/.g")); + ASSERT_TRUE(testAddOrRemoveBaseHelper("g..", BASE_URI[0], "http://a/b/c/g..")); + ASSERT_TRUE(testAddOrRemoveBaseHelper("..g", BASE_URI[0], "http://a/b/c/..g")); + ASSERT_TRUE(testAddOrRemoveBaseHelper("./../g", BASE_URI[0], "http://a/b/g")); + ASSERT_TRUE(testAddOrRemoveBaseHelper("./g/.", BASE_URI[0], "http://a/b/c/g/")); + ASSERT_TRUE(testAddOrRemoveBaseHelper("g/./h", BASE_URI[0], "http://a/b/c/g/h")); + ASSERT_TRUE(testAddOrRemoveBaseHelper("g/../h", BASE_URI[0], "http://a/b/c/h")); + ASSERT_TRUE( + testAddOrRemoveBaseHelper("g;x=1/./y", BASE_URI[0], "http://a/b/c/g;x=1/y")); + ASSERT_TRUE(testAddOrRemoveBaseHelper("g;x=1/../y", BASE_URI[0], "http://a/b/c/y")); + ASSERT_TRUE( + testAddOrRemoveBaseHelper("g?y/./x", BASE_URI[0], "http://a/b/c/g?y/./x")); + ASSERT_TRUE( + testAddOrRemoveBaseHelper("g?y/../x", BASE_URI[0], "http://a/b/c/g?y/../x")); + ASSERT_TRUE( + testAddOrRemoveBaseHelper("g#s/./x", BASE_URI[0], "http://a/b/c/g#s/./x")); + ASSERT_TRUE( + testAddOrRemoveBaseHelper("g#s/../x", BASE_URI[0], "http://a/b/c/g#s/../x")); + ASSERT_TRUE( + testAddOrRemoveBaseHelper("http:g", BASE_URI[0], "http:g")); // http://a/b/c/g + ASSERT_TRUE(testAddOrRemoveBaseHelper("http:", BASE_URI[0], "http:")); // BASE_URI[0] + + // not sure where this one originated + ASSERT_TRUE( + testAddOrRemoveBaseHelper("/a/b/c/./../../g", BASE_URI[0], "http://a/a/g")); + + // http://gbiv.com/protocols/uri/test/rel_examples2.html + // slashes in base URI's query args + ASSERT_TRUE(testAddOrRemoveBaseHelper("g", BASE_URI[1], "http://a/b/c/g")); + ASSERT_TRUE(testAddOrRemoveBaseHelper("./g", BASE_URI[1], "http://a/b/c/g")); + ASSERT_TRUE(testAddOrRemoveBaseHelper("g/", BASE_URI[1], "http://a/b/c/g/")); + ASSERT_TRUE(testAddOrRemoveBaseHelper("/g", BASE_URI[1], "http://a/g")); + ASSERT_TRUE(testAddOrRemoveBaseHelper("//g", BASE_URI[1], "http://g")); + + // changed in RFC 2396bis + // ASSERT_TRUE(testAddOrRemoveBaseHelper("?y", BASE_URI[1], "http://a/b/c/?y")); + ASSERT_TRUE(testAddOrRemoveBaseHelper("?y", BASE_URI[1], "http://a/b/c/d;p?y")); + ASSERT_TRUE(testAddOrRemoveBaseHelper("g?y", BASE_URI[1], "http://a/b/c/g?y")); + ASSERT_TRUE( + testAddOrRemoveBaseHelper("g?y/./x", BASE_URI[1], "http://a/b/c/g?y/./x")); + ASSERT_TRUE( + testAddOrRemoveBaseHelper("g?y/../x", BASE_URI[1], "http://a/b/c/g?y/../x")); + ASSERT_TRUE(testAddOrRemoveBaseHelper("g#s", BASE_URI[1], "http://a/b/c/g#s")); + ASSERT_TRUE( + testAddOrRemoveBaseHelper("g#s/./x", BASE_URI[1], "http://a/b/c/g#s/./x")); + ASSERT_TRUE( + testAddOrRemoveBaseHelper("g#s/../x", BASE_URI[1], "http://a/b/c/g#s/../x")); + ASSERT_TRUE(testAddOrRemoveBaseHelper("./", BASE_URI[1], "http://a/b/c/")); + ASSERT_TRUE(testAddOrRemoveBaseHelper("../", BASE_URI[1], "http://a/b/")); + ASSERT_TRUE(testAddOrRemoveBaseHelper("../g", BASE_URI[1], "http://a/b/g")); + ASSERT_TRUE(testAddOrRemoveBaseHelper("../../", BASE_URI[1], "http://a/")); + ASSERT_TRUE(testAddOrRemoveBaseHelper("../../g", BASE_URI[1], "http://a/g")); + + // http://gbiv.com/protocols/uri/test/rel_examples3.html + // slashes in path params + // all of these changed in RFC 2396bis + ASSERT_TRUE(testAddOrRemoveBaseHelper("g", BASE_URI[2], "http://a/b/c/d;p=1/g")); + ASSERT_TRUE(testAddOrRemoveBaseHelper("./g", BASE_URI[2], "http://a/b/c/d;p=1/g")); + ASSERT_TRUE(testAddOrRemoveBaseHelper("g/", BASE_URI[2], "http://a/b/c/d;p=1/g/")); + ASSERT_TRUE(testAddOrRemoveBaseHelper("g?y", BASE_URI[2], "http://a/b/c/d;p=1/g?y")); + ASSERT_TRUE(testAddOrRemoveBaseHelper(";x", BASE_URI[2], "http://a/b/c/d;p=1/;x")); + ASSERT_TRUE(testAddOrRemoveBaseHelper("g;x", BASE_URI[2], "http://a/b/c/d;p=1/g;x")); + ASSERT_TRUE(testAddOrRemoveBaseHelper("g;x=1/./y", BASE_URI[2], + "http://a/b/c/d;p=1/g;x=1/y")); + ASSERT_TRUE( + testAddOrRemoveBaseHelper("g;x=1/../y", BASE_URI[2], "http://a/b/c/d;p=1/y")); + ASSERT_TRUE(testAddOrRemoveBaseHelper("./", BASE_URI[2], "http://a/b/c/d;p=1/")); + ASSERT_TRUE(testAddOrRemoveBaseHelper("../", BASE_URI[2], "http://a/b/c/")); + ASSERT_TRUE(testAddOrRemoveBaseHelper("../g", BASE_URI[2], "http://a/b/c/g")); + ASSERT_TRUE(testAddOrRemoveBaseHelper("../../", BASE_URI[2], "http://a/b/")); + ASSERT_TRUE(testAddOrRemoveBaseHelper("../../g", BASE_URI[2], "http://a/b/g")); + + // http://gbiv.com/protocols/uri/test/rel_examples4.html + // double and triple slash, unknown scheme + ASSERT_TRUE(testAddOrRemoveBaseHelper("g:h", BASE_URI[3], "g:h")); + ASSERT_TRUE(testAddOrRemoveBaseHelper("g", BASE_URI[3], "fred:///s//a/b/g")); + ASSERT_TRUE(testAddOrRemoveBaseHelper("./g", BASE_URI[3], "fred:///s//a/b/g")); + ASSERT_TRUE(testAddOrRemoveBaseHelper("g/", BASE_URI[3], "fred:///s//a/b/g/")); + ASSERT_TRUE(testAddOrRemoveBaseHelper("/g", BASE_URI[3], + "fred:///g")); // may change to fred:///s//a/g + ASSERT_TRUE(testAddOrRemoveBaseHelper("//g", BASE_URI[3], + "fred://g")); // may change to fred:///s//g + ASSERT_TRUE(testAddOrRemoveBaseHelper("//g/x", BASE_URI[3], + "fred://g/x")); // may change to fred:///s//g/x + ASSERT_TRUE(testAddOrRemoveBaseHelper("///g", BASE_URI[3], "fred:///g")); + ASSERT_TRUE(testAddOrRemoveBaseHelper("./", BASE_URI[3], "fred:///s//a/b/")); + ASSERT_TRUE(testAddOrRemoveBaseHelper("../", BASE_URI[3], "fred:///s//a/")); + ASSERT_TRUE(testAddOrRemoveBaseHelper("../g", BASE_URI[3], "fred:///s//a/g")); + ASSERT_TRUE(testAddOrRemoveBaseHelper( + "../../", BASE_URI[3], "fred:///s//")); // may change to fred:///s//a/../ + ASSERT_TRUE(testAddOrRemoveBaseHelper( + "../../g", BASE_URI[3], "fred:///s//g")); // may change to fred:///s//a/../g + ASSERT_TRUE(testAddOrRemoveBaseHelper( + "../../../g", BASE_URI[3], "fred:///s/g")); // may change to fred:///s//a/../../g + ASSERT_TRUE( + testAddOrRemoveBaseHelper("../../../../g", BASE_URI[3], + "fred:///g")); // may change to fred:///s//a/../../../g + + // http://gbiv.com/protocols/uri/test/rel_examples5.html + // double and triple slash, well-known scheme + ASSERT_TRUE(testAddOrRemoveBaseHelper("g:h", BASE_URI[4], "g:h")); + ASSERT_TRUE(testAddOrRemoveBaseHelper("g", BASE_URI[4], "http:///s//a/b/g")); + ASSERT_TRUE(testAddOrRemoveBaseHelper("./g", BASE_URI[4], "http:///s//a/b/g")); + ASSERT_TRUE(testAddOrRemoveBaseHelper("g/", BASE_URI[4], "http:///s//a/b/g/")); + ASSERT_TRUE(testAddOrRemoveBaseHelper("/g", BASE_URI[4], + "http:///g")); // may change to http:///s//a/g + ASSERT_TRUE(testAddOrRemoveBaseHelper("//g", BASE_URI[4], + "http://g")); // may change to http:///s//g + ASSERT_TRUE(testAddOrRemoveBaseHelper("//g/x", BASE_URI[4], + "http://g/x")); // may change to http:///s//g/x + ASSERT_TRUE(testAddOrRemoveBaseHelper("///g", BASE_URI[4], "http:///g")); + ASSERT_TRUE(testAddOrRemoveBaseHelper("./", BASE_URI[4], "http:///s//a/b/")); + ASSERT_TRUE(testAddOrRemoveBaseHelper("../", BASE_URI[4], "http:///s//a/")); + ASSERT_TRUE(testAddOrRemoveBaseHelper("../g", BASE_URI[4], "http:///s//a/g")); + ASSERT_TRUE(testAddOrRemoveBaseHelper( + "../../", BASE_URI[4], "http:///s//")); // may change to http:///s//a/../ + ASSERT_TRUE(testAddOrRemoveBaseHelper( + "../../g", BASE_URI[4], "http:///s//g")); // may change to http:///s//a/../g + ASSERT_TRUE(testAddOrRemoveBaseHelper( + "../../../g", BASE_URI[4], "http:///s/g")); // may change to http:///s//a/../../g + ASSERT_TRUE( + testAddOrRemoveBaseHelper("../../../../g", BASE_URI[4], + "http:///g")); // may change to http:///s//a/../../../g + + // from Dan Connelly's tests in http://www.w3.org/2000/10/swap/uripath.py + ASSERT_TRUE(testAddOrRemoveBaseHelper("bar:abc", "foo:xyz", "bar:abc")); + ASSERT_TRUE(testAddOrRemoveBaseHelper("../abc", "http://example/x/y/z", + "http://example/x/abc")); + ASSERT_TRUE(testAddOrRemoveBaseHelper("http://example/x/abc", "http://example2/x/y/z", + "http://example/x/abc")); + ASSERT_TRUE(testAddOrRemoveBaseHelper("../r", "http://ex/x/y/z", "http://ex/x/r")); + ASSERT_TRUE(testAddOrRemoveBaseHelper("q/r", "http://ex/x/y", "http://ex/x/q/r")); + ASSERT_TRUE(testAddOrRemoveBaseHelper("q/r#s", "http://ex/x/y", "http://ex/x/q/r#s")); + ASSERT_TRUE( + testAddOrRemoveBaseHelper("q/r#s/t", "http://ex/x/y", "http://ex/x/q/r#s/t")); + ASSERT_TRUE( + testAddOrRemoveBaseHelper("ftp://ex/x/q/r", "http://ex/x/y", "ftp://ex/x/q/r")); + ASSERT_TRUE(testAddOrRemoveBaseHelper("", "http://ex/x/y", "http://ex/x/y")); + ASSERT_TRUE(testAddOrRemoveBaseHelper("", "http://ex/x/y/", "http://ex/x/y/")); + ASSERT_TRUE(testAddOrRemoveBaseHelper("", "http://ex/x/y/pdq", "http://ex/x/y/pdq")); + ASSERT_TRUE(testAddOrRemoveBaseHelper("z/", "http://ex/x/y/", "http://ex/x/y/z/")); + ASSERT_TRUE(testAddOrRemoveBaseHelper("#Animal", "file:/swap/test/animal.rdf", + "file:/swap/test/animal.rdf#Animal")); + ASSERT_TRUE(testAddOrRemoveBaseHelper("../abc", "file:/e/x/y/z", "file:/e/x/abc")); + ASSERT_TRUE(testAddOrRemoveBaseHelper("/example/x/abc", "file:/example2/x/y/z", + "file:/example/x/abc")); + ASSERT_TRUE(testAddOrRemoveBaseHelper("../r", "file:/ex/x/y/z", "file:/ex/x/r")); + ASSERT_TRUE(testAddOrRemoveBaseHelper("/r", "file:/ex/x/y/z", "file:/r")); + ASSERT_TRUE(testAddOrRemoveBaseHelper("q/r", "file:/ex/x/y", "file:/ex/x/q/r")); + ASSERT_TRUE(testAddOrRemoveBaseHelper("q/r#s", "file:/ex/x/y", "file:/ex/x/q/r#s")); + ASSERT_TRUE(testAddOrRemoveBaseHelper("q/r#", "file:/ex/x/y", "file:/ex/x/q/r#")); + ASSERT_TRUE( + testAddOrRemoveBaseHelper("q/r#s/t", "file:/ex/x/y", "file:/ex/x/q/r#s/t")); + ASSERT_TRUE( + testAddOrRemoveBaseHelper("ftp://ex/x/q/r", "file:/ex/x/y", "ftp://ex/x/q/r")); + ASSERT_TRUE(testAddOrRemoveBaseHelper("", "file:/ex/x/y", "file:/ex/x/y")); + ASSERT_TRUE(testAddOrRemoveBaseHelper("", "file:/ex/x/y/", "file:/ex/x/y/")); + ASSERT_TRUE(testAddOrRemoveBaseHelper("", "file:/ex/x/y/pdq", "file:/ex/x/y/pdq")); + ASSERT_TRUE(testAddOrRemoveBaseHelper("z/", "file:/ex/x/y/", "file:/ex/x/y/z/")); + ASSERT_TRUE(testAddOrRemoveBaseHelper("file://meetings.example.com/cal#m1", + "file:/devel/WWW/2000/10/swap/test/reluri-1.n3", + "file://meetings.example.com/cal#m1")); + ASSERT_TRUE(testAddOrRemoveBaseHelper( + "file://meetings.example.com/cal#m1", + "file:/home/connolly/w3ccvs/WWW/2000/10/swap/test/reluri-1.n3", + "file://meetings.example.com/cal#m1")); + ASSERT_TRUE(testAddOrRemoveBaseHelper("./#blort", "file:/some/dir/foo", + "file:/some/dir/#blort")); + ASSERT_TRUE( + testAddOrRemoveBaseHelper("./#", "file:/some/dir/foo", "file:/some/dir/#")); + + // Ryan Lee + ASSERT_TRUE( + testAddOrRemoveBaseHelper("./", "http://example/x/abc.efg", "http://example/x/")); + + // Graham Klyne's tests + // http://www.ninebynine.org/Software/HaskellUtils/Network/UriTest.xls + // 01-31 are from Connelly's cases + + // 32-49 + ASSERT_TRUE(testAddOrRemoveBaseHelper("./q:r", "http://ex/x/y", "http://ex/x/q:r")); + ASSERT_TRUE( + testAddOrRemoveBaseHelper("./p=q:r", "http://ex/x/y", "http://ex/x/p=q:r")); + ASSERT_TRUE(testAddOrRemoveBaseHelper("?pp/rr", "http://ex/x/y?pp/qq", + "http://ex/x/y?pp/rr")); + ASSERT_TRUE( + testAddOrRemoveBaseHelper("y/z", "http://ex/x/y?pp/qq", "http://ex/x/y/z")); + ASSERT_TRUE(testAddOrRemoveBaseHelper("local/qual@domain.org#frag", "mailto:local", + "mailto:local/qual@domain.org#frag")); + ASSERT_TRUE(testAddOrRemoveBaseHelper("more/qual2@domain2.org#frag", + "mailto:local/qual1@domain1.org", + "mailto:local/more/qual2@domain2.org#frag")); + ASSERT_TRUE(testAddOrRemoveBaseHelper("y?q", "http://ex/x/y?q", "http://ex/x/y?q")); + ASSERT_TRUE(testAddOrRemoveBaseHelper("/x/y?q", "http://ex?p", "http://ex/x/y?q")); + ASSERT_TRUE(testAddOrRemoveBaseHelper("c/d", "foo:a/b", "foo:a/c/d")); + ASSERT_TRUE(testAddOrRemoveBaseHelper("/c/d", "foo:a/b", "foo:/c/d")); + ASSERT_TRUE(testAddOrRemoveBaseHelper("", "foo:a/b?c#d", "foo:a/b?c")); + ASSERT_TRUE(testAddOrRemoveBaseHelper("b/c", "foo:a", "foo:b/c")); + ASSERT_TRUE(testAddOrRemoveBaseHelper("../b/c", "foo:/a/y/z", "foo:/a/b/c")); + ASSERT_TRUE(testAddOrRemoveBaseHelper("./b/c", "foo:a", "foo:b/c")); + ASSERT_TRUE(testAddOrRemoveBaseHelper("/./b/c", "foo:a", "foo:/b/c")); + ASSERT_TRUE(testAddOrRemoveBaseHelper("../../d", "foo://a//b/c", "foo://a/d")); + ASSERT_TRUE(testAddOrRemoveBaseHelper(".", "foo:a", "foo:")); + ASSERT_TRUE(testAddOrRemoveBaseHelper("..", "foo:a", "foo:")); + + // 50-57 (cf. TimBL comments -- + // http://lists.w3.org/Archives/Public/uri/2003Feb/0028.html, + // http://lists.w3.org/Archives/Public/uri/2003Jan/0008.html) + ASSERT_TRUE(testAddOrRemoveBaseHelper("abc", "http://example/x/y%2Fz", + "http://example/x/abc")); + ASSERT_TRUE(testAddOrRemoveBaseHelper("../../x%2Fabc", "http://example/a/x/y/z", + "http://example/a/x%2Fabc")); + ASSERT_TRUE(testAddOrRemoveBaseHelper("../x%2Fabc", "http://example/a/x/y%2Fz", + "http://example/a/x%2Fabc")); + ASSERT_TRUE(testAddOrRemoveBaseHelper("abc", "http://example/x%2Fy/z", + "http://example/x%2Fy/abc")); + ASSERT_TRUE(testAddOrRemoveBaseHelper("q%3Ar", "http://ex/x/y", "http://ex/x/q%3Ar")); + ASSERT_TRUE(testAddOrRemoveBaseHelper("/x%2Fabc", "http://example/x/y%2Fz", + "http://example/x%2Fabc")); + ASSERT_TRUE(testAddOrRemoveBaseHelper("/x%2Fabc", "http://example/x/y/z", + "http://example/x%2Fabc")); + ASSERT_TRUE(testAddOrRemoveBaseHelper("/x%2Fabc", "http://example/x/y%2Fz", + "http://example/x%2Fabc")); + + // 70-77 + ASSERT_TRUE(testAddOrRemoveBaseHelper( + "local2@domain2", "mailto:local1@domain1?query1", "mailto:local2@domain2")); + ASSERT_TRUE(testAddOrRemoveBaseHelper("local2@domain2?query2", + "mailto:local1@domain1", + "mailto:local2@domain2?query2")); + ASSERT_TRUE(testAddOrRemoveBaseHelper("local2@domain2?query2", + "mailto:local1@domain1?query1", + "mailto:local2@domain2?query2")); + ASSERT_TRUE(testAddOrRemoveBaseHelper("?query2", "mailto:local@domain?query1", + "mailto:local@domain?query2")); + ASSERT_TRUE(testAddOrRemoveBaseHelper("local@domain?query2", "mailto:?query1", + "mailto:local@domain?query2")); + ASSERT_TRUE(testAddOrRemoveBaseHelper("?query2", "mailto:local@domain?query1", + "mailto:local@domain?query2")); + ASSERT_TRUE(testAddOrRemoveBaseHelper("http://example/a/b?c/../d", "foo:bar", + "http://example/a/b?c/../d")); + ASSERT_TRUE(testAddOrRemoveBaseHelper("http://example/a/b#c/../d", "foo:bar", + "http://example/a/b#c/../d")); + + // 82-88 + ASSERT_TRUE(testAddOrRemoveBaseHelper("http:this", "http://example.org/base/uri", + "http:this")); + ASSERT_TRUE(testAddOrRemoveBaseHelper("http:this", "http:base", "http:this")); + // Whole in the URI spec, see + // http://lists.w3.org/Archives/Public/uri/2007Aug/0003.html + // ASSERT_TRUE(testAddOrRemoveBaseHelper(".//g", "f:/a", "f://g")); // ORIGINAL + ASSERT_TRUE(testAddOrRemoveBaseHelper(".//g", "f:/a", "f:/.//g")); // FIXED ONE + ASSERT_TRUE(testAddOrRemoveBaseHelper("b/c//d/e", "f://example.org/base/a", + "f://example.org/base/b/c//d/e")); + ASSERT_TRUE(testAddOrRemoveBaseHelper( + "m2@example.ord/c2@example.org", "mid:m@example.ord/c@example.org", + "mid:m@example.ord/m2@example.ord/c2@example.org")); + ASSERT_TRUE(testAddOrRemoveBaseHelper( + "mini1.xml", "file:///C:/DEV/Haskell/lib/HXmlToolbox-3.01/examples/", + "file:///C:/DEV/Haskell/lib/HXmlToolbox-3.01/examples/mini1.xml")); + ASSERT_TRUE(testAddOrRemoveBaseHelper("../b/c", "foo:a/y/z", "foo:a/b/c")); } - - TEST(FourSuite, RelativizeTestCases) { - const bool REMOVE_MODE = false; - const bool DOMAIN_ROOT_MODE = true; - - // to convert, base, exptected - - ASSERT_TRUE(testAddOrRemoveBaseHelper("s://ex/a/b/c", "s://ex/a/d", "b/c", REMOVE_MODE)); - ASSERT_TRUE(testAddOrRemoveBaseHelper("s://ex/b/b/c", "s://ex/a/d", "/b/b/c", REMOVE_MODE, DOMAIN_ROOT_MODE)); - ASSERT_TRUE(testAddOrRemoveBaseHelper("s://ex/a/b/c", "s://ex/a/b/", "c", REMOVE_MODE)); - ASSERT_TRUE(testAddOrRemoveBaseHelper("s://other.ex/a/b/", "s://ex/a/d", "//other.ex/a/b/", REMOVE_MODE)); - ASSERT_TRUE(testAddOrRemoveBaseHelper("s://ex/a/b/c", "s://other.ex/a/d", "//ex/a/b/c", REMOVE_MODE)); - ASSERT_TRUE(testAddOrRemoveBaseHelper("t://ex/a/b/c", "s://ex/a/d", "t://ex/a/b/c", REMOVE_MODE)); - ASSERT_TRUE(testAddOrRemoveBaseHelper("s://ex/a/b/c", "t://ex/a/d", "s://ex/a/b/c", REMOVE_MODE)); - ASSERT_TRUE(testAddOrRemoveBaseHelper("s://ex/a", "s://ex/b/c/d", "/a", REMOVE_MODE, DOMAIN_ROOT_MODE)); - ASSERT_TRUE(testAddOrRemoveBaseHelper("s://ex/b/c/d", "s://ex/a", "b/c/d", REMOVE_MODE)); - ASSERT_TRUE(testAddOrRemoveBaseHelper("s://ex/a/b/c?h", "s://ex/a/d?w", "b/c?h", REMOVE_MODE)); - ASSERT_TRUE(testAddOrRemoveBaseHelper("s://ex/a/b/c#h", "s://ex/a/d#w", "b/c#h", REMOVE_MODE)); - ASSERT_TRUE(testAddOrRemoveBaseHelper("s://ex/a/b/c?h#i", "s://ex/a/d?w#j", "b/c?h#i", REMOVE_MODE)); - ASSERT_TRUE(testAddOrRemoveBaseHelper("s://ex/a#i", "s://ex/a", "#i", REMOVE_MODE)); - ASSERT_TRUE(testAddOrRemoveBaseHelper("s://ex/a?i", "s://ex/a", "?i", REMOVE_MODE)); - - ASSERT_TRUE(testAddOrRemoveBaseHelper("s://ex/a/b/", "s://ex/a/b/", "", REMOVE_MODE)); - ASSERT_TRUE(testAddOrRemoveBaseHelper("s://ex/a/b", "s://ex/a/b", "", REMOVE_MODE)); - ASSERT_TRUE(testAddOrRemoveBaseHelper("s://ex/", "s://ex/", "", REMOVE_MODE)); - - ASSERT_TRUE(testAddOrRemoveBaseHelper("s://ex/a/b/c", "s://ex/a/d/c", "../b/c", REMOVE_MODE)); - ASSERT_TRUE(testAddOrRemoveBaseHelper("s://ex/a/b/c/", "s://ex/a/d/c", "../b/c/", REMOVE_MODE)); - ASSERT_TRUE(testAddOrRemoveBaseHelper("s://ex/a/b/c/d", "s://ex/a/d/c/d", "../../b/c/d", REMOVE_MODE)); - ASSERT_TRUE(testAddOrRemoveBaseHelper("s://ex/a/b/c", "s://ex/d/e/f", "/a/b/c", REMOVE_MODE, DOMAIN_ROOT_MODE)); - ASSERT_TRUE(testAddOrRemoveBaseHelper("s://ex/a/b/", "s://ex/a/c/d/e", "../../b/", REMOVE_MODE)); - - // Some tests to ensure that empty path segments don't cause problems. - ASSERT_TRUE(testAddOrRemoveBaseHelper("s://ex/a/b", "s://ex/a//b/c", "../../b", REMOVE_MODE)); - ASSERT_TRUE(testAddOrRemoveBaseHelper("s://ex/a///b", "s://ex/a/", ".///b", REMOVE_MODE)); - ASSERT_TRUE(testAddOrRemoveBaseHelper("s://ex/a/", "s://ex/a///b", "../../", REMOVE_MODE)); - ASSERT_TRUE(testAddOrRemoveBaseHelper("s://ex/a//b/c", "s://ex/a/b", ".//b/c", REMOVE_MODE)); + const bool REMOVE_MODE = false; + const bool DOMAIN_ROOT_MODE = true; + + // to convert, base, expected + + ASSERT_TRUE( + testAddOrRemoveBaseHelper("s://ex/a/b/c", "s://ex/a/d", "b/c", REMOVE_MODE)); + ASSERT_TRUE(testAddOrRemoveBaseHelper("s://ex/b/b/c", "s://ex/a/d", "/b/b/c", + REMOVE_MODE, DOMAIN_ROOT_MODE)); + ASSERT_TRUE( + testAddOrRemoveBaseHelper("s://ex/a/b/c", "s://ex/a/b/", "c", REMOVE_MODE)); + ASSERT_TRUE(testAddOrRemoveBaseHelper("s://other.ex/a/b/", "s://ex/a/d", + "//other.ex/a/b/", REMOVE_MODE)); + ASSERT_TRUE(testAddOrRemoveBaseHelper("s://ex/a/b/c", "s://other.ex/a/d", + "//ex/a/b/c", REMOVE_MODE)); + ASSERT_TRUE(testAddOrRemoveBaseHelper("t://ex/a/b/c", "s://ex/a/d", "t://ex/a/b/c", + REMOVE_MODE)); + ASSERT_TRUE(testAddOrRemoveBaseHelper("s://ex/a/b/c", "t://ex/a/d", "s://ex/a/b/c", + REMOVE_MODE)); + ASSERT_TRUE(testAddOrRemoveBaseHelper("s://ex/a", "s://ex/b/c/d", "/a", REMOVE_MODE, + DOMAIN_ROOT_MODE)); + ASSERT_TRUE( + testAddOrRemoveBaseHelper("s://ex/b/c/d", "s://ex/a", "b/c/d", REMOVE_MODE)); + ASSERT_TRUE(testAddOrRemoveBaseHelper("s://ex/a/b/c?h", "s://ex/a/d?w", "b/c?h", + REMOVE_MODE)); + ASSERT_TRUE(testAddOrRemoveBaseHelper("s://ex/a/b/c#h", "s://ex/a/d#w", "b/c#h", + REMOVE_MODE)); + ASSERT_TRUE(testAddOrRemoveBaseHelper("s://ex/a/b/c?h#i", "s://ex/a/d?w#j", "b/c?h#i", + REMOVE_MODE)); + ASSERT_TRUE(testAddOrRemoveBaseHelper("s://ex/a#i", "s://ex/a", "#i", REMOVE_MODE)); + ASSERT_TRUE(testAddOrRemoveBaseHelper("s://ex/a?i", "s://ex/a", "?i", REMOVE_MODE)); + + ASSERT_TRUE(testAddOrRemoveBaseHelper("s://ex/a/b/", "s://ex/a/b/", "", REMOVE_MODE)); + ASSERT_TRUE(testAddOrRemoveBaseHelper("s://ex/a/b", "s://ex/a/b", "", REMOVE_MODE)); + ASSERT_TRUE(testAddOrRemoveBaseHelper("s://ex/", "s://ex/", "", REMOVE_MODE)); + + ASSERT_TRUE( + testAddOrRemoveBaseHelper("s://ex/a/b/c", "s://ex/a/d/c", "../b/c", REMOVE_MODE)); + ASSERT_TRUE(testAddOrRemoveBaseHelper("s://ex/a/b/c/", "s://ex/a/d/c", "../b/c/", + REMOVE_MODE)); + ASSERT_TRUE(testAddOrRemoveBaseHelper("s://ex/a/b/c/d", "s://ex/a/d/c/d", + "../../b/c/d", REMOVE_MODE)); + ASSERT_TRUE(testAddOrRemoveBaseHelper("s://ex/a/b/c", "s://ex/d/e/f", "/a/b/c", + REMOVE_MODE, DOMAIN_ROOT_MODE)); + ASSERT_TRUE(testAddOrRemoveBaseHelper("s://ex/a/b/", "s://ex/a/c/d/e", "../../b/", + REMOVE_MODE)); + + // Some tests to ensure that empty path segments don't cause problems. + ASSERT_TRUE( + testAddOrRemoveBaseHelper("s://ex/a/b", "s://ex/a//b/c", "../../b", REMOVE_MODE)); + ASSERT_TRUE( + testAddOrRemoveBaseHelper("s://ex/a///b", "s://ex/a/", ".///b", REMOVE_MODE)); + ASSERT_TRUE( + testAddOrRemoveBaseHelper("s://ex/a/", "s://ex/a///b", "../../", REMOVE_MODE)); + ASSERT_TRUE( + testAddOrRemoveBaseHelper("s://ex/a//b/c", "s://ex/a/b", ".//b/c", REMOVE_MODE)); } - namespace { int testParseUri(const char * uriText, const char ** expectedErrorPos = NULL) { - UriParserStateA state; - UriUriA uri; - state.uri = &uri; - int res = uriParseUriA(&state, uriText); - if (expectedErrorPos != NULL) { - *expectedErrorPos = state.errorPos; - } - uriFreeUriMembersA(&uri); - return res; + UriParserStateA state; + UriUriA uri; + state.uri = &uri; + int res = uriParseUriA(&state, uriText); + if (expectedErrorPos != NULL) { + *expectedErrorPos = state.errorPos; + } + uriFreeUriMembersA(&uri); + return res; } - - bool testGoodUri(const char * uriText) { - return (testParseUri(uriText) == 0); + return (testParseUri(uriText) == 0); } - - bool testBadUri(const char * uriText, int expectedErrorOffset = -1) { - const char * errorPos = NULL; - const int ret = testParseUri(uriText, &errorPos); - return ((ret == URI_ERROR_SYNTAX) - && (errorPos != NULL) - && ( - (expectedErrorOffset == -1) - || (errorPos == (uriText + expectedErrorOffset)) - )); + const char * errorPos = NULL; + const int ret = testParseUri(uriText, &errorPos); + return ((ret == URI_ERROR_SYNTAX) && (errorPos != NULL) + && ((expectedErrorOffset == -1) + || (errorPos == (uriText + expectedErrorOffset)))); } } // namespace - - TEST(FourSuite, GoodUriReferences) { - ASSERT_TRUE(testGoodUri("file:///foo/bar")); - ASSERT_TRUE(testGoodUri("mailto:user@host?subject=blah")); - ASSERT_TRUE(testGoodUri("dav:")); // empty opaque part / rel-path allowed by RFC 2396bis - ASSERT_TRUE(testGoodUri("about:")); // empty opaque part / rel-path allowed by RFC 2396bis - - // the following test cases are from a Perl script by David A. Wheeler - // at http://www.dwheeler.com/secure-programs/url.pl - ASSERT_TRUE(testGoodUri("http://www.yahoo.com")); - ASSERT_TRUE(testGoodUri("http://www.yahoo.com/")); - ASSERT_TRUE(testGoodUri("http://1.2.3.4/")); - ASSERT_TRUE(testGoodUri("http://www.yahoo.com/stuff")); - ASSERT_TRUE(testGoodUri("http://www.yahoo.com/stuff/")); - ASSERT_TRUE(testGoodUri("http://www.yahoo.com/hello%20world/")); - ASSERT_TRUE(testGoodUri("http://www.yahoo.com?name=obi")); - ASSERT_TRUE(testGoodUri("http://www.yahoo.com?name=obi+wan&status=jedi")); - ASSERT_TRUE(testGoodUri("http://www.yahoo.com?onery")); - ASSERT_TRUE(testGoodUri("http://www.yahoo.com#bottom")); - ASSERT_TRUE(testGoodUri("http://www.yahoo.com/yelp.html#bottom")); - ASSERT_TRUE(testGoodUri("https://www.yahoo.com/")); - ASSERT_TRUE(testGoodUri("ftp://www.yahoo.com/")); - ASSERT_TRUE(testGoodUri("ftp://www.yahoo.com/hello")); - ASSERT_TRUE(testGoodUri("demo.txt")); - ASSERT_TRUE(testGoodUri("demo/hello.txt")); - ASSERT_TRUE(testGoodUri("demo/hello.txt?query=hello#fragment")); - ASSERT_TRUE(testGoodUri("/cgi-bin/query?query=hello#fragment")); - ASSERT_TRUE(testGoodUri("/demo.txt")); - ASSERT_TRUE(testGoodUri("/hello/demo.txt")); - ASSERT_TRUE(testGoodUri("hello/demo.txt")); - ASSERT_TRUE(testGoodUri("/")); - ASSERT_TRUE(testGoodUri("")); - ASSERT_TRUE(testGoodUri("#")); - ASSERT_TRUE(testGoodUri("#here")); - - // Wheeler's script says these are invalid, but they aren't - ASSERT_TRUE(testGoodUri("http://www.yahoo.com?name=%00%01")); - ASSERT_TRUE(testGoodUri("http://www.yaho%6f.com")); - ASSERT_TRUE(testGoodUri("http://www.yahoo.com/hello%00world/")); - ASSERT_TRUE(testGoodUri("http://www.yahoo.com/hello+world/")); - ASSERT_TRUE(testGoodUri("http://www.yahoo.com?name=obi&")); - ASSERT_TRUE(testGoodUri("http://www.yahoo.com?name=obi&type=")); - ASSERT_TRUE(testGoodUri("http://www.yahoo.com/yelp.html#")); - ASSERT_TRUE(testGoodUri("//")); - - // the following test cases are from a Haskell program by Graham Klyne - // at http://www.ninebynine.org/Software/HaskellUtils/Network/URITest.hs - ASSERT_TRUE(testGoodUri("http://example.org/aaa/bbb#ccc")); - ASSERT_TRUE(testGoodUri("mailto:local@domain.org")); - ASSERT_TRUE(testGoodUri("mailto:local@domain.org#frag")); - ASSERT_TRUE(testGoodUri("HTTP://EXAMPLE.ORG/AAA/BBB#CCC")); - ASSERT_TRUE(testGoodUri("//example.org/aaa/bbb#ccc")); - ASSERT_TRUE(testGoodUri("/aaa/bbb#ccc")); - ASSERT_TRUE(testGoodUri("bbb#ccc")); - ASSERT_TRUE(testGoodUri("#ccc")); - ASSERT_TRUE(testGoodUri("#")); - ASSERT_TRUE(testGoodUri("A'C")); - - // escapes - ASSERT_TRUE(testGoodUri("http://example.org/aaa%2fbbb#ccc")); - ASSERT_TRUE(testGoodUri("http://example.org/aaa%2Fbbb#ccc")); - ASSERT_TRUE(testGoodUri("%2F")); - ASSERT_TRUE(testGoodUri("aaa%2Fbbb")); - - // ports - ASSERT_TRUE(testGoodUri("http://example.org:80/aaa/bbb#ccc")); - ASSERT_TRUE(testGoodUri("http://example.org:/aaa/bbb#ccc")); - ASSERT_TRUE(testGoodUri("http://example.org./aaa/bbb#ccc")); - ASSERT_TRUE(testGoodUri("http://example.123./aaa/bbb#ccc")); - - // bare authority - ASSERT_TRUE(testGoodUri("http://example.org")); - - // IPv6 literals (from RFC2732): - ASSERT_TRUE(testGoodUri("http://[FEDC:BA98:7654:3210:FEDC:BA98:7654:3210]:80/index.html")); - ASSERT_TRUE(testGoodUri("http://[1080:0:0:0:8:800:200C:417A]/index.html")); - ASSERT_TRUE(testGoodUri("http://[3ffe:2a00:100:7031::1]")); - ASSERT_TRUE(testGoodUri("http://[1080::8:800:200C:417A]/foo")); - ASSERT_TRUE(testGoodUri("http://[::192.9.5.5]/ipng")); - ASSERT_TRUE(testGoodUri("http://[::FFFF:129.144.52.38]:80/index.html")); - ASSERT_TRUE(testGoodUri("http://[2010:836B:4179::836B:4179]")); - ASSERT_TRUE(testGoodUri("//[2010:836B:4179::836B:4179]")); - - // Random other things that crop up - ASSERT_TRUE(testGoodUri("http://example/Andrȷ")); - ASSERT_TRUE(testGoodUri("file:///C:/DEV/Haskell/lib/HXmlToolbox-3.01/examples/")); + ASSERT_TRUE(testGoodUri("file:///foo/bar")); + ASSERT_TRUE(testGoodUri("mailto:user@host?subject=blah")); + ASSERT_TRUE( + testGoodUri("dav:")); // empty opaque part / rel-path allowed by RFC 2396bis + ASSERT_TRUE( + testGoodUri("about:")); // empty opaque part / rel-path allowed by RFC 2396bis + + // the following test cases are from a Perl script by David A. Wheeler + // at http://www.dwheeler.com/secure-programs/url.pl + ASSERT_TRUE(testGoodUri("http://www.yahoo.com")); + ASSERT_TRUE(testGoodUri("http://www.yahoo.com/")); + ASSERT_TRUE(testGoodUri("http://1.2.3.4/")); + ASSERT_TRUE(testGoodUri("http://www.yahoo.com/stuff")); + ASSERT_TRUE(testGoodUri("http://www.yahoo.com/stuff/")); + ASSERT_TRUE(testGoodUri("http://www.yahoo.com/hello%20world/")); + ASSERT_TRUE(testGoodUri("http://www.yahoo.com?name=obi")); + ASSERT_TRUE(testGoodUri("http://www.yahoo.com?name=obi+wan&status=jedi")); + ASSERT_TRUE(testGoodUri("http://www.yahoo.com?onery")); + ASSERT_TRUE(testGoodUri("http://www.yahoo.com#bottom")); + ASSERT_TRUE(testGoodUri("http://www.yahoo.com/yelp.html#bottom")); + ASSERT_TRUE(testGoodUri("https://www.yahoo.com/")); + ASSERT_TRUE(testGoodUri("ftp://www.yahoo.com/")); + ASSERT_TRUE(testGoodUri("ftp://www.yahoo.com/hello")); + ASSERT_TRUE(testGoodUri("demo.txt")); + ASSERT_TRUE(testGoodUri("demo/hello.txt")); + ASSERT_TRUE(testGoodUri("demo/hello.txt?query=hello#fragment")); + ASSERT_TRUE(testGoodUri("/cgi-bin/query?query=hello#fragment")); + ASSERT_TRUE(testGoodUri("/demo.txt")); + ASSERT_TRUE(testGoodUri("/hello/demo.txt")); + ASSERT_TRUE(testGoodUri("hello/demo.txt")); + ASSERT_TRUE(testGoodUri("/")); + ASSERT_TRUE(testGoodUri("")); + ASSERT_TRUE(testGoodUri("#")); + ASSERT_TRUE(testGoodUri("#here")); + + // Wheeler's script says these are invalid, but they aren't + ASSERT_TRUE(testGoodUri("http://www.yahoo.com?name=%00%01")); + ASSERT_TRUE(testGoodUri("http://www.yaho%6f.com")); + ASSERT_TRUE(testGoodUri("http://www.yahoo.com/hello%00world/")); + ASSERT_TRUE(testGoodUri("http://www.yahoo.com/hello+world/")); + ASSERT_TRUE(testGoodUri("http://www.yahoo.com?name=obi&")); + ASSERT_TRUE(testGoodUri("http://www.yahoo.com?name=obi&type=")); + ASSERT_TRUE(testGoodUri("http://www.yahoo.com/yelp.html#")); + ASSERT_TRUE(testGoodUri("//")); + + // the following test cases are from a Haskell program by Graham Klyne + // at http://www.ninebynine.org/Software/HaskellUtils/Network/URITest.hs + ASSERT_TRUE(testGoodUri("http://example.org/aaa/bbb#ccc")); + ASSERT_TRUE(testGoodUri("mailto:local@domain.org")); + ASSERT_TRUE(testGoodUri("mailto:local@domain.org#frag")); + ASSERT_TRUE(testGoodUri("HTTP://EXAMPLE.ORG/AAA/BBB#CCC")); + ASSERT_TRUE(testGoodUri("//example.org/aaa/bbb#ccc")); + ASSERT_TRUE(testGoodUri("/aaa/bbb#ccc")); + ASSERT_TRUE(testGoodUri("bbb#ccc")); + ASSERT_TRUE(testGoodUri("#ccc")); + ASSERT_TRUE(testGoodUri("#")); + ASSERT_TRUE(testGoodUri("A'C")); + + // escapes + ASSERT_TRUE(testGoodUri("http://example.org/aaa%2fbbb#ccc")); + ASSERT_TRUE(testGoodUri("http://example.org/aaa%2Fbbb#ccc")); + ASSERT_TRUE(testGoodUri("%2F")); + ASSERT_TRUE(testGoodUri("aaa%2Fbbb")); + + // ports + ASSERT_TRUE(testGoodUri("http://example.org:80/aaa/bbb#ccc")); + ASSERT_TRUE(testGoodUri("http://example.org:/aaa/bbb#ccc")); + ASSERT_TRUE(testGoodUri("http://example.org./aaa/bbb#ccc")); + ASSERT_TRUE(testGoodUri("http://example.123./aaa/bbb#ccc")); + + // bare authority + ASSERT_TRUE(testGoodUri("http://example.org")); + + // IPv6 literals (from RFC2732): + ASSERT_TRUE( + testGoodUri("http://[FEDC:BA98:7654:3210:FEDC:BA98:7654:3210]:80/index.html")); + ASSERT_TRUE(testGoodUri("http://[1080:0:0:0:8:800:200C:417A]/index.html")); + ASSERT_TRUE(testGoodUri("http://[3ffe:2a00:100:7031::1]")); + ASSERT_TRUE(testGoodUri("http://[1080::8:800:200C:417A]/foo")); + ASSERT_TRUE(testGoodUri("http://[::192.9.5.5]/ipng")); + ASSERT_TRUE(testGoodUri("http://[::FFFF:129.144.52.38]:80/index.html")); + ASSERT_TRUE(testGoodUri("http://[2010:836B:4179::836B:4179]")); + ASSERT_TRUE(testGoodUri("//[2010:836B:4179::836B:4179]")); + + // Random other things that crop up + ASSERT_TRUE(testGoodUri("http://example/Andrȷ")); + ASSERT_TRUE(testGoodUri("file:///C:/DEV/Haskell/lib/HXmlToolbox-3.01/examples/")); } - - TEST(FourSuite, BadUriReferences) { - ASSERT_TRUE(testBadUri("beepbeep\x07\x07", 8)); - ASSERT_TRUE(testBadUri("\n", 0)); - ASSERT_TRUE(testBadUri("::", 0)); // not OK, per Roy Fielding on the W3C uri list on 2004-04-01 - - // the following test cases are from a Perl script by David A. Wheeler - // at http://www.dwheeler.com/secure-programs/url.pl - ASSERT_TRUE(testBadUri("http://www yahoo.com", 10)); - ASSERT_TRUE(testBadUri("http://www.yahoo.com/hello world/", 26)); - ASSERT_TRUE(testBadUri("http://www.yahoo.com/yelp.html#\"", 31)); - - // the following test cases are from a Haskell program by Graham Klyne - // at http://www.ninebynine.org/Software/HaskellUtils/Network/URITest.hs - ASSERT_TRUE(testBadUri("[2010:836B:4179::836B:4179]", 0)); - ASSERT_TRUE(testBadUri(" ", 0)); - ASSERT_TRUE(testBadUri("%", 1)); - ASSERT_TRUE(testBadUri("A%Z", 2)); - ASSERT_TRUE(testBadUri("%ZZ", 1)); - ASSERT_TRUE(testBadUri("%AZ", 2)); - ASSERT_TRUE(testBadUri("A C", 1)); - ASSERT_TRUE(testBadUri("A\\'C", 1)); // r"A\'C" - ASSERT_TRUE(testBadUri("A`C", 1)); - ASSERT_TRUE(testBadUri("A<C", 1)); - ASSERT_TRUE(testBadUri("A>C", 1)); - ASSERT_TRUE(testBadUri("A^C", 1)); - ASSERT_TRUE(testBadUri("A\\\\C", 1)); // r'A\\C' - ASSERT_TRUE(testBadUri("A{C", 1)); - ASSERT_TRUE(testBadUri("A|C", 1)); - ASSERT_TRUE(testBadUri("A}C", 1)); - ASSERT_TRUE(testBadUri("A[C", 1)); - ASSERT_TRUE(testBadUri("A]C", 1)); - ASSERT_TRUE(testBadUri("A[**]C", 1)); - ASSERT_TRUE(testBadUri("http://[xyz]/", 8)); - ASSERT_TRUE(testBadUri("http://]/", 7)); - ASSERT_TRUE(testBadUri("http://example.org/[2010:836B:4179::836B:4179]", 19)); - ASSERT_TRUE(testBadUri("http://example.org/abc#[2010:836B:4179::836B:4179]", 23)); - ASSERT_TRUE(testBadUri("http://example.org/xxx/[qwerty]#a[b]", 23)); - - // from a post to the W3C uri list on 2004-02-17 - // breaks at 22 instead of 17 because everything up to that point is a valid userinfo - ASSERT_TRUE(testBadUri("http://w3c.org:80path1/path2", 22)); + ASSERT_TRUE(testBadUri("beepbeep\x07\x07", 8)); + ASSERT_TRUE(testBadUri("\n", 0)); + ASSERT_TRUE(testBadUri( + "::", 0)); // not OK, per Roy Fielding on the W3C uri list on 2004-04-01 + + // the following test cases are from a Perl script by David A. Wheeler + // at http://www.dwheeler.com/secure-programs/url.pl + ASSERT_TRUE(testBadUri("http://www yahoo.com", 10)); + ASSERT_TRUE(testBadUri("http://www.yahoo.com/hello world/", 26)); + ASSERT_TRUE(testBadUri("http://www.yahoo.com/yelp.html#\"", 31)); + + // the following test cases are from a Haskell program by Graham Klyne + // at http://www.ninebynine.org/Software/HaskellUtils/Network/URITest.hs + ASSERT_TRUE(testBadUri("[2010:836B:4179::836B:4179]", 0)); + ASSERT_TRUE(testBadUri(" ", 0)); + ASSERT_TRUE(testBadUri("%", 1)); + ASSERT_TRUE(testBadUri("A%Z", 2)); + ASSERT_TRUE(testBadUri("%ZZ", 1)); + ASSERT_TRUE(testBadUri("%AZ", 2)); + ASSERT_TRUE(testBadUri("A C", 1)); + ASSERT_TRUE(testBadUri("A\\'C", 1)); // r"A\'C" + ASSERT_TRUE(testBadUri("A`C", 1)); + ASSERT_TRUE(testBadUri("A<C", 1)); + ASSERT_TRUE(testBadUri("A>C", 1)); + ASSERT_TRUE(testBadUri("A^C", 1)); + ASSERT_TRUE(testBadUri("A\\\\C", 1)); // r'A\\C' + ASSERT_TRUE(testBadUri("A{C", 1)); + ASSERT_TRUE(testBadUri("A|C", 1)); + ASSERT_TRUE(testBadUri("A}C", 1)); + ASSERT_TRUE(testBadUri("A[C", 1)); + ASSERT_TRUE(testBadUri("A]C", 1)); + ASSERT_TRUE(testBadUri("A[**]C", 1)); + ASSERT_TRUE(testBadUri("http://[xyz]/", 8)); + ASSERT_TRUE(testBadUri("http://]/", 7)); + ASSERT_TRUE(testBadUri("http://example.org/[2010:836B:4179::836B:4179]", 19)); + ASSERT_TRUE(testBadUri("http://example.org/abc#[2010:836B:4179::836B:4179]", 23)); + ASSERT_TRUE(testBadUri("http://example.org/xxx/[qwerty]#a[b]", 23)); + + // from a post to the W3C uri list on 2004-02-17 + // breaks at 22 instead of 17 because everything up to that point is a valid userinfo + ASSERT_TRUE(testBadUri("http://w3c.org:80path1/path2", 22)); } - - namespace { -bool normalizeAndCompare(const char * uriText, - const char * expectedNormalized) { - UriParserStateA stateA; - int res; - - UriUriA testUri; - stateA.uri = &testUri; - res = uriParseUriA(&stateA, uriText); - if (res != 0) { - uriFreeUriMembersA(&testUri); - return false; - } - - // Expected result - UriUriA expectedUri; - stateA.uri = &expectedUri; - res = uriParseUriA(&stateA, expectedNormalized); - if (res != 0) { - uriFreeUriMembersA(&testUri); - uriFreeUriMembersA(&expectedUri); - return false; - } - - res = uriNormalizeSyntaxA(&testUri); - if (res != 0) { - uriFreeUriMembersA(&testUri); - uriFreeUriMembersA(&expectedUri); - return false; - } - - const bool equalAfter = (URI_TRUE == uriEqualsUriA(&testUri, &expectedUri)); - uriFreeUriMembersA(&testUri); - uriFreeUriMembersA(&expectedUri); - return equalAfter; +bool normalizeAndCompare(const char * uriText, const char * expectedNormalized) { + UriParserStateA stateA; + int res; + + UriUriA testUri; + stateA.uri = &testUri; + res = uriParseUriA(&stateA, uriText); + if (res != 0) { + uriFreeUriMembersA(&testUri); + return false; + } + + // Expected result + UriUriA expectedUri; + stateA.uri = &expectedUri; + res = uriParseUriA(&stateA, expectedNormalized); + if (res != 0) { + uriFreeUriMembersA(&testUri); + uriFreeUriMembersA(&expectedUri); + return false; + } + + res = uriNormalizeSyntaxA(&testUri); + if (res != 0) { + uriFreeUriMembersA(&testUri); + uriFreeUriMembersA(&expectedUri); + return false; + } + + const bool equalAfter = (URI_TRUE == uriEqualsUriA(&testUri, &expectedUri)); + uriFreeUriMembersA(&testUri); + uriFreeUriMembersA(&expectedUri); + return equalAfter; } } // namespace - - TEST(FourSuite, CaseNormalizationTests) { - ASSERT_TRUE(normalizeAndCompare("HTTP://www.EXAMPLE.com/", "http://www.example.com/")); - ASSERT_TRUE(normalizeAndCompare("example://A/b/c/%7bfoo%7d", "example://a/b/c/%7Bfoo%7D")); + ASSERT_TRUE( + normalizeAndCompare("HTTP://www.EXAMPLE.com/", "http://www.example.com/")); + ASSERT_TRUE( + normalizeAndCompare("example://A/b/c/%7bfoo%7d", "example://a/b/c/%7Bfoo%7D")); } - - TEST(FourSuite, PctEncNormalizationTests) { - ASSERT_TRUE(normalizeAndCompare("http://host/%7Euser/x/y/z", "http://host/~user/x/y/z")); - ASSERT_TRUE(normalizeAndCompare("http://host/%7euser/x/y/z", "http://host/~user/x/y/z")); + ASSERT_TRUE( + normalizeAndCompare("http://host/%7Euser/x/y/z", "http://host/~user/x/y/z")); + ASSERT_TRUE( + normalizeAndCompare("http://host/%7euser/x/y/z", "http://host/~user/x/y/z")); } - - TEST(FourSuite, PathSegmentNormalizationTests) { - ASSERT_TRUE(normalizeAndCompare("/a/b/../../c", "/c")); - // ASSERT_TRUE(normalizeAndCompare("a/b/../../c", "a/b/../../c")); - // Fixed: - ASSERT_TRUE(normalizeAndCompare("a/b/../../c", "c")); - ASSERT_TRUE(normalizeAndCompare("/a/b/././c", "/a/b/c")); - // ASSERT_TRUE(normalizeAndCompare("a/b/././c", "a/b/././c")); - // Fixed: - ASSERT_TRUE(normalizeAndCompare("a/b/././c", "a/b/c")); - ASSERT_TRUE(normalizeAndCompare("/a/b/../c/././d", "/a/c/d")); - // ASSERT_TRUE(normalizeAndCompare("a/b/../c/././d", "a/b/../c/././d")); - // Fixed: - ASSERT_TRUE(normalizeAndCompare("a/b/../c/././d", "a/c/d")); + ASSERT_TRUE(normalizeAndCompare("/a/b/../../c", "/c")); + // ASSERT_TRUE(normalizeAndCompare("a/b/../../c", "a/b/../../c")); + // Fixed: + ASSERT_TRUE(normalizeAndCompare("a/b/../../c", "c")); + ASSERT_TRUE(normalizeAndCompare("/a/b/././c", "/a/b/c")); + // ASSERT_TRUE(normalizeAndCompare("a/b/././c", "a/b/././c")); + // Fixed: + ASSERT_TRUE(normalizeAndCompare("a/b/././c", "a/b/c")); + ASSERT_TRUE(normalizeAndCompare("/a/b/../c/././d", "/a/c/d")); + // ASSERT_TRUE(normalizeAndCompare("a/b/../c/././d", "a/b/../c/././d")); + // Fixed: + ASSERT_TRUE(normalizeAndCompare("a/b/../c/././d", "a/c/d")); } diff --git a/test/MemoryManagerSuite.cpp b/test/MemoryManagerSuite.cpp index e4af977..5b64e90 100644 --- a/test/MemoryManagerSuite.cpp +++ b/test/MemoryManagerSuite.cpp @@ -33,413 +33,437 @@ extern "C" { #include "../src/UriMemory.h" } - namespace { - - static void * failingMalloc(UriMemoryManager * memory, size_t size); static void * failingCalloc(UriMemoryManager * memory, size_t nmemb, size_t size); static void * failingRealloc(UriMemoryManager * memory, void * ptr, size_t size); -static void * failingReallocarray(UriMemoryManager * memory, void * ptr, size_t nmemb, size_t size); +static void * failingReallocarray(UriMemoryManager * memory, void * ptr, size_t nmemb, + size_t size); static void countingFree(UriMemoryManager * memory, void * ptr); - - class FailingMemoryManager { private: - UriMemoryManager memoryManager; - unsigned int callCountAlloc; - unsigned int callCountFree; - unsigned int failAllocAfterTimes; - - friend void * failingMalloc(UriMemoryManager * memory, size_t size); - friend void * failingCalloc(UriMemoryManager * memory, size_t nmemb, size_t size); - friend void * failingRealloc(UriMemoryManager * memory, void * ptr, size_t size); - friend void * failingReallocarray(UriMemoryManager * memory, void * ptr, size_t nmemb, size_t size); - friend void countingFree(UriMemoryManager * memory, void * ptr); + UriMemoryManager memoryManager; + unsigned int callCountAlloc; + unsigned int callCountFree; + unsigned int failAllocAfterTimes; + + friend void * failingMalloc(UriMemoryManager * memory, size_t size); + friend void * failingCalloc(UriMemoryManager * memory, size_t nmemb, size_t size); + friend void * failingRealloc(UriMemoryManager * memory, void * ptr, size_t size); + friend void * failingReallocarray(UriMemoryManager * memory, void * ptr, size_t nmemb, + size_t size); + friend void countingFree(UriMemoryManager * memory, void * ptr); public: - FailingMemoryManager(unsigned int failAllocAfterTimes = 0) - : callCountAlloc(0), callCountFree(0), - failAllocAfterTimes(failAllocAfterTimes) { - this->memoryManager.malloc = failingMalloc; - this->memoryManager.calloc = failingCalloc; - this->memoryManager.realloc = failingRealloc; - this->memoryManager.reallocarray = failingReallocarray; - this->memoryManager.free = countingFree; - this->memoryManager.userData = this; - } - - UriMemoryManager * operator&() { - return &(this->memoryManager); - } - - unsigned int getCallCountFree() const { - return this->callCountFree; - } + FailingMemoryManager(unsigned int failAllocAfterTimes = 0) + : callCountAlloc(0), callCountFree(0), failAllocAfterTimes(failAllocAfterTimes) { + this->memoryManager.malloc = failingMalloc; + this->memoryManager.calloc = failingCalloc; + this->memoryManager.realloc = failingRealloc; + this->memoryManager.reallocarray = failingReallocarray; + this->memoryManager.free = countingFree; + this->memoryManager.userData = this; + } + + UriMemoryManager * operator&() { + return &(this->memoryManager); + } + + unsigned int getCallCountAlloc() const { + return this->callCountAlloc; + } + + unsigned int getCallCountFree() const { + return this->callCountFree; + } }; - - static void * failingMalloc(UriMemoryManager * memory, size_t size) { - FailingMemoryManager * const fmm = static_cast<FailingMemoryManager *>(memory->userData); - fmm->callCountAlloc++; - if (fmm->callCountAlloc > fmm->failAllocAfterTimes) { - errno = ENOMEM; - return NULL; - } - return malloc(size); + FailingMemoryManager * const fmm = + static_cast<FailingMemoryManager *>(memory->userData); + fmm->callCountAlloc++; + if (fmm->callCountAlloc > fmm->failAllocAfterTimes) { + errno = ENOMEM; + return NULL; + } + return malloc(size); } - - static void * failingCalloc(UriMemoryManager * memory, size_t nmemb, size_t size) { - FailingMemoryManager * const fmm = static_cast<FailingMemoryManager *>(memory->userData); - fmm->callCountAlloc++; - if (fmm->callCountAlloc > fmm->failAllocAfterTimes) { - errno = ENOMEM; - return NULL; - } - return calloc(nmemb, size); + FailingMemoryManager * const fmm = + static_cast<FailingMemoryManager *>(memory->userData); + fmm->callCountAlloc++; + if (fmm->callCountAlloc > fmm->failAllocAfterTimes) { + errno = ENOMEM; + return NULL; + } + return calloc(nmemb, size); } - - static void * failingRealloc(UriMemoryManager * memory, void * ptr, size_t size) { - FailingMemoryManager * const fmm = static_cast<FailingMemoryManager *>(memory->userData); - fmm->callCountAlloc++; - if (fmm->callCountAlloc > fmm->failAllocAfterTimes) { - errno = ENOMEM; - return NULL; - } - return realloc(ptr, size); + FailingMemoryManager * const fmm = + static_cast<FailingMemoryManager *>(memory->userData); + fmm->callCountAlloc++; + if (fmm->callCountAlloc > fmm->failAllocAfterTimes) { + errno = ENOMEM; + return NULL; + } + return realloc(ptr, size); } - - -static void * failingReallocarray(UriMemoryManager * memory, void * ptr, size_t nmemb, size_t size) { - return uriEmulateReallocarray(memory, ptr, nmemb, size); +static void * failingReallocarray(UriMemoryManager * memory, void * ptr, size_t nmemb, + size_t size) { + return uriEmulateReallocarray(memory, ptr, nmemb, size); } - - static void countingFree(UriMemoryManager * memory, void * ptr) { - FailingMemoryManager * const fmm = static_cast<FailingMemoryManager *>(memory->userData); - fmm->callCountFree++; - return free(ptr); + FailingMemoryManager * const fmm = + static_cast<FailingMemoryManager *>(memory->userData); + fmm->callCountFree++; + return free(ptr); } - - static UriUriA parse(const char * sourceUriString) { - UriParserStateA state; - UriUriA uri; - state.uri = &uri; - assert(uriParseUriA(&state, sourceUriString) == URI_SUCCESS); - return uri; + UriParserStateA state; + UriUriA uri; + state.uri = &uri; + assert(uriParseUriA(&state, sourceUriString) == URI_SUCCESS); + return uri; } - - static UriQueryListA * parseQueryList(const char * queryString) { - UriQueryListA * queryList; - const char * const first = queryString; - const char * const afterLast = first + strlen(first); - assert(uriDissectQueryMallocA(&queryList, NULL, first, afterLast) - == URI_SUCCESS); - return queryList; + UriQueryListA * queryList; + const char * const first = queryString; + const char * const afterLast = first + strlen(first); + assert(uriDissectQueryMallocA(&queryList, NULL, first, afterLast) == URI_SUCCESS); + return queryList; } } // namespace - - TEST(MemoryManagerCompletenessSuite, AllFunctionMembersRequired) { - UriUriA uri = parse("whatever"); - UriMemoryManager memory; + UriUriA uri = parse("whatever"); + UriMemoryManager memory; - memcpy(&memory, &defaultMemoryManager, sizeof(UriMemoryManager)); - memory.malloc = NULL; - ASSERT_EQ(uriFreeUriMembersMmA(&uri, &memory), - URI_ERROR_MEMORY_MANAGER_INCOMPLETE); + memcpy(&memory, &defaultMemoryManager, sizeof(UriMemoryManager)); + memory.malloc = NULL; + ASSERT_EQ(uriFreeUriMembersMmA(&uri, &memory), URI_ERROR_MEMORY_MANAGER_INCOMPLETE); - memcpy(&memory, &defaultMemoryManager, sizeof(UriMemoryManager)); - memory.calloc = NULL; - ASSERT_EQ(uriFreeUriMembersMmA(&uri, &memory), - URI_ERROR_MEMORY_MANAGER_INCOMPLETE); + memcpy(&memory, &defaultMemoryManager, sizeof(UriMemoryManager)); + memory.calloc = NULL; + ASSERT_EQ(uriFreeUriMembersMmA(&uri, &memory), URI_ERROR_MEMORY_MANAGER_INCOMPLETE); - memcpy(&memory, &defaultMemoryManager, sizeof(UriMemoryManager)); - memory.realloc = NULL; - ASSERT_EQ(uriFreeUriMembersMmA(&uri, &memory), - URI_ERROR_MEMORY_MANAGER_INCOMPLETE); + memcpy(&memory, &defaultMemoryManager, sizeof(UriMemoryManager)); + memory.realloc = NULL; + ASSERT_EQ(uriFreeUriMembersMmA(&uri, &memory), URI_ERROR_MEMORY_MANAGER_INCOMPLETE); - memcpy(&memory, &defaultMemoryManager, sizeof(UriMemoryManager)); - memory.reallocarray = NULL; - ASSERT_EQ(uriFreeUriMembersMmA(&uri, &memory), - URI_ERROR_MEMORY_MANAGER_INCOMPLETE); + memcpy(&memory, &defaultMemoryManager, sizeof(UriMemoryManager)); + memory.reallocarray = NULL; + ASSERT_EQ(uriFreeUriMembersMmA(&uri, &memory), URI_ERROR_MEMORY_MANAGER_INCOMPLETE); - memcpy(&memory, &defaultMemoryManager, sizeof(UriMemoryManager)); - memory.free = NULL; - ASSERT_EQ(uriFreeUriMembersMmA(&uri, &memory), - URI_ERROR_MEMORY_MANAGER_INCOMPLETE); + memcpy(&memory, &defaultMemoryManager, sizeof(UriMemoryManager)); + memory.free = NULL; + ASSERT_EQ(uriFreeUriMembersMmA(&uri, &memory), URI_ERROR_MEMORY_MANAGER_INCOMPLETE); - memcpy(&memory, &defaultMemoryManager, sizeof(UriMemoryManager)); - ASSERT_EQ(uriFreeUriMembersMmA(&uri, &memory), URI_SUCCESS); + memcpy(&memory, &defaultMemoryManager, sizeof(UriMemoryManager)); + ASSERT_EQ(uriFreeUriMembersMmA(&uri, &memory), URI_SUCCESS); } +TEST(MemoryManagerCompletionSuite, MallocAndFreeRequired) { + UriMemoryManager memory; + UriMemoryManager backend; + memcpy(&backend, &defaultMemoryManager, sizeof(UriMemoryManager)); + backend.malloc = NULL; + ASSERT_EQ(uriCompleteMemoryManager(&memory, &backend), + URI_ERROR_MEMORY_MANAGER_INCOMPLETE); -TEST(MemoryManagerCompletenessSuite, MallocAndFreeRequiredOnly) { - UriMemoryManager memory; - UriMemoryManager backend; - - memcpy(&backend, &defaultMemoryManager, sizeof(UriMemoryManager)); - backend.malloc = NULL; - ASSERT_EQ(uriCompleteMemoryManager(&memory, &backend), - URI_ERROR_MEMORY_MANAGER_INCOMPLETE); - - memcpy(&backend, &defaultMemoryManager, sizeof(UriMemoryManager)); - backend.free = NULL; - ASSERT_EQ(uriCompleteMemoryManager(&memory, &backend), - URI_ERROR_MEMORY_MANAGER_INCOMPLETE); + memcpy(&backend, &defaultMemoryManager, sizeof(UriMemoryManager)); + backend.free = NULL; + ASSERT_EQ(uriCompleteMemoryManager(&memory, &backend), + URI_ERROR_MEMORY_MANAGER_INCOMPLETE); } - - TEST(MemoryManagerTestingSuite, DefaultMemoryManager) { - ASSERT_EQ(uriTestMemoryManager(&defaultMemoryManager), URI_SUCCESS); + ASSERT_EQ(uriTestMemoryManagerEx(&defaultMemoryManager, URI_TRUE), URI_SUCCESS); } +TEST(MemoryManagerCompletionSuite, MallocAndFreeSufficient) { + UriMemoryManager memory; + UriMemoryManager backend; + memset(&backend, 0, sizeof(UriMemoryManager)); + backend.malloc = defaultMemoryManager.malloc; + backend.free = defaultMemoryManager.free; -TEST(MemoryManagerTestingSuite, CompleteMemoryManager) { - UriMemoryManager memory; - UriMemoryManager backend; - - memset(&backend, 0, sizeof(UriMemoryManager)); - backend.malloc = defaultMemoryManager.malloc; - backend.free = defaultMemoryManager.free; - - ASSERT_EQ(uriCompleteMemoryManager(&memory, &backend), - URI_SUCCESS); + ASSERT_EQ(uriCompleteMemoryManager(&memory, &backend), URI_SUCCESS); - ASSERT_EQ(uriTestMemoryManager(&memory), URI_SUCCESS); + ASSERT_EQ(uriTestMemoryManagerEx(&memory, URI_TRUE), URI_SUCCESS); } - - TEST(MemoryManagerTestingSuite, EmulateCalloc) { - UriMemoryManager partialEmulationMemoryManager; - memcpy(&partialEmulationMemoryManager, &defaultMemoryManager, - sizeof(UriMemoryManager)); - partialEmulationMemoryManager.calloc = uriEmulateCalloc; + UriMemoryManager partialEmulationMemoryManager; + memcpy(&partialEmulationMemoryManager, &defaultMemoryManager, + sizeof(UriMemoryManager)); + partialEmulationMemoryManager.calloc = uriEmulateCalloc; - ASSERT_EQ(uriTestMemoryManager(&partialEmulationMemoryManager), - URI_SUCCESS); + ASSERT_EQ(uriTestMemoryManagerEx(&partialEmulationMemoryManager, URI_TRUE), + URI_SUCCESS); } - - TEST(MemoryManagerTestingSuite, EmulateReallocarray) { - UriMemoryManager partialEmulationMemoryManager; - memcpy(&partialEmulationMemoryManager, &defaultMemoryManager, - sizeof(UriMemoryManager)); - partialEmulationMemoryManager.reallocarray = uriEmulateReallocarray; + UriMemoryManager partialEmulationMemoryManager; + memcpy(&partialEmulationMemoryManager, &defaultMemoryManager, + sizeof(UriMemoryManager)); + partialEmulationMemoryManager.reallocarray = uriEmulateReallocarray; - ASSERT_EQ(uriTestMemoryManager(&partialEmulationMemoryManager), - URI_SUCCESS); + ASSERT_EQ(uriTestMemoryManagerEx(&partialEmulationMemoryManager, URI_TRUE), + URI_SUCCESS); } +TEST(MemoryManagerTestingOverflowDetectionSuite, EmulateCalloc) { + EXPECT_GT(2 * sizeof(size_t), sizeof(void *)); + errno = 0; + ASSERT_EQ(NULL, uriEmulateCalloc(&defaultMemoryManager, (size_t)-1, (size_t)-1)); + ASSERT_EQ(errno, ENOMEM); +} -TEST(MemoryManagerTestingOverflowDetectionSuite, EmulateCalloc) { - EXPECT_GT(2 * sizeof(size_t), sizeof(void *)); +TEST(MemoryManagerTestingOverflowDetectionSuite, EmulateReallocarray) { + EXPECT_GT(2 * sizeof(size_t), sizeof(void *)); - errno = 0; - ASSERT_EQ(NULL, uriEmulateCalloc( - &defaultMemoryManager, (size_t)-1, (size_t)-1)); - ASSERT_EQ(errno, ENOMEM); + errno = 0; + ASSERT_EQ(NULL, uriEmulateReallocarray(&defaultMemoryManager, NULL, (size_t)-1, + (size_t)-1)); + ASSERT_EQ(errno, ENOMEM); } +TEST(MemoryManagerTestingSuite, EmulateCallocAndReallocarray) { + UriMemoryManager partialEmulationMemoryManager; + memcpy(&partialEmulationMemoryManager, &defaultMemoryManager, + sizeof(UriMemoryManager)); + partialEmulationMemoryManager.calloc = uriEmulateCalloc; + partialEmulationMemoryManager.reallocarray = uriEmulateReallocarray; + ASSERT_EQ(uriTestMemoryManagerEx(&partialEmulationMemoryManager, URI_TRUE), + URI_SUCCESS); +} -TEST(MemoryManagerTestingOverflowDetectionSuite, EmulateReallocarray) { - EXPECT_GT(2 * sizeof(size_t), sizeof(void *)); +TEST(FailingMemoryManagerSuite, AddBaseUriExMm) { + UriUriA absoluteDest; + UriUriA relativeSource = parse("foo"); + UriUriA absoluteBase = parse("http://example.org/bar"); + const UriResolutionOptions options = URI_RESOLVE_STRICTLY; + FailingMemoryManager failingMemoryManager; - errno = 0; - ASSERT_EQ(NULL, uriEmulateReallocarray( - &defaultMemoryManager, NULL, (size_t)-1, (size_t)-1)); - ASSERT_EQ(errno, ENOMEM); + ASSERT_EQ(uriAddBaseUriExMmA(&absoluteDest, &relativeSource, &absoluteBase, options, + &failingMemoryManager), + URI_ERROR_MALLOC); + + uriFreeUriMembersA(&relativeSource); + uriFreeUriMembersA(&absoluteBase); } +TEST(FailingMemoryManagerSuite, ComposeQueryMallocExMm) { + char * dest = NULL; + UriQueryListA * const queryList = parseQueryList("k1=v1"); + UriBool spaceToPlus = URI_TRUE; // not of interest + UriBool normalizeBreaks = URI_TRUE; // not of interest + FailingMemoryManager failingMemoryManager; + ASSERT_EQ(uriComposeQueryMallocExMmA(&dest, queryList, spaceToPlus, normalizeBreaks, + &failingMemoryManager), + URI_ERROR_MALLOC); -TEST(MemoryManagerTestingSuite, EmulateCallocAndReallocarray) { - UriMemoryManager partialEmulationMemoryManager; - memcpy(&partialEmulationMemoryManager, &defaultMemoryManager, - sizeof(UriMemoryManager)); - partialEmulationMemoryManager.calloc = uriEmulateCalloc; - partialEmulationMemoryManager.reallocarray = uriEmulateReallocarray; + uriFreeQueryListA(queryList); +} - ASSERT_EQ(uriTestMemoryManager(&partialEmulationMemoryManager), - URI_SUCCESS); +TEST(FailingMemoryManagerSuite, DissectQueryMallocExMm) { + UriQueryListA * queryList; + int itemCount; + const char * const first = "k1=v1&k2=v2"; + const char * const afterLast = first + strlen(first); + const UriBool plusToSpace = URI_TRUE; // not of interest + const UriBreakConversion breakConversion = URI_BR_DONT_TOUCH; // not o. i. + FailingMemoryManager failingMemoryManager; + + ASSERT_EQ(uriDissectQueryMallocExMmA(&queryList, &itemCount, first, afterLast, + plusToSpace, breakConversion, + &failingMemoryManager), + URI_ERROR_MALLOC); } +TEST(FailingMemoryManagerSuite, FreeQueryListMm) { + UriQueryListA * const queryList = parseQueryList("k1=v1"); + FailingMemoryManager failingMemoryManager; + ASSERT_EQ(failingMemoryManager.getCallCountFree(), 0U); + uriFreeQueryListMmA(queryList, &failingMemoryManager); -TEST(FailingMemoryManagerSuite, AddBaseUriExMm) { - UriUriA absoluteDest; - UriUriA relativeSource = parse("foo"); - UriUriA absoluteBase = parse("http://example.org/bar"); - const UriResolutionOptions options = URI_RESOLVE_STRICTLY; - FailingMemoryManager failingMemoryManager; + ASSERT_GE(failingMemoryManager.getCallCountFree(), 1U); +} + +TEST(FailingMemoryManagerSuite, FreeUriMembersMm) { + UriUriA uri = parse("http://example.org/"); + FailingMemoryManager failingMemoryManager; + ASSERT_EQ(failingMemoryManager.getCallCountFree(), 0U); - ASSERT_EQ(uriAddBaseUriExMmA(&absoluteDest, &relativeSource, - &absoluteBase, options, &failingMemoryManager), - URI_ERROR_MALLOC); + uriFreeUriMembersMmA(&uri, &failingMemoryManager); - uriFreeUriMembersA(&relativeSource); - uriFreeUriMembersA(&absoluteBase); + ASSERT_GE(failingMemoryManager.getCallCountFree(), 1U); + uriFreeUriMembersA(&uri); } +TEST(FailingMemoryManagerSuite, IsWellFormedHostIp6Mm) { + FailingMemoryManager failingMemoryManager; + const char * const first = "::1"; + const char * const afterLast = first + strlen(first); + EXPECT_EQ(failingMemoryManager.getCallCountAlloc(), 0U); + EXPECT_EQ(uriIsWellFormedHostIp6MmA(first, afterLast, &failingMemoryManager), + URI_ERROR_MALLOC); -TEST(FailingMemoryManagerSuite, ComposeQueryMallocExMm) { - char * dest = NULL; - UriQueryListA * const queryList = parseQueryList("k1=v1"); - UriBool spaceToPlus = URI_TRUE; // not of interest - UriBool normalizeBreaks = URI_TRUE; // not of interest - FailingMemoryManager failingMemoryManager; + EXPECT_EQ(failingMemoryManager.getCallCountAlloc(), 1U); +} + +TEST(FailingMemoryManagerSuite, IsWellFormedHostIpFutureMm) { + FailingMemoryManager failingMemoryManager; + const char * const first = "v7.host"; + const char * const afterLast = first + strlen(first); + EXPECT_EQ(failingMemoryManager.getCallCountAlloc(), 0U); - ASSERT_EQ(uriComposeQueryMallocExMmA(&dest, queryList, - spaceToPlus, normalizeBreaks, &failingMemoryManager), - URI_ERROR_MALLOC); + EXPECT_EQ(uriIsWellFormedHostIpFutureMmA(first, afterLast, &failingMemoryManager), + URI_ERROR_MALLOC); - uriFreeQueryListA(queryList); + EXPECT_EQ(failingMemoryManager.getCallCountAlloc(), 1U); } +TEST(FailingMemoryManagerSuite, SetPortTextMm) { + UriUriA uri = parse("https://host/"); + FailingMemoryManager failingMemoryManager; + const char * const first = "443"; + const char * const afterLast = first + strlen(first); + ASSERT_EQ(failingMemoryManager.getCallCountAlloc(), 0U); + ASSERT_EQ(uriSetPortTextMmA(&uri, first, afterLast, &failingMemoryManager), + URI_ERROR_MALLOC); -TEST(FailingMemoryManagerSuite, DissectQueryMallocExMm) { - UriQueryListA * queryList; - int itemCount; - const char * const first = "k1=v1&k2=v2"; - const char * const afterLast = first + strlen(first); - const UriBool plusToSpace = URI_TRUE; // not of interest - const UriBreakConversion breakConversion = URI_BR_DONT_TOUCH; // not o. i. - FailingMemoryManager failingMemoryManager; + ASSERT_EQ(failingMemoryManager.getCallCountAlloc(), 1U); - ASSERT_EQ(uriDissectQueryMallocExMmA(&queryList, &itemCount, - first, afterLast, plusToSpace, breakConversion, - &failingMemoryManager), - URI_ERROR_MALLOC); + uriFreeUriMembersA(&uri); } +TEST(FailingMemoryManagerSuite, SetQueryMm) { + UriUriA uri = parse("scheme://host/"); + FailingMemoryManager failingMemoryManager; + const char * const first = "k1=v1"; + const char * const afterLast = first + strlen(first); + ASSERT_EQ(failingMemoryManager.getCallCountAlloc(), 0U); + ASSERT_EQ(uriSetQueryMmA(&uri, first, afterLast, &failingMemoryManager), + URI_ERROR_MALLOC); -TEST(FailingMemoryManagerSuite, FreeQueryListMm) { - UriQueryListA * const queryList = parseQueryList("k1=v1"); - FailingMemoryManager failingMemoryManager; - ASSERT_EQ(failingMemoryManager.getCallCountFree(), 0U); - - uriFreeQueryListMmA(queryList, &failingMemoryManager); + ASSERT_EQ(failingMemoryManager.getCallCountAlloc(), 1U); - ASSERT_GE(failingMemoryManager.getCallCountFree(), 1U); + uriFreeUriMembersA(&uri); } +TEST(FailingMemoryManagerSuite, SetUserInfoMm) { + UriUriA uri = parse("scheme://host/"); + FailingMemoryManager failingMemoryManager; + const char * const first = "user:password"; + const char * const afterLast = first + strlen(first); + ASSERT_EQ(failingMemoryManager.getCallCountAlloc(), 0U); + ASSERT_EQ(uriSetUserInfoMmA(&uri, first, afterLast, &failingMemoryManager), + URI_ERROR_MALLOC); -TEST(FailingMemoryManagerSuite, FreeUriMembersMm) { - UriUriA uri = parse("http://example.org/"); - FailingMemoryManager failingMemoryManager; - ASSERT_EQ(failingMemoryManager.getCallCountFree(), 0U); - - uriFreeUriMembersMmA(&uri, &failingMemoryManager); + ASSERT_EQ(failingMemoryManager.getCallCountAlloc(), 1U); - ASSERT_GE(failingMemoryManager.getCallCountFree(), 1U); - uriFreeUriMembersA(&uri); + uriFreeUriMembersA(&uri); } namespace { - void testNormalizeSyntaxWithFailingMallocCallsFreeTimes(const char * uriString, - unsigned int mask, - unsigned int failAllocAfterTimes = 0, - unsigned int expectedCallCountFree = 0) { - UriUriA uri = parse(uriString); - FailingMemoryManager failingMemoryManager(failAllocAfterTimes); +void testNormalizeSyntaxWithFailingMallocCallsFreeTimes( + const char * uriString, unsigned int mask, unsigned int failAllocAfterTimes = 0, + unsigned int expectedCallCountFree = 0) { + UriUriA uri = parse(uriString); + FailingMemoryManager failingMemoryManager(failAllocAfterTimes); - ASSERT_EQ(uriNormalizeSyntaxExMmA(&uri, mask, &failingMemoryManager), - URI_ERROR_MALLOC); + ASSERT_EQ(uriNormalizeSyntaxExMmA(&uri, mask, &failingMemoryManager), + URI_ERROR_MALLOC); - EXPECT_EQ(failingMemoryManager.getCallCountFree(), expectedCallCountFree); + EXPECT_EQ(failingMemoryManager.getCallCountFree(), expectedCallCountFree); - uriFreeUriMembersA(&uri); - } + uriFreeUriMembersA(&uri); +} } // namespace TEST(FailingMemoryManagerSuite, NormalizeSyntaxExMmScheme) { - testNormalizeSyntaxWithFailingMallocCallsFreeTimes("hTTp://example.org/path", URI_NORMALIZE_SCHEME); + testNormalizeSyntaxWithFailingMallocCallsFreeTimes("hTTp://example.org/path", + URI_NORMALIZE_SCHEME); } TEST(FailingMemoryManagerSuite, NormalizeSyntaxExMmEmptyUserInfo) { - testNormalizeSyntaxWithFailingMallocCallsFreeTimes("//@:123", URI_NORMALIZE_USER_INFO); + testNormalizeSyntaxWithFailingMallocCallsFreeTimes("//@:123", + URI_NORMALIZE_USER_INFO); } TEST(FailingMemoryManagerSuite, NormalizeSyntaxExMmEmptyHostRegname) { - testNormalizeSyntaxWithFailingMallocCallsFreeTimes("//:123", URI_NORMALIZE_HOST); + testNormalizeSyntaxWithFailingMallocCallsFreeTimes("//:123", URI_NORMALIZE_HOST); } TEST(FailingMemoryManagerSuite, NormalizeSyntaxExMmEmptyQuery) { - testNormalizeSyntaxWithFailingMallocCallsFreeTimes("//:123?", URI_NORMALIZE_QUERY); + testNormalizeSyntaxWithFailingMallocCallsFreeTimes("//:123?", URI_NORMALIZE_QUERY); } TEST(FailingMemoryManagerSuite, NormalizeSyntaxExMmEmptyFragment) { - testNormalizeSyntaxWithFailingMallocCallsFreeTimes("//:123#", URI_NORMALIZE_FRAGMENT); + testNormalizeSyntaxWithFailingMallocCallsFreeTimes("//:123#", URI_NORMALIZE_FRAGMENT); } TEST(FailingMemoryManagerSuite, NormalizeSyntaxExMmHostTextIp4) { // issue #121 - testNormalizeSyntaxWithFailingMallocCallsFreeTimes("//192.0.2.0:123" /* RFC 5737 */, URI_NORMALIZE_HOST, 1, 1); + testNormalizeSyntaxWithFailingMallocCallsFreeTimes("//192.0.2.0:123" /* RFC 5737 */, + URI_NORMALIZE_HOST, 1, 1); } TEST(FailingMemoryManagerSuite, NormalizeSyntaxExMmHostTextIp6) { // issue #121 - testNormalizeSyntaxWithFailingMallocCallsFreeTimes("//[2001:db8::]:123" /* RFC 3849 */, URI_NORMALIZE_HOST, 1, 1); + testNormalizeSyntaxWithFailingMallocCallsFreeTimes( + "//[2001:db8::]:123" /* RFC 3849 */, URI_NORMALIZE_HOST, 1, 1); } TEST(FailingMemoryManagerSuite, NormalizeSyntaxExMmHostTextRegname) { // issue #121 - testNormalizeSyntaxWithFailingMallocCallsFreeTimes("//host123.test:123" /* RFC 6761 */, URI_NORMALIZE_HOST, 1, 1); + testNormalizeSyntaxWithFailingMallocCallsFreeTimes( + "//host123.test:123" /* RFC 6761 */, URI_NORMALIZE_HOST, 1, 1); } TEST(FailingMemoryManagerSuite, NormalizeSyntaxExMmHostTextFuture) { // issue #121 - testNormalizeSyntaxWithFailingMallocCallsFreeTimes("//[v7.X]:123" /* arbitrary IPvFuture */, URI_NORMALIZE_HOST, 1, 1); + testNormalizeSyntaxWithFailingMallocCallsFreeTimes( + "//[v7.X]:123" /* arbitrary IPvFuture */, URI_NORMALIZE_HOST, 1, 1); } - - TEST(FailingMemoryManagerSuite, ParseSingleUriExMm) { - UriUriA uri; - const char * const first = "k1=v1&k2=v2"; - const char * const afterLast = first + strlen(first); - FailingMemoryManager failingMemoryManager; + UriUriA uri; + const char * const first = "k1=v1&k2=v2"; + const char * const afterLast = first + strlen(first); + FailingMemoryManager failingMemoryManager; - ASSERT_EQ(uriParseSingleUriExMmA(&uri, first, afterLast, NULL, - &failingMemoryManager), - URI_ERROR_MALLOC); + ASSERT_EQ(uriParseSingleUriExMmA(&uri, first, afterLast, NULL, &failingMemoryManager), + URI_ERROR_MALLOC); } - - TEST(FailingMemoryManagerSuite, RemoveBaseUriMm) { - UriUriA dest; - UriUriA absoluteSource = parse("http://example.org/a/b/c/"); - UriUriA absoluteBase = parse("http://example.org/a/"); - const UriBool domainRootMode = URI_TRUE; // not of interest - FailingMemoryManager failingMemoryManager; - - ASSERT_EQ(uriRemoveBaseUriMmA(&dest, &absoluteSource, &absoluteBase, - domainRootMode, &failingMemoryManager), - URI_ERROR_MALLOC); - - uriFreeUriMembersA(&absoluteSource); - uriFreeUriMembersA(&absoluteBase); + UriUriA dest; + UriUriA absoluteSource = parse("http://example.org/a/b/c/"); + UriUriA absoluteBase = parse("http://example.org/a/"); + const UriBool domainRootMode = URI_TRUE; // not of interest + FailingMemoryManager failingMemoryManager; + + ASSERT_EQ(uriRemoveBaseUriMmA(&dest, &absoluteSource, &absoluteBase, domainRootMode, + &failingMemoryManager), + URI_ERROR_MALLOC); + + uriFreeUriMembersA(&absoluteSource); + uriFreeUriMembersA(&absoluteBase); } diff --git a/test/SetFragment.cpp b/test/SetFragment.cpp new file mode 100644 index 0000000..71e5343 --- /dev/null +++ b/test/SetFragment.cpp @@ -0,0 +1,230 @@ +/* + * uriparser - RFC 3986 URI parsing library + * + * Copyright (C) 2025, Sebastian Pipping <sebastian@pipping.org> + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library 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 + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#undef NDEBUG // because we rely on assert(3) further down + +#include <cassert> + +#include <gtest/gtest.h> + +#include <uriparser/Uri.h> + +namespace { + +static void testIsWellFormedFragment(const char * candidate, bool expectedWellFormed) { + const char * const first = candidate; + const char * const afterLast = + (candidate == NULL) ? NULL : (candidate + strlen(candidate)); + + const UriBool actualWellFormed = uriIsWellFormedFragmentA(first, afterLast); + + ASSERT_EQ(actualWellFormed, expectedWellFormed); +} + +static UriUriA parseWellFormedUri(const char * text) { + UriUriA uri; + const int error = uriParseSingleUriA(&uri, text, NULL); + // NOTE: we cannot use ASSERT_EQ here because of the outer non-void return type + assert(error == URI_SUCCESS); + return uri; +} + +static void assertUriEqual(const UriUriA * uri, const char * expected) { + int charsRequired = -1; + ASSERT_EQ(uriToStringCharsRequiredA(uri, &charsRequired), URI_SUCCESS); + ASSERT_TRUE(charsRequired >= 0); + + char * const buffer = (char *)malloc(charsRequired + 1); + ASSERT_TRUE(buffer != NULL); + + ASSERT_EQ(uriToStringA(buffer, uri, charsRequired + 1, NULL), URI_SUCCESS); + + EXPECT_STREQ(buffer, expected); + + free(buffer); +} + +} // namespace + +TEST(IsWellFormedFragment, Null) { + testIsWellFormedFragment(NULL, false); +} + +TEST(IsWellFormedFragment, Empty) { + testIsWellFormedFragment("", true); +} + +TEST(IsWellFormedFragment, AllowedCharacters) { + // The related grammar subset is this: + // + // fragment = *( pchar / "/" / "?" ) + // pchar = unreserved / pct-encoded / sub-delims / ":" / "@" + // unreserved = ALPHA / DIGIT / "-" / "." / "_" / "~" + // pct-encoded = "%" HEXDIG HEXDIG + // sub-delims = "!" / "$" / "&" / "'" / "(" / ")" + // / "*" / "+" / "," / ";" / "=" + // + // NOTE: Percent encoding has dedicated tests further down + testIsWellFormedFragment("0123456789" + "ABCDEF" + "abcdef" + "gGhHiIjJkKlLmMnNoOpPqQrRsStTuUvVwWxXyYzZ" + "-._~" + "!$&'()*+,;=" + ":@" + "/?", + true); +} + +TEST(IsWellFormedFragment, ForbiddenCharacters) { + testIsWellFormedFragment(" ", false); +} + +TEST(IsWellFormedFragment, PercentEncodingWellFormed) { + testIsWellFormedFragment("%" + "aa" + "%" + "AA", + true); +} + +TEST(IsWellFormedFragment, PercentEncodingMalformedCutOff1) { + testIsWellFormedFragment("%", false); +} + +TEST(IsWellFormedFragment, PercentEncodingMalformedCutOff2) { + testIsWellFormedFragment("%" + "a", + false); +} + +TEST(IsWellFormedFragment, PercentEncodingMalformedForbiddenCharacter1) { + testIsWellFormedFragment("%" + "ga", + false); +} + +TEST(IsWellFormedFragment, PercentEncodingMalformedForbiddenCharacter2) { + testIsWellFormedFragment("%" + "ag", + false); +} + +TEST(SetFragment, NullUriOnly) { + UriUriA * const uri = NULL; + const char * const first = "toc"; + const char * const afterLast = first + strlen(first); + ASSERT_EQ(uriSetFragmentA(uri, first, afterLast), URI_ERROR_NULL); +} + +TEST(SetFragment, NullFirstOnly) { + UriUriA uri = {}; + const char * const fragment = "toc"; + const char * const first = NULL; + const char * const afterLast = fragment + strlen(fragment); + ASSERT_EQ(uriSetFragmentA(&uri, first, afterLast), URI_ERROR_NULL); +} + +TEST(SetFragment, NullAfterLastOnly) { + UriUriA uri = {}; + const char * const first = "toc"; + const char * const afterLast = NULL; + ASSERT_EQ(uriSetFragmentA(&uri, first, afterLast), URI_ERROR_NULL); +} + +TEST(SetFragment, NullValueLeavesOwnerAtFalse) { + UriUriA uri = parseWellFormedUri("scheme://host/#fragment"); + EXPECT_EQ(uri.owner, URI_FALSE); // self-test + + EXPECT_EQ(uriSetFragmentA(&uri, NULL, NULL), URI_SUCCESS); + + EXPECT_EQ(uri.owner, URI_FALSE); // i.e. still false + + uriFreeUriMembersA(&uri); +} + +TEST(SetFragment, NonNullValueMakesOwner) { + UriUriA uri = parseWellFormedUri("scheme://host/#old"); + const char * const first = "new"; + const char * const afterLast = first + strlen(first); + EXPECT_EQ(uri.owner, URI_FALSE); // self-test + + EXPECT_EQ(uriSetFragmentA(&uri, first, afterLast), URI_SUCCESS); + + EXPECT_EQ(uri.owner, URI_TRUE); // i.e. now owned + + uriFreeUriMembersA(&uri); +} + +TEST(SetFragment, NullValueApplied) { + UriUriA uri = parseWellFormedUri("scheme://host/#fragment"); + + EXPECT_EQ(uriSetFragmentA(&uri, NULL, NULL), URI_SUCCESS); + + assertUriEqual(&uri, "scheme://host/"); + + uriFreeUriMembersA(&uri); +} + +TEST(SetFragment, NonNullValueAppliedEmpty) { + UriUriA uri = parseWellFormedUri("scheme://host/#fragment"); + const char * const empty = ""; + + EXPECT_EQ(uriSetFragmentA(&uri, empty, empty), URI_SUCCESS); + + assertUriEqual(&uri, "scheme://host/#"); + + uriFreeUriMembersA(&uri); +} + +TEST(SetFragment, NonNullValueAppliedNonEmpty) { + UriUriA uri = parseWellFormedUri("scheme://host/#old"); + const char * const first = "new"; + const char * const afterLast = first + strlen(first); + + EXPECT_EQ(uriSetFragmentA(&uri, first, afterLast), URI_SUCCESS); + + assertUriEqual(&uri, "scheme://host/#new"); + + uriFreeUriMembersA(&uri); +} + +TEST(SetFragment, MalformedValueRejected) { + UriUriA uri = parseWellFormedUri("scheme://host/#fragment"); + const char * const first = "not well-formed"; + const char * const afterLast = first + strlen(first); + + EXPECT_EQ(uriSetFragmentA(&uri, first, afterLast), URI_ERROR_SYNTAX); + + uriFreeUriMembersA(&uri); +} + +TEST(SetFragment, UriWithoutHostTolerated) { + UriUriA uri = parseWellFormedUri("/no/host/here"); + const char * const first = "toc"; + const char * const afterLast = first + strlen(first); + EXPECT_TRUE(uri.hostText.first == NULL); // self-test + + EXPECT_EQ(uriSetFragmentA(&uri, first, afterLast), URI_SUCCESS); + + assertUriEqual(&uri, "/no/host/here#toc"); + + uriFreeUriMembersA(&uri); +} diff --git a/test/SetHostAuto.cpp b/test/SetHostAuto.cpp new file mode 100644 index 0000000..48a7452 --- /dev/null +++ b/test/SetHostAuto.cpp @@ -0,0 +1,223 @@ +/* + * uriparser - RFC 3986 URI parsing library + * + * Copyright (C) 2025, Sebastian Pipping <sebastian@pipping.org> + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library 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 + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#include <gtest/gtest.h> + +#include <uriparser/Uri.h> + +namespace { + +static UriUriA parseWellFormedUri(const char * text) { + UriUriA uri; + const int error = uriParseSingleUriA(&uri, text, NULL); + // NOTE: we cannot use ASSERT_EQ here because of the outer non-void return type + assert(error == URI_SUCCESS); + return uri; +} + +static void assertUriEqual(const UriUriA * uri, const char * expected) { + int charsRequired = -1; + ASSERT_EQ(uriToStringCharsRequiredA(uri, &charsRequired), URI_SUCCESS); + ASSERT_TRUE(charsRequired >= 0); + + char * const buffer = (char *)malloc(charsRequired + 1); + ASSERT_TRUE(buffer != NULL); + + ASSERT_EQ(uriToStringA(buffer, uri, charsRequired + 1, NULL), URI_SUCCESS); + + EXPECT_STREQ(buffer, expected); + + free(buffer); +} + +static void assertMalformedHostValueRejected(const char * text) { + UriUriA uri = parseWellFormedUri("scheme://host/"); + const char * const first = text; + const char * const afterLast = text + strlen(text); + + EXPECT_EQ(uriSetHostAutoA(&uri, first, afterLast), URI_ERROR_SYNTAX); + + uriFreeUriMembersA(&uri); +} + +} // namespace + +TEST(SetHostAuto, NullUriOnly) { + UriUriA * const uri = NULL; + const char * const first = "localhost"; + const char * const afterLast = first + strlen(first); + ASSERT_EQ(uriSetHostAutoA(uri, first, afterLast), URI_ERROR_NULL); +} + +TEST(SetHostAuto, NullFirstOnly) { + UriUriA uri = {}; + const char * const fragment = "localhost"; + const char * const first = NULL; + const char * const afterLast = fragment + strlen(fragment); + ASSERT_EQ(uriSetHostAutoA(&uri, first, afterLast), URI_ERROR_NULL); +} + +TEST(SetHostAuto, NullAfterLastOnly) { + UriUriA uri = {}; + const char * const first = "localhost"; + const char * const afterLast = NULL; + ASSERT_EQ(uriSetHostAutoA(&uri, first, afterLast), URI_ERROR_NULL); +} + +TEST(SetHostAuto, NullValueLeavesOwnerAtFalse) { + UriUriA uri = parseWellFormedUri("scheme://host/"); + EXPECT_EQ(uri.owner, URI_FALSE); // self-test + + EXPECT_EQ(uriSetHostAutoA(&uri, NULL, NULL), URI_SUCCESS); + + EXPECT_EQ(uri.owner, URI_FALSE); // i.e. still false + + uriFreeUriMembersA(&uri); +} + +TEST(SetHostAuto, NonNullValueMakesOwner) { + UriUriA uri = parseWellFormedUri("scheme://old/"); + const char * const first = "new"; + const char * const afterLast = first + strlen(first); + EXPECT_EQ(uri.owner, URI_FALSE); // self-test + + EXPECT_EQ(uriSetHostAutoA(&uri, first, afterLast), URI_SUCCESS); + + EXPECT_EQ(uri.owner, URI_TRUE); // i.e. now owned + + uriFreeUriMembersA(&uri); +} + +TEST(SetHostAuto, NullValueApplied) { + UriUriA uri = parseWellFormedUri("scheme://host/path"); + + EXPECT_EQ(uriSetHostAutoA(&uri, NULL, NULL), URI_SUCCESS); + + assertUriEqual(&uri, "scheme:/path"); + + uriFreeUriMembersA(&uri); +} + +TEST(SetHostAuto, NullValueAppliedNoPath) { + UriUriA uri = parseWellFormedUri("https://example.com"); + + EXPECT_EQ(uriSetHostAutoA(&uri, NULL, NULL), URI_SUCCESS); + + assertUriEqual(&uri, "https:"); + + uriFreeUriMembersA(&uri); +} + +TEST(SetHostAuto, NullValueAppliedNoPath2) { + UriUriA uri = parseWellFormedUri("https://example.com?foo=bar"); + + EXPECT_EQ(uriSetHostAutoA(&uri, NULL, NULL), URI_SUCCESS); + + assertUriEqual(&uri, "https:?foo=bar"); + + uriFreeUriMembersA(&uri); +} + +TEST(SetHostAuto, NonNullValueAppliedEmpty) { + UriUriA uri = parseWellFormedUri("scheme://host/path"); + const char * const empty = ""; + + EXPECT_EQ(uriSetHostAutoA(&uri, empty, empty), URI_SUCCESS); + + assertUriEqual(&uri, "scheme:///path"); + + uriFreeUriMembersA(&uri); +} + +TEST(SetHostAuto, NonNullValueAppliedNonEmptyIp4) { + UriUriA uri = parseWellFormedUri("scheme://host/path"); + const char * const first = "1.2.3.4"; + const char * const afterLast = first + strlen(first); + + EXPECT_EQ(uriSetHostAutoA(&uri, first, afterLast), URI_SUCCESS); + + assertUriEqual(&uri, "scheme://1.2.3.4/path"); + + uriFreeUriMembersA(&uri); +} + +TEST(SetHostAuto, NonNullValueAppliedNonEmptyIp6) { + UriUriA uri = parseWellFormedUri("scheme://host/path"); + const char * const first = "[::1]"; + const char * const afterLast = first + strlen(first); + + EXPECT_EQ(uriSetHostAutoA(&uri, first, afterLast), URI_SUCCESS); + + assertUriEqual(&uri, "scheme://[0000:0000:0000:0000:0000:0000:0000:0001]/path"); + + uriFreeUriMembersA(&uri); +} + +TEST(SetHostAuto, NonNullValueAppliedNonEmptyIpFuture) { + UriUriA uri = parseWellFormedUri("scheme://host/path"); + const char * const first = "[v7.host]"; + const char * const afterLast = first + strlen(first); + + EXPECT_EQ(uriSetHostAutoA(&uri, first, afterLast), URI_SUCCESS); + + assertUriEqual(&uri, "scheme://[v7.host]/path"); + + uriFreeUriMembersA(&uri); +} + +TEST(SetHostAuto, NonNullValueAppliedNonEmptyRegName) { + UriUriA uri = parseWellFormedUri("scheme://old/path"); + const char * const first = "new"; + const char * const afterLast = first + strlen(first); + + EXPECT_EQ(uriSetHostAutoA(&uri, first, afterLast), URI_SUCCESS); + + assertUriEqual(&uri, "scheme://new/path"); + + uriFreeUriMembersA(&uri); +} + +TEST(SetHostAuto, MalformedValueRejectedIp6BothSquareBracketsMissing) { + assertMalformedHostValueRejected("::1"); +} + +TEST(SetHostAuto, MalformedValueRejectedIp6ClosingSquareBracketMissing) { + assertMalformedHostValueRejected("[::1"); +} + +TEST(SetHostAuto, MalformedValueRejectedIp6OpeningSquareBracketMissing) { + assertMalformedHostValueRejected("::1]"); +} + +TEST(SetHostAuto, MalformedValueRejectedIp6SquareBracketsMissing) { + assertMalformedHostValueRejected("::1"); +} + +TEST(SetHostAuto, MalformedValueRejectedIp6Empty) { + assertMalformedHostValueRejected("[]"); +} + +TEST(SetHostAuto, MalformedValueRejectedIpFutureClosingSquareBracketMissing) { + assertMalformedHostValueRejected("[v7.host"); +} + +TEST(SetHostAuto, MalformedValueRejectedRegNameForbiddenCharacters) { + assertMalformedHostValueRejected("not well-formed"); +} diff --git a/test/SetHostIp4.cpp b/test/SetHostIp4.cpp new file mode 100644 index 0000000..727483d --- /dev/null +++ b/test/SetHostIp4.cpp @@ -0,0 +1,316 @@ +/* + * uriparser - RFC 3986 URI parsing library + * + * Copyright (C) 2025, Sebastian Pipping <sebastian@pipping.org> + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library 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 + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#include <gtest/gtest.h> + +#include <uriparser/Uri.h> + +namespace { + +static void testIsWellFormedHostIp4(const char * candidate, bool expectedWellFormed) { + const char * const first = candidate; + const char * const afterLast = + (candidate == NULL) ? NULL : (candidate + strlen(candidate)); + + const UriBool actualWellFormed = uriIsWellFormedHostIp4A(first, afterLast); + + ASSERT_EQ(actualWellFormed, expectedWellFormed); +} + +static UriUriA parseWellFormedUri(const char * text) { + UriUriA uri; + const int error = uriParseSingleUriA(&uri, text, NULL); + // NOTE: we cannot use ASSERT_EQ here because of the outer non-void return type + assert(error == URI_SUCCESS); + return uri; +} + +static void assertUriEqual(const UriUriA * uri, const char * expected) { + int charsRequired = -1; + ASSERT_EQ(uriToStringCharsRequiredA(uri, &charsRequired), URI_SUCCESS); + ASSERT_TRUE(charsRequired >= 0); + + char * const buffer = (char *)malloc(charsRequired + 1); + ASSERT_TRUE(buffer != NULL); + + ASSERT_EQ(uriToStringA(buffer, uri, charsRequired + 1, NULL), URI_SUCCESS); + + EXPECT_STREQ(buffer, expected); + + free(buffer); +} + +static void assertUriHostIp4Equal(const UriUriA * uri, unsigned char o1, unsigned char o2, + unsigned char o3, unsigned char o4) { + ASSERT_TRUE(uri->hostData.ip4 != NULL); + EXPECT_EQ(uri->hostData.ip4->data[0], o1); + EXPECT_EQ(uri->hostData.ip4->data[1], o2); + EXPECT_EQ(uri->hostData.ip4->data[2], o3); + EXPECT_EQ(uri->hostData.ip4->data[3], o4); +} + +} // namespace + +TEST(IsWellFormedHostIp4, Null) { + testIsWellFormedHostIp4(NULL, false); +} + +TEST(IsWellFormedHostIp4, Empty) { + testIsWellFormedHostIp4("", false); +} + +TEST(IsWellFormedHostIp4, AllUnset) { + testIsWellFormedHostIp4("0.0.0.0", true); +} + +TEST(IsWellFormedHostIp4, AllSet) { + testIsWellFormedHostIp4("255.255.255.255", true); +} + +TEST(IsWellFormedHostIp4, ThreeOctets) { + testIsWellFormedHostIp4("1.2.3", false); +} + +TEST(IsWellFormedHostIp4, FiveOctets) { + testIsWellFormedHostIp4("1.2.3.4.5", false); +} + +TEST(IsWellFormedHostIp4, LeadingZeros) { + testIsWellFormedHostIp4("01.2.3.4", false); + testIsWellFormedHostIp4("1.02.3.4", false); + testIsWellFormedHostIp4("1.2.03.4", false); + testIsWellFormedHostIp4("1.2.3.04", false); +} + +TEST(IsWellFormedHostIp4, Overflow) { + testIsWellFormedHostIp4("256.2.3.4", false); + testIsWellFormedHostIp4("1.256.3.4", false); + testIsWellFormedHostIp4("1.2.256.4", false); + testIsWellFormedHostIp4("1.2.3.256", false); +} + +TEST(SetHostIp4, NullUriOnly) { + UriUriA * const uri = NULL; + const char * const first = "1.2.3.4"; + const char * const afterLast = first + strlen(first); + ASSERT_EQ(uriSetHostIp4A(uri, first, afterLast), URI_ERROR_NULL); +} + +TEST(SetHostIp4, NullFirstOnly) { + UriUriA uri = {}; + const char * const host = "1.2.3.4"; + const char * const first = NULL; + const char * const afterLast = host + strlen(host); + ASSERT_EQ(uriSetHostIp4A(&uri, first, afterLast), URI_ERROR_NULL); +} + +TEST(SetHostIp4, NullAfterLastOnly) { + UriUriA uri = {}; + const char * const first = "1.2.3.4"; + const char * const afterLast = NULL; + ASSERT_EQ(uriSetHostIp4A(&uri, first, afterLast), URI_ERROR_NULL); +} + +TEST(SetHostIp4, NullValueLeavesOwnerAtFalse) { + UriUriA uri = parseWellFormedUri("scheme://host/"); + EXPECT_EQ(uri.owner, URI_FALSE); // self-test + + EXPECT_EQ(uriSetHostIp4A(&uri, NULL, NULL), URI_SUCCESS); + + EXPECT_EQ(uri.owner, URI_FALSE); // i.e. still false + + uriFreeUriMembersA(&uri); +} + +TEST(SetHostIp4, NonNullValueMakesOwner) { + UriUriA uri = parseWellFormedUri("scheme://old/"); + const char * const first = "1.2.3.4"; + const char * const afterLast = first + strlen(first); + EXPECT_EQ(uri.owner, URI_FALSE); // self-test + + EXPECT_EQ(uriSetHostIp4A(&uri, first, afterLast), URI_SUCCESS); + + EXPECT_EQ(uri.owner, URI_TRUE); // i.e. now owned + + uriFreeUriMembersA(&uri); +} + +TEST(SetHostIp4, NullValueAppliedDotInserted) { + UriUriA uri = parseWellFormedUri("scheme://host//path1/path2"); + + EXPECT_EQ(uriSetHostIp4A(&uri, NULL, NULL), URI_SUCCESS); + + assertUriEqual(&uri, "scheme:/.//path1/path2"); // i.e. not scheme://path1/path2 + + uriFreeUriMembersA(&uri); +} + +TEST(SetHostIp4, NullValueAppliedDotNotInserted) { + UriUriA uri = parseWellFormedUri("//host/./path1/path2"); + + EXPECT_EQ(uriSetHostIp4A(&uri, NULL, NULL), URI_SUCCESS); + + assertUriEqual(&uri, "/./path1/path2"); // i.e. not /././path1/path2 + + uriFreeUriMembersA(&uri); +} + +TEST(SetHostIp4, NullValueAppliedPriorNull) { + UriUriA uri = parseWellFormedUri("scheme:/path"); + + EXPECT_EQ(uriSetHostIp4A(&uri, NULL, NULL), URI_SUCCESS); + + assertUriEqual(&uri, "scheme:/path"); + + uriFreeUriMembersA(&uri); +} + +TEST(SetHostIp4, NullValueAppliedPriorIp4) { + UriUriA uri = parseWellFormedUri("scheme://1.2.3.4/path"); + + EXPECT_EQ(uriSetHostIp4A(&uri, NULL, NULL), URI_SUCCESS); + + assertUriEqual(&uri, "scheme:/path"); + + uriFreeUriMembersA(&uri); +} + +TEST(SetHostIp4, NullValueAppliedPriorIp6) { + UriUriA uri = parseWellFormedUri("scheme://[::1]/path"); + + EXPECT_EQ(uriSetHostIp4A(&uri, NULL, NULL), URI_SUCCESS); + + assertUriEqual(&uri, "scheme:/path"); + + uriFreeUriMembersA(&uri); +} + +TEST(SetHostIp4, NullValueAppliedPriorIpFuture) { + UriUriA uri = parseWellFormedUri("scheme://[v7.host]/path"); + + EXPECT_EQ(uriSetHostIp4A(&uri, NULL, NULL), URI_SUCCESS); + + assertUriEqual(&uri, "scheme:/path"); + + uriFreeUriMembersA(&uri); +} + +TEST(SetHostIp4, NullValueAppliedPriorRegName) { + UriUriA uri = parseWellFormedUri("scheme://host/path"); + + EXPECT_EQ(uriSetHostIp4A(&uri, NULL, NULL), URI_SUCCESS); + + assertUriEqual(&uri, "scheme:/path"); + + uriFreeUriMembersA(&uri); +} + +TEST(SetHostIp4, NonNullValueAppliedNonEmptyPriorNull) { + UriUriA uri = parseWellFormedUri("scheme:"); + const char * const first = "1.2.3.4"; + const char * const afterLast = first + strlen(first); + + EXPECT_EQ(uriSetHostIp4A(&uri, first, afterLast), URI_SUCCESS); + + assertUriEqual(&uri, "scheme://1.2.3.4"); + assertUriHostIp4Equal(&uri, 1, 2, 3, 4); + + uriFreeUriMembersA(&uri); +} + +TEST(SetHostIp4, NonNullValueAppliedNonEmptyPriorIp4) { + UriUriA uri = parseWellFormedUri("//1.2.3.4"); + const char * const first = "5.6.7.8"; + const char * const afterLast = first + strlen(first); + + EXPECT_EQ(uriSetHostIp4A(&uri, first, afterLast), URI_SUCCESS); + + assertUriEqual(&uri, "//5.6.7.8"); + assertUriHostIp4Equal(&uri, 5, 6, 7, 8); + + uriFreeUriMembersA(&uri); +} + +TEST(SetHostIp4, NonNullValueAppliedNonEmptyPriorIp6) { + UriUriA uri = parseWellFormedUri("//[::1]"); + const char * const first = "1.2.3.4"; + const char * const afterLast = first + strlen(first); + + EXPECT_EQ(uriSetHostIp4A(&uri, first, afterLast), URI_SUCCESS); + + assertUriEqual(&uri, "//1.2.3.4"); + assertUriHostIp4Equal(&uri, 1, 2, 3, 4); + + uriFreeUriMembersA(&uri); +} + +TEST(SetHostIp4, NonNullValueAppliedNonEmptyPriorIpFuture) { + UriUriA uri = parseWellFormedUri("//[v7.host]"); + const char * const first = "1.2.3.4"; + const char * const afterLast = first + strlen(first); + + EXPECT_EQ(uriSetHostIp4A(&uri, first, afterLast), URI_SUCCESS); + + assertUriEqual(&uri, "//1.2.3.4"); + assertUriHostIp4Equal(&uri, 1, 2, 3, 4); + + uriFreeUriMembersA(&uri); +} + +TEST(SetHostIp4, NonNullValueAppliedNonEmptyPriorRegName) { + UriUriA uri = parseWellFormedUri("//hostname.test"); + const char * const first = "1.2.3.4"; + const char * const afterLast = first + strlen(first); + + EXPECT_EQ(uriSetHostIp4A(&uri, first, afterLast), URI_SUCCESS); + + assertUriEqual(&uri, "//1.2.3.4"); + assertUriHostIp4Equal(&uri, 1, 2, 3, 4); + + uriFreeUriMembersA(&uri); +} + +TEST(SetHostIp4, MalformedValueRejected) { + UriUriA uri = parseWellFormedUri("scheme://host/"); + const char * const first = "not well-formed"; + const char * const afterLast = first + strlen(first); + + EXPECT_EQ(uriSetHostIp4A(&uri, first, afterLast), URI_ERROR_SYNTAX); + + uriFreeUriMembersA(&uri); +} + +TEST(SetHostIp4, UriWithPortRejected) { + UriUriA uri = parseWellFormedUri("//host:1234"); + EXPECT_TRUE(uri.portText.first != NULL); // self-test + + EXPECT_EQ(uriSetHostIp4A(&uri, NULL, NULL), URI_ERROR_SETHOST_PORT_SET); + + uriFreeUriMembersA(&uri); +} + +TEST(SetHostIp4, UriWithUserInfoRejected) { + UriUriA uri = parseWellFormedUri("//user:password@host"); + EXPECT_TRUE(uri.userInfo.first != NULL); // self-test + + EXPECT_EQ(uriSetHostIp4A(&uri, NULL, NULL), URI_ERROR_SETHOST_USERINFO_SET); + + uriFreeUriMembersA(&uri); +} diff --git a/test/SetHostIp6.cpp b/test/SetHostIp6.cpp new file mode 100644 index 0000000..e81eab9 --- /dev/null +++ b/test/SetHostIp6.cpp @@ -0,0 +1,387 @@ +/* + * uriparser - RFC 3986 URI parsing library + * + * Copyright (C) 2025, Sebastian Pipping <sebastian@pipping.org> + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library 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 + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#include <gtest/gtest.h> + +#include <uriparser/Uri.h> + +namespace { + +static void testIsWellFormedHostIp6(const char * candidate, bool expectedWellFormed) { + const char * const first = candidate; + const char * const afterLast = + (candidate == NULL) ? NULL : (candidate + strlen(candidate)); + + const UriBool actualWellFormed = + (uriIsWellFormedHostIp6A(first, afterLast) == URI_SUCCESS) ? URI_TRUE : URI_FALSE; + + ASSERT_EQ(actualWellFormed, expectedWellFormed); +} + +static UriUriA parseWellFormedUri(const char * text) { + UriUriA uri; + const int error = uriParseSingleUriA(&uri, text, NULL); + // NOTE: we cannot use ASSERT_EQ here because of the outer non-void return type + assert(error == URI_SUCCESS); + return uri; +} + +static void assertUriEqual(const UriUriA * uri, const char * expected) { + int charsRequired = -1; + ASSERT_EQ(uriToStringCharsRequiredA(uri, &charsRequired), URI_SUCCESS); + ASSERT_TRUE(charsRequired >= 0); + + char * const buffer = (char *)malloc(charsRequired + 1); + ASSERT_TRUE(buffer != NULL); + + ASSERT_EQ(uriToStringA(buffer, uri, charsRequired + 1, NULL), URI_SUCCESS); + + EXPECT_STREQ(buffer, expected); + + free(buffer); +} + +} // namespace + +TEST(IsWellFormedHostIp6, Null) { + testIsWellFormedHostIp6(NULL, false); +} + +TEST(IsWellFormedHostIp6, Empty) { + testIsWellFormedHostIp6("", false); +} + +TEST(IsWellFormedHostIp6, Ip4EmbeddingAllUnset) { + testIsWellFormedHostIp6("::0.0.0.0", true); +} + +TEST(IsWellFormedHostIp6, Ip4EmbeddingAllSet) { + testIsWellFormedHostIp6("::255.255.255.255", true); +} + +TEST(IsWellFormedHostIp6, Ip4EmbeddingThreeOctets) { + testIsWellFormedHostIp6("::1.2.3", false); +} + +TEST(IsWellFormedHostIp6, Ip4EmbeddingFiveOctets) { + testIsWellFormedHostIp6("::1.2.3.4.5", false); +} + +TEST(IsWellFormedHostIp6, Ip4EmbeddingLeadingZeros) { + testIsWellFormedHostIp6("::01.2.3.4", false); + testIsWellFormedHostIp6("::1.02.3.4", false); + testIsWellFormedHostIp6("::1.2.03.4", false); + testIsWellFormedHostIp6("::1.2.3.04", false); +} + +TEST(IsWellFormedHostIp6, Ip4EmbeddingOverflow) { + testIsWellFormedHostIp6("::256.2.3.4", false); + testIsWellFormedHostIp6("::1.256.3.4", false); + testIsWellFormedHostIp6("::1.2.256.4", false); + testIsWellFormedHostIp6("::1.2.3.256", false); +} + +TEST(IsWellFormedHostIp6, Ip4EmbeddingHex) { + testIsWellFormedHostIp6("::a.2.3.4", false); + testIsWellFormedHostIp6("::1.a.3.4", false); + testIsWellFormedHostIp6("::1.2.a.4", false); + testIsWellFormedHostIp6("::1.2.3.a", false); +} + +TEST(IsWellFormedHostIp6, Uppercase) { + testIsWellFormedHostIp6("ABCD:EF01:2345:6789:ABCD:EF01:2345:6789", true); +} + +TEST(IsWellFormedHostIp6, Lowercase) { + testIsWellFormedHostIp6("abcd:ef01:2345:6789:abcd:ef01:2345:6789", true); +} + +TEST(IsWellFormedHostIp6, MaxLengthViolation) { + testIsWellFormedHostIp6("aaaa:aaaa:aaaa:aaaa:aaaa:aaaa:aaaa:aaaa" + "X", + false); +} + +TEST(IsWellFormedHostIp6, NineQuads) { + testIsWellFormedHostIp6("1:2:3:4:5:6:7:8:9", false); +} + +TEST(IsWellFormedHostIp6, SevenQuads) { + testIsWellFormedHostIp6("1:2:3:4:5:6:7", false); +} + +TEST(IsWellFormedHostIp6, AllUnset) { + testIsWellFormedHostIp6("::", true); +} + +TEST(IsWellFormedHostIp6, Loopback) { + testIsWellFormedHostIp6("::1", true); +} + +TEST(IsWellFormedHostIp6, SparseLeadingZeros) { + testIsWellFormedHostIp6("01:02:03:04:05:06:07:08", true); +} + +TEST(IsWellFormedHostIp6, SingleZipper) { + testIsWellFormedHostIp6("1::8", true); +} + +TEST(IsWellFormedHostIp6, TwoZippers) { + testIsWellFormedHostIp6("1::4::8", false); +} + +TEST(IsWellFormedHostIp6, Overzipped) { + testIsWellFormedHostIp6("::1:2:3:4:5:6:7:8", false); + testIsWellFormedHostIp6("1:2:3:4::5:6:7:8", false); + testIsWellFormedHostIp6("1:2:3:4:5:6:7:8::", false); +} + +TEST(IsWellFormedHostIp6, NonHex) { + testIsWellFormedHostIp6("000g::", false); + testIsWellFormedHostIp6("00g0::", false); + testIsWellFormedHostIp6("0g00::", false); + testIsWellFormedHostIp6("g000::", false); + + testIsWellFormedHostIp6("000G::", false); + testIsWellFormedHostIp6("00G0::", false); + testIsWellFormedHostIp6("0G00::", false); + testIsWellFormedHostIp6("G000::", false); +} + +TEST(IsWellFormedHostIp6, IpFuture) { + testIsWellFormedHostIp6("v7.host", false); + testIsWellFormedHostIp6("V7.host", false); +} + +TEST(SetHostIp6, NullUriOnly) { + UriUriA * const uri = NULL; + const char * const first = "::1"; + const char * const afterLast = first + strlen(first); + ASSERT_EQ(uriSetHostIp6A(uri, first, afterLast), URI_ERROR_NULL); +} + +TEST(SetHostIp6, NullFirstOnly) { + UriUriA uri = {}; + const char * const host = "::1"; + const char * const first = NULL; + const char * const afterLast = host + strlen(host); + ASSERT_EQ(uriSetHostIp6A(&uri, first, afterLast), URI_ERROR_NULL); +} + +TEST(SetHostIp6, NullAfterLastOnly) { + UriUriA uri = {}; + const char * const first = "::1"; + const char * const afterLast = NULL; + ASSERT_EQ(uriSetHostIp6A(&uri, first, afterLast), URI_ERROR_NULL); +} + +TEST(SetHostIp6, NullValueLeavesOwnerAtFalse) { + UriUriA uri = parseWellFormedUri("scheme://host/"); + EXPECT_EQ(uri.owner, URI_FALSE); // self-test + + EXPECT_EQ(uriSetHostIp6A(&uri, NULL, NULL), URI_SUCCESS); + + EXPECT_EQ(uri.owner, URI_FALSE); // i.e. still false + + uriFreeUriMembersA(&uri); +} + +TEST(SetHostIp6, NonNullValueMakesOwner) { + UriUriA uri = parseWellFormedUri("scheme://old/"); + const char * const first = "::1"; + const char * const afterLast = first + strlen(first); + EXPECT_EQ(uri.owner, URI_FALSE); // self-test + + EXPECT_EQ(uriSetHostIp6A(&uri, first, afterLast), URI_SUCCESS); + + EXPECT_EQ(uri.owner, URI_TRUE); // i.e. now owned + + uriFreeUriMembersA(&uri); +} + +TEST(SetHostIp6, NullValueAppliedDotInserted) { + UriUriA uri = parseWellFormedUri("scheme://host//path1/path2"); + + EXPECT_EQ(uriSetHostIp6A(&uri, NULL, NULL), URI_SUCCESS); + + assertUriEqual(&uri, "scheme:/.//path1/path2"); // i.e. not scheme://path1/path2 + + uriFreeUriMembersA(&uri); +} + +TEST(SetHostIp6, NullValueAppliedDotNotInserted) { + UriUriA uri = parseWellFormedUri("//host/./path1/path2"); + + EXPECT_EQ(uriSetHostIp6A(&uri, NULL, NULL), URI_SUCCESS); + + assertUriEqual(&uri, "/./path1/path2"); // i.e. not /././path1/path2 + + uriFreeUriMembersA(&uri); +} + +TEST(SetHostIp6, NullValueAppliedPriorNull) { + UriUriA uri = parseWellFormedUri("scheme:/path"); + + EXPECT_EQ(uriSetHostIp6A(&uri, NULL, NULL), URI_SUCCESS); + + assertUriEqual(&uri, "scheme:/path"); + + uriFreeUriMembersA(&uri); +} + +TEST(SetHostIp6, NullValueAppliedPriorIp4) { + UriUriA uri = parseWellFormedUri("scheme://1.2.3.4/path"); + + EXPECT_EQ(uriSetHostIp6A(&uri, NULL, NULL), URI_SUCCESS); + + assertUriEqual(&uri, "scheme:/path"); + + uriFreeUriMembersA(&uri); +} + +TEST(SetHostIp6, NullValueAppliedPriorIp6) { + UriUriA uri = parseWellFormedUri("scheme://[::1]/path"); + + EXPECT_EQ(uriSetHostIp6A(&uri, NULL, NULL), URI_SUCCESS); + + assertUriEqual(&uri, "scheme:/path"); + + uriFreeUriMembersA(&uri); +} + +TEST(SetHostIp6, NullValueAppliedPriorIpFuture) { + UriUriA uri = parseWellFormedUri("scheme://[v7.host]/path"); + + EXPECT_EQ(uriSetHostIp6A(&uri, NULL, NULL), URI_SUCCESS); + + assertUriEqual(&uri, "scheme:/path"); + + uriFreeUriMembersA(&uri); +} + +TEST(SetHostIp6, NullValueAppliedPriorRegName) { + UriUriA uri = parseWellFormedUri("scheme://host/path"); + + EXPECT_EQ(uriSetHostIp6A(&uri, NULL, NULL), URI_SUCCESS); + + assertUriEqual(&uri, "scheme:/path"); + + uriFreeUriMembersA(&uri); +} + +TEST(SetHostIp6, NonNullValueAppliedNonEmptyPriorNull) { + UriUriA uri = parseWellFormedUri("scheme:"); + const char * const first = "::1"; + const char * const afterLast = first + strlen(first); + + EXPECT_EQ(uriSetHostIp6A(&uri, first, afterLast), URI_SUCCESS); + + assertUriEqual(&uri, "scheme://[0000:0000:0000:0000:0000:0000:0000:0001]"); + + uriFreeUriMembersA(&uri); +} + +TEST(SetHostIp6, MutationTesting) { + UriUriA uri = parseWellFormedUri("scheme:"); + const char * const first = "1:23:456:7890::5.43.219.0"; + const char * const afterLast = first + strlen(first); + + EXPECT_EQ(uriSetHostIp6A(&uri, first, afterLast), URI_SUCCESS); + + assertUriEqual(&uri, "scheme://[0001:0023:0456:7890:0000:0000:052b:db00]"); + + uriFreeUriMembersA(&uri); +} + +TEST(SetHostIp6, NonNullValueAppliedNonEmptyPriorIp4) { + UriUriA uri = parseWellFormedUri("//1.2.3.4"); + const char * const first = "::1"; + const char * const afterLast = first + strlen(first); + + EXPECT_EQ(uriSetHostIp6A(&uri, first, afterLast), URI_SUCCESS); + + assertUriEqual(&uri, "//[0000:0000:0000:0000:0000:0000:0000:0001]"); + + uriFreeUriMembersA(&uri); +} + +TEST(SetHostIp6, NonNullValueAppliedNonEmptyPriorIp6) { + UriUriA uri = parseWellFormedUri("//[::1]"); + const char * const first = "::2"; + const char * const afterLast = first + strlen(first); + + EXPECT_EQ(uriSetHostIp6A(&uri, first, afterLast), URI_SUCCESS); + + assertUriEqual(&uri, "//[0000:0000:0000:0000:0000:0000:0000:0002]"); + + uriFreeUriMembersA(&uri); +} + +TEST(SetHostIp6, NonNullValueAppliedNonEmptyPriorIpFuture) { + UriUriA uri = parseWellFormedUri("//[v7.host]"); + const char * const first = "::1"; + const char * const afterLast = first + strlen(first); + + EXPECT_EQ(uriSetHostIp6A(&uri, first, afterLast), URI_SUCCESS); + + assertUriEqual(&uri, "//[0000:0000:0000:0000:0000:0000:0000:0001]"); + + uriFreeUriMembersA(&uri); +} + +TEST(SetHostIp6, NonNullValueAppliedNonEmptyPriorRegName) { + UriUriA uri = parseWellFormedUri("//hostname.test"); + const char * const first = "::1"; + const char * const afterLast = first + strlen(first); + + EXPECT_EQ(uriSetHostIp6A(&uri, first, afterLast), URI_SUCCESS); + + assertUriEqual(&uri, "//[0000:0000:0000:0000:0000:0000:0000:0001]"); + + uriFreeUriMembersA(&uri); +} + +TEST(SetHostIp6, MalformedValueRejected) { + UriUriA uri = parseWellFormedUri("scheme://host/"); + const char * const first = "not well-formed"; + const char * const afterLast = first + strlen(first); + + EXPECT_EQ(uriSetHostIp6A(&uri, first, afterLast), URI_ERROR_SYNTAX); + + uriFreeUriMembersA(&uri); +} + +TEST(SetHostIp6, UriWithPortRejected) { + UriUriA uri = parseWellFormedUri("//host:1234"); + EXPECT_TRUE(uri.portText.first != NULL); // self-test + + EXPECT_EQ(uriSetHostIp6A(&uri, NULL, NULL), URI_ERROR_SETHOST_PORT_SET); + + uriFreeUriMembersA(&uri); +} + +TEST(SetHostIp6, UriWithUserInfoRejected) { + UriUriA uri = parseWellFormedUri("//user:password@host"); + EXPECT_TRUE(uri.userInfo.first != NULL); // self-test + + EXPECT_EQ(uriSetHostIp6A(&uri, NULL, NULL), URI_ERROR_SETHOST_USERINFO_SET); + + uriFreeUriMembersA(&uri); +} diff --git a/test/SetHostIpFuture.cpp b/test/SetHostIpFuture.cpp new file mode 100644 index 0000000..7601ae0 --- /dev/null +++ b/test/SetHostIpFuture.cpp @@ -0,0 +1,300 @@ +/* + * uriparser - RFC 3986 URI parsing library + * + * Copyright (C) 2025, Sebastian Pipping <sebastian@pipping.org> + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library 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 + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#include <gtest/gtest.h> + +#include <uriparser/Uri.h> + +namespace { + +static void testIsWellFormedHostIpFuture(const char * candidate, + bool expectedWellFormed) { + const char * const first = candidate; + const char * const afterLast = + (candidate == NULL) ? NULL : (candidate + strlen(candidate)); + + const UriBool actualWellFormed = + (uriIsWellFormedHostIpFutureA(first, afterLast) == URI_SUCCESS) ? URI_TRUE + : URI_FALSE; + + ASSERT_EQ(actualWellFormed, expectedWellFormed); +} + +static UriUriA parseWellFormedUri(const char * text) { + UriUriA uri; + const int error = uriParseSingleUriA(&uri, text, NULL); + // NOTE: we cannot use ASSERT_EQ here because of the outer non-void return type + assert(error == URI_SUCCESS); + return uri; +} + +static void assertUriEqual(const UriUriA * uri, const char * expected) { + int charsRequired = -1; + ASSERT_EQ(uriToStringCharsRequiredA(uri, &charsRequired), URI_SUCCESS); + ASSERT_TRUE(charsRequired >= 0); + + char * const buffer = (char *)malloc(charsRequired + 1); + ASSERT_TRUE(buffer != NULL); + + ASSERT_EQ(uriToStringA(buffer, uri, charsRequired + 1, NULL), URI_SUCCESS); + + EXPECT_STREQ(buffer, expected); + + free(buffer); +} + +static void assertIpFutureMatchHostText(const UriUriA * uri) { + ASSERT_TRUE(uri != NULL); + EXPECT_TRUE(uri->hostText.first != NULL); + EXPECT_TRUE(uri->hostText.afterLast != NULL); + EXPECT_EQ(uri->hostText.first, uri->hostData.ipFuture.first); + EXPECT_EQ(uri->hostText.afterLast, uri->hostData.ipFuture.afterLast); +} + +} // namespace + +TEST(IsWellFormedHostIpFuture, Null) { + testIsWellFormedHostIpFuture(NULL, false); +} + +TEST(IsWellFormedHostIpFuture, Empty) { + testIsWellFormedHostIpFuture("", false); +} + +TEST(IsWellFormedHostIpFuture, Ip6) { + testIsWellFormedHostIpFuture("abcd:ef01:2345:6789:abcd:ef01:2345:6789", false); +} + +TEST(IsWellFormedHostIpFuture, Lowercase) { + testIsWellFormedHostIpFuture("v7.host", true); +} + +TEST(IsWellFormedHostIpFuture, Uppercase) { + testIsWellFormedHostIpFuture("V7.HOST", true); +} + +TEST(SetHostIpFuture, NullUriOnly) { + UriUriA * const uri = NULL; + const char * const first = "v7.host"; + const char * const afterLast = first + strlen(first); + ASSERT_EQ(uriSetHostIpFutureA(uri, first, afterLast), URI_ERROR_NULL); +} + +TEST(SetHostIpFuture, NullFirstOnly) { + UriUriA uri = {}; + const char * const host = "v7.host"; + const char * const first = NULL; + const char * const afterLast = host + strlen(host); + ASSERT_EQ(uriSetHostIpFutureA(&uri, first, afterLast), URI_ERROR_NULL); +} + +TEST(SetHostIpFuture, NullAfterLastOnly) { + UriUriA uri = {}; + const char * const first = "v7.host"; + const char * const afterLast = NULL; + ASSERT_EQ(uriSetHostIpFutureA(&uri, first, afterLast), URI_ERROR_NULL); +} + +TEST(SetHostIpFuture, NullValueLeavesOwnerAtFalse) { + UriUriA uri = parseWellFormedUri("scheme://host/"); + EXPECT_EQ(uri.owner, URI_FALSE); // self-test + + EXPECT_EQ(uriSetHostIpFutureA(&uri, NULL, NULL), URI_SUCCESS); + + EXPECT_EQ(uri.owner, URI_FALSE); // i.e. still false + + uriFreeUriMembersA(&uri); +} + +TEST(SetHostIpFuture, NonNullValueMakesOwner) { + UriUriA uri = parseWellFormedUri("scheme://old/"); + const char * const first = "v7.host"; + const char * const afterLast = first + strlen(first); + EXPECT_EQ(uri.owner, URI_FALSE); // self-test + + EXPECT_EQ(uriSetHostIpFutureA(&uri, first, afterLast), URI_SUCCESS); + + EXPECT_EQ(uri.owner, URI_TRUE); // i.e. now owned + + uriFreeUriMembersA(&uri); +} + +TEST(SetHostIpFuture, NullValueAppliedDotInserted) { + UriUriA uri = parseWellFormedUri("scheme://host//path1/path2"); + + EXPECT_EQ(uriSetHostIpFutureA(&uri, NULL, NULL), URI_SUCCESS); + + assertUriEqual(&uri, "scheme:/.//path1/path2"); // i.e. not scheme://path1/path2 + + uriFreeUriMembersA(&uri); +} + +TEST(SetHostIpFuture, NullValueAppliedDotNotInserted) { + UriUriA uri = parseWellFormedUri("//host/./path1/path2"); + + EXPECT_EQ(uriSetHostIpFutureA(&uri, NULL, NULL), URI_SUCCESS); + + assertUriEqual(&uri, "/./path1/path2"); // i.e. not /././path1/path2 + + uriFreeUriMembersA(&uri); +} + +TEST(SetHostIpFuture, NullValueAppliedPriorNull) { + UriUriA uri = parseWellFormedUri("scheme:/path"); + + EXPECT_EQ(uriSetHostIpFutureA(&uri, NULL, NULL), URI_SUCCESS); + + assertUriEqual(&uri, "scheme:/path"); + + uriFreeUriMembersA(&uri); +} + +TEST(SetHostIpFuture, NullValueAppliedPriorIp4) { + UriUriA uri = parseWellFormedUri("scheme://1.2.3.4/path"); + + EXPECT_EQ(uriSetHostIpFutureA(&uri, NULL, NULL), URI_SUCCESS); + + assertUriEqual(&uri, "scheme:/path"); + + uriFreeUriMembersA(&uri); +} + +TEST(SetHostIpFuture, NullValueAppliedPriorIp6) { + UriUriA uri = parseWellFormedUri("scheme://[::1]/path"); + + EXPECT_EQ(uriSetHostIpFutureA(&uri, NULL, NULL), URI_SUCCESS); + + assertUriEqual(&uri, "scheme:/path"); + + uriFreeUriMembersA(&uri); +} + +TEST(SetHostIpFuture, NullValueAppliedPriorIpFuture) { + UriUriA uri = parseWellFormedUri("scheme://[v7.host]/path"); + + EXPECT_EQ(uriSetHostIpFutureA(&uri, NULL, NULL), URI_SUCCESS); + + assertUriEqual(&uri, "scheme:/path"); + + uriFreeUriMembersA(&uri); +} + +TEST(SetHostIpFuture, NullValueAppliedPriorRegName) { + UriUriA uri = parseWellFormedUri("scheme://host/path"); + + EXPECT_EQ(uriSetHostIpFutureA(&uri, NULL, NULL), URI_SUCCESS); + + assertUriEqual(&uri, "scheme:/path"); + + uriFreeUriMembersA(&uri); +} + +TEST(SetHostIpFuture, NonNullValueAppliedNonEmptyPriorNull) { + UriUriA uri = parseWellFormedUri("scheme:"); + const char * const first = "v7.host"; + const char * const afterLast = first + strlen(first); + + EXPECT_EQ(uriSetHostIpFutureA(&uri, first, afterLast), URI_SUCCESS); + + assertUriEqual(&uri, "scheme://[v7.host]"); + assertIpFutureMatchHostText(&uri); + + uriFreeUriMembersA(&uri); +} + +TEST(SetHostIpFuture, NonNullValueAppliedNonEmptyPriorIp4) { + UriUriA uri = parseWellFormedUri("//1.2.3.4"); + const char * const first = "v7.host"; + const char * const afterLast = first + strlen(first); + + EXPECT_EQ(uriSetHostIpFutureA(&uri, first, afterLast), URI_SUCCESS); + + assertUriEqual(&uri, "//[v7.host]"); + assertIpFutureMatchHostText(&uri); + + uriFreeUriMembersA(&uri); +} + +TEST(SetHostIpFuture, NonNullValueAppliedNonEmptyPriorIp6) { + UriUriA uri = parseWellFormedUri("//[::1]"); + const char * const first = "v7.host"; + const char * const afterLast = first + strlen(first); + + EXPECT_EQ(uriSetHostIpFutureA(&uri, first, afterLast), URI_SUCCESS); + + assertUriEqual(&uri, "//[v7.host]"); + assertIpFutureMatchHostText(&uri); + + uriFreeUriMembersA(&uri); +} + +TEST(SetHostIpFuture, NonNullValueAppliedNonEmptyPriorIpFuture) { + UriUriA uri = parseWellFormedUri("//[v7.old]"); + const char * const first = "v7.new"; + const char * const afterLast = first + strlen(first); + + EXPECT_EQ(uriSetHostIpFutureA(&uri, first, afterLast), URI_SUCCESS); + + assertUriEqual(&uri, "//[v7.new]"); + assertIpFutureMatchHostText(&uri); + + uriFreeUriMembersA(&uri); +} + +TEST(SetHostIpFuture, NonNullValueAppliedNonEmptyPriorRegName) { + UriUriA uri = parseWellFormedUri("//hostname.test"); + const char * const first = "v7.host"; + const char * const afterLast = first + strlen(first); + + EXPECT_EQ(uriSetHostIpFutureA(&uri, first, afterLast), URI_SUCCESS); + + assertUriEqual(&uri, "//[v7.host]"); + assertIpFutureMatchHostText(&uri); + + uriFreeUriMembersA(&uri); +} + +TEST(SetHostIpFuture, MalformedValueRejected) { + UriUriA uri = parseWellFormedUri("scheme://host/"); + const char * const first = "not well-formed"; + const char * const afterLast = first + strlen(first); + + EXPECT_EQ(uriSetHostIpFutureA(&uri, first, afterLast), URI_ERROR_SYNTAX); + + uriFreeUriMembersA(&uri); +} + +TEST(SetHostIpFuture, UriWithPortRejected) { + UriUriA uri = parseWellFormedUri("//host:1234"); + EXPECT_TRUE(uri.portText.first != NULL); // self-test + + EXPECT_EQ(uriSetHostIpFutureA(&uri, NULL, NULL), URI_ERROR_SETHOST_PORT_SET); + + uriFreeUriMembersA(&uri); +} + +TEST(SetHostIpFuture, UriWithUserInfoRejected) { + UriUriA uri = parseWellFormedUri("//user:password@host"); + EXPECT_TRUE(uri.userInfo.first != NULL); // self-test + + EXPECT_EQ(uriSetHostIpFutureA(&uri, NULL, NULL), URI_ERROR_SETHOST_USERINFO_SET); + + uriFreeUriMembersA(&uri); +} diff --git a/test/SetHostRegName.cpp b/test/SetHostRegName.cpp new file mode 100644 index 0000000..4a525b1 --- /dev/null +++ b/test/SetHostRegName.cpp @@ -0,0 +1,336 @@ +/* + * uriparser - RFC 3986 URI parsing library + * + * Copyright (C) 2025, Sebastian Pipping <sebastian@pipping.org> + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library 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 + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#include <gtest/gtest.h> + +#include <uriparser/Uri.h> + +namespace { + +static void testIsWellFormedHostRegName(const char * candidate, bool expectedWellFormed) { + const char * const first = candidate; + const char * const afterLast = + (candidate == NULL) ? NULL : (candidate + strlen(candidate)); + + const UriBool actualWellFormed = uriIsWellFormedHostRegNameA(first, afterLast); + + ASSERT_EQ(actualWellFormed, expectedWellFormed); +} + +static UriUriA parseWellFormedUri(const char * text) { + UriUriA uri; + const int error = uriParseSingleUriA(&uri, text, NULL); + // NOTE: we cannot use ASSERT_EQ here because of the outer non-void return type + assert(error == URI_SUCCESS); + return uri; +} + +static void assertUriEqual(const UriUriA * uri, const char * expected) { + int charsRequired = -1; + ASSERT_EQ(uriToStringCharsRequiredA(uri, &charsRequired), URI_SUCCESS); + ASSERT_TRUE(charsRequired >= 0); + + char * const buffer = (char *)malloc(charsRequired + 1); + ASSERT_TRUE(buffer != NULL); + + ASSERT_EQ(uriToStringA(buffer, uri, charsRequired + 1, NULL), URI_SUCCESS); + + EXPECT_STREQ(buffer, expected); + + free(buffer); +} + +} // namespace + +TEST(IsWellFormedHostRegName, Null) { + testIsWellFormedHostRegName(NULL, false); +} + +TEST(IsWellFormedHostRegName, Empty) { + testIsWellFormedHostRegName("", true); +} + +TEST(IsWellFormedHostRegName, AllowedCharacters) { + // The related grammar subset is this: + // + // reg-name = *( unreserved / pct-encoded / sub-delims ) + // unreserved = ALPHA / DIGIT / "-" / "." / "_" / "~" + // pct-encoded = "%" HEXDIG HEXDIG + // sub-delims = "!" / "$" / "&" / "'" / "(" / ")" + // / "*" / "+" / "," / ";" / "=" + // + // NOTE: Percent encoding has dedicated tests further down + testIsWellFormedHostRegName("0123456789" + "ABCDEF" + "abcdef" + "gGhHiIjJkKlLmMnNoOpPqQrRsStTuUvVwWxXyYzZ" + "-._~" + "!$&'()*+,;=", + true); +} + +TEST(IsWellFormedHostRegName, ForbiddenCharacters) { + testIsWellFormedHostRegName(" ", false); +} + +TEST(IsWellFormedHostRegName, PercentEncodingWellFormed) { + testIsWellFormedHostRegName("%" + "aa" + "%" + "AA", + true); +} + +TEST(IsWellFormedHostRegName, PercentEncodingMalformedCutOff1) { + testIsWellFormedHostRegName("%", false); +} + +TEST(IsWellFormedHostRegName, PercentEncodingMalformedCutOff2) { + testIsWellFormedHostRegName("%" + "a", + false); +} + +TEST(IsWellFormedHostRegName, PercentEncodingMalformedForbiddenCharacter1) { + testIsWellFormedHostRegName("%" + "ga", + false); +} + +TEST(IsWellFormedHostRegName, PercentEncodingMalformedForbiddenCharacter2) { + testIsWellFormedHostRegName("%" + "ag", + false); +} + +TEST(SetHostRegName, NullUriOnly) { + UriUriA * const uri = NULL; + const char * const first = "localhost"; + const char * const afterLast = first + strlen(first); + ASSERT_EQ(uriSetHostRegNameA(uri, first, afterLast), URI_ERROR_NULL); +} + +TEST(SetHostRegName, NullFirstOnly) { + UriUriA uri = {}; + const char * const fragment = "localhost"; + const char * const first = NULL; + const char * const afterLast = fragment + strlen(fragment); + ASSERT_EQ(uriSetHostRegNameA(&uri, first, afterLast), URI_ERROR_NULL); +} + +TEST(SetHostRegName, NullAfterLastOnly) { + UriUriA uri = {}; + const char * const first = "localhost"; + const char * const afterLast = NULL; + ASSERT_EQ(uriSetHostRegNameA(&uri, first, afterLast), URI_ERROR_NULL); +} + +TEST(SetHostRegName, NullValueLeavesOwnerAtFalse) { + UriUriA uri = parseWellFormedUri("scheme://host/"); + EXPECT_EQ(uri.owner, URI_FALSE); // self-test + + EXPECT_EQ(uriSetHostRegNameA(&uri, NULL, NULL), URI_SUCCESS); + + EXPECT_EQ(uri.owner, URI_FALSE); // i.e. still false + + uriFreeUriMembersA(&uri); +} + +TEST(SetHostRegName, NonNullValueMakesOwner) { + UriUriA uri = parseWellFormedUri("scheme://old/"); + const char * const first = "new"; + const char * const afterLast = first + strlen(first); + EXPECT_EQ(uri.owner, URI_FALSE); // self-test + + EXPECT_EQ(uriSetHostRegNameA(&uri, first, afterLast), URI_SUCCESS); + + EXPECT_EQ(uri.owner, URI_TRUE); // i.e. now owned + + uriFreeUriMembersA(&uri); +} + +TEST(SetHostRegName, NullValueAppliedDotInserted) { + UriUriA uri = parseWellFormedUri("scheme://host//path1/path2"); + + EXPECT_EQ(uriSetHostRegNameA(&uri, NULL, NULL), URI_SUCCESS); + + assertUriEqual(&uri, "scheme:/.//path1/path2"); // i.e. not scheme://path1/path2 + + uriFreeUriMembersA(&uri); +} + +TEST(SetHostRegName, NullValueAppliedDotNotInserted) { + UriUriA uri = parseWellFormedUri("//host/./path1/path2"); + + EXPECT_EQ(uriSetHostRegNameA(&uri, NULL, NULL), URI_SUCCESS); + + assertUriEqual(&uri, "/./path1/path2"); // i.e. not /././path1/path2 + + uriFreeUriMembersA(&uri); +} + +TEST(SetHostRegName, NullValueAppliedPriorNull) { + UriUriA uri = parseWellFormedUri("scheme:/path"); + + EXPECT_EQ(uriSetHostRegNameA(&uri, NULL, NULL), URI_SUCCESS); + + assertUriEqual(&uri, "scheme:/path"); + + uriFreeUriMembersA(&uri); +} + +TEST(SetHostRegName, NullValueAppliedPriorIp4) { + UriUriA uri = parseWellFormedUri("scheme://1.2.3.4/path"); + + EXPECT_EQ(uriSetHostRegNameA(&uri, NULL, NULL), URI_SUCCESS); + + assertUriEqual(&uri, "scheme:/path"); + + uriFreeUriMembersA(&uri); +} + +TEST(SetHostRegName, NullValueAppliedPriorIp6) { + UriUriA uri = parseWellFormedUri("scheme://[::1]/path"); + + EXPECT_EQ(uriSetHostRegNameA(&uri, NULL, NULL), URI_SUCCESS); + + assertUriEqual(&uri, "scheme:/path"); + + uriFreeUriMembersA(&uri); +} + +TEST(SetHostRegName, NullValueAppliedPriorIpFuture) { + UriUriA uri = parseWellFormedUri("scheme://[v7.host]/path"); + + EXPECT_EQ(uriSetHostRegNameA(&uri, NULL, NULL), URI_SUCCESS); + + assertUriEqual(&uri, "scheme:/path"); + + uriFreeUriMembersA(&uri); +} + +TEST(SetHostRegName, NullValueAppliedPriorRegName) { + UriUriA uri = parseWellFormedUri("scheme://host/path"); + + EXPECT_EQ(uriSetHostRegNameA(&uri, NULL, NULL), URI_SUCCESS); + + assertUriEqual(&uri, "scheme:/path"); + + uriFreeUriMembersA(&uri); +} + +TEST(SetHostRegName, NonNullValueAppliedEmpty) { + UriUriA uri = parseWellFormedUri("scheme://host/path"); + const char * const empty = ""; + + EXPECT_EQ(uriSetHostRegNameA(&uri, empty, empty), URI_SUCCESS); + + assertUriEqual(&uri, "scheme:///path"); + + uriFreeUriMembersA(&uri); +} + +TEST(SetHostRegName, NonNullValueAppliedNonEmptyPriorNull) { + UriUriA uri = parseWellFormedUri("scheme:"); + const char * const first = "localhost"; + const char * const afterLast = first + strlen(first); + + EXPECT_EQ(uriSetHostRegNameA(&uri, first, afterLast), URI_SUCCESS); + + assertUriEqual(&uri, "scheme://localhost"); + + uriFreeUriMembersA(&uri); +} + +TEST(SetHostRegName, NonNullValueAppliedNonEmptyPriorIp4) { + UriUriA uri = parseWellFormedUri("//1.2.3.4"); + const char * const first = "localhost"; + const char * const afterLast = first + strlen(first); + + EXPECT_EQ(uriSetHostRegNameA(&uri, first, afterLast), URI_SUCCESS); + + assertUriEqual(&uri, "//localhost"); + + uriFreeUriMembersA(&uri); +} + +TEST(SetHostRegName, NonNullValueAppliedNonEmptyPriorIp6) { + UriUriA uri = parseWellFormedUri("//[::1]"); + const char * const first = "localhost"; + const char * const afterLast = first + strlen(first); + + EXPECT_EQ(uriSetHostRegNameA(&uri, first, afterLast), URI_SUCCESS); + + assertUriEqual(&uri, "//localhost"); + + uriFreeUriMembersA(&uri); +} + +TEST(SetHostRegName, NonNullValueAppliedNonEmptyPriorIpFuture) { + UriUriA uri = parseWellFormedUri("//[v7.host]"); + const char * const first = "localhost"; + const char * const afterLast = first + strlen(first); + + EXPECT_EQ(uriSetHostRegNameA(&uri, first, afterLast), URI_SUCCESS); + + assertUriEqual(&uri, "//localhost"); + + uriFreeUriMembersA(&uri); +} + +TEST(SetHostRegName, NonNullValueAppliedNonEmptyPriorRegName) { + UriUriA uri = parseWellFormedUri("//hostname.test"); + const char * const first = "localhost"; + const char * const afterLast = first + strlen(first); + + EXPECT_EQ(uriSetHostRegNameA(&uri, first, afterLast), URI_SUCCESS); + + assertUriEqual(&uri, "//localhost"); + + uriFreeUriMembersA(&uri); +} + +TEST(SetHostRegName, MalformedValueRejected) { + UriUriA uri = parseWellFormedUri("scheme://host/"); + const char * const first = "not well-formed"; + const char * const afterLast = first + strlen(first); + + EXPECT_EQ(uriSetHostRegNameA(&uri, first, afterLast), URI_ERROR_SYNTAX); + + uriFreeUriMembersA(&uri); +} + +TEST(SetHostRegName, UriWithPortRejected) { + UriUriA uri = parseWellFormedUri("//host:1234"); + EXPECT_TRUE(uri.portText.first != NULL); // self-test + + EXPECT_EQ(uriSetHostRegNameA(&uri, NULL, NULL), URI_ERROR_SETHOST_PORT_SET); + + uriFreeUriMembersA(&uri); +} + +TEST(SetHostRegName, UriWithUserInfoRejected) { + UriUriA uri = parseWellFormedUri("//user:password@host"); + EXPECT_TRUE(uri.userInfo.first != NULL); // self-test + + EXPECT_EQ(uriSetHostRegNameA(&uri, NULL, NULL), URI_ERROR_SETHOST_USERINFO_SET); + + uriFreeUriMembersA(&uri); +} diff --git a/test/SetPath.cpp b/test/SetPath.cpp new file mode 100644 index 0000000..fcb971f --- /dev/null +++ b/test/SetPath.cpp @@ -0,0 +1,450 @@ +/* + * uriparser - RFC 3986 URI parsing library + * + * Copyright (C) 2025, Sebastian Pipping <sebastian@pipping.org> + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library 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 + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#undef NDEBUG // because we rely on assert(3) further down + +#include <cassert> + +#include <gtest/gtest.h> + +#include <uriparser/Uri.h> + +namespace { + +static void testIsWellFormedPath(const char * candidate, bool hasHost, + bool expectedWellFormed) { + const char * const first = candidate; + const char * const afterLast = + (candidate == NULL) ? NULL : (candidate + strlen(candidate)); + + const UriBool actualWellFormed = uriIsWellFormedPathA(first, afterLast, hasHost); + + ASSERT_EQ(actualWellFormed, expectedWellFormed); +} + +static UriUriA parseWellFormedUri(const char * text) { + UriUriA uri; + const int error = uriParseSingleUriA(&uri, text, NULL); + // NOTE: we cannot use ASSERT_EQ here because of the outer non-void return type + assert(error == URI_SUCCESS); + return uri; +} + +static void assertUriEqual(const UriUriA * uri, const char * expected) { + int charsRequired = -1; + ASSERT_EQ(uriToStringCharsRequiredA(uri, &charsRequired), URI_SUCCESS); + ASSERT_TRUE(charsRequired >= 0); + + char * const buffer = (char *)malloc(charsRequired + 1); + ASSERT_TRUE(buffer != NULL); + + ASSERT_EQ(uriToStringA(buffer, uri, charsRequired + 1, NULL), URI_SUCCESS); + + EXPECT_STREQ(buffer, expected); + + free(buffer); +} + +} // namespace + +TEST(IsWellFormedPath, Null) { + const bool hasHostValues[] = {true, false}; + for (size_t i = 0; i < sizeof(hasHostValues) / sizeof(hasHostValues[0]); i++) { + const UriBool hasHost = hasHostValues[i] ? URI_TRUE : URI_FALSE; + testIsWellFormedPath(NULL, hasHost, false); + } +} + +TEST(IsWellFormedPath, Empty) { + testIsWellFormedPath("", /* hasHost=*/true, false); + testIsWellFormedPath("", /* hasHost=*/false, true); +} + +TEST(IsWellFormedPath, NonEmptyWithoutLeadingSlash) { + testIsWellFormedPath("no-leading-slash", /* hasHost=*/true, false); + testIsWellFormedPath("no-leading-slash", /* hasHost=*/false, true); +} + +TEST(IsWellFormedPath, NonEmptySingleSlash) { + const bool hasHostValues[] = {true, false}; + for (size_t i = 0; i < sizeof(hasHostValues) / sizeof(hasHostValues[0]); i++) { + const UriBool hasHost = hasHostValues[i] ? URI_TRUE : URI_FALSE; + testIsWellFormedPath("/", hasHost, true); + } +} + +TEST(IsWellFormedPath, NonEmptyTwoSlashes) { + const bool hasHostValues[] = {true, false}; + for (size_t i = 0; i < sizeof(hasHostValues) / sizeof(hasHostValues[0]); i++) { + const UriBool hasHost = hasHostValues[i] ? URI_TRUE : URI_FALSE; + testIsWellFormedPath("//", hasHost, true); + } +} + +TEST(IsWellFormedPath, AllowedCharacters) { + // The (simplified) related grammar subset is this: + // + // path = *( unreserved / pct-encoded / sub-delims / ":" / "@" / "/" ) + // + // NOTE: Percent encoding has dedicated tests further down + const bool hasHostValues[] = {true, false}; + for (size_t i = 0; i < sizeof(hasHostValues) / sizeof(hasHostValues[0]); i++) { + const UriBool hasHost = hasHostValues[i] ? URI_TRUE : URI_FALSE; + testIsWellFormedPath("/" + "0123456789" + "ABCDEF" + "abcdef" + "gGhHiIjJkKlLmMnNoOpPqQrRsStTuUvVwWxXyYzZ" + "-._~" + "!$&'()*+,;=" + ":@", + hasHost, true); + } +} + +TEST(IsWellFormedPath, ForbiddenCharacters) { + const bool hasHostValues[] = {true, false}; + for (size_t i = 0; i < sizeof(hasHostValues) / sizeof(hasHostValues[0]); i++) { + const UriBool hasHost = hasHostValues[i] ? URI_TRUE : URI_FALSE; + testIsWellFormedPath("/ ", hasHost, false); + testIsWellFormedPath("/?", hasHost, false); + testIsWellFormedPath("/#", hasHost, false); + } +} + +TEST(IsWellFormedPath, PercentEncodingWellFormed) { + const bool hasHostValues[] = {true, false}; + for (size_t i = 0; i < sizeof(hasHostValues) / sizeof(hasHostValues[0]); i++) { + const UriBool hasHost = hasHostValues[i] ? URI_TRUE : URI_FALSE; + testIsWellFormedPath("/" + "%" + "aa" + "%" + "AA", + hasHost, true); + } +} + +TEST(IsWellFormedPath, PercentEncodingMalformedCutOff1) { + const bool hasHostValues[] = {true, false}; + for (size_t i = 0; i < sizeof(hasHostValues) / sizeof(hasHostValues[0]); i++) { + const UriBool hasHost = hasHostValues[i] ? URI_TRUE : URI_FALSE; + testIsWellFormedPath("/" + "%", + hasHost, false); + } +} + +TEST(IsWellFormedPath, PercentEncodingMalformedCutOff2) { + const bool hasHostValues[] = {true, false}; + for (size_t i = 0; i < sizeof(hasHostValues) / sizeof(hasHostValues[0]); i++) { + const UriBool hasHost = hasHostValues[i] ? URI_TRUE : URI_FALSE; + testIsWellFormedPath("/" + "%" + "a", + hasHost, false); + } +} + +TEST(IsWellFormedPath, PercentEncodingMalformedForbiddenCharacter1) { + const bool hasHostValues[] = {true, false}; + for (size_t i = 0; i < sizeof(hasHostValues) / sizeof(hasHostValues[0]); i++) { + const UriBool hasHost = hasHostValues[i] ? URI_TRUE : URI_FALSE; + testIsWellFormedPath("/" + "%" + "ga", + hasHost, false); + } +} + +TEST(IsWellFormedPath, PercentEncodingMalformedForbiddenCharacter2) { + const bool hasHostValues[] = {true, false}; + for (size_t i = 0; i < sizeof(hasHostValues) / sizeof(hasHostValues[0]); i++) { + const UriBool hasHost = hasHostValues[i] ? URI_TRUE : URI_FALSE; + testIsWellFormedPath("/" + "%" + "ag", + hasHost, false); + } +} + +TEST(SetPath, NullUriOnly) { + UriUriA * const uri = NULL; + const char * const first = "path1/path2"; + const char * const afterLast = first + strlen(first); + ASSERT_EQ(uriSetPathA(uri, first, afterLast), URI_ERROR_NULL); +} + +TEST(SetPath, NullFirstOnly) { + UriUriA uri = {}; + const char * const path = "path1/path2"; + const char * const first = NULL; + const char * const afterLast = path + strlen(path); + ASSERT_EQ(uriSetPathA(&uri, first, afterLast), URI_ERROR_NULL); +} + +TEST(SetPath, NullAfterLastOnly) { + UriUriA uri = {}; + const char * const first = "path1/path2"; + const char * const afterLast = NULL; + ASSERT_EQ(uriSetPathA(&uri, first, afterLast), URI_ERROR_NULL); +} + +TEST(SetPath, NullValueLeavesOwnerAtFalse) { + UriUriA uri = parseWellFormedUri("/path"); + EXPECT_EQ(uri.owner, URI_FALSE); // self-test + + EXPECT_EQ(uriSetPathA(&uri, NULL, NULL), URI_SUCCESS); + + EXPECT_EQ(uri.owner, URI_FALSE); // i.e. still false + + uriFreeUriMembersA(&uri); +} + +TEST(SetPath, NonNullValueMakesOwner) { + UriUriA uri = parseWellFormedUri("//host/old"); + const char * const first = "/new"; + const char * const afterLast = first + strlen(first); + EXPECT_EQ(uri.owner, URI_FALSE); // self-test + + EXPECT_EQ(uriSetPathA(&uri, first, afterLast), URI_SUCCESS); + + EXPECT_EQ(uri.owner, URI_TRUE); // i.e. now owned + + uriFreeUriMembersA(&uri); +} + +TEST(SetPath, NullValueAppliedWithHost) { + UriUriA uri = parseWellFormedUri("//host/path"); + + EXPECT_EQ(uriSetPathA(&uri, NULL, NULL), URI_SUCCESS); + + assertUriEqual(&uri, "//host"); + + uriFreeUriMembersA(&uri); +} + +TEST(SetPath, NullValueAppliedWithoutHost) { + UriUriA uri = parseWellFormedUri("scheme:/path"); + + EXPECT_EQ(uriSetPathA(&uri, NULL, NULL), URI_SUCCESS); + + assertUriEqual(&uri, "scheme:"); + + uriFreeUriMembersA(&uri); +} + +TEST(SetPath, NonNullValueAppliedSingleSlashWithHost) { + UriUriA uri = parseWellFormedUri("//host/path"); + const char * const first = "/"; + const char * const afterLast = first + strlen(first); + + EXPECT_EQ(uriSetPathA(&uri, first, afterLast), URI_SUCCESS); + + assertUriEqual(&uri, "//host/"); + EXPECT_EQ(uri.absolutePath, URI_FALSE); // always false for URIs with host + + uriFreeUriMembersA(&uri); +} + +TEST(SetPath, NonNullValueAppliedSingleSlashWithoutHost) { + UriUriA uri = parseWellFormedUri("scheme:path"); + const char * const first = "/"; + const char * const afterLast = first + strlen(first); + + EXPECT_EQ(uriSetPathA(&uri, first, afterLast), URI_SUCCESS); + + assertUriEqual(&uri, "scheme:/"); + EXPECT_EQ(uri.absolutePath, URI_TRUE); + + uriFreeUriMembersA(&uri); +} + +TEST(SetPath, NonNullValueAppliedTwoSlashesWithHost) { + UriUriA uri = parseWellFormedUri("//host/path"); + const char * const first = "//"; + const char * const afterLast = first + strlen(first); + + EXPECT_EQ(uriSetPathA(&uri, first, afterLast), URI_SUCCESS); + + assertUriEqual(&uri, "//host//"); + EXPECT_EQ(uri.absolutePath, URI_FALSE); // always false for URIs with host + + uriFreeUriMembersA(&uri); +} + +TEST(SetPath, NonNullValueAppliedTwoSlashesWithoutHostDotInserted) { + UriUriA uri = parseWellFormedUri("scheme:path"); + const char * const first = "//"; + const char * const afterLast = first + strlen(first); + + EXPECT_EQ(uriSetPathA(&uri, first, afterLast), URI_SUCCESS); + + assertUriEqual(&uri, "scheme:/.//"); // i.e. not scheme:// + EXPECT_EQ(uri.absolutePath, URI_TRUE); + + uriFreeUriMembersA(&uri); +} + +TEST(SetPath, NonNullValueAppliedThreeSlashesWithHost) { + UriUriA uri = parseWellFormedUri("//host/path"); + const char * const first = "///"; + const char * const afterLast = first + strlen(first); + + EXPECT_EQ(uriSetPathA(&uri, first, afterLast), URI_SUCCESS); + + assertUriEqual(&uri, "//host///"); + EXPECT_EQ(uri.absolutePath, URI_FALSE); // always false for URIs with host + + uriFreeUriMembersA(&uri); +} + +TEST(SetPath, NonNullValueAppliedThreeSlashesWithoutHostDotInserted) { + UriUriA uri = parseWellFormedUri("scheme:path"); + const char * const first = "///"; + const char * const afterLast = first + strlen(first); + + EXPECT_EQ(uriSetPathA(&uri, first, afterLast), URI_SUCCESS); + + assertUriEqual(&uri, "scheme:/.///"); // i.e. not scheme:/// + EXPECT_EQ(uri.absolutePath, URI_TRUE); + + uriFreeUriMembersA(&uri); +} + +TEST(SetPath, NonNullValueAppliedEmptyWithHost) { + UriUriA uri = parseWellFormedUri("//host/path"); + const char * const empty = ""; + + EXPECT_EQ(uriSetPathA(&uri, empty, empty), URI_ERROR_SYNTAX); + + uriFreeUriMembersA(&uri); +} + +TEST(SetPath, NonNullValueAppliedEmptyWithoutHost) { + UriUriA uri = parseWellFormedUri("scheme:path"); + const char * const empty = ""; + + EXPECT_EQ(uriSetPathA(&uri, empty, empty), URI_SUCCESS); + + assertUriEqual(&uri, "scheme:"); + EXPECT_TRUE(uri.pathHead == NULL); + EXPECT_TRUE(uri.pathTail == NULL); + + uriFreeUriMembersA(&uri); +} + +TEST(SetPath, NonNullValueAppliedNonEmptyWithEmptyHost) { + UriUriA uri = parseWellFormedUri("file:///old1/old2"); + const char * const first = "/new1/new2"; + const char * const afterLast = first + strlen(first); + + EXPECT_EQ(uriSetPathA(&uri, first, afterLast), URI_SUCCESS); + + assertUriEqual(&uri, "file:///new1/new2"); + EXPECT_EQ(uri.absolutePath, URI_FALSE); // always false for URIs with host + + uriFreeUriMembersA(&uri); +} + +TEST(SetPath, NonNullValueAppliedNonEmptyWithNonEmptyHost) { + UriUriA uri = parseWellFormedUri("//host/old1/old2"); + const char * const first = "/new1/new2"; + const char * const afterLast = first + strlen(first); + + EXPECT_EQ(uriSetPathA(&uri, first, afterLast), URI_SUCCESS); + + assertUriEqual(&uri, "//host/new1/new2"); + EXPECT_EQ(uri.absolutePath, URI_FALSE); // always false for URIs with host + + uriFreeUriMembersA(&uri); +} + +TEST(SetPath, NonNullValueAppliedNonEmptyWithoutHostRel) { + UriUriA uri = parseWellFormedUri("/old1/old2"); + const char * const first = "new1/new2"; + const char * const afterLast = first + strlen(first); + + EXPECT_EQ(uriSetPathA(&uri, first, afterLast), URI_SUCCESS); + + assertUriEqual(&uri, "new1/new2"); + + uriFreeUriMembersA(&uri); +} + +TEST(SetPath, NonNullValueAppliedNonEmptyWithoutHostRelDotInserted) { + UriUriA uri = parseWellFormedUri("/old1/old2"); + const char * const first = "path1:/path2"; + const char * const afterLast = first + strlen(first); + + EXPECT_EQ(uriSetPathA(&uri, first, afterLast), URI_SUCCESS); + + assertUriEqual(&uri, "./path1:/path2"); // i.e. not path1:/path2 + + uriFreeUriMembersA(&uri); +} + +TEST(SetPath, NonNullValueAppliedNonEmptyWithoutHostAbs) { + UriUriA uri = parseWellFormedUri("old1/old2"); + const char * const first = "/new1/new2"; + const char * const afterLast = first + strlen(first); + + EXPECT_EQ(uriSetPathA(&uri, first, afterLast), URI_SUCCESS); + + assertUriEqual(&uri, "/new1/new2"); + EXPECT_EQ(uri.absolutePath, URI_TRUE); + + uriFreeUriMembersA(&uri); +} + +TEST(SetPath, NonNullValueAppliedNonEmptyWithoutHostAbsDotInserted) { + UriUriA uri = parseWellFormedUri("old1/old2"); + const char * const first = "//path1/path2"; + const char * const afterLast = first + strlen(first); + + EXPECT_EQ(uriSetPathA(&uri, first, afterLast), URI_SUCCESS); + + assertUriEqual(&uri, "/.//path1/path2"); // i.e. not //path1/path2 + EXPECT_EQ(uri.absolutePath, URI_TRUE); + + uriFreeUriMembersA(&uri); +} + +TEST(SetPath, NonNullValueAppliedNonEmptyWithoutHostWithScheme) { + UriUriA uri = parseWellFormedUri("scheme:"); + const char * const first = "path1:/path2/path3"; + const char * const afterLast = first + strlen(first); + + EXPECT_EQ(uriSetPathA(&uri, first, afterLast), URI_SUCCESS); + + assertUriEqual(&uri, "scheme:path1:/path2/path3"); + + uriFreeUriMembersA(&uri); +} + +TEST(SetPath, MalformedValueRejected) { + UriUriA uri = parseWellFormedUri("/path"); + const char * const first = "not well-formed"; + const char * const afterLast = first + strlen(first); + + EXPECT_EQ(uriSetPathA(&uri, first, afterLast), URI_ERROR_SYNTAX); + + uriFreeUriMembersA(&uri); +} diff --git a/test/SetPort.cpp b/test/SetPort.cpp new file mode 100644 index 0000000..d27361c --- /dev/null +++ b/test/SetPort.cpp @@ -0,0 +1,191 @@ +/* + * uriparser - RFC 3986 URI parsing library + * + * Copyright (C) 2025, Sebastian Pipping <sebastian@pipping.org> + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library 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 + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#undef NDEBUG // because we rely on assert(3) further down + +#include <cassert> + +#include <gtest/gtest.h> + +#include <uriparser/Uri.h> + +namespace { + +static void testIsWellFormedPort(const char * candidate, bool expectedWellFormed) { + const char * const first = candidate; + const char * const afterLast = + (candidate == NULL) ? NULL : (candidate + strlen(candidate)); + + const UriBool actualWellFormed = uriIsWellFormedPortA(first, afterLast); + + ASSERT_EQ(actualWellFormed, expectedWellFormed); +} + +static UriUriA parseWellFormedUri(const char * text) { + UriUriA uri; + const int error = uriParseSingleUriA(&uri, text, NULL); + // NOTE: we cannot use ASSERT_EQ here because of the outer non-void return type + assert(error == URI_SUCCESS); + return uri; +} + +static void assertUriEqual(const UriUriA * uri, const char * expected) { + int charsRequired = -1; + ASSERT_EQ(uriToStringCharsRequiredA(uri, &charsRequired), URI_SUCCESS); + ASSERT_TRUE(charsRequired >= 0); + + char * const buffer = (char *)malloc(charsRequired + 1); + ASSERT_TRUE(buffer != NULL); + + ASSERT_EQ(uriToStringA(buffer, uri, charsRequired + 1, NULL), URI_SUCCESS); + + EXPECT_STREQ(buffer, expected); + + free(buffer); +} + +} // namespace + +TEST(IsWellFormedPort, Null) { + testIsWellFormedPort(NULL, false); +} + +TEST(IsWellFormedPort, Empty) { + testIsWellFormedPort("", true); +} + +TEST(IsWellFormedPort, AllowedCharacters) { + testIsWellFormedPort("0123456789", true); +} + +TEST(IsWellFormedPort, ForbiddenCharacters) { + testIsWellFormedPort(" ", false); +} + +TEST(SetPortText, NullUriOnly) { + UriUriA * const uri = NULL; + const char * const first = "443"; + const char * const afterLast = first + strlen(first); + ASSERT_EQ(uriSetPortTextA(uri, first, afterLast), URI_ERROR_NULL); +} + +TEST(SetPortText, NullFirstOnly) { + UriUriA uri = {}; + const char * const postText = "443"; + const char * const first = NULL; + const char * const afterLast = postText + strlen(postText); + ASSERT_EQ(uriSetPortTextA(&uri, first, afterLast), URI_ERROR_NULL); +} + +TEST(SetPortText, NullAfterLastOnly) { + UriUriA uri = {}; + const char * const first = "443"; + const char * const afterLast = NULL; + ASSERT_EQ(uriSetPortTextA(&uri, first, afterLast), URI_ERROR_NULL); +} + +TEST(SetPortText, NullValueLeavesOwnerAtFalse) { + UriUriA uri = parseWellFormedUri("https://host:443/"); + EXPECT_EQ(uri.owner, URI_FALSE); // self-test + + EXPECT_EQ(uriSetPortTextA(&uri, NULL, NULL), URI_SUCCESS); + + EXPECT_EQ(uri.owner, URI_FALSE); // i.e. still false + + uriFreeUriMembersA(&uri); +} + +TEST(SetPortText, NonNullValueMakesOwner) { + UriUriA uri = parseWellFormedUri("https://host:443/"); + const char * const first = "50443"; + const char * const afterLast = first + strlen(first); + EXPECT_EQ(uri.owner, URI_FALSE); // self-test + + EXPECT_EQ(uriSetPortTextA(&uri, first, afterLast), URI_SUCCESS); + + EXPECT_EQ(uri.owner, URI_TRUE); // i.e. now owned + + uriFreeUriMembersA(&uri); +} + +TEST(SetPortText, NullValueApplied) { + UriUriA uri = parseWellFormedUri("https://host:443/"); + + EXPECT_EQ(uriSetPortTextA(&uri, NULL, NULL), URI_SUCCESS); + + assertUriEqual(&uri, "https://host/"); + + uriFreeUriMembersA(&uri); +} + +TEST(SetPortText, NonNullValueAppliedEmpty) { + UriUriA uri = parseWellFormedUri("https://host:443/"); + const char * const empty = ""; + + EXPECT_EQ(uriSetPortTextA(&uri, empty, empty), URI_SUCCESS); + + assertUriEqual(&uri, "https://host:/"); + + uriFreeUriMembersA(&uri); +} + +TEST(SetPortText, NonNullValueAppliedNonEmpty) { + UriUriA uri = parseWellFormedUri("https://host:443/"); + const char * const first = "50443"; + const char * const afterLast = first + strlen(first); + + EXPECT_EQ(uriSetPortTextA(&uri, first, afterLast), URI_SUCCESS); + + assertUriEqual(&uri, "https://host:50443/"); + + uriFreeUriMembersA(&uri); +} + +TEST(SetPortText, MalformedValueRejected) { + UriUriA uri = parseWellFormedUri("https://host:443/"); + const char * const first = "not well-formed"; + const char * const afterLast = first + strlen(first); + + EXPECT_EQ(uriSetPortTextA(&uri, first, afterLast), URI_ERROR_SYNTAX); + + uriFreeUriMembersA(&uri); +} + +TEST(SetPortText, UriWithoutHostNullTolerated) { + const char * originalText = "/no/host/here"; + UriUriA uri = parseWellFormedUri(originalText); + + EXPECT_EQ(uriSetPortTextA(&uri, NULL, NULL), URI_SUCCESS); + + assertUriEqual(&uri, originalText); + + uriFreeUriMembersA(&uri); +} + +TEST(SetPortText, UriWithoutHostNonNullRejected) { + UriUriA uri = parseWellFormedUri("/no/host/here"); + const char * const first = "443"; + const char * const afterLast = first + strlen(first); + EXPECT_TRUE(uri.hostText.first == NULL); // self-test + + EXPECT_EQ(uriSetPortTextA(&uri, first, afterLast), URI_ERROR_SETPORT_HOST_NOT_SET); + + uriFreeUriMembersA(&uri); +} diff --git a/test/SetQuery.cpp b/test/SetQuery.cpp new file mode 100644 index 0000000..3a69d17 --- /dev/null +++ b/test/SetQuery.cpp @@ -0,0 +1,231 @@ +/* + * uriparser - RFC 3986 URI parsing library + * + * Copyright (C) 2025, Sebastian Pipping <sebastian@pipping.org> + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library 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 + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#undef NDEBUG // because we rely on assert(3) further down + +#include <cassert> + +#include <gtest/gtest.h> + +#include <uriparser/Uri.h> + +namespace { + +static void testIsWellFormedQuery(const char * candidate, bool expectedWellFormed) { + const char * const first = candidate; + const char * const afterLast = + (candidate == NULL) ? NULL : (candidate + strlen(candidate)); + + const UriBool actualWellFormed = uriIsWellFormedQueryA(first, afterLast); + + ASSERT_EQ(actualWellFormed, expectedWellFormed); +} + +static UriUriA parseWellFormedUri(const char * text) { + UriUriA uri; + const int error = uriParseSingleUriA(&uri, text, NULL); + // NOTE: we cannot use ASSERT_EQ here because of the outer non-void return type + assert(error == URI_SUCCESS); + return uri; +} + +static void assertUriEqual(const UriUriA * uri, const char * expected) { + int charsRequired = -1; + ASSERT_EQ(uriToStringCharsRequiredA(uri, &charsRequired), URI_SUCCESS); + ASSERT_TRUE(charsRequired >= 0); + + char * const buffer = (char *)malloc(charsRequired + 1); + ASSERT_TRUE(buffer != NULL); + + ASSERT_EQ(uriToStringA(buffer, uri, charsRequired + 1, NULL), URI_SUCCESS); + + EXPECT_STREQ(buffer, expected); + + free(buffer); +} + +} // namespace + +TEST(IsWellFormedQuery, Null) { + testIsWellFormedQuery(NULL, false); +} + +TEST(IsWellFormedQuery, Empty) { + testIsWellFormedQuery("", true); +} + +TEST(IsWellFormedQuery, AllowedCharacters) { + // The related grammar subset is this: + // + // query = *( pchar / "/" / "?" ) + // pchar = unreserved / pct-encoded / sub-delims / ":" / "@" + // unreserved = ALPHA / DIGIT / "-" / "." / "_" / "~" + // pct-encoded = "%" HEXDIG HEXDIG + // sub-delims = "!" / "$" / "&" / "'" / "(" / ")" + // / "*" / "+" / "," / ";" / "=" + // + // NOTE: Percent encoding has dedicated tests further down + testIsWellFormedQuery("0123456789" + "ABCDEF" + "abcdef" + "gGhHiIjJkKlLmMnNoOpPqQrRsStTuUvVwWxXyYzZ" + "-._~" + "!$&'()*+,;=" + ":@" + "/?", + true); +} + +TEST(IsWellFormedQuery, ForbiddenCharacters) { + testIsWellFormedQuery(" ", false); + testIsWellFormedQuery("#", false); +} + +TEST(IsWellFormedQuery, PercentEncodingWellFormed) { + testIsWellFormedQuery("%" + "aa" + "%" + "AA", + true); +} + +TEST(IsWellFormedQuery, PercentEncodingMalformedCutOff1) { + testIsWellFormedQuery("%", false); +} + +TEST(IsWellFormedQuery, PercentEncodingMalformedCutOff2) { + testIsWellFormedQuery("%" + "a", + false); +} + +TEST(IsWellFormedQuery, PercentEncodingMalformedForbiddenCharacter1) { + testIsWellFormedQuery("%" + "ga", + false); +} + +TEST(IsWellFormedQuery, PercentEncodingMalformedForbiddenCharacter2) { + testIsWellFormedQuery("%" + "ag", + false); +} + +TEST(SetQuery, NullUriOnly) { + UriUriA * const uri = NULL; + const char * const first = "k1=v1"; + const char * const afterLast = first + strlen(first); + ASSERT_EQ(uriSetQueryA(uri, first, afterLast), URI_ERROR_NULL); +} + +TEST(SetQuery, NullFirstOnly) { + UriUriA uri = {}; + const char * const query = "k1=v1"; + const char * const first = NULL; + const char * const afterLast = query + strlen(query); + ASSERT_EQ(uriSetQueryA(&uri, first, afterLast), URI_ERROR_NULL); +} + +TEST(SetQuery, NullAfterLastOnly) { + UriUriA uri = {}; + const char * const first = "k1=v1"; + const char * const afterLast = NULL; + ASSERT_EQ(uriSetQueryA(&uri, first, afterLast), URI_ERROR_NULL); +} + +TEST(SetQuery, NullValueLeavesOwnerAtFalse) { + UriUriA uri = parseWellFormedUri("scheme://host/?query"); + EXPECT_EQ(uri.owner, URI_FALSE); // self-test + + EXPECT_EQ(uriSetQueryA(&uri, NULL, NULL), URI_SUCCESS); + + EXPECT_EQ(uri.owner, URI_FALSE); // i.e. still false + + uriFreeUriMembersA(&uri); +} + +TEST(SetQuery, NonNullValueMakesOwner) { + UriUriA uri = parseWellFormedUri("scheme://host/?old"); + const char * const first = "new"; + const char * const afterLast = first + strlen(first); + EXPECT_EQ(uri.owner, URI_FALSE); // self-test + + EXPECT_EQ(uriSetQueryA(&uri, first, afterLast), URI_SUCCESS); + + EXPECT_EQ(uri.owner, URI_TRUE); // i.e. now owned + + uriFreeUriMembersA(&uri); +} + +TEST(SetQuery, NullValueApplied) { + UriUriA uri = parseWellFormedUri("scheme://host/?query"); + + EXPECT_EQ(uriSetQueryA(&uri, NULL, NULL), URI_SUCCESS); + + assertUriEqual(&uri, "scheme://host/"); + + uriFreeUriMembersA(&uri); +} + +TEST(SetQuery, NonNullValueAppliedEmpty) { + UriUriA uri = parseWellFormedUri("scheme://host/?query"); + const char * const empty = ""; + + EXPECT_EQ(uriSetQueryA(&uri, empty, empty), URI_SUCCESS); + + assertUriEqual(&uri, "scheme://host/?"); + + uriFreeUriMembersA(&uri); +} + +TEST(SetQuery, NonNullValueAppliedNonEmpty) { + UriUriA uri = parseWellFormedUri("scheme://host/?old"); + const char * const first = "new"; + const char * const afterLast = first + strlen(first); + + EXPECT_EQ(uriSetQueryA(&uri, first, afterLast), URI_SUCCESS); + + assertUriEqual(&uri, "scheme://host/?new"); + + uriFreeUriMembersA(&uri); +} + +TEST(SetQuery, MalformedValueRejected) { + UriUriA uri = parseWellFormedUri("scheme://host/?query"); + const char * const first = "not well-formed"; + const char * const afterLast = first + strlen(first); + + EXPECT_EQ(uriSetQueryA(&uri, first, afterLast), URI_ERROR_SYNTAX); + + uriFreeUriMembersA(&uri); +} + +TEST(SetQuery, UriWithoutHostTolerated) { + UriUriA uri = parseWellFormedUri("/no/host/here"); + const char * const first = "k1=v1"; + const char * const afterLast = first + strlen(first); + EXPECT_TRUE(uri.hostText.first == NULL); // self-test + + EXPECT_EQ(uriSetQueryA(&uri, first, afterLast), URI_SUCCESS); + + assertUriEqual(&uri, "/no/host/here?k1=v1"); + + uriFreeUriMembersA(&uri); +} diff --git a/test/SetScheme.cpp b/test/SetScheme.cpp new file mode 100644 index 0000000..a609ab7 --- /dev/null +++ b/test/SetScheme.cpp @@ -0,0 +1,230 @@ +/* + * uriparser - RFC 3986 URI parsing library + * + * Copyright (C) 2025, Sebastian Pipping <sebastian@pipping.org> + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library 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 + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#undef NDEBUG // because we rely on assert(3) further down + +#include <cassert> + +#include <gtest/gtest.h> + +#include <uriparser/Uri.h> + +namespace { + +static void testIsWellFormedScheme(const char * candidate, bool expectedWellFormed) { + const char * const first = candidate; + const char * const afterLast = + (candidate == NULL) ? NULL : (candidate + strlen(candidate)); + + const UriBool actualWellFormed = uriIsWellFormedSchemeA(first, afterLast); + + ASSERT_EQ(actualWellFormed, expectedWellFormed); +} + +static UriUriA parseWellFormedUri(const char * text) { + UriUriA uri; + const int error = uriParseSingleUriA(&uri, text, NULL); + // NOTE: we cannot use ASSERT_EQ here because of the outer non-void return type + assert(error == URI_SUCCESS); + return uri; +} + +static void assertUriEqual(const UriUriA * uri, const char * expected) { + int charsRequired = -1; + ASSERT_EQ(uriToStringCharsRequiredA(uri, &charsRequired), URI_SUCCESS); + ASSERT_TRUE(charsRequired >= 0); + + char * const buffer = (char *)malloc(charsRequired + 1); + ASSERT_TRUE(buffer != NULL); + + ASSERT_EQ(uriToStringA(buffer, uri, charsRequired + 1, NULL), URI_SUCCESS); + + EXPECT_STREQ(buffer, expected); + + free(buffer); +} + +} // namespace + +TEST(IsWellFormedScheme, Null) { + testIsWellFormedScheme(NULL, false); +} + +TEST(IsWellFormedScheme, Empty) { + testIsWellFormedScheme("", false); +} + +TEST(IsWellFormedScheme, AllowedCharacters) { + // The related grammar subset is this: + // + // scheme = ALPHA *( ALPHA / DIGIT / "+" / "-" / "." ) + // + testIsWellFormedScheme("ABCDEF" + "abcdef" + "gGhHiIjJkKlLmMnNoOpPqQrRsStTuUvVwWxXyYzZ" + "0123456789" + "+-.", + true); +} + +TEST(IsWellFormedScheme, ForbiddenCharacters) { + testIsWellFormedScheme(" ", false); +} + +TEST(SetScheme, NullUriOnly) { + UriUriA * const uri = NULL; + const char * const first = "ssh"; + const char * const afterLast = first + strlen(first); + ASSERT_EQ(uriSetSchemeA(uri, first, afterLast), URI_ERROR_NULL); +} + +TEST(SetScheme, NullFirstOnly) { + UriUriA uri = {}; + const char * const scheme = "ssh"; + const char * const first = NULL; + const char * const afterLast = scheme + strlen(scheme); + ASSERT_EQ(uriSetSchemeA(&uri, first, afterLast), URI_ERROR_NULL); +} + +TEST(SetScheme, NullAfterLastOnly) { + UriUriA uri = {}; + const char * const first = "ssh"; + const char * const afterLast = NULL; + ASSERT_EQ(uriSetSchemeA(&uri, first, afterLast), URI_ERROR_NULL); +} + +TEST(SetScheme, NullValueLeavesOwnerAtFalse) { + UriUriA uri = parseWellFormedUri("scheme://"); + EXPECT_EQ(uri.owner, URI_FALSE); // self-test + + EXPECT_EQ(uriSetSchemeA(&uri, NULL, NULL), URI_SUCCESS); + + EXPECT_EQ(uri.owner, URI_FALSE); // i.e. still false + + uriFreeUriMembersA(&uri); +} + +TEST(SetScheme, NonNullValueMakesOwner) { + UriUriA uri = parseWellFormedUri("//host/"); + const char * const first = "ssh"; + const char * const afterLast = first + strlen(first); + EXPECT_EQ(uri.owner, URI_FALSE); // self-test + + EXPECT_EQ(uriSetSchemeA(&uri, first, afterLast), URI_SUCCESS); + + EXPECT_EQ(uri.owner, URI_TRUE); // i.e. now owned + + uriFreeUriMembersA(&uri); +} + +TEST(SetScheme, NullValueAppliedHost) { + UriUriA uri = parseWellFormedUri("ssh://host/"); + + EXPECT_EQ(uriSetSchemeA(&uri, NULL, NULL), URI_SUCCESS); + + assertUriEqual(&uri, "//host/"); + + uriFreeUriMembersA(&uri); +} + +TEST(SetScheme, NullValueAppliedPathWithoutColon) { + UriUriA uri = parseWellFormedUri("scheme:path1/path2/path3"); + + EXPECT_EQ(uriSetSchemeA(&uri, NULL, NULL), URI_SUCCESS); + + assertUriEqual(&uri, "path1/path2/path3"); + + uriFreeUriMembersA(&uri); +} + +TEST(SetScheme, NullValueAppliedPathWithColonRelativeDotPrepended) { + UriUriA uri = parseWellFormedUri("scheme:path1:/path2/path3"); + + EXPECT_EQ(uriSetSchemeA(&uri, NULL, NULL), URI_SUCCESS); + + assertUriEqual(&uri, "./path1:/path2/path3"); // i.e. not path1:/path2/path3 + + uriFreeUriMembersA(&uri); +} + +TEST(SetScheme, NullValueAppliedPathWithColonRelativeDotNotPrepended) { + UriUriA uri = parseWellFormedUri("scheme:path1/path2:/path3"); + + EXPECT_EQ(uriSetSchemeA(&uri, NULL, NULL), URI_SUCCESS); + + assertUriEqual(&uri, "path1/path2:/path3"); // i.e. not ./path1/path2:/path3 + + uriFreeUriMembersA(&uri); +} + +TEST(SetScheme, NullValueAppliedPathWithColonAbsolute) { + UriUriA uri = parseWellFormedUri("scheme:/path1:/path2/path3"); + + EXPECT_EQ(uriSetSchemeA(&uri, NULL, NULL), URI_SUCCESS); + + assertUriEqual(&uri, "/path1:/path2/path3"); + + uriFreeUriMembersA(&uri); +} + +TEST(SetScheme, NullValueAppliedPathWithColonAndHost) { + UriUriA uri = parseWellFormedUri("scheme://host/path1:/path2/path3"); + + EXPECT_EQ(uriSetSchemeA(&uri, NULL, NULL), URI_SUCCESS); + + assertUriEqual(&uri, "//host/path1:/path2/path3"); + + uriFreeUriMembersA(&uri); +} + +TEST(SetScheme, NonNullValueApplied) { + UriUriA uri = parseWellFormedUri("old://host/"); + const char * const first = "new"; + const char * const afterLast = first + strlen(first); + + EXPECT_EQ(uriSetSchemeA(&uri, first, afterLast), URI_SUCCESS); + + assertUriEqual(&uri, "new://host/"); + + uriFreeUriMembersA(&uri); +} + +TEST(SetScheme, MalformedValueRejected) { + UriUriA uri = parseWellFormedUri("scheme://host/"); + const char * const first = "not well-formed"; + const char * const afterLast = first + strlen(first); + + EXPECT_EQ(uriSetSchemeA(&uri, first, afterLast), URI_ERROR_SYNTAX); + + uriFreeUriMembersA(&uri); +} + +TEST(SetScheme, UriWithoutHostTolerated) { + UriUriA uri = parseWellFormedUri("/no/host/here"); + const char * const first = "scheme"; + const char * const afterLast = first + strlen(first); + EXPECT_TRUE(uri.hostText.first == NULL); // self-test + + EXPECT_EQ(uriSetSchemeA(&uri, first, afterLast), URI_SUCCESS); + + assertUriEqual(&uri, "scheme:/no/host/here"); + + uriFreeUriMembersA(&uri); +} diff --git a/test/SetUserInfo.cpp b/test/SetUserInfo.cpp new file mode 100644 index 0000000..304e8af --- /dev/null +++ b/test/SetUserInfo.cpp @@ -0,0 +1,238 @@ +/* + * uriparser - RFC 3986 URI parsing library + * + * Copyright (C) 2025, Sebastian Pipping <sebastian@pipping.org> + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library 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 + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#undef NDEBUG // because we rely on assert(3) further down + +#include <cassert> + +#include <gtest/gtest.h> + +#include <uriparser/Uri.h> + +namespace { + +static void testIsWellFormedUserInfo(const char * candidate, bool expectedWellFormed) { + const char * const first = candidate; + const char * const afterLast = + (candidate == NULL) ? NULL : (candidate + strlen(candidate)); + + const UriBool actualWellFormed = uriIsWellFormedUserInfoA(first, afterLast); + + ASSERT_EQ(actualWellFormed, expectedWellFormed); +} + +static UriUriA parseWellFormedUri(const char * text) { + UriUriA uri; + const int error = uriParseSingleUriA(&uri, text, NULL); + // NOTE: we cannot use ASSERT_EQ here because of the outer non-void return type + assert(error == URI_SUCCESS); + return uri; +} + +static void assertUriEqual(const UriUriA * uri, const char * expected) { + int charsRequired = -1; + ASSERT_EQ(uriToStringCharsRequiredA(uri, &charsRequired), URI_SUCCESS); + ASSERT_TRUE(charsRequired >= 0); + + char * const buffer = (char *)malloc(charsRequired + 1); + ASSERT_TRUE(buffer != NULL); + + ASSERT_EQ(uriToStringA(buffer, uri, charsRequired + 1, NULL), URI_SUCCESS); + + EXPECT_STREQ(buffer, expected); + + free(buffer); +} + +} // namespace + +TEST(IsWellFormedUserInfo, Null) { + testIsWellFormedUserInfo(NULL, false); +} + +TEST(IsWellFormedUserInfo, Empty) { + testIsWellFormedUserInfo("", true); +} + +TEST(IsWellFormedUserInfo, AllowedCharacters) { + // The related grammar subset is this: + // + // userinfo = *( unreserved / pct-encoded / sub-delims / ":" ) + // unreserved = ALPHA / DIGIT / "-" / "." / "_" / "~" + // pct-encoded = "%" HEXDIG HEXDIG + // sub-delims = "!" / "$" / "&" / "'" / "(" / ")" + // / "*" / "+" / "," / ";" / "=" + // + // NOTE: Percent encoding has dedicated tests further down + testIsWellFormedUserInfo("0123456789" + "ABCDEF" + "abcdef" + "gGhHiIjJkKlLmMnNoOpPqQrRsStTuUvVwWxXyYzZ" + "-._~" + "!$&'()*+,;=" + ":", + true); +} + +TEST(IsWellFormedUserInfo, ForbiddenCharacters) { + testIsWellFormedUserInfo(" ", false); +} + +TEST(IsWellFormedUserInfo, PercentEncodingWellFormed) { + testIsWellFormedUserInfo("%" + "aa" + "%" + "AA", + true); +} + +TEST(IsWellFormedUserInfo, PercentEncodingMalformedCutOff1) { + testIsWellFormedUserInfo("%", false); +} + +TEST(IsWellFormedUserInfo, PercentEncodingMalformedCutOff2) { + testIsWellFormedUserInfo("%" + "a", + false); +} + +TEST(IsWellFormedUserInfo, PercentEncodingMalformedForbiddenCharacter1) { + testIsWellFormedUserInfo("%" + "ga", + false); +} + +TEST(IsWellFormedUserInfo, PercentEncodingMalformedForbiddenCharacter2) { + testIsWellFormedUserInfo("%" + "ag", + false); +} + +TEST(SetUserInfo, NullUriOnly) { + UriUriA * const uri = NULL; + const char * const first = "user:password"; + const char * const afterLast = first + strlen(first); + ASSERT_EQ(uriSetUserInfoA(uri, first, afterLast), URI_ERROR_NULL); +} + +TEST(SetUserInfo, NullFirstOnly) { + UriUriA uri = {}; + const char * const userInfo = "user:password"; + const char * const first = NULL; + const char * const afterLast = userInfo + strlen(userInfo); + ASSERT_EQ(uriSetUserInfoA(&uri, first, afterLast), URI_ERROR_NULL); +} + +TEST(SetUserInfo, NullAfterLastOnly) { + UriUriA uri = {}; + const char * const first = "user:password"; + const char * const afterLast = NULL; + ASSERT_EQ(uriSetUserInfoA(&uri, first, afterLast), URI_ERROR_NULL); +} + +TEST(SetUserInfo, NullValueLeavesOwnerAtFalse) { + UriUriA uri = parseWellFormedUri("scheme://userinfo@host/"); + EXPECT_EQ(uri.owner, URI_FALSE); // self-test + + EXPECT_EQ(uriSetUserInfoA(&uri, NULL, NULL), URI_SUCCESS); + + EXPECT_EQ(uri.owner, URI_FALSE); // i.e. still false + + uriFreeUriMembersA(&uri); +} + +TEST(SetUserInfo, NonNullValueMakesOwner) { + UriUriA uri = parseWellFormedUri("scheme://old@host/"); + const char * const first = "new"; + const char * const afterLast = first + strlen(first); + EXPECT_EQ(uri.owner, URI_FALSE); // self-test + + EXPECT_EQ(uriSetUserInfoA(&uri, first, afterLast), URI_SUCCESS); + + EXPECT_EQ(uri.owner, URI_TRUE); // i.e. now owned + + uriFreeUriMembersA(&uri); +} + +TEST(SetUserInfo, NullValueApplied) { + UriUriA uri = parseWellFormedUri("scheme://old@host/"); + + EXPECT_EQ(uriSetUserInfoA(&uri, NULL, NULL), URI_SUCCESS); + + assertUriEqual(&uri, "scheme://host/"); + + uriFreeUriMembersA(&uri); +} + +TEST(SetUserInfo, NonNullValueAppliedEmpty) { + UriUriA uri = parseWellFormedUri("scheme://old@host/"); + const char * const empty = ""; + + EXPECT_EQ(uriSetUserInfoA(&uri, empty, empty), URI_SUCCESS); + + assertUriEqual(&uri, "scheme://@host/"); + + uriFreeUriMembersA(&uri); +} + +TEST(SetUserInfo, NonNullValueAppliedNonEmpty) { + UriUriA uri = parseWellFormedUri("scheme://old@host/"); + const char * const first = "new"; + const char * const afterLast = first + strlen(first); + + EXPECT_EQ(uriSetUserInfoA(&uri, first, afterLast), URI_SUCCESS); + + assertUriEqual(&uri, "scheme://new@host/"); + + uriFreeUriMembersA(&uri); +} + +TEST(SetUserInfo, MalformedValueRejected) { + UriUriA uri = parseWellFormedUri("scheme://userinfo@host/"); + const char * const first = "not well-formed"; + const char * const afterLast = first + strlen(first); + + EXPECT_EQ(uriSetUserInfoA(&uri, first, afterLast), URI_ERROR_SYNTAX); + + uriFreeUriMembersA(&uri); +} + +TEST(SetUserInfo, UriWithoutHostNullTolerated) { + const char * const originalText = "/no/host/here"; + UriUriA uri = parseWellFormedUri(originalText); + + EXPECT_EQ(uriSetUserInfoA(&uri, NULL, NULL), URI_SUCCESS); + + assertUriEqual(&uri, originalText); + + uriFreeUriMembersA(&uri); +} + +TEST(SetUserInfo, UriWithoutHostNonNullRejected) { + UriUriA uri = parseWellFormedUri("/no/host/here"); + const char * const first = "user:password"; + const char * const afterLast = first + strlen(first); + EXPECT_TRUE(uri.hostText.first == NULL); // self-test + + EXPECT_EQ(uriSetUserInfoA(&uri, first, afterLast), + URI_ERROR_SETUSERINFO_HOST_NOT_SET); + + uriFreeUriMembersA(&uri); +} diff --git a/test/VersionSuite.cpp b/test/VersionSuite.cpp index 01f0284..cdc03b8 100644 --- a/test/VersionSuite.cpp +++ b/test/VersionSuite.cpp @@ -22,22 +22,20 @@ #include <cstdio> - #include "UriConfig.h" // for PACKAGE_VERSION -#include <uriparser/UriBase.h> - +#include <uriparser/Uri.h> TEST(VersionSuite, EnsureVersionDefinesInSync) { - char INSIDE_VERSION[256]; - const int bytes_printed = sprintf(INSIDE_VERSION, "%d.%d.%d%s", - URI_VER_MAJOR, URI_VER_MINOR, URI_VER_RELEASE, URI_VER_SUFFIX_ANSI); - ASSERT_TRUE(bytes_printed != -1); + char INSIDE_VERSION[256]; + const int bytes_printed = + sprintf(INSIDE_VERSION, "%d.%d.%d%s", URI_VER_MAJOR, URI_VER_MINOR, + URI_VER_RELEASE, URI_VER_SUFFIX_ANSI); + ASSERT_NE(bytes_printed, -1); + EXPECT_STREQ(INSIDE_VERSION, PACKAGE_VERSION); +} - const bool equal = !strcmp(INSIDE_VERSION, PACKAGE_VERSION); - if (! equal) { - printf("Inside/outside version mismatch detected:\n"); - printf(" Tarball version: <%s>\n", PACKAGE_VERSION); - printf(" Header defines version: <%s>\n", INSIDE_VERSION); - } - ASSERT_TRUE(equal); +TEST(VersionSuite, EnsureRuntimeVersionAsExpected) { + // NOTE: This needs a bump for every release + EXPECT_STREQ(uriBaseRuntimeVersionA(), "1.0.1"); + EXPECT_STREQ(uriBaseRuntimeVersionW(), L"1.0.1"); } diff --git a/test/copy.cpp b/test/copy.cpp new file mode 100644 index 0000000..b058c98 --- /dev/null +++ b/test/copy.cpp @@ -0,0 +1,202 @@ +/* + * uriparser - RFC 3986 URI parsing library + * + * Copyright (C) 2007, Weijia Song <songweijia@gmail.com> + * Copyright (C) 2007, Sebastian Pipping <sebastian@pipping.org> + * Copyright (C) 2025, Máté Kocsis <kocsismate@php.net> + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library 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 + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#include <uriparser/Uri.h> +#include <uriparser/UriIp4.h> +#include <gtest/gtest.h> +#include <memory> +#include <cstdio> +#include <cstdlib> +#include <cwchar> +#include <string> + +using namespace std; + +namespace { +void testCopyUri(UriUriA * destUri, const char * const sourceUriString) { + UriUriA sourceUri; + + ASSERT_EQ(uriParseSingleUriA(&sourceUri, sourceUriString, NULL), URI_SUCCESS); + + ASSERT_EQ(URI_SUCCESS, uriCopyUriA(destUri, &sourceUri)); + ASSERT_EQ(URI_TRUE, uriEqualsUriA(destUri, &sourceUri)); + + uriFreeUriMembersA(&sourceUri); +} +} // namespace + +TEST(CopyUriSuite, ErrorSourceUriNull) { + UriUriA destUri; + + ASSERT_EQ(uriCopyUriA(&destUri, NULL), URI_ERROR_NULL); +} + +TEST(CopyUriSuite, ErrorDestUriNull) { + UriUriA sourceUri; + const char * const sourceUriString = "https://example.com"; + + ASSERT_EQ(uriParseSingleUriA(&sourceUri, sourceUriString, NULL), URI_SUCCESS); + + ASSERT_EQ(URI_ERROR_NULL, uriCopyUriA(NULL, &sourceUri)); + + uriFreeUriMembersA(&sourceUri); +} + +TEST(CopyUriSuite, ErrorIncompleteMemoryManager) { + UriUriA sourceUri; + const char * const sourceUriString = "https://example.com"; + UriMemoryManager memory = {NULL, NULL, NULL, NULL, NULL, NULL}; + + ASSERT_EQ(uriParseSingleUriA(&sourceUri, sourceUriString, NULL), URI_SUCCESS); + + UriUriA destUri; + ASSERT_EQ(URI_ERROR_MEMORY_MANAGER_INCOMPLETE, + uriCopyUriMmA(&destUri, &sourceUri, &memory)); + + uriFreeUriMembersA(&sourceUri); +} + +TEST(CopyUriSuite, SuccessRegName) { + UriUriA destUri; + testCopyUri(&destUri, "https://somehost.com"); + + ASSERT_TRUE(destUri.hostData.ip4 == NULL); + ASSERT_TRUE(destUri.hostData.ip6 == NULL); + ASSERT_TRUE(destUri.hostData.ipFuture.first == NULL); + ASSERT_TRUE(destUri.hostData.ipFuture.afterLast == NULL); + ASSERT_EQ(0, strncmp(destUri.hostText.first, "somehost.com", strlen("somehost.com"))); + + uriFreeUriMembersA(&destUri); +} + +TEST(CopyUriSuite, SuccessCompleteUri) { + UriUriA destUri; + testCopyUri(&destUri, "https://user:pass@somehost.com:80/path?query#frag"); + + uriFreeUriMembersA(&destUri); +} + +TEST(CopyUriSuite, SuccessRelativeReference) { + UriUriA destUri; + testCopyUri(&destUri, "/foo/bar/baz"); + + uriFreeUriMembersA(&destUri); +} + +TEST(CopyUriSuite, SuccessEmail) { + UriUriA destUri; + testCopyUri(&destUri, "mailto:fred@example.com"); + + uriFreeUriMembersA(&destUri); +} + +TEST(CopyUriSuite, SuccessIpV4) { + UriUriA destUri; + testCopyUri(&destUri, "http://192.168.0.1/"); + + const unsigned char expected[4] = {192, 168, 0, 1}; + ASSERT_EQ(memcmp(expected, destUri.hostData.ip4->data, sizeof(expected)), 0); + + ASSERT_TRUE(destUri.hostData.ip6 == NULL); + ASSERT_TRUE(destUri.hostData.ipFuture.first == NULL); + ASSERT_TRUE(destUri.hostData.ipFuture.afterLast == NULL); + ASSERT_EQ(0, strncmp(destUri.hostText.first, "192.168.0.1", strlen("192.168.0.1"))); + + uriFreeUriMembersA(&destUri); +} + +TEST(CopyUriSuite, SuccessIpV6) { + UriUriA destUri; + testCopyUri(&destUri, + "https://[2001:0db8:0001:0000:0000:0ab9:c0a8:0102]"); // RFC 3849 + + const unsigned char expected[16] = {0x20, 0x01, 0x0d, 0xb8, 0x00, 0x01, 0x00, 0x00, + 0x00, 0x00, 0x0a, 0xb9, 0xc0, 0xa8, 0x01, 0x02}; + ASSERT_EQ(memcmp(expected, destUri.hostData.ip6->data, sizeof(expected)), 0); + + ASSERT_TRUE(destUri.hostData.ip4 == NULL); + ASSERT_TRUE(destUri.hostData.ipFuture.first == NULL); + ASSERT_TRUE(destUri.hostData.ipFuture.afterLast == NULL); + ASSERT_EQ(0, + strncmp(destUri.hostText.first, "2001:0db8:0001:0000:0000:0ab9:c0a8:0102", + strlen("2001:0db8:0001:0000:0000:0ab9:c0a8:0102"))); + + uriFreeUriMembersA(&destUri); +} + +TEST(CopyUriSuite, SuccessIpFuture) { + UriUriA destUri; + testCopyUri(&destUri, "//[v7.host]/source"); + + ASSERT_EQ(0, strncmp(destUri.hostData.ipFuture.first, "v7.host", strlen("v7.host"))); + + ASSERT_TRUE(destUri.hostData.ip4 == NULL); + ASSERT_TRUE(destUri.hostData.ip6 == NULL); + ASSERT_TRUE(destUri.hostText.first == destUri.hostData.ipFuture.first); + ASSERT_TRUE(destUri.hostText.afterLast == destUri.hostData.ipFuture.afterLast); + + uriFreeUriMembersA(&destUri); +} + +TEST(CopyUriSuite, SuccessEmptyPort) { + UriUriA destUri; + testCopyUri(&destUri, "http://example.com:/"); + + ASSERT_TRUE(destUri.portText.first != NULL); + ASSERT_TRUE(destUri.portText.afterLast != NULL); + ASSERT_EQ(destUri.portText.first, destUri.portText.afterLast); + + uriFreeUriMembersA(&destUri); +} + +TEST(CopyUriSuite, SuccessEmptyUserInfo) { + UriUriA destUri; + testCopyUri(&destUri, "http://@example.com/"); + + ASSERT_TRUE(destUri.userInfo.first != NULL); + ASSERT_TRUE(destUri.userInfo.afterLast != NULL); + ASSERT_EQ(destUri.userInfo.first, destUri.userInfo.afterLast); + + uriFreeUriMembersA(&destUri); +} + +TEST(CopyUriSuite, SuccessEmptyQuery) { + UriUriA destUri; + testCopyUri(&destUri, "http://example.com/?"); + + ASSERT_TRUE(destUri.query.first != NULL); + ASSERT_TRUE(destUri.query.afterLast != NULL); + ASSERT_EQ(destUri.query.first, destUri.query.afterLast); + + uriFreeUriMembersA(&destUri); +} + +TEST(CopyUriSuite, SuccessEmptyFragment) { + UriUriA destUri; + testCopyUri(&destUri, "http://example.com/#"); + + ASSERT_TRUE(destUri.fragment.first != NULL); + ASSERT_TRUE(destUri.fragment.afterLast != NULL); + ASSERT_EQ(destUri.fragment.first, destUri.fragment.afterLast); + + uriFreeUriMembersA(&destUri); +} diff --git a/test/test.cpp b/test/test.cpp index fade025..30399b3 100644 --- a/test/test.cpp +++ b/test/test.cpp @@ -29,79 +29,75 @@ using namespace std; - - extern "C" { UriBool uri_TESTING_ONLY_ParseIpSixA(const char * text); UriBool uri_TESTING_ONLY_ParseIpFourA(const char * text); int uriCompareRangeA(const UriTextRangeA * a, const UriTextRangeA * b); } - - -#define URI_TEST_IP_FOUR_FAIL(x) ASSERT_TRUE(URI_FALSE == uri_TESTING_ONLY_ParseIpFourA(x)) -#define URI_TEST_IP_FOUR_PASS(x) ASSERT_TRUE(URI_TRUE == uri_TESTING_ONLY_ParseIpFourA(x)) +#define URI_TEST_IP_FOUR_FAIL(x) ASSERT_EQ(URI_FALSE, uri_TESTING_ONLY_ParseIpFourA(x)) +#define URI_TEST_IP_FOUR_PASS(x) ASSERT_EQ(URI_TRUE, uri_TESTING_ONLY_ParseIpFourA(x)) // Note the closing brackets! TODO -#define URI_TEST_IP_SIX_FAIL(x) ASSERT_TRUE(URI_FALSE == uri_TESTING_ONLY_ParseIpSixA(x "]")) -#define URI_TEST_IP_SIX_PASS(x) ASSERT_TRUE(URI_TRUE == uri_TESTING_ONLY_ParseIpSixA(x "]")) +#define URI_TEST_IP_SIX_FAIL(x) ASSERT_EQ(URI_FALSE, uri_TESTING_ONLY_ParseIpSixA(x "]")) +#define URI_TEST_IP_SIX_PASS(x) ASSERT_EQ(URI_TRUE, uri_TESTING_ONLY_ParseIpSixA(x "]")) -#define URI_EXPECT_BETWEEN(candidate, first, afterLast) \ - EXPECT_TRUE((candidate >= first) && (candidate <= afterLast)) +#define URI_EXPECT_BETWEEN(candidate, first, afterLast) \ + EXPECT_TRUE((candidate >= first) && (candidate <= afterLast)) -#define URI_EXPECT_OUTSIDE(candidate, first, afterLast) \ - EXPECT_TRUE((candidate < first) || (candidate > afterLast)) +#define URI_EXPECT_OUTSIDE(candidate, first, afterLast) \ + EXPECT_TRUE((candidate < first) || (candidate > afterLast)) -#define URI_EXPECT_RANGE_BETWEEN(range, uriFirst, uriAfterLast) \ - URI_EXPECT_BETWEEN(range.first, uriFirst, uriAfterLast); \ - URI_EXPECT_BETWEEN(range.afterLast, uriFirst, uriAfterLast) +#define URI_EXPECT_RANGE_BETWEEN(range, uriFirst, uriAfterLast) \ + URI_EXPECT_BETWEEN(range.first, uriFirst, uriAfterLast); \ + URI_EXPECT_BETWEEN(range.afterLast, uriFirst, uriAfterLast) -#define URI_EXPECT_RANGE_OUTSIDE(range, uriFirst, uriAfterLast) \ - URI_EXPECT_OUTSIDE(range.first, uriFirst, uriAfterLast); \ - URI_EXPECT_OUTSIDE(range.afterLast, uriFirst, uriAfterLast) +#define URI_EXPECT_RANGE_OUTSIDE(range, uriFirst, uriAfterLast) \ + URI_EXPECT_OUTSIDE(range.first, uriFirst, uriAfterLast); \ + URI_EXPECT_OUTSIDE(range.afterLast, uriFirst, uriAfterLast) -#define URI_EXPECT_RANGE_EMPTY(range) \ - EXPECT_TRUE((range.first != NULL) \ - && (range.afterLast != NULL) \ - && (range.first == range.afterLast)) +#define URI_EXPECT_RANGE_EMPTY(range) \ + EXPECT_TRUE((range.first != NULL) && (range.afterLast != NULL) \ + && (range.first == range.afterLast)) namespace { - bool testDistinctionHelper(const char * uriText, bool expectedHostSet, - bool expectedAbsPath, bool expectedEmptyTailSegment) { - UriParserStateA state; - UriUriA uri; - state.uri = &uri; - - int res = uriParseUriA(&state, uriText); - if (res != URI_SUCCESS) { - uriFreeUriMembersA(&uri); - return false; - } - - if (expectedHostSet != (uri.hostText.first != NULL)) { - uriFreeUriMembersA(&uri); - return false; - } - - if (expectedAbsPath != (uri.absolutePath == URI_TRUE)) { - uriFreeUriMembersA(&uri); - return false; - } - - if (expectedEmptyTailSegment != ((uri.pathTail != NULL) - && (uri.pathTail->text.first == uri.pathTail->text.afterLast))) { - uriFreeUriMembersA(&uri); - return false; - } - - uriFreeUriMembersA(&uri); - return true; - } +bool testDistinctionHelper(const char * uriText, bool expectedHostSet, + bool expectedAbsPath, bool expectedEmptyTailSegment) { + UriParserStateA state; + UriUriA uri; + state.uri = &uri; + + int res = uriParseUriA(&state, uriText); + if (res != URI_SUCCESS) { + uriFreeUriMembersA(&uri); + return false; + } + + if (expectedHostSet != (uri.hostText.first != NULL)) { + uriFreeUriMembersA(&uri); + return false; + } + + if (expectedAbsPath != (uri.absolutePath == URI_TRUE)) { + uriFreeUriMembersA(&uri); + return false; + } + + if (expectedEmptyTailSegment + != ((uri.pathTail != NULL) + && (uri.pathTail->text.first == uri.pathTail->text.afterLast))) { + uriFreeUriMembersA(&uri); + return false; + } + + uriFreeUriMembersA(&uri); + return true; +} } // namespace - TEST(UriSuite, TestDistinction) { - /* + /* clang-format off */ + /* ============================================================================ Rule | Example | hostSet | absPath | emptySeg ------------------------------------|---------|---------|---------|--------- @@ -123,2284 +119,2413 @@ Rule | Example | hostSet | absPath | emptySeg | "a/" | false | false | true 4) path-empty | "" | false | false | false ============================================================================ - */ - ASSERT_TRUE(testDistinctionHelper("s://", true, false, false)); - ASSERT_TRUE(testDistinctionHelper("s:///", true, false, true)); - ASSERT_TRUE(testDistinctionHelper("s://a", true, false, false)); - ASSERT_TRUE(testDistinctionHelper("s://a/", true, false, true)); - ASSERT_TRUE(testDistinctionHelper("s:/", false, true, false)); - ASSERT_TRUE(testDistinctionHelper("s:a", false, false, false)); - ASSERT_TRUE(testDistinctionHelper("s:a/", false, false, true)); - ASSERT_TRUE(testDistinctionHelper("s:", false, false, false)); - - ASSERT_TRUE(testDistinctionHelper("//", true, false, false)); - ASSERT_TRUE(testDistinctionHelper("///", true, false, true)); - ASSERT_TRUE(testDistinctionHelper("/", false, true, false)); - ASSERT_TRUE(testDistinctionHelper("a", false, false, false)); - ASSERT_TRUE(testDistinctionHelper("a/", false, false, true)); - ASSERT_TRUE(testDistinctionHelper("", false, false, false)); + */ + /* clang-format on */ + ASSERT_TRUE(testDistinctionHelper("s://", true, false, false)); + ASSERT_TRUE(testDistinctionHelper("s:///", true, false, true)); + ASSERT_TRUE(testDistinctionHelper("s://a", true, false, false)); + ASSERT_TRUE(testDistinctionHelper("s://a/", true, false, true)); + ASSERT_TRUE(testDistinctionHelper("s:/", false, true, false)); + ASSERT_TRUE(testDistinctionHelper("s:a", false, false, false)); + ASSERT_TRUE(testDistinctionHelper("s:a/", false, false, true)); + ASSERT_TRUE(testDistinctionHelper("s:", false, false, false)); + + ASSERT_TRUE(testDistinctionHelper("//", true, false, false)); + ASSERT_TRUE(testDistinctionHelper("///", true, false, true)); + ASSERT_TRUE(testDistinctionHelper("/", false, true, false)); + ASSERT_TRUE(testDistinctionHelper("a", false, false, false)); + ASSERT_TRUE(testDistinctionHelper("a/", false, false, true)); + ASSERT_TRUE(testDistinctionHelper("", false, false, false)); } TEST(UriSuite, TestIpFour) { - URI_TEST_IP_FOUR_FAIL("01.0.0.0"); - URI_TEST_IP_FOUR_FAIL("001.0.0.0"); - URI_TEST_IP_FOUR_FAIL("00.0.0.0"); - URI_TEST_IP_FOUR_FAIL("000.0.0.0"); - URI_TEST_IP_FOUR_FAIL("256.0.0.0"); - URI_TEST_IP_FOUR_FAIL("300.0.0.0"); - URI_TEST_IP_FOUR_FAIL("1111.0.0.0"); - URI_TEST_IP_FOUR_FAIL("-1.0.0.0"); - URI_TEST_IP_FOUR_FAIL("0.0.0"); - URI_TEST_IP_FOUR_FAIL("0.0.0."); - URI_TEST_IP_FOUR_FAIL("0.0.0.0."); - URI_TEST_IP_FOUR_FAIL("0.0.0.0.0"); - URI_TEST_IP_FOUR_FAIL("0.0..0"); - URI_TEST_IP_FOUR_FAIL(".0.0.0"); - - URI_TEST_IP_FOUR_PASS("255.0.0.0"); - URI_TEST_IP_FOUR_PASS("0.0.0.0"); - URI_TEST_IP_FOUR_PASS("1.0.0.0"); - URI_TEST_IP_FOUR_PASS("2.0.0.0"); - URI_TEST_IP_FOUR_PASS("3.0.0.0"); - URI_TEST_IP_FOUR_PASS("30.0.0.0"); + URI_TEST_IP_FOUR_FAIL("01.0.0.0"); + URI_TEST_IP_FOUR_FAIL("001.0.0.0"); + URI_TEST_IP_FOUR_FAIL("00.0.0.0"); + URI_TEST_IP_FOUR_FAIL("000.0.0.0"); + URI_TEST_IP_FOUR_FAIL("256.0.0.0"); + URI_TEST_IP_FOUR_FAIL("300.0.0.0"); + URI_TEST_IP_FOUR_FAIL("1111.0.0.0"); + URI_TEST_IP_FOUR_FAIL("-1.0.0.0"); + URI_TEST_IP_FOUR_FAIL("0.0.0"); + URI_TEST_IP_FOUR_FAIL("0.0.0."); + URI_TEST_IP_FOUR_FAIL("0.0.0.0."); + URI_TEST_IP_FOUR_FAIL("0.0.0.0.0"); + URI_TEST_IP_FOUR_FAIL("0.0..0"); + URI_TEST_IP_FOUR_FAIL(".0.0.0"); + + URI_TEST_IP_FOUR_PASS("255.0.0.0"); + URI_TEST_IP_FOUR_PASS("0.0.0.0"); + URI_TEST_IP_FOUR_PASS("1.0.0.0"); + URI_TEST_IP_FOUR_PASS("2.0.0.0"); + URI_TEST_IP_FOUR_PASS("3.0.0.0"); + URI_TEST_IP_FOUR_PASS("30.0.0.0"); } TEST(UriSuite, TestIpSixPass) { - // Quad length - URI_TEST_IP_SIX_PASS("abcd::"); - - URI_TEST_IP_SIX_PASS("abcd::1"); - URI_TEST_IP_SIX_PASS("abcd::12"); - URI_TEST_IP_SIX_PASS("abcd::123"); - URI_TEST_IP_SIX_PASS("abcd::1234"); - - // Full length - URI_TEST_IP_SIX_PASS("2001:0db8:0100:f101:0210:a4ff:fee3:9566"); // lower hex - URI_TEST_IP_SIX_PASS("2001:0DB8:0100:F101:0210:A4FF:FEE3:9566"); // Upper hex - URI_TEST_IP_SIX_PASS("2001:db8:100:f101:210:a4ff:fee3:9566"); - URI_TEST_IP_SIX_PASS("2001:0db8:100:f101:0:0:0:1"); - URI_TEST_IP_SIX_PASS("1:2:3:4:5:6:255.255.255.255"); - - // Legal IPv4 - URI_TEST_IP_SIX_PASS("::1.2.3.4"); - URI_TEST_IP_SIX_PASS("3:4::5:1.2.3.4"); - URI_TEST_IP_SIX_PASS("::ffff:1.2.3.4"); - URI_TEST_IP_SIX_PASS("::0.0.0.0"); // Min IPv4 - URI_TEST_IP_SIX_PASS("::255.255.255.255"); // Max IPv4 - - // Zipper position - URI_TEST_IP_SIX_PASS("::1:2:3:4:5:6:7"); - URI_TEST_IP_SIX_PASS("1::1:2:3:4:5:6"); - URI_TEST_IP_SIX_PASS("1:2::1:2:3:4:5"); - URI_TEST_IP_SIX_PASS("1:2:3::1:2:3:4"); - URI_TEST_IP_SIX_PASS("1:2:3:4::1:2:3"); - URI_TEST_IP_SIX_PASS("1:2:3:4:5::1:2"); - URI_TEST_IP_SIX_PASS("1:2:3:4:5:6::1"); - URI_TEST_IP_SIX_PASS("1:2:3:4:5:6:7::"); - - // Zipper length - URI_TEST_IP_SIX_PASS("1:1:1::1:1:1:1"); - URI_TEST_IP_SIX_PASS("1:1:1::1:1:1"); - URI_TEST_IP_SIX_PASS("1:1:1::1:1"); - URI_TEST_IP_SIX_PASS("1:1::1:1"); - URI_TEST_IP_SIX_PASS("1:1::1"); - URI_TEST_IP_SIX_PASS("1::1"); - URI_TEST_IP_SIX_PASS("::1"); // == localhost - URI_TEST_IP_SIX_PASS("::"); // == all addresses - - // A few more variations - URI_TEST_IP_SIX_PASS("21ff:abcd::1"); - URI_TEST_IP_SIX_PASS("2001:db8:100:f101::1"); - URI_TEST_IP_SIX_PASS("a:b:c::12:1"); - URI_TEST_IP_SIX_PASS("a:b::0:1:2:3"); - - // Issue #146: These are not leading zeros. - URI_TEST_IP_SIX_PASS("::100.1.1.1"); - URI_TEST_IP_SIX_PASS("::1.100.1.1"); - URI_TEST_IP_SIX_PASS("::1.1.100.1"); - URI_TEST_IP_SIX_PASS("::1.1.1.100"); - URI_TEST_IP_SIX_PASS("::100.100.100.100"); - URI_TEST_IP_SIX_PASS("::10.1.1.1"); - URI_TEST_IP_SIX_PASS("::1.10.1.1"); - URI_TEST_IP_SIX_PASS("::1.1.10.1"); - URI_TEST_IP_SIX_PASS("::1.1.1.10"); - URI_TEST_IP_SIX_PASS("::10.10.10.10"); + // Quad length + URI_TEST_IP_SIX_PASS("abcd::"); + + URI_TEST_IP_SIX_PASS("abcd::1"); + URI_TEST_IP_SIX_PASS("abcd::12"); + URI_TEST_IP_SIX_PASS("abcd::123"); + URI_TEST_IP_SIX_PASS("abcd::1234"); + + // Full length + URI_TEST_IP_SIX_PASS("2001:0db8:0100:f101:0210:a4ff:fee3:9566"); // lower hex + URI_TEST_IP_SIX_PASS("2001:0DB8:0100:F101:0210:A4FF:FEE3:9566"); // Upper hex + URI_TEST_IP_SIX_PASS("2001:db8:100:f101:210:a4ff:fee3:9566"); + URI_TEST_IP_SIX_PASS("2001:0db8:100:f101:0:0:0:1"); + URI_TEST_IP_SIX_PASS("1:2:3:4:5:6:255.255.255.255"); + + // Legal IPv4 + URI_TEST_IP_SIX_PASS("::1.2.3.4"); + URI_TEST_IP_SIX_PASS("3:4::5:1.2.3.4"); + URI_TEST_IP_SIX_PASS("::ffff:1.2.3.4"); + URI_TEST_IP_SIX_PASS("::0.0.0.0"); // Min IPv4 + URI_TEST_IP_SIX_PASS("::255.255.255.255"); // Max IPv4 + + // Zipper position + URI_TEST_IP_SIX_PASS("::1:2:3:4:5:6:7"); + URI_TEST_IP_SIX_PASS("1::1:2:3:4:5:6"); + URI_TEST_IP_SIX_PASS("1:2::1:2:3:4:5"); + URI_TEST_IP_SIX_PASS("1:2:3::1:2:3:4"); + URI_TEST_IP_SIX_PASS("1:2:3:4::1:2:3"); + URI_TEST_IP_SIX_PASS("1:2:3:4:5::1:2"); + URI_TEST_IP_SIX_PASS("1:2:3:4:5:6::1"); + URI_TEST_IP_SIX_PASS("1:2:3:4:5:6:7::"); + + // Zipper length + URI_TEST_IP_SIX_PASS("1:1:1::1:1:1:1"); + URI_TEST_IP_SIX_PASS("1:1:1::1:1:1"); + URI_TEST_IP_SIX_PASS("1:1:1::1:1"); + URI_TEST_IP_SIX_PASS("1:1::1:1"); + URI_TEST_IP_SIX_PASS("1:1::1"); + URI_TEST_IP_SIX_PASS("1::1"); + URI_TEST_IP_SIX_PASS("::1"); // == localhost + URI_TEST_IP_SIX_PASS("::"); // == all addresses + + // A few more variations + URI_TEST_IP_SIX_PASS("21ff:abcd::1"); + URI_TEST_IP_SIX_PASS("2001:db8:100:f101::1"); + URI_TEST_IP_SIX_PASS("a:b:c::12:1"); + URI_TEST_IP_SIX_PASS("a:b::0:1:2:3"); + + // Issue #146: These are not leading zeros. + URI_TEST_IP_SIX_PASS("::100.1.1.1"); + URI_TEST_IP_SIX_PASS("::1.100.1.1"); + URI_TEST_IP_SIX_PASS("::1.1.100.1"); + URI_TEST_IP_SIX_PASS("::1.1.1.100"); + URI_TEST_IP_SIX_PASS("::100.100.100.100"); + URI_TEST_IP_SIX_PASS("::10.1.1.1"); + URI_TEST_IP_SIX_PASS("::1.10.1.1"); + URI_TEST_IP_SIX_PASS("::1.1.10.1"); + URI_TEST_IP_SIX_PASS("::1.1.1.10"); + URI_TEST_IP_SIX_PASS("::10.10.10.10"); } TEST(UriSuite, TestIpSixFail) { - // 5 char quad - URI_TEST_IP_SIX_FAIL("::12345"); - - // Two zippers - URI_TEST_IP_SIX_FAIL("abcd::abcd::abcd"); - - // Triple-colon zipper - URI_TEST_IP_SIX_FAIL(":::1234"); - URI_TEST_IP_SIX_FAIL("1234:::1234:1234"); - URI_TEST_IP_SIX_FAIL("1234:1234:::1234"); - URI_TEST_IP_SIX_FAIL("1234:::"); - - // No quads, just IPv4 - URI_TEST_IP_SIX_FAIL("1.2.3.4"); - URI_TEST_IP_SIX_FAIL("0001.0002.0003.0004"); - - // Five quads - URI_TEST_IP_SIX_FAIL("0000:0000:0000:0000:0000:1.2.3.4"); - - // Seven quads - URI_TEST_IP_SIX_FAIL("0:0:0:0:0:0:0"); - URI_TEST_IP_SIX_FAIL("0:0:0:0:0:0:0:"); - URI_TEST_IP_SIX_FAIL("0:0:0:0:0:0:0:1.2.3.4"); - - // Nine quads (or more) - URI_TEST_IP_SIX_FAIL("1:2:3:4:5:6:7:8:9"); - URI_TEST_IP_SIX_FAIL("::2:3:4:5:6:7:8:9"); - URI_TEST_IP_SIX_FAIL("1:2:3:4::6:7:8:9"); - URI_TEST_IP_SIX_FAIL("1:2:3:4:5:6:7:8::"); - - // Invalid IPv4 part - URI_TEST_IP_SIX_FAIL("::ffff:001.02.03.004"); // Leading zeros - URI_TEST_IP_SIX_FAIL("::ffff:1.2.3.1111"); // Four char octet - URI_TEST_IP_SIX_FAIL("::ffff:1.2.3.256"); // > 255 - URI_TEST_IP_SIX_FAIL("::ffff:311.2.3.4"); // > 155 - URI_TEST_IP_SIX_FAIL("::ffff:1.2.3:4"); // Not a dot - URI_TEST_IP_SIX_FAIL("::ffff:1.2.3"); // Missing octet - URI_TEST_IP_SIX_FAIL("::ffff:1.2.3."); // Missing octet - URI_TEST_IP_SIX_FAIL("::ffff:1.2.3a.4"); // Hex in octet - URI_TEST_IP_SIX_FAIL("::ffff:1.2.3.4:123"); // Crap input - - // Nonhex - URI_TEST_IP_SIX_FAIL("g:0:0:0:0:0:0"); - - // Issue #146: Zipper between the 7th and 8th quads. - URI_TEST_IP_SIX_FAIL("0:0:0:0:0:0:0::1"); - - // Issue #146: Leading or trailing ":". - URI_TEST_IP_SIX_FAIL(":1::1"); - URI_TEST_IP_SIX_FAIL("1::1:"); - URI_TEST_IP_SIX_FAIL(":1::1:"); - URI_TEST_IP_SIX_FAIL(":0:0:0:0:0:0:0:0"); - URI_TEST_IP_SIX_FAIL("0:0:0:0:0:0:0:0:"); - URI_TEST_IP_SIX_FAIL(":0:0:0:0:0:0:0:0:"); - - // Issue #146: Zipper between six quads and IPv4 address. - URI_TEST_IP_SIX_FAIL("1:1:1:1:1:1::1.1.1.1"); + // 5 char quad + URI_TEST_IP_SIX_FAIL("::12345"); + + // Two zippers + URI_TEST_IP_SIX_FAIL("abcd::abcd::abcd"); + + // Triple-colon zipper + URI_TEST_IP_SIX_FAIL(":::1234"); + URI_TEST_IP_SIX_FAIL("1234:::1234:1234"); + URI_TEST_IP_SIX_FAIL("1234:1234:::1234"); + URI_TEST_IP_SIX_FAIL("1234:::"); + + // No quads, just IPv4 + URI_TEST_IP_SIX_FAIL("1.2.3.4"); + URI_TEST_IP_SIX_FAIL("0001.0002.0003.0004"); + + // Five quads + URI_TEST_IP_SIX_FAIL("0000:0000:0000:0000:0000:1.2.3.4"); + + // Seven quads + URI_TEST_IP_SIX_FAIL("0:0:0:0:0:0:0"); + URI_TEST_IP_SIX_FAIL("0:0:0:0:0:0:0:"); + URI_TEST_IP_SIX_FAIL("0:0:0:0:0:0:0:1.2.3.4"); + + // Nine quads (or more) + URI_TEST_IP_SIX_FAIL("1:2:3:4:5:6:7:8:9"); + URI_TEST_IP_SIX_FAIL("::2:3:4:5:6:7:8:9"); + URI_TEST_IP_SIX_FAIL("1:2:3:4::6:7:8:9"); + URI_TEST_IP_SIX_FAIL("1:2:3:4:5:6:7:8::"); + + // Invalid IPv4 part + URI_TEST_IP_SIX_FAIL("::ffff:001.02.03.004"); // Leading zeros + URI_TEST_IP_SIX_FAIL("::ffff:1.2.3.1111"); // Four char octet + URI_TEST_IP_SIX_FAIL("::ffff:1.2.3.256"); // > 255 + URI_TEST_IP_SIX_FAIL("::ffff:311.2.3.4"); // > 155 + URI_TEST_IP_SIX_FAIL("::ffff:1.2.3:4"); // Not a dot + URI_TEST_IP_SIX_FAIL("::ffff:1.2.3"); // Missing octet + URI_TEST_IP_SIX_FAIL("::ffff:1.2.3."); // Missing octet + URI_TEST_IP_SIX_FAIL("::ffff:1.2.3a.4"); // Hex in octet + URI_TEST_IP_SIX_FAIL("::ffff:1.2.3.4:123"); // Crap input + + // Nonhex + URI_TEST_IP_SIX_FAIL("g:0:0:0:0:0:0"); + + // Issue #146: Zipper between the 7th and 8th quads. + URI_TEST_IP_SIX_FAIL("0:0:0:0:0:0:0::1"); + + // Issue #146: Leading or trailing ":". + URI_TEST_IP_SIX_FAIL(":1::1"); + URI_TEST_IP_SIX_FAIL("1::1:"); + URI_TEST_IP_SIX_FAIL(":1::1:"); + URI_TEST_IP_SIX_FAIL(":0:0:0:0:0:0:0:0"); + URI_TEST_IP_SIX_FAIL("0:0:0:0:0:0:0:0:"); + URI_TEST_IP_SIX_FAIL(":0:0:0:0:0:0:0:0:"); + + // Issue #146: Zipper between six quads and IPv4 address. + URI_TEST_IP_SIX_FAIL("1:1:1:1:1:1::1.1.1.1"); } TEST(UriSuite, TestIpFuture) { - UriParserStateA stateA; - UriUriA uriA; - stateA.uri = &uriA; + UriParserStateA stateA; + UriUriA uriA; + stateA.uri = &uriA; - // Issue #146: The leading "v" of IPvFuture is case-insensitive. - ASSERT_TRUE(0 == uriParseUriA(&stateA, "//[vF.addr]")); - uriFreeUriMembersA(&uriA); - ASSERT_TRUE(0 == uriParseUriA(&stateA, "//[VF.addr]")); - uriFreeUriMembersA(&uriA); + // Issue #146: The leading "v" of IPvFuture is case-insensitive. + ASSERT_EQ(0, uriParseUriA(&stateA, "//[vF.addr]")); + uriFreeUriMembersA(&uriA); + ASSERT_EQ(0, uriParseUriA(&stateA, "//[VF.addr]")); + uriFreeUriMembersA(&uriA); } TEST(UriSuite, TestIpSixOverread) { - UriUriA uri; - const char * errorPos; + UriUriA uri; + const char * errorPos; - // NOTE: This string is designed to not have a terminator - char uriText[2 + 3 + 2 + 1 + 1]; - memcpy(uriText, "//[::44.1", sizeof(uriText)); + // NOTE: This string is designed to not have a terminator + char uriText[2 + 3 + 2 + 1 + 1]; + memcpy(uriText, "//[::44.1", sizeof(uriText)); - EXPECT_EQ(uriParseSingleUriExA(&uri, uriText, - uriText + sizeof(uriText), &errorPos), URI_ERROR_SYNTAX); - EXPECT_EQ(errorPos, uriText + sizeof(uriText)); + EXPECT_EQ(uriParseSingleUriExA(&uri, uriText, uriText + sizeof(uriText), &errorPos), + URI_ERROR_SYNTAX); + EXPECT_EQ(errorPos, uriText + sizeof(uriText)); } TEST(UriSuite, TestUri) { - UriParserStateA stateA; - UriParserStateW stateW; - UriUriA uriA; - UriUriW uriW; - - stateA.uri = &uriA; - stateW.uri = &uriW; - - // On/off for each - ASSERT_TRUE(0 == uriParseUriA(&stateA, "//user:pass@[::1]:80/segment/index.html?query#frag")); - uriFreeUriMembersA(&uriA); - ASSERT_TRUE(0 == uriParseUriA(&stateA, "http://[::1]:80/segment/index.html?query#frag")); - uriFreeUriMembersA(&uriA); - ASSERT_TRUE(0 == uriParseUriA(&stateA, "http://user:pass@[::1]/segment/index.html?query#frag")); - uriFreeUriMembersA(&uriA); - ASSERT_TRUE(0 == uriParseUriA(&stateA, "http://user:pass@[::1]:80?query#frag")); - uriFreeUriMembersA(&uriA); - ASSERT_TRUE(0 == uriParseUriA(&stateA, "http://user:pass@[::1]:80/segment/index.html#frag")); - uriFreeUriMembersA(&uriA); - ASSERT_TRUE(0 == uriParseUriA(&stateA, "http://user:pass@[::1]:80/segment/index.html?query")); - uriFreeUriMembersA(&uriA); - - // Schema, port, one segment - ASSERT_TRUE(0 == uriParseUriA(&stateA, "ftp://host:21/gnu/")); - uriFreeUriMembersA(&uriA); - - // Relative - ASSERT_TRUE(0 == uriParseUriA(&stateA, "one/two/three")); - ASSERT_TRUE(!uriA.absolutePath); - uriFreeUriMembersA(&uriA); - ASSERT_TRUE(0 == uriParseUriA(&stateA, "/one/two/three")); - ASSERT_TRUE(uriA.absolutePath); - uriFreeUriMembersA(&uriA); - ASSERT_TRUE(0 == uriParseUriA(&stateA, "//user:pass@localhost/one/two/three")); - uriFreeUriMembersA(&uriA); - - // Both narrow and wide string version - ASSERT_TRUE(0 == uriParseUriA(&stateA, "http://www.example.com/")); - uriFreeUriMembersA(&uriA); - ASSERT_TRUE(0 == uriParseUriW(&stateW, L"http://www.example.com/")); - uriFreeUriMembersW(&uriW); - - // Real life examples - ASSERT_TRUE(0 == uriParseUriA(&stateA, "http://sourceforge.net/projects/uriparser/")); - uriFreeUriMembersA(&uriA); - ASSERT_TRUE(0 == uriParseUriA(&stateA, "http://sourceforge.net/project/platformdownload.php?group_id=182840")); - uriFreeUriMembersA(&uriA); - ASSERT_TRUE(0 == uriParseUriA(&stateA, "mailto:test@example.com")); - uriFreeUriMembersA(&uriA); - ASSERT_TRUE(0 == uriParseUriA(&stateA, "../../")); - uriFreeUriMembersA(&uriA); - ASSERT_TRUE(0 == uriParseUriA(&stateA, "/")); - ASSERT_TRUE(uriA.absolutePath); - uriFreeUriMembersA(&uriA); - ASSERT_TRUE(0 == uriParseUriA(&stateA, "")); - ASSERT_TRUE(!uriA.absolutePath); - uriFreeUriMembersA(&uriA); - ASSERT_TRUE(0 == uriParseUriA(&stateA, "file:///bin/bash")); - uriFreeUriMembersA(&uriA); - - // Percent encoding - ASSERT_TRUE(0 == uriParseUriA(&stateA, "http://www.example.com/name%20with%20spaces/")); - uriFreeUriMembersA(&uriA); - ASSERT_TRUE(0 != uriParseUriA(&stateA, "http://www.example.com/name with spaces/")); - uriFreeUriMembersA(&uriA); + UriParserStateA stateA; + UriParserStateW stateW; + UriUriA uriA; + UriUriW uriW; + + stateA.uri = &uriA; + stateW.uri = &uriW; + + // On/off for each + ASSERT_EQ( + 0, uriParseUriA(&stateA, "//user:pass@[::1]:80/segment/index.html?query#frag")); + uriFreeUriMembersA(&uriA); + ASSERT_EQ(0, uriParseUriA(&stateA, "http://[::1]:80/segment/index.html?query#frag")); + uriFreeUriMembersA(&uriA); + ASSERT_EQ( + 0, uriParseUriA(&stateA, "http://user:pass@[::1]/segment/index.html?query#frag")); + uriFreeUriMembersA(&uriA); + ASSERT_EQ(0, uriParseUriA(&stateA, "http://user:pass@[::1]:80?query#frag")); + uriFreeUriMembersA(&uriA); + ASSERT_EQ(0, + uriParseUriA(&stateA, "http://user:pass@[::1]:80/segment/index.html#frag")); + uriFreeUriMembersA(&uriA); + ASSERT_EQ( + 0, uriParseUriA(&stateA, "http://user:pass@[::1]:80/segment/index.html?query")); + uriFreeUriMembersA(&uriA); + + // Schema, port, one segment + ASSERT_EQ(0, uriParseUriA(&stateA, "ftp://host:21/gnu/")); + uriFreeUriMembersA(&uriA); + + // Relative + ASSERT_EQ(0, uriParseUriA(&stateA, "one/two/three")); + ASSERT_TRUE(!uriA.absolutePath); + uriFreeUriMembersA(&uriA); + ASSERT_EQ(0, uriParseUriA(&stateA, "/one/two/three")); + ASSERT_TRUE(uriA.absolutePath); + uriFreeUriMembersA(&uriA); + ASSERT_EQ(0, uriParseUriA(&stateA, "//user:pass@localhost/one/two/three")); + uriFreeUriMembersA(&uriA); + + // Both narrow and wide string version + ASSERT_EQ(0, uriParseUriA(&stateA, "http://www.example.com/")); + uriFreeUriMembersA(&uriA); + ASSERT_EQ(0, uriParseUriW(&stateW, L"http://www.example.com/")); + uriFreeUriMembersW(&uriW); + + // Real life examples + ASSERT_EQ(0, uriParseUriA(&stateA, "http://sourceforge.net/projects/uriparser/")); + uriFreeUriMembersA(&uriA); + ASSERT_EQ(0, + uriParseUriA( + &stateA, + "http://sourceforge.net/project/platformdownload.php?group_id=182840")); + uriFreeUriMembersA(&uriA); + ASSERT_EQ(0, uriParseUriA(&stateA, "mailto:test@example.com")); + uriFreeUriMembersA(&uriA); + ASSERT_EQ(0, uriParseUriA(&stateA, "../../")); + uriFreeUriMembersA(&uriA); + ASSERT_EQ(0, uriParseUriA(&stateA, "/")); + ASSERT_TRUE(uriA.absolutePath); + uriFreeUriMembersA(&uriA); + ASSERT_EQ(0, uriParseUriA(&stateA, "")); + ASSERT_TRUE(!uriA.absolutePath); + uriFreeUriMembersA(&uriA); + ASSERT_EQ(0, uriParseUriA(&stateA, "file:///bin/bash")); + uriFreeUriMembersA(&uriA); + + // Percent encoding + ASSERT_EQ(0, uriParseUriA(&stateA, "http://www.example.com/name%20with%20spaces/")); + uriFreeUriMembersA(&uriA); + ASSERT_NE(0, uriParseUriA(&stateA, "http://www.example.com/name with spaces/")); + uriFreeUriMembersA(&uriA); } TEST(UriSuite, TestUriComponents) { - UriParserStateA stateA; - UriUriA uriA; - stateA.uri = &uriA; - // 0 4 0 3 0 15 01 0 7 01 - const char * const input = "http" "://" "sourceforge.net" "/" "project" "/" - // 0 20 01 0 15 - "platformdownload.php" "?" "group_id=182840"; - ASSERT_TRUE(0 == uriParseUriA(&stateA, input)); - - ASSERT_TRUE(uriA.scheme.first == input); - ASSERT_TRUE(uriA.scheme.afterLast == input + 4); - ASSERT_TRUE(uriA.userInfo.first == NULL); - ASSERT_TRUE(uriA.userInfo.afterLast == NULL); - ASSERT_TRUE(uriA.hostText.first == input + 4 + 3); - ASSERT_TRUE(uriA.hostText.afterLast == input + 4 + 3 + 15); - ASSERT_TRUE(uriA.hostData.ipFuture.first == NULL); - ASSERT_TRUE(uriA.hostData.ipFuture.afterLast == NULL); - ASSERT_TRUE(uriA.portText.first == NULL); - ASSERT_TRUE(uriA.portText.afterLast == NULL); - - ASSERT_TRUE(uriA.pathHead->text.first == input + 4 + 3 + 15 + 1); - ASSERT_TRUE(uriA.pathHead->text.afterLast == input + 4 + 3 + 15 + 1 + 7); - ASSERT_TRUE(uriA.pathHead->next->text.first == input + 4 + 3 + 15 + 1 + 7 + 1); - ASSERT_TRUE(uriA.pathHead->next->text.afterLast == input + 4 + 3 + 15 + 1 + 7 + 1 + 20); - ASSERT_TRUE(uriA.pathHead->next->next == NULL); - ASSERT_TRUE(uriA.pathTail == uriA.pathHead->next); - - ASSERT_TRUE(uriA.query.first == input + 4 + 3 + 15 + 1 + 7 + 1 + 20 + 1); - ASSERT_TRUE(uriA.query.afterLast == input + 4 + 3 + 15 + 1 + 7 + 1 + 20 + 1 + 15); - ASSERT_TRUE(uriA.fragment.first == NULL); - ASSERT_TRUE(uriA.fragment.afterLast == NULL); - uriFreeUriMembersA(&uriA); + UriParserStateA stateA; + UriUriA uriA; + stateA.uri = &uriA; + // clang-format off + // 0 4 0 3 0 15 01 0 7 01 + const char * const input = "http" "://" "sourceforge.net" "/" "project" "/" + // 0 20 01 0 15 + "platformdownload.php" "?" "group_id=182840"; + // clang-format on + ASSERT_EQ(0, uriParseUriA(&stateA, input)); + + ASSERT_EQ(uriA.scheme.first, input); + ASSERT_EQ(uriA.scheme.afterLast, input + 4); + ASSERT_TRUE(uriA.userInfo.first == NULL); + ASSERT_TRUE(uriA.userInfo.afterLast == NULL); + ASSERT_EQ(uriA.hostText.first, input + 4 + 3); + ASSERT_EQ(uriA.hostText.afterLast, input + 4 + 3 + 15); + ASSERT_TRUE(uriA.hostData.ipFuture.first == NULL); + ASSERT_TRUE(uriA.hostData.ipFuture.afterLast == NULL); + ASSERT_TRUE(uriA.portText.first == NULL); + ASSERT_TRUE(uriA.portText.afterLast == NULL); + + ASSERT_EQ(uriA.pathHead->text.first, input + 4 + 3 + 15 + 1); + ASSERT_EQ(uriA.pathHead->text.afterLast, input + 4 + 3 + 15 + 1 + 7); + ASSERT_EQ(uriA.pathHead->next->text.first, input + 4 + 3 + 15 + 1 + 7 + 1); + ASSERT_EQ(uriA.pathHead->next->text.afterLast, input + 4 + 3 + 15 + 1 + 7 + 1 + 20); + ASSERT_TRUE(uriA.pathHead->next->next == NULL); + ASSERT_EQ(uriA.pathTail, uriA.pathHead->next); + + ASSERT_EQ(uriA.query.first, input + 4 + 3 + 15 + 1 + 7 + 1 + 20 + 1); + ASSERT_EQ(uriA.query.afterLast, input + 4 + 3 + 15 + 1 + 7 + 1 + 20 + 1 + 15); + ASSERT_TRUE(uriA.fragment.first == NULL); + ASSERT_TRUE(uriA.fragment.afterLast == NULL); + uriFreeUriMembersA(&uriA); } TEST(UriSuite, TestUriComponentsBug20070701) { - UriParserStateA stateA; - UriUriA uriA; - stateA.uri = &uriA; - // 01 01 01 - const char * const input = "a" ":" "b"; - ASSERT_TRUE(0 == uriParseUriA(&stateA, input)); - - ASSERT_TRUE(uriA.scheme.first == input); - ASSERT_TRUE(uriA.scheme.afterLast == input + 1); - ASSERT_TRUE(uriA.userInfo.first == NULL); - ASSERT_TRUE(uriA.userInfo.afterLast == NULL); - ASSERT_TRUE(uriA.hostText.first == NULL); - ASSERT_TRUE(uriA.hostText.afterLast == NULL); - ASSERT_TRUE(uriA.hostData.ipFuture.first == NULL); - ASSERT_TRUE(uriA.hostData.ipFuture.afterLast == NULL); - ASSERT_TRUE(uriA.portText.first == NULL); - ASSERT_TRUE(uriA.portText.afterLast == NULL); - - ASSERT_TRUE(uriA.pathHead->text.first == input + 1 + 1); - ASSERT_TRUE(uriA.pathHead->text.afterLast == input + 1 + 1 + 1); - ASSERT_TRUE(uriA.pathHead->next == NULL); - ASSERT_TRUE(uriA.pathTail == uriA.pathHead); - - ASSERT_TRUE(uriA.query.first == NULL); - ASSERT_TRUE(uriA.query.afterLast == NULL); - ASSERT_TRUE(uriA.fragment.first == NULL); - ASSERT_TRUE(uriA.fragment.afterLast == NULL); - - ASSERT_TRUE(!uriA.absolutePath); - uriFreeUriMembersA(&uriA); + UriParserStateA stateA; + UriUriA uriA; + stateA.uri = &uriA; + // clang-format off + // 01 01 01 + const char * const input = "a" ":" "b"; + // clang-format on + ASSERT_EQ(0, uriParseUriA(&stateA, input)); + + ASSERT_EQ(uriA.scheme.first, input); + ASSERT_EQ(uriA.scheme.afterLast, input + 1); + ASSERT_TRUE(uriA.userInfo.first == NULL); + ASSERT_TRUE(uriA.userInfo.afterLast == NULL); + ASSERT_TRUE(uriA.hostText.first == NULL); + ASSERT_TRUE(uriA.hostText.afterLast == NULL); + ASSERT_TRUE(uriA.hostData.ipFuture.first == NULL); + ASSERT_TRUE(uriA.hostData.ipFuture.afterLast == NULL); + ASSERT_TRUE(uriA.portText.first == NULL); + ASSERT_TRUE(uriA.portText.afterLast == NULL); + + ASSERT_EQ(uriA.pathHead->text.first, input + 1 + 1); + ASSERT_EQ(uriA.pathHead->text.afterLast, input + 1 + 1 + 1); + ASSERT_TRUE(uriA.pathHead->next == NULL); + ASSERT_EQ(uriA.pathTail, uriA.pathHead); + + ASSERT_TRUE(uriA.query.first == NULL); + ASSERT_TRUE(uriA.query.afterLast == NULL); + ASSERT_TRUE(uriA.fragment.first == NULL); + ASSERT_TRUE(uriA.fragment.afterLast == NULL); + + ASSERT_TRUE(!uriA.absolutePath); + uriFreeUriMembersA(&uriA); } TEST(UriSuite, TestUriUserInfoHostPort1) { - // User info with ":", no port - UriParserStateA stateA; - UriUriA uriA; - stateA.uri = &uriA; - // 0 4 0 3 0 7 01 0 9 - const char * const input = "http" "://" "abc:def" "@" "localhost"; - ASSERT_TRUE(0 == uriParseUriA(&stateA, input)); - - ASSERT_TRUE(uriA.userInfo.first == input + 4 + 3); - ASSERT_TRUE(uriA.userInfo.afterLast == input + 4 + 3 + 7); - ASSERT_TRUE(uriA.hostText.first == input + 4 + 3 + 7 + 1); - ASSERT_TRUE(uriA.hostText.afterLast == input + 4 + 3 + 7 + 1 + 9); - ASSERT_TRUE(uriA.portText.first == NULL); - ASSERT_TRUE(uriA.portText.afterLast == NULL); - uriFreeUriMembersA(&uriA); + // User info with ":", no port + UriParserStateA stateA; + UriUriA uriA; + stateA.uri = &uriA; + // clang-format off + // 0 4 0 3 0 7 01 0 9 + const char * const input = "http" "://" "abc:def" "@" "localhost"; + // clang-format on + ASSERT_EQ(0, uriParseUriA(&stateA, input)); + + ASSERT_EQ(uriA.userInfo.first, input + 4 + 3); + ASSERT_EQ(uriA.userInfo.afterLast, input + 4 + 3 + 7); + ASSERT_EQ(uriA.hostText.first, input + 4 + 3 + 7 + 1); + ASSERT_EQ(uriA.hostText.afterLast, input + 4 + 3 + 7 + 1 + 9); + ASSERT_TRUE(uriA.portText.first == NULL); + ASSERT_TRUE(uriA.portText.afterLast == NULL); + uriFreeUriMembersA(&uriA); } TEST(UriSuite, TestUriUserInfoHostPort2) { - // User info with ":", with port - UriParserStateA stateA; - UriUriA uriA; - stateA.uri = &uriA; - // 0 4 0 3 0 7 01 0 9 - const char * const input = "http" "://" "abc:def" "@" "localhost" - // 01 0 3 - ":" "123"; - ASSERT_TRUE(0 == uriParseUriA(&stateA, input)); - - ASSERT_TRUE(uriA.userInfo.first == input + 4 + 3); - ASSERT_TRUE(uriA.userInfo.afterLast == input + 4 + 3 + 7); - ASSERT_TRUE(uriA.hostText.first == input + 4 + 3 + 7 + 1); - ASSERT_TRUE(uriA.hostText.afterLast == input + 4 + 3 + 7 + 1 + 9); - ASSERT_TRUE(uriA.portText.first == input + 4 + 3 + 7 + 1 + 9 + 1); - ASSERT_TRUE(uriA.portText.afterLast == input + 4 + 3 + 7 + 1 + 9 + 1 + 3); - uriFreeUriMembersA(&uriA); + // User info with ":", with port + UriParserStateA stateA; + UriUriA uriA; + stateA.uri = &uriA; + // clang-format off + // 0 4 0 3 0 7 01 0 9 + const char * const input = "http" "://" "abc:def" "@" "localhost" + // 01 0 3 + ":" "123"; + // clang-format on + ASSERT_EQ(0, uriParseUriA(&stateA, input)); + + ASSERT_EQ(uriA.userInfo.first, input + 4 + 3); + ASSERT_EQ(uriA.userInfo.afterLast, input + 4 + 3 + 7); + ASSERT_EQ(uriA.hostText.first, input + 4 + 3 + 7 + 1); + ASSERT_EQ(uriA.hostText.afterLast, input + 4 + 3 + 7 + 1 + 9); + ASSERT_EQ(uriA.portText.first, input + 4 + 3 + 7 + 1 + 9 + 1); + ASSERT_EQ(uriA.portText.afterLast, input + 4 + 3 + 7 + 1 + 9 + 1 + 3); + uriFreeUriMembersA(&uriA); } TEST(UriSuite, TestUriUserInfoHostPort22Bug1948038) { - UriParserStateA stateA; - UriUriA uriA; - stateA.uri = &uriA; + UriParserStateA stateA; + UriUriA uriA; + stateA.uri = &uriA; - int res; + int res; - res = uriParseUriA(&stateA, "http://user:21@host/"); - ASSERT_TRUE(URI_SUCCESS == res); - ASSERT_TRUE(!memcmp(uriA.userInfo.first, "user:21", 7 * sizeof(char))); - ASSERT_TRUE(uriA.userInfo.afterLast - uriA.userInfo.first == 7); - ASSERT_TRUE(!memcmp(uriA.hostText.first, "host", 4 * sizeof(char))); - ASSERT_TRUE(uriA.hostText.afterLast - uriA.hostText.first == 4); - ASSERT_TRUE(uriA.portText.first == NULL); - ASSERT_TRUE(uriA.portText.afterLast == NULL); - uriFreeUriMembersA(&uriA); + res = uriParseUriA(&stateA, "http://user:21@host/"); + ASSERT_EQ(URI_SUCCESS, res); + ASSERT_TRUE(!memcmp(uriA.userInfo.first, "user:21", 7 * sizeof(char))); + ASSERT_EQ(uriA.userInfo.afterLast - uriA.userInfo.first, 7); + ASSERT_TRUE(!memcmp(uriA.hostText.first, "host", 4 * sizeof(char))); + ASSERT_EQ(uriA.hostText.afterLast - uriA.hostText.first, 4); + ASSERT_TRUE(uriA.portText.first == NULL); + ASSERT_TRUE(uriA.portText.afterLast == NULL); + uriFreeUriMembersA(&uriA); - res = uriParseUriA(&stateA, "http://user:1234@192.168.0.1:1234/foo.com"); - ASSERT_TRUE(URI_SUCCESS == res); - uriFreeUriMembersA(&uriA); + res = uriParseUriA(&stateA, "http://user:1234@192.168.0.1:1234/foo.com"); + ASSERT_EQ(URI_SUCCESS, res); + uriFreeUriMembersA(&uriA); - res = uriParseUriA(&stateA, "http://moo:21@moo:21@moo/"); - ASSERT_TRUE(URI_ERROR_SYNTAX == res); - uriFreeUriMembersA(&uriA); + res = uriParseUriA(&stateA, "http://moo:21@moo:21@moo/"); + ASSERT_EQ(URI_ERROR_SYNTAX, res); + uriFreeUriMembersA(&uriA); - res = uriParseUriA(&stateA, "http://moo:21@moo:21@moo:21/"); - ASSERT_TRUE(URI_ERROR_SYNTAX == res); - uriFreeUriMembersA(&uriA); + res = uriParseUriA(&stateA, "http://moo:21@moo:21@moo:21/"); + ASSERT_EQ(URI_ERROR_SYNTAX, res); + uriFreeUriMembersA(&uriA); } TEST(UriSuite, TestUriUserInfoHostPort23Bug3510198One) { - // User info with ":", with port, with escaped chars in password - UriParserStateA stateA; - UriUriA uriA; - stateA.uri = &uriA; - - int res; - // 0 4 0 3 0 10 01 0 4 01 - res = uriParseUriA(&stateA, "http" "://" "user:%2F21" "@" "host" "/"); - ASSERT_TRUE(URI_SUCCESS == res); - ASSERT_TRUE(!memcmp(uriA.userInfo.first, "user:%2F21", 10 * sizeof(char))); - ASSERT_TRUE(uriA.userInfo.afterLast - uriA.userInfo.first == 10); - ASSERT_TRUE(!memcmp(uriA.hostText.first, "host", 4 * sizeof(char))); - ASSERT_TRUE(uriA.hostText.afterLast - uriA.hostText.first == 4); - ASSERT_TRUE(uriA.portText.first == NULL); - ASSERT_TRUE(uriA.portText.afterLast == NULL); - uriFreeUriMembersA(&uriA); + // User info with ":", with port, with escaped chars in password + UriParserStateA stateA; + UriUriA uriA; + stateA.uri = &uriA; + + int res; + // clang-format off + // 0 4 0 3 0 10 01 0 4 01 + res = uriParseUriA(&stateA, "http" "://" "user:%2F21" "@" "host" "/"); + // clang-format on + ASSERT_EQ(URI_SUCCESS, res); + ASSERT_TRUE(!memcmp(uriA.userInfo.first, "user:%2F21", 10 * sizeof(char))); + ASSERT_EQ(uriA.userInfo.afterLast - uriA.userInfo.first, 10); + ASSERT_TRUE(!memcmp(uriA.hostText.first, "host", 4 * sizeof(char))); + ASSERT_EQ(uriA.hostText.afterLast - uriA.hostText.first, 4); + ASSERT_TRUE(uriA.portText.first == NULL); + ASSERT_TRUE(uriA.portText.afterLast == NULL); + uriFreeUriMembersA(&uriA); } TEST(UriSuite, TestUriUserInfoHostPort23Bug3510198Two) { - // User info with ":", with port, with escaped chars in user name and password - UriParserStateA stateA; - UriUriA uriA; - stateA.uri = &uriA; - - int res; - // 0 4 0 3 0 13 01 0 4 01 - res = uriParseUriA(&stateA, "http" "://" "%2Fuser:%2F21" "@" "host" "/"); - ASSERT_TRUE(URI_SUCCESS == res); - ASSERT_TRUE(!memcmp(uriA.userInfo.first, "%2Fuser:%2F21", 13 * sizeof(char))); - ASSERT_TRUE(uriA.userInfo.afterLast - uriA.userInfo.first == 13); - ASSERT_TRUE(!memcmp(uriA.hostText.first, "host", 4 * sizeof(char))); - ASSERT_TRUE(uriA.hostText.afterLast - uriA.hostText.first == 4); - ASSERT_TRUE(uriA.portText.first == NULL); - ASSERT_TRUE(uriA.portText.afterLast == NULL); - uriFreeUriMembersA(&uriA); + // User info with ":", with port, with escaped chars in user name and password + UriParserStateA stateA; + UriUriA uriA; + stateA.uri = &uriA; + + int res; + // clang-format off + // 0 4 0 3 0 13 01 0 4 01 + res = uriParseUriA(&stateA, "http" "://" "%2Fuser:%2F21" "@" "host" "/"); + // clang-format on + ASSERT_EQ(URI_SUCCESS, res); + ASSERT_TRUE(!memcmp(uriA.userInfo.first, "%2Fuser:%2F21", 13 * sizeof(char))); + ASSERT_EQ(uriA.userInfo.afterLast - uriA.userInfo.first, 13); + ASSERT_TRUE(!memcmp(uriA.hostText.first, "host", 4 * sizeof(char))); + ASSERT_EQ(uriA.hostText.afterLast - uriA.hostText.first, 4); + ASSERT_TRUE(uriA.portText.first == NULL); + ASSERT_TRUE(uriA.portText.afterLast == NULL); + uriFreeUriMembersA(&uriA); } TEST(UriSuite, TestUriUserInfoHostPort23Bug3510198Three) { - // User info with ":", with port, with escaped chars in password - UriParserStateA stateA; - UriUriA uriA; - stateA.uri = &uriA; - - int res; - // 0 4 0 3 0 16 01 0 4 01 - res = uriParseUriA(&stateA, "http" "://" "user:!$&'()*+,;=" "@" "host" "/"); - ASSERT_TRUE(URI_SUCCESS == res); - ASSERT_TRUE(!memcmp(uriA.userInfo.first, "user:!$&'()*+,;=", 16 * sizeof(char))); - ASSERT_TRUE(uriA.userInfo.afterLast - uriA.userInfo.first == 16); - ASSERT_TRUE(!memcmp(uriA.hostText.first, "host", 4 * sizeof(char))); - ASSERT_TRUE(uriA.hostText.afterLast - uriA.hostText.first == 4); - ASSERT_TRUE(uriA.portText.first == NULL); - ASSERT_TRUE(uriA.portText.afterLast == NULL); - uriFreeUriMembersA(&uriA); + // User info with ":", with port, with escaped chars in password + UriParserStateA stateA; + UriUriA uriA; + stateA.uri = &uriA; + + int res; + // clang-format off + // 0 4 0 3 0 16 01 0 4 01 + res = uriParseUriA(&stateA, "http" "://" "user:!$&'()*+,;=" "@" "host" "/"); + // clang-format on + ASSERT_EQ(URI_SUCCESS, res); + ASSERT_TRUE(!memcmp(uriA.userInfo.first, "user:!$&'()*+,;=", 16 * sizeof(char))); + ASSERT_EQ(uriA.userInfo.afterLast - uriA.userInfo.first, 16); + ASSERT_TRUE(!memcmp(uriA.hostText.first, "host", 4 * sizeof(char))); + ASSERT_EQ(uriA.hostText.afterLast - uriA.hostText.first, 4); + ASSERT_TRUE(uriA.portText.first == NULL); + ASSERT_TRUE(uriA.portText.afterLast == NULL); + uriFreeUriMembersA(&uriA); } TEST(UriSuite, TestUriUserInfoHostPort23Bug3510198Four) { - // User info with ":", with port, with escaped chars in user name and password - UriParserStateA stateA; - UriUriA uriA; - stateA.uri = &uriA; - - int res; - // 0 4 0 3 0 20 01 0 4 01 - res = uriParseUriA(&stateA, "http" "://" "!$&'()*+,;=:password" "@" "host" "/"); - ASSERT_TRUE(URI_SUCCESS == res); - ASSERT_TRUE(!memcmp(uriA.userInfo.first, "!$&'()*+,;=:password", 20 * sizeof(char))); - ASSERT_TRUE(uriA.userInfo.afterLast - uriA.userInfo.first == 20); - ASSERT_TRUE(!memcmp(uriA.hostText.first, "host", 4 * sizeof(char))); - ASSERT_TRUE(uriA.hostText.afterLast - uriA.hostText.first == 4); - ASSERT_TRUE(uriA.portText.first == NULL); - ASSERT_TRUE(uriA.portText.afterLast == NULL); - uriFreeUriMembersA(&uriA); + // User info with ":", with port, with escaped chars in user name and password + UriParserStateA stateA; + UriUriA uriA; + stateA.uri = &uriA; + + int res; + // clang-format off + // 0 4 0 3 0 20 01 0 4 01 + res = uriParseUriA(&stateA, "http" "://" "!$&'()*+,;=:password" "@" "host" "/"); + // clang-format on + ASSERT_EQ(URI_SUCCESS, res); + ASSERT_TRUE(!memcmp(uriA.userInfo.first, "!$&'()*+,;=:password", 20 * sizeof(char))); + ASSERT_EQ(uriA.userInfo.afterLast - uriA.userInfo.first, 20); + ASSERT_TRUE(!memcmp(uriA.hostText.first, "host", 4 * sizeof(char))); + ASSERT_EQ(uriA.hostText.afterLast - uriA.hostText.first, 4); + ASSERT_TRUE(uriA.portText.first == NULL); + ASSERT_TRUE(uriA.portText.afterLast == NULL); + uriFreeUriMembersA(&uriA); } TEST(UriSuite, TestUriUserInfoHostPort23Bug3510198RelatedOne) { - // Empty user info - UriParserStateA stateA; - UriUriA uriA; - stateA.uri = &uriA; - - int res; - // 0 4 0 3 01 0 4 01 - res = uriParseUriA(&stateA, "http" "://" "@" "host" "/"); - ASSERT_TRUE(URI_SUCCESS == res); - ASSERT_TRUE(uriA.userInfo.afterLast != NULL); - ASSERT_TRUE(uriA.userInfo.first != NULL); - ASSERT_TRUE(uriA.userInfo.afterLast - uriA.userInfo.first == 0); - ASSERT_TRUE(!memcmp(uriA.hostText.first, "host", 4 * sizeof(char))); - ASSERT_TRUE(uriA.hostText.afterLast - uriA.hostText.first == 4); - ASSERT_TRUE(uriA.portText.first == NULL); - ASSERT_TRUE(uriA.portText.afterLast == NULL); - uriFreeUriMembersA(&uriA); + // Empty user info + UriParserStateA stateA; + UriUriA uriA; + stateA.uri = &uriA; + + int res; + // clang-format off + // 0 4 0 3 01 0 4 01 + res = uriParseUriA(&stateA, "http" "://" "@" "host" "/"); + // clang-format on + ASSERT_EQ(URI_SUCCESS, res); + ASSERT_TRUE(uriA.userInfo.afterLast != NULL); + ASSERT_TRUE(uriA.userInfo.first != NULL); + ASSERT_EQ(uriA.userInfo.afterLast - uriA.userInfo.first, 0); + ASSERT_TRUE(!memcmp(uriA.hostText.first, "host", 4 * sizeof(char))); + ASSERT_EQ(uriA.hostText.afterLast - uriA.hostText.first, 4); + ASSERT_TRUE(uriA.portText.first == NULL); + ASSERT_TRUE(uriA.portText.afterLast == NULL); + uriFreeUriMembersA(&uriA); } TEST(UriSuite, TestUriUserInfoHostPort23Bug3510198RelatedOneTwo) { - // Empty user info - UriParserStateA stateA; - UriUriA uriA; - stateA.uri = &uriA; - - int res; - // 0 4 0 3 0 7 01 - res = uriParseUriA(&stateA, "http" "://" "%2Fhost" "/"); - ASSERT_TRUE(URI_SUCCESS == res); - ASSERT_TRUE(uriA.userInfo.afterLast == NULL); - ASSERT_TRUE(uriA.userInfo.first == NULL); - ASSERT_TRUE(!memcmp(uriA.hostText.first, "%2Fhost", 7 * sizeof(char))); - ASSERT_TRUE(uriA.hostText.afterLast - uriA.hostText.first == 7); - ASSERT_TRUE(uriA.portText.first == NULL); - ASSERT_TRUE(uriA.portText.afterLast == NULL); - uriFreeUriMembersA(&uriA); + // Empty user info + UriParserStateA stateA; + UriUriA uriA; + stateA.uri = &uriA; + + int res; + // clang-format off + // 0 4 0 3 0 7 01 + res = uriParseUriA(&stateA, "http" "://" "%2Fhost" "/"); + // clang-format on + ASSERT_EQ(URI_SUCCESS, res); + ASSERT_TRUE(uriA.userInfo.afterLast == NULL); + ASSERT_TRUE(uriA.userInfo.first == NULL); + ASSERT_TRUE(!memcmp(uriA.hostText.first, "%2Fhost", 7 * sizeof(char))); + ASSERT_EQ(uriA.hostText.afterLast - uriA.hostText.first, 7); + ASSERT_TRUE(uriA.portText.first == NULL); + ASSERT_TRUE(uriA.portText.afterLast == NULL); + uriFreeUriMembersA(&uriA); } TEST(UriSuite, TestUriUserInfoHostPort23Bug3510198RelatedTwo) { - // Several colons in userinfo - UriParserStateA stateA; - UriUriA uriA; - stateA.uri = &uriA; - - int res; - // 0 4 0 3 0 2 01 0 4 01 - res = uriParseUriA(&stateA, "http" "://" "::" "@" "host" "/"); - ASSERT_TRUE(URI_SUCCESS == res); - ASSERT_TRUE(!memcmp(uriA.userInfo.first, "::", 2 * sizeof(char))); - ASSERT_TRUE(uriA.userInfo.afterLast - uriA.userInfo.first == 2); - ASSERT_TRUE(!memcmp(uriA.hostText.first, "host", 4 * sizeof(char))); - ASSERT_TRUE(uriA.hostText.afterLast - uriA.hostText.first == 4); - ASSERT_TRUE(uriA.portText.first == NULL); - ASSERT_TRUE(uriA.portText.afterLast == NULL); - uriFreeUriMembersA(&uriA); + // Several colons in userinfo + UriParserStateA stateA; + UriUriA uriA; + stateA.uri = &uriA; + + int res; + // clang-format off + // 0 4 0 3 0 2 01 0 4 01 + res = uriParseUriA(&stateA, "http" "://" "::" "@" "host" "/"); + // clang-format on + ASSERT_EQ(URI_SUCCESS, res); + ASSERT_TRUE(!memcmp(uriA.userInfo.first, "::", 2 * sizeof(char))); + ASSERT_EQ(uriA.userInfo.afterLast - uriA.userInfo.first, 2); + ASSERT_TRUE(!memcmp(uriA.hostText.first, "host", 4 * sizeof(char))); + ASSERT_EQ(uriA.hostText.afterLast - uriA.hostText.first, 4); + ASSERT_TRUE(uriA.portText.first == NULL); + ASSERT_TRUE(uriA.portText.afterLast == NULL); + uriFreeUriMembersA(&uriA); } TEST(UriSuite, TestUriUserInfoHostPort3) { - // User info without ":", no port - UriParserStateA stateA; - UriUriA uriA; - stateA.uri = &uriA; - // 0 4 0 3 0 7 01 0 9 - const char * const input = "http" "://" "abcdefg" "@" "localhost"; - ASSERT_TRUE(0 == uriParseUriA(&stateA, input)); - - ASSERT_TRUE(uriA.userInfo.first == input + 4 + 3); - ASSERT_TRUE(uriA.userInfo.afterLast == input + 4 + 3 + 7); - ASSERT_TRUE(uriA.hostText.first == input + 4 + 3 + 7 + 1); - ASSERT_TRUE(uriA.hostText.afterLast == input + 4 + 3 + 7 + 1 + 9); - ASSERT_TRUE(uriA.portText.first == NULL); - ASSERT_TRUE(uriA.portText.afterLast == NULL); - uriFreeUriMembersA(&uriA); + // User info without ":", no port + UriParserStateA stateA; + UriUriA uriA; + stateA.uri = &uriA; + // clang-format off + // 0 4 0 3 0 7 01 0 9 + const char * const input = "http" "://" "abcdefg" "@" "localhost"; + // clang-format on + ASSERT_EQ(0, uriParseUriA(&stateA, input)); + + ASSERT_EQ(uriA.userInfo.first, input + 4 + 3); + ASSERT_EQ(uriA.userInfo.afterLast, input + 4 + 3 + 7); + ASSERT_EQ(uriA.hostText.first, input + 4 + 3 + 7 + 1); + ASSERT_EQ(uriA.hostText.afterLast, input + 4 + 3 + 7 + 1 + 9); + ASSERT_TRUE(uriA.portText.first == NULL); + ASSERT_TRUE(uriA.portText.afterLast == NULL); + uriFreeUriMembersA(&uriA); } TEST(UriSuite, TestUriUserInfoHostPort4) { - // User info without ":", with port - UriParserStateA stateA; - UriUriA uriA; - stateA.uri = &uriA; - // 0 4 0 3 0 7 01 0 9 - const char * const input = "http" "://" "abcdefg" "@" "localhost" - // 01 0 3 - ":" "123"; - ASSERT_TRUE(0 == uriParseUriA(&stateA, input)); - - ASSERT_TRUE(uriA.userInfo.first == input + 4 + 3); - ASSERT_TRUE(uriA.userInfo.afterLast == input + 4 + 3 + 7); - ASSERT_TRUE(uriA.hostText.first == input + 4 + 3 + 7 + 1); - ASSERT_TRUE(uriA.hostText.afterLast == input + 4 + 3 + 7 + 1 + 9); - ASSERT_TRUE(uriA.portText.first == input + 4 + 3 + 7 + 1 + 9 + 1); - ASSERT_TRUE(uriA.portText.afterLast == input + 4 + 3 + 7 + 1 + 9 + 1 + 3); - uriFreeUriMembersA(&uriA); + // User info without ":", with port + UriParserStateA stateA; + UriUriA uriA; + stateA.uri = &uriA; + // clang-format off + // 0 4 0 3 0 7 01 0 9 + const char * const input = "http" "://" "abcdefg" "@" "localhost" + // 01 0 3 + ":" "123"; + // clang-format on + ASSERT_EQ(0, uriParseUriA(&stateA, input)); + + ASSERT_EQ(uriA.userInfo.first, input + 4 + 3); + ASSERT_EQ(uriA.userInfo.afterLast, input + 4 + 3 + 7); + ASSERT_EQ(uriA.hostText.first, input + 4 + 3 + 7 + 1); + ASSERT_EQ(uriA.hostText.afterLast, input + 4 + 3 + 7 + 1 + 9); + ASSERT_EQ(uriA.portText.first, input + 4 + 3 + 7 + 1 + 9 + 1); + ASSERT_EQ(uriA.portText.afterLast, input + 4 + 3 + 7 + 1 + 9 + 1 + 3); + uriFreeUriMembersA(&uriA); } TEST(UriSuite, TestUriUserInfoHostPort5) { - // No user info, no port - UriParserStateA stateA; - UriUriA uriA; - stateA.uri = &uriA; - // 0 4 0 3 0 9 - const char * const input = "http" "://" "localhost"; - ASSERT_TRUE(0 == uriParseUriA(&stateA, input)); - - ASSERT_TRUE(uriA.userInfo.first == NULL); - ASSERT_TRUE(uriA.userInfo.afterLast == NULL); - ASSERT_TRUE(uriA.hostText.first == input + 4 + 3); - ASSERT_TRUE(uriA.hostText.afterLast == input + 4 + 3 + 9); - ASSERT_TRUE(uriA.portText.first == NULL); - ASSERT_TRUE(uriA.portText.afterLast == NULL); - uriFreeUriMembersA(&uriA); + // No user info, no port + UriParserStateA stateA; + UriUriA uriA; + stateA.uri = &uriA; + // clang-format off + // 0 4 0 3 0 9 + const char * const input = "http" "://" "localhost"; + // clang-format on + ASSERT_EQ(0, uriParseUriA(&stateA, input)); + + ASSERT_TRUE(uriA.userInfo.first == NULL); + ASSERT_TRUE(uriA.userInfo.afterLast == NULL); + ASSERT_EQ(uriA.hostText.first, input + 4 + 3); + ASSERT_EQ(uriA.hostText.afterLast, input + 4 + 3 + 9); + ASSERT_TRUE(uriA.portText.first == NULL); + ASSERT_TRUE(uriA.portText.afterLast == NULL); + uriFreeUriMembersA(&uriA); } TEST(UriSuite, TestUriUserInfoHostPort6) { - // No user info, with port - UriParserStateA stateA; - UriUriA uriA; - stateA.uri = &uriA; - // 0 4 0 3 0 9 01 0 3 - const char * const input = "http" "://" "localhost" ":" "123"; - ASSERT_TRUE(0 == uriParseUriA(&stateA, input)); - - ASSERT_TRUE(uriA.userInfo.first == NULL); - ASSERT_TRUE(uriA.userInfo.afterLast == NULL); - ASSERT_TRUE(uriA.hostText.first == input + 4 + 3); - ASSERT_TRUE(uriA.hostText.afterLast == input + 4 + 3 + 9); - ASSERT_TRUE(uriA.portText.first == input + 4 + 3 + 9 + 1); - ASSERT_TRUE(uriA.portText.afterLast == input + 4 + 3 + 9 + 1 + 3); - uriFreeUriMembersA(&uriA); + // No user info, with port + UriParserStateA stateA; + UriUriA uriA; + stateA.uri = &uriA; + // clang-format off + // 0 4 0 3 0 9 01 0 3 + const char * const input = "http" "://" "localhost" ":" "123"; + // clang-format on + ASSERT_EQ(0, uriParseUriA(&stateA, input)); + + ASSERT_TRUE(uriA.userInfo.first == NULL); + ASSERT_TRUE(uriA.userInfo.afterLast == NULL); + ASSERT_EQ(uriA.hostText.first, input + 4 + 3); + ASSERT_EQ(uriA.hostText.afterLast, input + 4 + 3 + 9); + ASSERT_EQ(uriA.portText.first, input + 4 + 3 + 9 + 1); + ASSERT_EQ(uriA.portText.afterLast, input + 4 + 3 + 9 + 1 + 3); + uriFreeUriMembersA(&uriA); } TEST(UriSuite, TestUriHostRegname) { - UriParserStateA stateA; - UriUriA uriA; - stateA.uri = &uriA; - // 0 4 0 3 0 11 - const char * const input = "http" "://" "example.com"; - ASSERT_TRUE(0 == uriParseUriA(&stateA, input)); - - ASSERT_TRUE(uriA.hostText.first == input + 4 + 3); - ASSERT_TRUE(uriA.hostText.afterLast == input + 4 + 3 + 11); - ASSERT_TRUE(uriA.hostData.ip4 == NULL); - ASSERT_TRUE(uriA.hostData.ip6 == NULL); - ASSERT_TRUE(uriA.hostData.ipFuture.first == NULL); - ASSERT_TRUE(uriA.hostData.ipFuture.afterLast == NULL); - uriFreeUriMembersA(&uriA); + UriParserStateA stateA; + UriUriA uriA; + stateA.uri = &uriA; + // clang-format off + // 0 4 0 3 0 11 + const char * const input = "http" "://" "example.com"; + // clang-format on + ASSERT_EQ(0, uriParseUriA(&stateA, input)); + + ASSERT_EQ(uriA.hostText.first, input + 4 + 3); + ASSERT_EQ(uriA.hostText.afterLast, input + 4 + 3 + 11); + ASSERT_TRUE(uriA.hostData.ip4 == NULL); + ASSERT_TRUE(uriA.hostData.ip6 == NULL); + ASSERT_TRUE(uriA.hostData.ipFuture.first == NULL); + ASSERT_TRUE(uriA.hostData.ipFuture.afterLast == NULL); + uriFreeUriMembersA(&uriA); } TEST(UriSuite, TestUriHostIpFour1) { - UriParserStateA stateA; - UriUriA uriA; - stateA.uri = &uriA; - // 0 4 0 3 0 7 01 0 2 - const char * const input = "http" "://" "1.2.3.4" ":" "80"; - ASSERT_TRUE(0 == uriParseUriA(&stateA, input)); - - ASSERT_TRUE(uriA.hostText.first == input + 4 + 3); - ASSERT_TRUE(uriA.hostText.afterLast == input + 4 + 3 + 7); - ASSERT_TRUE(uriA.hostData.ip4 != NULL); - ASSERT_TRUE(uriA.hostData.ip6 == NULL); - ASSERT_TRUE(uriA.hostData.ipFuture.first == NULL); - ASSERT_TRUE(uriA.hostData.ipFuture.afterLast == NULL); - uriFreeUriMembersA(&uriA); + UriParserStateA stateA; + UriUriA uriA; + stateA.uri = &uriA; + // clang-format off + // 0 4 0 3 0 7 01 0 2 + const char * const input = "http" "://" "1.2.3.4" ":" "80"; + // clang-format on + ASSERT_EQ(0, uriParseUriA(&stateA, input)); + + ASSERT_EQ(uriA.hostText.first, input + 4 + 3); + ASSERT_EQ(uriA.hostText.afterLast, input + 4 + 3 + 7); + ASSERT_TRUE(uriA.hostData.ip4 != NULL); + ASSERT_TRUE(uriA.hostData.ip6 == NULL); + ASSERT_TRUE(uriA.hostData.ipFuture.first == NULL); + ASSERT_TRUE(uriA.hostData.ipFuture.afterLast == NULL); + uriFreeUriMembersA(&uriA); } TEST(UriSuite, TestUriHostIpFour2) { - UriParserStateA stateA; - UriUriA uriA; - stateA.uri = &uriA; - // 0 4 0 3 0 7 - const char * const input = "http" "://" "1.2.3.4"; - ASSERT_TRUE(0 == uriParseUriA(&stateA, input)); - - ASSERT_TRUE(uriA.hostText.first == input + 4 + 3); - ASSERT_TRUE(uriA.hostText.afterLast == input + 4 + 3 + 7); - ASSERT_TRUE(uriA.hostData.ip4 != NULL); - ASSERT_TRUE(uriA.hostData.ip6 == NULL); - ASSERT_TRUE(uriA.hostData.ipFuture.first == NULL); - ASSERT_TRUE(uriA.hostData.ipFuture.afterLast == NULL); - uriFreeUriMembersA(&uriA); + UriParserStateA stateA; + UriUriA uriA; + stateA.uri = &uriA; + // clang-format off + // 0 4 0 3 0 7 + const char * const input = "http" "://" "1.2.3.4"; + // clang-format on + ASSERT_EQ(0, uriParseUriA(&stateA, input)); + + ASSERT_EQ(uriA.hostText.first, input + 4 + 3); + ASSERT_EQ(uriA.hostText.afterLast, input + 4 + 3 + 7); + ASSERT_TRUE(uriA.hostData.ip4 != NULL); + ASSERT_TRUE(uriA.hostData.ip6 == NULL); + ASSERT_TRUE(uriA.hostData.ipFuture.first == NULL); + ASSERT_TRUE(uriA.hostData.ipFuture.afterLast == NULL); + uriFreeUriMembersA(&uriA); } TEST(UriSuite, TestUriHostIpSix1) { - UriParserStateA stateA; - UriUriA uriA; - stateA.uri = &uriA; - // 0 4 0 3 01 45 01 0 2 - const char * const input = "http" "://" "[::1]" ":" "80"; - ASSERT_TRUE(0 == uriParseUriA(&stateA, input)); - - ASSERT_TRUE(uriA.hostText.first == input + 4 + 3 + 1); - ASSERT_TRUE(uriA.hostText.afterLast == input + 4 + 3 + 4); - ASSERT_TRUE(uriA.hostData.ip4 == NULL); - ASSERT_TRUE(uriA.hostData.ip6 != NULL); - ASSERT_TRUE(uriA.hostData.ipFuture.first == NULL); - ASSERT_TRUE(uriA.hostData.ipFuture.afterLast == NULL); - uriFreeUriMembersA(&uriA); + UriParserStateA stateA; + UriUriA uriA; + stateA.uri = &uriA; + // clang-format off + // 0 4 0 3 01 45 01 0 2 + const char * const input = "http" "://" "[::1]" ":" "80"; + // clang-format on + ASSERT_EQ(0, uriParseUriA(&stateA, input)); + + ASSERT_EQ(uriA.hostText.first, input + 4 + 3 + 1); + ASSERT_EQ(uriA.hostText.afterLast, input + 4 + 3 + 4); + ASSERT_TRUE(uriA.hostData.ip4 == NULL); + ASSERT_TRUE(uriA.hostData.ip6 != NULL); + ASSERT_TRUE(uriA.hostData.ipFuture.first == NULL); + ASSERT_TRUE(uriA.hostData.ipFuture.afterLast == NULL); + uriFreeUriMembersA(&uriA); } TEST(UriSuite, TestUriHostIpSix2) { - UriParserStateA stateA; - UriUriA uriA; - stateA.uri = &uriA; - // 0 4 0 3 01 45 - const char * const input = "http" "://" "[::1]"; - ASSERT_TRUE(0 == uriParseUriA(&stateA, input)); - - ASSERT_TRUE(uriA.hostText.first == input + 4 + 3 + 1); - ASSERT_TRUE(uriA.hostText.afterLast == input + 4 + 3 + 4); - ASSERT_TRUE(uriA.hostData.ip4 == NULL); - ASSERT_TRUE(uriA.hostData.ip6 != NULL); - ASSERT_TRUE(uriA.hostData.ipFuture.first == NULL); - ASSERT_TRUE(uriA.hostData.ipFuture.afterLast == NULL); - uriFreeUriMembersA(&uriA); + UriParserStateA stateA; + UriUriA uriA; + stateA.uri = &uriA; + // clang-format off + // 0 4 0 3 01 45 + const char * const input = "http" "://" "[::1]"; + // clang-format on + ASSERT_EQ(0, uriParseUriA(&stateA, input)); + + ASSERT_EQ(uriA.hostText.first, input + 4 + 3 + 1); + ASSERT_EQ(uriA.hostText.afterLast, input + 4 + 3 + 4); + ASSERT_TRUE(uriA.hostData.ip4 == NULL); + ASSERT_TRUE(uriA.hostData.ip6 != NULL); + ASSERT_TRUE(uriA.hostData.ipFuture.first == NULL); + ASSERT_TRUE(uriA.hostData.ipFuture.afterLast == NULL); + uriFreeUriMembersA(&uriA); } TEST(UriSuite, TestUriHostEmpty) { - UriParserStateA stateA; - UriUriA uriA; - stateA.uri = &uriA; - // 0 4 0 3 01 0 3 - const char * const input = "http" "://" ":" "123"; - const int res = uriParseUriA(&stateA, input); - ASSERT_TRUE(URI_SUCCESS == res); - ASSERT_TRUE(uriA.userInfo.first == NULL); - ASSERT_TRUE(uriA.userInfo.afterLast == NULL); - ASSERT_TRUE(uriA.hostText.first != NULL); - ASSERT_TRUE(uriA.hostText.afterLast != NULL); - ASSERT_TRUE(uriA.hostText.afterLast - uriA.hostText.first == 0); - ASSERT_TRUE(uriA.portText.first == input + 4 + 3 + 1); - ASSERT_TRUE(uriA.portText.afterLast == input + 4 + 3 + 1 + 3); - uriFreeUriMembersA(&uriA); + UriParserStateA stateA; + UriUriA uriA; + stateA.uri = &uriA; + // clang-format off + // 0 4 0 3 01 0 3 + const char * const input = "http" "://" ":" "123"; + // clang-format on + const int res = uriParseUriA(&stateA, input); + ASSERT_EQ(URI_SUCCESS, res); + ASSERT_TRUE(uriA.userInfo.first == NULL); + ASSERT_TRUE(uriA.userInfo.afterLast == NULL); + ASSERT_TRUE(uriA.hostText.first != NULL); + ASSERT_TRUE(uriA.hostText.afterLast != NULL); + ASSERT_EQ(uriA.hostText.afterLast - uriA.hostText.first, 0); + ASSERT_EQ(uriA.portText.first, input + 4 + 3 + 1); + ASSERT_EQ(uriA.portText.afterLast, input + 4 + 3 + 1 + 3); + uriFreeUriMembersA(&uriA); } TEST(UriSuite, TestUriHostIpFuture) { - // TODO + UriUriA uri; + // clang-format off + // 0 2 01 0 8 01 + const char * const input = "//" "[" "v7.hello" "]"; + // clang-format on + ASSERT_EQ(uriParseSingleUriA(&uri, input, NULL), URI_SUCCESS); + ASSERT_EQ(uri.hostText.first, input + 2 + 1); + ASSERT_EQ(uri.hostText.afterLast, input + 2 + 1 + 8); + ASSERT_EQ(uri.hostData.ipFuture.first, uri.hostText.first); + ASSERT_EQ(uri.hostData.ipFuture.afterLast, uri.hostText.afterLast); + uriFreeUriMembersA(&uri); } namespace { - bool testEscapingHelper(const wchar_t * in, const wchar_t * expectedOut, - bool spaceToPlus = false, bool normalizeBreaks = false) { - wchar_t * const buffer = new wchar_t[(normalizeBreaks ? 6 : 3) - * wcslen(in) + 1]; - if (uriEscapeW(in, buffer, spaceToPlus, normalizeBreaks) - != buffer + wcslen(expectedOut)) { - delete [] buffer; - return false; - } - - const bool equal = !wcscmp(buffer, expectedOut); - delete [] buffer; - return equal; - } +bool testEscapingHelper(const wchar_t * in, const wchar_t * expectedOut, + bool spaceToPlus = false, bool normalizeBreaks = false) { + wchar_t * const buffer = new wchar_t[(normalizeBreaks ? 6 : 3) * wcslen(in) + 1]; + if (uriEscapeW(in, buffer, spaceToPlus, normalizeBreaks) + != buffer + wcslen(expectedOut)) { + delete[] buffer; + return false; + } + + const bool equal = !wcscmp(buffer, expectedOut); + delete[] buffer; + return equal; +} } // namespace TEST(UriSuite, TestEscaping) { - const bool SPACE_TO_PLUS = true; - const bool SPACE_TO_PERCENT = false; - const bool KEEP_UNMODIFIED = false; - const bool NORMALIZE = true; - - // '+' to ' ' - ASSERT_TRUE(testEscapingHelper(L"abc def", L"abc+def", SPACE_TO_PLUS)); - ASSERT_TRUE(testEscapingHelper(L"abc def", L"abc%20def", SPACE_TO_PERCENT)); - - // Percent encoding - ASSERT_TRUE(testEscapingHelper(L"\x00", L"\0")); - ASSERT_TRUE(testEscapingHelper(L"\x01", L"%01")); - ASSERT_TRUE(testEscapingHelper(L"\xff", L"%FF")); - - // Linebreak normalization - ASSERT_TRUE(testEscapingHelper(L"\x0d", L"%0D%0A", SPACE_TO_PLUS, NORMALIZE)); - ASSERT_TRUE(testEscapingHelper(L"g\x0d", L"g%0D%0A", SPACE_TO_PLUS, NORMALIZE)); - ASSERT_TRUE(testEscapingHelper(L"\x0dg", L"%0D%0Ag", SPACE_TO_PLUS, NORMALIZE)); - ASSERT_TRUE(testEscapingHelper(L"\x0d", L"%0D", SPACE_TO_PLUS, KEEP_UNMODIFIED)); - ASSERT_TRUE(testEscapingHelper(L"g\x0d", L"g%0D", SPACE_TO_PLUS, KEEP_UNMODIFIED)); - ASSERT_TRUE(testEscapingHelper(L"\x0dg", L"%0Dg", SPACE_TO_PLUS, KEEP_UNMODIFIED)); - - ASSERT_TRUE(testEscapingHelper(L"\x0a", L"%0D%0A", SPACE_TO_PLUS, NORMALIZE)); - ASSERT_TRUE(testEscapingHelper(L"g\x0a", L"g%0D%0A", SPACE_TO_PLUS, NORMALIZE)); - ASSERT_TRUE(testEscapingHelper(L"\x0ag", L"%0D%0Ag", SPACE_TO_PLUS, NORMALIZE)); - ASSERT_TRUE(testEscapingHelper(L"\x0a", L"%0A", SPACE_TO_PLUS, KEEP_UNMODIFIED)); - ASSERT_TRUE(testEscapingHelper(L"g\x0a", L"g%0A", SPACE_TO_PLUS, KEEP_UNMODIFIED)); - ASSERT_TRUE(testEscapingHelper(L"\x0ag", L"%0Ag", SPACE_TO_PLUS, KEEP_UNMODIFIED)); - - ASSERT_TRUE(testEscapingHelper(L"\x0d\x0a", L"%0D%0A", SPACE_TO_PLUS, NORMALIZE)); - ASSERT_TRUE(testEscapingHelper(L"g\x0d\x0a", L"g%0D%0A", SPACE_TO_PLUS, NORMALIZE)); - ASSERT_TRUE(testEscapingHelper(L"\x0d\x0ag", L"%0D%0Ag", SPACE_TO_PLUS, NORMALIZE)); - ASSERT_TRUE(testEscapingHelper(L"\x0d\x0a", L"%0D%0A", SPACE_TO_PLUS, KEEP_UNMODIFIED)); - ASSERT_TRUE(testEscapingHelper(L"g\x0d\x0a", L"g%0D%0A", SPACE_TO_PLUS, KEEP_UNMODIFIED)); - ASSERT_TRUE(testEscapingHelper(L"\x0d\x0ag", L"%0D%0Ag", SPACE_TO_PLUS, KEEP_UNMODIFIED)); - - ASSERT_TRUE(testEscapingHelper(L"\x0a\x0d", L"%0D%0A%0D%0A", SPACE_TO_PLUS, NORMALIZE)); - ASSERT_TRUE(testEscapingHelper(L"g\x0a\x0d", L"g%0D%0A%0D%0A", SPACE_TO_PLUS, NORMALIZE)); - ASSERT_TRUE(testEscapingHelper(L"\x0a\x0dg", L"%0D%0A%0D%0Ag", SPACE_TO_PLUS, NORMALIZE)); - ASSERT_TRUE(testEscapingHelper(L"\x0a\x0d", L"%0A%0D", SPACE_TO_PLUS, KEEP_UNMODIFIED)); - ASSERT_TRUE(testEscapingHelper(L"g\x0a\x0d", L"g%0A%0D", SPACE_TO_PLUS, KEEP_UNMODIFIED)); - ASSERT_TRUE(testEscapingHelper(L"\x0a\x0dg", L"%0A%0Dg", SPACE_TO_PLUS, KEEP_UNMODIFIED)); + const bool SPACE_TO_PLUS = true; + const bool SPACE_TO_PERCENT = false; + const bool KEEP_UNMODIFIED = false; + const bool NORMALIZE = true; + + // '+' to ' ' + ASSERT_TRUE(testEscapingHelper(L"abc def", L"abc+def", SPACE_TO_PLUS)); + ASSERT_TRUE(testEscapingHelper(L"abc def", L"abc%20def", SPACE_TO_PERCENT)); + + // Percent encoding + ASSERT_TRUE(testEscapingHelper(L"\x00", L"\0")); + ASSERT_TRUE(testEscapingHelper(L"\x01", L"%01")); + ASSERT_TRUE(testEscapingHelper(L"\xff", L"%FF")); + + // Linebreak normalization + ASSERT_TRUE(testEscapingHelper(L"\x0d", L"%0D%0A", SPACE_TO_PLUS, NORMALIZE)); + ASSERT_TRUE(testEscapingHelper(L"g\x0d", L"g%0D%0A", SPACE_TO_PLUS, NORMALIZE)); + ASSERT_TRUE(testEscapingHelper(L"\x0dg", L"%0D%0Ag", SPACE_TO_PLUS, NORMALIZE)); + ASSERT_TRUE(testEscapingHelper(L"\x0d", L"%0D", SPACE_TO_PLUS, KEEP_UNMODIFIED)); + ASSERT_TRUE(testEscapingHelper(L"g\x0d", L"g%0D", SPACE_TO_PLUS, KEEP_UNMODIFIED)); + ASSERT_TRUE(testEscapingHelper(L"\x0dg", L"%0Dg", SPACE_TO_PLUS, KEEP_UNMODIFIED)); + + ASSERT_TRUE(testEscapingHelper(L"\x0a", L"%0D%0A", SPACE_TO_PLUS, NORMALIZE)); + ASSERT_TRUE(testEscapingHelper(L"g\x0a", L"g%0D%0A", SPACE_TO_PLUS, NORMALIZE)); + ASSERT_TRUE(testEscapingHelper(L"\x0ag", L"%0D%0Ag", SPACE_TO_PLUS, NORMALIZE)); + ASSERT_TRUE(testEscapingHelper(L"\x0a", L"%0A", SPACE_TO_PLUS, KEEP_UNMODIFIED)); + ASSERT_TRUE(testEscapingHelper(L"g\x0a", L"g%0A", SPACE_TO_PLUS, KEEP_UNMODIFIED)); + ASSERT_TRUE(testEscapingHelper(L"\x0ag", L"%0Ag", SPACE_TO_PLUS, KEEP_UNMODIFIED)); + + ASSERT_TRUE(testEscapingHelper(L"\x0d\x0a", L"%0D%0A", SPACE_TO_PLUS, NORMALIZE)); + ASSERT_TRUE(testEscapingHelper(L"g\x0d\x0a", L"g%0D%0A", SPACE_TO_PLUS, NORMALIZE)); + ASSERT_TRUE(testEscapingHelper(L"\x0d\x0ag", L"%0D%0Ag", SPACE_TO_PLUS, NORMALIZE)); + ASSERT_TRUE( + testEscapingHelper(L"\x0d\x0a", L"%0D%0A", SPACE_TO_PLUS, KEEP_UNMODIFIED)); + ASSERT_TRUE( + testEscapingHelper(L"g\x0d\x0a", L"g%0D%0A", SPACE_TO_PLUS, KEEP_UNMODIFIED)); + ASSERT_TRUE( + testEscapingHelper(L"\x0d\x0ag", L"%0D%0Ag", SPACE_TO_PLUS, KEEP_UNMODIFIED)); + + ASSERT_TRUE( + testEscapingHelper(L"\x0a\x0d", L"%0D%0A%0D%0A", SPACE_TO_PLUS, NORMALIZE)); + ASSERT_TRUE( + testEscapingHelper(L"g\x0a\x0d", L"g%0D%0A%0D%0A", SPACE_TO_PLUS, NORMALIZE)); + ASSERT_TRUE( + testEscapingHelper(L"\x0a\x0dg", L"%0D%0A%0D%0Ag", SPACE_TO_PLUS, NORMALIZE)); + ASSERT_TRUE( + testEscapingHelper(L"\x0a\x0d", L"%0A%0D", SPACE_TO_PLUS, KEEP_UNMODIFIED)); + ASSERT_TRUE( + testEscapingHelper(L"g\x0a\x0d", L"g%0A%0D", SPACE_TO_PLUS, KEEP_UNMODIFIED)); + ASSERT_TRUE( + testEscapingHelper(L"\x0a\x0dg", L"%0A%0Dg", SPACE_TO_PLUS, KEEP_UNMODIFIED)); } namespace { - bool testUnescapingHelper(const wchar_t * input, const wchar_t * output, - bool plusToSpace = false, UriBreakConversion breakConversion = URI_BR_DONT_TOUCH) { - wchar_t * working = new wchar_t[URI_STRLEN(input) + 1]; - wcscpy(working, input); - const wchar_t * newTermZero = uriUnescapeInPlaceExW(working, - plusToSpace ? URI_TRUE : URI_FALSE, breakConversion); - const bool success = ((newTermZero == working + wcslen(output)) - && !wcscmp(working, output)); - delete[] working; - return success; - } +bool testUnescapingHelper(const wchar_t * input, const wchar_t * output, + bool plusToSpace = false, + UriBreakConversion breakConversion = URI_BR_DONT_TOUCH) { + wchar_t * working = new wchar_t[URI_STRLEN(input) + 1]; + wcscpy(working, input); + const wchar_t * newTermZero = uriUnescapeInPlaceExW( + working, plusToSpace ? URI_TRUE : URI_FALSE, breakConversion); + const bool success = + ((newTermZero == working + wcslen(output)) && !wcscmp(working, output)); + delete[] working; + return success; +} } // namespace TEST(UriSuite, TestUnescaping) { - const bool PLUS_TO_SPACE = true; - const bool PLUS_DONT_TOUCH = false; - - - // Proper - ASSERT_TRUE(testUnescapingHelper(L"abc%20%41BC", L"abc ABC")); - ASSERT_TRUE(testUnescapingHelper(L"%20", L" ")); - - // Incomplete - ASSERT_TRUE(testUnescapingHelper(L"%0", L"%0")); - - // Nonhex - ASSERT_TRUE(testUnescapingHelper(L"%0g", L"%0g")); - ASSERT_TRUE(testUnescapingHelper(L"%G0", L"%G0")); - - // No double decoding - ASSERT_TRUE(testUnescapingHelper(L"%2520", L"%20")); - - // Decoding of '+' - ASSERT_TRUE(testUnescapingHelper(L"abc+def", L"abc+def", PLUS_DONT_TOUCH)); - ASSERT_TRUE(testUnescapingHelper(L"abc+def", L"abc def", PLUS_TO_SPACE)); - - // Line break conversion - ASSERT_TRUE(testUnescapingHelper(L"%0d", L"\x0a", PLUS_DONT_TOUCH, URI_BR_TO_UNIX)); - ASSERT_TRUE(testUnescapingHelper(L"%0d", L"\x0d\x0a", PLUS_DONT_TOUCH, URI_BR_TO_WINDOWS)); - ASSERT_TRUE(testUnescapingHelper(L"%0d", L"\x0d", PLUS_DONT_TOUCH, URI_BR_TO_MAC)); - ASSERT_TRUE(testUnescapingHelper(L"%0d", L"\x0d", PLUS_DONT_TOUCH, URI_BR_DONT_TOUCH)); - - ASSERT_TRUE(testUnescapingHelper(L"%0d%0d", L"\x0a\x0a", PLUS_DONT_TOUCH, URI_BR_TO_UNIX)); - ASSERT_TRUE(testUnescapingHelper(L"%0d%0d", L"\x0d\x0a\x0d\x0a", PLUS_DONT_TOUCH, URI_BR_TO_WINDOWS)); - ASSERT_TRUE(testUnescapingHelper(L"%0d%0d", L"\x0d\x0d", PLUS_DONT_TOUCH, URI_BR_TO_MAC)); - ASSERT_TRUE(testUnescapingHelper(L"%0d%0d", L"\x0d\x0d", PLUS_DONT_TOUCH, URI_BR_DONT_TOUCH)); - - - ASSERT_TRUE(testUnescapingHelper(L"%0a", L"\x0a", PLUS_DONT_TOUCH, URI_BR_TO_UNIX)); - ASSERT_TRUE(testUnescapingHelper(L"%0a", L"\x0d\x0a", PLUS_DONT_TOUCH, URI_BR_TO_WINDOWS)); - ASSERT_TRUE(testUnescapingHelper(L"%0a", L"\x0d", PLUS_DONT_TOUCH, URI_BR_TO_MAC)); - ASSERT_TRUE(testUnescapingHelper(L"%0a", L"\x0a", PLUS_DONT_TOUCH, URI_BR_DONT_TOUCH)); - - ASSERT_TRUE(testUnescapingHelper(L"%0a%0a", L"\x0a\x0a", PLUS_DONT_TOUCH, URI_BR_TO_UNIX)); - ASSERT_TRUE(testUnescapingHelper(L"%0a%0a", L"\x0d\x0a\x0d\x0a", PLUS_DONT_TOUCH, URI_BR_TO_WINDOWS)); - ASSERT_TRUE(testUnescapingHelper(L"%0a%0a", L"\x0d\x0d", PLUS_DONT_TOUCH, URI_BR_TO_MAC)); - ASSERT_TRUE(testUnescapingHelper(L"%0a%0a", L"\x0a\x0a", PLUS_DONT_TOUCH, URI_BR_DONT_TOUCH)); - - - ASSERT_TRUE(testUnescapingHelper(L"%0d%0a", L"\x0a", PLUS_DONT_TOUCH, URI_BR_TO_UNIX)); - ASSERT_TRUE(testUnescapingHelper(L"%0d%0a", L"\x0d\x0a", PLUS_DONT_TOUCH, URI_BR_TO_WINDOWS)); - ASSERT_TRUE(testUnescapingHelper(L"%0d%0a", L"\x0d", PLUS_DONT_TOUCH, URI_BR_TO_MAC)); - ASSERT_TRUE(testUnescapingHelper(L"%0d%0a", L"\x0d\x0a", PLUS_DONT_TOUCH, URI_BR_DONT_TOUCH)); - - ASSERT_TRUE(testUnescapingHelper(L"%0d%0a%0a", L"\x0a\x0a", PLUS_DONT_TOUCH, URI_BR_TO_UNIX)); - ASSERT_TRUE(testUnescapingHelper(L"%0d%0a%0a", L"\x0d\x0a\x0d\x0a", PLUS_DONT_TOUCH, URI_BR_TO_WINDOWS)); - ASSERT_TRUE(testUnescapingHelper(L"%0d%0a%0a", L"\x0d\x0d", PLUS_DONT_TOUCH, URI_BR_TO_MAC)); - ASSERT_TRUE(testUnescapingHelper(L"%0d%0a%0a", L"\x0d\x0a\x0a", PLUS_DONT_TOUCH, URI_BR_DONT_TOUCH)); - - ASSERT_TRUE(testUnescapingHelper(L"%0d%0a%0d", L"\x0a\x0a", PLUS_DONT_TOUCH, URI_BR_TO_UNIX)); - ASSERT_TRUE(testUnescapingHelper(L"%0d%0a%0d", L"\x0d\x0a\x0d\x0a", PLUS_DONT_TOUCH, URI_BR_TO_WINDOWS)); - ASSERT_TRUE(testUnescapingHelper(L"%0d%0a%0d", L"\x0d\x0d", PLUS_DONT_TOUCH, URI_BR_TO_MAC)); - ASSERT_TRUE(testUnescapingHelper(L"%0d%0a%0d", L"\x0d\x0a\x0d", PLUS_DONT_TOUCH, URI_BR_DONT_TOUCH)); - - ASSERT_TRUE(testUnescapingHelper(L"%0d%0a%0d%0a", L"\x0a\x0a", PLUS_DONT_TOUCH, URI_BR_TO_UNIX)); - ASSERT_TRUE(testUnescapingHelper(L"%0d%0a%0d%0a", L"\x0d\x0a\x0d\x0a", PLUS_DONT_TOUCH, URI_BR_TO_WINDOWS)); - ASSERT_TRUE(testUnescapingHelper(L"%0d%0a%0d%0a", L"\x0d\x0d", PLUS_DONT_TOUCH, URI_BR_TO_MAC)); - ASSERT_TRUE(testUnescapingHelper(L"%0d%0a%0d%0a", L"\x0d\x0a\x0d\x0a", PLUS_DONT_TOUCH, URI_BR_DONT_TOUCH)); - - - ASSERT_TRUE(testUnescapingHelper(L"%0a%0d", L"\x0a\x0a", PLUS_DONT_TOUCH, URI_BR_TO_UNIX)); - ASSERT_TRUE(testUnescapingHelper(L"%0a%0d", L"\x0d\x0a\x0d\x0a", PLUS_DONT_TOUCH, URI_BR_TO_WINDOWS)); - ASSERT_TRUE(testUnescapingHelper(L"%0a%0d", L"\x0d\x0d", PLUS_DONT_TOUCH, URI_BR_TO_MAC)); - ASSERT_TRUE(testUnescapingHelper(L"%0a%0d", L"\x0a\x0d", PLUS_DONT_TOUCH, URI_BR_DONT_TOUCH)); - - ASSERT_TRUE(testUnescapingHelper(L"%0a%0d%0a", L"\x0a\x0a", PLUS_DONT_TOUCH, URI_BR_TO_UNIX)); - ASSERT_TRUE(testUnescapingHelper(L"%0a%0d%0a", L"\x0d\x0a\x0d\x0a", PLUS_DONT_TOUCH, URI_BR_TO_WINDOWS)); - ASSERT_TRUE(testUnescapingHelper(L"%0a%0d%0a", L"\x0d\x0d", PLUS_DONT_TOUCH, URI_BR_TO_MAC)); - ASSERT_TRUE(testUnescapingHelper(L"%0a%0d%0a", L"\x0a\x0d\x0a", PLUS_DONT_TOUCH, URI_BR_DONT_TOUCH)); - - ASSERT_TRUE(testUnescapingHelper(L"%0a%0d%0d", L"\x0a\x0a\x0a", PLUS_DONT_TOUCH, URI_BR_TO_UNIX)); - ASSERT_TRUE(testUnescapingHelper(L"%0a%0d%0d", L"\x0d\x0a\x0d\x0a\x0d\x0a", PLUS_DONT_TOUCH, URI_BR_TO_WINDOWS)); - ASSERT_TRUE(testUnescapingHelper(L"%0a%0d%0d", L"\x0d\x0d\x0d", PLUS_DONT_TOUCH, URI_BR_TO_MAC)); - ASSERT_TRUE(testUnescapingHelper(L"%0a%0d%0d", L"\x0a\x0d\x0d", PLUS_DONT_TOUCH, URI_BR_DONT_TOUCH)); - - ASSERT_TRUE(testUnescapingHelper(L"%0a%0d%0a%0d", L"\x0a\x0a\x0a", PLUS_DONT_TOUCH, URI_BR_TO_UNIX)); - ASSERT_TRUE(testUnescapingHelper(L"%0a%0d%0a%0d", L"\x0d\x0a\x0d\x0a\x0d\x0a", PLUS_DONT_TOUCH, URI_BR_TO_WINDOWS)); - ASSERT_TRUE(testUnescapingHelper(L"%0a%0d%0a%0d", L"\x0d\x0d\x0d", PLUS_DONT_TOUCH, URI_BR_TO_MAC)); - ASSERT_TRUE(testUnescapingHelper(L"%0a%0d%0a%0d", L"\x0a\x0d\x0a\x0d", PLUS_DONT_TOUCH, URI_BR_DONT_TOUCH)); + const bool PLUS_TO_SPACE = true; + const bool PLUS_DONT_TOUCH = false; + + // Proper + ASSERT_TRUE(testUnescapingHelper(L"abc%20%41BC", L"abc ABC")); + ASSERT_TRUE(testUnescapingHelper(L"%20", L" ")); + + // Incomplete + ASSERT_TRUE(testUnescapingHelper(L"%0", L"%0")); + + // Nonhex + ASSERT_TRUE(testUnescapingHelper(L"%0g", L"%0g")); + ASSERT_TRUE(testUnescapingHelper(L"%G0", L"%G0")); + + // No double decoding + ASSERT_TRUE(testUnescapingHelper(L"%2520", L"%20")); + + // Decoding of '+' + ASSERT_TRUE(testUnescapingHelper(L"abc+def", L"abc+def", PLUS_DONT_TOUCH)); + ASSERT_TRUE(testUnescapingHelper(L"abc+def", L"abc def", PLUS_TO_SPACE)); + + // Line break conversion + ASSERT_TRUE(testUnescapingHelper(L"%0d", L"\x0a", PLUS_DONT_TOUCH, URI_BR_TO_UNIX)); + ASSERT_TRUE( + testUnescapingHelper(L"%0d", L"\x0d\x0a", PLUS_DONT_TOUCH, URI_BR_TO_WINDOWS)); + ASSERT_TRUE(testUnescapingHelper(L"%0d", L"\x0d", PLUS_DONT_TOUCH, URI_BR_TO_MAC)); + ASSERT_TRUE( + testUnescapingHelper(L"%0d", L"\x0d", PLUS_DONT_TOUCH, URI_BR_DONT_TOUCH)); + + ASSERT_TRUE( + testUnescapingHelper(L"%0d%0d", L"\x0a\x0a", PLUS_DONT_TOUCH, URI_BR_TO_UNIX)); + ASSERT_TRUE(testUnescapingHelper(L"%0d%0d", L"\x0d\x0a\x0d\x0a", PLUS_DONT_TOUCH, + URI_BR_TO_WINDOWS)); + ASSERT_TRUE( + testUnescapingHelper(L"%0d%0d", L"\x0d\x0d", PLUS_DONT_TOUCH, URI_BR_TO_MAC)); + ASSERT_TRUE( + testUnescapingHelper(L"%0d%0d", L"\x0d\x0d", PLUS_DONT_TOUCH, URI_BR_DONT_TOUCH)); + + ASSERT_TRUE(testUnescapingHelper(L"%0a", L"\x0a", PLUS_DONT_TOUCH, URI_BR_TO_UNIX)); + ASSERT_TRUE( + testUnescapingHelper(L"%0a", L"\x0d\x0a", PLUS_DONT_TOUCH, URI_BR_TO_WINDOWS)); + ASSERT_TRUE(testUnescapingHelper(L"%0a", L"\x0d", PLUS_DONT_TOUCH, URI_BR_TO_MAC)); + ASSERT_TRUE( + testUnescapingHelper(L"%0a", L"\x0a", PLUS_DONT_TOUCH, URI_BR_DONT_TOUCH)); + + ASSERT_TRUE( + testUnescapingHelper(L"%0a%0a", L"\x0a\x0a", PLUS_DONT_TOUCH, URI_BR_TO_UNIX)); + ASSERT_TRUE(testUnescapingHelper(L"%0a%0a", L"\x0d\x0a\x0d\x0a", PLUS_DONT_TOUCH, + URI_BR_TO_WINDOWS)); + ASSERT_TRUE( + testUnescapingHelper(L"%0a%0a", L"\x0d\x0d", PLUS_DONT_TOUCH, URI_BR_TO_MAC)); + ASSERT_TRUE( + testUnescapingHelper(L"%0a%0a", L"\x0a\x0a", PLUS_DONT_TOUCH, URI_BR_DONT_TOUCH)); + + ASSERT_TRUE( + testUnescapingHelper(L"%0d%0a", L"\x0a", PLUS_DONT_TOUCH, URI_BR_TO_UNIX)); + ASSERT_TRUE( + testUnescapingHelper(L"%0d%0a", L"\x0d\x0a", PLUS_DONT_TOUCH, URI_BR_TO_WINDOWS)); + ASSERT_TRUE(testUnescapingHelper(L"%0d%0a", L"\x0d", PLUS_DONT_TOUCH, URI_BR_TO_MAC)); + ASSERT_TRUE( + testUnescapingHelper(L"%0d%0a", L"\x0d\x0a", PLUS_DONT_TOUCH, URI_BR_DONT_TOUCH)); + + ASSERT_TRUE( + testUnescapingHelper(L"%0d%0a%0a", L"\x0a\x0a", PLUS_DONT_TOUCH, URI_BR_TO_UNIX)); + ASSERT_TRUE(testUnescapingHelper(L"%0d%0a%0a", L"\x0d\x0a\x0d\x0a", PLUS_DONT_TOUCH, + URI_BR_TO_WINDOWS)); + ASSERT_TRUE( + testUnescapingHelper(L"%0d%0a%0a", L"\x0d\x0d", PLUS_DONT_TOUCH, URI_BR_TO_MAC)); + ASSERT_TRUE(testUnescapingHelper(L"%0d%0a%0a", L"\x0d\x0a\x0a", PLUS_DONT_TOUCH, + URI_BR_DONT_TOUCH)); + + ASSERT_TRUE( + testUnescapingHelper(L"%0d%0a%0d", L"\x0a\x0a", PLUS_DONT_TOUCH, URI_BR_TO_UNIX)); + ASSERT_TRUE(testUnescapingHelper(L"%0d%0a%0d", L"\x0d\x0a\x0d\x0a", PLUS_DONT_TOUCH, + URI_BR_TO_WINDOWS)); + ASSERT_TRUE( + testUnescapingHelper(L"%0d%0a%0d", L"\x0d\x0d", PLUS_DONT_TOUCH, URI_BR_TO_MAC)); + ASSERT_TRUE(testUnescapingHelper(L"%0d%0a%0d", L"\x0d\x0a\x0d", PLUS_DONT_TOUCH, + URI_BR_DONT_TOUCH)); + + ASSERT_TRUE(testUnescapingHelper(L"%0d%0a%0d%0a", L"\x0a\x0a", PLUS_DONT_TOUCH, + URI_BR_TO_UNIX)); + ASSERT_TRUE(testUnescapingHelper(L"%0d%0a%0d%0a", L"\x0d\x0a\x0d\x0a", + PLUS_DONT_TOUCH, URI_BR_TO_WINDOWS)); + ASSERT_TRUE(testUnescapingHelper(L"%0d%0a%0d%0a", L"\x0d\x0d", PLUS_DONT_TOUCH, + URI_BR_TO_MAC)); + ASSERT_TRUE(testUnescapingHelper(L"%0d%0a%0d%0a", L"\x0d\x0a\x0d\x0a", + PLUS_DONT_TOUCH, URI_BR_DONT_TOUCH)); + + ASSERT_TRUE( + testUnescapingHelper(L"%0a%0d", L"\x0a\x0a", PLUS_DONT_TOUCH, URI_BR_TO_UNIX)); + ASSERT_TRUE(testUnescapingHelper(L"%0a%0d", L"\x0d\x0a\x0d\x0a", PLUS_DONT_TOUCH, + URI_BR_TO_WINDOWS)); + ASSERT_TRUE( + testUnescapingHelper(L"%0a%0d", L"\x0d\x0d", PLUS_DONT_TOUCH, URI_BR_TO_MAC)); + ASSERT_TRUE( + testUnescapingHelper(L"%0a%0d", L"\x0a\x0d", PLUS_DONT_TOUCH, URI_BR_DONT_TOUCH)); + + ASSERT_TRUE( + testUnescapingHelper(L"%0a%0d%0a", L"\x0a\x0a", PLUS_DONT_TOUCH, URI_BR_TO_UNIX)); + ASSERT_TRUE(testUnescapingHelper(L"%0a%0d%0a", L"\x0d\x0a\x0d\x0a", PLUS_DONT_TOUCH, + URI_BR_TO_WINDOWS)); + ASSERT_TRUE( + testUnescapingHelper(L"%0a%0d%0a", L"\x0d\x0d", PLUS_DONT_TOUCH, URI_BR_TO_MAC)); + ASSERT_TRUE(testUnescapingHelper(L"%0a%0d%0a", L"\x0a\x0d\x0a", PLUS_DONT_TOUCH, + URI_BR_DONT_TOUCH)); + + ASSERT_TRUE(testUnescapingHelper(L"%0a%0d%0d", L"\x0a\x0a\x0a", PLUS_DONT_TOUCH, + URI_BR_TO_UNIX)); + ASSERT_TRUE(testUnescapingHelper(L"%0a%0d%0d", L"\x0d\x0a\x0d\x0a\x0d\x0a", + PLUS_DONT_TOUCH, URI_BR_TO_WINDOWS)); + ASSERT_TRUE(testUnescapingHelper(L"%0a%0d%0d", L"\x0d\x0d\x0d", PLUS_DONT_TOUCH, + URI_BR_TO_MAC)); + ASSERT_TRUE(testUnescapingHelper(L"%0a%0d%0d", L"\x0a\x0d\x0d", PLUS_DONT_TOUCH, + URI_BR_DONT_TOUCH)); + + ASSERT_TRUE(testUnescapingHelper(L"%0a%0d%0a%0d", L"\x0a\x0a\x0a", PLUS_DONT_TOUCH, + URI_BR_TO_UNIX)); + ASSERT_TRUE(testUnescapingHelper(L"%0a%0d%0a%0d", L"\x0d\x0a\x0d\x0a\x0d\x0a", + PLUS_DONT_TOUCH, URI_BR_TO_WINDOWS)); + ASSERT_TRUE(testUnescapingHelper(L"%0a%0d%0a%0d", L"\x0d\x0d\x0d", PLUS_DONT_TOUCH, + URI_BR_TO_MAC)); + ASSERT_TRUE(testUnescapingHelper(L"%0a%0d%0a%0d", L"\x0a\x0d\x0a\x0d", + PLUS_DONT_TOUCH, URI_BR_DONT_TOUCH)); } namespace { - bool testAddBaseHelper(const wchar_t * base, const wchar_t * rel, const wchar_t * expectedResult, bool backward_compatibility = false) { - UriParserStateW stateW; - - // Base - UriUriW baseUri; - stateW.uri = &baseUri; - int res = uriParseUriW(&stateW, base); - if (res != 0) { - uriFreeUriMembersW(&baseUri); - return false; - } - - // Rel - UriUriW relUri; - stateW.uri = &relUri; - res = uriParseUriW(&stateW, rel); - if (res != 0) { - uriFreeUriMembersW(&baseUri); - uriFreeUriMembersW(&relUri); - return false; - } - - // Expected result - UriUriW expectedUri; - stateW.uri = &expectedUri; - res = uriParseUriW(&stateW, expectedResult); - if (res != 0) { - uriFreeUriMembersW(&baseUri); - uriFreeUriMembersW(&relUri); - uriFreeUriMembersW(&expectedUri); - return false; - } - - // Transform - UriUriW transformedUri; - if (backward_compatibility) { - res = uriAddBaseUriExW(&transformedUri, &relUri, &baseUri, URI_RESOLVE_IDENTICAL_SCHEME_COMPAT); - } else { - res = uriAddBaseUriW(&transformedUri, &relUri, &baseUri); - } - - if (res != 0) { - uriFreeUriMembersW(&baseUri); - uriFreeUriMembersW(&relUri); - uriFreeUriMembersW(&expectedUri); - uriFreeUriMembersW(&transformedUri); - return false; - } - - const bool equal = (URI_TRUE == uriEqualsUriW(&transformedUri, &expectedUri)); - if (!equal) { - wchar_t transformedUriText[1024 * 8]; - wchar_t expectedUriText[1024 * 8]; - uriToStringW(transformedUriText, &transformedUri, 1024 * 8, NULL); - uriToStringW(expectedUriText, &expectedUri, 1024 * 8, NULL); +bool testAddBaseHelper(const wchar_t * base, const wchar_t * rel, + const wchar_t * expectedResult, + bool backward_compatibility = false) { + UriParserStateW stateW; + + // Base + UriUriW baseUri; + stateW.uri = &baseUri; + int res = uriParseUriW(&stateW, base); + if (res != 0) { + uriFreeUriMembersW(&baseUri); + return false; + } + + // Rel + UriUriW relUri; + stateW.uri = &relUri; + res = uriParseUriW(&stateW, rel); + if (res != 0) { + uriFreeUriMembersW(&baseUri); + uriFreeUriMembersW(&relUri); + return false; + } + + // Expected result + UriUriW expectedUri; + stateW.uri = &expectedUri; + res = uriParseUriW(&stateW, expectedResult); + if (res != 0) { + uriFreeUriMembersW(&baseUri); + uriFreeUriMembersW(&relUri); + uriFreeUriMembersW(&expectedUri); + return false; + } + + // Transform + UriUriW transformedUri; + if (backward_compatibility) { + res = uriAddBaseUriExW(&transformedUri, &relUri, &baseUri, + URI_RESOLVE_IDENTICAL_SCHEME_COMPAT); + } else { + res = uriAddBaseUriW(&transformedUri, &relUri, &baseUri); + } + + if (res != 0) { + uriFreeUriMembersW(&baseUri); + uriFreeUriMembersW(&relUri); + uriFreeUriMembersW(&expectedUri); + uriFreeUriMembersW(&transformedUri); + return false; + } + + const bool equal = (URI_TRUE == uriEqualsUriW(&transformedUri, &expectedUri)); + if (!equal) { + wchar_t transformedUriText[1024 * 8]; + wchar_t expectedUriText[1024 * 8]; + uriToStringW(transformedUriText, &transformedUri, 1024 * 8, NULL); + uriToStringW(expectedUriText, &expectedUri, 1024 * 8, NULL); #ifdef HAVE_WPRINTF - wprintf(L"\n\n\nExpected: \"%s\"\nReceived: \"%s\"\n\n\n", expectedUriText, transformedUriText); + wprintf(L"\n\n\nExpected: \"%s\"\nReceived: \"%s\"\n\n\n", expectedUriText, + transformedUriText); #endif - } - - uriFreeUriMembersW(&baseUri); - uriFreeUriMembersW(&relUri); - uriFreeUriMembersW(&expectedUri); - uriFreeUriMembersW(&transformedUri); - return equal; - } + } + + uriFreeUriMembersW(&baseUri); + uriFreeUriMembersW(&relUri); + uriFreeUriMembersW(&expectedUri); + uriFreeUriMembersW(&transformedUri); + return equal; +} } // namespace TEST(UriSuite, TestTrailingSlash) { - UriParserStateA stateA; - UriUriA uriA; - stateA.uri = &uriA; - // 0 3 01 - const char * const input = "abc" "/"; - ASSERT_TRUE(0 == uriParseUriA(&stateA, input)); - - ASSERT_TRUE(uriA.pathHead->text.first == input); - ASSERT_TRUE(uriA.pathHead->text.afterLast == input + 3); - ASSERT_TRUE(uriA.pathHead->next->text.first == uriA.pathHead->next->text.afterLast); - ASSERT_TRUE(uriA.pathHead->next->next == NULL); - ASSERT_TRUE(uriA.pathTail == uriA.pathHead->next); - uriFreeUriMembersA(&uriA); + UriParserStateA stateA; + UriUriA uriA; + stateA.uri = &uriA; + // clang-format off + // 0 3 01 + const char * const input = "abc" "/"; + // clang-format on + ASSERT_EQ(0, uriParseUriA(&stateA, input)); + + ASSERT_EQ(uriA.pathHead->text.first, input); + ASSERT_EQ(uriA.pathHead->text.afterLast, input + 3); + ASSERT_EQ(uriA.pathHead->next->text.first, uriA.pathHead->next->text.afterLast); + ASSERT_TRUE(uriA.pathHead->next->next == NULL); + ASSERT_EQ(uriA.pathTail, uriA.pathHead->next); + uriFreeUriMembersA(&uriA); } TEST(UriSuite, TestAddBase) { - // 5.4.1. Normal Examples - ASSERT_TRUE(testAddBaseHelper(L"http://a/b/c/d;p?q", L"g:h", L"g:h")); - ASSERT_TRUE(testAddBaseHelper(L"http://a/b/c/d;p?q", L"g", L"http://a/b/c/g")); - ASSERT_TRUE(testAddBaseHelper(L"http://a/b/c/d;p?q", L"./g", L"http://a/b/c/g")); - ASSERT_TRUE(testAddBaseHelper(L"http://a/b/c/d;p?q", L"g/", L"http://a/b/c/g/")); - ASSERT_TRUE(testAddBaseHelper(L"http://a/b/c/d;p?q", L"/g", L"http://a/g")); - ASSERT_TRUE(testAddBaseHelper(L"http://a/b/c/d;p?q", L"//g", L"http://g")); - ASSERT_TRUE(testAddBaseHelper(L"http://a/b/c/d;p?q", L"?y", L"http://a/b/c/d;p?y")); - ASSERT_TRUE(testAddBaseHelper(L"http://a/b/c/d;p?q", L"g?y", L"http://a/b/c/g?y")); - ASSERT_TRUE(testAddBaseHelper(L"http://a/b/c/d;p?q", L"#s", L"http://a/b/c/d;p?q#s")); - ASSERT_TRUE(testAddBaseHelper(L"http://a/b/c/d;p?q", L"g#s", L"http://a/b/c/g#s")); - ASSERT_TRUE(testAddBaseHelper(L"http://a/b/c/d;p?q", L"g?y#s", L"http://a/b/c/g?y#s")); - ASSERT_TRUE(testAddBaseHelper(L"http://a/b/c/d;p?q", L";x", L"http://a/b/c/;x")); - ASSERT_TRUE(testAddBaseHelper(L"http://a/b/c/d;p?q", L"g;x", L"http://a/b/c/g;x")); - ASSERT_TRUE(testAddBaseHelper(L"http://a/b/c/d;p?q", L"g;x?y#s", L"http://a/b/c/g;x?y#s")); - ASSERT_TRUE(testAddBaseHelper(L"http://a/b/c/d;p?q", L"", L"http://a/b/c/d;p?q")); - ASSERT_TRUE(testAddBaseHelper(L"http://a/b/c/d;p?q", L".", L"http://a/b/c/")); - ASSERT_TRUE(testAddBaseHelper(L"http://a/b/c/d;p?q", L"./", L"http://a/b/c/")); - ASSERT_TRUE(testAddBaseHelper(L"http://a/b/c/d;p?q", L"..", L"http://a/b/")); - ASSERT_TRUE(testAddBaseHelper(L"http://a/b/c/d;p?q", L"../", L"http://a/b/")); - ASSERT_TRUE(testAddBaseHelper(L"http://a/b/c/d;p?q", L"../g", L"http://a/b/g")); - ASSERT_TRUE(testAddBaseHelper(L"http://a/b/c/d;p?q", L"../..", L"http://a/")); - ASSERT_TRUE(testAddBaseHelper(L"http://a/b/c/d;p?q", L"../../", L"http://a/")); - ASSERT_TRUE(testAddBaseHelper(L"http://a/b/c/d;p?q", L"../../g", L"http://a/g")); - - // 5.4.2. Abnormal Examples - ASSERT_TRUE(testAddBaseHelper(L"http://a/b/c/d;p?q", L"../../../g", L"http://a/g")); - ASSERT_TRUE(testAddBaseHelper(L"http://a/b/c/d;p?q", L"../../../../g", L"http://a/g")); - ASSERT_TRUE(testAddBaseHelper(L"http://a/b/c/d;p?q", L"/./g", L"http://a/g")); - ASSERT_TRUE(testAddBaseHelper(L"http://a/b/c/d;p?q", L"/../g", L"http://a/g")); - ASSERT_TRUE(testAddBaseHelper(L"http://a/b/c/d;p?q", L"g.", L"http://a/b/c/g.")); - ASSERT_TRUE(testAddBaseHelper(L"http://a/b/c/d;p?q", L".g", L"http://a/b/c/.g")); - ASSERT_TRUE(testAddBaseHelper(L"http://a/b/c/d;p?q", L"g..", L"http://a/b/c/g..")); - ASSERT_TRUE(testAddBaseHelper(L"http://a/b/c/d;p?q", L"..g", L"http://a/b/c/..g")); - ASSERT_TRUE(testAddBaseHelper(L"http://a/b/c/d;p?q", L"./../g", L"http://a/b/g")); - ASSERT_TRUE(testAddBaseHelper(L"http://a/b/c/d;p?q", L"./g/.", L"http://a/b/c/g/")); - ASSERT_TRUE(testAddBaseHelper(L"http://a/b/c/d;p?q", L"g/./h", L"http://a/b/c/g/h")); - ASSERT_TRUE(testAddBaseHelper(L"http://a/b/c/d;p?q", L"g/../h", L"http://a/b/c/h")); - ASSERT_TRUE(testAddBaseHelper(L"http://a/b/c/d;p?q", L"g;x=1/./y", L"http://a/b/c/g;x=1/y")); - ASSERT_TRUE(testAddBaseHelper(L"http://a/b/c/d;p?q", L"g;x=1/../y", L"http://a/b/c/y")); - ASSERT_TRUE(testAddBaseHelper(L"http://a/b/c/d;p?q", L"g?y/./x", L"http://a/b/c/g?y/./x")); - ASSERT_TRUE(testAddBaseHelper(L"http://a/b/c/d;p?q", L"g?y/../x", L"http://a/b/c/g?y/../x")); - ASSERT_TRUE(testAddBaseHelper(L"http://a/b/c/d;p?q", L"g#s/./x", L"http://a/b/c/g#s/./x")); - ASSERT_TRUE(testAddBaseHelper(L"http://a/b/c/d;p?q", L"g#s/../x", L"http://a/b/c/g#s/../x")); - ASSERT_TRUE(testAddBaseHelper(L"http://a/b/c/d;p?q", L"http:g", L"http:g")); - - // Backward compatibility (feature request #4, RFC3986 5.4.2) - ASSERT_TRUE(testAddBaseHelper(L"http://a/b/c/d;p?q", L"http:g", L"http:g", false)); - ASSERT_TRUE(testAddBaseHelper(L"http://a/b/c/d;p?q", L"http:g", L"http://a/b/c/g", true)); - ASSERT_TRUE(testAddBaseHelper(L"http://a/b/c/d;p?q", L"http:g?q#f", L"http://a/b/c/g?q#f", true)); - ASSERT_TRUE(testAddBaseHelper(L"http://a/b/c/d;p?q", L"other:g?q#f", L"other:g?q#f", true)); - - // Bug related to absolutePath flag set despite presence of host - ASSERT_TRUE(testAddBaseHelper(L"http://a/b/c/d;p?q", L"/", L"http://a/")); - ASSERT_TRUE(testAddBaseHelper(L"http://a/b/c/d;p?q", L"/g/", L"http://a/g/")); - - // GitHub issue #92 - EXPECT_TRUE(testAddBaseHelper(L"http://a/b/c/../d;p?q", L"../..", L"http://a/")); - EXPECT_TRUE(testAddBaseHelper(L"http://a/b/c/../d;p?q", L"../../", L"http://a/")); - - EXPECT_TRUE(testAddBaseHelper(L"http://a/b/../c/d;p?q", L"../..", L"http://a/")); - EXPECT_TRUE(testAddBaseHelper(L"http://a/b/../c/d;p?q", L"../../", L"http://a/")); - - EXPECT_TRUE(testAddBaseHelper(L"http://a/../b/c/d;p?q", L"../..", L"http://a/")); - EXPECT_TRUE(testAddBaseHelper(L"http://a/../b/c/d;p?q", L"../../", L"http://a/")); - - EXPECT_TRUE(testAddBaseHelper(L"http://a/b/c/d;p?q", L"../../..", L"http://a/")); - EXPECT_TRUE(testAddBaseHelper(L"http://a/b/c/d;p?q", L"../../../", L"http://a/")); + // 5.4.1. Normal Examples + ASSERT_TRUE(testAddBaseHelper(L"http://a/b/c/d;p?q", L"g:h", L"g:h")); + ASSERT_TRUE(testAddBaseHelper(L"http://a/b/c/d;p?q", L"g", L"http://a/b/c/g")); + ASSERT_TRUE(testAddBaseHelper(L"http://a/b/c/d;p?q", L"./g", L"http://a/b/c/g")); + ASSERT_TRUE(testAddBaseHelper(L"http://a/b/c/d;p?q", L"g/", L"http://a/b/c/g/")); + ASSERT_TRUE(testAddBaseHelper(L"http://a/b/c/d;p?q", L"/g", L"http://a/g")); + ASSERT_TRUE(testAddBaseHelper(L"http://a/b/c/d;p?q", L"//g", L"http://g")); + ASSERT_TRUE(testAddBaseHelper(L"http://a/b/c/d;p?q", L"?y", L"http://a/b/c/d;p?y")); + ASSERT_TRUE(testAddBaseHelper(L"http://a/b/c/d;p?q", L"g?y", L"http://a/b/c/g?y")); + ASSERT_TRUE(testAddBaseHelper(L"http://a/b/c/d;p?q", L"#s", L"http://a/b/c/d;p?q#s")); + ASSERT_TRUE(testAddBaseHelper(L"http://a/b/c/d;p?q", L"g#s", L"http://a/b/c/g#s")); + ASSERT_TRUE( + testAddBaseHelper(L"http://a/b/c/d;p?q", L"g?y#s", L"http://a/b/c/g?y#s")); + ASSERT_TRUE(testAddBaseHelper(L"http://a/b/c/d;p?q", L";x", L"http://a/b/c/;x")); + ASSERT_TRUE(testAddBaseHelper(L"http://a/b/c/d;p?q", L"g;x", L"http://a/b/c/g;x")); + ASSERT_TRUE( + testAddBaseHelper(L"http://a/b/c/d;p?q", L"g;x?y#s", L"http://a/b/c/g;x?y#s")); + ASSERT_TRUE(testAddBaseHelper(L"http://a/b/c/d;p?q", L"", L"http://a/b/c/d;p?q")); + ASSERT_TRUE(testAddBaseHelper(L"http://a/b/c/d;p?q", L".", L"http://a/b/c/")); + ASSERT_TRUE(testAddBaseHelper(L"http://a/b/c/d;p?q", L"./", L"http://a/b/c/")); + ASSERT_TRUE(testAddBaseHelper(L"http://a/b/c/d;p?q", L"..", L"http://a/b/")); + ASSERT_TRUE(testAddBaseHelper(L"http://a/b/c/d;p?q", L"../", L"http://a/b/")); + ASSERT_TRUE(testAddBaseHelper(L"http://a/b/c/d;p?q", L"../g", L"http://a/b/g")); + ASSERT_TRUE(testAddBaseHelper(L"http://a/b/c/d;p?q", L"../..", L"http://a/")); + ASSERT_TRUE(testAddBaseHelper(L"http://a/b/c/d;p?q", L"../../", L"http://a/")); + ASSERT_TRUE(testAddBaseHelper(L"http://a/b/c/d;p?q", L"../../g", L"http://a/g")); + + // 5.4.2. Abnormal Examples + ASSERT_TRUE(testAddBaseHelper(L"http://a/b/c/d;p?q", L"../../../g", L"http://a/g")); + ASSERT_TRUE( + testAddBaseHelper(L"http://a/b/c/d;p?q", L"../../../../g", L"http://a/g")); + ASSERT_TRUE(testAddBaseHelper(L"http://a/b/c/d;p?q", L"/./g", L"http://a/g")); + ASSERT_TRUE(testAddBaseHelper(L"http://a/b/c/d;p?q", L"/../g", L"http://a/g")); + ASSERT_TRUE(testAddBaseHelper(L"http://a/b/c/d;p?q", L"g.", L"http://a/b/c/g.")); + ASSERT_TRUE(testAddBaseHelper(L"http://a/b/c/d;p?q", L".g", L"http://a/b/c/.g")); + ASSERT_TRUE(testAddBaseHelper(L"http://a/b/c/d;p?q", L"g..", L"http://a/b/c/g..")); + ASSERT_TRUE(testAddBaseHelper(L"http://a/b/c/d;p?q", L"..g", L"http://a/b/c/..g")); + ASSERT_TRUE(testAddBaseHelper(L"http://a/b/c/d;p?q", L"./../g", L"http://a/b/g")); + ASSERT_TRUE(testAddBaseHelper(L"http://a/b/c/d;p?q", L"./g/.", L"http://a/b/c/g/")); + ASSERT_TRUE(testAddBaseHelper(L"http://a/b/c/d;p?q", L"g/./h", L"http://a/b/c/g/h")); + ASSERT_TRUE(testAddBaseHelper(L"http://a/b/c/d;p?q", L"g/../h", L"http://a/b/c/h")); + ASSERT_TRUE( + testAddBaseHelper(L"http://a/b/c/d;p?q", L"g;x=1/./y", L"http://a/b/c/g;x=1/y")); + ASSERT_TRUE( + testAddBaseHelper(L"http://a/b/c/d;p?q", L"g;x=1/../y", L"http://a/b/c/y")); + ASSERT_TRUE( + testAddBaseHelper(L"http://a/b/c/d;p?q", L"g?y/./x", L"http://a/b/c/g?y/./x")); + ASSERT_TRUE( + testAddBaseHelper(L"http://a/b/c/d;p?q", L"g?y/../x", L"http://a/b/c/g?y/../x")); + ASSERT_TRUE( + testAddBaseHelper(L"http://a/b/c/d;p?q", L"g#s/./x", L"http://a/b/c/g#s/./x")); + ASSERT_TRUE( + testAddBaseHelper(L"http://a/b/c/d;p?q", L"g#s/../x", L"http://a/b/c/g#s/../x")); + ASSERT_TRUE(testAddBaseHelper(L"http://a/b/c/d;p?q", L"http:g", L"http:g")); + + // Backward compatibility (feature request #4, RFC3986 5.4.2) + ASSERT_TRUE(testAddBaseHelper(L"http://a/b/c/d;p?q", L"http:g", L"http:g", false)); + ASSERT_TRUE( + testAddBaseHelper(L"http://a/b/c/d;p?q", L"http:g", L"http://a/b/c/g", true)); + ASSERT_TRUE(testAddBaseHelper(L"http://a/b/c/d;p?q", L"http:g?q#f", + L"http://a/b/c/g?q#f", true)); + ASSERT_TRUE( + testAddBaseHelper(L"http://a/b/c/d;p?q", L"other:g?q#f", L"other:g?q#f", true)); + + // Bug related to absolutePath flag set despite presence of host + ASSERT_TRUE(testAddBaseHelper(L"http://a/b/c/d;p?q", L"/", L"http://a/")); + ASSERT_TRUE(testAddBaseHelper(L"http://a/b/c/d;p?q", L"/g/", L"http://a/g/")); + + // GitHub issue #92 + EXPECT_TRUE(testAddBaseHelper(L"http://a/b/c/../d;p?q", L"../..", L"http://a/")); + EXPECT_TRUE(testAddBaseHelper(L"http://a/b/c/../d;p?q", L"../../", L"http://a/")); + + EXPECT_TRUE(testAddBaseHelper(L"http://a/b/../c/d;p?q", L"../..", L"http://a/")); + EXPECT_TRUE(testAddBaseHelper(L"http://a/b/../c/d;p?q", L"../../", L"http://a/")); + + EXPECT_TRUE(testAddBaseHelper(L"http://a/../b/c/d;p?q", L"../..", L"http://a/")); + EXPECT_TRUE(testAddBaseHelper(L"http://a/../b/c/d;p?q", L"../../", L"http://a/")); + + EXPECT_TRUE(testAddBaseHelper(L"http://a/b/c/d;p?q", L"../../..", L"http://a/")); + EXPECT_TRUE(testAddBaseHelper(L"http://a/b/c/d;p?q", L"../../../", L"http://a/")); } namespace { - bool testToStringHelper(const wchar_t * text) { - // Parse - UriParserStateW state; - UriUriW uri; - state.uri = &uri; - int res = uriParseUriW(&state, text); - if (res != 0) { - uriFreeUriMembersW(&uri); - return false; - } - - // Back to string, _huge_ limit - wchar_t shouldbeTheSame[1024 * 8]; - res = uriToStringW(shouldbeTheSame, &uri, 1024 * 8, NULL); - if (res != 0) { - uriFreeUriMembersW(&uri); - return false; - } - - // Compare - bool equals = (0 == wcscmp(shouldbeTheSame, text)); - if (!equals) { +bool testToStringHelper(const wchar_t * text) { + // Parse + UriParserStateW state; + UriUriW uri; + state.uri = &uri; + int res = uriParseUriW(&state, text); + if (res != 0) { + uriFreeUriMembersW(&uri); + return false; + } + + // Back to string, _huge_ limit + wchar_t shouldbeTheSame[1024 * 8]; + res = uriToStringW(shouldbeTheSame, &uri, 1024 * 8, NULL); + if (res != 0) { + uriFreeUriMembersW(&uri); + return false; + } + + // Compare + bool equals = (0 == wcscmp(shouldbeTheSame, text)); + if (!equals) { #ifdef HAVE_WPRINTF - wprintf(L"\n\n\nExpected: \"%s\"\nReceived: \"%s\"\n\n\n", text, shouldbeTheSame); + wprintf(L"\n\n\nExpected: \"%s\"\nReceived: \"%s\"\n\n\n", text, shouldbeTheSame); #endif - } - - // Back to string, _exact_ limit - const int len = static_cast<int>(wcslen(text)); - int charsWritten; - res = uriToStringW(shouldbeTheSame, &uri, len + 1, &charsWritten); - if ((res != 0) || (charsWritten != len + 1)) { - uriFreeUriMembersW(&uri); - return false; - } - - // Back to string, _too small_ limit - res = uriToStringW(shouldbeTheSame, &uri, len, &charsWritten); - if ((res == 0) || (charsWritten >= len + 1)) { - uriFreeUriMembersW(&uri); - return false; - } - - uriFreeUriMembersW(&uri); - return equals; - } + } + + // Back to string, _exact_ limit + const int len = static_cast<int>(wcslen(text)); + int charsWritten; + res = uriToStringW(shouldbeTheSame, &uri, len + 1, &charsWritten); + if ((res != 0) || (charsWritten != len + 1)) { + uriFreeUriMembersW(&uri); + return false; + } + + // Back to string, _too small_ limit + res = uriToStringW(shouldbeTheSame, &uri, len, &charsWritten); + if ((res == 0) || (charsWritten >= len + 1)) { + uriFreeUriMembersW(&uri); + return false; + } + + uriFreeUriMembersW(&uri); + return equals; +} } // namespace TEST(UriSuite, TestToString) { - // Scheme - ASSERT_TRUE(testToStringHelper(L"ftp://localhost/")); - // UserInfo - ASSERT_TRUE(testToStringHelper(L"http://user:pass@localhost/")); - // IPv4 - ASSERT_TRUE(testToStringHelper(L"http://123.0.1.255/")); - // IPv6 - ASSERT_TRUE(testToStringHelper(L"http://[abcd:abcd:abcd:abcd:abcd:abcd:abcd:abcd]/")); - // IPvFuture - ASSERT_TRUE(testToStringHelper(L"http://[vA.123456]/")); - // Port - ASSERT_TRUE(testToStringHelper(L"http://example.com:123/")); - // Path - ASSERT_TRUE(testToStringHelper(L"http://example.com")); - ASSERT_TRUE(testToStringHelper(L"http://example.com/")); - ASSERT_TRUE(testToStringHelper(L"http://example.com/abc/")); - ASSERT_TRUE(testToStringHelper(L"http://example.com/abc/def")); - ASSERT_TRUE(testToStringHelper(L"http://example.com/abc/def/")); - ASSERT_TRUE(testToStringHelper(L"http://example.com//")); - ASSERT_TRUE(testToStringHelper(L"http://example.com/./..")); - // Query - ASSERT_TRUE(testToStringHelper(L"http://example.com/?abc")); - // Fragment - ASSERT_TRUE(testToStringHelper(L"http://example.com/#abc")); - ASSERT_TRUE(testToStringHelper(L"http://example.com/?def#abc")); - - // Relative - ASSERT_TRUE(testToStringHelper(L"a")); - ASSERT_TRUE(testToStringHelper(L"a/")); - ASSERT_TRUE(testToStringHelper(L"/a")); - ASSERT_TRUE(testToStringHelper(L"/a/")); - ASSERT_TRUE(testToStringHelper(L"abc")); - ASSERT_TRUE(testToStringHelper(L"abc/")); - ASSERT_TRUE(testToStringHelper(L"/abc")); - ASSERT_TRUE(testToStringHelper(L"/abc/")); - ASSERT_TRUE(testToStringHelper(L"a/def")); - ASSERT_TRUE(testToStringHelper(L"a/def/")); - ASSERT_TRUE(testToStringHelper(L"/a/def")); - ASSERT_TRUE(testToStringHelper(L"/a/def/")); - ASSERT_TRUE(testToStringHelper(L"abc/def")); - ASSERT_TRUE(testToStringHelper(L"abc/def/")); - ASSERT_TRUE(testToStringHelper(L"/abc/def")); - ASSERT_TRUE(testToStringHelper(L"/abc/def/")); - ASSERT_TRUE(testToStringHelper(L"/")); - ASSERT_TRUE(testToStringHelper(L"//a/")); - ASSERT_TRUE(testToStringHelper(L".")); - ASSERT_TRUE(testToStringHelper(L"./")); - ASSERT_TRUE(testToStringHelper(L"/.")); - ASSERT_TRUE(testToStringHelper(L"/./")); - ASSERT_TRUE(testToStringHelper(L"")); - ASSERT_TRUE(testToStringHelper(L"./abc/def")); - ASSERT_TRUE(testToStringHelper(L"?query")); - ASSERT_TRUE(testToStringHelper(L"#fragment")); - ASSERT_TRUE(testToStringHelper(L"?query#fragment")); - - // Tests for bugs from the past - ASSERT_TRUE(testToStringHelper(L"f:/.//g")); + // Scheme + ASSERT_TRUE(testToStringHelper(L"ftp://localhost/")); + // UserInfo + ASSERT_TRUE(testToStringHelper(L"http://user:pass@localhost/")); + // IPv4 + ASSERT_TRUE(testToStringHelper(L"http://123.0.1.255/")); + // IPv6 + ASSERT_TRUE(testToStringHelper(L"http://[abcd:abcd:abcd:abcd:abcd:abcd:abcd:abcd]/")); + // IPvFuture + ASSERT_TRUE(testToStringHelper(L"http://[vA.123456]/")); + // Port + ASSERT_TRUE(testToStringHelper(L"http://example.com:123/")); + // Path + ASSERT_TRUE(testToStringHelper(L"http://example.com")); + ASSERT_TRUE(testToStringHelper(L"http://example.com/")); + ASSERT_TRUE(testToStringHelper(L"http://example.com/abc/")); + ASSERT_TRUE(testToStringHelper(L"http://example.com/abc/def")); + ASSERT_TRUE(testToStringHelper(L"http://example.com/abc/def/")); + ASSERT_TRUE(testToStringHelper(L"http://example.com//")); + ASSERT_TRUE(testToStringHelper(L"http://example.com/./..")); + // Query + ASSERT_TRUE(testToStringHelper(L"http://example.com/?abc")); + // Fragment + ASSERT_TRUE(testToStringHelper(L"http://example.com/#abc")); + ASSERT_TRUE(testToStringHelper(L"http://example.com/?def#abc")); + + // Relative + ASSERT_TRUE(testToStringHelper(L"a")); + ASSERT_TRUE(testToStringHelper(L"a/")); + ASSERT_TRUE(testToStringHelper(L"/a")); + ASSERT_TRUE(testToStringHelper(L"/a/")); + ASSERT_TRUE(testToStringHelper(L"abc")); + ASSERT_TRUE(testToStringHelper(L"abc/")); + ASSERT_TRUE(testToStringHelper(L"/abc")); + ASSERT_TRUE(testToStringHelper(L"/abc/")); + ASSERT_TRUE(testToStringHelper(L"a/def")); + ASSERT_TRUE(testToStringHelper(L"a/def/")); + ASSERT_TRUE(testToStringHelper(L"/a/def")); + ASSERT_TRUE(testToStringHelper(L"/a/def/")); + ASSERT_TRUE(testToStringHelper(L"abc/def")); + ASSERT_TRUE(testToStringHelper(L"abc/def/")); + ASSERT_TRUE(testToStringHelper(L"/abc/def")); + ASSERT_TRUE(testToStringHelper(L"/abc/def/")); + ASSERT_TRUE(testToStringHelper(L"/")); + ASSERT_TRUE(testToStringHelper(L"//a/")); + ASSERT_TRUE(testToStringHelper(L".")); + ASSERT_TRUE(testToStringHelper(L"./")); + ASSERT_TRUE(testToStringHelper(L"/.")); + ASSERT_TRUE(testToStringHelper(L"/./")); + ASSERT_TRUE(testToStringHelper(L"")); + ASSERT_TRUE(testToStringHelper(L"./abc/def")); + ASSERT_TRUE(testToStringHelper(L"?query")); + ASSERT_TRUE(testToStringHelper(L"#fragment")); + ASSERT_TRUE(testToStringHelper(L"?query#fragment")); + + // Tests for bugs from the past + ASSERT_TRUE(testToStringHelper(L"f:/.//g")); } TEST(UriSuite, TestToStringBug1950126) { - UriParserStateW state; - UriUriW uriOne; - UriUriW uriTwo; - const wchar_t * const uriOneString = L"http://e.com/"; - const wchar_t * const uriTwoString = L"http://e.com"; - state.uri = &uriOne; - ASSERT_TRUE(URI_SUCCESS == uriParseUriW(&state, uriOneString)); - state.uri = &uriTwo; - ASSERT_TRUE(URI_SUCCESS == uriParseUriW(&state, uriTwoString)); - ASSERT_TRUE(URI_FALSE == uriEqualsUriW(&uriOne, &uriTwo)); - uriFreeUriMembersW(&uriOne); - uriFreeUriMembersW(&uriTwo); - - ASSERT_TRUE(testToStringHelper(uriOneString)); - ASSERT_TRUE(testToStringHelper(uriTwoString)); + UriParserStateW state; + UriUriW uriOne; + UriUriW uriTwo; + const wchar_t * const uriOneString = L"http://e.com/"; + const wchar_t * const uriTwoString = L"http://e.com"; + state.uri = &uriOne; + ASSERT_EQ(URI_SUCCESS, uriParseUriW(&state, uriOneString)); + state.uri = &uriTwo; + ASSERT_EQ(URI_SUCCESS, uriParseUriW(&state, uriTwoString)); + ASSERT_EQ(URI_FALSE, uriEqualsUriW(&uriOne, &uriTwo)); + uriFreeUriMembersW(&uriOne); + uriFreeUriMembersW(&uriTwo); + + ASSERT_TRUE(testToStringHelper(uriOneString)); + ASSERT_TRUE(testToStringHelper(uriTwoString)); } namespace { - bool testToStringCharsRequiredHelper(const wchar_t * text) { - // Parse - UriParserStateW state; - UriUriW uri; - state.uri = &uri; - int res = uriParseUriW(&state, text); - if (res != 0) { - uriFreeUriMembersW(&uri); - return false; - } - - // Required space? - int charsRequired; - if (uriToStringCharsRequiredW(&uri, &charsRequired) != 0) { - uriFreeUriMembersW(&uri); - return false; - } - - EXPECT_EQ(charsRequired, wcslen(text)); - - // Minimum - wchar_t * buffer = new wchar_t[charsRequired + 1]; - if (uriToStringW(buffer, &uri, charsRequired + 1, NULL) != 0) { - uriFreeUriMembersW(&uri); - delete [] buffer; - return false; - } - - // One less than minimum - if (uriToStringW(buffer, &uri, charsRequired, NULL) == 0) { - uriFreeUriMembersW(&uri); - delete [] buffer; - return false; - } - - uriFreeUriMembersW(&uri); - delete [] buffer; - return true; - } +bool testToStringCharsRequiredHelper(const wchar_t * text) { + // Parse + UriParserStateW state; + UriUriW uri; + state.uri = &uri; + int res = uriParseUriW(&state, text); + if (res != 0) { + uriFreeUriMembersW(&uri); + return false; + } + + // Required space? + int charsRequired; + if (uriToStringCharsRequiredW(&uri, &charsRequired) != 0) { + uriFreeUriMembersW(&uri); + return false; + } + + EXPECT_EQ(charsRequired, wcslen(text)); + + // Minimum + wchar_t * buffer = new wchar_t[charsRequired + 1]; + if (uriToStringW(buffer, &uri, charsRequired + 1, NULL) != 0) { + uriFreeUriMembersW(&uri); + delete[] buffer; + return false; + } + + // One less than minimum + if (uriToStringW(buffer, &uri, charsRequired, NULL) == 0) { + uriFreeUriMembersW(&uri); + delete[] buffer; + return false; + } + + uriFreeUriMembersW(&uri); + delete[] buffer; + return true; +} } // namespace TEST(UriSuite, TestToStringCharsRequired) { - EXPECT_TRUE(testToStringCharsRequiredHelper(L"http://1.1.1.1/")); - EXPECT_TRUE(testToStringCharsRequiredHelper(L"http://12.1.1.1/")); - EXPECT_TRUE(testToStringCharsRequiredHelper(L"http://123.1.1.1/")); - EXPECT_TRUE(testToStringCharsRequiredHelper(L"http://1.12.1.1/")); - EXPECT_TRUE(testToStringCharsRequiredHelper(L"http://1.123.1.1/")); - EXPECT_TRUE(testToStringCharsRequiredHelper(L"http://1.1.12.1/")); - EXPECT_TRUE(testToStringCharsRequiredHelper(L"http://1.1.123.1/")); - EXPECT_TRUE(testToStringCharsRequiredHelper(L"http://1.1.1.12/")); - EXPECT_TRUE(testToStringCharsRequiredHelper(L"http://1.1.1.123/")); - EXPECT_TRUE(testToStringCharsRequiredHelper(L"http://www.example.com/")); - EXPECT_TRUE(testToStringCharsRequiredHelper(L"http://www.example.com:80/")); - EXPECT_TRUE(testToStringCharsRequiredHelper(L"http://user:pass@www.example.com/")); - EXPECT_TRUE(testToStringCharsRequiredHelper(L"http://www.example.com/index.html")); - EXPECT_TRUE(testToStringCharsRequiredHelper(L"http://www.example.com/?abc")); - EXPECT_TRUE(testToStringCharsRequiredHelper(L"http://www.example.com/#def")); - EXPECT_TRUE(testToStringCharsRequiredHelper(L"http://www.example.com/?abc#def")); - EXPECT_TRUE(testToStringCharsRequiredHelper(L"/test")); - EXPECT_TRUE(testToStringCharsRequiredHelper(L"test")); + EXPECT_TRUE(testToStringCharsRequiredHelper(L"http://1.1.1.1/")); + EXPECT_TRUE(testToStringCharsRequiredHelper(L"http://12.1.1.1/")); + EXPECT_TRUE(testToStringCharsRequiredHelper(L"http://123.1.1.1/")); + EXPECT_TRUE(testToStringCharsRequiredHelper(L"http://1.12.1.1/")); + EXPECT_TRUE(testToStringCharsRequiredHelper(L"http://1.123.1.1/")); + EXPECT_TRUE(testToStringCharsRequiredHelper(L"http://1.1.12.1/")); + EXPECT_TRUE(testToStringCharsRequiredHelper(L"http://1.1.123.1/")); + EXPECT_TRUE(testToStringCharsRequiredHelper(L"http://1.1.1.12/")); + EXPECT_TRUE(testToStringCharsRequiredHelper(L"http://1.1.1.123/")); + EXPECT_TRUE(testToStringCharsRequiredHelper(L"http://www.example.com/")); + EXPECT_TRUE(testToStringCharsRequiredHelper(L"http://www.example.com:80/")); + EXPECT_TRUE(testToStringCharsRequiredHelper(L"http://user:pass@www.example.com/")); + EXPECT_TRUE(testToStringCharsRequiredHelper(L"http://www.example.com/index.html")); + EXPECT_TRUE(testToStringCharsRequiredHelper(L"http://www.example.com/?abc")); + EXPECT_TRUE(testToStringCharsRequiredHelper(L"http://www.example.com/#def")); + EXPECT_TRUE(testToStringCharsRequiredHelper(L"http://www.example.com/?abc#def")); + EXPECT_TRUE(testToStringCharsRequiredHelper(L"/test")); + EXPECT_TRUE(testToStringCharsRequiredHelper(L"test")); } namespace { - bool testNormalizeMaskHelper(const wchar_t * uriText, unsigned int expectedMask) { - UriParserStateW state; - UriUriW uri; - state.uri = &uri; - int res = uriParseUriW(&state, uriText); - if (res != 0) { - uriFreeUriMembersW(&uri); - return false; - } - - const unsigned int maskBefore = uriNormalizeSyntaxMaskRequiredW(&uri); - if (maskBefore != expectedMask) { - uriFreeUriMembersW(&uri); - return false; - } - - res = uriNormalizeSyntaxW(&uri); - if (res != 0) { - uriFreeUriMembersW(&uri); - return false; - } - - const unsigned int maskAfter = uriNormalizeSyntaxMaskRequiredW(&uri); - uriFreeUriMembersW(&uri); - - // Second call should be no problem - uriFreeUriMembersW(&uri); - - return (maskAfter == URI_NORMALIZED); - } +bool testNormalizeMaskHelper(const wchar_t * uriText, unsigned int expectedMask) { + UriParserStateW state; + UriUriW uri; + state.uri = &uri; + int res = uriParseUriW(&state, uriText); + if (res != 0) { + uriFreeUriMembersW(&uri); + return false; + } + + const unsigned int maskBefore = uriNormalizeSyntaxMaskRequiredW(&uri); + if (maskBefore != expectedMask) { + uriFreeUriMembersW(&uri); + return false; + } + + res = uriNormalizeSyntaxW(&uri); + if (res != 0) { + uriFreeUriMembersW(&uri); + return false; + } + + const unsigned int maskAfter = uriNormalizeSyntaxMaskRequiredW(&uri); + uriFreeUriMembersW(&uri); + + // Second call should be no problem + uriFreeUriMembersW(&uri); + + return (maskAfter == URI_NORMALIZED); +} } // namespace TEST(UriSuite, TestNormalizeSyntaxMaskRequired) { - ASSERT_TRUE(testNormalizeMaskHelper(L"http://localhost/", URI_NORMALIZED)); - ASSERT_TRUE(testNormalizeMaskHelper(L"httP://localhost/", URI_NORMALIZE_SCHEME)); - ASSERT_TRUE(testNormalizeMaskHelper(L"http://%0d@localhost/", URI_NORMALIZE_USER_INFO)); - ASSERT_TRUE(testNormalizeMaskHelper(L"http://localhosT/", URI_NORMALIZE_HOST)); - ASSERT_TRUE(testNormalizeMaskHelper(L"http://localhost/./abc", URI_NORMALIZE_PATH)); - ASSERT_TRUE(testNormalizeMaskHelper(L"http://localhost/?AB%43", URI_NORMALIZE_QUERY)); - ASSERT_TRUE(testNormalizeMaskHelper(L"http://localhost/#AB%43", URI_NORMALIZE_FRAGMENT)); + ASSERT_TRUE(testNormalizeMaskHelper(L"http://localhost/", URI_NORMALIZED)); + ASSERT_TRUE(testNormalizeMaskHelper(L"httP://localhost/", URI_NORMALIZE_SCHEME)); + ASSERT_TRUE( + testNormalizeMaskHelper(L"http://%0d@localhost/", URI_NORMALIZE_USER_INFO)); + ASSERT_TRUE(testNormalizeMaskHelper(L"http://localhosT/", URI_NORMALIZE_HOST)); + ASSERT_TRUE(testNormalizeMaskHelper(L"http://localhost/./abc", URI_NORMALIZE_PATH)); + ASSERT_TRUE(testNormalizeMaskHelper(L"http://localhost/?AB%43", URI_NORMALIZE_QUERY)); + ASSERT_TRUE( + testNormalizeMaskHelper(L"http://localhost/#AB%43", URI_NORMALIZE_FRAGMENT)); +} + +TEST(UriSuite, TestNormalizeSyntaxMaskRequiredPort) { + EXPECT_TRUE(testNormalizeMaskHelper(L"https://localhost:443/", URI_NORMALIZED)); + EXPECT_TRUE(testNormalizeMaskHelper(L"https://localhost:0/", URI_NORMALIZED)); + EXPECT_TRUE(testNormalizeMaskHelper(L"https://localhost:/", URI_NORMALIZED)); + + EXPECT_TRUE(testNormalizeMaskHelper(L"https://localhost:0443/", URI_NORMALIZE_PORT)); + EXPECT_TRUE(testNormalizeMaskHelper(L"https://localhost:00443/", URI_NORMALIZE_PORT)); + EXPECT_TRUE(testNormalizeMaskHelper(L"https://localhost:00/", URI_NORMALIZE_PORT)); } namespace { - bool testNormalizeSyntaxHelper(const wchar_t * uriText, const wchar_t * expectedNormalized, - unsigned int mask = static_cast<unsigned int>(-1)) { - UriParserStateW stateW; - int res; - - UriUriW testUri; - stateW.uri = &testUri; - res = uriParseUriW(&stateW, uriText); - if (res != 0) { - uriFreeUriMembersW(&testUri); - return false; - } - - // Expected result - UriUriW expectedUri; - stateW.uri = &expectedUri; - res = uriParseUriW(&stateW, expectedNormalized); - if (res != 0) { - uriFreeUriMembersW(&testUri); - uriFreeUriMembersW(&expectedUri); - return false; - } - - // First run - res = uriNormalizeSyntaxExW(&testUri, mask); - if (res != 0) { - uriFreeUriMembersW(&testUri); - uriFreeUriMembersW(&expectedUri); - return false; - } - - bool equalAfter = (URI_TRUE == uriEqualsUriW(&testUri, &expectedUri)); - - // Second run - res = uriNormalizeSyntaxExW(&testUri, mask); - if (res != 0) { - uriFreeUriMembersW(&testUri); - uriFreeUriMembersW(&expectedUri); - return false; - } - - equalAfter = equalAfter - && (URI_TRUE == uriEqualsUriW(&testUri, &expectedUri)); - - uriFreeUriMembersW(&testUri); - uriFreeUriMembersW(&expectedUri); - return equalAfter; - } +bool testNormalizeSyntaxHelper(const wchar_t * uriText, + const wchar_t * expectedNormalized, + unsigned int mask = static_cast<unsigned int>(-1)) { + UriParserStateW stateW; + int res; + + UriUriW testUri; + stateW.uri = &testUri; + res = uriParseUriW(&stateW, uriText); + if (res != 0) { + uriFreeUriMembersW(&testUri); + return false; + } + + // Expected result + UriUriW expectedUri; + stateW.uri = &expectedUri; + res = uriParseUriW(&stateW, expectedNormalized); + if (res != 0) { + uriFreeUriMembersW(&testUri); + uriFreeUriMembersW(&expectedUri); + return false; + } + + // First run + res = uriNormalizeSyntaxExW(&testUri, mask); + if (res != 0) { + uriFreeUriMembersW(&testUri); + uriFreeUriMembersW(&expectedUri); + return false; + } + + bool equalAfter = (URI_TRUE == uriEqualsUriW(&testUri, &expectedUri)); + + // Second run + res = uriNormalizeSyntaxExW(&testUri, mask); + if (res != 0) { + uriFreeUriMembersW(&testUri); + uriFreeUriMembersW(&expectedUri); + return false; + } + + equalAfter = equalAfter && (URI_TRUE == uriEqualsUriW(&testUri, &expectedUri)); + + uriFreeUriMembersW(&testUri); + uriFreeUriMembersW(&expectedUri); + return equalAfter; +} } // namespace TEST(UriSuite, TestNormalizeSyntax) { - ASSERT_TRUE(testNormalizeSyntaxHelper( - L"eXAMPLE://a/./b/../b/%63/%7bfoo%7d", - L"example://a/b/c/%7Bfoo%7D")); + ASSERT_TRUE(testNormalizeSyntaxHelper(L"eXAMPLE://a/./b/../b/%63/%7bfoo%7d", + L"example://a/b/c/%7Bfoo%7D")); + + // Testcase by Adrian Manrique + ASSERT_TRUE( + testNormalizeSyntaxHelper(L"http://examp%4Ce.com/", L"http://example.com/")); - // Testcase by Adrian Manrique - ASSERT_TRUE(testNormalizeSyntaxHelper( - L"http://examp%4Ce.com/", - L"http://example.com/")); + // Testcase by Adrian Manrique + ASSERT_TRUE(testNormalizeSyntaxHelper(L"http://example.com/a/b/%2E%2E/", + L"http://example.com/a/")); - // Testcase by Adrian Manrique - ASSERT_TRUE(testNormalizeSyntaxHelper( - L"http://example.com/a/b/%2E%2E/", - L"http://example.com/a/")); + // Reported by Adrian Manrique + ASSERT_TRUE(testNormalizeSyntaxHelper(L"http://user:pass@SOMEHOST.COM:123", + L"http://user:pass@somehost.com:123")); - // Reported by Adrian Manrique - ASSERT_TRUE(testNormalizeSyntaxHelper( - L"http://user:pass@SOMEHOST.COM:123", - L"http://user:pass@somehost.com:123")); + ASSERT_TRUE( + testNormalizeSyntaxHelper(L"https://%e4%bd%a0%e5%a5%bd%e4%bd%a0%e5%a5%bd.com", + L"https://%E4%BD%A0%E5%A5%BD%E4%BD%A0%E5%A5%BD.com")); - ASSERT_TRUE(testNormalizeSyntaxHelper( - L"HTTP://a:b@HOST:123/./1/2/../%41?abc#def", - L"http://a:b@host:123/1/A?abc#def")); + ASSERT_TRUE(testNormalizeSyntaxHelper(L"https://[2041:0000:140F::875B:131B]", + L"https://[2041:0000:140f::875b:131b]")); - ASSERT_TRUE(testNormalizeSyntaxHelper( - L"../../abc", - L"../../abc")); + ASSERT_TRUE(testNormalizeSyntaxHelper(L"HTTP://a:b@HOST:123/./1/2/../%41?abc#def", + L"http://a:b@host:123/1/A?abc#def")); - ASSERT_TRUE(testNormalizeSyntaxHelper( - L"../../abc/..", - L"../../")); + ASSERT_TRUE(testNormalizeSyntaxHelper(L"../../abc", L"../../abc")); - ASSERT_TRUE(testNormalizeSyntaxHelper( - L"../../abc/../def", - L"../../def")); + ASSERT_TRUE(testNormalizeSyntaxHelper(L"../../abc/..", L"../../")); - ASSERT_TRUE(testNormalizeSyntaxHelper( - L"abc/..", - L"")); + ASSERT_TRUE(testNormalizeSyntaxHelper(L"../../abc/../def", L"../../def")); - ASSERT_TRUE(testNormalizeSyntaxHelper( - L"abc/../", - L"")); + ASSERT_TRUE(testNormalizeSyntaxHelper(L"abc/..", L"")); - ASSERT_TRUE(testNormalizeSyntaxHelper( - L"../../abc/./def", - L"../../abc/def")); + ASSERT_TRUE(testNormalizeSyntaxHelper(L"abc/../", L"")); - ASSERT_TRUE(testNormalizeSyntaxHelper( - L"./def", - L"def")); + ASSERT_TRUE(testNormalizeSyntaxHelper(L"../../abc/./def", L"../../abc/def")); - ASSERT_TRUE(testNormalizeSyntaxHelper( - L"def/.", - L"def/")); + ASSERT_TRUE(testNormalizeSyntaxHelper(L"./def", L"def")); - ASSERT_TRUE(testNormalizeSyntaxHelper( - L"./abc:def", - L"./abc:def")); + ASSERT_TRUE(testNormalizeSyntaxHelper(L"def/.", L"def/")); + + ASSERT_TRUE(testNormalizeSyntaxHelper(L"./abc:def", L"./abc:def")); } TEST(UriSuite, TestNormalizeSyntaxComponents) { - ASSERT_TRUE(testNormalizeSyntaxHelper( - L"HTTP://%41@EXAMPLE.ORG/../a?%41#%41", - L"http://%41@EXAMPLE.ORG/../a?%41#%41", - URI_NORMALIZE_SCHEME)); + ASSERT_TRUE(testNormalizeSyntaxHelper(L"HTTP://%41@EXAMPLE.ORG/../a?%41#%41", + L"http://%41@EXAMPLE.ORG/../a?%41#%41", + URI_NORMALIZE_SCHEME)); + + ASSERT_TRUE(testNormalizeSyntaxHelper(L"HTTP://%41@EXAMPLE.ORG/../a?%41#%41", + L"HTTP://A@EXAMPLE.ORG/../a?%41#%41", + URI_NORMALIZE_USER_INFO)); - ASSERT_TRUE(testNormalizeSyntaxHelper( - L"HTTP://%41@EXAMPLE.ORG/../a?%41#%41", - L"HTTP://A@EXAMPLE.ORG/../a?%41#%41", - URI_NORMALIZE_USER_INFO)); + ASSERT_TRUE(testNormalizeSyntaxHelper(L"HTTP://%41@EXAMPLE.ORG/../a?%41#%41", + L"HTTP://%41@example.org/../a?%41#%41", + URI_NORMALIZE_HOST)); - ASSERT_TRUE(testNormalizeSyntaxHelper( - L"HTTP://%41@EXAMPLE.ORG/../a?%41#%41", - L"HTTP://%41@example.org/../a?%41#%41", - URI_NORMALIZE_HOST)); + ASSERT_TRUE(testNormalizeSyntaxHelper(L"HTTP://EXAMPLE.ORG:00080/", + L"HTTP://EXAMPLE.ORG:80/", URI_NORMALIZE_PORT)); - ASSERT_TRUE(testNormalizeSyntaxHelper( - L"HTTP://%41@EXAMPLE.ORG/../a?%41#%41", - L"HTTP://%41@EXAMPLE.ORG/a?%41#%41", - URI_NORMALIZE_PATH)); + ASSERT_TRUE(testNormalizeSyntaxHelper(L"HTTP://%41@EXAMPLE.ORG/../a?%41#%41", + L"HTTP://%41@EXAMPLE.ORG/a?%41#%41", + URI_NORMALIZE_PATH)); - ASSERT_TRUE(testNormalizeSyntaxHelper( - L"HTTP://%41@EXAMPLE.ORG/../a?%41#%41", - L"HTTP://%41@EXAMPLE.ORG/../a?A#%41", - URI_NORMALIZE_QUERY)); + ASSERT_TRUE(testNormalizeSyntaxHelper(L"HTTP://%41@EXAMPLE.ORG/../a?%41#%41", + L"HTTP://%41@EXAMPLE.ORG/../a?A#%41", + URI_NORMALIZE_QUERY)); - ASSERT_TRUE(testNormalizeSyntaxHelper( - L"HTTP://%41@EXAMPLE.ORG/../a?%41#%41", - L"HTTP://%41@EXAMPLE.ORG/../a?%41#A", - URI_NORMALIZE_FRAGMENT)); + ASSERT_TRUE(testNormalizeSyntaxHelper(L"HTTP://%41@EXAMPLE.ORG/../a?%41#%41", + L"HTTP://%41@EXAMPLE.ORG/../a?%41#A", + URI_NORMALIZE_FRAGMENT)); +} + +TEST(UriSuite, TestNormalizeSyntaxPort) { + // Empty port text unchanged + ASSERT_TRUE(testNormalizeSyntaxHelper(L"scheme://host:/", L"scheme://host:/", + URI_NORMALIZE_PORT)); + // Zero port unchanged + ASSERT_TRUE(testNormalizeSyntaxHelper(L"scheme://host:0/", L"scheme://host:0/", + URI_NORMALIZE_PORT)); + // All-zeros port turned into single zero + ASSERT_TRUE(testNormalizeSyntaxHelper(L"scheme://host:00/", L"scheme://host:0/", + URI_NORMALIZE_PORT)); + // Leading zeros cut off + ASSERT_TRUE(testNormalizeSyntaxHelper(L"scheme://host:00080/", L"scheme://host:80/", + URI_NORMALIZE_PORT)); } TEST(UriSuite, TestNormalizeSyntaxPath) { - // These are from GitHub issue #92 - EXPECT_TRUE(testNormalizeSyntaxHelper( - L"http://a/b/c/../../..", - L"http://a/", - URI_NORMALIZE_PATH)); - EXPECT_TRUE(testNormalizeSyntaxHelper( - L"http://a/b/../c/../..", - L"http://a/", - URI_NORMALIZE_PATH)); - EXPECT_TRUE(testNormalizeSyntaxHelper( - L"http://a/b/c/../../..", - L"http://a/", - URI_NORMALIZE_PATH)); - - // .. and these are related - EXPECT_TRUE(testNormalizeSyntaxHelper( - L"http://a/..", - L"http://a/", - URI_NORMALIZE_PATH)); - EXPECT_TRUE(testNormalizeSyntaxHelper( - L"/..", - L"/", - URI_NORMALIZE_PATH)); - EXPECT_TRUE(testNormalizeSyntaxHelper( - L"http://a/..///", - L"http://a///", - URI_NORMALIZE_PATH)); - EXPECT_TRUE(testNormalizeSyntaxHelper( - L"http://a/..///..", - L"http://a//", - URI_NORMALIZE_PATH)); - EXPECT_TRUE(testNormalizeSyntaxHelper( - L"a/b/c/../../..", - L"", - URI_NORMALIZE_PATH)); - EXPECT_TRUE(testNormalizeSyntaxHelper( - L"a/b/../../c/..", - L"", - URI_NORMALIZE_PATH)); + // These are from GitHub issue #92 + EXPECT_TRUE(testNormalizeSyntaxHelper(L"http://a/b/c/../../..", L"http://a/", + URI_NORMALIZE_PATH)); + EXPECT_TRUE(testNormalizeSyntaxHelper(L"http://a/b/../c/../..", L"http://a/", + URI_NORMALIZE_PATH)); + EXPECT_TRUE(testNormalizeSyntaxHelper(L"http://a/b/c/../../..", L"http://a/", + URI_NORMALIZE_PATH)); + + // .. and these are related + EXPECT_TRUE( + testNormalizeSyntaxHelper(L"http://a/..", L"http://a/", URI_NORMALIZE_PATH)); + EXPECT_TRUE(testNormalizeSyntaxHelper(L"/..", L"/", URI_NORMALIZE_PATH)); + EXPECT_TRUE( + testNormalizeSyntaxHelper(L"http://a/..///", L"http://a///", URI_NORMALIZE_PATH)); + EXPECT_TRUE(testNormalizeSyntaxHelper(L"http://a/..///..", L"http://a//", + URI_NORMALIZE_PATH)); + EXPECT_TRUE(testNormalizeSyntaxHelper(L"a/b/c/../../..", L"", URI_NORMALIZE_PATH)); + EXPECT_TRUE(testNormalizeSyntaxHelper(L"a/b/../../c/..", L"", URI_NORMALIZE_PATH)); } TEST(UriSuite, TestNormalizeCrashBug20080224) { - UriParserStateW stateW; - int res; - UriUriW testUri; - stateW.uri = &testUri; - - res = uriParseUriW(&stateW, L"http://example.org/abc//../def"); - ASSERT_TRUE(res == 0); - - // First call will make us owner of copied memory - res = uriNormalizeSyntaxExW(&testUri, URI_NORMALIZE_SCHEME); - ASSERT_TRUE(res == 0); - res = uriNormalizeSyntaxExW(&testUri, URI_NORMALIZE_HOST); - ASSERT_TRUE(res == 0); - - // Frees empty path segment -> crash - res = uriNormalizeSyntaxW(&testUri); - ASSERT_TRUE(res == 0); - - uriFreeUriMembersW(&testUri); + UriParserStateW stateW; + int res; + UriUriW testUri; + stateW.uri = &testUri; + + res = uriParseUriW(&stateW, L"http://example.org/abc//../def"); + ASSERT_EQ(res, 0); + + // First call will make us owner of copied memory + res = uriNormalizeSyntaxExW(&testUri, URI_NORMALIZE_SCHEME); + ASSERT_EQ(res, 0); + res = uriNormalizeSyntaxExW(&testUri, URI_NORMALIZE_HOST); + ASSERT_EQ(res, 0); + + // Frees empty path segment -> crash + res = uriNormalizeSyntaxW(&testUri); + ASSERT_EQ(res, 0); + + uriFreeUriMembersW(&testUri); +} + +TEST(UriSuite, TestNormalizeBug262Fixed) { + EXPECT_TRUE(testNormalizeSyntaxHelper(L"scheme:/.//foo/bar", L"scheme:/.//foo/bar", + URI_NORMALIZE_PATH)); + EXPECT_TRUE( + testNormalizeSyntaxHelper(L"/.//foo/bar", L"/.//foo/bar", URI_NORMALIZE_PATH)); + EXPECT_TRUE( + testNormalizeSyntaxHelper(L".//foo/bar", L".//foo/bar", URI_NORMALIZE_PATH)); +} + +TEST(UriSuite, TestNormalizeBug262Unchanged) { + // 3x same as TestNormalizeBug262Fixed above + // but with a single slash rather than double slashes + EXPECT_TRUE(testNormalizeSyntaxHelper(L"scheme:/./foo/bar", L"scheme:/foo/bar", + URI_NORMALIZE_PATH)); + EXPECT_TRUE( + testNormalizeSyntaxHelper(L"/./foo/bar", L"/foo/bar", URI_NORMALIZE_PATH)); + EXPECT_TRUE(testNormalizeSyntaxHelper(L"./foo/bar", L"foo/bar", URI_NORMALIZE_PATH)); + + // 2x same as TestNormalizeBug262Fixed above + // but with a host added + EXPECT_TRUE(testNormalizeSyntaxHelper(L"scheme://host/.//foo/bar", + L"scheme://host//foo/bar", URI_NORMALIZE_PATH)); + EXPECT_TRUE(testNormalizeSyntaxHelper(L"//host/.//foo/bar", L"//host//foo/bar", + URI_NORMALIZE_PATH)); + + // Second path segment containing a colon + EXPECT_TRUE(testNormalizeSyntaxHelper(L"scheme:./path1:/path2", + L"scheme:path1:/path2", URI_NORMALIZE_PATH)); + EXPECT_TRUE(testNormalizeSyntaxHelper(L"./path1:/path2", L"./path1:/path2", + URI_NORMALIZE_PATH)); } namespace { - void testFilenameUriConversionHelper(const wchar_t * filename, - const wchar_t * uriString, bool forUnix, - const wchar_t * expectedUriString = NULL) { - const int prefixLen = forUnix ? 7 : 8; - if (! expectedUriString) { - expectedUriString = uriString; - } - - // Filename to URI string - const size_t uriBufferLen = prefixLen + 3 * wcslen(filename) + 1; - wchar_t * uriBuffer = new wchar_t[uriBufferLen]; - if (forUnix) { - uriUnixFilenameToUriStringW(filename, uriBuffer); - } else { - uriWindowsFilenameToUriStringW(filename, uriBuffer); - } -#ifdef HAVE_WPRINTF - // wprintf(L"1 [%s][%s]\n", uriBuffer, expectedUriString); -#endif - ASSERT_TRUE(!wcscmp(uriBuffer, expectedUriString)); - delete [] uriBuffer; - - // URI string to filename - const size_t filenameBufferLen = wcslen(uriString) + 1; - wchar_t * filenameBuffer = new wchar_t[filenameBufferLen]; - if (forUnix) { - uriUriStringToUnixFilenameW(uriString, filenameBuffer); - } else { - uriUriStringToWindowsFilenameW(uriString, filenameBuffer); - } -#ifdef HAVE_WPRINTF - // wprintf(L"2 [%s][%s]\n", filenameBuffer, filename); -#endif - ASSERT_TRUE(!wcscmp(filenameBuffer, filename)); - delete [] filenameBuffer; - } +void testFilenameUriConversionHelper(const wchar_t * filename, const wchar_t * uriString, + bool forUnix, + const wchar_t * expectedUriString = NULL) { + const int prefixLen = forUnix ? 7 : 8; + if (!expectedUriString) { + expectedUriString = uriString; + } + + // Filename to URI string + const size_t uriBufferLen = prefixLen + 3 * wcslen(filename) + 1; + wchar_t * uriBuffer = new wchar_t[uriBufferLen]; + if (forUnix) { + uriUnixFilenameToUriStringW(filename, uriBuffer); + } else { + uriWindowsFilenameToUriStringW(filename, uriBuffer); + } + ASSERT_TRUE(!wcscmp(uriBuffer, expectedUriString)); + delete[] uriBuffer; + + // URI string to filename + const size_t filenameBufferLen = wcslen(uriString) + 1; + wchar_t * filenameBuffer = new wchar_t[filenameBufferLen]; + if (forUnix) { + uriUriStringToUnixFilenameW(uriString, filenameBuffer); + } else { + uriUriStringToWindowsFilenameW(uriString, filenameBuffer); + } + ASSERT_TRUE(!wcscmp(filenameBuffer, filename)); + delete[] filenameBuffer; +} } // namespace TEST(UriSuite, TestFilenameUriConversion) { - const bool FOR_UNIX = true; - const bool FOR_WINDOWS = false; - testFilenameUriConversionHelper(L"/bin/bash", L"file:///bin/bash", FOR_UNIX); - testFilenameUriConversionHelper(L"/bin/bash", L"file:/bin/bash", FOR_UNIX, L"file:///bin/bash"); - testFilenameUriConversionHelper(L"./configure", L"./configure", FOR_UNIX); + const bool FOR_UNIX = true; + const bool FOR_WINDOWS = false; + testFilenameUriConversionHelper(L"/bin/bash", L"file:///bin/bash", FOR_UNIX); + testFilenameUriConversionHelper(L"/bin/bash", L"file:/bin/bash", FOR_UNIX, + L"file:///bin/bash"); + testFilenameUriConversionHelper(L"./configure", L"./configure", FOR_UNIX); - testFilenameUriConversionHelper(L"E:\\Documents and Settings", L"file:///E:/Documents%20and%20Settings", FOR_WINDOWS); - testFilenameUriConversionHelper(L"c:\\path\\to\\file.txt", L"file:c:/path/to/file.txt", FOR_WINDOWS, L"file:///c:/path/to/file.txt"); + testFilenameUriConversionHelper(L"E:\\Documents and Settings", + L"file:///E:/Documents%20and%20Settings", + FOR_WINDOWS); + testFilenameUriConversionHelper(L"c:\\path\\to\\file.txt", + L"file:c:/path/to/file.txt", FOR_WINDOWS, + L"file:///c:/path/to/file.txt"); - testFilenameUriConversionHelper(L".\\Readme.txt", L"./Readme.txt", FOR_WINDOWS); + testFilenameUriConversionHelper(L".\\Readme.txt", L"./Readme.txt", FOR_WINDOWS); - testFilenameUriConversionHelper(L"index.htm", L"index.htm", FOR_WINDOWS); - testFilenameUriConversionHelper(L"index.htm", L"index.htm", FOR_UNIX); + testFilenameUriConversionHelper(L"index.htm", L"index.htm", FOR_WINDOWS); + testFilenameUriConversionHelper(L"index.htm", L"index.htm", FOR_UNIX); - testFilenameUriConversionHelper(L"abc def", L"abc%20def", FOR_WINDOWS); - testFilenameUriConversionHelper(L"abc def", L"abc%20def", FOR_UNIX); + testFilenameUriConversionHelper(L"abc def", L"abc%20def", FOR_WINDOWS); + testFilenameUriConversionHelper(L"abc def", L"abc%20def", FOR_UNIX); - testFilenameUriConversionHelper(L"\\\\Server01\\user\\docs\\Letter.txt", L"file://Server01/user/docs/Letter.txt", FOR_WINDOWS); + testFilenameUriConversionHelper(L"\\\\Server01\\user\\docs\\Letter.txt", + L"file://Server01/user/docs/Letter.txt", FOR_WINDOWS); } TEST(UriSuite, TestCrashFreeUriMembersBug20080116) { - // Testcase by Adrian Manrique - UriParserStateA state; - UriUriA uri; - state.uri = &uri; - uriParseUriA(&state, "http://test/?"); - uriNormalizeSyntaxA(&uri); - uriFreeUriMembersA(&uri); + // Testcase by Adrian Manrique + UriParserStateA state; + UriUriA uri; + state.uri = &uri; + uriParseUriA(&state, "http://test/?"); + uriNormalizeSyntaxA(&uri); + uriFreeUriMembersA(&uri); - ASSERT_TRUE(true); + ASSERT_TRUE(true); } namespace { - void helperTestQueryString(char const * uriString, int pairsExpected); +void helperTestQueryString(char const * uriString, int pairsExpected); } TEST(UriSuite, TestCrashReport2418192) { - // Testcase by Harvey Vrsalovic - helperTestQueryString("http://svcs.cnn.com/weather/wrapper.jsp?&csiID=csi1", 1); + // Testcase by Harvey Vrsalovic + helperTestQueryString("http://svcs.cnn.com/weather/wrapper.jsp?&csiID=csi1", 1); } TEST(UriSuite, TestPervertedQueryString) { - helperTestQueryString("http://example.org/?&&=&&&=&&&&==&===&====", 5); + helperTestQueryString("http://example.org/?&&=&&&=&&&&==&===&====", 5); } TEST(UriSuite, TestQueryStringEndingInEqualSignNonBug32) { - const char * queryString = "firstname=sdsd&lastname="; + const char * queryString = "firstname=sdsd&lastname="; - UriQueryListA * queryList = NULL; - int itemCount = 0; - const int res = uriDissectQueryMallocA(&queryList, &itemCount, - queryString, queryString + strlen(queryString)); + UriQueryListA * queryList = NULL; + int itemCount = 0; + const int res = uriDissectQueryMallocA(&queryList, &itemCount, queryString, + queryString + strlen(queryString)); - ASSERT_TRUE(res == URI_SUCCESS); - ASSERT_TRUE(itemCount == 2); - ASSERT_TRUE(queryList != NULL); - ASSERT_TRUE(strcmp(queryList->key, "firstname") == 0); - ASSERT_TRUE(strcmp(queryList->value, "sdsd") == 0); - ASSERT_TRUE(strcmp(queryList->next->key, "lastname") == 0); - ASSERT_TRUE(strcmp(queryList->next->value, "") == 0); - ASSERT_TRUE(queryList->next->next == NULL); + ASSERT_EQ(res, URI_SUCCESS); + ASSERT_EQ(itemCount, 2); + ASSERT_TRUE(queryList != NULL); + EXPECT_STREQ(queryList->key, "firstname"); + EXPECT_STREQ(queryList->value, "sdsd"); + EXPECT_STREQ(queryList->next->key, "lastname"); + EXPECT_STREQ(queryList->next->value, ""); + ASSERT_TRUE(queryList->next->next == NULL); - uriFreeQueryListA(queryList); + uriFreeQueryListA(queryList); } namespace { - void helperTestQueryString(char const * uriString, int pairsExpected) { - UriParserStateA state; - UriUriA uri; - state.uri = &uri; - int res = uriParseUriA(&state, uriString); - ASSERT_TRUE(res == URI_SUCCESS); - - UriQueryListA * queryList = NULL; - int itemCount = 0; - - res = uriDissectQueryMallocA(&queryList, &itemCount, - uri.query.first, uri.query.afterLast); - ASSERT_TRUE(res == URI_SUCCESS); - ASSERT_TRUE(queryList != NULL); - ASSERT_TRUE(itemCount == pairsExpected); - uriFreeQueryListA(queryList); - uriFreeUriMembersA(&uri); - } +void helperTestQueryString(char const * uriString, int pairsExpected) { + UriParserStateA state; + UriUriA uri; + state.uri = &uri; + int res = uriParseUriA(&state, uriString); + ASSERT_EQ(res, URI_SUCCESS); + + UriQueryListA * queryList = NULL; + int itemCount = 0; + + res = uriDissectQueryMallocA(&queryList, &itemCount, uri.query.first, + uri.query.afterLast); + ASSERT_EQ(res, URI_SUCCESS); + ASSERT_TRUE(queryList != NULL); + ASSERT_EQ(itemCount, pairsExpected); + uriFreeQueryListA(queryList); + uriFreeUriMembersA(&uri); +} } // namespace TEST(UriSuite, TestCrashMakeOwnerBug20080207) { - // Testcase by Adrian Manrique - UriParserStateA state; - UriUriA sourceUri; - state.uri = &sourceUri; - const char * const sourceUriString = "http://user:pass@somehost.com:80/"; - if (uriParseUriA(&state, sourceUriString) != 0) { - ASSERT_TRUE(false); - } - if (uriNormalizeSyntaxA(&sourceUri) != 0) { - ASSERT_TRUE(false); - } - uriFreeUriMembersA(&sourceUri); - ASSERT_TRUE(true); + // Testcase by Adrian Manrique + UriParserStateA state; + UriUriA sourceUri; + state.uri = &sourceUri; + const char * const sourceUriString = "http://user:pass@somehost.com:80/"; + if (uriParseUriA(&state, sourceUriString) != 0) { + ASSERT_TRUE(false); + } + if (uriNormalizeSyntaxA(&sourceUri) != 0) { + ASSERT_TRUE(false); + } + uriFreeUriMembersA(&sourceUri); + ASSERT_TRUE(true); } namespace { - void testQueryListHelper(const wchar_t * input, int expectedItemCount) { - int res; - - UriBool spacePlusConversion = URI_TRUE; - UriBool normalizeBreaks = URI_FALSE; - UriBreakConversion breakConversion = URI_BR_DONT_TOUCH; - - int itemCount; - UriQueryListW * queryList; - res = uriDissectQueryMallocExW(&queryList, &itemCount, - input, input + wcslen(input), spacePlusConversion, breakConversion); - ASSERT_TRUE(res == URI_SUCCESS); - ASSERT_TRUE(itemCount == expectedItemCount); - ASSERT_TRUE((queryList == NULL) == (expectedItemCount == 0)); - - if (expectedItemCount != 0) { - // First - int charsRequired; - res = uriComposeQueryCharsRequiredExW(queryList, &charsRequired, spacePlusConversion, - normalizeBreaks); - ASSERT_TRUE(res == URI_SUCCESS); - ASSERT_TRUE(charsRequired >= (int)wcslen(input)); - - wchar_t * recomposed = new wchar_t[charsRequired + 1]; - int charsWritten; - res = uriComposeQueryExW(recomposed, queryList, charsRequired + 1, - &charsWritten, spacePlusConversion, normalizeBreaks); - ASSERT_TRUE(res == URI_SUCCESS); - ASSERT_TRUE(charsWritten <= charsRequired); - ASSERT_TRUE(charsWritten == (int)wcslen(input) + 1); - ASSERT_TRUE(!wcscmp(input, recomposed)); - delete [] recomposed; - - recomposed = NULL; - res = uriComposeQueryMallocW(&recomposed, queryList); - ASSERT_TRUE(res == URI_SUCCESS); - ASSERT_TRUE(recomposed != NULL); - ASSERT_TRUE(charsWritten == (int)wcslen(input) + 1); - ASSERT_TRUE(!wcscmp(input, recomposed)); - free(recomposed); - } - - uriFreeQueryListW(queryList); - } +void testQueryListHelper(const wchar_t * input, int expectedItemCount) { + int res; + + UriBool spacePlusConversion = URI_TRUE; + UriBool normalizeBreaks = URI_FALSE; + UriBreakConversion breakConversion = URI_BR_DONT_TOUCH; + + int itemCount; + UriQueryListW * queryList; + res = uriDissectQueryMallocExW(&queryList, &itemCount, input, input + wcslen(input), + spacePlusConversion, breakConversion); + ASSERT_EQ(res, URI_SUCCESS); + ASSERT_EQ(itemCount, expectedItemCount); + ASSERT_EQ((queryList == NULL), (expectedItemCount == 0)); + + if (expectedItemCount != 0) { + // First + int charsRequired; + res = uriComposeQueryCharsRequiredExW(queryList, &charsRequired, + spacePlusConversion, normalizeBreaks); + ASSERT_EQ(res, URI_SUCCESS); + ASSERT_TRUE(charsRequired >= (int)wcslen(input)); + + wchar_t * recomposed = new wchar_t[charsRequired + 1]; + int charsWritten; + res = uriComposeQueryExW(recomposed, queryList, charsRequired + 1, &charsWritten, + spacePlusConversion, normalizeBreaks); + ASSERT_EQ(res, URI_SUCCESS); + ASSERT_TRUE(charsWritten <= charsRequired); + ASSERT_EQ(charsWritten, (int)wcslen(input) + 1); + ASSERT_TRUE(!wcscmp(input, recomposed)); + delete[] recomposed; + + recomposed = NULL; + res = uriComposeQueryMallocW(&recomposed, queryList); + ASSERT_EQ(res, URI_SUCCESS); + ASSERT_TRUE(recomposed != NULL); + ASSERT_EQ(charsWritten, (int)wcslen(input) + 1); + ASSERT_TRUE(!wcscmp(input, recomposed)); + free(recomposed); + } + + uriFreeQueryListW(queryList); +} } // namespace TEST(UriSuite, QueryList) { - testQueryListHelper(L"one=ONE&two=TWO", 2); - testQueryListHelper(L"one=ONE&two=&three=THREE", 3); - testQueryListHelper(L"one=ONE&two&three=THREE", 3); - testQueryListHelper(L"one=ONE", 1); - testQueryListHelper(L"one", 1); - testQueryListHelper(L"", 0); + testQueryListHelper(L"one=ONE&two=TWO", 2); + testQueryListHelper(L"one=ONE&two=&three=THREE", 3); + testQueryListHelper(L"one=ONE&two&three=THREE", 3); + testQueryListHelper(L"one=ONE", 1); + testQueryListHelper(L"one", 1); + testQueryListHelper(L"", 0); } namespace { - void testQueryListPairHelper(const char * pair, const char * unescapedKey, - const char * unescapedValue, const char * fixed = NULL) { - int res; - UriQueryListA * queryList; - int itemCount; - - res = uriDissectQueryMallocA(&queryList, &itemCount, pair, pair + strlen(pair)); - ASSERT_TRUE(res == URI_SUCCESS); - ASSERT_TRUE(queryList != NULL); - ASSERT_TRUE(itemCount == 1); - ASSERT_TRUE(!strcmp(queryList->key, unescapedKey)); - ASSERT_TRUE(!strcmp(queryList->value, unescapedValue)); - - char * recomposed; - res = uriComposeQueryMallocA(&recomposed, queryList); - ASSERT_TRUE(res == URI_SUCCESS); - ASSERT_TRUE(recomposed != NULL); - ASSERT_TRUE(!strcmp(recomposed, (fixed != NULL) ? fixed : pair)); - free(recomposed); - uriFreeQueryListA(queryList); - } +void testQueryListPairHelper(const char * pair, const char * unescapedKey, + const char * unescapedValue, const char * fixed = NULL) { + int res; + UriQueryListA * queryList; + int itemCount; + + res = uriDissectQueryMallocA(&queryList, &itemCount, pair, pair + strlen(pair)); + ASSERT_EQ(res, URI_SUCCESS); + ASSERT_TRUE(queryList != NULL); + ASSERT_EQ(itemCount, 1); + EXPECT_STREQ(queryList->key, unescapedKey); + EXPECT_STREQ(queryList->value, unescapedValue); + + char * recomposed; + res = uriComposeQueryMallocA(&recomposed, queryList); + ASSERT_EQ(res, URI_SUCCESS); + ASSERT_TRUE(recomposed != NULL); + EXPECT_STREQ(recomposed, (fixed != NULL) ? fixed : pair); + free(recomposed); + uriFreeQueryListA(queryList); +} } // namespace TEST(UriSuite, TestQueryListPair) { - testQueryListPairHelper("one+two+%26+three=%2B", "one two & three", "+"); - testQueryListPairHelper("one=two=three", "one", "two=three", "one=two%3Dthree"); - testQueryListPairHelper("one=two=three=four", "one", "two=three=four", "one=two%3Dthree%3Dfour"); + testQueryListPairHelper("one+two+%26+three=%2B", "one two & three", "+"); + testQueryListPairHelper("one=two=three", "one", "two=three", "one=two%3Dthree"); + testQueryListPairHelper("one=two=three=four", "one", "two=three=four", + "one=two%3Dthree%3Dfour"); } TEST(UriSuite, TestQueryDissectionBug3590761) { - int res; - UriQueryListA * queryList; - int itemCount; - const char * const pair = "q=hello&x=&y="; + int res; + UriQueryListA * queryList; + int itemCount; + const char * const pair = "q=hello&x=&y="; - res = uriDissectQueryMallocA(&queryList, &itemCount, pair, pair + strlen(pair)); - ASSERT_TRUE(res == URI_SUCCESS); - ASSERT_TRUE(queryList != NULL); - ASSERT_TRUE(itemCount == 3); + res = uriDissectQueryMallocA(&queryList, &itemCount, pair, pair + strlen(pair)); + ASSERT_EQ(res, URI_SUCCESS); + ASSERT_TRUE(queryList != NULL); + ASSERT_EQ(itemCount, 3); - ASSERT_TRUE(!strcmp(queryList->key, "q")); - ASSERT_TRUE(!strcmp(queryList->value, "hello")); + EXPECT_STREQ(queryList->key, "q"); + EXPECT_STREQ(queryList->value, "hello"); - ASSERT_TRUE(!strcmp(queryList->next->key, "x")); - ASSERT_TRUE(!strcmp(queryList->next->value, "")); + EXPECT_STREQ(queryList->next->key, "x"); + EXPECT_STREQ(queryList->next->value, ""); - ASSERT_TRUE(!strcmp(queryList->next->next->key, "y")); - ASSERT_TRUE(!strcmp(queryList->next->next->value, "")); + EXPECT_STREQ(queryList->next->next->key, "y"); + EXPECT_STREQ(queryList->next->next->value, ""); - ASSERT_TRUE(! queryList->next->next->next); + ASSERT_TRUE(!queryList->next->next->next); - uriFreeQueryListA(queryList); + uriFreeQueryListA(queryList); } TEST(UriSuite, TestQueryCompositionMathCalc) { - UriQueryListA second = { /*.key =*/ "k2", /*.value =*/ "v2", /*.next =*/ NULL }; - UriQueryListA first = { /*.key =*/ "k1", /*.value =*/ "v1", /*.next =*/ &second }; + UriQueryListA second = {/*.key =*/"k2", /*.value =*/"v2", /*.next =*/NULL}; + UriQueryListA first = {/*.key =*/"k1", /*.value =*/"v1", /*.next =*/&second}; - int charsRequired; - ASSERT_TRUE(uriComposeQueryCharsRequiredA(&first, &charsRequired) - == URI_SUCCESS); + int charsRequired; + ASSERT_TRUE(uriComposeQueryCharsRequiredA(&first, &charsRequired) == URI_SUCCESS); - const int FACTOR = 6; /* due to escaping with normalizeBreaks */ - ASSERT_TRUE((unsigned)charsRequired == - FACTOR * strlen(first.key) + 1 + FACTOR * strlen(first.value) - + 1 - + FACTOR * strlen(second.key) + 1 + FACTOR * strlen(second.value) - ); + const int FACTOR = 6; /* due to escaping with normalizeBreaks */ + ASSERT_EQ((unsigned)charsRequired, + FACTOR * strlen(first.key) + 1 + FACTOR * strlen(first.value) + 1 + + FACTOR * strlen(second.key) + 1 + FACTOR * strlen(second.value)); } TEST(UriSuite, TestQueryCompositionMathWriteGoogleAutofuzz113244572) { - UriQueryListA second = { /*.key =*/ "\x11", /*.value =*/ NULL, /*.next =*/ NULL }; - UriQueryListA first = { /*.key =*/ "\x01", /*.value =*/ "\x02", /*.next =*/ &second }; - - const UriBool spaceToPlus = URI_TRUE; - const UriBool normalizeBreaks = URI_FALSE; /* for factor 3 but 6 */ - - const int charsRequired = (3 + 1 + 3) + 1 + (3); - - { - // Minimum space to hold everything fine - const char * const expected = "%01=%02" "&" "%11"; - char dest[charsRequired + 1]; - int charsWritten; - ASSERT_TRUE(uriComposeQueryExA(dest, &first, sizeof(dest), - &charsWritten, spaceToPlus, normalizeBreaks) - == URI_SUCCESS); - ASSERT_TRUE(! strcmp(dest, expected)); - ASSERT_TRUE(charsWritten == strlen(expected) + 1); - } - - { - // Previous math failed to take ampersand into account - char dest[charsRequired + 1 - 1]; - int charsWritten; - ASSERT_TRUE(uriComposeQueryExA(dest, &first, sizeof(dest), - &charsWritten, spaceToPlus, normalizeBreaks) - == URI_ERROR_OUTPUT_TOO_LARGE); - } + UriQueryListA second = {/*.key =*/"\x11", /*.value =*/NULL, /*.next =*/NULL}; + UriQueryListA first = {/*.key =*/"\x01", /*.value =*/"\x02", /*.next =*/&second}; + + const UriBool spaceToPlus = URI_TRUE; + const UriBool normalizeBreaks = URI_FALSE; /* for factor 3 but 6 */ + + const int charsRequired = (3 + 1 + 3) + 1 + (3); + + { + // Minimum space to hold everything fine + const char * const expected = "%01=%02" + "&" + "%11"; + char dest[charsRequired + 1]; + int charsWritten; + ASSERT_TRUE(uriComposeQueryExA(dest, &first, sizeof(dest), &charsWritten, + spaceToPlus, normalizeBreaks) + == URI_SUCCESS); + EXPECT_STREQ(dest, expected); + ASSERT_EQ(charsWritten, strlen(expected) + 1); + } + + { + // Previous math failed to take ampersand into account + char dest[charsRequired + 1 - 1]; + int charsWritten; + ASSERT_TRUE(uriComposeQueryExA(dest, &first, sizeof(dest), &charsWritten, + spaceToPlus, normalizeBreaks) + == URI_ERROR_OUTPUT_TOO_LARGE); + } } TEST(UriSuite, TestFreeCrashBug20080827) { - char const * const sourceUri = "abc"; - char const * const baseUri = "http://www.example.org/"; + char const * const sourceUri = "abc"; + char const * const baseUri = "http://www.example.org/"; - int res; - UriParserStateA state; - UriUriA absoluteDest; - UriUriA relativeSource; - UriUriA absoluteBase; + int res; + UriParserStateA state; + UriUriA absoluteDest; + UriUriA relativeSource; + UriUriA absoluteBase; - state.uri = &relativeSource; - res = uriParseUriA(&state, sourceUri); - ASSERT_TRUE(res == URI_SUCCESS); + state.uri = &relativeSource; + res = uriParseUriA(&state, sourceUri); + ASSERT_EQ(res, URI_SUCCESS); - state.uri = &absoluteBase; - res = uriParseUriA(&state, baseUri); - ASSERT_TRUE(res == URI_SUCCESS); + state.uri = &absoluteBase; + res = uriParseUriA(&state, baseUri); + ASSERT_EQ(res, URI_SUCCESS); - res = uriRemoveBaseUriA(&absoluteDest, &relativeSource, &absoluteBase, URI_FALSE); - ASSERT_TRUE(res == URI_ERROR_REMOVEBASE_REL_SOURCE); + res = uriRemoveBaseUriA(&absoluteDest, &relativeSource, &absoluteBase, URI_FALSE); + ASSERT_EQ(res, URI_ERROR_REMOVEBASE_REL_SOURCE); - uriFreeUriMembersA(&relativeSource); - uriFreeUriMembersA(&absoluteBase); - uriFreeUriMembersA(&absoluteDest); // Crashed here + uriFreeUriMembersA(&relativeSource); + uriFreeUriMembersA(&absoluteBase); + uriFreeUriMembersA(&absoluteDest); // Crashed here } TEST(UriSuite, TestInvalidInputBug16) { - UriParserStateA stateA; - UriUriA uriA; - stateA.uri = &uriA; - const char * const input = "A>B"; + UriParserStateA stateA; + UriUriA uriA; + stateA.uri = &uriA; + const char * const input = "A>B"; - const int res = uriParseUriA(&stateA, input); + const int res = uriParseUriA(&stateA, input); - ASSERT_TRUE(res == URI_ERROR_SYNTAX); - ASSERT_TRUE(stateA.errorPos == input + 1); - ASSERT_TRUE(stateA.errorCode == URI_ERROR_SYNTAX); /* failed previously */ + ASSERT_EQ(res, URI_ERROR_SYNTAX); + ASSERT_EQ(stateA.errorPos, input + 1); + ASSERT_EQ(stateA.errorCode, URI_ERROR_SYNTAX); /* failed previously */ - uriFreeUriMembersA(&uriA); + uriFreeUriMembersA(&uriA); } namespace { - void testEqualsHelper(const char * uri_to_test) { - UriParserStateA state; - UriUriA uriOne; - UriUriA uriTwo; - state.uri = &uriOne; - ASSERT_TRUE(URI_SUCCESS == uriParseUriA(&state, uri_to_test)); - state.uri = &uriTwo; - ASSERT_TRUE(URI_SUCCESS == uriParseUriA(&state, uri_to_test)); - ASSERT_TRUE(URI_TRUE == uriEqualsUriA(&uriOne, &uriTwo)); - uriFreeUriMembersA(&uriOne); - uriFreeUriMembersA(&uriTwo); - } +void testEqualsHelper(const char * uri_to_test) { + UriParserStateA state; + UriUriA uriOne; + UriUriA uriTwo; + state.uri = &uriOne; + ASSERT_EQ(URI_SUCCESS, uriParseUriA(&state, uri_to_test)); + state.uri = &uriTwo; + ASSERT_EQ(URI_SUCCESS, uriParseUriA(&state, uri_to_test)); + ASSERT_EQ(URI_TRUE, uriEqualsUriA(&uriOne, &uriTwo)); + uriFreeUriMembersA(&uriOne); + uriFreeUriMembersA(&uriTwo); +} } // namespace TEST(UriSuite, TestEquals) { - testEqualsHelper("http://host"); - testEqualsHelper("http://host:123"); - testEqualsHelper("http://foo:bar@host:123"); - testEqualsHelper("http://foo:bar@host:123/"); - testEqualsHelper("http://foo:bar@host:123/path"); - testEqualsHelper("http://foo:bar@host:123/path?query"); - testEqualsHelper("http://foo:bar@host:123/path?query#fragment"); - - testEqualsHelper("path"); - testEqualsHelper("/path"); - testEqualsHelper("/path/"); - testEqualsHelper("//path/"); - testEqualsHelper("//host"); - testEqualsHelper("//host:123"); + testEqualsHelper("http://host"); + testEqualsHelper("http://host:123"); + testEqualsHelper("http://foo:bar@host:123"); + testEqualsHelper("http://foo:bar@host:123/"); + testEqualsHelper("http://foo:bar@host:123/path"); + testEqualsHelper("http://foo:bar@host:123/path?query"); + testEqualsHelper("http://foo:bar@host:123/path?query#fragment"); + + testEqualsHelper("path"); + testEqualsHelper("/path"); + testEqualsHelper("/path/"); + testEqualsHelper("//path/"); + testEqualsHelper("//host"); + testEqualsHelper("//host:123"); } TEST(UriSuite, TestHostTextTerminationIssue15) { - UriParserStateA state; - UriUriA uri; - state.uri = &uri; - - // Empty host and port - const char * const emptyHostWithPortUri = "//:123"; - ASSERT_TRUE(URI_SUCCESS == uriParseUriA(&state, emptyHostWithPortUri)); - ASSERT_TRUE(uri.hostText.first == emptyHostWithPortUri + strlen("//")); - ASSERT_TRUE(uri.hostText.afterLast == uri.hostText.first + 0); - ASSERT_TRUE(uri.portText.first == emptyHostWithPortUri - + strlen("//:")); - ASSERT_TRUE(uri.portText.afterLast == uri.portText.first - + strlen("123")); - uriFreeUriMembersA(&uri); - - // Non-empty host and port - const char * const hostWithPortUri = "//h:123"; - ASSERT_TRUE(URI_SUCCESS == uriParseUriA(&state, hostWithPortUri)); - ASSERT_TRUE(uri.hostText.first == hostWithPortUri + strlen("//")); - ASSERT_TRUE(uri.hostText.afterLast == uri.hostText.first - + strlen("h")); - ASSERT_TRUE(uri.portText.first == hostWithPortUri + strlen("//h:")); - ASSERT_TRUE(uri.portText.afterLast == uri.portText.first - + strlen("123")); - uriFreeUriMembersA(&uri); - - // Empty host, empty user info - const char * const emptyHostEmptyUserInfoUri = "//@"; - ASSERT_TRUE(URI_SUCCESS == uriParseUriA(&state, - emptyHostEmptyUserInfoUri)); - ASSERT_TRUE(uri.userInfo.first == emptyHostEmptyUserInfoUri - + strlen("//")); - ASSERT_TRUE(uri.userInfo.afterLast == uri.userInfo.first + 0); - ASSERT_TRUE(uri.hostText.first == emptyHostEmptyUserInfoUri - + strlen("//@")); - ASSERT_TRUE(uri.hostText.afterLast == uri.hostText.first + 0); - uriFreeUriMembersA(&uri); - - // Non-empty host, empty user info - const char * const hostEmptyUserInfoUri = "//@h"; - ASSERT_TRUE(URI_SUCCESS == uriParseUriA(&state, hostEmptyUserInfoUri)); - ASSERT_TRUE(uri.userInfo.first == hostEmptyUserInfoUri + strlen("//")); - ASSERT_TRUE(uri.userInfo.afterLast == uri.userInfo.first + 0); - ASSERT_TRUE(uri.hostText.first == hostEmptyUserInfoUri - + strlen("//@")); - ASSERT_TRUE(uri.hostText.afterLast == uri.hostText.first - + strlen("h")); - uriFreeUriMembersA(&uri); - - // Empty host, non-empty user info - const char * const emptyHostWithUserInfoUri = "//:@"; - ASSERT_TRUE(URI_SUCCESS == uriParseUriA(&state, - emptyHostWithUserInfoUri)); - ASSERT_TRUE(uri.userInfo.first == emptyHostWithUserInfoUri - + strlen("//")); - ASSERT_TRUE(uri.userInfo.afterLast == uri.userInfo.first + 1); - ASSERT_TRUE(uri.hostText.first == emptyHostWithUserInfoUri - + strlen("//:@")); - ASSERT_TRUE(uri.hostText.afterLast == uri.hostText.first + 0); - uriFreeUriMembersA(&uri); - - // Exact case from issue #15 - const char * const issue15Uri = "//:%aa@"; - ASSERT_TRUE(URI_SUCCESS == uriParseUriA(&state, issue15Uri)); - ASSERT_TRUE(uri.userInfo.first == issue15Uri + strlen("//")); - ASSERT_TRUE(uri.userInfo.afterLast == uri.userInfo.first - + strlen(":%aa")); - ASSERT_TRUE(uri.hostText.first == issue15Uri + strlen("//:%aa@")); - ASSERT_TRUE(uri.hostText.afterLast == uri.hostText.first + 0); - uriFreeUriMembersA(&uri); + UriParserStateA state; + UriUriA uri; + state.uri = &uri; + + // Empty host and port + const char * const emptyHostWithPortUri = "//:123"; + ASSERT_EQ(URI_SUCCESS, uriParseUriA(&state, emptyHostWithPortUri)); + ASSERT_EQ(uri.hostText.first, emptyHostWithPortUri + strlen("//")); + ASSERT_EQ(uri.hostText.afterLast, uri.hostText.first + 0); + ASSERT_EQ(uri.portText.first, emptyHostWithPortUri + strlen("//:")); + ASSERT_EQ(uri.portText.afterLast, uri.portText.first + strlen("123")); + uriFreeUriMembersA(&uri); + + // Non-empty host and port + const char * const hostWithPortUri = "//h:123"; + ASSERT_EQ(URI_SUCCESS, uriParseUriA(&state, hostWithPortUri)); + ASSERT_EQ(uri.hostText.first, hostWithPortUri + strlen("//")); + ASSERT_EQ(uri.hostText.afterLast, uri.hostText.first + strlen("h")); + ASSERT_EQ(uri.portText.first, hostWithPortUri + strlen("//h:")); + ASSERT_EQ(uri.portText.afterLast, uri.portText.first + strlen("123")); + uriFreeUriMembersA(&uri); + + // Empty host, empty user info + const char * const emptyHostEmptyUserInfoUri = "//@"; + ASSERT_EQ(URI_SUCCESS, uriParseUriA(&state, emptyHostEmptyUserInfoUri)); + ASSERT_EQ(uri.userInfo.first, emptyHostEmptyUserInfoUri + strlen("//")); + ASSERT_EQ(uri.userInfo.afterLast, uri.userInfo.first + 0); + ASSERT_EQ(uri.hostText.first, emptyHostEmptyUserInfoUri + strlen("//@")); + ASSERT_EQ(uri.hostText.afterLast, uri.hostText.first + 0); + uriFreeUriMembersA(&uri); + + // Non-empty host, empty user info + const char * const hostEmptyUserInfoUri = "//@h"; + ASSERT_EQ(URI_SUCCESS, uriParseUriA(&state, hostEmptyUserInfoUri)); + ASSERT_EQ(uri.userInfo.first, hostEmptyUserInfoUri + strlen("//")); + ASSERT_EQ(uri.userInfo.afterLast, uri.userInfo.first + 0); + ASSERT_EQ(uri.hostText.first, hostEmptyUserInfoUri + strlen("//@")); + ASSERT_EQ(uri.hostText.afterLast, uri.hostText.first + strlen("h")); + uriFreeUriMembersA(&uri); + + // Empty host, non-empty user info + const char * const emptyHostWithUserInfoUri = "//:@"; + ASSERT_EQ(URI_SUCCESS, uriParseUriA(&state, emptyHostWithUserInfoUri)); + ASSERT_EQ(uri.userInfo.first, emptyHostWithUserInfoUri + strlen("//")); + ASSERT_EQ(uri.userInfo.afterLast, uri.userInfo.first + 1); + ASSERT_EQ(uri.hostText.first, emptyHostWithUserInfoUri + strlen("//:@")); + ASSERT_EQ(uri.hostText.afterLast, uri.hostText.first + 0); + uriFreeUriMembersA(&uri); + + // Exact case from issue #15 + const char * const issue15Uri = "//:%aa@"; + ASSERT_EQ(URI_SUCCESS, uriParseUriA(&state, issue15Uri)); + ASSERT_EQ(uri.userInfo.first, issue15Uri + strlen("//")); + ASSERT_EQ(uri.userInfo.afterLast, uri.userInfo.first + strlen(":%aa")); + ASSERT_EQ(uri.hostText.first, issue15Uri + strlen("//:%aa@")); + ASSERT_EQ(uri.hostText.afterLast, uri.hostText.first + 0); + uriFreeUriMembersA(&uri); } namespace { - void testCompareRangeHelper(const char * a, const char * b, int expected, bool avoidNullRange = true) { - UriTextRangeA ra; - UriTextRangeA rb; - - if (a) { - ra.first = a; - ra.afterLast = a + strlen(a); - } else { - ra.first = NULL; - ra.afterLast = NULL; - } - - if (b) { - rb.first = b; - rb.afterLast = b + strlen(b); - } else { - rb.first = NULL; - rb.afterLast = NULL; - } - - const int received = uriCompareRangeA( - ((a == NULL) && avoidNullRange) ? NULL : &ra, - ((b == NULL) && avoidNullRange) ? NULL : &rb); - if (received != expected) { - printf("Comparing <%s> to <%s> yields %d, expected %d.\n", - a, b, received, expected); - } - ASSERT_TRUE(received == expected); - } +void testCompareRangeHelper(const char * a, const char * b, int expected, + bool avoidNullRange = true) { + UriTextRangeA ra; + UriTextRangeA rb; + + if (a) { + ra.first = a; + ra.afterLast = a + strlen(a); + } else { + ra.first = NULL; + ra.afterLast = NULL; + } + + if (b) { + rb.first = b; + rb.afterLast = b + strlen(b); + } else { + rb.first = NULL; + rb.afterLast = NULL; + } + + const int received = uriCompareRangeA(((a == NULL) && avoidNullRange) ? NULL : &ra, + ((b == NULL) && avoidNullRange) ? NULL : &rb); + if (received != expected) { + printf("Comparing <%s> to <%s> yields %d, expected %d.\n", a, b, received, + expected); + } + ASSERT_EQ(received, expected); +} } // namespace TEST(UriSuite, TestRangeComparison) { - testCompareRangeHelper("", "", 0); - testCompareRangeHelper("a", "", 1); - testCompareRangeHelper("", "a", -1); + testCompareRangeHelper("", "", 0); + testCompareRangeHelper("a", "", 1); + testCompareRangeHelper("", "a", -1); - testCompareRangeHelper("a", "a", 0); - testCompareRangeHelper("a", "b", -1); - testCompareRangeHelper("b", "a", 1); + testCompareRangeHelper("a", "a", 0); + testCompareRangeHelper("a", "b", -1); + testCompareRangeHelper("b", "a", 1); - testCompareRangeHelper("a", "aa", -1); - testCompareRangeHelper("aa", "a", 1); + testCompareRangeHelper("a", "aa", -1); + testCompareRangeHelper("aa", "a", 1); - // Fixed with 0.8.1: - testCompareRangeHelper(NULL, "a", -1); - testCompareRangeHelper("a", NULL, 1); - testCompareRangeHelper(NULL, NULL, 0); + // Fixed with 0.8.1: + testCompareRangeHelper(NULL, "a", -1); + testCompareRangeHelper("a", NULL, 1); + testCompareRangeHelper(NULL, NULL, 0); - // Fixed with 0.8.3 - const bool KEEP_NULL_RANGE = false; - const bool AVOID_NULL_RANGE = true; - testCompareRangeHelper(NULL, "", -1, AVOID_NULL_RANGE); - testCompareRangeHelper(NULL, "", -1, KEEP_NULL_RANGE); - testCompareRangeHelper("", NULL, 1, AVOID_NULL_RANGE); - testCompareRangeHelper("", NULL, 1, KEEP_NULL_RANGE); + // Fixed with 0.8.3 + const bool KEEP_NULL_RANGE = false; + const bool AVOID_NULL_RANGE = true; + testCompareRangeHelper(NULL, "", -1, AVOID_NULL_RANGE); + testCompareRangeHelper(NULL, "", -1, KEEP_NULL_RANGE); + testCompareRangeHelper("", NULL, 1, AVOID_NULL_RANGE); + testCompareRangeHelper("", NULL, 1, KEEP_NULL_RANGE); } namespace { - void testRemoveBaseUriHelper(const char * expected, - const char * absSourceStr, - const char * absBaseStr) { - UriParserStateA state; - UriUriA absSource; - UriUriA absBase; - UriUriA dest; - - state.uri = &absSource; - ASSERT_TRUE(uriParseUriA(&state, absSourceStr) == URI_SUCCESS); - - state.uri = &absBase; - ASSERT_TRUE(uriParseUriA(&state, absBaseStr) == URI_SUCCESS); - - ASSERT_TRUE(uriRemoveBaseUriA(&dest, &absSource, &absBase, URI_FALSE) - == URI_SUCCESS); - - int size = 0; - ASSERT_TRUE(uriToStringCharsRequiredA(&dest, &size) == URI_SUCCESS); - char * const buffer = (char *)malloc(size + 1); - ASSERT_TRUE(buffer); - ASSERT_TRUE(uriToStringA(buffer, &dest, size + 1, &size) - == URI_SUCCESS); - if (strcmp(buffer, expected)) { - printf("Expected \"%s\" but got \"%s\"\n", expected, buffer); - ASSERT_TRUE(0); - } - free(buffer); - - uriFreeUriMembersA(&absSource); - uriFreeUriMembersA(&absBase); - uriFreeUriMembersA(&dest); - } +void testRemoveBaseUriHelper(const char * expected, const char * absSourceStr, + const char * absBaseStr) { + UriParserStateA state; + UriUriA absSource; + UriUriA absBase; + UriUriA dest; + + state.uri = &absSource; + ASSERT_EQ(uriParseUriA(&state, absSourceStr), URI_SUCCESS); + + state.uri = &absBase; + ASSERT_EQ(uriParseUriA(&state, absBaseStr), URI_SUCCESS); + + ASSERT_TRUE(uriRemoveBaseUriA(&dest, &absSource, &absBase, URI_FALSE) == URI_SUCCESS); + + int size = 0; + ASSERT_EQ(uriToStringCharsRequiredA(&dest, &size), URI_SUCCESS); + char * const buffer = (char *)malloc(size + 1); + ASSERT_TRUE(buffer); + ASSERT_TRUE(uriToStringA(buffer, &dest, size + 1, &size) == URI_SUCCESS); + EXPECT_STREQ(buffer, expected); + free(buffer); + + uriFreeUriMembersA(&absSource); + uriFreeUriMembersA(&absBase); + uriFreeUriMembersA(&dest); +} } // namespace TEST(UriSuite, TestRangeComparisonRemoveBaseUriIssue19) { - // scheme - testRemoveBaseUriHelper("scheme://host/source", - "scheme://host/source", - "schemelonger://host/base"); - testRemoveBaseUriHelper("schemelonger://host/source", - "schemelonger://host/source", - "scheme://host/base"); - - // hostText - testRemoveBaseUriHelper("//host/source", - "http://host/source", - "http://hostlonger/base"); - testRemoveBaseUriHelper("//hostlonger/source", - "http://hostlonger/source", - "http://host/base"); - - // hostData.ipFuture - testRemoveBaseUriHelper("//[v7.host]/source", - "http://[v7.host]/source", - "http://[v7.hostlonger]/base"); - testRemoveBaseUriHelper("//[v7.hostlonger]/source", - "http://[v7.hostlonger]/source", - "http://host/base"); - - // path - testRemoveBaseUriHelper("path1", - "http://host/path1", - "http://host/path111"); - testRemoveBaseUriHelper("../path1/path2", - "http://host/path1/path2", - "http://host/path111/path222"); - testRemoveBaseUriHelper("path111", - "http://host/path111", - "http://host/path1"); - testRemoveBaseUriHelper("../path111/path222", - "http://host/path111/path222", - "http://host/path1/path2"); - - // Exact issue #19 - testRemoveBaseUriHelper("//example/x/abc", - "http://example/x/abc", - "http://example2/x/y/z"); + // scheme + testRemoveBaseUriHelper("scheme://host/source", "scheme://host/source", + "schemelonger://host/base"); + testRemoveBaseUriHelper("schemelonger://host/source", "schemelonger://host/source", + "scheme://host/base"); + + // hostText + testRemoveBaseUriHelper("//host/source", "http://host/source", + "http://hostlonger/base"); + testRemoveBaseUriHelper("//hostlonger/source", "http://hostlonger/source", + "http://host/base"); + + // hostData.ipFuture + testRemoveBaseUriHelper("//[v7.host]/source", "http://[v7.host]/source", + "http://[v7.hostlonger]/base"); + testRemoveBaseUriHelper("//[v7.hostlonger]/source", "http://[v7.hostlonger]/source", + "http://host/base"); + + // path + testRemoveBaseUriHelper("path1", "http://host/path1", "http://host/path111"); + testRemoveBaseUriHelper("../path1/path2", "http://host/path1/path2", + "http://host/path111/path222"); + testRemoveBaseUriHelper("path111", "http://host/path111", "http://host/path1"); + testRemoveBaseUriHelper("../path111/path222", "http://host/path111/path222", + "http://host/path1/path2"); + + // Exact issue #19 + testRemoveBaseUriHelper("//example/x/abc", "http://example/x/abc", + "http://example2/x/y/z"); } TEST(ErrorPosSuite, TestErrorPosIPvFuture) { - UriUriA uri; - const char * errorPos; + UriUriA uri; + const char * errorPos; - const char * const uriText = "http://[vA.123456"; // missing "]" - EXPECT_EQ(uriParseSingleUriA(&uri, uriText, &errorPos), - URI_ERROR_SYNTAX); - EXPECT_EQ(errorPos, uriText + strlen(uriText)); + const char * const uriText = "http://[vA.123456"; // missing "]" + EXPECT_EQ(uriParseSingleUriA(&uri, uriText, &errorPos), URI_ERROR_SYNTAX); + EXPECT_EQ(errorPos, uriText + strlen(uriText)); } TEST(UriParseSingleSuite, Success) { - UriUriA uri; + UriUriA uri; - EXPECT_EQ(uriParseSingleUriA(&uri, "file:///home/user/song.mp3", NULL), - URI_SUCCESS); + EXPECT_EQ(uriParseSingleUriA(&uri, "file:///home/user/song.mp3", NULL), URI_SUCCESS); - uriFreeUriMembersA(&uri); + uriFreeUriMembersA(&uri); } TEST(UriParseSingleSuite, ErrorSyntaxParseErrorSetsErrorPos) { - UriUriA uri; - const char * errorPos; - const char * const uriString = "abc{}def"; + UriUriA uri; + const char * errorPos; + const char * const uriString = "abc{}def"; - EXPECT_EQ(uriParseSingleUriA(&uri, uriString, &errorPos), - URI_ERROR_SYNTAX); - EXPECT_EQ(errorPos, uriString + strlen("abc")); + EXPECT_EQ(uriParseSingleUriA(&uri, uriString, &errorPos), URI_ERROR_SYNTAX); + EXPECT_EQ(errorPos, uriString + strlen("abc")); - uriFreeUriMembersA(&uri); + uriFreeUriMembersA(&uri); } TEST(UriParseSingleSuite, ErrorNullFirstDetected) { - UriUriA uri; - const char * errorPos; + UriUriA uri; + const char * errorPos; - EXPECT_EQ(uriParseSingleUriExA(&uri, NULL, "notnull", &errorPos), - URI_ERROR_NULL); + EXPECT_EQ(uriParseSingleUriExA(&uri, NULL, "notnull", &errorPos), URI_ERROR_NULL); } TEST(UriParseSingleSuite, ErrorNullAfterLastDetected) { - UriUriA uri; + UriUriA uri; - EXPECT_EQ(uriParseSingleUriExA(&uri, "foo", NULL, NULL), URI_SUCCESS); + EXPECT_EQ(uriParseSingleUriExA(&uri, "foo", NULL, NULL), URI_SUCCESS); - uriFreeUriMembersA(&uri); + uriFreeUriMembersA(&uri); } TEST(UriParseSingleSuite, ErrorNullMemoryManagerDetected) { - UriUriA uri; - const char * errorPos; - const char * const uriString = "somethingwellformed"; + UriUriA uri; + const char * errorPos; + const char * const uriString = "somethingwellformed"; - EXPECT_EQ(uriParseSingleUriExMmA(&uri, - uriString, - uriString + strlen(uriString), - &errorPos, NULL), URI_SUCCESS); + EXPECT_EQ(uriParseSingleUriExMmA(&uri, uriString, uriString + strlen(uriString), + &errorPos, NULL), + URI_SUCCESS); - EXPECT_EQ(uriFreeUriMembersMmA(&uri, NULL), URI_SUCCESS); + EXPECT_EQ(uriFreeUriMembersMmA(&uri, NULL), URI_SUCCESS); } TEST(FreeUriMembersSuite, MultiFreeWorksFine) { - UriUriA uri; + UriUriA uri; - EXPECT_EQ(uriParseSingleUriA(&uri, "file:///home/user/song.mp3", NULL), - URI_SUCCESS); + EXPECT_EQ(uriParseSingleUriA(&uri, "file:///home/user/song.mp3", NULL), URI_SUCCESS); - UriUriA uriBackup = uri; - EXPECT_EQ(memcmp(&uriBackup, &uri, sizeof(UriUriA)), 0); + UriUriA uriBackup = uri; + EXPECT_EQ(memcmp(&uriBackup, &uri, sizeof(UriUriA)), 0); - uriFreeUriMembersA(&uri); + uriFreeUriMembersA(&uri); - // Did some pointers change (to NULL)? - EXPECT_NE(memcmp(&uriBackup, &uri, sizeof(UriUriA)), 0); + // Did some pointers change (to NULL)? + EXPECT_NE(memcmp(&uriBackup, &uri, sizeof(UriUriA)), 0); - uriFreeUriMembersA(&uri); // second time + uriFreeUriMembersA(&uri); // second time +} + +TEST(FreeUriMembersSuite, ZerosFreeWorksFine) { + UriUriA uri; + memset(&uri, 0, sizeof(uri)); + uriFreeUriMembersA(&uri); } namespace { - void testFreeUriMembersFreesHostText(const char *const uriFirst) { // issue #121 - const char *const uriAfterLast = uriFirst + strlen(uriFirst); - UriUriA uri; +void testFreeUriMembersFreesHostText(const char * const uriFirst) { // issue #121 + const char * const uriAfterLast = uriFirst + strlen(uriFirst); + UriUriA uri; - EXPECT_EQ(uriParseSingleUriA(&uri, uriFirst, NULL), URI_SUCCESS); - EXPECT_EQ(uriMakeOwnerA(&uri), URI_SUCCESS); + EXPECT_EQ(uriParseSingleUriA(&uri, uriFirst, NULL), URI_SUCCESS); + EXPECT_EQ(uriMakeOwnerA(&uri), URI_SUCCESS); - EXPECT_EQ(uri.owner, URI_TRUE); - EXPECT_TRUE(uri.hostText.first); - EXPECT_TRUE(uri.hostText.afterLast); - EXPECT_NE(uri.hostText.first, uri.hostText.afterLast); - URI_EXPECT_RANGE_OUTSIDE(uri.hostText, uriFirst, uriAfterLast); + EXPECT_EQ(uri.owner, URI_TRUE); + EXPECT_TRUE(uri.hostText.first); + EXPECT_TRUE(uri.hostText.afterLast); + EXPECT_NE(uri.hostText.first, uri.hostText.afterLast); + URI_EXPECT_RANGE_OUTSIDE(uri.hostText, uriFirst, uriAfterLast); - uriFreeUriMembersA(&uri); + uriFreeUriMembersA(&uri); - EXPECT_FALSE(uri.hostText.first); - EXPECT_FALSE(uri.hostText.afterLast); + EXPECT_FALSE(uri.hostText.first); + EXPECT_FALSE(uri.hostText.afterLast); - uriFreeUriMembersA(&uri); // second time - } + uriFreeUriMembersA(&uri); // second time +} } // namespace TEST(FreeUriMembersSuite, FreeUriMembersFreesHostTextIp4) { // issue #121 - testFreeUriMembersFreesHostText("//192.0.2.0"); // RFC 5737 + testFreeUriMembersFreesHostText("//192.0.2.0"); // RFC 5737 } TEST(FreeUriMembersSuite, FreeUriMembersFreesHostTextIp6) { // issue #121 - testFreeUriMembersFreesHostText("//[2001:db8::]"); // RFC 3849 + testFreeUriMembersFreesHostText("//[2001:db8::]"); // RFC 3849 } TEST(FreeUriMembersSuite, FreeUriMembersFreesHostTextRegname) { // issue #121 - testFreeUriMembersFreesHostText("//host123.test"); // RFC 6761 + testFreeUriMembersFreesHostText("//host123.test"); // RFC 6761 } TEST(FreeUriMembersSuite, FreeUriMembersFreesHostTextFuture) { // issue #121 - testFreeUriMembersFreesHostText("//[v7.X]"); // arbitrary IPvFuture + testFreeUriMembersFreesHostText("//[v7.X]"); // arbitrary IPvFuture } TEST(MakeOwnerSuite, MakeOwner) { - const char * const uriString = "scheme://user:pass@[v7.X]:55555/path/../path/?query#fragment"; - UriUriA uri; - char * uriFirst = strdup(uriString); - const size_t uriLen = strlen(uriFirst); - char * uriAfterLast = uriFirst + uriLen; - - EXPECT_EQ(uriParseSingleUriExA(&uri, uriFirst, uriAfterLast, NULL), URI_SUCCESS); - - // After plain parse, all strings should point inside the original URI string - EXPECT_EQ(uri.owner, URI_FALSE); - URI_EXPECT_RANGE_BETWEEN(uri.scheme, uriFirst, uriAfterLast); - URI_EXPECT_RANGE_BETWEEN(uri.userInfo, uriFirst, uriAfterLast); - URI_EXPECT_RANGE_BETWEEN(uri.hostText, uriFirst, uriAfterLast); - URI_EXPECT_RANGE_BETWEEN(uri.hostData.ipFuture, uriFirst, uriAfterLast); - URI_EXPECT_RANGE_BETWEEN(uri.portText, uriFirst, uriAfterLast); - URI_EXPECT_RANGE_BETWEEN(uri.pathHead->text, uriFirst, uriAfterLast); - URI_EXPECT_RANGE_BETWEEN(uri.pathHead->next->text, uriFirst, uriAfterLast); - URI_EXPECT_RANGE_BETWEEN(uri.pathHead->next->next->text, uriFirst, uriAfterLast); - URI_EXPECT_RANGE_EMPTY(uri.pathHead->next->next->next->text); - EXPECT_TRUE(uri.pathHead->next->next->next->next == NULL); - URI_EXPECT_RANGE_BETWEEN(uri.query, uriFirst, uriAfterLast); - URI_EXPECT_RANGE_BETWEEN(uri.fragment, uriFirst, uriAfterLast); - - EXPECT_EQ(uriMakeOwnerA(&uri), URI_SUCCESS); - - // After making owner, *none* of the strings should point inside the original URI string - EXPECT_EQ(uri.owner, URI_TRUE); - URI_EXPECT_RANGE_OUTSIDE(uri.scheme, uriFirst, uriAfterLast); - URI_EXPECT_RANGE_OUTSIDE(uri.userInfo, uriFirst, uriAfterLast); - URI_EXPECT_RANGE_OUTSIDE(uri.hostText, uriFirst, uriAfterLast); - URI_EXPECT_RANGE_OUTSIDE(uri.hostData.ipFuture, uriFirst, uriAfterLast); - URI_EXPECT_RANGE_OUTSIDE(uri.portText, uriFirst, uriAfterLast); - URI_EXPECT_RANGE_OUTSIDE(uri.pathHead->text, uriFirst, uriAfterLast); - URI_EXPECT_RANGE_OUTSIDE(uri.pathHead->next->text, uriFirst, uriAfterLast); - URI_EXPECT_RANGE_OUTSIDE(uri.pathHead->next->next->text, uriFirst, uriAfterLast); - URI_EXPECT_RANGE_EMPTY(uri.pathHead->next->next->next->text); - EXPECT_TRUE(uri.pathHead->next->next->next->next == NULL); - URI_EXPECT_RANGE_OUTSIDE(uri.query, uriFirst, uriAfterLast); - URI_EXPECT_RANGE_OUTSIDE(uri.fragment, uriFirst, uriAfterLast); - - // Free originally used memory so we'd get violations on access with ASan - uriAfterLast = NULL; - free(uriFirst); - uriFirst = NULL; - - // Can we recompose the URI without accessing any old freed memory? - int charsRequired; - EXPECT_EQ(uriToStringCharsRequiredA(&uri, &charsRequired), URI_SUCCESS); - EXPECT_TRUE((charsRequired >= 0) && (charsRequired >= static_cast<int>(uriLen))); - char * const uriRemake = new char[charsRequired + 1]; - EXPECT_TRUE(uriRemake != NULL); - EXPECT_EQ(uriToStringA(uriRemake, &uri, charsRequired + 1, NULL), URI_SUCCESS); - EXPECT_TRUE(! strcmp(uriString, uriRemake)); - delete [] uriRemake; - - uriFreeUriMembersA(&uri); + const char * const uriString = + "scheme://user:pass@[v7.X]:55555/path/../path/?query#fragment"; + UriUriA uri; + char * uriFirst = strdup(uriString); + const size_t uriLen = strlen(uriFirst); + char * uriAfterLast = uriFirst + uriLen; + + EXPECT_EQ(uriParseSingleUriExA(&uri, uriFirst, uriAfterLast, NULL), URI_SUCCESS); + + // After plain parse, all strings should point inside the original URI string + EXPECT_EQ(uri.owner, URI_FALSE); + URI_EXPECT_RANGE_BETWEEN(uri.scheme, uriFirst, uriAfterLast); + URI_EXPECT_RANGE_BETWEEN(uri.userInfo, uriFirst, uriAfterLast); + URI_EXPECT_RANGE_BETWEEN(uri.hostText, uriFirst, uriAfterLast); + URI_EXPECT_RANGE_BETWEEN(uri.hostData.ipFuture, uriFirst, uriAfterLast); + URI_EXPECT_RANGE_BETWEEN(uri.portText, uriFirst, uriAfterLast); + URI_EXPECT_RANGE_BETWEEN(uri.pathHead->text, uriFirst, uriAfterLast); + URI_EXPECT_RANGE_BETWEEN(uri.pathHead->next->text, uriFirst, uriAfterLast); + URI_EXPECT_RANGE_BETWEEN(uri.pathHead->next->next->text, uriFirst, uriAfterLast); + URI_EXPECT_RANGE_EMPTY(uri.pathHead->next->next->next->text); + EXPECT_TRUE(uri.pathHead->next->next->next->next == NULL); + URI_EXPECT_RANGE_BETWEEN(uri.query, uriFirst, uriAfterLast); + URI_EXPECT_RANGE_BETWEEN(uri.fragment, uriFirst, uriAfterLast); + + EXPECT_EQ(uriMakeOwnerA(&uri), URI_SUCCESS); + + // After making owner, *none* of the strings should point inside the original URI + // string + EXPECT_EQ(uri.owner, URI_TRUE); + URI_EXPECT_RANGE_OUTSIDE(uri.scheme, uriFirst, uriAfterLast); + URI_EXPECT_RANGE_OUTSIDE(uri.userInfo, uriFirst, uriAfterLast); + URI_EXPECT_RANGE_OUTSIDE(uri.hostText, uriFirst, uriAfterLast); + URI_EXPECT_RANGE_OUTSIDE(uri.hostData.ipFuture, uriFirst, uriAfterLast); + URI_EXPECT_RANGE_OUTSIDE(uri.portText, uriFirst, uriAfterLast); + URI_EXPECT_RANGE_OUTSIDE(uri.pathHead->text, uriFirst, uriAfterLast); + URI_EXPECT_RANGE_OUTSIDE(uri.pathHead->next->text, uriFirst, uriAfterLast); + URI_EXPECT_RANGE_OUTSIDE(uri.pathHead->next->next->text, uriFirst, uriAfterLast); + URI_EXPECT_RANGE_EMPTY(uri.pathHead->next->next->next->text); + EXPECT_TRUE(uri.pathHead->next->next->next->next == NULL); + URI_EXPECT_RANGE_OUTSIDE(uri.query, uriFirst, uriAfterLast); + URI_EXPECT_RANGE_OUTSIDE(uri.fragment, uriFirst, uriAfterLast); + + // Free originally used memory so we'd get violations on access with ASan + uriAfterLast = NULL; + free(uriFirst); + uriFirst = NULL; + + // Can we recompose the URI without accessing any old freed memory? + int charsRequired; + EXPECT_EQ(uriToStringCharsRequiredA(&uri, &charsRequired), URI_SUCCESS); + EXPECT_TRUE((charsRequired >= 0) && (charsRequired >= static_cast<int>(uriLen))); + char * const uriRemake = new char[charsRequired + 1]; + EXPECT_TRUE(uriRemake != NULL); + EXPECT_EQ(uriToStringA(uriRemake, &uri, charsRequired + 1, NULL), URI_SUCCESS); + EXPECT_STREQ(uriString, uriRemake); + delete[] uriRemake; + + uriFreeUriMembersA(&uri); } namespace { - void testMakeOwnerCopiesHostText(const char *const uriFirst) { // issue #121 - const char *const uriAfterLast = uriFirst + strlen(uriFirst); - UriUriA uri; +void testMakeOwnerCopiesHostText(const char * const uriFirst) { // issue #121 + const char * const uriAfterLast = uriFirst + strlen(uriFirst); + UriUriA uri; - EXPECT_EQ(uriParseSingleUriA(&uri, uriFirst, NULL), URI_SUCCESS); - EXPECT_EQ(uri.owner, URI_FALSE); - URI_EXPECT_RANGE_BETWEEN(uri.hostText, uriFirst, uriAfterLast); + EXPECT_EQ(uriParseSingleUriA(&uri, uriFirst, NULL), URI_SUCCESS); + EXPECT_EQ(uri.owner, URI_FALSE); + URI_EXPECT_RANGE_BETWEEN(uri.hostText, uriFirst, uriAfterLast); - EXPECT_EQ(uriMakeOwnerA(&uri), URI_SUCCESS); + EXPECT_EQ(uriMakeOwnerA(&uri), URI_SUCCESS); - EXPECT_EQ(uri.owner, URI_TRUE); - URI_EXPECT_RANGE_OUTSIDE(uri.hostText, uriFirst, uriAfterLast); + EXPECT_EQ(uri.owner, URI_TRUE); + URI_EXPECT_RANGE_OUTSIDE(uri.hostText, uriFirst, uriAfterLast); - uriFreeUriMembersA(&uri); - uriFreeUriMembersA(&uri); // tried freeing stack pointers before the fix - } -} // namespace + uriFreeUriMembersA(&uri); + uriFreeUriMembersA(&uri); // tried freeing stack pointers before the fix +} +} // namespace TEST(MakeOwnerSuite, MakeOwnerCopiesHostTextIp4) { // issue #121 - testMakeOwnerCopiesHostText("//192.0.2.0"); // RFC 5737 + testMakeOwnerCopiesHostText("//192.0.2.0"); // RFC 5737 } TEST(MakeOwnerSuite, MakeOwnerCopiesHostTextIp6) { // issue #121 - testMakeOwnerCopiesHostText("//[2001:db8::]"); // RFC 3849 + testMakeOwnerCopiesHostText("//[2001:db8::]"); // RFC 3849 } TEST(MakeOwnerSuite, MakeOwnerCopiesHostTextRegname) { // issue #121 - testMakeOwnerCopiesHostText("//host123.test"); // RFC 6761 + testMakeOwnerCopiesHostText("//host123.test"); // RFC 6761 } TEST(MakeOwnerSuite, MakeOwnerCopiesHostTextFuture) { // issue #121 - testMakeOwnerCopiesHostText("//[v7.X]"); // arbitrary IPvFuture + testMakeOwnerCopiesHostText("//[v7.X]"); // arbitrary IPvFuture } TEST(ParseIpFourAddressSuite, FourSaneOctets) { - unsigned char octetOutput[4]; - const char * const ipAddressText = "111.22.3.40"; - const int res = uriParseIpFourAddressA(octetOutput, ipAddressText, - ipAddressText + strlen(ipAddressText)); - EXPECT_EQ(res, URI_SUCCESS); - EXPECT_EQ(octetOutput[0], 111); - EXPECT_EQ(octetOutput[1], 22); - EXPECT_EQ(octetOutput[2], 3); - EXPECT_EQ(octetOutput[3], 40); + unsigned char octetOutput[4]; + const char * const ipAddressText = "111.22.3.40"; + const int res = uriParseIpFourAddressA(octetOutput, ipAddressText, + ipAddressText + strlen(ipAddressText)); + EXPECT_EQ(res, URI_SUCCESS); + EXPECT_EQ(octetOutput[0], 111); + EXPECT_EQ(octetOutput[1], 22); + EXPECT_EQ(octetOutput[2], 3); + EXPECT_EQ(octetOutput[3], 40); } +TEST(UriSuite, NoStackOverflowIssue282) { + const size_t sizeBytes = 2 * 1024 * 1024; + + char * const uriString = new char[sizeBytes]; + ASSERT_TRUE(uriString != NULL); + ::memset(uriString, 'x', sizeBytes - 1); + uriString[sizeBytes - 1] = '\0'; + + UriUriA uri; + ASSERT_EQ(uriParseSingleUriA(&uri, uriString, NULL), URI_SUCCESS); + + uriFreeUriMembersA(&uri); + delete[] uriString; +} int main(int argc, char ** argv) { - ::testing::InitGoogleTest(&argc, argv); - return RUN_ALL_TESTS(); + ::testing::InitGoogleTest(&argc, argv); + return RUN_ALL_TESTS(); } |
