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
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 '***********************************************************************************/
30 namespace NUnit.Console
33 using System.Collections;
34 using System.Collections.Specialized;
36 using System.Reflection;
39 using System.Xml.XPath;
40 using System.Resources;
42 using System.Text.RegularExpressions;
43 using System.Diagnostics;
49 /// Summary description for ConsoleUi.
51 public class ConsoleUi
56 public static int Main(string[] args)
58 ConsoleOptions options = new ConsoleOptions(args);
70 Console.Error.WriteLine("fatal error: no inputs specified");
75 if(!options.Validate())
77 Console.Error.WriteLine("fatal error: invalid arguments");
84 ConsoleUi consoleUi = new ConsoleUi();
85 return consoleUi.Execute( options );
87 catch( FileNotFoundException ex )
89 Console.WriteLine( ex.Message );
92 catch( BadImageFormatException ex )
94 Console.WriteLine( ex.Message );
99 Console.WriteLine( "Unhandled Exception:\n{0}", ex.ToString() );
106 Console.Out.WriteLine("\nHit <enter> key to continue");
112 private static XmlTextReader GetTransformReader(ConsoleOptions parser)
114 XmlTextReader reader = null;
115 if(!parser.IsTransform)
117 Assembly assembly = Assembly.GetAssembly(typeof(XmlResultVisitor));
118 ResourceManager resourceManager = new ResourceManager("NUnit.Util.Transform",assembly);
119 string xmlData = (string)resourceManager.GetObject("Summary.xslt");
121 reader = new XmlTextReader(new StringReader(xmlData));
125 FileInfo xsltInfo = new FileInfo(parser.transform);
128 Console.Error.WriteLine("Transform file: {0} does not exist", xsltInfo.FullName);
133 reader = new XmlTextReader(xsltInfo.FullName);
140 private static void WriteCopyright()
142 Assembly executingAssembly = Assembly.GetExecutingAssembly();
143 System.Version version = executingAssembly.GetName().Version;
145 object[] objectAttrs = executingAssembly.GetCustomAttributes(typeof(AssemblyProductAttribute), false);
146 AssemblyProductAttribute productAttr = (AssemblyProductAttribute)objectAttrs[0];
148 objectAttrs = executingAssembly.GetCustomAttributes(typeof(AssemblyCopyrightAttribute), false);
149 AssemblyCopyrightAttribute copyrightAttr = (AssemblyCopyrightAttribute)objectAttrs[0];
151 Console.WriteLine(String.Format("{0} version {1}", productAttr.Product, version.ToString(3)));
152 Console.WriteLine(copyrightAttr.Copyright);
155 string clrPlatform = Type.GetType("Mono.Runtime", false) == null ? ".NET" : "Mono";
157 Console.WriteLine( string.Format("OS Version: {0} {1} Version: {2}",
158 Environment.OSVersion, clrPlatform, Environment.Version ) );
163 private static Test MakeTestFromCommandLine(TestDomain testDomain, ConsoleOptions parser)
165 NUnitProject project;
167 if ( parser.IsTestProject )
169 project = NUnitProject.LoadProject( (string)parser.Parameters[0] );
170 string configName = (string) parser.config;
171 if ( configName != null )
172 project.SetActiveConfig( configName );
175 project = NUnitProject.FromAssemblies( (string[])parser.Parameters.ToArray( typeof( string ) ) );
177 return testDomain.Load( project, parser.fixture );
184 public int Execute( ConsoleOptions options )
186 XmlTextReader transformReader = GetTransformReader(options);
187 if(transformReader == null) return 3;
189 ConsoleWriter outStream = options.isOut
190 ? new ConsoleWriter( new StreamWriter( options.output ) )
191 : new ConsoleWriter(Console.Out);
193 ConsoleWriter errorStream = options.isErr
194 ? new ConsoleWriter( new StreamWriter( options.err ) )
195 : new ConsoleWriter(Console.Error);
197 TestDomain testDomain = new TestDomain(outStream, errorStream);
198 if ( options.noshadow ) testDomain.ShadowCopyFiles = false;
200 Test test = MakeTestFromCommandLine(testDomain, options);
204 Console.Error.WriteLine("Unable to locate fixture {0}", options.fixture);
208 Directory.SetCurrentDirectory(new FileInfo((string)options.Parameters[0]).DirectoryName);
210 EventCollector collector = new EventCollector( options, outStream );
212 string savedDirectory = Environment.CurrentDirectory;
214 if (options.HasInclude)
216 Console.WriteLine( "Included categories: " + options.include );
217 testDomain.SetFilter( new CategoryFilter( options.IncludedCategories ) );
219 else if ( options.HasExclude )
221 Console.WriteLine( "Excluded categories: " + options.exclude );
222 testDomain.SetFilter( new CategoryFilter( options.ExcludedCategories, true ) );
225 TestResult result = null;
226 if ( options.thread )
228 testDomain.RunTest( collector );
230 result = testDomain.Result;
234 result = testDomain.Run( collector );
237 Directory.SetCurrentDirectory( savedDirectory );
241 collector.PrintSummary( result );
244 string xmlOutput = CreateXmlOutput( result );
246 if (options.xmlConsole)
247 Console.WriteLine(xmlOutput);
249 CreateSummaryDocument(xmlOutput, transformReader, outStream);
251 // Write xml output here
252 string xmlResultFile = options.IsXml ? options.xml : "TestResult.xml";
254 using ( StreamWriter writer = new StreamWriter( xmlResultFile ) )
256 writer.Write(xmlOutput);
261 if ( testDomain != null )
264 return result.IsFailure ? 1 : 0;
267 private string CreateXmlOutput( TestResult result )
269 StringBuilder builder = new StringBuilder();
270 XmlResultVisitor resultVisitor = new XmlResultVisitor(new StringWriter( builder ), result);
271 result.Accept(resultVisitor);
272 resultVisitor.Write();
274 return builder.ToString();
277 private void CreateSummaryDocument(string xmlOutput, XmlTextReader transformReader,
278 ConsoleWriter outStream)
280 XPathDocument originalXPathDocument = new XPathDocument(new StringReader(xmlOutput));
281 XslTransform summaryXslTransform = new XslTransform();
283 // Using obsolete form for now, remove warning suppression from project after changing
284 summaryXslTransform.Load(transformReader);
286 // Using obsolete form for now, remove warning suppression from project after changing
287 summaryXslTransform.Transform(originalXPathDocument,null,outStream);
290 #region Nested Class to Handle Events
292 private class EventCollector : LongLivingMarshalByRefObject, EventListener
294 private int testRunCount;
295 private int testIgnoreCount;
296 private int failureCount;
299 private ConsoleOptions options;
300 private ConsoleWriter writer;
302 StringCollection messages;
304 private bool debugger = false;
305 private string currentTestName;
307 public EventCollector( ConsoleOptions options, ConsoleWriter writer )
309 debugger = Debugger.IsAttached;
311 this.options = options;
312 this.writer = writer;
313 this.currentTestName = string.Empty;
316 public void RunStarted(Test[] tests)
320 public void RunFinished(TestResult[] results)
324 public void RunFinished(Exception exception)
328 public void TestFinished(TestCaseResult testResult)
330 if ( !options.xmlConsole && !options.labels )
332 if(testResult.Executed)
336 if(testResult.IsFailure)
342 messages.Add( string.Format( "{0}) {1} :", failureCount, testResult.Test.FullName ) );
343 messages.Add( testResult.Message.Trim( Environment.NewLine.ToCharArray() ) );
345 string stackTrace = StackTraceFilter.Filter( testResult.StackTrace );
346 string[] trace = stackTrace.Split( System.Environment.NewLine.ToCharArray() );
347 foreach( string s in trace )
349 if ( s != string.Empty )
351 string link = Regex.Replace( s.Trim(), @".* in (.*):line (.*)", "$1($2)");
352 messages.Add( string.Format( "at\n{0}", link ) );
365 currentTestName = string.Empty;
368 public void TestStarted(TestCase testCase)
370 currentTestName = testCase.FullName;
372 if ( options.labels )
373 writer.WriteLine("***** {0}", testCase.FullName );
374 else if ( !options.xmlConsole )
378 public void SuiteStarted(TestSuite suite)
380 if ( debugger && level++ == 0 )
382 messages = new StringCollection();
386 Trace.WriteLine( "################################ UNIT TESTS ################################" );
387 Trace.WriteLine( "Running tests in '" + suite.FullName + "'..." );
391 public void SuiteFinished(TestSuiteResult suiteResult)
393 if ( debugger && --level == 0)
395 Trace.WriteLine( "############################################################################" );
397 if (messages.Count == 0)
399 Trace.WriteLine( "############## S U C C E S S #################" );
403 Trace.WriteLine( "############## F A I L U R E S #################" );
405 foreach ( string s in messages )
411 Trace.WriteLine( "############################################################################" );
412 Trace.WriteLine( "Executed tests : " + testRunCount );
413 Trace.WriteLine( "Ignored tests : " + testIgnoreCount );
414 Trace.WriteLine( "Failed tests : " + failureCount );
415 Trace.WriteLine( "Total time : " + suiteResult.Time + " seconds" );
416 Trace.WriteLine( "############################################################################");
420 public void PrintSummary (TestResult suiteResult)
422 if (failureCount > 0){
423 Console.WriteLine("Tests run: {0}, Failures: {1}, Not run: {2}, Time: {3} seconds",
424 testRunCount, failureCount, testIgnoreCount, suiteResult.Time);
426 Console.WriteLine("Tests run: {0} (all pass), Not run: {1}, Time: {2} seconds",
427 testRunCount, testIgnoreCount, suiteResult.Time);
431 public void UnhandledException( Exception exception )
433 string msg = string.Format( "##### Unhandled Exception while running {0}", currentTestName );
435 // If we do labels, we already have a newline
436 if ( !options.labels ) writer.WriteLine();
437 writer.WriteLine( msg );
438 writer.WriteLine( exception.ToString() );
442 Trace.WriteLine( msg );
443 Trace.WriteLine( exception.ToString() );