#region Copyright (c) 2002-2003, James W. Newkirk, Michael C. Two, Alexei A. Vorontsov, Charlie Poole, Philip A. Craig /************************************************************************************ ' ' Copyright 2002-2003 James W. Newkirk, Michael C. Two, Alexei A. Vorontsov, Charlie Poole ' Copyright 2000-2002 Philip A. Craig ' ' This software is provided 'as-is', without any express or implied warranty. In no ' event will the authors be held liable for any damages arising from the use of this ' software. ' ' Permission is granted to anyone to use this software for any purpose, including ' commercial applications, and to alter it and redistribute it freely, subject to the ' following restrictions: ' ' 1. The origin of this software must not be misrepresented; you must not claim that ' you wrote the original software. If you use this software in a product, an ' acknowledgment (see the following) in the product documentation is required. ' ' Portions Copyright 2002-2003 James W. Newkirk, Michael C. Two, Alexei A. Vorontsov, Charlie Poole ' or Copyright 2000-2002 Philip A. Craig ' ' 2. Altered source versions must be plainly marked as such, and must not be ' misrepresented as being the original software. ' ' 3. This notice may not be removed or altered from any source distribution. ' '***********************************************************************************/ #endregion namespace NUnit.Util { using System; using System.Collections; using NUnit.Core; /// /// UITestNode holds common info needed about a test /// in the UI, avoiding the remoting issues associated /// with holding an actual Test object. /// public class UITestNode : ITest { #region Instance Variables /// /// The full name of the test, including the assembly and namespaces /// private string fullName; /// /// The test name /// private string testName; /// /// Used to distinguish tests in multiple assemblies; /// private int assemblyKey; /// /// True if the test should be run /// private bool shouldRun; /// /// Reason for not running the test /// private string ignoreReason; /// /// Number of test cases in this test or suite /// private int testCaseCount; /// /// For a test suite, the child tests or suites /// Null if this is not a test suite /// private ArrayList tests; /// /// True if this is a suite /// private bool isSuite; /// /// Interface of the test suite from which this /// object was constructed. Used for deferred /// population of the object. /// private ITest testSuite; /// /// The test description /// private string description; private ArrayList categories = new ArrayList(); private bool isExplicit; #endregion #region Construction and Conversion /// /// Construct from a TestInfo interface, which might be /// a Test or another UITestNode. Optionally, populate /// the array of child tests. /// /// TestInfo interface from which a UITestNode is to be constructed /// True if child array is to be populated public UITestNode ( ITest test, bool populate ) { fullName = test.FullName; testName = test.Name; assemblyKey = test.AssemblyKey; shouldRun = test.ShouldRun; ignoreReason = test.IgnoreReason; description = test.Description; isExplicit = test.IsExplicit; if (test.Categories != null) { categories.AddRange(test.Categories); } if ( test is UITestNode ) testCaseCount = 0; if ( test.IsSuite ) { testCaseCount = 0; testSuite = test; isSuite = true; tests = new ArrayList(); if ( populate ) PopulateTests(); } else { testCaseCount = 1; isSuite = false; } } /// /// Default construction uses lazy population approach /// /// public UITestNode ( ITest test ) : this( test, false ) { } public UITestNode ( string pathName, string testName ) : this( pathName, testName, 0 ) { } public UITestNode ( string pathName, string testName, int assemblyKey ) { this.fullName = pathName + "." + testName; this.testName = testName; this.assemblyKey = assemblyKey; this.shouldRun = true; this.isSuite = false; this.testCaseCount = 1; } /// /// Populate the arraylist of child Tests recursively. /// If already populated, it has no effect. /// public void PopulateTests() { if ( !Populated ) { foreach( ITest test in testSuite.Tests ) { UITestNode node = new UITestNode( test, true ); tests.Add( node ); testCaseCount += node.CountTestCases(); } testSuite = null; } } /// /// Allow implicit conversion of a Test to a TestInfo /// /// /// public static implicit operator UITestNode( Test test ) { return new UITestNode( test ); } #endregion #region Properties /// /// The test description /// public string Description { get { return description; } set { description = value; } } /// /// The reason for ignoring a test /// public string IgnoreReason { get { return ignoreReason; } set { ignoreReason = value; } } /// /// True if the test should be run /// public bool ShouldRun { get { return shouldRun; } set { shouldRun = value; } } /// /// Full name of the test /// public string FullName { get { return fullName; } } /// /// Name of the test /// public string Name { get { return testName; } } /// /// Identifier for assembly containing this test /// public int AssemblyKey { get { return assemblyKey; } set { assemblyKey = value; } } public string UniqueName { get{ return string.Format( "[{0}]{1}", assemblyKey, fullName ); } } /// /// If the name is a path, this just returns the file part /// public string ShortName { get { string name = Name; int val = name.LastIndexOf("\\"); if(val != -1) name = name.Substring(val+1); return name; } } public bool IsExplicit { get { return isExplicit; } set { isExplicit = value; } } public IList Categories { get { return categories; } } public bool HasCategory( string name ) { return categories != null && categories.Contains( name ); } public bool HasCategory( IList names ) { if ( categories == null ) return false; foreach( string name in names ) if ( categories.Contains( name ) ) return true; return false; } /// /// Count of test cases in this test. If the suite /// has never been populated, it will be done now. /// public int CountTestCases() { if ( !Populated ) PopulateTests(); return testCaseCount; } /// /// Array of child tests, null if this is a test case. /// The array is populated on access if necessary. /// public ArrayList Tests { get { if ( !Populated ) PopulateTests(); return tests; } } /// /// True if this is a suite, false if a test case /// public bool IsSuite { get { return isSuite; } } /// /// True if this is a test case, false if a suite /// public bool IsTestCase { get { return !isSuite; } } /// /// True if this is a fixture. May populate the test's /// children as a side effect. /// TODO: An easier way to tell this? /// public bool IsFixture { get { // A test case is obviously not a fixture if ( IsTestCase ) return false; // We have no way of constructing an empty suite unless it's a fixture if ( Tests.Count == 0 ) return true; // Any suite with children is a fixture if the children are test cases UITestNode firstChild = (UITestNode)Tests[0]; return !firstChild.IsSuite; } } /// /// False for suites that have not yet been populated /// with their children, otherwise true - used for testing. /// public bool Populated { get { return testSuite == null; } } public TestResult Run( EventListener listener ) { throw new InvalidOperationException( "Cannot use Run on a local copy of Test data" ); } #endregion } }