**** Merged from MCS ****
[mono-project.git] / mcs / nunit20 / nunit-console / ConsoleUi.cs
blob23780997bd267c2d6d78b6a8da70782a8ad03b47
1 #region Copyright (c) 2002-2003, James W. Newkirk, Michael C. Two, Alexei A. Vorontsov, Charlie Poole, Philip A. Craig
2 /************************************************************************************
4 ' Copyright © 2002-2003 James W. Newkirk, Michael C. Two, Alexei A. Vorontsov, Charlie Poole
5 ' Copyright © 2000-2003 Philip A. Craig
7 ' This software is provided 'as-is', without any express or implied warranty. In no
8 ' event will the authors be held liable for any damages arising from the use of this
9 ' software.
11 ' Permission is granted to anyone to use this software for any purpose, including
12 ' commercial applications, and to alter it and redistribute it freely, subject to the
13 ' following restrictions:
15 ' 1. The origin of this software must not be misrepresented; you must not claim that
16 ' you wrote the original software. If you use this software in a product, an
17 ' acknowledgment (see the following) in the product documentation is required.
19 ' Portions Copyright © 2003 James W. Newkirk, Michael C. Two, Alexei A. Vorontsov, Charlie Poole
20 ' or Copyright © 2000-2003 Philip A. Craig
22 ' 2. Altered source versions must be plainly marked as such, and must not be
23 ' misrepresented as being the original software.
25 ' 3. This notice may not be removed or altered from any source distribution.
27 '***********************************************************************************/
28 #endregion
30 namespace NUnit.Console
32 using System;
33 using System.Collections;
34 using System.Collections.Specialized;
35 using System.IO;
36 using System.Reflection;
37 using System.Xml;
38 using System.Xml.Xsl;
39 using System.Xml.XPath;
40 using System.Resources;
41 using System.Text;
42 using System.Text.RegularExpressions;
43 using System.Diagnostics;
44 using NUnit.Core;
45 using NUnit.Util;
48 /// <summary>
49 /// Summary description for ConsoleUi.
50 /// </summary>
51 public class ConsoleUi
53 [STAThread]
54 public static int Main(string[] args)
56 ConsoleOptions options = new ConsoleOptions(args);
57 if(!options.nologo)
58 WriteCopyright();
60 if(options.help)
62 options.Help();
63 return 0;
66 if(options.NoArgs)
68 Console.Error.WriteLine("fatal error: no inputs specified");
69 options.Help();
70 return 0;
73 if(!options.Validate())
75 Console.Error.WriteLine("fatal error: invalid arguments");
76 options.Help();
77 return 2;
80 try
82 ConsoleUi consoleUi = new ConsoleUi();
83 return consoleUi.Execute( options );
85 catch( FileNotFoundException ex )
87 Console.WriteLine( ex.Message );
88 return 2;
90 catch( BadImageFormatException ex )
92 Console.WriteLine( ex.Message );
93 return 2;
95 catch( Exception ex )
97 Console.WriteLine( "Unhandled Exception:\n{0}", ex.ToString() );
98 return 2;
100 finally
102 if(options.wait)
104 Console.Out.WriteLine("\nHit <enter> key to continue");
105 Console.ReadLine();
110 private static XmlTextReader GetTransformReader(ConsoleOptions parser)
112 XmlTextReader reader = null;
113 if(!parser.IsTransform)
115 Assembly assembly = Assembly.GetAssembly(typeof(XmlResultVisitor));
116 ResourceManager resourceManager = new ResourceManager("NUnit.Util.Transform",assembly);
117 string xmlData = (string)resourceManager.GetObject("Summary.xslt");
119 reader = new XmlTextReader(new StringReader(xmlData));
121 else
123 FileInfo xsltInfo = new FileInfo(parser.transform);
124 if(!xsltInfo.Exists)
126 Console.Error.WriteLine("Transform file: {0} does not exist", xsltInfo.FullName);
127 reader = null;
129 else
131 reader = new XmlTextReader(xsltInfo.FullName);
135 return reader;
138 private static void WriteCopyright()
140 Assembly executingAssembly = Assembly.GetExecutingAssembly();
141 System.Version version = executingAssembly.GetName().Version;
143 object[] objectAttrs = executingAssembly.GetCustomAttributes(typeof(AssemblyProductAttribute), false);
144 AssemblyProductAttribute productAttr = (AssemblyProductAttribute)objectAttrs[0];
146 objectAttrs = executingAssembly.GetCustomAttributes(typeof(AssemblyCopyrightAttribute), false);
147 AssemblyCopyrightAttribute copyrightAttr = (AssemblyCopyrightAttribute)objectAttrs[0];
149 Console.WriteLine(String.Format("{0} version {1}", productAttr.Product, version.ToString(3)));
150 Console.WriteLine(copyrightAttr.Copyright);
151 Console.WriteLine();
153 string clrPlatform = Type.GetType("Mono.Runtime", false) == null ? ".NET" : "Mono";
154 Console.WriteLine( string.Format("OS Version: {0} {1} Version: {2}",
155 Environment.OSVersion, clrPlatform, Environment.Version ) );
156 Console.WriteLine();
159 private static Test MakeTestFromCommandLine(TestDomain testDomain, ConsoleOptions parser)
161 NUnitProject project;
163 if ( parser.IsTestProject )
165 project = NUnitProject.LoadProject( (string)parser.Parameters[0] );
166 string configName = (string) parser.config;
167 if ( configName != null )
168 project.SetActiveConfig( configName );
170 else
171 project = NUnitProject.FromAssemblies( (string[])parser.Parameters.ToArray( typeof( string ) ) );
173 return testDomain.Load( project, parser.fixture );
176 public ConsoleUi()
180 public int Execute( ConsoleOptions options )
182 XmlTextReader transformReader = GetTransformReader(options);
183 if(transformReader == null) return 3;
185 ConsoleWriter outStream = options.isOut
186 ? new ConsoleWriter( new StreamWriter( options.output ) )
187 : new ConsoleWriter(Console.Out);
189 ConsoleWriter errorStream = options.isErr
190 ? new ConsoleWriter( new StreamWriter( options.err ) )
191 : new ConsoleWriter(Console.Error);
193 TestDomain testDomain = new TestDomain(outStream, errorStream);
194 if ( options.noshadow ) testDomain.ShadowCopyFiles = false;
196 Test test = MakeTestFromCommandLine(testDomain, options);
198 if(test == null)
200 Console.Error.WriteLine("Unable to locate fixture {0}", options.fixture);
201 return 2;
204 Directory.SetCurrentDirectory(new FileInfo((string)options.Parameters[0]).DirectoryName);
206 EventListener collector = new EventCollector( options, outStream );
208 string savedDirectory = Environment.CurrentDirectory;
210 if (options.HasInclude)
212 Console.WriteLine( "Included categories: " + options.include );
213 testDomain.SetFilter( new CategoryFilter( options.IncludedCategories ) );
215 else if ( options.HasExclude )
217 Console.WriteLine( "Excluded categories: " + options.exclude );
218 testDomain.SetFilter( new CategoryFilter( options.ExcludedCategories, true ) );
221 TestResult result = null;
222 if ( options.thread )
224 testDomain.RunTest( collector );
225 testDomain.Wait();
226 result = testDomain.Result;
228 else
230 result = testDomain.Run( collector );
233 Directory.SetCurrentDirectory( savedDirectory );
235 Console.WriteLine();
237 string xmlOutput = CreateXmlOutput( result );
239 if (options.xmlConsole)
240 Console.WriteLine(xmlOutput);
241 else
242 CreateSummaryDocument(xmlOutput, transformReader);
244 // Write xml output here
245 string xmlResultFile = options.IsXml ? options.xml : "TestResult.xml";
247 using ( StreamWriter writer = new StreamWriter( xmlResultFile ) )
249 writer.Write(xmlOutput);
252 if ( testDomain != null )
253 testDomain.Unload();
255 return result.IsFailure ? 1 : 0;
258 private string CreateXmlOutput( TestResult result )
260 StringBuilder builder = new StringBuilder();
261 XmlResultVisitor resultVisitor = new XmlResultVisitor(new StringWriter( builder ), result);
262 result.Accept(resultVisitor);
263 resultVisitor.Write();
265 return builder.ToString();
268 private void CreateSummaryDocument(string xmlOutput, XmlTextReader transformReader)
270 XPathDocument originalXPathDocument = new XPathDocument(new StringReader(xmlOutput));
271 XslTransform summaryXslTransform = new XslTransform();
273 // Using obsolete form for now, remove warning suppression from project after changing
274 summaryXslTransform.Load(transformReader);
276 // Using obsolete form for now, remove warning suppression from project after changing
277 summaryXslTransform.Transform(originalXPathDocument,null,Console.Out);
280 #region Nested Class to Handle Events
282 private class EventCollector : LongLivingMarshalByRefObject, EventListener
284 private int testRunCount;
285 private int testIgnoreCount;
286 private int failureCount;
287 private int level;
289 private ConsoleOptions options;
290 private ConsoleWriter writer;
292 StringCollection messages;
294 private bool debugger = false;
295 private string currentTestName;
297 public EventCollector( ConsoleOptions options, ConsoleWriter writer )
299 debugger = Debugger.IsAttached;
300 level = 0;
301 this.options = options;
302 this.writer = writer;
303 this.currentTestName = string.Empty;
306 public void RunStarted(Test[] tests)
310 public void RunFinished(TestResult[] results)
314 public void RunFinished(Exception exception)
318 public void TestFinished(TestCaseResult testResult)
320 if ( !options.xmlConsole && !options.labels )
322 if(testResult.Executed)
324 testRunCount++;
326 if(testResult.IsFailure)
328 failureCount++;
329 Console.Write("F");
330 if ( debugger )
332 messages.Add( string.Format( "{0}) {1} :", failureCount, testResult.Test.FullName ) );
333 messages.Add( testResult.Message.Trim( Environment.NewLine.ToCharArray() ) );
335 string stackTrace = StackTraceFilter.Filter( testResult.StackTrace );
336 string[] trace = stackTrace.Split( System.Environment.NewLine.ToCharArray() );
337 foreach( string s in trace )
339 if ( s != string.Empty )
341 string link = Regex.Replace( s.Trim(), @".* in (.*):line (.*)", "$1($2)");
342 messages.Add( string.Format( "at\n{0}", link ) );
348 else
350 testIgnoreCount++;
351 Console.Write("N");
355 currentTestName = string.Empty;
358 public void TestStarted(TestCase testCase)
360 currentTestName = testCase.FullName;
362 if ( options.labels )
363 writer.WriteLine("***** {0}", testCase.FullName );
364 else if ( !options.xmlConsole )
365 Console.Write(".");
368 public void SuiteStarted(TestSuite suite)
370 if ( debugger && level++ == 0 )
372 messages = new StringCollection();
373 testRunCount = 0;
374 testIgnoreCount = 0;
375 failureCount = 0;
376 Trace.WriteLine( "################################ UNIT TESTS ################################" );
377 Trace.WriteLine( "Running tests in '" + suite.FullName + "'..." );
381 public void SuiteFinished(TestSuiteResult suiteResult)
383 if ( debugger && --level == 0)
385 Trace.WriteLine( "############################################################################" );
387 if (messages.Count == 0)
389 Trace.WriteLine( "############## S U C C E S S #################" );
391 else
393 Trace.WriteLine( "############## F A I L U R E S #################" );
395 foreach ( string s in messages )
397 Trace.WriteLine(s);
401 Trace.WriteLine( "############################################################################" );
402 Trace.WriteLine( "Executed tests : " + testRunCount );
403 Trace.WriteLine( "Ignored tests : " + testIgnoreCount );
404 Trace.WriteLine( "Failed tests : " + failureCount );
405 Trace.WriteLine( "Total time : " + suiteResult.Time + " seconds" );
406 Trace.WriteLine( "############################################################################");
410 public void UnhandledException( Exception exception )
412 string msg = string.Format( "##### Unhandled Exception while running {0}", currentTestName );
414 // If we do labels, we already have a newline
415 if ( !options.labels ) writer.WriteLine();
416 writer.WriteLine( msg );
417 writer.WriteLine( exception.ToString() );
419 if ( debugger )
421 Trace.WriteLine( msg );
422 Trace.WriteLine( exception.ToString() );
427 #endregion