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
// ****************************************************************
8
using System.Collections;
10
using System.Xml.Schema;
12
using System.Threading;
18
/// Class that represents an NUnit test project
20
public class NUnitProject
23
public static readonly string Extension = ".nunit";
26
#region Instance variables
29
/// Path to the file storing this project
31
private string projectPath;
34
/// Application Base for the project. Since this
35
/// can be null, always fetch from the property
36
/// rather than using the field directly.
38
private string basePath;
41
/// Whether the project is dirty
43
private bool isDirty = false;
46
/// Whether canges have been made requiring a reload
48
private bool reloadRequired = false;
51
/// Collection of configs for the project
53
private ProjectConfigCollection configs;
56
/// True for NUnit-related projects that follow the config
57
/// of the NUnit build under which they are running.
59
private bool autoConfig;
62
/// The currently active configuration
64
private ProjectConfig activeConfig;
67
/// Flag indicating that this project is a
68
/// temporary wrapper for an assembly.
70
private bool isAssemblyWrapper = false;
73
/// The ProcessModel to be used in loading this project
75
private ProcessModel processModel;
78
/// The DomainUsage setting to be used in loading this project
80
private DomainUsage domainUsage;
86
public NUnitProject( string projectPath )
88
this.projectPath = Path.GetFullPath( projectPath );
89
configs = new ProjectConfigCollection( this );
94
#region Properties and Events
97
/// The path to which a project will be saved.
99
public string ProjectPath
101
get { return projectPath; }
104
projectPath = Path.GetFullPath( value );
109
public string DefaultBasePath
111
get { return Path.GetDirectoryName( projectPath ); }
115
/// Indicates whether a base path was specified for the project
117
public bool BasePathSpecified
121
return basePath != null && basePath != string.Empty;
126
/// The base path for the project. Constructor sets
127
/// it to the directory part of the project path.
129
public string BasePath
133
if ( !BasePathSpecified )
134
return DefaultBasePath;
141
if (basePath != null && basePath != string.Empty
142
&& !Path.IsPathRooted(basePath))
144
basePath = Path.Combine(
149
basePath = PathUtils.Canonicalize(basePath);
150
HasChangesRequiringReload = IsDirty = true;
155
/// The name of the project.
159
get { return Path.GetFileNameWithoutExtension( projectPath ); }
162
public bool AutoConfig
164
get { return autoConfig; }
165
set { autoConfig = value; }
168
public ProjectConfig ActiveConfig
172
// In case the previous active config was removed
173
if ( activeConfig != null && !configs.Contains( activeConfig ) )
176
// In case no active config is set or it was removed
177
if (activeConfig == null && configs.Count > 0)
178
activeConfig = configs[0];
184
// Safe access to name of the active config
185
public string ActiveConfigName
189
ProjectConfig config = ActiveConfig;
190
return config == null ? null : config.Name;
194
public bool IsLoadable
198
return ActiveConfig != null &&
199
ActiveConfig.Assemblies.Count > 0;
203
// A project made from a single assembly is treated
204
// as a transparent wrapper for some purposes until
205
// a change is made to it.
206
public bool IsAssemblyWrapper
208
get { return isAssemblyWrapper; }
209
set { isAssemblyWrapper = value; }
212
public string ConfigurationFile
217
return isAssemblyWrapper
218
? Path.GetFileName( projectPath ) + ".config"
219
: Path.GetFileNameWithoutExtension( projectPath ) + ".config";
225
get { return isDirty; }
230
if (isAssemblyWrapper && value == true)
232
projectPath = Path.ChangeExtension(projectPath, ".nunit");
233
isAssemblyWrapper = false;
234
HasChangesRequiringReload = true;
239
public bool HasChangesRequiringReload
241
get { return reloadRequired; }
242
set { reloadRequired = value; }
245
public ProcessModel ProcessModel
247
get { return processModel; }
250
processModel = value;
251
HasChangesRequiringReload = IsDirty = true;
255
public DomainUsage DomainUsage
257
get { return domainUsage; }
261
HasChangesRequiringReload = IsDirty = true;
265
public ProjectConfigCollection Configs
267
get { return configs; }
271
#region Static Methods
272
public static bool IsNUnitProjectFile(string path)
274
return Path.GetExtension(path) == Extension;
277
public static string ProjectPathFromFile(string path)
279
string fileName = Path.GetFileNameWithoutExtension(path) + NUnitProject.Extension;
280
return Path.Combine(Path.GetDirectoryName(path), fileName);
284
#region Instance Methods
286
public void SetActiveConfig( int index )
288
activeConfig = configs[index];
289
HasChangesRequiringReload = IsDirty = true;
292
public void SetActiveConfig( string name )
294
foreach( ProjectConfig config in configs )
296
if ( config.Name == name )
298
activeConfig = config;
299
HasChangesRequiringReload = IsDirty = true;
305
public void Add( VSProject vsProject )
307
foreach( VSProjectConfig vsConfig in vsProject.Configs )
309
string name = vsConfig.Name;
311
if ( !configs.Contains( name ) )
314
ProjectConfig config = this.Configs[name];
316
foreach ( string assembly in vsConfig.Assemblies )
317
config.Assemblies.Add( assembly );
323
XmlTextReader reader = new XmlTextReader( projectPath );
325
string activeConfigName = null;
326
ProjectConfig currentConfig = null;
330
reader.MoveToContent();
331
if ( reader.NodeType != XmlNodeType.Element || reader.Name != "NUnitProject" )
332
throw new ProjectFormatException(
333
"Invalid project format: <NUnitProject> expected.",
334
reader.LineNumber, reader.LinePosition );
336
while( reader.Read() )
337
if ( reader.NodeType == XmlNodeType.Element )
338
switch( reader.Name )
341
if ( reader.NodeType == XmlNodeType.Element )
343
activeConfigName = reader.GetAttribute( "activeconfig" );
345
string autoConfig = reader.GetAttribute("autoconfig");
346
if (autoConfig != null)
347
this.AutoConfig = autoConfig.ToLower() == "true";
349
activeConfigName = NUnitConfiguration.BuildConfiguration;
351
string appbase = reader.GetAttribute( "appbase" );
352
if ( appbase != null )
353
this.BasePath = appbase;
355
string processModel = reader.GetAttribute("processModel");
356
if (processModel != null)
357
this.ProcessModel = (ProcessModel)Enum.Parse(typeof(ProcessModel), processModel);
359
string domainUsage = reader.GetAttribute("domainUsage");
360
if (domainUsage != null)
361
this.DomainUsage = (DomainUsage)Enum.Parse(typeof(DomainUsage), domainUsage);
366
if ( reader.NodeType == XmlNodeType.Element )
368
string configName = reader.GetAttribute( "name" );
369
currentConfig = new ProjectConfig( configName );
370
currentConfig.BasePath = reader.GetAttribute( "appbase" );
371
currentConfig.ConfigurationFile = reader.GetAttribute( "configfile" );
373
string binpath = reader.GetAttribute( "binpath" );
374
currentConfig.PrivateBinPath = binpath;
375
string type = reader.GetAttribute( "binpathtype" );
377
if ( binpath == null )
378
currentConfig.BinPathType = BinPathType.Auto;
380
currentConfig.BinPathType = BinPathType.Manual;
382
currentConfig.BinPathType = (BinPathType)Enum.Parse( typeof( BinPathType ), type, true );
384
string runtime = reader.GetAttribute("runtimeFramework");
385
if ( runtime != null )
386
currentConfig.RuntimeFramework = RuntimeFramework.Parse(runtime);
388
Configs.Add(currentConfig);
389
if ( configName == activeConfigName )
390
activeConfig = currentConfig;
392
else if ( reader.NodeType == XmlNodeType.EndElement )
393
currentConfig = null;
397
if ( reader.NodeType == XmlNodeType.Element && currentConfig != null )
399
string path = reader.GetAttribute( "path" );
400
currentConfig.Assemblies.Add(
401
Path.Combine( currentConfig.BasePath, path ) );
409
this.IsDirty = false;
410
this.reloadRequired = false;
412
catch( FileNotFoundException )
416
catch( XmlException e )
418
throw new ProjectFormatException(
419
string.Format( "Invalid project format: {0}", e.Message ),
420
e.LineNumber, e.LinePosition );
424
throw new ProjectFormatException(
425
string.Format( "Invalid project format: {0} Line {1}, Position {2}",
426
e.Message, reader.LineNumber, reader.LinePosition ),
427
reader.LineNumber, reader.LinePosition );
437
projectPath = ProjectPathFromFile( projectPath );
439
XmlTextWriter writer = new XmlTextWriter( projectPath, System.Text.Encoding.UTF8 );
440
writer.Formatting = Formatting.Indented;
442
writer.WriteStartElement( "NUnitProject" );
444
if ( configs.Count > 0 || this.BasePath != this.DefaultBasePath )
446
writer.WriteStartElement( "Settings" );
447
if ( configs.Count > 0 )
448
writer.WriteAttributeString( "activeconfig", ActiveConfigName );
449
if ( this.BasePath != this.DefaultBasePath )
450
writer.WriteAttributeString( "appbase", this.BasePath );
452
writer.WriteAttributeString("autoconfig", "true");
453
if (this.ProcessModel != ProcessModel.Default)
454
writer.WriteAttributeString("processModel", this.ProcessModel.ToString());
455
if (this.DomainUsage != DomainUsage.Default)
456
writer.WriteAttributeString("domainUsage", this.DomainUsage.ToString());
457
writer.WriteEndElement();
460
foreach( ProjectConfig config in Configs )
462
writer.WriteStartElement( "Config" );
463
writer.WriteAttributeString( "name", config.Name );
464
string appbase = config.BasePath;
465
if ( !PathUtils.SamePathOrUnder( this.BasePath, appbase ) )
466
writer.WriteAttributeString( "appbase", appbase );
467
else if ( config.RelativeBasePath != null )
468
writer.WriteAttributeString( "appbase", config.RelativeBasePath );
470
string configFile = config.ConfigurationFile;
471
if ( configFile != null && configFile != this.ConfigurationFile )
472
writer.WriteAttributeString( "configfile", config.ConfigurationFile );
474
if ( config.BinPathType == BinPathType.Manual )
475
writer.WriteAttributeString( "binpath", config.PrivateBinPath );
477
writer.WriteAttributeString( "binpathtype", config.BinPathType.ToString() );
479
if (config.RuntimeFramework != null)
480
writer.WriteAttributeString("runtimeFramework", config.RuntimeFramework.ToString());
482
foreach( string assembly in config.Assemblies )
484
writer.WriteStartElement( "assembly" );
485
writer.WriteAttributeString( "path", PathUtils.RelativePath( config.BasePath, assembly ) );
486
writer.WriteEndElement();
489
writer.WriteEndElement();
492
writer.WriteEndElement();
495
this.IsDirty = false;
497
// Once we save a project, it's no longer
498
// loaded as an assembly wrapper on reload.
499
this.isAssemblyWrapper = false;
502
public void Save( string projectPath )
504
this.ProjectPath = projectPath;
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
// ****************************************************************
8
using System.Collections;
10
using System.Xml.Schema;
12
using System.Threading;
18
/// Class that represents an NUnit test project
20
public class NUnitProject
23
public static readonly string Extension = ".nunit";
26
#region Instance variables
29
/// Path to the file storing this project
31
private string projectPath;
34
/// Application Base for the project. Since this
35
/// can be null, always fetch from the property
36
/// rather than using the field directly.
38
private string basePath;
41
/// Whether the project is dirty
43
private bool isDirty = false;
46
/// Whether canges have been made requiring a reload
48
private bool reloadRequired = false;
51
/// Collection of configs for the project
53
private ProjectConfigCollection configs;
56
/// True for NUnit-related projects that follow the config
57
/// of the NUnit build under which they are running.
59
private bool autoConfig;
62
/// The currently active configuration
64
private ProjectConfig activeConfig;
67
/// Flag indicating that this project is a
68
/// temporary wrapper for an assembly.
70
private bool isAssemblyWrapper = false;
73
/// The ProcessModel to be used in loading this project
75
private ProcessModel processModel;
78
/// The DomainUsage setting to be used in loading this project
80
private DomainUsage domainUsage;
86
public NUnitProject( string projectPath )
88
this.projectPath = Path.GetFullPath( projectPath );
89
configs = new ProjectConfigCollection( this );
94
#region Properties and Events
97
/// The path to which a project will be saved.
99
public string ProjectPath
101
get { return projectPath; }
104
projectPath = Path.GetFullPath( value );
109
public string DefaultBasePath
111
get { return Path.GetDirectoryName( projectPath ); }
115
/// Indicates whether a base path was specified for the project
117
public bool BasePathSpecified
121
return basePath != null && basePath != string.Empty;
126
/// The base path for the project. Constructor sets
127
/// it to the directory part of the project path.
129
public string BasePath
133
if ( !BasePathSpecified )
134
return DefaultBasePath;
141
if (basePath != null && basePath != string.Empty
142
&& !Path.IsPathRooted(basePath))
144
basePath = Path.Combine(
149
basePath = PathUtils.Canonicalize(basePath);
150
HasChangesRequiringReload = IsDirty = true;
155
/// The name of the project.
159
get { return Path.GetFileNameWithoutExtension( projectPath ); }
162
public bool AutoConfig
164
get { return autoConfig; }
165
set { autoConfig = value; }
168
public ProjectConfig ActiveConfig
172
// In case the previous active config was removed
173
if ( activeConfig != null && !configs.Contains( activeConfig ) )
176
// In case no active config is set or it was removed
177
if (activeConfig == null && configs.Count > 0)
178
activeConfig = configs[0];
184
// Safe access to name of the active config
185
public string ActiveConfigName
189
ProjectConfig config = ActiveConfig;
190
return config == null ? null : config.Name;
194
public bool IsLoadable
198
return ActiveConfig != null &&
199
ActiveConfig.Assemblies.Count > 0;
203
// A project made from a single assembly is treated
204
// as a transparent wrapper for some purposes until
205
// a change is made to it.
206
public bool IsAssemblyWrapper
208
get { return isAssemblyWrapper; }
209
set { isAssemblyWrapper = value; }
212
public string ConfigurationFile
217
return isAssemblyWrapper
218
? Path.GetFileName( projectPath ) + ".config"
219
: Path.GetFileNameWithoutExtension( projectPath ) + ".config";
225
get { return isDirty; }
230
if (isAssemblyWrapper && value == true)
232
projectPath = Path.ChangeExtension(projectPath, ".nunit");
233
isAssemblyWrapper = false;
234
HasChangesRequiringReload = true;
239
public bool HasChangesRequiringReload
241
get { return reloadRequired; }
242
set { reloadRequired = value; }
245
public ProcessModel ProcessModel
247
get { return processModel; }
250
processModel = value;
251
HasChangesRequiringReload = IsDirty = true;
255
public DomainUsage DomainUsage
257
get { return domainUsage; }
261
HasChangesRequiringReload = IsDirty = true;
265
public ProjectConfigCollection Configs
267
get { return configs; }
271
#region Static Methods
272
public static bool IsNUnitProjectFile(string path)
274
return Path.GetExtension(path) == Extension;
277
public static string ProjectPathFromFile(string path)
279
string fileName = Path.GetFileNameWithoutExtension(path) + NUnitProject.Extension;
280
return Path.Combine(Path.GetDirectoryName(path), fileName);
284
#region Instance Methods
286
public void SetActiveConfig( int index )
288
activeConfig = configs[index];
289
HasChangesRequiringReload = IsDirty = true;
292
public void SetActiveConfig( string name )
294
foreach( ProjectConfig config in configs )
296
if ( config.Name == name )
298
activeConfig = config;
299
HasChangesRequiringReload = IsDirty = true;
305
public void Add( VSProject vsProject )
307
foreach( VSProjectConfig vsConfig in vsProject.Configs )
309
string name = vsConfig.Name;
311
if ( !configs.Contains( name ) )
314
ProjectConfig config = this.Configs[name];
316
foreach ( string assembly in vsConfig.Assemblies )
317
config.Assemblies.Add( assembly );
323
XmlTextReader reader = new XmlTextReader( projectPath );
325
string activeConfigName = null;
326
ProjectConfig currentConfig = null;
330
reader.MoveToContent();
331
if ( reader.NodeType != XmlNodeType.Element || reader.Name != "NUnitProject" )
332
throw new ProjectFormatException(
333
"Invalid project format: <NUnitProject> expected.",
334
reader.LineNumber, reader.LinePosition );
336
while( reader.Read() )
337
if ( reader.NodeType == XmlNodeType.Element )
338
switch( reader.Name )
341
if ( reader.NodeType == XmlNodeType.Element )
343
activeConfigName = reader.GetAttribute( "activeconfig" );
345
string autoConfig = reader.GetAttribute("autoconfig");
346
if (autoConfig != null)
347
this.AutoConfig = autoConfig.ToLower() == "true";
349
activeConfigName = NUnitConfiguration.BuildConfiguration;
351
string appbase = reader.GetAttribute( "appbase" );
352
if ( appbase != null )
353
this.BasePath = appbase;
355
string processModel = reader.GetAttribute("processModel");
356
if (processModel != null)
357
this.ProcessModel = (ProcessModel)Enum.Parse(typeof(ProcessModel), processModel);
359
string domainUsage = reader.GetAttribute("domainUsage");
360
if (domainUsage != null)
361
this.DomainUsage = (DomainUsage)Enum.Parse(typeof(DomainUsage), domainUsage);
366
if ( reader.NodeType == XmlNodeType.Element )
368
string configName = reader.GetAttribute( "name" );
369
currentConfig = new ProjectConfig( configName );
370
currentConfig.BasePath = reader.GetAttribute( "appbase" );
371
currentConfig.ConfigurationFile = reader.GetAttribute( "configfile" );
373
string binpath = reader.GetAttribute( "binpath" );
374
currentConfig.PrivateBinPath = binpath;
375
string type = reader.GetAttribute( "binpathtype" );
377
if ( binpath == null )
378
currentConfig.BinPathType = BinPathType.Auto;
380
currentConfig.BinPathType = BinPathType.Manual;
382
currentConfig.BinPathType = (BinPathType)Enum.Parse( typeof( BinPathType ), type, true );
384
string runtime = reader.GetAttribute("runtimeFramework");
385
if ( runtime != null )
386
currentConfig.RuntimeFramework = RuntimeFramework.Parse(runtime);
388
Configs.Add(currentConfig);
389
if ( configName == activeConfigName )
390
activeConfig = currentConfig;
392
else if ( reader.NodeType == XmlNodeType.EndElement )
393
currentConfig = null;
397
if ( reader.NodeType == XmlNodeType.Element && currentConfig != null )
399
string path = reader.GetAttribute( "path" );
400
currentConfig.Assemblies.Add(
401
Path.Combine( currentConfig.BasePath, path ) );
409
this.IsDirty = false;
410
this.reloadRequired = false;
412
catch( FileNotFoundException )
416
catch( XmlException e )
418
throw new ProjectFormatException(
419
string.Format( "Invalid project format: {0}", e.Message ),
420
e.LineNumber, e.LinePosition );
424
throw new ProjectFormatException(
425
string.Format( "Invalid project format: {0} Line {1}, Position {2}",
426
e.Message, reader.LineNumber, reader.LinePosition ),
427
reader.LineNumber, reader.LinePosition );
437
projectPath = ProjectPathFromFile( projectPath );
439
XmlTextWriter writer = new XmlTextWriter( projectPath, System.Text.Encoding.UTF8 );
440
writer.Formatting = Formatting.Indented;
442
writer.WriteStartElement( "NUnitProject" );
444
if ( configs.Count > 0 || this.BasePath != this.DefaultBasePath )
446
writer.WriteStartElement( "Settings" );
447
if ( configs.Count > 0 )
448
writer.WriteAttributeString( "activeconfig", ActiveConfigName );
449
if ( this.BasePath != this.DefaultBasePath )
450
writer.WriteAttributeString( "appbase", this.BasePath );
452
writer.WriteAttributeString("autoconfig", "true");
453
if (this.ProcessModel != ProcessModel.Default)
454
writer.WriteAttributeString("processModel", this.ProcessModel.ToString());
455
if (this.DomainUsage != DomainUsage.Default)
456
writer.WriteAttributeString("domainUsage", this.DomainUsage.ToString());
457
writer.WriteEndElement();
460
foreach( ProjectConfig config in Configs )
462
writer.WriteStartElement( "Config" );
463
writer.WriteAttributeString( "name", config.Name );
464
string appbase = config.BasePath;
465
if ( !PathUtils.SamePathOrUnder( this.BasePath, appbase ) )
466
writer.WriteAttributeString( "appbase", appbase );
467
else if ( config.RelativeBasePath != null )
468
writer.WriteAttributeString( "appbase", config.RelativeBasePath );
470
string configFile = config.ConfigurationFile;
471
if ( configFile != null && configFile != this.ConfigurationFile )
472
writer.WriteAttributeString( "configfile", config.ConfigurationFile );
474
if ( config.BinPathType == BinPathType.Manual )
475
writer.WriteAttributeString( "binpath", config.PrivateBinPath );
477
writer.WriteAttributeString( "binpathtype", config.BinPathType.ToString() );
479
if (config.RuntimeFramework != null)
480
writer.WriteAttributeString("runtimeFramework", config.RuntimeFramework.ToString());
482
foreach( string assembly in config.Assemblies )
484
writer.WriteStartElement( "assembly" );
485
writer.WriteAttributeString( "path", PathUtils.RelativePath( config.BasePath, assembly ) );
486
writer.WriteEndElement();
489
writer.WriteEndElement();
492
writer.WriteEndElement();
495
this.IsDirty = false;
497
// Once we save a project, it's no longer
498
// loaded as an assembly wrapper on reload.
499
this.isAssemblyWrapper = false;
502
public void Save( string projectPath )
504
this.ProjectPath = projectPath;