[NUI] Rebase develnui (DevelNUI only patches --> master) (#3910)
[platform/core/csapi/tizenfx.git] / test / Tizen.NUI.Devel.Tests.Ubuntu / nunit.framework / Internal / TestNameGenerator.cs
1 // ***********************************************************************
2 // Copyright (c) 2015 Charlie Poole
3 //
4 // Permission is hereby granted, free of charge, to any person obtaining
5 // a copy of this software and associated documentation files (the
6 // "Software"), to deal in the Software without restriction, including
7 // without limitation the rights to use, copy, modify, merge, publish,
8 // distribute, sublicense, and/or sell copies of the Software, and to
9 // permit persons to whom the Software is furnished to do so, subject to
10 // the following conditions:
11 // 
12 // The above copyright notice and this permission notice shall be
13 // included in all copies or substantial portions of the Software.
14 // 
15 // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
16 // EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
17 // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
18 // NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
19 // LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
20 // OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
21 // WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
22 // ***********************************************************************
23 #define PORTABLE
24 #define TIZEN
25 #define NUNIT_FRAMEWORK
26 #define NUNITLITE
27 #define NET_4_5
28 #define PARALLEL
29 using System;
30 using System.Collections.Generic;
31 using System.Reflection;
32 using System.Text;
33
34 namespace NUnit.Framework.Internal
35 {
36     /// <summary>
37     /// TestNameGenerator is able to create test names according to
38     /// a coded pattern.
39     /// </summary>
40     public class TestNameGenerator
41     {
42         // TODO: Using a static here is not good it's the easiest
43         // way to get a temporary implementation without passing the
44         // pattern all the way down the test builder hierarchy
45
46         /// <summary>
47         /// Default pattern used to generate names
48         /// </summary>
49         public static string DefaultTestNamePattern = "{m}{a}";
50
51         // The name pattern used by this TestNameGenerator
52         private string _pattern;
53
54         // The list of NameFragments used to generate names
55         private List<NameFragment> _fragments;
56
57         /// <summary>
58         /// Construct a TestNameGenerator
59         /// </summary>
60         public TestNameGenerator()
61         {
62             _pattern = DefaultTestNamePattern;
63         }
64
65         /// <summary>
66         /// Construct a TestNameGenerator
67         /// </summary>
68         /// <param name="pattern">The pattern used by this generator.</param>
69         public TestNameGenerator(string pattern)
70         {
71             _pattern = pattern;
72         }
73
74         /// <summary>
75         /// Get the display name for a TestMethod and it's arguments
76         /// </summary>
77         /// <param name="testMethod">A TestMethod</param>
78         /// <returns>The display name</returns>
79         public string GetDisplayName(TestMethod testMethod)
80         {
81             return GetDisplayName(testMethod, null);
82         }
83
84         /// <summary>
85         /// Get the display name for a TestMethod and it's arguments
86         /// </summary>
87         /// <param name="testMethod">A TestMethod</param>
88         /// <param name="args">Arguments to be used</param>
89         /// <returns>The display name</returns>
90         public string GetDisplayName(TestMethod testMethod, object[] args)
91         {
92             if (_fragments == null)
93                 _fragments = BuildFragmentList(_pattern);
94
95             var result = new StringBuilder();
96
97             foreach (var fragment in _fragments)
98                 result.Append(fragment.GetText(testMethod, args));
99
100             return result.ToString();
101         }
102
103         #region Helper Methods
104
105         private static List<NameFragment> BuildFragmentList(string pattern)
106         {
107             var fragments = new List<NameFragment>();
108
109             // Build a list of actions so this generator can be applied to
110             // multiple types and methods.
111
112             int start = 0;
113             while (start < pattern.Length)
114             {
115                 int lcurly = pattern.IndexOf('{', start);
116                 if (lcurly < 0) // No more substitutions in pattern
117                     break;
118
119                 int rcurly = pattern.IndexOf('}', lcurly);
120                 if (rcurly < 0)
121                     break;
122
123                 if (lcurly > start) // Handle fixedixed text before curly brace
124                     fragments.Add(new FixedTextFragment(pattern.Substring(start, lcurly - start)));
125
126                 string token = pattern.Substring(lcurly, rcurly - lcurly + 1);
127
128                 switch (token)
129                 {
130                     case "{m}":
131                         fragments.Add(new MethodNameFragment());
132                         break;
133                     case "{i}":
134                         fragments.Add(new TestIDFragment());
135                         break;
136                     case "{n}":
137                         fragments.Add(new NamespaceFragment());
138                         break;
139                     case "{c}":
140                         fragments.Add(new ClassNameFragment());
141                         break;
142                     case "{C}":
143                         fragments.Add(new ClassFullNameFragment());
144                         break;
145                     case "{M}":
146                         fragments.Add(new MethodFullNameFragment());
147                         break;
148                     case "{a}":
149                         fragments.Add(new ArgListFragment(0));
150                         break;
151                     case "{0}":
152                     case "{1}":
153                     case "{2}":
154                     case "{3}":
155                     case "{4}":
156                     case "{5}":
157                     case "{6}":
158                     case "{7}":
159                     case "{8}":
160                     case "{9}":
161                         int index = token[1] - '0';
162                         fragments.Add(new ArgumentFragment(index, 40));
163                         break;
164                     default:
165                         char c = token[1];
166                         if (token.Length >= 5 && token[2] == ':' && (c == 'a' || char.IsDigit(c)))
167                         {
168                             int length;
169
170                             // NOTE: The code would be much simpler using TryParse. However,
171                             // that method doesn't exist in the Compact Framework.
172                             try
173                             {
174                                 length = int.Parse(token.Substring(3, token.Length - 4));
175                             }
176                             catch
177                             {
178                                 length = -1;
179                             }
180                             if (length > 0)
181                             {
182                                 if (c == 'a')
183                                     fragments.Add(new ArgListFragment(length));
184                                 else // It's a digit
185                                     fragments.Add(new ArgumentFragment(c - '0', length));
186                                 break;
187                             }
188                         }
189
190                         // Output the erroneous token to aid user in debugging
191                         fragments.Add(new FixedTextFragment(token));
192                         break;
193                 }
194
195                 start = rcurly + 1;
196             }
197
198
199             // Output any trailing plain text
200             if (start < pattern.Length)
201                 fragments.Add(new FixedTextFragment(pattern.Substring(start)));
202
203             return fragments;
204         }
205
206         #endregion
207
208         #region Nested Classes Representing Name Fragments
209
210         private abstract class NameFragment
211         {
212             private const string THREE_DOTS = "...";
213
214             public virtual string GetText(TestMethod testMethod, object[] args)
215             {
216                 return GetText(testMethod.Method.MethodInfo, args);
217             }
218
219             public abstract string GetText(MethodInfo method, object[] args);
220
221             protected static void AppendGenericTypeNames(StringBuilder sb, MethodInfo method)
222             {
223                 sb.Append("<");
224                 int cnt = 0;
225                 foreach (Type t in method.GetGenericArguments())
226                 {
227                     if (cnt++ > 0) sb.Append(",");
228                     sb.Append(t.Name);
229                 }
230                 sb.Append(">");
231             }
232
233             protected static string GetDisplayString(object arg, int stringMax)
234             {
235                 string display = arg == null
236                     ? "null"
237                     : Convert.ToString(arg, System.Globalization.CultureInfo.InvariantCulture);
238
239                 if (arg is double)
240                 {
241                     double d = (double)arg;
242
243                     if (double.IsNaN(d))
244                         display = "double.NaN";
245                     else if (double.IsPositiveInfinity(d))
246                         display = "double.PositiveInfinity";
247                     else if (double.IsNegativeInfinity(d))
248                         display = "double.NegativeInfinity";
249                     else if (d == double.MaxValue)
250                         display = "double.MaxValue";
251                     else if (d == double.MinValue)
252                         display = "double.MinValue";
253                     else
254                     {
255                         if (display.IndexOf('.') == -1)
256                             display += ".0";
257                         display += "d";
258                     }
259                 }
260                 else if (arg is float)
261                 {
262                     float f = (float)arg;
263
264                     if (float.IsNaN(f))
265                         display = "float.NaN";
266                     else if (float.IsPositiveInfinity(f))
267                         display = "float.PositiveInfinity";
268                     else if (float.IsNegativeInfinity(f))
269                         display = "float.NegativeInfinity";
270                     else if (f == float.MaxValue)
271                         display = "float.MaxValue";
272                     else if (f == float.MinValue)
273                         display = "float.MinValue";
274                     else
275                     {
276                         if (display.IndexOf('.') == -1)
277                             display += ".0";
278                         display += "f";
279                     }
280                 }
281                 else if (arg is decimal)
282                 {
283                     decimal d = (decimal)arg;
284                     if (d == decimal.MinValue)
285                         display = "decimal.MinValue";
286                     else if (d == decimal.MaxValue)
287                         display = "decimal.MaxValue";
288                     else
289                         display += "m";
290                 }
291                 else if (arg is long)
292                 {
293                     if (arg.Equals(long.MinValue))
294                         display = "long.MinValue";
295                     else if (arg.Equals(long.MaxValue))
296                         display = "long.MaxValue";
297                     else
298                         display += "L";
299                 }
300                 else if (arg is ulong)
301                 {
302                     ulong ul = (ulong)arg;
303                     if (ul == ulong.MinValue)
304                         display = "ulong.MinValue";
305                     else if (ul == ulong.MaxValue)
306                         display = "ulong.MaxValue";
307                     else
308                         display += "UL";
309                 }
310                 else if (arg is string)
311                 {
312                     var str = (string)arg;
313                     bool tooLong = stringMax > 0 && str.Length > stringMax;
314                     int limit = tooLong ? stringMax - THREE_DOTS.Length : 0;
315
316                     StringBuilder sb = new StringBuilder();
317                     sb.Append("\"");
318                     foreach (char c in str)
319                     {
320                         sb.Append(EscapeCharInString(c));
321                         if (tooLong && sb.Length > limit)
322                         {
323                             sb.Append(THREE_DOTS);
324                             break;
325                         }
326                     }
327                     sb.Append("\"");
328                     display = sb.ToString();
329                 }
330                 else if (arg is char)
331                 {
332                     display = "\'" + EscapeSingleChar((char)arg) + "\'";
333                 }
334                 else if (arg is int)
335                 {
336                     if (arg.Equals(int.MaxValue))
337                         display = "int.MaxValue";
338                     else if (arg.Equals(int.MinValue))
339                         display = "int.MinValue";
340                 }
341                 else if (arg is uint)
342                 {
343                     if (arg.Equals(uint.MaxValue))
344                         display = "uint.MaxValue";
345                     else if (arg.Equals(uint.MinValue))
346                         display = "uint.MinValue";
347                 }
348                 else if (arg is short)
349                 {
350                     if (arg.Equals(short.MaxValue))
351                         display = "short.MaxValue";
352                     else if (arg.Equals(short.MinValue))
353                         display = "short.MinValue";
354                 }
355                 else if (arg is ushort)
356                 {
357                     if (arg.Equals(ushort.MaxValue))
358                         display = "ushort.MaxValue";
359                     else if (arg.Equals(ushort.MinValue))
360                         display = "ushort.MinValue";
361                 }
362                 else if (arg is byte)
363                 {
364                     if (arg.Equals(byte.MaxValue))
365                         display = "byte.MaxValue";
366                     else if (arg.Equals(byte.MinValue))
367                         display = "byte.MinValue";
368                 }
369                 else if (arg is sbyte)
370                 {
371                     if (arg.Equals(sbyte.MaxValue))
372                         display = "sbyte.MaxValue";
373                     else if (arg.Equals(sbyte.MinValue))
374                         display = "sbyte.MinValue";
375                 }
376
377                 return display;
378             }
379
380             private static string EscapeSingleChar(char c)
381             {
382                 if (c == '\'')
383                     return "\\\'";
384
385                 return EscapeControlChar(c);
386             }
387
388             private static string EscapeCharInString(char c)
389             {
390                 if (c == '"')
391                     return "\\\"";
392
393                 return EscapeControlChar(c);
394             }
395             
396             private static string EscapeControlChar(char c)
397             {
398                 switch (c)
399                 {
400                     case '\\':
401                         return "\\\\";
402                     case '\0':
403                         return "\\0";
404                     case '\a':
405                         return "\\a";
406                     case '\b':
407                         return "\\b";
408                     case '\f':
409                         return "\\f";
410                     case '\n':
411                         return "\\n";
412                     case '\r':
413                         return "\\r";
414                     case '\t':
415                         return "\\t";
416                     case '\v':
417                         return "\\v";
418
419                     case '\x0085':
420                     case '\x2028':
421                     case '\x2029':
422                         return string.Format("\\x{0:X4}", (int)c);
423
424                     default:
425                         return c.ToString();
426                 }
427             }
428         }
429
430         private class TestIDFragment : NameFragment
431         {
432             public override string GetText(MethodInfo method, object[] args)
433             {
434                 return "{i}"; // No id available using MethodInfo
435             }
436
437             public override string GetText(TestMethod testMethod, object[] args)
438             {
439                 return testMethod.Id;
440             }
441         }
442
443         private class FixedTextFragment : NameFragment
444         {
445             private string _text;
446
447             public FixedTextFragment(string text)
448             {
449                 _text = text;
450             }
451
452             public override string GetText(MethodInfo method, object[] args)
453             {
454                 return _text;
455             }
456         }
457
458         private class MethodNameFragment : NameFragment
459         {
460             public override string GetText(MethodInfo method, object[] args)
461             {
462                 var sb = new StringBuilder();
463
464                 sb.Append(method.Name);
465
466                 if (method.IsGenericMethod)
467                     AppendGenericTypeNames(sb, method);
468
469                 return sb.ToString();
470             }
471         }
472
473         private class NamespaceFragment : NameFragment
474         {
475             public override string GetText(MethodInfo method, object[] args)
476             {
477                 return method.DeclaringType.Namespace;
478             }
479         }
480
481         private class MethodFullNameFragment : NameFragment
482         {
483             public override string GetText(MethodInfo method, object[] args)
484             {
485                 var sb = new StringBuilder();
486
487                 sb.Append(method.DeclaringType.FullName);
488                 sb.Append('.');
489                 sb.Append(method.Name);
490
491                 if (method.IsGenericMethod)
492                     AppendGenericTypeNames(sb, method);
493
494                 return sb.ToString();
495             }
496         }
497
498         private class ClassNameFragment : NameFragment
499         {
500             public override string GetText(MethodInfo method, object[] args)
501             {
502                 return method.DeclaringType.Name;
503             }
504         }
505
506         private class ClassFullNameFragment : NameFragment
507         {
508             public override string GetText(MethodInfo method, object[] args)
509             {
510                 return method.DeclaringType.FullName;
511             }
512         }
513
514         private class ArgListFragment : NameFragment
515         {
516             private int _maxStringLength;
517
518             public ArgListFragment(int maxStringLength)
519             {
520                 _maxStringLength = maxStringLength;
521             }
522
523             public override string GetText(MethodInfo method, object[] arglist)
524             {
525                 var sb = new StringBuilder();
526
527                 if (arglist != null)
528                 {
529                     sb.Append('(');
530
531                     for (int i = 0; i < arglist.Length; i++)
532                     {
533                         if (i > 0) sb.Append(",");
534                         sb.Append(GetDisplayString(arglist[i], _maxStringLength));
535                     }
536                     
537                     sb.Append(')');
538                 }
539
540                 return sb.ToString();
541             }
542         }
543
544         private class ArgumentFragment : NameFragment
545         {
546             private int _index;
547             private int _maxStringLength;
548
549             public ArgumentFragment(int index, int maxStringLength)
550             {
551                 _index = index;
552                 _maxStringLength = maxStringLength;
553             }
554
555             public override string GetText(MethodInfo method, object[] args)
556             {
557                 return _index < args.Length
558                     ? GetDisplayString(args[_index], _maxStringLength)
559                     : string.Empty;
560             }
561         }
562
563         #endregion
564     }
565 }