diff --git a/src/uri/uri.cc b/src/uri/uri.cc index cf94de7fd..dd06f9608 100644 --- a/src/uri/uri.cc +++ b/src/uri/uri.cc @@ -316,6 +316,11 @@ auto URI::recompose_without_fragment() const -> std::optional { } } + const auto user_info{this->userinfo()}; + if (user_info.has_value()) { + result << user_info.value() << "@"; + } + // Host const auto result_host{this->host()}; if (result_host.has_value()) { diff --git a/test/uri/CMakeLists.txt b/test/uri/CMakeLists.txt index 81ca77f0e..d6372f783 100644 --- a/test/uri/CMakeLists.txt +++ b/test/uri/CMakeLists.txt @@ -12,6 +12,7 @@ add_executable(sourcemeta_jsontoolkit_uri_unit uri_is_tag_test.cc uri_recompose_test.cc uri_recompose_without_fragment_test.cc + uri_normalize_test.cc uri_canonicalize_test.cc uri_resolve_from_test.cc uri_relative_to_test.cc diff --git a/test/uri/uri_normalize_test.cc b/test/uri/uri_normalize_test.cc new file mode 100644 index 000000000..3e65ad25d --- /dev/null +++ b/test/uri/uri_normalize_test.cc @@ -0,0 +1,90 @@ +#include +#include + +/* + * RFC 3986 normalization tests + * + * We test the normalization through the .recompose() API, as the + * URI is normalized during construction. + */ + +// Inspired from https://cr.openjdk.org/~dfuchs/writeups/updating-uri/ + +TEST(URI_normalize, rfc3986_1) { + const sourcemeta::jsontoolkit::URI uri{"s://h/a/../../b"}; + EXPECT_EQ(uri.recompose(), "s://h/b"); +} + +// Inspired from +// https://github.com/uriparser/uriparser/blob/master/test/test.cpp#L1438 + +TEST(URI_normalize, rfc3986_2) { + const sourcemeta::jsontoolkit::URI uri{"eXAMPLE://a/./b/../b/%63/%7bfoo%7d"}; + EXPECT_EQ(uri.recompose(), "example://a/b/c/%7Bfoo%7D"); +} + +TEST(URI_normalize, percent_encoding) { + const sourcemeta::jsontoolkit::URI uri{"http://examp%4Ce.com/"}; + EXPECT_EQ(uri.recompose(), "http://example.com/"); +} + +TEST(URI_normalize, dot_segments) { + const sourcemeta::jsontoolkit::URI uri{"http://example.com/a/b/%2E%2E/"}; + EXPECT_EQ(uri.recompose(), "http://example.com/a/"); +} + +TEST(URI_normalize, case_normalization) { + const sourcemeta::jsontoolkit::URI uri{"http://user:pass@SOMEHOST.COM:123"}; + EXPECT_EQ(uri.recompose(), "http://user:pass@somehost.com:123"); +} + +TEST(URI_normalize, complex_case) { + const sourcemeta::jsontoolkit::URI uri{ + "HTTP://a:b@HOST:123/./1/2/../%41?abc#def"}; + EXPECT_EQ(uri.recompose(), "http://a:b@host:123/1/A?abc#def"); +} + +TEST(URI_normalize, relative_path_1) { + const sourcemeta::jsontoolkit::URI uri{"../../abc"}; + EXPECT_EQ(uri.recompose(), "../../abc"); +} + +TEST(URI_normalize, relative_path_2) { + const sourcemeta::jsontoolkit::URI uri{"../../abc/.."}; + EXPECT_EQ(uri.recompose(), "../../"); +} + +TEST(URI_normalize, relative_path_3) { + const sourcemeta::jsontoolkit::URI uri{"../../abc/../def"}; + EXPECT_EQ(uri.recompose(), "../../def"); +} + +TEST(URI_normalize, relative_path_4) { + const sourcemeta::jsontoolkit::URI uri{"abc/.."}; + EXPECT_EQ(uri.recompose(), ""); +} + +TEST(URI_normalize, relative_path_5) { + const sourcemeta::jsontoolkit::URI uri{"abc/../"}; + EXPECT_EQ(uri.recompose(), ""); +} + +TEST(URI_normalize, relative_path_6) { + const sourcemeta::jsontoolkit::URI uri{"../../abc/./def"}; + EXPECT_EQ(uri.recompose(), "../../abc/def"); +} + +TEST(URI_normalize, relative_path_7) { + const sourcemeta::jsontoolkit::URI uri{"./def"}; + EXPECT_EQ(uri.recompose(), "def"); +} + +TEST(URI_normalize, relative_path_8) { + const sourcemeta::jsontoolkit::URI uri{"def/."}; + EXPECT_EQ(uri.recompose(), "def/"); +} + +TEST(URI_normalize, relative_path_9) { + const sourcemeta::jsontoolkit::URI uri{"./abc:def"}; + EXPECT_EQ(uri.recompose(), "./abc:def"); +}