5 // Atsushi Enomoto <atsushi@ximian.com>
7 // Copyright (C) 2008 Novell, Inc (http://www.novell.com)
8 // Copyright 2011 Xamarin Inc (http://www.xamarin.com).
10 // Permission is hereby granted, free of charge, to any person obtaining
11 // a copy of this software and associated documentation files (the
12 // "Software"), to deal in the Software without restriction, including
13 // without limitation the rights to use, copy, modify, merge, publish,
14 // distribute, sublicense, and/or sell copies of the Software, and to
15 // permit persons to whom the Software is furnished to do so, subject to
16 // the following conditions:
18 // The above copyright notice and this permission notice shall be
19 // included in all copies or substantial portions of the Software.
21 // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
22 // EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
23 // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
24 // NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
25 // LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
26 // OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
27 // WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
30 using System.Collections.Generic;
31 using System.Collections.ObjectModel;
32 using System.Collections.Specialized;
33 using NUnit.Framework;
35 namespace MonoTests.System
38 public class UriTemplateTest
41 [ExpectedException (typeof (ArgumentNullException))]
42 public void ConstructorNull ()
44 new UriTemplate (null);
48 public void ConstructorEmpty ()
50 // it does not raise an error at this state.
51 new UriTemplate (String.Empty);
55 public void ConstructorNullDictionary ()
57 new UriTemplate (String.Empty, null);
61 public void IgnoreTrailingSlashDefault ()
63 Assert.IsFalse (new UriTemplate (String.Empty).IgnoreTrailingSlash);
67 [ExpectedException (typeof (FormatException))]
68 public void ConstructorBrokenTemplate ()
70 // it used to be allowed but now it isn't in 3.5 SP1.
71 new UriTemplate ("{");
75 [ExpectedException (typeof (FormatException))]
76 public void ConstructorBrokenTemplate2 ()
78 new UriTemplate ("http://localhost:8080/{foo}/{");
82 [ExpectedException (typeof (FormatException))]
83 public void ConstructorBrokenTemplate3 ()
85 new UriTemplate ("http://localhost:8080/{foo}/*/baz");
89 public void ToString ()
91 Assert.AreEqual ("urn:foo", new UriTemplate ("urn:foo").ToString (), "#1");
92 // It used to be allowed but now it isn't in 3.5 SP1.
93 //Assert.AreEqual ("{", new UriTemplate ("{").ToString (), "#2");
97 public void Variables ()
99 var t = new UriTemplate ("urn:foo");
100 Assert.AreEqual (0, t.PathSegmentVariableNames.Count, "#1a");
101 Assert.AreEqual (0, t.QueryValueVariableNames.Count, "#1b");
103 t = new UriTemplate ("http://localhost:8080/");
104 Assert.AreEqual (0, t.PathSegmentVariableNames.Count, "#2a");
105 Assert.AreEqual (0, t.QueryValueVariableNames.Count, "#2b");
107 t = new UriTemplate ("http://localhost:8080/foo/");
108 Assert.AreEqual (0, t.PathSegmentVariableNames.Count, "#3a");
109 Assert.AreEqual (0, t.QueryValueVariableNames.Count, "#3b");
111 t = new UriTemplate ("http://localhost:8080/{foo}");
112 Assert.AreEqual (1, t.PathSegmentVariableNames.Count, "#4a");
113 Assert.AreEqual ("FOO", t.PathSegmentVariableNames [0], "#4b");
114 Assert.AreEqual (0, t.QueryValueVariableNames.Count, "#4c");
116 // This became invalid in 3.5 SP1
117 //t = new UriTemplate ("http://localhost:8080/{foo}/{");
118 //Assert.AreEqual (1, t.PathSegmentVariableNames.Count, "#5a");
119 //Assert.AreEqual ("FOO", t.PathSegmentVariableNames [0], "#5b");
120 //Assert.AreEqual (0, t.QueryValueVariableNames.Count, "#5c");
122 t = new UriTemplate ("http://localhost:8080/hoge?test={foo}&test2={bar}");
123 Assert.AreEqual (0, t.PathSegmentVariableNames.Count, "#6a");
124 Assert.AreEqual (2, t.QueryValueVariableNames.Count, "#6b");
125 Assert.AreEqual ("FOO", t.QueryValueVariableNames [0], "#6c");
126 Assert.AreEqual ("BAR", t.QueryValueVariableNames [1], "#6d");
130 [ExpectedException (typeof (ArgumentException))]
131 public void VariablesInSameSegment ()
133 new UriTemplate ("http://localhost:8080/{foo}{bar}");
137 [Category ("NotDotNet")] //.NET 3.5 SP1 incorrectly matches the port part
138 public void VariablesInNonPathQuery ()
140 var t = new UriTemplate ("http://localhost:{foo}/");
141 Assert.AreEqual (0, t.PathSegmentVariableNames.Count, "#8a");
142 Assert.AreEqual (0, t.QueryValueVariableNames.Count, "#8b");
146 [ExpectedException (typeof (InvalidOperationException))]
147 public void DuplicateNameInTemplate ()
149 // one name to two places to match
150 new UriTemplate ("http://localhost:8080/hoge?test={foo}&test2={foo}");
154 [ExpectedException (typeof (InvalidOperationException))]
155 public void DuplicateNameInTemplate2 ()
157 // one name to two places to match
158 new UriTemplate ("http://localhost:8080/hoge/{foo}?test={foo}");
162 [ExpectedException (typeof (ArgumentNullException))]
163 public void BindByNameNullBaseAddress ()
165 var t = new UriTemplate ("http://localhost:8080/");
166 t.BindByName (null, new NameValueCollection ());
170 [ExpectedException (typeof (ArgumentException))]
171 public void BindByNameRelativeBaseAddress ()
173 var t = new UriTemplate ("http://localhost:8080/");
174 t.BindByName (new Uri ("", UriKind.Relative), new NameValueCollection ());
178 [Category ("NotWorking")] // not worthy
179 public void BindByNameFileUriBaseAddress ()
181 var t = new UriTemplate ("http://localhost:8080/");
182 var u = t.BindByName (new Uri ("file:///"), new NameValueCollection ());
183 Assert.AreEqual ("file:///http://localhost:8080/", u.ToString ());
186 [Test] // it is allowed.
187 public void BindByNameFileExtraNames ()
189 var t = new UriTemplate ("http://localhost:8080/");
190 var n = new NameValueCollection ();
191 n.Add ("name", "value");
192 t.BindByName (new Uri ("http://localhost/"), n);
196 [ExpectedException (typeof (ArgumentException))]
197 public void BindByNameFileMissingName ()
199 var t = new UriTemplate ("/{foo}/");
200 t.BindByName (new Uri ("http://localhost/"), new NameValueCollection ());
204 [ExpectedException (typeof (ArgumentException))]
205 public void BindInSameSegment ()
207 new UriTemplate ("/hoo/{foo}{bar}");
211 public void BindByName ()
213 var t = new UriTemplate ("/{foo}/{bar}/");
214 var n = new NameValueCollection ();
215 n.Add ("Bar", "value1"); // case insensitive
216 n.Add ("FOO", "value2"); // case insensitive
217 var u = t.BindByName (new Uri ("http://localhost/"), n);
218 Assert.AreEqual ("http://localhost/value2/value1/", u.ToString ());
222 public void BindByName2 ()
224 var t = new UriTemplate ("{foo}/{bar}");
225 var n = new NameValueCollection ();
226 n.Add ("Bar", "value1"); // case insensitive
227 n.Add ("FOO", "value2"); // case insensitive
228 var u = t.BindByName (new Uri ("http://localhost/x"), n);
229 Assert.AreEqual ("http://localhost/x/value2/value1", u.ToString ());
233 public void BindByName3 ()
235 var t = new UriTemplate ("Login?clientLoginData={clientLoginData}&credentials={credentials}");
236 var n = new NameValueCollection ();
237 var u = t.BindByName (new Uri ("http://localhost"), n);
238 Assert.AreEqual ("http://localhost/Login", u.ToString (), "#1");
242 public void BindByNameManySlashes ()
244 var t = new UriTemplate ("////{foo}/{bar}/");
245 var n = new NameValueCollection ();
246 n.Add ("Bar", "value1"); // case insensitive
247 n.Add ("FOO", "value2"); // case insensitive
248 var u = t.BindByName (new Uri ("http://localhost/"), n);
249 Assert.AreEqual ("http://localhost////value2/value1/", u.ToString ());
253 public void BindByNameManySlashes2 ()
255 var t = new UriTemplate ("////{foo}/{bar}/");
256 var n = new NameValueCollection ();
257 n.Add ("Bar", "value1"); // case insensitive
258 n.Add ("FOO", "value2"); // case insensitive
259 var u = t.BindByName (new Uri ("http://localhost//"), n);
260 Assert.AreEqual ("http://localhost/////value2/value1/", u.ToString ());
264 public void BindByNameWithDefaults ()
266 var d = new Dictionary<string,string> ();
267 d.Add ("Bar", "value1"); // case insensitive
268 d.Add ("FOO", "value2"); // case insensitive
269 var t = new UriTemplate ("/{foo}/{bar}/", d);
270 var u = t.BindByName (new Uri ("http://localhost/"), new NameValueCollection ());
271 Assert.AreEqual ("http://localhost/value2/value1/", u.ToString ());
275 [ExpectedException (typeof (ArgumentException))]
276 public void BindByNameWithDefaults2 ()
278 var d = new Dictionary<string,string> ();
279 d.Add ("Bar", "value1"); // case insensitive
280 d.Add ("FOO", "value2"); // case insensitive
281 var t = new UriTemplate ("/{foo}/{bar}/{baz}", d);
282 t.BindByName (new Uri ("http://localhost/"), new NameValueCollection ()); // missing baz
286 [ExpectedException (typeof (ArgumentNullException))]
287 public void BindByPositionNullBaseAddress ()
289 var t = new UriTemplate ("http://localhost:8080/");
290 t.BindByPosition (null);
294 [ExpectedException (typeof (ArgumentException))]
295 public void BindByPositionRelativeBaseAddress ()
297 var t = new UriTemplate ("http://localhost:8080/");
298 t.BindByPosition (new Uri ("", UriKind.Relative));
302 [Category ("NotWorking")] // not worthy
303 public void BindByPositionFileUriBaseAddress ()
305 var t = new UriTemplate ("http://localhost:8080/");
306 Assert.AreEqual (new Uri ("file:///http://localhost:8080/"), t.BindByPosition (new Uri ("file:///")));
309 [Test] // it is NOT allowed (unlike BindByName)
310 [ExpectedException (typeof (FormatException))]
311 public void BindByPositionFileExtraValues ()
313 var t = new UriTemplate ("http://localhost:8080/");
314 t.BindByPosition (new Uri ("http://localhost/"), "value");
318 [ExpectedException (typeof (FormatException))]
319 public void BindByPositionFileMissingValues ()
321 var t = new UriTemplate ("/{foo}/");
322 t.BindByPosition (new Uri ("http://localhost/"));
326 public void BindByPosition ()
328 var t = new UriTemplate ("/{foo}/{bar}/");
329 var u = t.BindByPosition (new Uri ("http://localhost/"), "value1", "value2");
330 Assert.AreEqual ("http://localhost/value1/value2/", u.ToString ());
334 [ExpectedException (typeof (FormatException))] // it does not allow default values
335 public void BindByPositionWithDefaults ()
337 var d = new Dictionary<string,string> ();
338 d ["baz"] = "value3";
339 var t = new UriTemplate ("/{foo}/{bar}/{baz}", d);
340 t.BindByPosition (new Uri ("http://localhost/"), "value1", "value2");
344 [ExpectedException (typeof (ArgumentNullException))]
345 public void MatchNullArgument1 ()
347 var t = new UriTemplate ("/hooray");
348 t.Match (null, new Uri ("http://localhost/"));
352 [ExpectedException (typeof (ArgumentNullException))]
353 public void MatchNullArgument2 ()
355 var t = new UriTemplate ("/hooray");
356 t.Match (new Uri ("http://localhost/"), null);
360 public void MatchNoTemplateItem ()
362 var t = new UriTemplate ("/hooray");
363 var n = new NameValueCollection ();
364 Assert.IsNotNull (t.Match (new Uri ("http://localhost/"), new Uri ("http://localhost/hooray")), "#1");
365 Assert.IsNull (t.Match (new Uri ("http://localhost/"), new Uri ("http://localhost/foobar")), "#2");
366 Assert.IsNull (t.Match (new Uri ("http://localhost/"), new Uri ("http://localhost/hooray/foobar")), "#3");
370 public void MatchWrongTemplate ()
372 var t = new UriTemplate ("/hoo{foo}");
373 var n = new NameValueCollection ();
374 var m = t.Match (new Uri ("http://localhost/"), new Uri ("http://localhost/hooray"));
375 Assert.AreEqual ("ray", m.BoundVariables ["foo"], "#1");
376 Assert.IsNull (t.Match (new Uri ("http://localhost/"), new Uri ("http://localhost/foobar")), "#2");
377 Assert.IsNull (t.Match (new Uri ("http://localhost/"), new Uri ("http://localhost/hooray/foobar")), "#3");
378 Assert.IsNull (t.Match (new Uri ("http://localhost/"), new Uri ("http://localhost/hoo/ray")), "#4");
379 Assert.IsNull (t.Match (new Uri ("http://localhost/"), new Uri ("http://localhost/hoo")), "#5");
380 // this matches (as if there were no template).
381 Assert.IsNotNull (t.Match (new Uri ("http://localhost/"), new Uri ("http://localhost/hoo{foo}")), "#6");
387 var t = new UriTemplate ("/{foo}/{bar}");
388 var n = new NameValueCollection ();
389 Uri baseUri = new Uri ("http://localhost/");
390 Assert.IsNull (t.Match (baseUri, new Uri ("http://localhost/hooray")), "#1");
391 Assert.IsNull (t.Match (baseUri, new Uri ("http://localhost/v1/v2/extra")), "#2");
392 Assert.IsNull (t.Match (baseUri, new Uri ("http://localhost/1/2/")), "#3");
393 UriTemplateMatch m = t.Match (baseUri, new Uri ("http://localhost/foooo/baaar"));
394 Assert.IsNotNull (m, "#4");
395 Assert.AreEqual ("foooo", m.BoundVariables ["foo"], "#5");
396 Assert.AreEqual ("baaar", m.BoundVariables ["bar"], "#6");
400 public void Match2 ()
402 var t = new UriTemplate ("/{foo}/{bar}?p1={baz}");
403 var n = new NameValueCollection ();
404 Uri baseUri = new Uri ("http://localhost/");
405 Assert.IsNotNull (t.Match (baseUri, new Uri ("http://localhost/X/Y")), "#1");
406 UriTemplateMatch m = t.Match (baseUri, new Uri ("http://localhost/X/Y?p2=v&p1=vv"));
407 Assert.IsNotNull (m, "#2");
408 // QueryParameters must contain non-template query parameters.
409 Assert.AreEqual (2, m.QueryParameters.Count, "#3");
410 Assert.AreEqual ("v", m.QueryParameters ["p2"], "#4");
411 Assert.AreEqual ("vv", m.QueryParameters ["p1"], "#5");
415 public void Match3 ()
417 var template = new UriTemplate ("test");
418 var match1 = template.Match (new Uri ("http://something"), new Uri ("http://something/test"));
419 var match2 = template.Match (new Uri ("http://something/something2"), new Uri ("http://something/something2/test"));
420 Assert.IsNotNull (match1, "#1");
421 Assert.IsNotNull (match2, "#2");
425 public void MatchWildcard ()
427 var t = new UriTemplate ("/hoge/*?p1={foo}");
428 var m = t.Match (new Uri ("http://localhost"), new Uri ("http://localhost/hoge/ppp/qqq?p1=v1"));
429 Assert.IsNotNull (m, "#0");
430 Assert.IsNotNull (m.QueryParameters, "#1.0");
431 Assert.AreEqual ("v1", m.QueryParameters ["p1"], "#1");
432 Assert.IsNotNull (m.WildcardPathSegments, "#2.0");
433 Assert.AreEqual (2, m.WildcardPathSegments.Count, "#2");
434 Assert.AreEqual ("ppp", m.WildcardPathSegments [0], "#3");
435 Assert.AreEqual ("qqq", m.WildcardPathSegments [1], "#4");
439 public void MatchWildcard2 ()
441 var t = new UriTemplate ("*");
442 var m = t.Match (new Uri ("http://localhost"), new Uri ("http://localhost/hoge/ppp"));
443 Assert.IsNotNull (m, "#0");
444 Assert.IsEmpty (m.QueryParameters, "#1.0");
445 Assert.AreEqual ("hoge", m.WildcardPathSegments [0], "#2");
446 Assert.AreEqual ("ppp", m.WildcardPathSegments [1], "#3");
450 public void MatchWildcard3 ()
452 var t = new UriTemplate ("*?p1={foo}");
453 var m = t.Match (new Uri ("http://localhost"), new Uri ("http://localhost/hoge/ppp/qqq?p1=v1"));
454 Assert.IsNotNull (m, "#0");
455 Assert.IsNotNull (m.QueryParameters, "#1.0");
456 Assert.AreEqual ("v1", m.QueryParameters ["p1"], "#1");
457 Assert.IsNotNull (m.WildcardPathSegments, "#2.0");
458 Assert.AreEqual (3, m.WildcardPathSegments.Count, "#2");
459 Assert.AreEqual ("hoge", m.WildcardPathSegments [0], "#3");
460 Assert.AreEqual ("ppp", m.WildcardPathSegments [1], "#4");
461 Assert.AreEqual ("qqq", m.WildcardPathSegments [2], "#5");
465 public void IgnoreTrailingSlash ()
467 var t = new UriTemplate ("/{foo}/{bar}", true);
468 var n = new NameValueCollection ();
469 Uri baseUri = new Uri ("http://localhost/");
470 Assert.IsNotNull (t.Match (baseUri, new Uri ("http://localhost/v1/v2/")), "#1");
472 t = new UriTemplate ("/{foo}/{bar}", false);
473 Assert.IsNull (t.Match (baseUri, new Uri ("http://localhost/v1/v2/")), "#2");
477 [Category ("NotWorking")]
478 public void SimpleWebGet () {
479 UriTemplate t = new UriTemplate ("GetBlog");
480 Assert.IsNotNull(t.Match(new Uri("http://localhost:8000/BlogService"),
481 new Uri("http://localhost:8000/BlogService/GetBlog")), "Matches simple WebGet method");
482 Assert.IsNull(t.Match (new Uri ("http://localhost:8000/BlogService"),
483 new Uri ("http://localhost:8000/BlogService/GetData")), "Doesn't match wrong WebGet method");
487 [ExpectedException (typeof (ArgumentException))]
488 public void DictContainsNullValue ()
490 var t = new UriTemplate ("/id-{foo}/{bar}");
491 var dic = new Dictionary<string,string> ();
494 t.BindByName (new Uri ("http://localhost:8080"), dic);
498 public void DictContainsCaseInsensitiveKey ()
500 var t = new UriTemplate ("/id-{foo}/{bar}");
501 var dic = new Dictionary<string,string> ();
504 var uri = t.BindByName (new Uri ("http://localhost:8080"), dic);
505 Assert.AreEqual ("http://localhost:8080/id-aaa/bbb", uri.ToString ());
509 public void NamedWildcard ()
511 UriTemplate template = new UriTemplate ("{*path}");
512 UriTemplateMatch match = template.Match (new Uri ("http://localhost"), new Uri ("http://localhost/something"));
513 Assert.IsNotNull (match, "#1");
514 Assert.AreEqual ("something", match.BoundVariables ["path"], "#2");
518 [Category ("NotWorking")]
519 public void EscapedUriCandidate ()
521 var candidateUri = new Uri (@"https://somehost:12345/path1/path2/path3/endprefix/tpath1/guid1/tpath2/~|~~|~%3F~|~Path{guid2}~|~/tpath3");
522 var matchUri = new Uri (candidateUri.Scheme + "://" + candidateUri.Host + ":" + candidateUri.Port + @"/path1/path2/path3/endprefix");
524 var template = new UriTemplate (@"tpath1/{guid}/tpath2/{encodedGuidString}/tpath3");
525 var match = template.Match (matchUri, candidateUri);
527 Assert.IsNotNull (match);
528 Assert.That (match.BoundVariables ["GUID"] == "guid1");
529 Assert.That (match.BoundVariables ["ENCODEDGUIDSTRING"] == "~|~~|~?~|~Path{guid2}~|~");