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 '***********************************************************************************/
34 using System.Reflection;
35 using System.Collections;
38 /// Summary description for TestSuiteBuilder.
40 public class TestSuiteBuilder
42 #region Private Fields
45 /// Hashtable of all test suites we have created to represent namespaces.
46 /// Used to locate namespace parent suites for fixtures.
48 Hashtable namespaceSuites = new Hashtable();
51 /// The root of the test suite being created by this builder. This
52 /// may be a simple TestSuite, an AssemblyTestSuite or a RootTestSuite
53 /// encompassing multiple assemblies.
58 /// The version of the nunit framework referenced by the loaded assembly.
60 Version frameworkVersion = null;
66 public Version FrameworkVersion
68 get { return frameworkVersion; }
73 #region Public Methods
75 public Assembly Load(string assemblyName)
77 // Change currentDirectory in case assembly references unmanaged dlls
78 string currentDirectory = Environment.CurrentDirectory;
79 string assemblyDirectory = Path.GetDirectoryName( assemblyName );
80 bool swap = assemblyDirectory != null && assemblyDirectory != string.Empty;
85 Environment.CurrentDirectory = assemblyDirectory;
88 Assembly assembly = AppDomain.CurrentDomain.Load(Path.GetFileNameWithoutExtension(assemblyName));
90 Assembly assembly = Assembly.Load(Path.GetFileNameWithoutExtension(assemblyName));
93 foreach( AssemblyName refAssembly in assembly.GetReferencedAssemblies() )
95 if ( refAssembly.Name == "nunit.framework" )
96 this.frameworkVersion = refAssembly.Version;
104 Environment.CurrentDirectory = currentDirectory;
108 public TestSuite Build(string projectName, IList assemblies)
110 RootTestSuite rootSuite = new RootTestSuite( projectName );
113 foreach(string assembly in assemblies)
115 TestSuite suite = Build( assembly, assemblyKey++ );
116 rootSuite.Add( suite );
122 public TestSuite Build( string assemblyName )
124 return Build( assemblyName, 0 );
127 public TestSuite Build(string assemblyName, string testName )
129 TestSuite suite = null;
131 Assembly assembly = Load(assemblyName);
135 Type testType = assembly.GetType(testName);
136 if( testType != null )
137 return MakeSuite( testType );
139 // Assume that testName is a namespace
140 string prefix = testName + '.';
143 Type[] testTypes = assembly.GetExportedTypes();
145 Type[] testTypes = GetAssemblyExportedTypes(assembly);
147 int testFixtureCount = 0;
149 foreach(Type type in testTypes)
151 if( CanMakeSuite( type ) && type.Namespace != null )
153 if( type.Namespace == testName || type.Namespace.StartsWith(prefix) )
155 suite = BuildFromNameSpace(testName, 0);
157 //suite.Add( new TestFixture( type ) );
158 suite.Add( MakeSuite( type ) );
164 return testFixtureCount == 0 ? null : rootSuite;
170 public TestSuite Build( IList assemblies, string testName )
172 TestSuite suite = null;
174 foreach(string assemblyName in assemblies)
176 suite = Build( assemblyName, testName );
177 if ( suite != null ) break;
183 // TODO: Only used in tests
184 public object BuildTestFixture( Type fixtureType )
186 Reflect.CheckFixtureType( fixtureType );
189 ConstructorInfo ctor = Reflect.GetConstructor( fixtureType );
193 testFixture = ctor.Invoke( Type.EmptyTypes );
195 catch( Exception ex )
197 throw new InvalidTestFixtureException( ctor.Name + " threw a exception", ex );
200 if(testFixture == null) throw new InvalidTestFixtureException(ctor.Name + " cannot be invoked");
207 #region Nested TypeFilter Class
209 private class TypeFilter
211 private string rootNamespace;
213 TypeFilter( string rootNamespace )
215 this.rootNamespace = rootNamespace;
218 public bool Include( Type type )
220 if ( type.Namespace == rootNamespace )
223 return type.Namespace.StartsWith( rootNamespace + '.' );
229 #region Helper Methods
231 private TestSuite BuildFromNameSpace( string nameSpace, int assemblyKey )
233 if( nameSpace == null || nameSpace == "" ) return rootSuite;
234 TestSuite suite = (TestSuite)namespaceSuites[nameSpace];
235 if(suite!=null) return suite;
237 int index = nameSpace.LastIndexOf(".");
238 string prefix = string.Format( "[{0}]", assemblyKey );
241 suite = new NamespaceSuite( nameSpace, assemblyKey );
242 if ( rootSuite == null )
245 rootSuite.Add(suite);
246 namespaceSuites[nameSpace]=suite;
250 string parentNameSpace = nameSpace.Substring( 0,index );
251 TestSuite parent = BuildFromNameSpace( parentNameSpace, assemblyKey );
252 string suiteName = nameSpace.Substring( index+1 );
253 suite = new NamespaceSuite( parentNameSpace, suiteName, assemblyKey );
255 namespaceSuites[nameSpace] = suite;
261 private TestSuite Build( string assemblyName, int assemblyKey )
263 TestSuiteBuilder builder = new TestSuiteBuilder();
265 Assembly assembly = Load( assemblyName );
267 builder.rootSuite = new AssemblyTestSuite( assemblyName, assemblyKey );
268 int testFixtureCount = 0;
270 Type[] testTypes = assembly.GetExportedTypes();
272 Type[] testTypes = GetAssemblyExportedTypes(assembly);
274 foreach(Type testType in testTypes)
276 if( CanMakeSuite( testType ) )
279 string namespaces = testType.Namespace;
280 TestSuite suite = builder.BuildFromNameSpace( namespaces, assemblyKey );
282 //suite.Add( new TestFixture( testType ) );
283 suite.Add( MakeSuite( testType ) );
287 if(testFixtureCount == 0)
289 builder.rootSuite.ShouldRun = false;
290 builder.rootSuite.IgnoreReason = "Has no TestFixtures";
293 return builder.rootSuite;
297 private Type[] GetAssemblyExportedTypes(Assembly assembly)
299 Type[] allTypes = null;
302 allTypes = assembly.GetTypes();
306 System.Console.WriteLine("ReflectionTypeLoadException error");
308 ArrayList tmpTestTypes = new ArrayList(allTypes.Length);
309 foreach(Type current in allTypes)
311 if (current.IsPublic || current.IsNestedPublic)
313 tmpTestTypes.Add(current);
316 return (Type[])tmpTestTypes.ToArray(typeof(Type));
320 /// Helper routine that makes a suite from either a TestFixture or
321 /// a legacy Suite property.
323 /// <param name="testType"></param>
324 /// <returns></returns>
325 private TestSuite MakeSuite( Type testType )
327 TestSuite suite = null;
331 if( TestFixture.IsValidType( testType ) )
333 suite = new TestFixture( testType );
335 else if( LegacySuite.IsValidType( testType ) )
337 suite = new LegacySuite( testType );
344 private bool CanMakeSuite( Type testType )
346 //return TestFixture.IsValidType( testType ) || LegacySuite.IsValidType( testType );
347 return TestFixture.IsValidType( testType );