1/*
2 * Copyright 2016-2018, Andrew Lindesay, apl@lindesay.co.nz.
3 * Distributed under the terms of the MIT License.
4 */
5
6
7#include "NetworkUrlTest.h"
8
9#include <Url.h>
10
11#include <cppunit/TestCaller.h>
12#include <cppunit/TestSuite.h>
13
14
15NetworkUrlTest::NetworkUrlTest()
16{
17}
18
19
20NetworkUrlTest::~NetworkUrlTest()
21{
22}
23
24
25void
26NetworkUrlTest::setUp()
27{
28}
29
30
31void
32NetworkUrlTest::tearDown()
33{
34}
35
36
37// #pragma mark - General Tests
38
39/*
40This is the "happy days" tests that checks that a URL featuring all of the
41parsed elements successfully processes and the elements are present.
42*/
43
44void NetworkUrlTest::TestValidFullUrl()
45{
46	BUrl url("http://ewe:pea@www.something.co.nz:8888/some/path?key1=value1#fragment");
47	CPPUNIT_ASSERT(url.IsValid());
48	CPPUNIT_ASSERT(url.Protocol() == "http");
49	CPPUNIT_ASSERT(url.HasProtocol());
50	CPPUNIT_ASSERT(url.UserName() == "ewe");
51	CPPUNIT_ASSERT(url.HasUserName());
52	CPPUNIT_ASSERT(url.Password() == "pea");
53	CPPUNIT_ASSERT(url.HasPassword());
54	CPPUNIT_ASSERT(url.Host() == "www.something.co.nz");
55	CPPUNIT_ASSERT(url.HasHost());
56	CPPUNIT_ASSERT(url.Port() == 8888);
57	CPPUNIT_ASSERT(url.HasPort());
58	CPPUNIT_ASSERT(url.Path() == "/some/path");
59	CPPUNIT_ASSERT(url.HasPath());
60	CPPUNIT_ASSERT(url.Request() == "key1=value1");
61	CPPUNIT_ASSERT(url.HasRequest());
62	CPPUNIT_ASSERT(url.Fragment() == "fragment");
63	CPPUNIT_ASSERT(url.HasFragment());
64}
65
66
67void NetworkUrlTest::TestHostWithPathAndFragment()
68{
69	BUrl url("http://1.2.3.4/some/path#frag/ment");
70	CPPUNIT_ASSERT(url.IsValid());
71	CPPUNIT_ASSERT(url.Protocol() == "http");
72	CPPUNIT_ASSERT(url.HasProtocol());
73	CPPUNIT_ASSERT(!url.HasUserName());
74	CPPUNIT_ASSERT(!url.HasPassword());
75	CPPUNIT_ASSERT(url.Host() == "1.2.3.4");
76	CPPUNIT_ASSERT(url.HasHost());
77	CPPUNIT_ASSERT(!url.HasPort());
78	CPPUNIT_ASSERT(url.Path() == "/some/path");
79	CPPUNIT_ASSERT(url.HasPath());
80	CPPUNIT_ASSERT(!url.HasRequest());
81	CPPUNIT_ASSERT(url.Fragment() == "frag/ment");
82	CPPUNIT_ASSERT(url.HasFragment());
83}
84
85
86void NetworkUrlTest::TestHostWithFragment()
87{
88	BUrl url("http://1.2.3.4#frag/ment");
89	CPPUNIT_ASSERT(url.IsValid());
90	CPPUNIT_ASSERT(url.Protocol() == "http");
91	CPPUNIT_ASSERT(url.HasProtocol());
92	CPPUNIT_ASSERT(!url.HasUserName());
93	CPPUNIT_ASSERT(!url.HasPassword());
94	CPPUNIT_ASSERT(url.Host() == "1.2.3.4");
95	CPPUNIT_ASSERT(url.HasHost());
96	CPPUNIT_ASSERT(!url.HasPort());
97	CPPUNIT_ASSERT(url.HasPath()); // see Url.cpp - evidently an empty path is still a path?
98	CPPUNIT_ASSERT(!url.HasRequest());
99	CPPUNIT_ASSERT(url.Fragment() == "frag/ment");
100	CPPUNIT_ASSERT(url.HasFragment());
101}
102
103
104void NetworkUrlTest::TestIpv6HostPortPathAndRequest()
105{
106	BUrl url("http://[123:a3:0:E3::123]:8080/some/path?key1=value1");
107	CPPUNIT_ASSERT(url.IsValid());
108	CPPUNIT_ASSERT(url.Protocol() == "http");
109	CPPUNIT_ASSERT(url.HasProtocol());
110	CPPUNIT_ASSERT(!url.HasUserName());
111	CPPUNIT_ASSERT(!url.HasPassword());
112	CPPUNIT_ASSERT(url.Host() == "[123:a3:0:E3::123]");
113	CPPUNIT_ASSERT(url.HasHost());
114	CPPUNIT_ASSERT(url.Port() == 8080);
115	CPPUNIT_ASSERT(url.HasPort());
116	CPPUNIT_ASSERT(url.Path() == "/some/path");
117	CPPUNIT_ASSERT(url.HasPath());
118	CPPUNIT_ASSERT(url.Request() == "key1=value1");
119	CPPUNIT_ASSERT(url.HasRequest());
120	CPPUNIT_ASSERT(!url.HasFragment());
121}
122
123
124void NetworkUrlTest::TestFileUrl()
125{
126	BUrl url("file:///northisland/wellington/brooklyn/windturbine");
127	CPPUNIT_ASSERT(url.IsValid());
128	CPPUNIT_ASSERT(url.Protocol() == "file");
129	CPPUNIT_ASSERT(url.HasProtocol());
130	CPPUNIT_ASSERT(!url.HasUserName());
131	CPPUNIT_ASSERT(!url.HasPassword());
132	CPPUNIT_ASSERT(url.Host() == "");
133	CPPUNIT_ASSERT(url.HasHost());
134	CPPUNIT_ASSERT(!url.HasPort());
135	CPPUNIT_ASSERT(url.Path() == "/northisland/wellington/brooklyn/windturbine");
136	CPPUNIT_ASSERT(url.HasPath());
137	CPPUNIT_ASSERT(!url.HasRequest());
138	CPPUNIT_ASSERT(!url.HasFragment());
139}
140
141
142void NetworkUrlTest::TestDataUrl()
143{
144	BUrl url("data:image/png;base64,iVBORw0KGI12P4//8/w38GIErkJggg==");
145	CPPUNIT_ASSERT(url.IsValid());
146	CPPUNIT_ASSERT(url.Protocol() == "data");
147	CPPUNIT_ASSERT(!url.HasUserName());
148	CPPUNIT_ASSERT(!url.HasPassword());
149	CPPUNIT_ASSERT(!url.HasHost());
150	CPPUNIT_ASSERT(url.HasPath());
151	CPPUNIT_ASSERT(url.Path() == "image/png;base64,iVBORw0KGI12P4//8/w38GIErkJggg==");
152	CPPUNIT_ASSERT(!url.HasRequest());
153	CPPUNIT_ASSERT(!url.HasFragment());
154}
155
156
157// #pragma mark - Authority Tests (UserName, Password, Host, Port)
158
159
160void NetworkUrlTest::TestWithUserNameAndPasswordNoHostAndPort()
161{
162	BUrl url("wierd://tea:tree@/x");
163	CPPUNIT_ASSERT(url.IsValid());
164	CPPUNIT_ASSERT(url.Protocol() == "wierd");
165	CPPUNIT_ASSERT(url.HasProtocol());
166	CPPUNIT_ASSERT(url.UserName() == "tea");
167	CPPUNIT_ASSERT(url.HasUserName());
168	CPPUNIT_ASSERT(url.Password() == "tree");
169	CPPUNIT_ASSERT(url.HasPassword());
170	CPPUNIT_ASSERT(url.Host() == "");
171	CPPUNIT_ASSERT(url.HasHost()); // any authority means there "is a host" - see SetAuthority comment.
172	CPPUNIT_ASSERT(!url.HasPort());
173	CPPUNIT_ASSERT(url.Path() == "/x");
174	CPPUNIT_ASSERT(url.HasPath());
175	CPPUNIT_ASSERT(!url.HasRequest());
176	CPPUNIT_ASSERT(!url.HasFragment());
177}
178
179
180void NetworkUrlTest::TestHostAndPortWithNoUserNameAndPassword()
181{
182	BUrl url("https://www.something.co.nz:443/z");
183	CPPUNIT_ASSERT(url.IsValid());
184	CPPUNIT_ASSERT(url.Protocol() == "https");
185	CPPUNIT_ASSERT(url.HasProtocol());
186	CPPUNIT_ASSERT(!url.HasUserName());
187	CPPUNIT_ASSERT(!url.HasPassword());
188	CPPUNIT_ASSERT(url.Port() == 443);
189	CPPUNIT_ASSERT(url.HasPort());
190	CPPUNIT_ASSERT(url.Host() == "www.something.co.nz");
191	CPPUNIT_ASSERT(url.HasHost());
192	CPPUNIT_ASSERT(url.Path() == "/z");
193	CPPUNIT_ASSERT(url.HasPath());
194	CPPUNIT_ASSERT(!url.HasRequest());
195	CPPUNIT_ASSERT(!url.HasFragment());
196}
197
198
199void NetworkUrlTest::TestHostWithNoPortOrUserNameAndPassword()
200{
201	BUrl url("https://www.something.co.nz/z");
202	CPPUNIT_ASSERT(url.IsValid());
203	CPPUNIT_ASSERT(url.Protocol() == "https");
204	CPPUNIT_ASSERT(url.HasProtocol());
205	CPPUNIT_ASSERT(!url.HasUserName());
206	CPPUNIT_ASSERT(!url.HasPassword());
207	CPPUNIT_ASSERT(url.Host() == "www.something.co.nz");
208	CPPUNIT_ASSERT(url.HasHost());
209	CPPUNIT_ASSERT(!url.HasPort());
210	CPPUNIT_ASSERT(url.Path() == "/z");
211	CPPUNIT_ASSERT(url.HasPath());
212	CPPUNIT_ASSERT(!url.HasRequest());
213	CPPUNIT_ASSERT(!url.HasFragment());
214}
215
216
217void NetworkUrlTest::TestHostWithNoPortNoPath()
218{
219	BUrl url("https://www.something.co.nz");
220	CPPUNIT_ASSERT(url.IsValid());
221	CPPUNIT_ASSERT(url.Protocol() == "https");
222	CPPUNIT_ASSERT(url.HasProtocol());
223	CPPUNIT_ASSERT(!url.HasUserName());
224	CPPUNIT_ASSERT(!url.HasPassword());
225	CPPUNIT_ASSERT(url.Host() == "www.something.co.nz");
226	CPPUNIT_ASSERT(url.HasHost());
227	CPPUNIT_ASSERT(!url.HasPort());
228	CPPUNIT_ASSERT(!url.HasPath());
229	CPPUNIT_ASSERT(!url.HasRequest());
230	CPPUNIT_ASSERT(!url.HasFragment());
231}
232
233
234void NetworkUrlTest::TestHostWithPortNoPath()
235{
236	BUrl url("https://www.something.co.nz:1234");
237	CPPUNIT_ASSERT(url.IsValid());
238	CPPUNIT_ASSERT(url.Protocol() == "https");
239	CPPUNIT_ASSERT(url.HasProtocol());
240	CPPUNIT_ASSERT(!url.HasUserName());
241	CPPUNIT_ASSERT(!url.HasPassword());
242	CPPUNIT_ASSERT(url.Host() == "www.something.co.nz");
243	CPPUNIT_ASSERT(url.HasHost());
244	CPPUNIT_ASSERT(url.Port() == 1234);
245	CPPUNIT_ASSERT(url.HasPort());
246	CPPUNIT_ASSERT(!url.HasPath());
247	CPPUNIT_ASSERT(!url.HasRequest());
248	CPPUNIT_ASSERT(!url.HasFragment());
249}
250
251
252void NetworkUrlTest::TestHostWithEmptyPort()
253{
254	BUrl url("https://www.something.co.nz:");
255	CPPUNIT_ASSERT(url.IsValid());
256	CPPUNIT_ASSERT(url.Protocol() == "https");
257	CPPUNIT_ASSERT(url.HasProtocol());
258	CPPUNIT_ASSERT(!url.HasUserName());
259	CPPUNIT_ASSERT(!url.HasPassword());
260	CPPUNIT_ASSERT(url.Host() == "www.something.co.nz");
261	CPPUNIT_ASSERT(url.HasHost());
262	CPPUNIT_ASSERT(!url.HasPort());
263	CPPUNIT_ASSERT(!url.HasPath());
264	CPPUNIT_ASSERT(!url.HasRequest());
265	CPPUNIT_ASSERT(!url.HasFragment());
266}
267
268
269void NetworkUrlTest::TestProtocol()
270{
271	BUrl url("olala:");
272	CPPUNIT_ASSERT(url.IsValid());
273	CPPUNIT_ASSERT(url.Protocol() == "olala");
274	CPPUNIT_ASSERT(url.HasProtocol());
275	CPPUNIT_ASSERT(!url.HasUserName());
276	CPPUNIT_ASSERT(!url.HasPassword());
277	CPPUNIT_ASSERT(!url.HasHost());
278	CPPUNIT_ASSERT(!url.HasPort());
279	CPPUNIT_ASSERT(!url.HasPath());
280	CPPUNIT_ASSERT(!url.HasRequest());
281	CPPUNIT_ASSERT(!url.HasFragment());
282}
283
284
285void NetworkUrlTest::TestMailTo()
286{
287	BUrl url("mailto:eric@example.com");
288	CPPUNIT_ASSERT(url.IsValid());
289	CPPUNIT_ASSERT(url.Protocol() == "mailto");
290	CPPUNIT_ASSERT(url.HasProtocol());
291	CPPUNIT_ASSERT(!url.HasUserName());
292	CPPUNIT_ASSERT(!url.HasPassword());
293	CPPUNIT_ASSERT(!url.HasHost());
294	CPPUNIT_ASSERT(!url.HasPort());
295	CPPUNIT_ASSERT(url.Path() == "eric@example.com");
296	CPPUNIT_ASSERT(url.HasPath());
297	CPPUNIT_ASSERT(!url.HasRequest());
298	CPPUNIT_ASSERT(!url.HasFragment());
299}
300
301
302// #pragma mark - Various Authority Checks
303
304
305void NetworkUrlTest::TestAuthorityNoUserName()
306{
307	BUrl url("anything://:pwd@host");
308	CPPUNIT_ASSERT(url.IsValid());
309	CPPUNIT_ASSERT(!url.HasUserName());
310	CPPUNIT_ASSERT(url.HasPassword());
311	CPPUNIT_ASSERT(url.Password() == "pwd");
312	CPPUNIT_ASSERT(url.HasHost());
313	CPPUNIT_ASSERT(url.Host() == "host");
314	CPPUNIT_ASSERT(!url.HasPort());
315}
316
317
318void NetworkUrlTest::TestAuthorityWithCredentialsSeparatorNoPassword()
319{
320	BUrl url("anything://unam:@host");
321	CPPUNIT_ASSERT(url.IsValid());
322	CPPUNIT_ASSERT(url.HasUserName());
323	CPPUNIT_ASSERT(url.UserName() == "unam");
324	CPPUNIT_ASSERT(!url.HasPassword());
325	CPPUNIT_ASSERT(url.HasHost());
326	CPPUNIT_ASSERT(url.Host() == "host");
327	CPPUNIT_ASSERT(!url.HasPort());
328}
329
330
331void NetworkUrlTest::TestAuthorityWithoutCredentialsSeparatorNoPassword()
332{
333	BUrl url("anything://unam@host");
334	CPPUNIT_ASSERT(url.IsValid());
335	CPPUNIT_ASSERT(url.HasUserName());
336	CPPUNIT_ASSERT(url.UserName() == "unam");
337	CPPUNIT_ASSERT(!url.HasPassword());
338	CPPUNIT_ASSERT(url.HasHost());
339	CPPUNIT_ASSERT(url.Host() == "host");
340	CPPUNIT_ASSERT(!url.HasPort());
341}
342
343
344void NetworkUrlTest::TestAuthorityBadPort()
345{
346	BUrl url("anything://host:aaa");
347	CPPUNIT_ASSERT(url.IsValid());
348	CPPUNIT_ASSERT(!url.HasUserName());
349	CPPUNIT_ASSERT(!url.HasPassword());
350	CPPUNIT_ASSERT(url.HasHost());
351	CPPUNIT_ASSERT(url.Host() == "host");
352	CPPUNIT_ASSERT(!url.HasPort());
353}
354
355
356// #pragma mark - Invalid Forms
357
358
359void NetworkUrlTest::TestWhitespaceBefore()
360{
361	BUrl url("   https://www.something.co.nz/z");
362	CPPUNIT_ASSERT(!url.IsValid());
363}
364
365
366void NetworkUrlTest::TestWhitespaceAfter()
367{
368	BUrl url("https://www.something.co.nz/z\t\t ");
369	CPPUNIT_ASSERT(!url.IsValid());
370}
371
372
373void NetworkUrlTest::TestWhitespaceMiddle()
374{
375	BUrl url("https://www.  something.co.nz/z");
376	CPPUNIT_ASSERT(!url.IsValid());
377}
378
379
380void NetworkUrlTest::TestHttpNoHost()
381{
382	BUrl url("https:///z");
383	CPPUNIT_ASSERT(!url.IsValid());
384}
385
386
387void NetworkUrlTest::TestEmpty()
388{
389	BUrl url("");
390	CPPUNIT_ASSERT(!url.IsValid());
391}
392
393
394// #pragma mark - Host validation
395
396
397void NetworkUrlTest::TestBadHosts()
398{
399	CPPUNIT_ASSERT_MESSAGE("control check",
400		BUrl("http://host.example.com").IsValid());
401
402	CPPUNIT_ASSERT_MESSAGE("hyphen in middle",
403		(BUrl("http://host.peppermint_tea.com").IsValid()));
404	CPPUNIT_ASSERT_MESSAGE("dot at end",
405		(BUrl("http://host.camomile.co.nz.").IsValid()));
406	CPPUNIT_ASSERT_MESSAGE("simple host",
407		(BUrl("http://tumeric").IsValid()));
408
409	CPPUNIT_ASSERT_MESSAGE("idn domain encoded",
410		(BUrl("http://xn--bcher-kva.tld").IsValid()));
411	CPPUNIT_ASSERT_MESSAGE("idn domain unencoded",
412		(BUrl("http://www.b\xc3\xbcch.at").IsValid()));
413
414	CPPUNIT_ASSERT_MESSAGE("dot at start",
415		!(BUrl("http://.host.example.com").IsValid()));
416	CPPUNIT_ASSERT_MESSAGE("double dot in domain",
417		!(BUrl("http://host.example..com").IsValid()));
418	CPPUNIT_ASSERT_MESSAGE("double dot",
419		!(BUrl("http://host.example..com").IsValid()));
420	CPPUNIT_ASSERT_MESSAGE("unexpected characters",
421		!(BUrl("http://<unexpected.characters>").IsValid()));
422	CPPUNIT_ASSERT_MESSAGE("whitespace",
423		!(BUrl("http://host.exa ple.com").IsValid()));
424}
425
426
427// #pragma mark - Control
428
429
430/*static*/ void
431NetworkUrlTest::AddTests(BTestSuite& parent)
432{
433	CppUnit::TestSuite& suite = *new CppUnit::TestSuite("NetworkUrlTest");
434
435	suite.addTest(new CppUnit::TestCaller<NetworkUrlTest>(
436		"NetworkUrlTest::TestHostAndPortWithNoUserNameAndPassword",
437		&NetworkUrlTest::TestHostAndPortWithNoUserNameAndPassword));
438	suite.addTest(new CppUnit::TestCaller<NetworkUrlTest>(
439		"NetworkUrlTest::TestWithUserNameAndPasswordNoHostAndPort",
440		&NetworkUrlTest::TestWithUserNameAndPasswordNoHostAndPort));
441	suite.addTest(new CppUnit::TestCaller<NetworkUrlTest>(
442		"NetworkUrlTest::TestHostWithNoPortOrUserNameAndPassword",
443		&NetworkUrlTest::TestHostWithNoPortOrUserNameAndPassword));
444	suite.addTest(new CppUnit::TestCaller<NetworkUrlTest>(
445		"NetworkUrlTest::TestHostWithNoPortNoPath",
446		&NetworkUrlTest::TestHostWithNoPortNoPath));
447	suite.addTest(new CppUnit::TestCaller<NetworkUrlTest>(
448		"NetworkUrlTest::TestHostWithPortNoPath",
449		&NetworkUrlTest::TestHostWithPortNoPath));
450	suite.addTest(new CppUnit::TestCaller<NetworkUrlTest>(
451		"NetworkUrlTest::TestHostWithEmptyPort",
452		&NetworkUrlTest::TestHostWithEmptyPort));
453	suite.addTest(new CppUnit::TestCaller<NetworkUrlTest>(
454		"NetworkUrlTest::TestHostWithPathAndFragment",
455		&NetworkUrlTest::TestHostWithPathAndFragment));
456	suite.addTest(new CppUnit::TestCaller<NetworkUrlTest>(
457		"NetworkUrlTest::TestHostWithFragment",
458		&NetworkUrlTest::TestHostWithFragment));
459	suite.addTest(new CppUnit::TestCaller<NetworkUrlTest>(
460		"NetworkUrlTest::TestIpv6HostPortPathAndRequest",
461		&NetworkUrlTest::TestIpv6HostPortPathAndRequest));
462	suite.addTest(new CppUnit::TestCaller<NetworkUrlTest>(
463		"NetworkUrlTest::TestProtocol",
464		&NetworkUrlTest::TestProtocol));
465	suite.addTest(new CppUnit::TestCaller<NetworkUrlTest>(
466		"NetworkUrlTest::TestMailTo",
467		&NetworkUrlTest::TestMailTo));
468	suite.addTest(new CppUnit::TestCaller<NetworkUrlTest>(
469		"NetworkUrlTest::TestDataUrl",
470		&NetworkUrlTest::TestDataUrl));
471
472	suite.addTest(new CppUnit::TestCaller<NetworkUrlTest>(
473		"NetworkUrlTest::TestAuthorityNoUserName",
474		&NetworkUrlTest::TestAuthorityNoUserName));
475	suite.addTest(new CppUnit::TestCaller<NetworkUrlTest>(
476        "NetworkUrlTest::TestAuthorityWithCredentialsSeparatorNoPassword",
477        &NetworkUrlTest::TestAuthorityWithCredentialsSeparatorNoPassword));
478	suite.addTest(new CppUnit::TestCaller<NetworkUrlTest>(
479        "NetworkUrlTest::TestAuthorityWithoutCredentialsSeparatorNoPassword",
480        &NetworkUrlTest::TestAuthorityWithoutCredentialsSeparatorNoPassword));
481	suite.addTest(new CppUnit::TestCaller<NetworkUrlTest>(
482        "NetworkUrlTest::TestAuthorityBadPort",
483        &NetworkUrlTest::TestAuthorityBadPort));
484
485	suite.addTest(new CppUnit::TestCaller<NetworkUrlTest>(
486		"NetworkUrlTest::TestWhitespaceBefore",
487		&NetworkUrlTest::TestWhitespaceBefore));
488	suite.addTest(new CppUnit::TestCaller<NetworkUrlTest>(
489		"NetworkUrlTest::TestWhitespaceAfter",
490		&NetworkUrlTest::TestWhitespaceAfter));
491	suite.addTest(new CppUnit::TestCaller<NetworkUrlTest>(
492		"NetworkUrlTest::TestWhitespaceMiddle",
493		&NetworkUrlTest::TestWhitespaceMiddle));
494	suite.addTest(new CppUnit::TestCaller<NetworkUrlTest>(
495		"NetworkUrlTest::TestEmpty",
496		&NetworkUrlTest::TestEmpty));
497
498	suite.addTest(new CppUnit::TestCaller<NetworkUrlTest>(
499		"NetworkUrlTest::TestFileUrl",
500		&NetworkUrlTest::TestFileUrl));
501	suite.addTest(new CppUnit::TestCaller<NetworkUrlTest>(
502		"NetworkUrlTest::TestValidFullUrl", &NetworkUrlTest::TestValidFullUrl));
503	suite.addTest(new CppUnit::TestCaller<NetworkUrlTest>(
504		"NetworkUrlTest::TestBadHosts", &NetworkUrlTest::TestBadHosts));
505
506	parent.addTest("NetworkUrlTest", &suite);
507}
508