Merge pull request #1319 from directhex/systemwide-per-arch-aot-cache
[mono.git] / mcs / nunit24 / NUnitFramework / framework / MsgUtils.cs
1 // ****************************************************************\r
2 // Copyright 2007, Charlie Poole\r
3 // This is free software licensed under the NUnit license. You may\r
4 // obtain a copy of the license at http://nunit.org/?p=license&r=2.4\r
5 // ****************************************************************\r
6 \r
7 using System;\r
8 using System.Text;\r
9 using System.Collections;\r
10 \r
11 namespace NUnit.Framework\r
12 {\r
13     /// <summary>\r
14     /// Static methods used in creating messages\r
15     /// </summary>\r
16     public class MsgUtils\r
17     {\r
18         /// <summary>\r
19         /// Static string used when strings are clipped\r
20         /// </summary>\r
21         public static readonly string ELLIPSIS = "...";\r
22 \r
23         /// <summary>\r
24         /// Returns the representation of a type as used in NUnitLite.\r
25         /// This is the same as Type.ToString() except for arrays,\r
26         /// which are displayed with their declared sizes.\r
27         /// </summary>\r
28         /// <param name="obj"></param>\r
29         /// <returns></returns>\r
30         public static string GetTypeRepresentation(object obj)\r
31         {\r
32             Array array = obj as Array;\r
33             if ( array == null )\r
34                 return string.Format( "<{0}>", obj.GetType() );\r
35 \r
36             StringBuilder sb = new StringBuilder();\r
37             Type elementType = array.GetType();\r
38             int nest = 0;\r
39             while (elementType.IsArray)\r
40             {\r
41                 elementType = elementType.GetElementType();\r
42                 ++nest;\r
43             }\r
44             sb.Append(elementType.ToString());\r
45             sb.Append('[');\r
46             for (int r = 0; r < array.Rank; r++)\r
47             {\r
48                 if (r > 0) sb.Append(',');\r
49                 sb.Append(array.GetLength(r));\r
50             }\r
51             sb.Append(']');\r
52 \r
53             while (--nest > 0)\r
54                 sb.Append("[]");\r
55 \r
56             return string.Format( "<{0}>", sb.ToString() );\r
57         }\r
58         /// <summary>\r
59         /// Converts any control characters in a string \r
60         /// to their escaped representation.\r
61         /// </summary>\r
62         /// <param name="s">The string to be converted</param>\r
63         /// <returns>The converted string</returns>\r
64         public static string ConvertWhitespace(string s)\r
65         {\r
66                         if( s != null )\r
67                         {\r
68                                 s = s.Replace( "\\", "\\\\" );\r
69                                 s = s.Replace( "\r", "\\r" );\r
70                                 s = s.Replace( "\n", "\\n" );\r
71                                 s = s.Replace( "\t", "\\t" );\r
72                         }\r
73                         return s;\r
74         }\r
75 \r
76         /// <summary>\r
77         /// Return the a string representation for a set of indices into an array\r
78         /// </summary>\r
79         /// <param name="indices">Array of indices for which a string is needed</param>\r
80         public static string GetArrayIndicesAsString(int[] indices)\r
81         {\r
82             StringBuilder sb = new StringBuilder();\r
83             sb.Append('[');\r
84             for (int r = 0; r < indices.Length; r++)\r
85             {\r
86                 if (r > 0) sb.Append(',');\r
87                 sb.Append(indices[r].ToString());\r
88             }\r
89             sb.Append(']');\r
90             return sb.ToString();\r
91         }\r
92 \r
93         /// <summary>\r
94         /// Get an array of indices representing the point in a collection or\r
95         /// array corresponding to a single int index into the collection.\r
96         /// </summary>\r
97         /// <param name="collection">The collection to which the indices apply</param>\r
98         /// <param name="index">Index in the collection</param>\r
99         /// <returns>Array of indices</returns>\r
100         public static int[] GetArrayIndicesFromCollectionIndex(ICollection collection, int index)\r
101         {\r
102             Array array = collection as Array;\r
103 \r
104             if ( array == null || array.Rank == 1)\r
105                 return new int[] { index };\r
106 \r
107             int[] result = new int[array.Rank];\r
108 \r
109             for (int r = array.Rank; --r > 0; )\r
110             {\r
111                 int l = array.GetLength(r);\r
112                 result[r] = index % l;\r
113                 index /= l;\r
114             }\r
115 \r
116             result[0] = index;\r
117             return result;\r
118         }\r
119 \r
120         /// <summary>\r
121         /// Clip a string to a given length, starting at a particular offset, returning the clipped\r
122         /// string with ellipses representing the removed parts\r
123         /// </summary>\r
124         /// <param name="s">The string to be clipped</param>\r
125         /// <param name="maxStringLength">The maximum permitted length of the result string</param>\r
126         /// <param name="clipStart">The point at which to start clipping</param>\r
127         /// <returns>The clipped string</returns>\r
128         public static string ClipString(string s, int maxStringLength, int clipStart)\r
129         {\r
130             int clipLength = maxStringLength;\r
131             StringBuilder sb = new StringBuilder();\r
132 \r
133             if (clipStart > 0)\r
134             {\r
135                 clipLength -= ELLIPSIS.Length;\r
136                 sb.Append( ELLIPSIS );\r
137             }\r
138 \r
139             if (s.Length - clipStart > clipLength)\r
140             {\r
141                 clipLength -= ELLIPSIS.Length;\r
142                 sb.Append( s.Substring( clipStart, clipLength ));\r
143                 sb.Append(ELLIPSIS);\r
144             }\r
145             else if (clipStart > 0)\r
146                 sb.Append( s.Substring(clipStart));\r
147             else\r
148                 sb.Append( s );\r
149  \r
150             return sb.ToString();\r
151         }\r
152 \r
153         /// <summary>\r
154         /// Clip the expected and actual strings in a coordinated fashion, \r
155         /// so that they may be displayed together.\r
156         /// </summary>\r
157         /// <param name="expected"></param>\r
158         /// <param name="actual"></param>\r
159         /// <param name="maxDisplayLength"></param>\r
160         /// <param name="mismatch"></param>\r
161         public static void ClipExpectedAndActual(ref string expected, ref string actual, int maxDisplayLength, int mismatch)\r
162         {\r
163             // Case 1: Both strings fit on line\r
164             int maxStringLength = Math.Max(expected.Length, actual.Length);\r
165             if (maxStringLength <= maxDisplayLength)\r
166                 return;\r
167 \r
168             // Case 2: Assume that the tail of each string fits on line\r
169             int clipLength = maxDisplayLength - ELLIPSIS.Length;\r
170             int tailLength = clipLength - mismatch;\r
171             int clipStart = maxStringLength - clipLength;\r
172 \r
173             // Case 3: If it doesn't, center the mismatch position\r
174             if ( clipStart > mismatch )\r
175                 clipStart = Math.Max( 0, mismatch - clipLength / 2 );\r
176 \r
177             expected = ClipString(expected, maxDisplayLength, clipStart);\r
178             actual = ClipString(actual, maxDisplayLength, clipStart);\r
179         }\r
180 \r
181         /// <summary>\r
182         /// Shows the position two strings start to differ.  Comparison \r
183         /// starts at the start index.\r
184         /// </summary>\r
185         /// <param name="expected">The expected string</param>\r
186         /// <param name="actual">The actual string</param>\r
187         /// <param name="istart">The index in the strings at which comparison should start</param>\r
188         /// <param name="ignoreCase">Boolean indicating whether case should be ignored</param>\r
189         /// <returns>-1 if no mismatch found, or the index where mismatch found</returns>\r
190         static public int FindMismatchPosition(string expected, string actual, int istart, bool ignoreCase)\r
191         {\r
192             int length = Math.Min(expected.Length, actual.Length);\r
193 \r
194             string s1 = ignoreCase ? expected.ToLower() : expected;\r
195             string s2 = ignoreCase ? actual.ToLower() : actual;\r
196 \r
197             for (int i = istart; i < length; i++)\r
198             {\r
199                 if (s1[i] != s2[i])\r
200                     return i;\r
201             }\r
202 \r
203             //\r
204             // Strings have same content up to the length of the shorter string.\r
205             // Mismatch occurs because string lengths are different, so show\r
206             // that they start differing where the shortest string ends\r
207             //\r
208             if (expected.Length != actual.Length)\r
209                 return length;\r
210 \r
211             //\r
212             // Same strings : We shouldn't get here\r
213             //\r
214             return -1;\r
215         }\r
216     }\r
217 }\r