PageRenderTime 24ms CodeModel.GetById 2ms app.highlight 16ms RepoModel.GetById 2ms app.codeStats 0ms

/src/NUnit/util/XmlResultWriter.cs

#
C# | 335 lines | 268 code | 45 blank | 22 comment | 42 complexity | 2aabafcee34144630906546940f16376 MD5 | raw file
  1// ****************************************************************
  2// This is free software licensed under the NUnit license. You
  3// may obtain a copy of the license as well as information regarding
  4// copyright ownership at http://nunit.org.
  5// ****************************************************************
  6
  7namespace NUnit.Util
  8{
  9	using System;
 10	using System.Globalization;
 11	using System.IO;
 12	using System.Xml;
 13    using System.Collections;
 14	using System.Reflection;
 15	using NUnit.Core;
 16
 17	/// <summary>
 18	/// Summary description for XmlResultWriter.
 19	/// </summary>
 20	public class XmlResultWriter
 21	{
 22		private XmlTextWriter xmlWriter;
 23		private TextWriter writer;
 24		private MemoryStream memoryStream;
 25
 26		#region Constructors
 27		public XmlResultWriter(string fileName)
 28		{
 29			xmlWriter = new XmlTextWriter( new StreamWriter(fileName, false, System.Text.Encoding.UTF8) );
 30		}
 31
 32        public XmlResultWriter( TextWriter writer )
 33		{
 34			this.memoryStream = new MemoryStream();
 35			this.writer = writer;
 36			this.xmlWriter = new XmlTextWriter( new StreamWriter( memoryStream, System.Text.Encoding.UTF8 ) );
 37		}
 38		#endregion
 39
 40		private void InitializeXmlFile(TestResult result) 
 41		{
 42			ResultSummarizer summaryResults = new ResultSummarizer(result);
 43
 44			xmlWriter.Formatting = Formatting.Indented;
 45			xmlWriter.WriteStartDocument(false);
 46			xmlWriter.WriteComment("This file represents the results of running a test suite");
 47
 48			xmlWriter.WriteStartElement("test-results");
 49
 50			xmlWriter.WriteAttributeString("name", summaryResults.Name);
 51			xmlWriter.WriteAttributeString("total", summaryResults.TestsRun.ToString());
 52            xmlWriter.WriteAttributeString("errors", summaryResults.Errors.ToString());
 53            xmlWriter.WriteAttributeString("failures", summaryResults.Failures.ToString());
 54            xmlWriter.WriteAttributeString("not-run", summaryResults.TestsNotRun.ToString());
 55            xmlWriter.WriteAttributeString("inconclusive", summaryResults.Inconclusive.ToString());
 56            xmlWriter.WriteAttributeString("ignored", summaryResults.Ignored.ToString());
 57            xmlWriter.WriteAttributeString("skipped", summaryResults.Skipped.ToString());
 58            xmlWriter.WriteAttributeString("invalid", summaryResults.NotRunnable.ToString());
 59
 60			DateTime now = DateTime.Now;
 61			xmlWriter.WriteAttributeString("date", XmlConvert.ToString( now, "yyyy-MM-dd" ) );
 62			xmlWriter.WriteAttributeString("time", XmlConvert.ToString( now, "HH:mm:ss" ));
 63			WriteEnvironment();
 64			WriteCultureInfo();
 65		}
 66
 67		private void WriteCultureInfo() {
 68			xmlWriter.WriteStartElement("culture-info");
 69			xmlWriter.WriteAttributeString("current-culture",
 70			                               CultureInfo.CurrentCulture.ToString());
 71			xmlWriter.WriteAttributeString("current-uiculture",
 72			                               CultureInfo.CurrentUICulture.ToString());
 73			xmlWriter.WriteEndElement();
 74		}
 75
 76		private void WriteEnvironment() {
 77			xmlWriter.WriteStartElement("environment");
 78			xmlWriter.WriteAttributeString("nunit-version", 
 79										   Assembly.GetExecutingAssembly().GetName().Version.ToString());
 80			xmlWriter.WriteAttributeString("clr-version", 
 81			                               Environment.Version.ToString());
 82			xmlWriter.WriteAttributeString("os-version",
 83			                               Environment.OSVersion.ToString());
 84			xmlWriter.WriteAttributeString("platform",
 85				Environment.OSVersion.Platform.ToString());
 86			xmlWriter.WriteAttributeString("cwd",
 87			                               Environment.CurrentDirectory);
 88			xmlWriter.WriteAttributeString("machine-name",
 89			                               Environment.MachineName);
 90			xmlWriter.WriteAttributeString("user",
 91			                               Environment.UserName);
 92			xmlWriter.WriteAttributeString("user-domain",
 93			                               Environment.UserDomainName);
 94			xmlWriter.WriteEndElement();
 95		}
 96
 97		#region Public Methods
 98		public void SaveTestResult( TestResult result )
 99		{
100			InitializeXmlFile( result );
101			WriteResultElement( result );
102			TerminateXmlFile();
103		}
104
105        private void WriteResultElement( TestResult result )
106        {
107			StartTestElement( result );
108
109			WriteCategoriesElement(result);
110			WritePropertiesElement(result);
111
112            switch (result.ResultState)
113            {
114                case ResultState.Ignored:
115                case ResultState.NotRunnable:
116                case ResultState.Skipped:
117                    WriteReasonElement(result);
118                    break;
119
120                case ResultState.Failure:
121                case ResultState.Error:
122                case ResultState.Cancelled:
123                    if (!result.Test.IsSuite || result.FailureSite == FailureSite.SetUp)
124                        WriteFailureElement(result);
125                    break;
126                case ResultState.Success:
127                case ResultState.Inconclusive:
128                    if (result.Message != null)
129                        WriteReasonElement(result);
130                    break;
131            }
132
133			if ( result.HasResults )
134				WriteChildResults( result );
135
136			xmlWriter.WriteEndElement(); // test element
137		}
138
139		private void TerminateXmlFile()
140		{
141			try 
142			{
143				xmlWriter.WriteEndElement(); // test-results
144				xmlWriter.WriteEndDocument();
145				xmlWriter.Flush();
146
147				if ( memoryStream != null && writer != null )
148				{
149					memoryStream.Position = 0;
150					using ( StreamReader rdr = new StreamReader( memoryStream ) )
151					{
152						writer.Write( rdr.ReadToEnd() );
153					}
154				}
155
156				xmlWriter.Close();
157			} 
158			finally 
159			{
160				//writer.Close();
161			}
162		}
163		#endregion
164
165		#region Element Creation Helpers
166		private void StartTestElement(TestResult result)
167		{
168            if (result.Test.IsSuite)
169            {
170                xmlWriter.WriteStartElement("test-suite");
171                xmlWriter.WriteAttributeString("type", result.Test.TestType);
172                xmlWriter.WriteAttributeString("name", result.Name);
173            }
174            else
175            {
176                xmlWriter.WriteStartElement("test-case");
177                xmlWriter.WriteAttributeString("name", result.FullName);
178            }
179
180			if (result.Description != null)
181				xmlWriter.WriteAttributeString("description", result.Description);
182
183			xmlWriter.WriteAttributeString("executed", result.Executed.ToString());
184            xmlWriter.WriteAttributeString("result", result.ResultState.ToString());
185			
186			if ( result.Executed )
187			{
188				xmlWriter.WriteAttributeString("success", result.IsSuccess.ToString());
189				xmlWriter.WriteAttributeString("time", result.Time.ToString("#####0.000", NumberFormatInfo.InvariantInfo));
190				xmlWriter.WriteAttributeString("asserts", result.AssertCount.ToString());
191			}
192		}
193
194		private void WriteCategoriesElement(TestResult result)
195		{
196			if (result.Test.Categories != null && result.Test.Categories.Count > 0)
197			{
198				xmlWriter.WriteStartElement("categories");
199				foreach (string category in result.Test.Categories)
200				{
201					xmlWriter.WriteStartElement("category");
202					xmlWriter.WriteAttributeString("name", category);
203					xmlWriter.WriteEndElement();
204				}
205				xmlWriter.WriteEndElement();
206			}
207		}
208
209		private void WritePropertiesElement(TestResult result)
210		{
211            IDictionary props = result.Test.Properties;
212
213			if (result.Test.Properties != null && props.Count > 0)
214			{
215                int nprops = 0;
216
217				foreach (string key in result.Test.Properties.Keys)
218				{
219                    if ( !key.StartsWith("_") )
220                    {
221                        object val = result.Test.Properties[key];
222                        if (val != null)
223                        {
224                            if ( nprops == 0 )
225                                xmlWriter.WriteStartElement("properties");
226
227                            xmlWriter.WriteStartElement("property");
228                            xmlWriter.WriteAttributeString("name", key);
229                            xmlWriter.WriteAttributeString("value", val.ToString());
230                            xmlWriter.WriteEndElement();
231
232                            ++nprops;
233                        }
234                    }
235				}
236
237                if ( nprops > 0 )
238				    xmlWriter.WriteEndElement();
239			}
240		}
241
242		private void WriteReasonElement(TestResult result)
243		{
244			xmlWriter.WriteStartElement("reason");
245			xmlWriter.WriteStartElement("message");
246			xmlWriter.WriteCData(result.Message);
247			xmlWriter.WriteEndElement();
248			xmlWriter.WriteEndElement();
249		}
250
251		private void WriteFailureElement(TestResult result)
252		{
253			xmlWriter.WriteStartElement("failure");
254
255			xmlWriter.WriteStartElement("message");
256            WriteCData(result.Message);
257			xmlWriter.WriteEndElement();
258
259			xmlWriter.WriteStartElement("stack-trace");
260            if (result.StackTrace != null)
261                WriteCData(StackTraceFilter.Filter(result.StackTrace));
262			xmlWriter.WriteEndElement();
263
264			xmlWriter.WriteEndElement();
265		}
266
267		private void WriteChildResults(TestResult result)
268		{
269			xmlWriter.WriteStartElement("results");
270
271			if ( result.HasResults )
272				foreach (TestResult childResult in result.Results)
273					WriteResultElement( childResult );
274
275			xmlWriter.WriteEndElement();
276		}
277		#endregion
278
279		#region Output Helpers
280		/// <summary>
281		/// Makes string safe for xml parsing, replacing control chars with '?'
282		/// </summary>
283		/// <param name="encodedString">string to make safe</param>
284		/// <returns>xml safe string</returns>
285		private static string CharacterSafeString(string encodedString)
286		{
287			/*The default code page for the system will be used.
288			Since all code pages use the same lower 128 bytes, this should be sufficient
289			for finding uprintable control characters that make the xslt processor error.
290			We use characters encoded by the default code page to avoid mistaking bytes as
291			individual characters on non-latin code pages.*/
292			char[] encodedChars = System.Text.Encoding.Default.GetChars(System.Text.Encoding.Default.GetBytes(encodedString));
293			
294			System.Collections.ArrayList pos = new System.Collections.ArrayList();
295			for(int x = 0 ; x < encodedChars.Length ; x++)
296			{
297				char currentChar = encodedChars[x];
298				//unprintable characters are below 0x20 in Unicode tables
299				//some control characters are acceptable. (carriage return 0x0D, line feed 0x0A, horizontal tab 0x09)
300				if(currentChar < 32 && (currentChar != 9 && currentChar != 10 && currentChar != 13))
301				{
302					//save the array index for later replacement.
303					pos.Add(x);
304				}
305			}
306			foreach(int index in pos)
307			{
308				encodedChars[index] = '?';//replace unprintable control characters with ?(3F)
309			}
310			return System.Text.Encoding.Default.GetString(System.Text.Encoding.Default.GetBytes(encodedChars));
311		}
312
313        private void WriteCData(string text)
314        {
315            int start = 0;
316            while (true)
317            {
318                int illegal = text.IndexOf("]]>", start);
319                if (illegal < 0)
320                    break;
321                xmlWriter.WriteCData(text.Substring(start, illegal - start + 2));
322                start = illegal + 2;
323                if (start >= text.Length)
324                    return;
325            }
326
327            if (start > 0)
328                xmlWriter.WriteCData(text.Substring(start));
329            else
330                xmlWriter.WriteCData(text);
331        }
332
333		#endregion
334	}
335}