1
// Copyright (c) AlphaSierraPapa for the SharpDevelop Team (for details please see \doc\copyright.txt)
2
// This code is distributed under the GNU LGPL (for details please see \doc\license.txt)
5
using System.Collections.Generic;
6
using System.Windows.Forms;
7
using ICSharpCode.SharpDevelop.Gui;
8
using ICSharpCode.SharpDevelop.Project;
10
namespace ICSharpCode.UnitTesting
13
/// Represents a namespace in the TestTreeView.
15
public class TestNamespaceTreeNode : TestTreeNode
17
string ns = String.Empty;
18
string namespacePrefix = String.Empty;
20
TestClassCollection testClasses;
21
List<TestNamespaceTreeNode> namespaceChildNodes = new List<TestNamespaceTreeNode>();
22
ExtTreeNode dummyNode;
25
/// Creates a new TestNamespaceTreeNode
28
/// Note that the Namespace child nodes are added in
29
/// the constructor not whilst the node is expanding
30
/// via the Initialize method. This is so the icon for the
31
/// node can be updated even if the parent node is not
32
/// expanded. The alternative is to have each namespace node,
33
/// even if it does not have any class child nodes, to
34
/// store all the classes that are below it in the tree and
35
/// update the icon based on their results. The assumption
36
/// is that there are fewer namespace nodes than classes so
37
/// adding the namespace nodes here does not matter.
39
/// <param name="namespacePrefix">The first part of the
40
/// namespace (including any dot characters) before this
41
/// particular namespace.</param>
42
/// <param name="name">The name of the namespace without any
43
/// dot characters (e.g. the name at this particular
44
/// location in the tree).</param>
45
public TestNamespaceTreeNode(TestProject testProject, string namespacePrefix, string name)
46
: base(testProject, name)
49
this.namespacePrefix = namespacePrefix;
50
fullNamespace = GetFullNamespace(namespacePrefix, ns);
52
testProject.TestClasses.TestClassAdded += TestClassAdded;
53
testProject.TestClasses.TestClassRemoved += TestClassRemoved;
55
// Add namespace nodes - do not add them on node expansion.
56
foreach (string namespaceName in TestProject.GetChildNamespaces(fullNamespace)) {
57
TestNamespaceTreeNode node = new TestNamespaceTreeNode(TestProject, fullNamespace, namespaceName);
59
namespaceChildNodes.Add(node);
60
node.ImageIndexChanged += TestNamespaceNodeImageIndexChanged;
63
// Add a dummy node if there are no namespaces since
64
// there might be class nodes which will be added
65
// lazily when the node is expanded.
66
if (namespaceChildNodes.Count == 0) {
67
dummyNode = new ExtTreeNode();
71
UpdateImageListIndex();
75
/// Creates a new TestNamespaceTreeNode with the specified
76
/// namespace name. This node will have no namespace prefix.
78
public TestNamespaceTreeNode(TestProject testProject, string name)
79
: this(testProject, String.Empty, name)
84
/// Frees any resources held by this class.
86
public override void Dispose()
89
TestProject.TestClasses.TestClassAdded -= TestClassAdded;
90
TestProject.TestClasses.TestClassRemoved -= TestClassRemoved;
91
testClasses.ResultChanged -= TestClassesResultChanged;
97
/// Gets whether this namespace node is considered empty. If
98
/// the node has been expanded then the node is empty if it
99
/// has no child nodes. If it has not been expanded then there
100
/// will be a dummy child node or a set of namespace
101
/// nodes but no test class nodes.
103
public bool IsEmpty {
106
return Nodes.Count == 0;
107
} else if (dummyNode != null) {
108
return testClasses.Count == 0;
110
return Nodes.Count == 0 && testClasses.Count == 0;
116
/// Gets the full namespace of this tree node. This includes any
117
/// parent namespaces prefixed to the namespace associated
118
/// with this tree node.
120
public string FullNamespace {
122
return fullNamespace;
127
/// Adds the test class nodes for this namespace when the
128
/// node is expanded.
130
protected override void Initialize()
132
if (dummyNode != null) {
136
// Add class nodes for this namespace.
137
foreach (TestClass c in testClasses) {
138
TestClassTreeNode classNode = new TestClassTreeNode(TestProject, c);
139
classNode.AddTo(this);
147
/// Adds the child namespace to the namespace prefix.
149
static string GetFullNamespace(string prefix, string name)
151
if (prefix.Length > 0) {
152
return String.Concat(prefix, ".", name);
158
/// Updates this node's icon because one of its child namespace nodes
161
void TestNamespaceNodeImageIndexChanged(object source, EventArgs e)
163
UpdateImageListIndex();
167
/// Gets the test classes for this namespace.
169
void GetTestClasses()
171
testClasses = new TestClassCollection();
172
foreach (TestClass c in TestProject.GetTestClasses(fullNamespace)) {
175
testClasses.ResultChanged += TestClassesResultChanged;
179
/// The overall test result for the classes in this namespace
180
/// have changed so the node's icon is updated.
182
void TestClassesResultChanged(object source, EventArgs e)
184
UpdateImageListIndex();
188
/// Determines the image list index for this node based
189
/// on the current state of all the child nodes.
192
/// Since the test classes overall test result is
193
/// available via the TestClassCollection we do not
194
/// need to sum all the individual test classes.
196
void UpdateImageListIndex()
198
int ignoredCount = 0;
202
// Count the passes, failures and ignores for the
203
// namespace child nodes.
204
foreach (ExtTreeNode node in namespaceChildNodes) {
205
switch (node.ImageIndex) {
206
case (int)TestTreeViewImageListIndex.TestFailed:
209
case (int)TestTreeViewImageListIndex.TestIgnored:
212
case (int)TestTreeViewImageListIndex.TestPassed:
218
// Check the passes, failures and ignores for the
219
// test classes that belong to this namespace.
220
switch (testClasses.Result) {
221
case TestResultType.Failure:
224
case TestResultType.Success:
227
case TestResultType.Ignored:
232
// Work out the total number of passes we are expecting
233
int total = namespaceChildNodes.Count;
234
if (testClasses.Count > 0) {
235
// Only add one for the testClasses since the
236
// overall pass or failure is indicated via
237
// the TestClassCollection so we do not need
238
// to add all the test classes.
242
// Determine the correct image list index for this node.
243
if (failedCount > 0) {
244
UpdateImageListIndex(TestResultType.Failure);
245
} else if (ignoredCount > 0) {
246
UpdateImageListIndex(TestResultType.Ignored);
247
} else if (passedCount == total) {
248
UpdateImageListIndex(TestResultType.Success);
250
UpdateImageListIndex(TestResultType.None);
255
/// A new test class has been added to the project so a new
256
/// tree node is added if the class belongs to this namespace.
258
void TestClassAdded(object source, TestClassEventArgs e)
260
if (e.TestClass.Namespace == fullNamespace) {
261
// Add test class to our monitored test classes.
262
testClasses.Add(e.TestClass);
264
// Add a new tree node.
265
TestClassTreeNode classNode = new TestClassTreeNode(TestProject, e.TestClass);
266
classNode.AddTo(this);
270
} else if (isInitialized && NamespaceStartsWith(e.TestClass.Namespace)) {
271
// Check if there is a child namespace node for the class.
272
string childNamespace = TestClass.GetChildNamespace(e.TestClass.Namespace, fullNamespace);
273
if (!NamespaceNodeExists(childNamespace)) {
274
// Add a new namespace node.
275
TestNamespaceTreeNode node = new TestNamespaceTreeNode(TestProject, fullNamespace, childNamespace);
285
/// Determines whether the namespace for this node starts
286
/// with the namespace specified.
288
bool NamespaceStartsWith(string ns)
290
return ns.StartsWith(String.Concat(fullNamespace, "."));
294
/// A test class has been removed from the project so the
295
/// corresponding tree node is removed if it belongs to this
298
void TestClassRemoved(object source, TestClassEventArgs e)
300
if (e.TestClass.Namespace == fullNamespace) {
301
// Remove test class from our monitored test classes.
302
testClasses.Remove(e.TestClass);
304
// Remove the corresponding tree node.
305
foreach (ExtTreeNode node in Nodes) {
306
TestClassTreeNode classNode = node as TestClassTreeNode;
307
if (classNode != null && classNode.Text == e.TestClass.Name) {
314
// Remove this namespace node if there are no more child nodes.
320
/// Removes this node if it has no child nodes. This
321
/// method also calls the same method on the parent
322
/// namespace node so it can check whether it should
330
TestNamespaceTreeNode parentNode = Parent as TestNamespaceTreeNode;
331
if (parentNode != null) {
332
parentNode.RemoveIfEmpty();