From 886e5076c8e81fd0cdfe82dbf4a80d19e778d594 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?J=C3=B6rg=20Frings-F=C3=BCrst?= Date: Wed, 6 Aug 2014 18:24:22 +0200 Subject: Imported Upstream version 0.8.0.1 --- test/FourSuite.cpp | 623 +++++++++++++++++++ test/FourSuite.h | 70 +++ test/test.cpp | 1751 ++++++++++++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 2444 insertions(+) create mode 100644 test/FourSuite.cpp create mode 100644 test/FourSuite.h create mode 100644 test/test.cpp (limited to 'test') diff --git a/test/FourSuite.cpp b/test/FourSuite.cpp new file mode 100644 index 0000000..706ee56 --- /dev/null +++ b/test/FourSuite.cpp @@ -0,0 +1,623 @@ +/* + * uriparser - RFC 3986 URI parsing library + * + * Copyright (C) 2007, Weijia Song + * Copyright (C) 2007, Sebastian Pipping + * + * 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 "FourSuite.h" + +#include + + + +// All testcases in this file are coming from +// http://cvs.4suite.org/viewcvs/4Suite/test/Lib/test_uri.py + + + +bool FourSuite::testAddOrRemoveBaseHelper(const char * ref, const char * base, + const char * expected, bool add, bool domainRootMode) { + 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; +} + + + +void FourSuite::absolutize_test_cases() { + 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 + TEST_ASSERT(testAddOrRemoveBaseHelper("../c", "foo:a/b", "foo:c")); + TEST_ASSERT(testAddOrRemoveBaseHelper("foo:.", "foo:a", "foo:")); + TEST_ASSERT(testAddOrRemoveBaseHelper("/foo/../../../bar", "zz:abc", "zz:/bar")); + TEST_ASSERT(testAddOrRemoveBaseHelper("/foo/../bar", "zz:abc", "zz:/bar")); + TEST_ASSERT(testAddOrRemoveBaseHelper("foo/../../../bar", "zz:abc", "zz:bar")); + TEST_ASSERT(testAddOrRemoveBaseHelper("foo/../bar", "zz:abc", "zz:bar")); + TEST_ASSERT(testAddOrRemoveBaseHelper("zz:.", "zz:abc", "zz:")); + TEST_ASSERT(testAddOrRemoveBaseHelper("/.", BASE_URI[0], "http://a/")); + TEST_ASSERT(testAddOrRemoveBaseHelper("/.foo", BASE_URI[0], "http://a/.foo")); + TEST_ASSERT(testAddOrRemoveBaseHelper(".foo", BASE_URI[0], "http://a/b/c/.foo")); + + // http://gbiv.com/protocols/uri/test/rel_examples1.html + // examples from RFC 2396 + TEST_ASSERT(testAddOrRemoveBaseHelper("g:h", BASE_URI[0], "g:h")); + TEST_ASSERT(testAddOrRemoveBaseHelper("g", BASE_URI[0], "http://a/b/c/g")); + TEST_ASSERT(testAddOrRemoveBaseHelper("./g", BASE_URI[0], "http://a/b/c/g")); + TEST_ASSERT(testAddOrRemoveBaseHelper("g/", BASE_URI[0], "http://a/b/c/g/")); + TEST_ASSERT(testAddOrRemoveBaseHelper("/g", BASE_URI[0], "http://a/g")); + TEST_ASSERT(testAddOrRemoveBaseHelper("//g", BASE_URI[0], "http://g")); + + // changed with RFC 2396bis + TEST_ASSERT(testAddOrRemoveBaseHelper("?y", BASE_URI[0], "http://a/b/c/d;p?y")); + TEST_ASSERT(testAddOrRemoveBaseHelper("g?y", BASE_URI[0], "http://a/b/c/g?y")); + + // changed with RFC 2396bis + TEST_ASSERT(testAddOrRemoveBaseHelper("#s", BASE_URI[0], "http://a/b/c/d;p?q#s")); + TEST_ASSERT(testAddOrRemoveBaseHelper("g#s", BASE_URI[0], "http://a/b/c/g#s")); + TEST_ASSERT(testAddOrRemoveBaseHelper("g?y#s", BASE_URI[0], "http://a/b/c/g?y#s")); + TEST_ASSERT(testAddOrRemoveBaseHelper(";x", BASE_URI[0], "http://a/b/c/;x")); + TEST_ASSERT(testAddOrRemoveBaseHelper("g;x", BASE_URI[0], "http://a/b/c/g;x")); + TEST_ASSERT(testAddOrRemoveBaseHelper("g;x?y#s", BASE_URI[0], "http://a/b/c/g;x?y#s")); + + // changed with RFC 2396bis + TEST_ASSERT(testAddOrRemoveBaseHelper("", BASE_URI[0], "http://a/b/c/d;p?q")); + TEST_ASSERT(testAddOrRemoveBaseHelper(".", BASE_URI[0], "http://a/b/c/")); + TEST_ASSERT(testAddOrRemoveBaseHelper("./", BASE_URI[0], "http://a/b/c/")); + TEST_ASSERT(testAddOrRemoveBaseHelper("..", BASE_URI[0], "http://a/b/")); + TEST_ASSERT(testAddOrRemoveBaseHelper("../", BASE_URI[0], "http://a/b/")); + TEST_ASSERT(testAddOrRemoveBaseHelper("../g", BASE_URI[0], "http://a/b/g")); + TEST_ASSERT(testAddOrRemoveBaseHelper("../..", BASE_URI[0], "http://a/")); + TEST_ASSERT(testAddOrRemoveBaseHelper("../../", BASE_URI[0], "http://a/")); + TEST_ASSERT(testAddOrRemoveBaseHelper("../../g", BASE_URI[0], "http://a/g")); + TEST_ASSERT(testAddOrRemoveBaseHelper("../../../g", BASE_URI[0], "http://a/g")); // http://a/../g + TEST_ASSERT(testAddOrRemoveBaseHelper("../../../../g", BASE_URI[0], "http://a/g")); // http://a/../../g + + // changed with RFC 2396bis + TEST_ASSERT(testAddOrRemoveBaseHelper("/./g", BASE_URI[0], "http://a/g")); + + // changed with RFC 2396bis + TEST_ASSERT(testAddOrRemoveBaseHelper("/../g", BASE_URI[0], "http://a/g")); + TEST_ASSERT(testAddOrRemoveBaseHelper("g.", BASE_URI[0], "http://a/b/c/g.")); + TEST_ASSERT(testAddOrRemoveBaseHelper(".g", BASE_URI[0], "http://a/b/c/.g")); + TEST_ASSERT(testAddOrRemoveBaseHelper("g..", BASE_URI[0], "http://a/b/c/g..")); + TEST_ASSERT(testAddOrRemoveBaseHelper("..g", BASE_URI[0], "http://a/b/c/..g")); + TEST_ASSERT(testAddOrRemoveBaseHelper("./../g", BASE_URI[0], "http://a/b/g")); + TEST_ASSERT(testAddOrRemoveBaseHelper("./g/.", BASE_URI[0], "http://a/b/c/g/")); + TEST_ASSERT(testAddOrRemoveBaseHelper("g/./h", BASE_URI[0], "http://a/b/c/g/h")); + TEST_ASSERT(testAddOrRemoveBaseHelper("g/../h", BASE_URI[0], "http://a/b/c/h")); + TEST_ASSERT(testAddOrRemoveBaseHelper("g;x=1/./y", BASE_URI[0], "http://a/b/c/g;x=1/y")); + TEST_ASSERT(testAddOrRemoveBaseHelper("g;x=1/../y", BASE_URI[0], "http://a/b/c/y")); + TEST_ASSERT(testAddOrRemoveBaseHelper("g?y/./x", BASE_URI[0], "http://a/b/c/g?y/./x")); + TEST_ASSERT(testAddOrRemoveBaseHelper("g?y/../x", BASE_URI[0], "http://a/b/c/g?y/../x")); + TEST_ASSERT(testAddOrRemoveBaseHelper("g#s/./x", BASE_URI[0], "http://a/b/c/g#s/./x")); + TEST_ASSERT(testAddOrRemoveBaseHelper("g#s/../x", BASE_URI[0], "http://a/b/c/g#s/../x")); + TEST_ASSERT(testAddOrRemoveBaseHelper("http:g", BASE_URI[0], "http:g")); // http://a/b/c/g + TEST_ASSERT(testAddOrRemoveBaseHelper("http:", BASE_URI[0], "http:")); // BASE_URI[0] + + // not sure where this one originated + TEST_ASSERT(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 + TEST_ASSERT(testAddOrRemoveBaseHelper("g", BASE_URI[1], "http://a/b/c/g")); + TEST_ASSERT(testAddOrRemoveBaseHelper("./g", BASE_URI[1], "http://a/b/c/g")); + TEST_ASSERT(testAddOrRemoveBaseHelper("g/", BASE_URI[1], "http://a/b/c/g/")); + TEST_ASSERT(testAddOrRemoveBaseHelper("/g", BASE_URI[1], "http://a/g")); + TEST_ASSERT(testAddOrRemoveBaseHelper("//g", BASE_URI[1], "http://g")); + + // changed in RFC 2396bis + // TEST_ASSERT(testAddOrRemoveBaseHelper("?y", BASE_URI[1], "http://a/b/c/?y")); + TEST_ASSERT(testAddOrRemoveBaseHelper("?y", BASE_URI[1], "http://a/b/c/d;p?y")); + TEST_ASSERT(testAddOrRemoveBaseHelper("g?y", BASE_URI[1], "http://a/b/c/g?y")); + TEST_ASSERT(testAddOrRemoveBaseHelper("g?y/./x", BASE_URI[1], "http://a/b/c/g?y/./x")); + TEST_ASSERT(testAddOrRemoveBaseHelper("g?y/../x", BASE_URI[1], "http://a/b/c/g?y/../x")); + TEST_ASSERT(testAddOrRemoveBaseHelper("g#s", BASE_URI[1], "http://a/b/c/g#s")); + TEST_ASSERT(testAddOrRemoveBaseHelper("g#s/./x", BASE_URI[1], "http://a/b/c/g#s/./x")); + TEST_ASSERT(testAddOrRemoveBaseHelper("g#s/../x", BASE_URI[1], "http://a/b/c/g#s/../x")); + TEST_ASSERT(testAddOrRemoveBaseHelper("./", BASE_URI[1], "http://a/b/c/")); + TEST_ASSERT(testAddOrRemoveBaseHelper("../", BASE_URI[1], "http://a/b/")); + TEST_ASSERT(testAddOrRemoveBaseHelper("../g", BASE_URI[1], "http://a/b/g")); + TEST_ASSERT(testAddOrRemoveBaseHelper("../../", BASE_URI[1], "http://a/")); + TEST_ASSERT(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 + TEST_ASSERT(testAddOrRemoveBaseHelper("g", BASE_URI[2], "http://a/b/c/d;p=1/g")); + TEST_ASSERT(testAddOrRemoveBaseHelper("./g", BASE_URI[2], "http://a/b/c/d;p=1/g")); + TEST_ASSERT(testAddOrRemoveBaseHelper("g/", BASE_URI[2], "http://a/b/c/d;p=1/g/")); + TEST_ASSERT(testAddOrRemoveBaseHelper("g?y", BASE_URI[2], "http://a/b/c/d;p=1/g?y")); + TEST_ASSERT(testAddOrRemoveBaseHelper(";x", BASE_URI[2], "http://a/b/c/d;p=1/;x")); + TEST_ASSERT(testAddOrRemoveBaseHelper("g;x", BASE_URI[2], "http://a/b/c/d;p=1/g;x")); + TEST_ASSERT(testAddOrRemoveBaseHelper("g;x=1/./y", BASE_URI[2], "http://a/b/c/d;p=1/g;x=1/y")); + TEST_ASSERT(testAddOrRemoveBaseHelper("g;x=1/../y", BASE_URI[2], "http://a/b/c/d;p=1/y")); + TEST_ASSERT(testAddOrRemoveBaseHelper("./", BASE_URI[2], "http://a/b/c/d;p=1/")); + TEST_ASSERT(testAddOrRemoveBaseHelper("../", BASE_URI[2], "http://a/b/c/")); + TEST_ASSERT(testAddOrRemoveBaseHelper("../g", BASE_URI[2], "http://a/b/c/g")); + TEST_ASSERT(testAddOrRemoveBaseHelper("../../", BASE_URI[2], "http://a/b/")); + TEST_ASSERT(testAddOrRemoveBaseHelper("../../g", BASE_URI[2], "http://a/b/g")); + + // http://gbiv.com/protocols/uri/test/rel_examples4.html + // double and triple slash, unknown scheme + TEST_ASSERT(testAddOrRemoveBaseHelper("g:h", BASE_URI[3], "g:h")); + TEST_ASSERT(testAddOrRemoveBaseHelper("g", BASE_URI[3], "fred:///s//a/b/g")); + TEST_ASSERT(testAddOrRemoveBaseHelper("./g", BASE_URI[3], "fred:///s//a/b/g")); + TEST_ASSERT(testAddOrRemoveBaseHelper("g/", BASE_URI[3], "fred:///s//a/b/g/")); + TEST_ASSERT(testAddOrRemoveBaseHelper("/g", BASE_URI[3], "fred:///g")); // may change to fred:///s//a/g + TEST_ASSERT(testAddOrRemoveBaseHelper("//g", BASE_URI[3], "fred://g")); // may change to fred:///s//g + TEST_ASSERT(testAddOrRemoveBaseHelper("//g/x", BASE_URI[3], "fred://g/x")); // may change to fred:///s//g/x + TEST_ASSERT(testAddOrRemoveBaseHelper("///g", BASE_URI[3], "fred:///g")); + TEST_ASSERT(testAddOrRemoveBaseHelper("./", BASE_URI[3], "fred:///s//a/b/")); + TEST_ASSERT(testAddOrRemoveBaseHelper("../", BASE_URI[3], "fred:///s//a/")); + TEST_ASSERT(testAddOrRemoveBaseHelper("../g", BASE_URI[3], "fred:///s//a/g")); + TEST_ASSERT(testAddOrRemoveBaseHelper("../../", BASE_URI[3], "fred:///s//")); // may change to fred:///s//a/../ + TEST_ASSERT(testAddOrRemoveBaseHelper("../../g", BASE_URI[3], "fred:///s//g")); // may change to fred:///s//a/../g + TEST_ASSERT(testAddOrRemoveBaseHelper("../../../g", BASE_URI[3], "fred:///s/g")); // may change to fred:///s//a/../../g + TEST_ASSERT(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 + TEST_ASSERT(testAddOrRemoveBaseHelper("g:h", BASE_URI[4], "g:h")); + TEST_ASSERT(testAddOrRemoveBaseHelper("g", BASE_URI[4], "http:///s//a/b/g")); + TEST_ASSERT(testAddOrRemoveBaseHelper("./g", BASE_URI[4], "http:///s//a/b/g")); + TEST_ASSERT(testAddOrRemoveBaseHelper("g/", BASE_URI[4], "http:///s//a/b/g/")); + TEST_ASSERT(testAddOrRemoveBaseHelper("/g", BASE_URI[4], "http:///g")); // may change to http:///s//a/g + TEST_ASSERT(testAddOrRemoveBaseHelper("//g", BASE_URI[4], "http://g")); // may change to http:///s//g + TEST_ASSERT(testAddOrRemoveBaseHelper("//g/x", BASE_URI[4], "http://g/x")); // may change to http:///s//g/x + TEST_ASSERT(testAddOrRemoveBaseHelper("///g", BASE_URI[4], "http:///g")); + TEST_ASSERT(testAddOrRemoveBaseHelper("./", BASE_URI[4], "http:///s//a/b/")); + TEST_ASSERT(testAddOrRemoveBaseHelper("../", BASE_URI[4], "http:///s//a/")); + TEST_ASSERT(testAddOrRemoveBaseHelper("../g", BASE_URI[4], "http:///s//a/g")); + TEST_ASSERT(testAddOrRemoveBaseHelper("../../", BASE_URI[4], "http:///s//")); // may change to http:///s//a/../ + TEST_ASSERT(testAddOrRemoveBaseHelper("../../g", BASE_URI[4], "http:///s//g")); // may change to http:///s//a/../g + TEST_ASSERT(testAddOrRemoveBaseHelper("../../../g", BASE_URI[4], "http:///s/g")); // may change to http:///s//a/../../g + TEST_ASSERT(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 + TEST_ASSERT(testAddOrRemoveBaseHelper("bar:abc", "foo:xyz", "bar:abc")); + TEST_ASSERT(testAddOrRemoveBaseHelper("../abc", "http://example/x/y/z", "http://example/x/abc")); + TEST_ASSERT(testAddOrRemoveBaseHelper("http://example/x/abc", "http://example2/x/y/z", "http://example/x/abc")); + TEST_ASSERT(testAddOrRemoveBaseHelper("../r", "http://ex/x/y/z", "http://ex/x/r")); + TEST_ASSERT(testAddOrRemoveBaseHelper("q/r", "http://ex/x/y", "http://ex/x/q/r")); + TEST_ASSERT(testAddOrRemoveBaseHelper("q/r#s", "http://ex/x/y", "http://ex/x/q/r#s")); + TEST_ASSERT(testAddOrRemoveBaseHelper("q/r#s/t", "http://ex/x/y", "http://ex/x/q/r#s/t")); + TEST_ASSERT(testAddOrRemoveBaseHelper("ftp://ex/x/q/r", "http://ex/x/y", "ftp://ex/x/q/r")); + TEST_ASSERT(testAddOrRemoveBaseHelper("", "http://ex/x/y", "http://ex/x/y")); + TEST_ASSERT(testAddOrRemoveBaseHelper("", "http://ex/x/y/", "http://ex/x/y/")); + TEST_ASSERT(testAddOrRemoveBaseHelper("", "http://ex/x/y/pdq", "http://ex/x/y/pdq")); + TEST_ASSERT(testAddOrRemoveBaseHelper("z/", "http://ex/x/y/", "http://ex/x/y/z/")); + TEST_ASSERT(testAddOrRemoveBaseHelper("#Animal", "file:/swap/test/animal.rdf", "file:/swap/test/animal.rdf#Animal")); + TEST_ASSERT(testAddOrRemoveBaseHelper("../abc", "file:/e/x/y/z", "file:/e/x/abc")); + TEST_ASSERT(testAddOrRemoveBaseHelper("/example/x/abc", "file:/example2/x/y/z", "file:/example/x/abc")); + TEST_ASSERT(testAddOrRemoveBaseHelper("../r", "file:/ex/x/y/z", "file:/ex/x/r")); + TEST_ASSERT(testAddOrRemoveBaseHelper("/r", "file:/ex/x/y/z", "file:/r")); + TEST_ASSERT(testAddOrRemoveBaseHelper("q/r", "file:/ex/x/y", "file:/ex/x/q/r")); + TEST_ASSERT(testAddOrRemoveBaseHelper("q/r#s", "file:/ex/x/y", "file:/ex/x/q/r#s")); + TEST_ASSERT(testAddOrRemoveBaseHelper("q/r#", "file:/ex/x/y", "file:/ex/x/q/r#")); + TEST_ASSERT(testAddOrRemoveBaseHelper("q/r#s/t", "file:/ex/x/y", "file:/ex/x/q/r#s/t")); + TEST_ASSERT(testAddOrRemoveBaseHelper("ftp://ex/x/q/r", "file:/ex/x/y", "ftp://ex/x/q/r")); + TEST_ASSERT(testAddOrRemoveBaseHelper("", "file:/ex/x/y", "file:/ex/x/y")); + TEST_ASSERT(testAddOrRemoveBaseHelper("", "file:/ex/x/y/", "file:/ex/x/y/")); + TEST_ASSERT(testAddOrRemoveBaseHelper("", "file:/ex/x/y/pdq", "file:/ex/x/y/pdq")); + TEST_ASSERT(testAddOrRemoveBaseHelper("z/", "file:/ex/x/y/", "file:/ex/x/y/z/")); + TEST_ASSERT(testAddOrRemoveBaseHelper("file://meetings.example.com/cal#m1", "file:/devel/WWW/2000/10/swap/test/reluri-1.n3", "file://meetings.example.com/cal#m1")); + TEST_ASSERT(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")); + TEST_ASSERT(testAddOrRemoveBaseHelper("./#blort", "file:/some/dir/foo", "file:/some/dir/#blort")); + TEST_ASSERT(testAddOrRemoveBaseHelper("./#", "file:/some/dir/foo", "file:/some/dir/#")); + + // Ryan Lee + TEST_ASSERT(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 + TEST_ASSERT(testAddOrRemoveBaseHelper("./q:r", "http://ex/x/y", "http://ex/x/q:r")); + TEST_ASSERT(testAddOrRemoveBaseHelper("./p=q:r", "http://ex/x/y", "http://ex/x/p=q:r")); + TEST_ASSERT(testAddOrRemoveBaseHelper("?pp/rr", "http://ex/x/y?pp/qq", "http://ex/x/y?pp/rr")); + TEST_ASSERT(testAddOrRemoveBaseHelper("y/z", "http://ex/x/y?pp/qq", "http://ex/x/y/z")); + TEST_ASSERT(testAddOrRemoveBaseHelper("local/qual@domain.org#frag", "mailto:local", "mailto:local/qual@domain.org#frag")); + TEST_ASSERT(testAddOrRemoveBaseHelper("more/qual2@domain2.org#frag", "mailto:local/qual1@domain1.org", "mailto:local/more/qual2@domain2.org#frag")); + TEST_ASSERT(testAddOrRemoveBaseHelper("y?q", "http://ex/x/y?q", "http://ex/x/y?q")); + TEST_ASSERT(testAddOrRemoveBaseHelper("/x/y?q", "http://ex?p", "http://ex/x/y?q")); + TEST_ASSERT(testAddOrRemoveBaseHelper("c/d", "foo:a/b", "foo:a/c/d")); + TEST_ASSERT(testAddOrRemoveBaseHelper("/c/d", "foo:a/b", "foo:/c/d")); + TEST_ASSERT(testAddOrRemoveBaseHelper("", "foo:a/b?c#d", "foo:a/b?c")); + TEST_ASSERT(testAddOrRemoveBaseHelper("b/c", "foo:a", "foo:b/c")); + TEST_ASSERT(testAddOrRemoveBaseHelper("../b/c", "foo:/a/y/z", "foo:/a/b/c")); + TEST_ASSERT(testAddOrRemoveBaseHelper("./b/c", "foo:a", "foo:b/c")); + TEST_ASSERT(testAddOrRemoveBaseHelper("/./b/c", "foo:a", "foo:/b/c")); + TEST_ASSERT(testAddOrRemoveBaseHelper("../../d", "foo://a//b/c", "foo://a/d")); + TEST_ASSERT(testAddOrRemoveBaseHelper(".", "foo:a", "foo:")); + TEST_ASSERT(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) + TEST_ASSERT(testAddOrRemoveBaseHelper("abc", "http://example/x/y%2Fz", "http://example/x/abc")); + TEST_ASSERT(testAddOrRemoveBaseHelper("../../x%2Fabc", "http://example/a/x/y/z", "http://example/a/x%2Fabc")); + TEST_ASSERT(testAddOrRemoveBaseHelper("../x%2Fabc", "http://example/a/x/y%2Fz", "http://example/a/x%2Fabc")); + TEST_ASSERT(testAddOrRemoveBaseHelper("abc", "http://example/x%2Fy/z", "http://example/x%2Fy/abc")); + TEST_ASSERT(testAddOrRemoveBaseHelper("q%3Ar", "http://ex/x/y", "http://ex/x/q%3Ar")); + TEST_ASSERT(testAddOrRemoveBaseHelper("/x%2Fabc", "http://example/x/y%2Fz", "http://example/x%2Fabc")); + TEST_ASSERT(testAddOrRemoveBaseHelper("/x%2Fabc", "http://example/x/y/z", "http://example/x%2Fabc")); + TEST_ASSERT(testAddOrRemoveBaseHelper("/x%2Fabc", "http://example/x/y%2Fz", "http://example/x%2Fabc")); + + // 70-77 + TEST_ASSERT(testAddOrRemoveBaseHelper("local2@domain2", "mailto:local1@domain1?query1", "mailto:local2@domain2")); + TEST_ASSERT(testAddOrRemoveBaseHelper("local2@domain2?query2", "mailto:local1@domain1", "mailto:local2@domain2?query2")); + TEST_ASSERT(testAddOrRemoveBaseHelper("local2@domain2?query2", "mailto:local1@domain1?query1", "mailto:local2@domain2?query2")); + TEST_ASSERT(testAddOrRemoveBaseHelper("?query2", "mailto:local@domain?query1", "mailto:local@domain?query2")); + TEST_ASSERT(testAddOrRemoveBaseHelper("local@domain?query2", "mailto:?query1", "mailto:local@domain?query2")); + TEST_ASSERT(testAddOrRemoveBaseHelper("?query2", "mailto:local@domain?query1", "mailto:local@domain?query2")); + TEST_ASSERT(testAddOrRemoveBaseHelper("http://example/a/b?c/../d", "foo:bar", "http://example/a/b?c/../d")); + TEST_ASSERT(testAddOrRemoveBaseHelper("http://example/a/b#c/../d", "foo:bar", "http://example/a/b#c/../d")); + + // 82-88 + TEST_ASSERT(testAddOrRemoveBaseHelper("http:this", "http://example.org/base/uri", "http:this")); + TEST_ASSERT(testAddOrRemoveBaseHelper("http:this", "http:base", "http:this")); + // Whole in the URI spec, see http://lists.w3.org/Archives/Public/uri/2007Aug/0003.html + // TEST_ASSERT(testAddOrRemoveBaseHelper(".//g", "f:/a", "f://g")); // ORIGINAL + TEST_ASSERT(testAddOrRemoveBaseHelper(".//g", "f:/a", "f:/.//g")); // FIXED ONE + TEST_ASSERT(testAddOrRemoveBaseHelper("b/c//d/e", "f://example.org/base/a", "f://example.org/base/b/c//d/e")); + TEST_ASSERT(testAddOrRemoveBaseHelper("m2@example.ord/c2@example.org", "mid:m@example.ord/c@example.org", "mid:m@example.ord/m2@example.ord/c2@example.org")); + TEST_ASSERT(testAddOrRemoveBaseHelper("mini1.xml", "file:///C:/DEV/Haskell/lib/HXmlToolbox-3.01/examples/", "file:///C:/DEV/Haskell/lib/HXmlToolbox-3.01/examples/mini1.xml")); + TEST_ASSERT(testAddOrRemoveBaseHelper("../b/c", "foo:a/y/z", "foo:a/b/c")); +} + + + +void FourSuite::relativize_test_cases() { + const bool REMOVE_MODE = false; + const bool DOMAIN_ROOT_MODE = true; + + // to convert, base, exptected + + TEST_ASSERT(testAddOrRemoveBaseHelper("s://ex/a/b/c", "s://ex/a/d", "b/c", REMOVE_MODE)); + TEST_ASSERT(testAddOrRemoveBaseHelper("s://ex/b/b/c", "s://ex/a/d", "/b/b/c", REMOVE_MODE, DOMAIN_ROOT_MODE)); + TEST_ASSERT(testAddOrRemoveBaseHelper("s://ex/a/b/c", "s://ex/a/b/", "c", REMOVE_MODE)); + TEST_ASSERT(testAddOrRemoveBaseHelper("s://other.ex/a/b/", "s://ex/a/d", "//other.ex/a/b/", REMOVE_MODE)); + TEST_ASSERT(testAddOrRemoveBaseHelper("s://ex/a/b/c", "s://other.ex/a/d", "//ex/a/b/c", REMOVE_MODE)); + TEST_ASSERT(testAddOrRemoveBaseHelper("t://ex/a/b/c", "s://ex/a/d", "t://ex/a/b/c", REMOVE_MODE)); + TEST_ASSERT(testAddOrRemoveBaseHelper("s://ex/a/b/c", "t://ex/a/d", "s://ex/a/b/c", REMOVE_MODE)); + TEST_ASSERT(testAddOrRemoveBaseHelper("s://ex/a", "s://ex/b/c/d", "/a", REMOVE_MODE, DOMAIN_ROOT_MODE)); + TEST_ASSERT(testAddOrRemoveBaseHelper("s://ex/b/c/d", "s://ex/a", "b/c/d", REMOVE_MODE)); + TEST_ASSERT(testAddOrRemoveBaseHelper("s://ex/a/b/c?h", "s://ex/a/d?w", "b/c?h", REMOVE_MODE)); + TEST_ASSERT(testAddOrRemoveBaseHelper("s://ex/a/b/c#h", "s://ex/a/d#w", "b/c#h", REMOVE_MODE)); + TEST_ASSERT(testAddOrRemoveBaseHelper("s://ex/a/b/c?h#i", "s://ex/a/d?w#j", "b/c?h#i", REMOVE_MODE)); + TEST_ASSERT(testAddOrRemoveBaseHelper("s://ex/a#i", "s://ex/a", "#i", REMOVE_MODE)); + TEST_ASSERT(testAddOrRemoveBaseHelper("s://ex/a?i", "s://ex/a", "?i", REMOVE_MODE)); + + TEST_ASSERT(testAddOrRemoveBaseHelper("s://ex/a/b/", "s://ex/a/b/", "", REMOVE_MODE)); + TEST_ASSERT(testAddOrRemoveBaseHelper("s://ex/a/b", "s://ex/a/b", "", REMOVE_MODE)); + TEST_ASSERT(testAddOrRemoveBaseHelper("s://ex/", "s://ex/", "", REMOVE_MODE)); + + TEST_ASSERT(testAddOrRemoveBaseHelper("s://ex/a/b/c", "s://ex/a/d/c", "../b/c", REMOVE_MODE)); + TEST_ASSERT(testAddOrRemoveBaseHelper("s://ex/a/b/c/", "s://ex/a/d/c", "../b/c/", REMOVE_MODE)); + TEST_ASSERT(testAddOrRemoveBaseHelper("s://ex/a/b/c/d", "s://ex/a/d/c/d", "../../b/c/d", REMOVE_MODE)); + TEST_ASSERT(testAddOrRemoveBaseHelper("s://ex/a/b/c", "s://ex/d/e/f", "/a/b/c", REMOVE_MODE, DOMAIN_ROOT_MODE)); + TEST_ASSERT(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. + TEST_ASSERT(testAddOrRemoveBaseHelper("s://ex/a/b", "s://ex/a//b/c", "../../b", REMOVE_MODE)); + TEST_ASSERT(testAddOrRemoveBaseHelper("s://ex/a///b", "s://ex/a/", ".///b", REMOVE_MODE)); + TEST_ASSERT(testAddOrRemoveBaseHelper("s://ex/a/", "s://ex/a///b", "../../", REMOVE_MODE)); + TEST_ASSERT(testAddOrRemoveBaseHelper("s://ex/a//b/c", "s://ex/a/b", ".//b/c", REMOVE_MODE)); +} + + + +int FourSuite::testParseUri(const char * uriText, const char ** expectedErrorPos) { + UriParserStateA state; + UriUriA uri; + state.uri = &uri; + int res = uriParseUriA(&state, uriText); + if (expectedErrorPos != NULL) { + *expectedErrorPos = state.errorPos; + } + uriFreeUriMembersA(&uri); + return res; +} + + + +bool FourSuite::testGoodUri(const char * uriText) { + return (testParseUri(uriText) == 0); +} + + + +bool FourSuite::testBadUri(const char * uriText, int expectedErrorOffset) { + const char * errorPos = NULL; + const int ret = testParseUri(uriText, &errorPos); + return ((ret == URI_ERROR_SYNTAX) + && (errorPos != NULL) + && ( + (expectedErrorOffset == -1) + || (errorPos == (uriText + expectedErrorOffset)) + )); +} + + + +void FourSuite::good_URI_references() { + TEST_ASSERT(testGoodUri("file:///foo/bar")); + TEST_ASSERT(testGoodUri("mailto:user@host?subject=blah")); + TEST_ASSERT(testGoodUri("dav:")); // empty opaque part / rel-path allowed by RFC 2396bis + TEST_ASSERT(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 + TEST_ASSERT(testGoodUri("http://www.yahoo.com")); + TEST_ASSERT(testGoodUri("http://www.yahoo.com/")); + TEST_ASSERT(testGoodUri("http://1.2.3.4/")); + TEST_ASSERT(testGoodUri("http://www.yahoo.com/stuff")); + TEST_ASSERT(testGoodUri("http://www.yahoo.com/stuff/")); + TEST_ASSERT(testGoodUri("http://www.yahoo.com/hello%20world/")); + TEST_ASSERT(testGoodUri("http://www.yahoo.com?name=obi")); + TEST_ASSERT(testGoodUri("http://www.yahoo.com?name=obi+wan&status=jedi")); + TEST_ASSERT(testGoodUri("http://www.yahoo.com?onery")); + TEST_ASSERT(testGoodUri("http://www.yahoo.com#bottom")); + TEST_ASSERT(testGoodUri("http://www.yahoo.com/yelp.html#bottom")); + TEST_ASSERT(testGoodUri("https://www.yahoo.com/")); + TEST_ASSERT(testGoodUri("ftp://www.yahoo.com/")); + TEST_ASSERT(testGoodUri("ftp://www.yahoo.com/hello")); + TEST_ASSERT(testGoodUri("demo.txt")); + TEST_ASSERT(testGoodUri("demo/hello.txt")); + TEST_ASSERT(testGoodUri("demo/hello.txt?query=hello#fragment")); + TEST_ASSERT(testGoodUri("/cgi-bin/query?query=hello#fragment")); + TEST_ASSERT(testGoodUri("/demo.txt")); + TEST_ASSERT(testGoodUri("/hello/demo.txt")); + TEST_ASSERT(testGoodUri("hello/demo.txt")); + TEST_ASSERT(testGoodUri("/")); + TEST_ASSERT(testGoodUri("")); + TEST_ASSERT(testGoodUri("#")); + TEST_ASSERT(testGoodUri("#here")); + + // Wheeler's script says these are invalid, but they aren't + TEST_ASSERT(testGoodUri("http://www.yahoo.com?name=%00%01")); + TEST_ASSERT(testGoodUri("http://www.yaho%6f.com")); + TEST_ASSERT(testGoodUri("http://www.yahoo.com/hello%00world/")); + TEST_ASSERT(testGoodUri("http://www.yahoo.com/hello+world/")); + TEST_ASSERT(testGoodUri("http://www.yahoo.com?name=obi&")); + TEST_ASSERT(testGoodUri("http://www.yahoo.com?name=obi&type=")); + TEST_ASSERT(testGoodUri("http://www.yahoo.com/yelp.html#")); + TEST_ASSERT(testGoodUri("//")); + + // the following test cases are from a Haskell program by Graham Klyne + // at http://www.ninebynine.org/Software/HaskellUtils/Network/URITest.hs + TEST_ASSERT(testGoodUri("http://example.org/aaa/bbb#ccc")); + TEST_ASSERT(testGoodUri("mailto:local@domain.org")); + TEST_ASSERT(testGoodUri("mailto:local@domain.org#frag")); + TEST_ASSERT(testGoodUri("HTTP://EXAMPLE.ORG/AAA/BBB#CCC")); + TEST_ASSERT(testGoodUri("//example.org/aaa/bbb#ccc")); + TEST_ASSERT(testGoodUri("/aaa/bbb#ccc")); + TEST_ASSERT(testGoodUri("bbb#ccc")); + TEST_ASSERT(testGoodUri("#ccc")); + TEST_ASSERT(testGoodUri("#")); + TEST_ASSERT(testGoodUri("A'C")); + + // escapes + TEST_ASSERT(testGoodUri("http://example.org/aaa%2fbbb#ccc")); + TEST_ASSERT(testGoodUri("http://example.org/aaa%2Fbbb#ccc")); + TEST_ASSERT(testGoodUri("%2F")); + TEST_ASSERT(testGoodUri("aaa%2Fbbb")); + + // ports + TEST_ASSERT(testGoodUri("http://example.org:80/aaa/bbb#ccc")); + TEST_ASSERT(testGoodUri("http://example.org:/aaa/bbb#ccc")); + TEST_ASSERT(testGoodUri("http://example.org./aaa/bbb#ccc")); + TEST_ASSERT(testGoodUri("http://example.123./aaa/bbb#ccc")); + + // bare authority + TEST_ASSERT(testGoodUri("http://example.org")); + + // IPv6 literals (from RFC2732): + TEST_ASSERT(testGoodUri("http://[FEDC:BA98:7654:3210:FEDC:BA98:7654:3210]:80/index.html")); + TEST_ASSERT(testGoodUri("http://[1080:0:0:0:8:800:200C:417A]/index.html")); + TEST_ASSERT(testGoodUri("http://[3ffe:2a00:100:7031::1]")); + TEST_ASSERT(testGoodUri("http://[1080::8:800:200C:417A]/foo")); + TEST_ASSERT(testGoodUri("http://[::192.9.5.5]/ipng")); + TEST_ASSERT(testGoodUri("http://[::FFFF:129.144.52.38]:80/index.html")); + TEST_ASSERT(testGoodUri("http://[2010:836B:4179::836B:4179]")); + TEST_ASSERT(testGoodUri("//[2010:836B:4179::836B:4179]")); + + // Random other things that crop up + TEST_ASSERT(testGoodUri("http://example/Andrȷ")); + TEST_ASSERT(testGoodUri("file:///C:/DEV/Haskell/lib/HXmlToolbox-3.01/examples/")); +} + + + +void FourSuite::bad_URI_references() { + TEST_ASSERT(testBadUri("beepbeep\x07\x07", 8)); + TEST_ASSERT(testBadUri("\n", 0)); + TEST_ASSERT(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 + TEST_ASSERT(testBadUri("http://www yahoo.com", 10)); + TEST_ASSERT(testBadUri("http://www.yahoo.com/hello world/", 26)); + TEST_ASSERT(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 + TEST_ASSERT(testBadUri("[2010:836B:4179::836B:4179]", 0)); + TEST_ASSERT(testBadUri(" ", 0)); + TEST_ASSERT(testBadUri("%", 1)); + TEST_ASSERT(testBadUri("A%Z", 2)); + TEST_ASSERT(testBadUri("%ZZ", 1)); + TEST_ASSERT(testBadUri("%AZ", 2)); + TEST_ASSERT(testBadUri("A C", 1)); + TEST_ASSERT(testBadUri("A\\'C", 1)); // r"A\'C" + TEST_ASSERT(testBadUri("A`C", 1)); + TEST_ASSERT(testBadUri("AC", 1)); + TEST_ASSERT(testBadUri("A^C", 1)); + TEST_ASSERT(testBadUri("A\\\\C", 1)); // r'A\\C' + TEST_ASSERT(testBadUri("A{C", 1)); + TEST_ASSERT(testBadUri("A|C", 1)); + TEST_ASSERT(testBadUri("A}C", 1)); + TEST_ASSERT(testBadUri("A[C", 1)); + TEST_ASSERT(testBadUri("A]C", 1)); + TEST_ASSERT(testBadUri("A[**]C", 1)); + TEST_ASSERT(testBadUri("http://[xyz]/", 8)); + TEST_ASSERT(testBadUri("http://]/", 7)); + TEST_ASSERT(testBadUri("http://example.org/[2010:836B:4179::836B:4179]", 19)); + TEST_ASSERT(testBadUri("http://example.org/abc#[2010:836B:4179::836B:4179]", 23)); + TEST_ASSERT(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 + TEST_ASSERT(testBadUri("http://w3c.org:80path1/path2", 22)); +} + + + +bool FourSuite::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; +} + + + +void FourSuite::caseNormalizationTests() { + TEST_ASSERT(normalizeAndCompare("HTTP://www.EXAMPLE.com/", "http://www.example.com/")); + TEST_ASSERT(normalizeAndCompare("example://A/b/c/%7bfoo%7d", "example://a/b/c/%7Bfoo%7D")); +} + + + +void FourSuite::pctEncNormalizationTests() { + TEST_ASSERT(normalizeAndCompare("http://host/%7Euser/x/y/z", "http://host/~user/x/y/z")); + TEST_ASSERT(normalizeAndCompare("http://host/%7euser/x/y/z", "http://host/~user/x/y/z")); +} + + + +void FourSuite::pathSegmentNormalizationTests() { + TEST_ASSERT(normalizeAndCompare("/a/b/../../c", "/c")); + // TEST_ASSERT(normalizeAndCompare("a/b/../../c", "a/b/../../c")); + // Fixed: + TEST_ASSERT(normalizeAndCompare("a/b/../../c", "c")); + TEST_ASSERT(normalizeAndCompare("/a/b/././c", "/a/b/c")); + // TEST_ASSERT(normalizeAndCompare("a/b/././c", "a/b/././c")); + // Fixed: + TEST_ASSERT(normalizeAndCompare("a/b/././c", "a/b/c")); + TEST_ASSERT(normalizeAndCompare("/a/b/../c/././d", "/a/c/d")); + // TEST_ASSERT(normalizeAndCompare("a/b/../c/././d", "a/b/../c/././d")); + // Fixed: + TEST_ASSERT(normalizeAndCompare("a/b/../c/././d", "a/c/d")); +} diff --git a/test/FourSuite.h b/test/FourSuite.h new file mode 100644 index 0000000..24144cc --- /dev/null +++ b/test/FourSuite.h @@ -0,0 +1,70 @@ +/* + * uriparser - RFC 3986 URI parsing library + * + * Copyright (C) 2007, Weijia Song + * Copyright (C) 2007, Sebastian Pipping + * + * 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 + */ + +#ifndef TEST_FOUR_SUITE_H +#define TEST_FOUR_SUITE_H 1 + + + +#include + +using namespace Test; + + + +class FourSuite : public Suite { + +public: + FourSuite() { + TEST_ADD(FourSuite::absolutize_test_cases) + TEST_ADD(FourSuite::relativize_test_cases) + TEST_ADD(FourSuite::good_URI_references) + TEST_ADD(FourSuite::bad_URI_references) + TEST_ADD(FourSuite::caseNormalizationTests) + TEST_ADD(FourSuite::pctEncNormalizationTests) + TEST_ADD(FourSuite::pathSegmentNormalizationTests) + } + +private: + bool testAddOrRemoveBaseHelper(const char * ref, + const char * base, const char * expected, bool add = true, + bool domainRootMode = false); + + void absolutize_test_cases(); + void relativize_test_cases(); + + int testParseUri(const char * uriText, const char ** expectedErrorPos = NULL); + bool testGoodUri(const char * uriText); + bool testBadUri(const char * uriText, int expectedErrorOffset = -1); + void good_URI_references(); + void bad_URI_references(); + + bool normalizeAndCompare(const char * uriText, + const char * expectedNormalized); + void caseNormalizationTests(); + void pctEncNormalizationTests(); + void pathSegmentNormalizationTests(); + +}; + + + +#endif // TEST_FOUR_SUITE_H diff --git a/test/test.cpp b/test/test.cpp new file mode 100644 index 0000000..8eef547 --- /dev/null +++ b/test/test.cpp @@ -0,0 +1,1751 @@ +/* + * uriparser - RFC 3986 URI parsing library + * + * Copyright (C) 2007, Weijia Song + * Copyright (C) 2007, Sebastian Pipping + * + * 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 +#include +#include +#include +#include + +#include "FourSuite.h" + +using namespace Test; +using namespace std; + + + +extern "C" { +UriBool uri_TESTING_ONLY_ParseIpSixA(const char * text); +UriBool uri_TESTING_ONLY_ParseIpFourA(const char * text); +} + + + +#define URI_TEST_IP_FOUR_FAIL(x) TEST_ASSERT(URI_FALSE == uri_TESTING_ONLY_ParseIpFourA(x)) +#define URI_TEST_IP_FOUR_PASS(x) TEST_ASSERT(URI_TRUE == uri_TESTING_ONLY_ParseIpFourA(x)) + +// Note the closing brackets! TODO +#define URI_TEST_IP_SIX_FAIL(x) TEST_ASSERT(URI_FALSE == uri_TESTING_ONLY_ParseIpSixA(x "]")) +#define URI_TEST_IP_SIX_PASS(x) TEST_ASSERT(URI_TRUE == uri_TESTING_ONLY_ParseIpSixA(x "]")) + + + +class UriSuite : public Suite { + +public: + UriSuite() { + TEST_ADD(UriSuite::testDistinction) + TEST_ADD(UriSuite::testIpFour) + TEST_ADD(UriSuite::testIpSixPass) + TEST_ADD(UriSuite::testIpSixFail) + TEST_ADD(UriSuite::testUri) + TEST_ADD(UriSuite::testUriUserInfoHostPort1) + TEST_ADD(UriSuite::testUriUserInfoHostPort2) + TEST_ADD(UriSuite::testUriUserInfoHostPort22_Bug1948038) + TEST_ADD(UriSuite::testUriUserInfoHostPort23_Bug3510198_1) + TEST_ADD(UriSuite::testUriUserInfoHostPort23_Bug3510198_2) + TEST_ADD(UriSuite::testUriUserInfoHostPort23_Bug3510198_3) + TEST_ADD(UriSuite::testUriUserInfoHostPort23_Bug3510198_4) + TEST_ADD(UriSuite::testUriUserInfoHostPort23_Bug3510198_related_1) + TEST_ADD(UriSuite::testUriUserInfoHostPort23_Bug3510198_related_12) + TEST_ADD(UriSuite::testUriUserInfoHostPort23_Bug3510198_related_2) + TEST_ADD(UriSuite::testUriUserInfoHostPort3) + TEST_ADD(UriSuite::testUriUserInfoHostPort4) + TEST_ADD(UriSuite::testUriUserInfoHostPort5) + TEST_ADD(UriSuite::testUriUserInfoHostPort6) + TEST_ADD(UriSuite::testUriHostRegname) + TEST_ADD(UriSuite::testUriHostIpFour1) + TEST_ADD(UriSuite::testUriHostIpFour2) + TEST_ADD(UriSuite::testUriHostIpSix1) + TEST_ADD(UriSuite::testUriHostIpSix2) + TEST_ADD(UriSuite::testUriHostIpFuture) + TEST_ADD(UriSuite::testUriHostEmpty) + TEST_ADD(UriSuite::testUriComponents) + TEST_ADD(UriSuite::testUriComponents_Bug20070701) + TEST_ADD(UriSuite::testEscaping) + TEST_ADD(UriSuite::testUnescaping) + TEST_ADD(UriSuite::testTrailingSlash) + TEST_ADD(UriSuite::testAddBase) + TEST_ADD(UriSuite::testToString) + TEST_ADD(UriSuite::testToString_Bug1950126) + TEST_ADD(UriSuite::testToStringCharsRequired) + TEST_ADD(UriSuite::testToStringCharsRequired) + TEST_ADD(UriSuite::testNormalizeSyntaxMaskRequired) + TEST_ADD(UriSuite::testNormalizeSyntax) + TEST_ADD(UriSuite::testNormalizeSyntaxComponents) + TEST_ADD(UriSuite::testNormalizeCrash_Bug20080224) + TEST_ADD(UriSuite::testFilenameUriConversion) + TEST_ADD(UriSuite::testCrash_FreeUriMembers_Bug20080116) + TEST_ADD(UriSuite::testCrash_Report2418192) + TEST_ADD(UriSuite::testPervertedQueryString); + TEST_ADD(UriSuite::testCrash_MakeOwner_Bug20080207) + TEST_ADD(UriSuite::testQueryList) + TEST_ADD(UriSuite::testQueryListPair) + TEST_ADD(UriSuite::testQueryDissection_Bug3590761) + TEST_ADD(UriSuite::testFreeCrash_Bug20080827) + TEST_ADD(UriSuite::testParseInvalid_Bug16) + } + +private: + 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; + } + + void testDistinction() { + /* +============================================================================ +Rule | Example | hostSet | absPath | emptySeg +------------------------------------|---------|---------|---------|--------- +1) URI = scheme ":" hier-part ... | | | | + 1) "//" authority path-abempty | "s://" | true | false | false + | "s:///" | true | false | true + | "s://a" | true | false | false + | "s://a/"| true | false | true + 2) path-absolute | "s:/" | false | true | false + 3) path-rootless | "s:a" | false | false | false + | "s:a/" | false | false | true + 4) path-empty | "s:" | false | false | false +------------------------------------|---------|---------|---------|--------- +2) relative-ref = relative-part ... | | | | + 1) "//" authority path-abempty | "//" | true | false | false + | "///" | true | false | true + 2) path-absolute | "/" | false | true | false + 3) path-noscheme | "a" | false | false | false + | "a/" | false | false | true + 4) path-empty | "" | false | false | false +============================================================================ + */ + TEST_ASSERT(testDistinctionHelper("s://", true, false, false)); + TEST_ASSERT(testDistinctionHelper("s:///", true, false, true)); + TEST_ASSERT(testDistinctionHelper("s://a", true, false, false)); + TEST_ASSERT(testDistinctionHelper("s://a/", true, false, true)); + TEST_ASSERT(testDistinctionHelper("s:/", false, true, false)); + TEST_ASSERT(testDistinctionHelper("s:a", false, false, false)); + TEST_ASSERT(testDistinctionHelper("s:a/", false, false, true)); + TEST_ASSERT(testDistinctionHelper("s:", false, false, false)); + + TEST_ASSERT(testDistinctionHelper("//", true, false, false)); + TEST_ASSERT(testDistinctionHelper("///", true, false, true)); + TEST_ASSERT(testDistinctionHelper("/", false, true, false)); + TEST_ASSERT(testDistinctionHelper("a", false, false, false)); + TEST_ASSERT(testDistinctionHelper("a/", false, false, true)); + TEST_ASSERT(testDistinctionHelper("", false, false, false)); + } + + void 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"); + } + + void 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"); + } + + void 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 + URI_TEST_IP_SIX_FAIL("0:0:0:0:0:0:0:0:0"); + + // 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"); + } + + void testUri() { + UriParserStateA stateA; + UriParserStateW stateW; + UriUriA uriA; + UriUriW uriW; + + stateA.uri = &uriA; + stateW.uri = &uriW; + + // On/off for each + TEST_ASSERT(0 == uriParseUriA(&stateA, "//user:pass@[::1]:80/segment/index.html?query#frag")); + uriFreeUriMembersA(&uriA); + TEST_ASSERT(0 == uriParseUriA(&stateA, "http://[::1]:80/segment/index.html?query#frag")); + uriFreeUriMembersA(&uriA); + TEST_ASSERT(0 == uriParseUriA(&stateA, "http://user:pass@[::1]/segment/index.html?query#frag")); + uriFreeUriMembersA(&uriA); + TEST_ASSERT(0 == uriParseUriA(&stateA, "http://user:pass@[::1]:80?query#frag")); + uriFreeUriMembersA(&uriA); + TEST_ASSERT(0 == uriParseUriA(&stateA, "http://user:pass@[::1]:80/segment/index.html#frag")); + uriFreeUriMembersA(&uriA); + TEST_ASSERT(0 == uriParseUriA(&stateA, "http://user:pass@[::1]:80/segment/index.html?query")); + uriFreeUriMembersA(&uriA); + + // Schema, port, one segment + TEST_ASSERT(0 == uriParseUriA(&stateA, "ftp://host:21/gnu/")); + uriFreeUriMembersA(&uriA); + + // Relative + TEST_ASSERT(0 == uriParseUriA(&stateA, "one/two/three")); + TEST_ASSERT(!uriA.absolutePath); + uriFreeUriMembersA(&uriA); + TEST_ASSERT(0 == uriParseUriA(&stateA, "/one/two/three")); + TEST_ASSERT(uriA.absolutePath); + uriFreeUriMembersA(&uriA); + TEST_ASSERT(0 == uriParseUriA(&stateA, "//user:pass@localhost/one/two/three")); + uriFreeUriMembersA(&uriA); + + // ANSI and Unicode + TEST_ASSERT(0 == uriParseUriA(&stateA, "http://www.example.com/")); + uriFreeUriMembersA(&uriA); + TEST_ASSERT(0 == uriParseUriW(&stateW, L"http://www.example.com/")); + uriFreeUriMembersW(&uriW); + + // Real life examples + TEST_ASSERT(0 == uriParseUriA(&stateA, "http://sourceforge.net/projects/uriparser/")); + uriFreeUriMembersA(&uriA); + TEST_ASSERT(0 == uriParseUriA(&stateA, "http://sourceforge.net/project/platformdownload.php?group_id=182840")); + uriFreeUriMembersA(&uriA); + TEST_ASSERT(0 == uriParseUriA(&stateA, "mailto:test@example.com")); + uriFreeUriMembersA(&uriA); + TEST_ASSERT(0 == uriParseUriA(&stateA, "../../")); + uriFreeUriMembersA(&uriA); + TEST_ASSERT(0 == uriParseUriA(&stateA, "/")); + TEST_ASSERT(uriA.absolutePath) + uriFreeUriMembersA(&uriA); + TEST_ASSERT(0 == uriParseUriA(&stateA, "")); + TEST_ASSERT(!uriA.absolutePath) + uriFreeUriMembersA(&uriA); + TEST_ASSERT(0 == uriParseUriA(&stateA, "file:///bin/bash")); + uriFreeUriMembersA(&uriA); + + // Percent encoding + TEST_ASSERT(0 == uriParseUriA(&stateA, "http://www.example.com/name%20with%20spaces/")); + uriFreeUriMembersA(&uriA); + TEST_ASSERT(0 != uriParseUriA(&stateA, "http://www.example.com/name with spaces/")); + uriFreeUriMembersA(&uriA); + } + + void 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"; + TEST_ASSERT(0 == uriParseUriA(&stateA, input)); + + TEST_ASSERT(uriA.scheme.first == input); + TEST_ASSERT(uriA.scheme.afterLast == input + 4); + TEST_ASSERT(uriA.userInfo.first == NULL); + TEST_ASSERT(uriA.userInfo.afterLast == NULL); + TEST_ASSERT(uriA.hostText.first == input + 4 + 3); + TEST_ASSERT(uriA.hostText.afterLast == input + 4 + 3 + 15); + TEST_ASSERT(uriA.hostData.ipFuture.first == NULL); + TEST_ASSERT(uriA.hostData.ipFuture.afterLast == NULL); + TEST_ASSERT(uriA.portText.first == NULL); + TEST_ASSERT(uriA.portText.afterLast == NULL); + + TEST_ASSERT(uriA.pathHead->text.first == input + 4 + 3 + 15 + 1); + TEST_ASSERT(uriA.pathHead->text.afterLast == input + 4 + 3 + 15 + 1 + 7); + TEST_ASSERT(uriA.pathHead->next->text.first == input + 4 + 3 + 15 + 1 + 7 + 1); + TEST_ASSERT(uriA.pathHead->next->text.afterLast == input + 4 + 3 + 15 + 1 + 7 + 1 + 20); + TEST_ASSERT(uriA.pathHead->next->next == NULL); + TEST_ASSERT(uriA.pathTail == uriA.pathHead->next); + + TEST_ASSERT(uriA.query.first == input + 4 + 3 + 15 + 1 + 7 + 1 + 20 + 1); + TEST_ASSERT(uriA.query.afterLast == input + 4 + 3 + 15 + 1 + 7 + 1 + 20 + 1 + 15); + TEST_ASSERT(uriA.fragment.first == NULL); + TEST_ASSERT(uriA.fragment.afterLast == NULL); + uriFreeUriMembersA(&uriA); + } + + void testUriComponents_Bug20070701() { + UriParserStateA stateA; + UriUriA uriA; + stateA.uri = &uriA; + // 01 01 01 + const char * const input = "a" ":" "b"; + TEST_ASSERT(0 == uriParseUriA(&stateA, input)); + + TEST_ASSERT(uriA.scheme.first == input); + TEST_ASSERT(uriA.scheme.afterLast == input + 1); + TEST_ASSERT(uriA.userInfo.first == NULL); + TEST_ASSERT(uriA.userInfo.afterLast == NULL); + TEST_ASSERT(uriA.hostText.first == NULL); + TEST_ASSERT(uriA.hostText.afterLast == NULL); + TEST_ASSERT(uriA.hostData.ipFuture.first == NULL); + TEST_ASSERT(uriA.hostData.ipFuture.afterLast == NULL); + TEST_ASSERT(uriA.portText.first == NULL); + TEST_ASSERT(uriA.portText.afterLast == NULL); + + TEST_ASSERT(uriA.pathHead->text.first == input + 1 + 1); + TEST_ASSERT(uriA.pathHead->text.afterLast == input + 1 + 1 + 1); + TEST_ASSERT(uriA.pathHead->next == NULL); + TEST_ASSERT(uriA.pathTail == uriA.pathHead); + + TEST_ASSERT(uriA.query.first == NULL); + TEST_ASSERT(uriA.query.afterLast == NULL); + TEST_ASSERT(uriA.fragment.first == NULL); + TEST_ASSERT(uriA.fragment.afterLast == NULL); + + TEST_ASSERT(!uriA.absolutePath); + uriFreeUriMembersA(&uriA); + } + + void 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"; + TEST_ASSERT(0 == uriParseUriA(&stateA, input)); + + TEST_ASSERT(uriA.userInfo.first == input + 4 + 3); + TEST_ASSERT(uriA.userInfo.afterLast == input + 4 + 3 + 7); + TEST_ASSERT(uriA.hostText.first == input + 4 + 3 + 7 + 1); + TEST_ASSERT(uriA.hostText.afterLast == input + 4 + 3 + 7 + 1 + 9); + TEST_ASSERT(uriA.portText.first == NULL); + TEST_ASSERT(uriA.portText.afterLast == NULL); + uriFreeUriMembersA(&uriA); + } + + void 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"; + TEST_ASSERT(0 == uriParseUriA(&stateA, input)); + + TEST_ASSERT(uriA.userInfo.first == input + 4 + 3); + TEST_ASSERT(uriA.userInfo.afterLast == input + 4 + 3 + 7); + TEST_ASSERT(uriA.hostText.first == input + 4 + 3 + 7 + 1); + TEST_ASSERT(uriA.hostText.afterLast == input + 4 + 3 + 7 + 1 + 9); + TEST_ASSERT(uriA.portText.first == input + 4 + 3 + 7 + 1 + 9 + 1); + TEST_ASSERT(uriA.portText.afterLast == input + 4 + 3 + 7 + 1 + 9 + 1 + 3); + uriFreeUriMembersA(&uriA); + } + + void testUriUserInfoHostPort22_Bug1948038() { + UriParserStateA stateA; + UriUriA uriA; + stateA.uri = &uriA; + + int res; + + res = uriParseUriA(&stateA, "http://user:21@host/"); + TEST_ASSERT(URI_SUCCESS == res); + TEST_ASSERT(!memcmp(uriA.userInfo.first, "user:21", 7 * sizeof(char))); + TEST_ASSERT(uriA.userInfo.afterLast - uriA.userInfo.first == 7); + TEST_ASSERT(!memcmp(uriA.hostText.first, "host", 4 * sizeof(char))); + TEST_ASSERT(uriA.hostText.afterLast - uriA.hostText.first == 4); + TEST_ASSERT(uriA.portText.first == NULL); + TEST_ASSERT(uriA.portText.afterLast == NULL); + uriFreeUriMembersA(&uriA); + + res = uriParseUriA(&stateA, "http://user:1234@192.168.0.1:1234/foo.com"); + TEST_ASSERT(URI_SUCCESS == res); + uriFreeUriMembersA(&uriA); + + res = uriParseUriA(&stateA, "http://moo:21@moo:21@moo/"); + TEST_ASSERT(URI_ERROR_SYNTAX == res); + uriFreeUriMembersA(&uriA); + + res = uriParseUriA(&stateA, "http://moo:21@moo:21@moo:21/"); + TEST_ASSERT(URI_ERROR_SYNTAX == res); + uriFreeUriMembersA(&uriA); + } + + void testUriUserInfoHostPort23_Bug3510198_1() { + // 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" "/"); + TEST_ASSERT(URI_SUCCESS == res); + TEST_ASSERT(!memcmp(uriA.userInfo.first, "user:%2F21", 10 * sizeof(char))); + TEST_ASSERT(uriA.userInfo.afterLast - uriA.userInfo.first == 10); + TEST_ASSERT(!memcmp(uriA.hostText.first, "host", 4 * sizeof(char))); + TEST_ASSERT(uriA.hostText.afterLast - uriA.hostText.first == 4); + TEST_ASSERT(uriA.portText.first == NULL); + TEST_ASSERT(uriA.portText.afterLast == NULL); + uriFreeUriMembersA(&uriA); + + } + + void testUriUserInfoHostPort23_Bug3510198_2() { + // 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" "/"); + TEST_ASSERT(URI_SUCCESS == res); + TEST_ASSERT(!memcmp(uriA.userInfo.first, "%2Fuser:%2F21", 13 * sizeof(char))); + TEST_ASSERT(uriA.userInfo.afterLast - uriA.userInfo.first == 13); + TEST_ASSERT(!memcmp(uriA.hostText.first, "host", 4 * sizeof(char))); + TEST_ASSERT(uriA.hostText.afterLast - uriA.hostText.first == 4); + TEST_ASSERT(uriA.portText.first == NULL); + TEST_ASSERT(uriA.portText.afterLast == NULL); + uriFreeUriMembersA(&uriA); + } + + void testUriUserInfoHostPort23_Bug3510198_3() { + // 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" "/"); + TEST_ASSERT(URI_SUCCESS == res); + TEST_ASSERT(!memcmp(uriA.userInfo.first, "user:!$&'()*+,;=", 16 * sizeof(char))); + TEST_ASSERT(uriA.userInfo.afterLast - uriA.userInfo.first == 16); + TEST_ASSERT(!memcmp(uriA.hostText.first, "host", 4 * sizeof(char))); + TEST_ASSERT(uriA.hostText.afterLast - uriA.hostText.first == 4); + TEST_ASSERT(uriA.portText.first == NULL); + TEST_ASSERT(uriA.portText.afterLast == NULL); + uriFreeUriMembersA(&uriA); + + } + + void testUriUserInfoHostPort23_Bug3510198_4() { + // 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" "/"); + TEST_ASSERT(URI_SUCCESS == res); + TEST_ASSERT(!memcmp(uriA.userInfo.first, "!$&'()*+,;=:password", 20 * sizeof(char))); + TEST_ASSERT(uriA.userInfo.afterLast - uriA.userInfo.first == 20); + TEST_ASSERT(!memcmp(uriA.hostText.first, "host", 4 * sizeof(char))); + TEST_ASSERT(uriA.hostText.afterLast - uriA.hostText.first == 4); + TEST_ASSERT(uriA.portText.first == NULL); + TEST_ASSERT(uriA.portText.afterLast == NULL); + uriFreeUriMembersA(&uriA); + } + + void testUriUserInfoHostPort23_Bug3510198_related_1() { + // 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" "/"); + TEST_ASSERT(URI_SUCCESS == res); + TEST_ASSERT(uriA.userInfo.afterLast != NULL); + TEST_ASSERT(uriA.userInfo.first != NULL); + TEST_ASSERT(uriA.userInfo.afterLast - uriA.userInfo.first == 0); + TEST_ASSERT(!memcmp(uriA.hostText.first, "host", 4 * sizeof(char))); + TEST_ASSERT(uriA.hostText.afterLast - uriA.hostText.first == 4); + TEST_ASSERT(uriA.portText.first == NULL); + TEST_ASSERT(uriA.portText.afterLast == NULL); + uriFreeUriMembersA(&uriA); + } + + void testUriUserInfoHostPort23_Bug3510198_related_12() { + // Empty user info + UriParserStateA stateA; + UriUriA uriA; + stateA.uri = &uriA; + + int res; + // 0 4 0 3 0 7 01 + res = uriParseUriA(&stateA, "http" "://" "%2Fhost" "/"); + TEST_ASSERT(URI_SUCCESS == res); + TEST_ASSERT(uriA.userInfo.afterLast == NULL); + TEST_ASSERT(uriA.userInfo.first == NULL); + TEST_ASSERT(!memcmp(uriA.hostText.first, "%2Fhost", 7 * sizeof(char))); + TEST_ASSERT(uriA.hostText.afterLast - uriA.hostText.first == 7); + TEST_ASSERT(uriA.portText.first == NULL); + TEST_ASSERT(uriA.portText.afterLast == NULL); + uriFreeUriMembersA(&uriA); + } + + void testUriUserInfoHostPort23_Bug3510198_related_2() { + // 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" "/"); + TEST_ASSERT(URI_SUCCESS == res); + TEST_ASSERT(!memcmp(uriA.userInfo.first, "::", 2 * sizeof(char))); + TEST_ASSERT(uriA.userInfo.afterLast - uriA.userInfo.first == 2); + TEST_ASSERT(!memcmp(uriA.hostText.first, "host", 4 * sizeof(char))); + TEST_ASSERT(uriA.hostText.afterLast - uriA.hostText.first == 4); + TEST_ASSERT(uriA.portText.first == NULL); + TEST_ASSERT(uriA.portText.afterLast == NULL); + uriFreeUriMembersA(&uriA); + } + + void 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"; + TEST_ASSERT(0 == uriParseUriA(&stateA, input)); + + TEST_ASSERT(uriA.userInfo.first == input + 4 + 3); + TEST_ASSERT(uriA.userInfo.afterLast == input + 4 + 3 + 7); + TEST_ASSERT(uriA.hostText.first == input + 4 + 3 + 7 + 1); + TEST_ASSERT(uriA.hostText.afterLast == input + 4 + 3 + 7 + 1 + 9); + TEST_ASSERT(uriA.portText.first == NULL); + TEST_ASSERT(uriA.portText.afterLast == NULL); + uriFreeUriMembersA(&uriA); + } + + void 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"; + TEST_ASSERT(0 == uriParseUriA(&stateA, input)); + + TEST_ASSERT(uriA.userInfo.first == input + 4 + 3); + TEST_ASSERT(uriA.userInfo.afterLast == input + 4 + 3 + 7); + TEST_ASSERT(uriA.hostText.first == input + 4 + 3 + 7 + 1); + TEST_ASSERT(uriA.hostText.afterLast == input + 4 + 3 + 7 + 1 + 9); + TEST_ASSERT(uriA.portText.first == input + 4 + 3 + 7 + 1 + 9 + 1); + TEST_ASSERT(uriA.portText.afterLast == input + 4 + 3 + 7 + 1 + 9 + 1 + 3); + uriFreeUriMembersA(&uriA); + } + + void 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"; + TEST_ASSERT(0 == uriParseUriA(&stateA, input)); + + TEST_ASSERT(uriA.userInfo.first == NULL); + TEST_ASSERT(uriA.userInfo.afterLast == NULL); + TEST_ASSERT(uriA.hostText.first == input + 4 + 3); + TEST_ASSERT(uriA.hostText.afterLast == input + 4 + 3 + 9); + TEST_ASSERT(uriA.portText.first == NULL); + TEST_ASSERT(uriA.portText.afterLast == NULL); + uriFreeUriMembersA(&uriA); + } + + void 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"; + TEST_ASSERT(0 == uriParseUriA(&stateA, input)); + + TEST_ASSERT(uriA.userInfo.first == NULL); + TEST_ASSERT(uriA.userInfo.afterLast == NULL); + TEST_ASSERT(uriA.hostText.first == input + 4 + 3); + TEST_ASSERT(uriA.hostText.afterLast == input + 4 + 3 + 9); + TEST_ASSERT(uriA.portText.first == input + 4 + 3 + 9 + 1); + TEST_ASSERT(uriA.portText.afterLast == input + 4 + 3 + 9 + 1 + 3); + uriFreeUriMembersA(&uriA); + } + + void testUriHostRegname() { + UriParserStateA stateA; + UriUriA uriA; + stateA.uri = &uriA; + // 0 4 0 3 0 11 + const char * const input = "http" "://" "example.com"; + TEST_ASSERT(0 == uriParseUriA(&stateA, input)); + + TEST_ASSERT(uriA.hostText.first == input + 4 + 3); + TEST_ASSERT(uriA.hostText.afterLast == input + 4 + 3 + 11); + TEST_ASSERT(uriA.hostData.ip4 == NULL); + TEST_ASSERT(uriA.hostData.ip6 == NULL); + TEST_ASSERT(uriA.hostData.ipFuture.first == NULL); + TEST_ASSERT(uriA.hostData.ipFuture.afterLast == NULL); + uriFreeUriMembersA(&uriA); + } + + void 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"; + TEST_ASSERT(0 == uriParseUriA(&stateA, input)); + + TEST_ASSERT(uriA.hostText.first == input + 4 + 3); + TEST_ASSERT(uriA.hostText.afterLast == input + 4 + 3 + 7); + TEST_ASSERT(uriA.hostData.ip4 != NULL); + TEST_ASSERT(uriA.hostData.ip6 == NULL); + TEST_ASSERT(uriA.hostData.ipFuture.first == NULL); + TEST_ASSERT(uriA.hostData.ipFuture.afterLast == NULL); + uriFreeUriMembersA(&uriA); + } + + void testUriHostIpFour2() { + UriParserStateA stateA; + UriUriA uriA; + stateA.uri = &uriA; + // 0 4 0 3 0 7 + const char * const input = "http" "://" "1.2.3.4"; + TEST_ASSERT(0 == uriParseUriA(&stateA, input)); + + TEST_ASSERT(uriA.hostText.first == input + 4 + 3); + TEST_ASSERT(uriA.hostText.afterLast == input + 4 + 3 + 7); + TEST_ASSERT(uriA.hostData.ip4 != NULL); + TEST_ASSERT(uriA.hostData.ip6 == NULL); + TEST_ASSERT(uriA.hostData.ipFuture.first == NULL); + TEST_ASSERT(uriA.hostData.ipFuture.afterLast == NULL); + uriFreeUriMembersA(&uriA); + } + + void testUriHostIpSix1() { + UriParserStateA stateA; + UriUriA uriA; + stateA.uri = &uriA; + // 0 4 0 3 01 45 01 0 2 + const char * const input = "http" "://" "[::1]" ":" "80"; + TEST_ASSERT(0 == uriParseUriA(&stateA, input)); + + TEST_ASSERT(uriA.hostText.first == input + 4 + 3 + 1); + TEST_ASSERT(uriA.hostText.afterLast == input + 4 + 3 + 4); + TEST_ASSERT(uriA.hostData.ip4 == NULL); + TEST_ASSERT(uriA.hostData.ip6 != NULL); + TEST_ASSERT(uriA.hostData.ipFuture.first == NULL); + TEST_ASSERT(uriA.hostData.ipFuture.afterLast == NULL); + uriFreeUriMembersA(&uriA); + } + + void testUriHostIpSix2() { + UriParserStateA stateA; + UriUriA uriA; + stateA.uri = &uriA; + // 0 4 0 3 01 45 + const char * const input = "http" "://" "[::1]"; + TEST_ASSERT(0 == uriParseUriA(&stateA, input)); + + TEST_ASSERT(uriA.hostText.first == input + 4 + 3 + 1); + TEST_ASSERT(uriA.hostText.afterLast == input + 4 + 3 + 4); + TEST_ASSERT(uriA.hostData.ip4 == NULL); + TEST_ASSERT(uriA.hostData.ip6 != NULL); + TEST_ASSERT(uriA.hostData.ipFuture.first == NULL); + TEST_ASSERT(uriA.hostData.ipFuture.afterLast == NULL); + uriFreeUriMembersA(&uriA); + } + + void 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); + TEST_ASSERT(URI_SUCCESS == res); + TEST_ASSERT(uriA.userInfo.first == NULL); + TEST_ASSERT(uriA.userInfo.afterLast == NULL); + TEST_ASSERT(uriA.hostText.first != NULL); + TEST_ASSERT(uriA.hostText.afterLast != NULL); + TEST_ASSERT(uriA.hostText.afterLast - uriA.hostText.first == 0); + TEST_ASSERT(uriA.portText.first == input + 4 + 3 + 1); + TEST_ASSERT(uriA.portText.afterLast == input + 4 + 3 + 1 + 3); + uriFreeUriMembersA(&uriA); + } + + void testUriHostIpFuture() { + // TODO + } + + 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; + } + + void testEscaping() { + const bool SPACE_TO_PLUS = true; + const bool SPACE_TO_PERCENT = false; + const bool KEEP_UNMODIFIED = false; + const bool NORMALIZE = true; + + // '+' to ' ' + TEST_ASSERT(testEscapingHelper(L"abc def", L"abc+def", SPACE_TO_PLUS)); + TEST_ASSERT(testEscapingHelper(L"abc def", L"abc%20def", SPACE_TO_PERCENT)); + + // Percent encoding + TEST_ASSERT(testEscapingHelper(L"\x00", L"\0")); + TEST_ASSERT(testEscapingHelper(L"\x01", L"%01")); + TEST_ASSERT(testEscapingHelper(L"\xff", L"%FF")); + + // Linebreak normalization + TEST_ASSERT(testEscapingHelper(L"\x0d", L"%0D%0A", SPACE_TO_PLUS, NORMALIZE)); + TEST_ASSERT(testEscapingHelper(L"g\x0d", L"g%0D%0A", SPACE_TO_PLUS, NORMALIZE)); + TEST_ASSERT(testEscapingHelper(L"\x0dg", L"%0D%0Ag", SPACE_TO_PLUS, NORMALIZE)); + TEST_ASSERT(testEscapingHelper(L"\x0d", L"%0D", SPACE_TO_PLUS, KEEP_UNMODIFIED)); + TEST_ASSERT(testEscapingHelper(L"g\x0d", L"g%0D", SPACE_TO_PLUS, KEEP_UNMODIFIED)); + TEST_ASSERT(testEscapingHelper(L"\x0dg", L"%0Dg", SPACE_TO_PLUS, KEEP_UNMODIFIED)); + + TEST_ASSERT(testEscapingHelper(L"\x0a", L"%0D%0A", SPACE_TO_PLUS, NORMALIZE)); + TEST_ASSERT(testEscapingHelper(L"g\x0a", L"g%0D%0A", SPACE_TO_PLUS, NORMALIZE)); + TEST_ASSERT(testEscapingHelper(L"\x0ag", L"%0D%0Ag", SPACE_TO_PLUS, NORMALIZE)); + TEST_ASSERT(testEscapingHelper(L"\x0a", L"%0A", SPACE_TO_PLUS, KEEP_UNMODIFIED)); + TEST_ASSERT(testEscapingHelper(L"g\x0a", L"g%0A", SPACE_TO_PLUS, KEEP_UNMODIFIED)); + TEST_ASSERT(testEscapingHelper(L"\x0ag", L"%0Ag", SPACE_TO_PLUS, KEEP_UNMODIFIED)); + + TEST_ASSERT(testEscapingHelper(L"\x0d\x0a", L"%0D%0A", SPACE_TO_PLUS, NORMALIZE)); + TEST_ASSERT(testEscapingHelper(L"g\x0d\x0a", L"g%0D%0A", SPACE_TO_PLUS, NORMALIZE)); + TEST_ASSERT(testEscapingHelper(L"\x0d\x0ag", L"%0D%0Ag", SPACE_TO_PLUS, NORMALIZE)); + TEST_ASSERT(testEscapingHelper(L"\x0d\x0a", L"%0D%0A", SPACE_TO_PLUS, KEEP_UNMODIFIED)); + TEST_ASSERT(testEscapingHelper(L"g\x0d\x0a", L"g%0D%0A", SPACE_TO_PLUS, KEEP_UNMODIFIED)); + TEST_ASSERT(testEscapingHelper(L"\x0d\x0ag", L"%0D%0Ag", SPACE_TO_PLUS, KEEP_UNMODIFIED)); + + TEST_ASSERT(testEscapingHelper(L"\x0a\x0d", L"%0D%0A%0D%0A", SPACE_TO_PLUS, NORMALIZE)); + TEST_ASSERT(testEscapingHelper(L"g\x0a\x0d", L"g%0D%0A%0D%0A", SPACE_TO_PLUS, NORMALIZE)); + TEST_ASSERT(testEscapingHelper(L"\x0a\x0dg", L"%0D%0A%0D%0Ag", SPACE_TO_PLUS, NORMALIZE)); + TEST_ASSERT(testEscapingHelper(L"\x0a\x0d", L"%0A%0D", SPACE_TO_PLUS, KEEP_UNMODIFIED)); + TEST_ASSERT(testEscapingHelper(L"g\x0a\x0d", L"g%0A%0D", SPACE_TO_PLUS, KEEP_UNMODIFIED)); + TEST_ASSERT(testEscapingHelper(L"\x0a\x0dg", L"%0A%0Dg", SPACE_TO_PLUS, KEEP_UNMODIFIED)); + } + + 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; + } + + void testUnescaping() { + const bool PLUS_TO_SPACE = true; + const bool PLUS_DONT_TOUCH = false; + + + // Proper + TEST_ASSERT(testUnescapingHelper(L"abc%20%41BC", L"abc ABC")); + TEST_ASSERT(testUnescapingHelper(L"%20", L" ")); + + // Incomplete + TEST_ASSERT(testUnescapingHelper(L"%0", L"%0")); + + // Nonhex + TEST_ASSERT(testUnescapingHelper(L"%0g", L"%0g")); + TEST_ASSERT(testUnescapingHelper(L"%G0", L"%G0")); + + // No double decoding + TEST_ASSERT(testUnescapingHelper(L"%2520", L"%20")); + + // Decoding of '+' + TEST_ASSERT(testUnescapingHelper(L"abc+def", L"abc+def", PLUS_DONT_TOUCH)); + TEST_ASSERT(testUnescapingHelper(L"abc+def", L"abc def", PLUS_TO_SPACE)); + + // Line break conversion + TEST_ASSERT(testUnescapingHelper(L"%0d", L"\x0a", PLUS_DONT_TOUCH, URI_BR_TO_UNIX)); + TEST_ASSERT(testUnescapingHelper(L"%0d", L"\x0d\x0a", PLUS_DONT_TOUCH, URI_BR_TO_WINDOWS)); + TEST_ASSERT(testUnescapingHelper(L"%0d", L"\x0d", PLUS_DONT_TOUCH, URI_BR_TO_MAC)); + TEST_ASSERT(testUnescapingHelper(L"%0d", L"\x0d", PLUS_DONT_TOUCH, URI_BR_DONT_TOUCH)); + + TEST_ASSERT(testUnescapingHelper(L"%0d%0d", L"\x0a\x0a", PLUS_DONT_TOUCH, URI_BR_TO_UNIX)); + TEST_ASSERT(testUnescapingHelper(L"%0d%0d", L"\x0d\x0a\x0d\x0a", PLUS_DONT_TOUCH, URI_BR_TO_WINDOWS)); + TEST_ASSERT(testUnescapingHelper(L"%0d%0d", L"\x0d\x0d", PLUS_DONT_TOUCH, URI_BR_TO_MAC)); + TEST_ASSERT(testUnescapingHelper(L"%0d%0d", L"\x0d\x0d", PLUS_DONT_TOUCH, URI_BR_DONT_TOUCH)); + + + TEST_ASSERT(testUnescapingHelper(L"%0a", L"\x0a", PLUS_DONT_TOUCH, URI_BR_TO_UNIX)); + TEST_ASSERT(testUnescapingHelper(L"%0a", L"\x0d\x0a", PLUS_DONT_TOUCH, URI_BR_TO_WINDOWS)); + TEST_ASSERT(testUnescapingHelper(L"%0a", L"\x0d", PLUS_DONT_TOUCH, URI_BR_TO_MAC)); + TEST_ASSERT(testUnescapingHelper(L"%0a", L"\x0a", PLUS_DONT_TOUCH, URI_BR_DONT_TOUCH)); + + TEST_ASSERT(testUnescapingHelper(L"%0a%0a", L"\x0a\x0a", PLUS_DONT_TOUCH, URI_BR_TO_UNIX)); + TEST_ASSERT(testUnescapingHelper(L"%0a%0a", L"\x0d\x0a\x0d\x0a", PLUS_DONT_TOUCH, URI_BR_TO_WINDOWS)); + TEST_ASSERT(testUnescapingHelper(L"%0a%0a", L"\x0d\x0d", PLUS_DONT_TOUCH, URI_BR_TO_MAC)); + TEST_ASSERT(testUnescapingHelper(L"%0a%0a", L"\x0a\x0a", PLUS_DONT_TOUCH, URI_BR_DONT_TOUCH)); + + + TEST_ASSERT(testUnescapingHelper(L"%0d%0a", L"\x0a", PLUS_DONT_TOUCH, URI_BR_TO_UNIX)); + TEST_ASSERT(testUnescapingHelper(L"%0d%0a", L"\x0d\x0a", PLUS_DONT_TOUCH, URI_BR_TO_WINDOWS)); + TEST_ASSERT(testUnescapingHelper(L"%0d%0a", L"\x0d", PLUS_DONT_TOUCH, URI_BR_TO_MAC)); + TEST_ASSERT(testUnescapingHelper(L"%0d%0a", L"\x0d\x0a", PLUS_DONT_TOUCH, URI_BR_DONT_TOUCH)); + + TEST_ASSERT(testUnescapingHelper(L"%0d%0a%0a", L"\x0a\x0a", PLUS_DONT_TOUCH, URI_BR_TO_UNIX)); + TEST_ASSERT(testUnescapingHelper(L"%0d%0a%0a", L"\x0d\x0a\x0d\x0a", PLUS_DONT_TOUCH, URI_BR_TO_WINDOWS)); + TEST_ASSERT(testUnescapingHelper(L"%0d%0a%0a", L"\x0d\x0d", PLUS_DONT_TOUCH, URI_BR_TO_MAC)); + TEST_ASSERT(testUnescapingHelper(L"%0d%0a%0a", L"\x0d\x0a\x0a", PLUS_DONT_TOUCH, URI_BR_DONT_TOUCH)); + + TEST_ASSERT(testUnescapingHelper(L"%0d%0a%0d", L"\x0a\x0a", PLUS_DONT_TOUCH, URI_BR_TO_UNIX)); + TEST_ASSERT(testUnescapingHelper(L"%0d%0a%0d", L"\x0d\x0a\x0d\x0a", PLUS_DONT_TOUCH, URI_BR_TO_WINDOWS)); + TEST_ASSERT(testUnescapingHelper(L"%0d%0a%0d", L"\x0d\x0d", PLUS_DONT_TOUCH, URI_BR_TO_MAC)); + TEST_ASSERT(testUnescapingHelper(L"%0d%0a%0d", L"\x0d\x0a\x0d", PLUS_DONT_TOUCH, URI_BR_DONT_TOUCH)); + + TEST_ASSERT(testUnescapingHelper(L"%0d%0a%0d%0a", L"\x0a\x0a", PLUS_DONT_TOUCH, URI_BR_TO_UNIX)); + TEST_ASSERT(testUnescapingHelper(L"%0d%0a%0d%0a", L"\x0d\x0a\x0d\x0a", PLUS_DONT_TOUCH, URI_BR_TO_WINDOWS)); + TEST_ASSERT(testUnescapingHelper(L"%0d%0a%0d%0a", L"\x0d\x0d", PLUS_DONT_TOUCH, URI_BR_TO_MAC)); + TEST_ASSERT(testUnescapingHelper(L"%0d%0a%0d%0a", L"\x0d\x0a\x0d\x0a", PLUS_DONT_TOUCH, URI_BR_DONT_TOUCH)); + + + TEST_ASSERT(testUnescapingHelper(L"%0a%0d", L"\x0a\x0a", PLUS_DONT_TOUCH, URI_BR_TO_UNIX)); + TEST_ASSERT(testUnescapingHelper(L"%0a%0d", L"\x0d\x0a\x0d\x0a", PLUS_DONT_TOUCH, URI_BR_TO_WINDOWS)); + TEST_ASSERT(testUnescapingHelper(L"%0a%0d", L"\x0d\x0d", PLUS_DONT_TOUCH, URI_BR_TO_MAC)); + TEST_ASSERT(testUnescapingHelper(L"%0a%0d", L"\x0a\x0d", PLUS_DONT_TOUCH, URI_BR_DONT_TOUCH)); + + TEST_ASSERT(testUnescapingHelper(L"%0a%0d%0a", L"\x0a\x0a", PLUS_DONT_TOUCH, URI_BR_TO_UNIX)); + TEST_ASSERT(testUnescapingHelper(L"%0a%0d%0a", L"\x0d\x0a\x0d\x0a", PLUS_DONT_TOUCH, URI_BR_TO_WINDOWS)); + TEST_ASSERT(testUnescapingHelper(L"%0a%0d%0a", L"\x0d\x0d", PLUS_DONT_TOUCH, URI_BR_TO_MAC)); + TEST_ASSERT(testUnescapingHelper(L"%0a%0d%0a", L"\x0a\x0d\x0a", PLUS_DONT_TOUCH, URI_BR_DONT_TOUCH)); + + TEST_ASSERT(testUnescapingHelper(L"%0a%0d%0d", L"\x0a\x0a\x0a", PLUS_DONT_TOUCH, URI_BR_TO_UNIX)); + TEST_ASSERT(testUnescapingHelper(L"%0a%0d%0d", L"\x0d\x0a\x0d\x0a\x0d\x0a", PLUS_DONT_TOUCH, URI_BR_TO_WINDOWS)); + TEST_ASSERT(testUnescapingHelper(L"%0a%0d%0d", L"\x0d\x0d\x0d", PLUS_DONT_TOUCH, URI_BR_TO_MAC)); + TEST_ASSERT(testUnescapingHelper(L"%0a%0d%0d", L"\x0a\x0d\x0d", PLUS_DONT_TOUCH, URI_BR_DONT_TOUCH)); + + TEST_ASSERT(testUnescapingHelper(L"%0a%0d%0a%0d", L"\x0a\x0a\x0a", PLUS_DONT_TOUCH, URI_BR_TO_UNIX)); + TEST_ASSERT(testUnescapingHelper(L"%0a%0d%0a%0d", L"\x0d\x0a\x0d\x0a\x0d\x0a", PLUS_DONT_TOUCH, URI_BR_TO_WINDOWS)); + TEST_ASSERT(testUnescapingHelper(L"%0a%0d%0a%0d", L"\x0d\x0d\x0d", PLUS_DONT_TOUCH, URI_BR_TO_MAC)); + TEST_ASSERT(testUnescapingHelper(L"%0a%0d%0a%0d", L"\x0a\x0d\x0a\x0d", PLUS_DONT_TOUCH, URI_BR_DONT_TOUCH)); + } + + bool testAddBaseHelper(const wchar_t * base, const wchar_t * rel, const wchar_t * expectedResult) { + 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; + 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); +#endif + } + + uriFreeUriMembersW(&baseUri); + uriFreeUriMembersW(&relUri); + uriFreeUriMembersW(&expectedUri); + uriFreeUriMembersW(&transformedUri); + return equal; + } + + void testTrailingSlash() { + UriParserStateA stateA; + UriUriA uriA; + stateA.uri = &uriA; + // 0 3 01 + const char * const input = "abc" "/"; + TEST_ASSERT(0 == uriParseUriA(&stateA, input)); + + TEST_ASSERT(uriA.pathHead->text.first == input); + TEST_ASSERT(uriA.pathHead->text.afterLast == input + 3); + TEST_ASSERT(uriA.pathHead->next->text.first == uriA.pathHead->next->text.afterLast); + TEST_ASSERT(uriA.pathHead->next->next == NULL); + TEST_ASSERT(uriA.pathTail == uriA.pathHead->next); + uriFreeUriMembersA(&uriA); + } + + void testAddBase() { + // 5.4.1. Normal Examples + TEST_ASSERT(testAddBaseHelper(L"http://a/b/c/d;p?q", L"g:h", L"g:h")); + TEST_ASSERT(testAddBaseHelper(L"http://a/b/c/d;p?q", L"g", L"http://a/b/c/g")); + TEST_ASSERT(testAddBaseHelper(L"http://a/b/c/d;p?q", L"./g", L"http://a/b/c/g")); + TEST_ASSERT(testAddBaseHelper(L"http://a/b/c/d;p?q", L"g/", L"http://a/b/c/g/")); + TEST_ASSERT(testAddBaseHelper(L"http://a/b/c/d;p?q", L"/g", L"http://a/g")); + TEST_ASSERT(testAddBaseHelper(L"http://a/b/c/d;p?q", L"//g", L"http://g")); + TEST_ASSERT(testAddBaseHelper(L"http://a/b/c/d;p?q", L"?y", L"http://a/b/c/d;p?y")); + TEST_ASSERT(testAddBaseHelper(L"http://a/b/c/d;p?q", L"g?y", L"http://a/b/c/g?y")); + TEST_ASSERT(testAddBaseHelper(L"http://a/b/c/d;p?q", L"#s", L"http://a/b/c/d;p?q#s")); + TEST_ASSERT(testAddBaseHelper(L"http://a/b/c/d;p?q", L"g#s", L"http://a/b/c/g#s")); + TEST_ASSERT(testAddBaseHelper(L"http://a/b/c/d;p?q", L"g?y#s", L"http://a/b/c/g?y#s")); + TEST_ASSERT(testAddBaseHelper(L"http://a/b/c/d;p?q", L";x", L"http://a/b/c/;x")); + TEST_ASSERT(testAddBaseHelper(L"http://a/b/c/d;p?q", L"g;x", L"http://a/b/c/g;x")); + TEST_ASSERT(testAddBaseHelper(L"http://a/b/c/d;p?q", L"g;x?y#s", L"http://a/b/c/g;x?y#s")); + TEST_ASSERT(testAddBaseHelper(L"http://a/b/c/d;p?q", L"", L"http://a/b/c/d;p?q")); + TEST_ASSERT(testAddBaseHelper(L"http://a/b/c/d;p?q", L".", L"http://a/b/c/")); + TEST_ASSERT(testAddBaseHelper(L"http://a/b/c/d;p?q", L"./", L"http://a/b/c/")); + TEST_ASSERT(testAddBaseHelper(L"http://a/b/c/d;p?q", L"..", L"http://a/b/")); + TEST_ASSERT(testAddBaseHelper(L"http://a/b/c/d;p?q", L"../", L"http://a/b/")); + TEST_ASSERT(testAddBaseHelper(L"http://a/b/c/d;p?q", L"../g", L"http://a/b/g")); + TEST_ASSERT(testAddBaseHelper(L"http://a/b/c/d;p?q", L"../..", L"http://a/")); + TEST_ASSERT(testAddBaseHelper(L"http://a/b/c/d;p?q", L"../../", L"http://a/")); + TEST_ASSERT(testAddBaseHelper(L"http://a/b/c/d;p?q", L"../../g", L"http://a/g")); + + // 5.4.2. Abnormal Examples + TEST_ASSERT(testAddBaseHelper(L"http://a/b/c/d;p?q", L"../../../g", L"http://a/g")); + TEST_ASSERT(testAddBaseHelper(L"http://a/b/c/d;p?q", L"../../../../g", L"http://a/g")); + TEST_ASSERT(testAddBaseHelper(L"http://a/b/c/d;p?q", L"/./g", L"http://a/g")); + TEST_ASSERT(testAddBaseHelper(L"http://a/b/c/d;p?q", L"/../g", L"http://a/g")); + TEST_ASSERT(testAddBaseHelper(L"http://a/b/c/d;p?q", L"g.", L"http://a/b/c/g.")); + TEST_ASSERT(testAddBaseHelper(L"http://a/b/c/d;p?q", L".g", L"http://a/b/c/.g")); + TEST_ASSERT(testAddBaseHelper(L"http://a/b/c/d;p?q", L"g..", L"http://a/b/c/g..")); + TEST_ASSERT(testAddBaseHelper(L"http://a/b/c/d;p?q", L"..g", L"http://a/b/c/..g")); + TEST_ASSERT(testAddBaseHelper(L"http://a/b/c/d;p?q", L"./../g", L"http://a/b/g")); + TEST_ASSERT(testAddBaseHelper(L"http://a/b/c/d;p?q", L"./g/.", L"http://a/b/c/g/")); + TEST_ASSERT(testAddBaseHelper(L"http://a/b/c/d;p?q", L"g/./h", L"http://a/b/c/g/h")); + TEST_ASSERT(testAddBaseHelper(L"http://a/b/c/d;p?q", L"g/../h", L"http://a/b/c/h")); + TEST_ASSERT(testAddBaseHelper(L"http://a/b/c/d;p?q", L"g;x=1/./y", L"http://a/b/c/g;x=1/y")); + TEST_ASSERT(testAddBaseHelper(L"http://a/b/c/d;p?q", L"g;x=1/../y", L"http://a/b/c/y")); + TEST_ASSERT(testAddBaseHelper(L"http://a/b/c/d;p?q", L"g?y/./x", L"http://a/b/c/g?y/./x")); + TEST_ASSERT(testAddBaseHelper(L"http://a/b/c/d;p?q", L"g?y/../x", L"http://a/b/c/g?y/../x")); + TEST_ASSERT(testAddBaseHelper(L"http://a/b/c/d;p?q", L"g#s/./x", L"http://a/b/c/g#s/./x")); + TEST_ASSERT(testAddBaseHelper(L"http://a/b/c/d;p?q", L"g#s/../x", L"http://a/b/c/g#s/../x")); + TEST_ASSERT(testAddBaseHelper(L"http://a/b/c/d;p?q", L"http:g", L"http:g")); + + // Bug related to absolutePath flag set despite presence of host + TEST_ASSERT(testAddBaseHelper(L"http://a/b/c/d;p?q", L"/", L"http://a/")); + TEST_ASSERT(testAddBaseHelper(L"http://a/b/c/d;p?q", L"/g/", L"http://a/g/")); + } + + 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); +#endif + } + + // Back to string, _exact_ limit + const int len = static_cast(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; + } + + void testToString() { + // Scheme + TEST_ASSERT(testToStringHelper(L"ftp://localhost/")); + // UserInfo + TEST_ASSERT(testToStringHelper(L"http://user:pass@localhost/")); + // IPv4 + TEST_ASSERT(testToStringHelper(L"http://123.0.1.255/")); + // IPv6 + TEST_ASSERT(testToStringHelper(L"http://[abcd:abcd:abcd:abcd:abcd:abcd:abcd:abcd]/")); + // IPvFuture + TEST_ASSERT(testToStringHelper(L"http://[vA.123456]/")); + // Port + TEST_ASSERT(testToStringHelper(L"http://example.com:123/")); + // Path + TEST_ASSERT(testToStringHelper(L"http://example.com")); + TEST_ASSERT(testToStringHelper(L"http://example.com/")); + TEST_ASSERT(testToStringHelper(L"http://example.com/abc/")); + TEST_ASSERT(testToStringHelper(L"http://example.com/abc/def")); + TEST_ASSERT(testToStringHelper(L"http://example.com/abc/def/")); + TEST_ASSERT(testToStringHelper(L"http://example.com//")); + TEST_ASSERT(testToStringHelper(L"http://example.com/./..")); + // Query + TEST_ASSERT(testToStringHelper(L"http://example.com/?abc")); + // Fragment + TEST_ASSERT(testToStringHelper(L"http://example.com/#abc")); + TEST_ASSERT(testToStringHelper(L"http://example.com/?def#abc")); + + // Relative + TEST_ASSERT(testToStringHelper(L"a")); + TEST_ASSERT(testToStringHelper(L"a/")); + TEST_ASSERT(testToStringHelper(L"/a")); + TEST_ASSERT(testToStringHelper(L"/a/")); + TEST_ASSERT(testToStringHelper(L"abc")); + TEST_ASSERT(testToStringHelper(L"abc/")); + TEST_ASSERT(testToStringHelper(L"/abc")); + TEST_ASSERT(testToStringHelper(L"/abc/")); + TEST_ASSERT(testToStringHelper(L"a/def")); + TEST_ASSERT(testToStringHelper(L"a/def/")); + TEST_ASSERT(testToStringHelper(L"/a/def")); + TEST_ASSERT(testToStringHelper(L"/a/def/")); + TEST_ASSERT(testToStringHelper(L"abc/def")); + TEST_ASSERT(testToStringHelper(L"abc/def/")); + TEST_ASSERT(testToStringHelper(L"/abc/def")); + TEST_ASSERT(testToStringHelper(L"/abc/def/")); + TEST_ASSERT(testToStringHelper(L"/")); + TEST_ASSERT(testToStringHelper(L"//a/")); + TEST_ASSERT(testToStringHelper(L".")); + TEST_ASSERT(testToStringHelper(L"./")); + TEST_ASSERT(testToStringHelper(L"/.")); + TEST_ASSERT(testToStringHelper(L"/./")); + TEST_ASSERT(testToStringHelper(L"")); + TEST_ASSERT(testToStringHelper(L"./abc/def")); + TEST_ASSERT(testToStringHelper(L"?query")); + TEST_ASSERT(testToStringHelper(L"#fragment")); + TEST_ASSERT(testToStringHelper(L"?query#fragment")); + + // Tests for bugs from the past + TEST_ASSERT(testToStringHelper(L"f:/.//g")); + } + + void testToString_Bug1950126() { + 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; + TEST_ASSERT(URI_SUCCESS == uriParseUriW(&state, uriOneString)); + state.uri = &uriTwo; + TEST_ASSERT(URI_SUCCESS == uriParseUriW(&state, uriTwoString)); + TEST_ASSERT(URI_FALSE == uriEqualsUriW(&uriOne, &uriTwo)); + uriFreeUriMembersW(&uriOne); + uriFreeUriMembersW(&uriTwo); + + TEST_ASSERT(testToStringHelper(uriOneString)); + TEST_ASSERT(testToStringHelper(uriTwoString)); + } + + 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; + } + + // 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; + } + + void testToStringCharsRequired() { + TEST_ASSERT(testToStringCharsRequiredHelper(L"http://www.example.com/")); + TEST_ASSERT(testToStringCharsRequiredHelper(L"http://www.example.com:80/")); + TEST_ASSERT(testToStringCharsRequiredHelper(L"http://user:pass@www.example.com/")); + TEST_ASSERT(testToStringCharsRequiredHelper(L"http://www.example.com/index.html")); + TEST_ASSERT(testToStringCharsRequiredHelper(L"http://www.example.com/?abc")); + TEST_ASSERT(testToStringCharsRequiredHelper(L"http://www.example.com/#def")); + TEST_ASSERT(testToStringCharsRequiredHelper(L"http://www.example.com/?abc#def")); + TEST_ASSERT(testToStringCharsRequiredHelper(L"/test")); + TEST_ASSERT(testToStringCharsRequiredHelper(L"test")); + } + + 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); + } + + void testNormalizeSyntaxMaskRequired() { + TEST_ASSERT(testNormalizeMaskHelper(L"http://localhost/", URI_NORMALIZED)); + TEST_ASSERT(testNormalizeMaskHelper(L"httP://localhost/", URI_NORMALIZE_SCHEME)); + TEST_ASSERT(testNormalizeMaskHelper(L"http://%0d@localhost/", URI_NORMALIZE_USER_INFO)); + TEST_ASSERT(testNormalizeMaskHelper(L"http://localhosT/", URI_NORMALIZE_HOST)); + TEST_ASSERT(testNormalizeMaskHelper(L"http://localhost/./abc", URI_NORMALIZE_PATH)); + TEST_ASSERT(testNormalizeMaskHelper(L"http://localhost/?AB%43", URI_NORMALIZE_QUERY)); + TEST_ASSERT(testNormalizeMaskHelper(L"http://localhost/#AB%43", URI_NORMALIZE_FRAGMENT)); + } + + bool testNormalizeSyntaxHelper(const wchar_t * uriText, const wchar_t * expectedNormalized, + unsigned int mask = static_cast(-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; + } + + void testNormalizeSyntax() { + TEST_ASSERT(testNormalizeSyntaxHelper( + L"eXAMPLE://a/./b/../b/%63/%7bfoo%7d", + L"example://a/b/c/%7Bfoo%7D")); + + // Testcase by Adrian Manrique + TEST_ASSERT(testNormalizeSyntaxHelper( + L"http://examp%4Ce.com/", + L"http://example.com/")); + + // Testcase by Adrian Manrique + TEST_ASSERT(testNormalizeSyntaxHelper( + L"http://example.com/a/b/%2E%2E/", + L"http://example.com/a/")); + + // Reported by Adrian Manrique + TEST_ASSERT(testNormalizeSyntaxHelper( + L"http://user:pass@SOMEHOST.COM:123", + L"http://user:pass@somehost.com:123")); + + TEST_ASSERT(testNormalizeSyntaxHelper( + L"HTTP://a:b@HOST:123/./1/2/../%41?abc#def", + L"http://a:b@host:123/1/A?abc#def")); + + TEST_ASSERT(testNormalizeSyntaxHelper( + L"../../abc", + L"../../abc")); + + TEST_ASSERT(testNormalizeSyntaxHelper( + L"../../abc/..", + L"../../")); + + TEST_ASSERT(testNormalizeSyntaxHelper( + L"../../abc/../def", + L"../../def")); + + TEST_ASSERT(testNormalizeSyntaxHelper( + L"abc/..", + L"")); + + TEST_ASSERT(testNormalizeSyntaxHelper( + L"abc/../", + L"")); + + TEST_ASSERT(testNormalizeSyntaxHelper( + L"../../abc/./def", + L"../../abc/def")); + + TEST_ASSERT(testNormalizeSyntaxHelper( + L"./def", + L"def")); + + TEST_ASSERT(testNormalizeSyntaxHelper( + L"def/.", + L"def/")); + + TEST_ASSERT(testNormalizeSyntaxHelper( + L"./abc:def", + L"./abc:def")); + } + + void testNormalizeSyntaxComponents() { + TEST_ASSERT(testNormalizeSyntaxHelper( + L"HTTP://%41@EXAMPLE.ORG/../a?%41#%41", + L"http://%41@EXAMPLE.ORG/../a?%41#%41", + URI_NORMALIZE_SCHEME)); + + TEST_ASSERT(testNormalizeSyntaxHelper( + L"HTTP://%41@EXAMPLE.ORG/../a?%41#%41", + L"HTTP://A@EXAMPLE.ORG/../a?%41#%41", + URI_NORMALIZE_USER_INFO)); + + TEST_ASSERT(testNormalizeSyntaxHelper( + L"HTTP://%41@EXAMPLE.ORG/../a?%41#%41", + L"HTTP://%41@example.org/../a?%41#%41", + URI_NORMALIZE_HOST)); + + TEST_ASSERT(testNormalizeSyntaxHelper( + L"HTTP://%41@EXAMPLE.ORG/../a?%41#%41", + L"HTTP://%41@EXAMPLE.ORG/a?%41#%41", + URI_NORMALIZE_PATH)); + + TEST_ASSERT(testNormalizeSyntaxHelper( + L"HTTP://%41@EXAMPLE.ORG/../a?%41#%41", + L"HTTP://%41@EXAMPLE.ORG/../a?A#%41", + URI_NORMALIZE_QUERY)); + + TEST_ASSERT(testNormalizeSyntaxHelper( + L"HTTP://%41@EXAMPLE.ORG/../a?%41#%41", + L"HTTP://%41@EXAMPLE.ORG/../a?%41#A", + URI_NORMALIZE_FRAGMENT)); + } + + void testNormalizeCrash_Bug20080224() { + UriParserStateW stateW; + int res; + UriUriW testUri; + stateW.uri = &testUri; + + res = uriParseUriW(&stateW, L"http://example.org/abc//../def"); + TEST_ASSERT(res == 0); + + // First call will make us owner of copied memory + res = uriNormalizeSyntaxExW(&testUri, URI_NORMALIZE_SCHEME); + TEST_ASSERT(res == 0); + res = uriNormalizeSyntaxExW(&testUri, URI_NORMALIZE_HOST); + TEST_ASSERT(res == 0); + + // Frees empty path segment -> crash + res = uriNormalizeSyntaxW(&testUri); + TEST_ASSERT(res == 0); + + uriFreeUriMembersW(&testUri); + } + + void testFilenameUriConversionHelper(const wchar_t * filename, + const wchar_t * uriString, bool forUnix) { + const int prefixLen = forUnix ? 7 : 8; + + // 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, uriString); +#endif + TEST_ASSERT(!wcscmp(uriBuffer, uriString)); + 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 + TEST_ASSERT(!wcscmp(filenameBuffer, filename)); + delete [] filenameBuffer; + } + + void testFilenameUriConversion() { + const bool FOR_UNIX = true; + const bool FOR_WINDOWS = false; + testFilenameUriConversionHelper(L"/bin/bash", L"file:///bin/bash", FOR_UNIX); + testFilenameUriConversionHelper(L"./configure", L"./configure", FOR_UNIX); + + testFilenameUriConversionHelper(L"E:\\Documents and Settings", L"file:///E:/Documents%20and%20Settings", 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"abc def", L"abc%20def", FOR_WINDOWS); + testFilenameUriConversionHelper(L"abc def", L"abc%20def", FOR_UNIX); + } + + void testCrash_FreeUriMembers_Bug20080116() { + // Testcase by Adrian Manrique + UriParserStateA state; + UriUriA uri; + state.uri = &uri; + uriParseUriA(&state, "http://test/?"); + uriNormalizeSyntaxA(&uri); + uriFreeUriMembersA(&uri); + + TEST_ASSERT(true); + } + + void testCrash_Report2418192() { + // Testcase by Harvey Vrsalovic + helperTestQueryString("http://svcs.cnn.com/weather/wrapper.jsp?&csiID=csi1", 1); + } + + void testPervertedQueryString() { + helperTestQueryString("http://example.org/?&&=&&&=&&&&==&===&====", 5); + } + + void helperTestQueryString(char const * uriString, int pairsExpected) { + UriParserStateA state; + UriUriA uri; + state.uri = &uri; + int res = uriParseUriA(&state, uriString); + TEST_ASSERT(res == URI_SUCCESS); + + UriQueryListA * queryList = NULL; + int itemCount = 0; + + res = uriDissectQueryMallocA(&queryList, &itemCount, + uri.query.first, uri.query.afterLast); + TEST_ASSERT(res == URI_SUCCESS); + TEST_ASSERT(queryList != NULL); + TEST_ASSERT(itemCount == pairsExpected); + uriFreeQueryListA(queryList); + uriFreeUriMembersA(&uri); + } + + void testCrash_MakeOwner_Bug20080207() { + // 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) { + TEST_ASSERT(false); + } + if (uriNormalizeSyntaxA(&sourceUri) != 0) { + TEST_ASSERT(false); + } + uriFreeUriMembersA(&sourceUri); + TEST_ASSERT(true); + } + + 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); + TEST_ASSERT(res == URI_SUCCESS); + TEST_ASSERT(itemCount == expectedItemCount); + TEST_ASSERT((queryList == NULL) == (expectedItemCount == 0)); + + if (expectedItemCount != 0) { + // First + int charsRequired; + res = uriComposeQueryCharsRequiredExW(queryList, &charsRequired, spacePlusConversion, + normalizeBreaks); + TEST_ASSERT(res == URI_SUCCESS); + TEST_ASSERT(charsRequired >= (int)wcslen(input)); + + wchar_t * recomposed = new wchar_t[charsRequired + 1]; + int charsWritten; + res = uriComposeQueryExW(recomposed, queryList, charsRequired + 1, + &charsWritten, spacePlusConversion, normalizeBreaks); + TEST_ASSERT(res == URI_SUCCESS); + TEST_ASSERT(charsWritten <= charsRequired); + TEST_ASSERT(charsWritten == (int)wcslen(input) + 1); + TEST_ASSERT(!wcscmp(input, recomposed)); + delete [] recomposed; + + recomposed = NULL; + res = uriComposeQueryMallocW(&recomposed, queryList); + TEST_ASSERT(res == URI_SUCCESS); + TEST_ASSERT(recomposed != NULL); + TEST_ASSERT(charsWritten == (int)wcslen(input) + 1); + TEST_ASSERT(!wcscmp(input, recomposed)); + free(recomposed); + } + + uriFreeQueryListW(queryList); + } + + void testQueryList() { + 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); + } + + 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)); + TEST_ASSERT(res == URI_SUCCESS); + TEST_ASSERT(queryList != NULL); + TEST_ASSERT(itemCount == 1); + TEST_ASSERT(!strcmp(queryList->key, unescapedKey)); + TEST_ASSERT(!strcmp(queryList->value, unescapedValue)); + + char * recomposed; + res = uriComposeQueryMallocA(&recomposed, queryList); + TEST_ASSERT(res == URI_SUCCESS); + TEST_ASSERT(recomposed != NULL); + TEST_ASSERT(!strcmp(recomposed, (fixed != NULL) ? fixed : pair)); + free(recomposed); + uriFreeQueryListA(queryList); + } + + void 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"); + } + + void testQueryDissection_Bug3590761() { + int res; + UriQueryListA * queryList; + int itemCount; + const char * const pair = "q=hello&x=&y="; + + res = uriDissectQueryMallocA(&queryList, &itemCount, pair, pair + strlen(pair)); + TEST_ASSERT(res == URI_SUCCESS); + TEST_ASSERT(queryList != NULL); + TEST_ASSERT(itemCount == 3); + + TEST_ASSERT(!strcmp(queryList->key, "q")); + TEST_ASSERT(!strcmp(queryList->value, "hello")); + + TEST_ASSERT(!strcmp(queryList->next->key, "x")); + TEST_ASSERT(!strcmp(queryList->next->value, "")); + + TEST_ASSERT(!strcmp(queryList->next->next->key, "y")); + TEST_ASSERT(!strcmp(queryList->next->next->value, "")); + + TEST_ASSERT(! queryList->next->next->next); + + uriFreeQueryListA(queryList); + } + + void testFreeCrash_Bug20080827() { + char const * const sourceUri = "abc"; + char const * const baseUri = "http://www.example.org/"; + + int res; + UriParserStateA state; + UriUriA absoluteDest; + UriUriA relativeSource; + UriUriA absoluteBase; + + state.uri = &relativeSource; + res = uriParseUriA(&state, sourceUri); + TEST_ASSERT(res == URI_SUCCESS); + + state.uri = &absoluteBase; + res = uriParseUriA(&state, baseUri); + TEST_ASSERT(res == URI_SUCCESS); + + res = uriRemoveBaseUriA(&absoluteDest, &relativeSource, &absoluteBase, URI_FALSE); + TEST_ASSERT(res == URI_ERROR_REMOVEBASE_REL_SOURCE); + + uriFreeUriMembersA(&relativeSource); + uriFreeUriMembersA(&absoluteBase); + uriFreeUriMembersA(&absoluteDest); // Crashed here + } + + void testParseInvalid_Bug16() { + UriParserStateA stateA; + UriUriA uriA; + stateA.uri = &uriA; + const char * const input = "A>B"; + + const int res = uriParseUriA(&stateA, input); + + TEST_ASSERT(res == URI_ERROR_SYNTAX); + TEST_ASSERT(stateA.errorPos == input + 1); + TEST_ASSERT(stateA.errorCode == URI_ERROR_SYNTAX); /* failed previously */ + + uriFreeUriMembersA(&uriA); + } +}; + + + +int main() { + Suite suite; + suite.add(auto_ptr(new UriSuite())); + suite.add(auto_ptr(new FourSuite())); + TextOutput output(TextOutput::Verbose); + return suite.run(output, false) ? 0 : 1; +} -- cgit v1.2.3