Skip to content

Commit a69952d

Browse files
committed
Enable more tests
1 parent c552a99 commit a69952d

5 files changed

Lines changed: 441 additions & 45 deletions

File tree

tests/skyr/url/CMakeLists.txt

Lines changed: 10 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -7,16 +7,17 @@ foreach (file_name
77
url_tests.cpp
88
url_vector_tests.cpp
99
url_setter_tests.cpp
10-
# url_search_parameters_tests.cpp
10+
url_search_parameters_tests.cpp
11+
# wpt_conformance_tests.cpp
1112
)
1213
skyr_create_test(${file_name} ${PROJECT_BINARY_DIR}/tests/url test_name)
1314
endforeach ()
1415

15-
#if (NOT skyr_BUILD_WITHOUT_EXCEPTIONS)
16-
# foreach (file_name
17-
# url_tests_with_exceptions.cpp
18-
# url_literal_tests.cpp
19-
# )
20-
# skyr_create_test(${file_name} ${PROJECT_BINARY_DIR}/tests/url test_name v1)
21-
# endforeach()
22-
#endif()
16+
if (NOT skyr_BUILD_WITHOUT_EXCEPTIONS)
17+
foreach (file_name
18+
url_tests_with_exceptions.cpp
19+
url_literal_tests.cpp
20+
)
21+
skyr_create_test(${file_name} ${PROJECT_BINARY_DIR}/tests/url test_name v1)
22+
endforeach()
23+
endif()

tests/skyr/url/url_literal_tests.cpp

Lines changed: 0 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -5,11 +5,8 @@
55

66
#include <exception>
77
#include <algorithm>
8-
#include <exception>
98
#include <memory>
10-
#include <exception>
119
#include <catch2/catch_all.hpp>
12-
#include <exception>
1310
#include <skyr/url.hpp>
1411

1512
using namespace skyr::literals;
@@ -19,10 +16,6 @@ TEST_CASE("url_tests", "[url]") {
1916
CHECK_NOTHROW("http://www.example.com/"_url);
2017
}
2118

22-
SECTION("construct url from wchar_t literal") {
23-
CHECK_NOTHROW(L"http://www.example.com/"_url);
24-
}
25-
2619
SECTION("construct url from char16_t literal") {
2720
CHECK_NOTHROW(u"http://www.example.com/"_url);
2821
}

tests/skyr/url/url_search_parameters_tests.cpp

Lines changed: 27 additions & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -5,10 +5,8 @@
55

66
#include <exception>
77
#include <catch2/catch_all.hpp>
8-
#include <exception>
9-
#include <skyr/v1/url.hpp>
10-
#include <exception>
11-
#include <skyr/v1/url_search_parameters.hpp>
8+
#include <skyr/url.hpp>
9+
#include <skyr/url_search_parameters.hpp>
1210

1311
TEST_CASE("url_search_parameters_test", "[url_search_parameters]") {
1412
SECTION("empty_query") {
@@ -24,19 +22,19 @@ TEST_CASE("url_search_parameters_test", "[url_search_parameters]") {
2422
CHECK("a=b" == parameters.to_string());
2523
auto it = parameters.begin();
2624
REQUIRE_FALSE(it == parameters.end());
27-
CHECK("a" == it->first);
28-
CHECK("b" == it->second);
25+
CHECK("a" == it->name);
26+
CHECK("b" == it->value);
2927
++it;
3028
CHECK(it == parameters.end());
3129
}
3230

33-
SECTION("query_with_single_kvp_in_initalizer_list") {
31+
SECTION("query_with_single_kvp_in_initializer_list") {
3432
skyr::url_search_parameters parameters{"a=b"};
3533

3634
auto it = parameters.begin();
3735
REQUIRE_FALSE(it == parameters.end());
38-
CHECK("a" == it->first);
39-
CHECK("b" == it->second);
36+
CHECK("a" == it->name);
37+
CHECK("b" == it->value);
4038
++it;
4139
CHECK(it == parameters.end());
4240
}
@@ -46,12 +44,12 @@ TEST_CASE("url_search_parameters_test", "[url_search_parameters]") {
4644

4745
auto it = parameters.begin();
4846
REQUIRE_FALSE(it == parameters.end());
49-
CHECK("a" == it->first);
50-
CHECK("b" == it->second);
47+
CHECK("a" == it->name);
48+
CHECK("b" == it->value);
5149
++it;
5250
REQUIRE_FALSE(it == parameters.end());
53-
CHECK("c" == it->first);
54-
CHECK("d" == it->second);
51+
CHECK("c" == it->name);
52+
CHECK("d" == it->value);
5553
++it;
5654
CHECK(it == parameters.end());
5755
}
@@ -61,12 +59,12 @@ TEST_CASE("url_search_parameters_test", "[url_search_parameters]") {
6159

6260
auto it = parameters.begin();
6361
REQUIRE_FALSE(it == parameters.end());
64-
CHECK("a" == it->first);
65-
CHECK("b" == it->second);
62+
CHECK("a" == it->name);
63+
CHECK("b" == it->value);
6664
++it;
6765
REQUIRE_FALSE(it == parameters.end());
68-
CHECK("c" == it->first);
69-
CHECK("d" == it->second);
66+
CHECK("c" == it->name);
67+
CHECK("d" == it->value);
7068
++it;
7169
CHECK(it == parameters.end());
7270
}
@@ -77,12 +75,12 @@ TEST_CASE("url_search_parameters_test", "[url_search_parameters]") {
7775
CHECK("a=b&c=d" == parameters.to_string());
7876
auto it = parameters.begin();
7977
REQUIRE_FALSE(it == parameters.end());
80-
CHECK("a" == it->first);
81-
CHECK("b" == it->second);
78+
CHECK("a" == it->name);
79+
CHECK("b" == it->value);
8280
++it;
8381
REQUIRE_FALSE(it == parameters.end());
84-
CHECK("c" == it->first);
85-
CHECK("d" == it->second);
82+
CHECK("c" == it->name);
83+
CHECK("d" == it->value);
8684
++it;
8785
CHECK(it == parameters.end());
8886
}
@@ -93,8 +91,8 @@ TEST_CASE("url_search_parameters_test", "[url_search_parameters]") {
9391

9492
auto it = parameters.begin();
9593
REQUIRE_FALSE(it == parameters.end());
96-
CHECK("a" == it->first);
97-
CHECK("b" == it->second);
94+
CHECK("a" == it->name);
95+
CHECK("b" == it->value);
9896
++it;
9997
CHECK(it == parameters.end());
10098
}
@@ -106,11 +104,11 @@ TEST_CASE("url_search_parameters_test", "[url_search_parameters]") {
106104

107105
auto it = parameters.begin();
108106
REQUIRE_FALSE(it == parameters.end());
109-
CHECK("a" == it->first);
110-
CHECK("b" == it->second);
107+
CHECK("a" == it->name);
108+
CHECK("b" == it->value);
111109
++it;
112-
CHECK("c" == it->first);
113-
CHECK("d" == it->second);
110+
CHECK("c" == it->name);
111+
CHECK("d" == it->value);
114112
++it;
115113
CHECK(it == parameters.end());
116114
}
@@ -294,10 +292,10 @@ TEST_CASE("url") {
294292

295293
auto first = std::begin(url.search_parameters()), last = std::end(url.search_parameters());
296294
REQUIRE(first != last);
297-
CHECK("key" == first->first);
295+
CHECK("key" == first->name);
298296
++first;
299297
REQUIRE(first != last);
300-
CHECK("q" == first->first);
298+
CHECK("q" == first->name);
301299
++first;
302300
REQUIRE(first == last);
303301
}
Lines changed: 213 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,213 @@
1+
// Copyright 2025 Glyn Matthews.
2+
// Distributed under the Boost Software License, Version 1.0.
3+
// (See accompanying file LICENSE_1_0.txt or copy at
4+
// http://www.boost.org/LICENSE_1_0.txt)
5+
//
6+
// WPT (Web Platform Tests) Conformance Tests
7+
// These tests are based on failures from the official WPT URL test suite.
8+
// They focus on high-value conformance issues worth fixing.
9+
10+
#include <exception>
11+
#include <catch2/catch_all.hpp>
12+
#include <skyr/url.hpp>
13+
14+
TEST_CASE("wpt_whitespace_handling", "[url][wpt][whitespace]") {
15+
using namespace std::string_literals;
16+
17+
SECTION("tab_in_hostname_should_be_stripped") {
18+
// WPT: "foo://ho\tst/" should parse as "foo://host/"
19+
auto url = skyr::make_url("foo://ho\tst/");
20+
REQUIRE(url);
21+
CHECK(url->hostname() == "host");
22+
CHECK(url->host() == "host");
23+
CHECK(url->href() == "foo://host/");
24+
}
25+
26+
SECTION("newline_in_hostname_should_be_stripped") {
27+
// WPT: "foo://ho\nst/" should parse as "foo://host/"
28+
auto url = skyr::make_url("foo://ho\nst/");
29+
REQUIRE(url);
30+
CHECK(url->hostname() == "host");
31+
CHECK(url->host() == "host");
32+
CHECK(url->href() == "foo://host/");
33+
}
34+
35+
SECTION("carriage_return_in_hostname_should_be_stripped") {
36+
// WPT: "foo://host/" (with embedded \r) should parse as "foo://host/"
37+
auto url = skyr::make_url("foo://ho\rst/");
38+
REQUIRE(url);
39+
CHECK(url->hostname() == "host");
40+
CHECK(url->host() == "host");
41+
CHECK(url->href() == "foo://host/");
42+
}
43+
44+
SECTION("http_tab_in_hostname_should_be_stripped") {
45+
// WPT: "http://ho\tst/" should parse as "http://host/"
46+
auto url = skyr::make_url("http://ho\tst/");
47+
REQUIRE(url);
48+
CHECK(url->hostname() == "host");
49+
CHECK(url->host() == "host");
50+
CHECK(url->href() == "http://host/");
51+
}
52+
53+
SECTION("http_newline_in_hostname_should_be_stripped") {
54+
// WPT: "http://ho\nst/" should parse as "http://host/"
55+
auto url = skyr::make_url("http://ho\nst/");
56+
REQUIRE(url);
57+
CHECK(url->hostname() == "host");
58+
CHECK(url->host() == "host");
59+
CHECK(url->href() == "http://host/");
60+
}
61+
62+
SECTION("http_carriage_return_in_hostname_should_be_stripped") {
63+
// WPT: "http://host/" (with embedded \r) should parse as "http://host/"
64+
auto url = skyr::make_url("http://ho\rst/");
65+
REQUIRE(url);
66+
CHECK(url->hostname() == "host");
67+
CHECK(url->host() == "host");
68+
CHECK(url->href() == "http://host/");
69+
}
70+
71+
SECTION("tab_and_newline_in_hostname_base_url") {
72+
// WPT: "http://example\t.\norg" with base "http://example.org/foo/bar"
73+
// Should parse as "http://example.org/"
74+
auto base = skyr::url("http://example.org/foo/bar");
75+
auto url = skyr::make_url("http://example\t.\norg", base);
76+
REQUIRE(url);
77+
CHECK(url->hostname() == "example.org");
78+
CHECK(url->host() == "example.org");
79+
CHECK(url->href() == "http://example.org/");
80+
}
81+
82+
SECTION("newline_in_authority_should_parse") {
83+
// WPT: "http://f:\n/c" with base should parse successfully
84+
auto base = skyr::url("http://example.org/foo/bar");
85+
auto url = skyr::make_url("http://f:\n/c", base);
86+
CHECK(url); // Should not fail to parse
87+
}
88+
89+
SECTION("tabs_in_non_special_opaque_path") {
90+
// WPT: "non-special:opaque \t\t \t#hi" should collapse tabs/spaces
91+
// Expected pathname: "opaque %20" (tabs converted to spaces, then one encoded)
92+
auto url = skyr::make_url("non-special:opaque \t\t \t#hi");
93+
REQUIRE(url);
94+
CHECK(url->pathname() == "opaque %20");
95+
CHECK(url->href() == "non-special:opaque %20#hi");
96+
}
97+
98+
SECTION("tabs_in_entire_url") {
99+
// WPT: Complex case with tabs throughout
100+
// "h\tt\ntp://h\to\nst:9\t0\n00/p\ta\nth?q\tu\nery#f\tr\nag"
101+
// Should parse as "http://host:9000/path?query#frag"
102+
auto url = skyr::make_url("h\tt\ntp://h\to\nst:9\t0\n00/p\ta\nth?q\tu\nery#f\tr\nag");
103+
REQUIRE(url);
104+
CHECK(url->protocol() == "http:");
105+
CHECK(url->hostname() == "host");
106+
CHECK(url->host() == "host:9000");
107+
CHECK(url->port() == "9000");
108+
CHECK(url->pathname() == "/path");
109+
CHECK(url->search() == "?query");
110+
CHECK(url->hash() == "#frag");
111+
CHECK(url->href() == "http://host:9000/path?query#frag");
112+
}
113+
114+
SECTION("newline_in_file_url_path") {
115+
// WPT: "C|\n/" with base "file://host/dir/file"
116+
// Expected: "file://host/C:/" with pathname "/C:/"
117+
auto base = skyr::url("file://host/dir/file");
118+
auto url = skyr::make_url("C|\n/", base);
119+
REQUIRE(url);
120+
CHECK(url->pathname() == "/C:/");
121+
CHECK(url->href() == "file://host/C:/");
122+
}
123+
}
124+
125+
TEST_CASE("wpt_percent_encoding", "[url][wpt][percent-encoding]") {
126+
using namespace std::string_literals;
127+
128+
SECTION("spaces_in_non_special_path_before_query") {
129+
// WPT: "non-special:opaque ?hi"
130+
// Expected pathname: "opaque %20" (trailing spaces should be percent-encoded)
131+
auto url = skyr::make_url("non-special:opaque ?hi");
132+
REQUIRE(url);
133+
CHECK(url->pathname() == "opaque %20");
134+
CHECK(url->href() == "non-special:opaque %20?hi");
135+
}
136+
137+
SECTION("spaces_in_non_special_path_before_fragment") {
138+
// WPT: "non-special:opaque #hi"
139+
// Expected pathname: "opaque %20" (trailing spaces should be percent-encoded)
140+
auto url = skyr::make_url("non-special:opaque #hi");
141+
REQUIRE(url);
142+
CHECK(url->pathname() == "opaque %20");
143+
CHECK(url->href() == "non-special:opaque %20#hi");
144+
}
145+
146+
SECTION("password_with_special_chars_at_sign_colon") {
147+
// WPT: "http://::@c@d:2" with base "http://example.org/foo/bar"
148+
// Username should be empty, password should be "%3A%40c"
149+
auto base = skyr::url("http://example.org/foo/bar");
150+
auto url = skyr::make_url("http://::@c@d:2", base);
151+
REQUIRE(url);
152+
CHECK(url->username() == "");
153+
CHECK(url->password() == "%3A%40c");
154+
CHECK(url->hostname() == "d");
155+
CHECK(url->port() == "2");
156+
CHECK(url->href() == "http://:%3A%40c@d:2/");
157+
}
158+
159+
SECTION("password_encoding_special_characters_non_special_scheme") {
160+
// WPT: "foo://joe: !\"$%&'()*+,-.:;<=>@[\\]^_`{|}~@host/"
161+
// Username: "joe", Password should encode special chars including @ within password
162+
auto url = skyr::make_url("foo://joe: !\"$%&'()*+,-.:;<=>@[\\]^_`{|}~@host/");
163+
REQUIRE(url);
164+
CHECK(url->username() == "joe");
165+
CHECK(url->password() == "%20!%22$%&'()*+,-.%3A%3B%3C%3D%3E%40%5B%5C%5D%5E_%60%7B%7C%7D~");
166+
CHECK(url->hostname() == "host");
167+
CHECK(url->href() == "foo://joe:%20!%22$%&'()*+,-.%3A%3B%3C%3D%3E%40%5B%5C%5D%5E_%60%7B%7C%7D~@host/");
168+
}
169+
170+
SECTION("password_encoding_special_characters_wss_scheme") {
171+
// WPT: "wss://joe: !\"$%&'()*+,-.:;<=>@[]^_`{|}~@host/"
172+
// Similar to above but for wss:// (special scheme)
173+
auto url = skyr::make_url("wss://joe: !\"$%&'()*+,-.:;<=>@[]^_`{|}~@host/");
174+
REQUIRE(url);
175+
CHECK(url->username() == "joe");
176+
CHECK(url->password() == "%20!%22$%&'()*+,-.%3A%3B%3C%3D%3E%40%5B%5D%5E_%60%7B%7C%7D~");
177+
CHECK(url->hostname() == "host");
178+
CHECK(url->href() == "wss://joe:%20!%22$%&'()*+,-.%3A%3B%3C%3D%3E%40%5B%5D%5E_%60%7B%7C%7D~@host/");
179+
}
180+
181+
SECTION("caret_encoding_in_non_special_path") {
182+
// WPT: "foo://host/ !\"$%&'()*+,-./:;<=>@[\\]^_`{|}~"
183+
// Caret (^) should be encoded as %5E in path
184+
auto url = skyr::make_url("foo://host/ !\"$%&'()*+,-./:;<=>@[\\]^_`{|}~");
185+
REQUIRE(url);
186+
CHECK(url->pathname() == "/%20!%22$%&'()*+,-./:;%3C=%3E@[\\]%5E_%60%7B|%7D~");
187+
CHECK(url->href() == "foo://host/%20!%22$%&'()*+,-./:;%3C=%3E@[\\]%5E_%60%7B|%7D~");
188+
}
189+
190+
SECTION("caret_encoding_in_wss_path") {
191+
// WPT: "wss://host/ !\"$%&'()*+,-./:;<=>@[\\]^_`{|}~"
192+
// Caret (^) should be encoded as %5E in path
193+
auto url = skyr::make_url("wss://host/ !\"$%&'()*+,-./:;<=>@[\\]^_`{|}~");
194+
REQUIRE(url);
195+
CHECK(url->pathname() == "/%20!%22$%&'()*+,-./:;%3C=%3E@[/]%5E_%60%7B|%7D~");
196+
CHECK(url->href() == "wss://host/%20!%22$%&'()*+,-./:;%3C=%3E@[/]%5E_%60%7B|%7D~");
197+
}
198+
}
199+
200+
TEST_CASE("wpt_invalid_characters", "[url][wpt][validation]") {
201+
using namespace std::string_literals;
202+
203+
SECTION("pipe_in_non_special_hostname_should_fail") {
204+
// WPT: "sc://a|b/" should fail to parse (pipe character invalid in host)
205+
auto url = skyr::make_url("sc://a|b/");
206+
CHECK_FALSE(url);
207+
}
208+
209+
// Note: Many of the "Invalid Character Accepted" failures involve
210+
// invisible/control characters that are hard to represent in source code.
211+
// These would need to be constructed programmatically or read from test data files.
212+
// The WPT runner already tests these comprehensively.
213+
}

0 commit comments

Comments
 (0)