Merge pull request #1909 from esdrubal/reflection
[mono.git] / mcs / class / System / Test / System / UriPermutationsTest.cs
1 using System;
2 using System.Text;
3 using NUnit.Framework;
4
5 namespace MonoTests.System {
6         [TestFixture]
7         public class UriPermutationsTest {
8
9                 // Set this to true to generate the expected values
10                 // The tests should run first on .NET with CreateMode = true
11                 // The generated files should then be used when running the tests in Mono with CreateMode = false
12                 private const bool createMode = false;
13
14                 // The final location depends on NET_2_0, NET_4_0, NET_4_5.
15                 private const string location = "./Test/System/UriPermutationsTest/";
16
17                 private const string nonAsciiTestedChars = "☕";
18
19                 // Chars that can change the current component.
20                 // Those characters are tested alone.
21                 private const string specialTestedChars = "@:?#";
22
23                 // Scheme news: and custom: are not tested because there is a strange behavior on .NET 4.5
24                 // new Uri("news:a/a%30").ToString() == "news:a/a%30a/a0"
25                 private static readonly string [] schemes = {
26                         "http://", "https://", "file://", "ftp://", "gopher://", "ldap://", "mailto:",
27                         "net.pipe://", "net.tcp://",  "nntp://", "telnet://", "custom://",
28                         //"news:", "custom:"
29                 };
30
31                 private static readonly string [] componentLocations = {
32                         "a/a{0}?", "b/a{0}#", "c/a?", "d/a#",
33                         "a/a{0}?%30#", "a/a?{0}#%30", "a/a%30?#",   // see why on TestChars comment
34                 };
35
36                 private static readonly string [] specialCases = {
37                         "a/a#%#", "a/a#%25#", // '%' cause '#' to escape in some cases
38                         "a/%80%81%B8%B9", // invalid utf8 encoding
39                 };
40
41                 private static readonly string [] reduceLocations = {
42                         "a/b/{0}", "a/b/{0}a", "a/b/c{0}",
43                         "a/b/{0}/a", "a/b/{0}a/a", "a/b/c{0}/a",
44                         // Test '\\'
45                         "a/b\\{0}", "a/b\\{0}a", "a/b\\c{0}",
46                         "a/b\\{0}\\a", "a/b\\{0}a\\a", "a/b\\c{0}\\a",
47                         // Test '/' %2F
48                         "a/b%2F{0}", "a/b%2F{0}a", "a/b%2Fc{0}",
49                         "a/b/{0}%2Fa", "a/b/{0}a%2Fa", "a/b/c{0}%2Fa",
50                         "a/b%2F{0}/a", "a/b%2F{0}a/a", "a/b%2Fc{0}/a",
51                         // Test '\\' %5C
52                         "a/b%5C{0}", "a/b%5C{0}a", "a/b%5Cc{0}",
53                         "a/b/{0}%5Ca", "a/b/{0}a%5Ca", "a/b/c{0}%5Ca",
54                         "a/b%5C{0}/a", "a/b%5C{0}a/a", "a/b%5Cc{0}/a",
55                 };
56
57                 private static readonly string [] reduceElements = {
58                         "", ".", "..", "...", "%2E", "%2E%2E", "%2E%2E%2E"
59                 };
60
61                 [SetUp]
62                 public void Setup()
63                 {
64                         StringTester.CreateMode = createMode;
65 #if NET_4_5
66                         StringTester.Location = location + "NET_4_5";
67 #else
68                         StringTester.Location = location + "NET_4_0";
69 #endif
70                 }
71
72                 [TearDown]
73                 public void Teardown()
74                 {
75                         StringTester.Save();
76                 }
77
78                 // With IriParsing: http://a/a%21 does not unescape to http://a/a!
79                 // but http://a/a%21%30 does unescape to http://a/a!0
80                 // This happens with alpha numeric characters, non ASCII,'-','.','_' and '~'.
81                 // So we tests characters with and without those characters.
82                 private void TestChars (Action<string> action)
83                 {
84                         var sb1 = new StringBuilder ();
85                         var sb2 = new StringBuilder ();
86                         for (char c = '\0'; c <= 0x7f; c++) {
87                                 if (specialTestedChars.Contains ("" + c))
88                                         continue;
89
90                                 if ((c >= 'A' && c <= 'Z') || (c >= 'a' && c <= 'z') || (c >= '0' && c <= '9') ||
91                                          c == '-' || c == '.' || c == '_' || c == '~') {
92                                          sb2.Append (c);
93                                          continue;
94                                 }
95
96                                 sb1.Append (c);
97                                 sb2.Append (c);
98                         }
99
100                         foreach (char c in nonAsciiTestedChars)
101                                 sb2.Append (c);
102
103                         action (sb1.ToString ());
104                         action (sb2.ToString ());
105
106                         foreach (char c in specialTestedChars)
107                                 action ("" + c);
108                 }
109
110                 internal static string HexEscapeMultiByte (char character, bool upper)
111                 {
112                         const string hex_upper_chars = "0123456789ABCDEF";
113                         const string hex_lower_chars = "0123456789abcdef";
114
115                         string hex_chars = (upper)? hex_upper_chars : hex_lower_chars;
116                         string ret = "";
117                         byte [] bytes = Encoding.UTF8.GetBytes (new [] {character});
118                         foreach (byte b in bytes)
119                                 ret += "%" + hex_chars [((b & 0xf0) >> 4)] + hex_chars [((b & 0x0f))];
120
121                         return ret;
122                 }
123
124                 private void TestScheme(Action<string> action)
125                 {
126                         foreach (string scheme in schemes)
127                                 action(scheme);
128                 }
129
130                 private delegate string UriToStringDelegate (Uri uri);
131
132                 private void TestLocation (string id, string str, UriToStringDelegate toString, bool testRelative = true)
133                 {
134                         TestScheme (scheme => {
135                                 string uri = scheme + str;
136                                 string actual = toString (new Uri (scheme + str, UriKind.Absolute));
137                                 StringTester.Assert (scheme + id, actual);
138                         });
139
140                         if (!testRelative)
141                                 return;
142
143                         string relActual = toString (new Uri ("./" + str, UriKind.Relative));
144                         StringTester.Assert ("./" + id, relActual);
145                 }
146
147                 private void TestLocations (string [] locations, string id, string str, UriToStringDelegate toString,
148                         bool testRelative = true)
149                 {
150                         foreach (string location in locations) {
151                                 if (location.Contains ("{0}"))
152                                         TestLocation (string.Format (location, id), string.Format (location, str), toString, testRelative);
153                                 else
154                                         TestLocation (location + id, location + str, toString, testRelative);
155                         }
156                 }
157
158                 private void TestPercentageEncoding (UriToStringDelegate toString, bool testRelative = false, string id = "")
159                 {
160                         TestChars (unescapedStr => {
161                                 var sbUpper = new StringBuilder ();
162                                 var sbLower = new StringBuilder ();
163                                 foreach (char c in unescapedStr) {
164                                         sbUpper.Append (HexEscapeMultiByte (c, true));
165                                         sbLower.Append (HexEscapeMultiByte (c, false));
166                                 }
167                                 string escapedUpperStr = sbUpper.ToString ();
168                                 string escapedLowerStr = sbLower.ToString ();
169
170                                 TestLocations (componentLocations, unescapedStr+id, unescapedStr, toString, testRelative);
171                                 TestLocations (componentLocations, escapedUpperStr+id+"[Upper]", escapedUpperStr, toString, testRelative);
172                                 TestLocations (componentLocations, escapedLowerStr+id+"[Lower]", escapedLowerStr, toString, testRelative);
173                         });
174
175                         TestLocations (specialCases, id, "", toString, testRelative);
176                 }
177
178                 private void TestReduce (UriToStringDelegate toString, bool testRelative = true, string id = "")
179                 {
180                         foreach(var el in reduceElements)
181                                 TestLocations (reduceLocations, el + id, el, toString, testRelative);
182                 }
183
184                 private void TestComponent (UriComponents component)
185                 {
186                         TestPercentageEncoding (uri => uri.GetComponents (component, UriFormat.SafeUnescaped), id: "[SafeUnescaped]");
187                         TestPercentageEncoding (uri => uri.GetComponents (component, UriFormat.Unescaped), id: "[Unescaped]");
188                         TestPercentageEncoding (uri => uri.GetComponents (component, UriFormat.UriEscaped), id: "[UriEscaped]");
189                 }
190
191                 private delegate void TestStringDelegate (UriToStringDelegate toString, bool testRelative = true, string id = "");
192
193                 [Test]
194                 public void PercentageEncoding_AbsoluteUri ()
195                 {
196                         TestPercentageEncoding (uri => uri.AbsoluteUri);
197                 }
198
199                 [Test]
200                 public void PercentageEncoding_AbsolutePath ()
201                 {
202                         TestPercentageEncoding (uri => uri.AbsolutePath);
203                 }
204
205                 [Test]
206                 public void PercentageEncoding_Fragment ()
207                 {
208                         TestPercentageEncoding (uri => uri.Fragment);
209                 }
210
211                 [Test]
212                 public void PercentageEncoding_GetComponents_AbsoluteUri ()
213                 {
214                         TestComponent (UriComponents.AbsoluteUri);
215                 }
216
217                 [Test]
218                 public void PercentageEncoding_GetComponents_Fragment ()
219                 {
220                         TestComponent (UriComponents.Fragment);
221                 }
222
223                 [Test]
224                 public void PercentageEncoding_GetComponents_Host ()
225                 {
226                         TestComponent (UriComponents.Host);
227                 }
228
229                 [Test]
230                 public void PercentageEncoding_GetComponents_Path ()
231                 {
232                         TestComponent (UriComponents.Path);
233                 }
234
235                 [Test]
236                 public void PercentageEncoding_GetComponents_PathAndQuery ()
237                 {
238                         TestComponent (UriComponents.PathAndQuery);
239                 }
240
241                 [Test]
242                 public void PercentageEncoding_GetComponents_Query ()
243                 {
244                         TestComponent (UriComponents.Query);
245                 }
246
247                 [Test]
248                 public void PercentageEncoding_Query ()
249                 {
250                         TestPercentageEncoding (uri => uri.Query);
251                 }
252
253                 [Test]
254                 public void PercentageEncoding_ToString ()
255                 {
256                         TestPercentageEncoding (uri => uri.ToString (), true);
257                 }
258
259                 class UriEx : Uri
260                 {
261                         public UriEx (string s) : base (s)
262                         {
263                         }
264
265                         public string UnescapeString (string s)
266                         {
267                                 return Unescape (s);
268                         }
269
270                         public static string UnescapeString (string uri, string target)
271                         {
272                                 return new UriEx (uri).UnescapeString (target);
273                         }
274                 }
275
276                 [Test]
277                 public void PercentageEncoding_Unescape ()
278                 {
279                         TestChars (str => {
280                                 var sbUpper = new StringBuilder ();
281                                 var sbLower = new StringBuilder ();
282                                 foreach (char c in str) {
283                                         sbUpper.Append (HexEscapeMultiByte (c, true));
284                                         sbLower.Append (HexEscapeMultiByte (c, false));
285                                 }
286                                 string escapedUpperStr = sbUpper.ToString ();
287                                 string escapedLowerStr = sbLower.ToString ();
288
289                                 StringTester.Assert (str + "[Unescaped]", UriEx.UnescapeString ("file://a/", str));
290                                 StringTester.Assert (escapedUpperStr + "[EscapedUpper]", UriEx.UnescapeString ("file://a/", escapedUpperStr));
291                                 StringTester.Assert (escapedLowerStr + "[EscapedLower]", UriEx.UnescapeString ("file://a/", escapedLowerStr));
292                         });
293
294                         foreach (var str in specialCases)
295                                 StringTester.Assert (str, UriEx.UnescapeString("file://a/", str));
296                 }
297
298                 [Test]
299                 public void Reduce_AbsoluteUri ()
300                 {
301                         TestReduce (uri => uri.AbsoluteUri, false);
302                 }
303
304                 [Test]
305                 public void Reduce_ToString ()
306                 {
307                         TestReduce (uri => uri.ToString (), true);
308                 }
309         }
310 }