~halega/+junk/sharpdevelop

« back to all changes in this revision

Viewing changes to src/AddIns/Analysis/UnitTesting/Src/TestNamespaceTreeNode.cs

  • Committer: sk
  • Date: 2011-09-10 05:17:57 UTC
  • Revision ID: halega@halega.com-20110910051757-qfouz1llya9m6boy
4.1.0.7915 Release Candidate 1

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
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)
 
3
 
 
4
using System;
 
5
using System.Collections.Generic;
 
6
using System.Windows.Forms;
 
7
using ICSharpCode.SharpDevelop.Gui;
 
8
using ICSharpCode.SharpDevelop.Project;
 
9
 
 
10
namespace ICSharpCode.UnitTesting
 
11
{
 
12
        /// <summary>
 
13
        /// Represents a namespace in the TestTreeView.
 
14
        /// </summary>
 
15
        public class TestNamespaceTreeNode : TestTreeNode
 
16
        {
 
17
                string ns = String.Empty;
 
18
                string namespacePrefix = String.Empty;
 
19
                string fullNamespace;
 
20
                TestClassCollection testClasses;
 
21
                List<TestNamespaceTreeNode> namespaceChildNodes = new List<TestNamespaceTreeNode>();
 
22
                ExtTreeNode dummyNode;
 
23
                
 
24
                /// <summary>
 
25
                /// Creates a new TestNamespaceTreeNode
 
26
                /// </summary>
 
27
                /// <remarks>
 
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. 
 
38
                /// </remarks>
 
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)
 
47
                {
 
48
                        ns = name;
 
49
                        this.namespacePrefix = namespacePrefix;
 
50
                        fullNamespace = GetFullNamespace(namespacePrefix, ns);
 
51
                        GetTestClasses();
 
52
                        testProject.TestClasses.TestClassAdded += TestClassAdded;
 
53
                        testProject.TestClasses.TestClassRemoved += TestClassRemoved;
 
54
                        
 
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);
 
58
                                node.AddTo(this);
 
59
                                namespaceChildNodes.Add(node);
 
60
                                node.ImageIndexChanged += TestNamespaceNodeImageIndexChanged;
 
61
                        }
 
62
                        
 
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();
 
68
                                Nodes.Add(dummyNode);
 
69
                        }
 
70
                        
 
71
                        UpdateImageListIndex();
 
72
                }
 
73
                
 
74
                /// <summary>
 
75
                /// Creates a new TestNamespaceTreeNode with the specified
 
76
                /// namespace name. This node will have no namespace prefix.
 
77
                /// </summary>
 
78
                public TestNamespaceTreeNode(TestProject testProject, string name) 
 
79
                        : this(testProject, String.Empty, name)
 
80
                {
 
81
                }
 
82
                
 
83
                /// <summary>
 
84
                /// Frees any resources held by this class.
 
85
                /// </summary>
 
86
                public override void Dispose()
 
87
                {
 
88
                        if (!IsDisposed) {
 
89
                                TestProject.TestClasses.TestClassAdded -= TestClassAdded;
 
90
                                TestProject.TestClasses.TestClassRemoved -= TestClassRemoved;
 
91
                                testClasses.ResultChanged -= TestClassesResultChanged;
 
92
                        }
 
93
                        base.Dispose();
 
94
                }
 
95
                
 
96
                /// <summary>
 
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.
 
102
                /// </summary>
 
103
                public bool IsEmpty {
 
104
                        get {
 
105
                                if (isInitialized) {
 
106
                                        return Nodes.Count == 0;
 
107
                                } else if (dummyNode != null) {
 
108
                                        return testClasses.Count == 0;
 
109
                                } else {
 
110
                                        return Nodes.Count == 0 && testClasses.Count == 0;
 
111
                                }
 
112
                        }
 
113
                }
 
114
                
 
115
                /// <summary>
 
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.
 
119
                /// </summary>
 
120
                public string FullNamespace {
 
121
                        get {
 
122
                                return fullNamespace;
 
123
                        }
 
124
                }
 
125
                        
 
126
                /// <summary>
 
127
                /// Adds the test class nodes for this namespace when the
 
128
                /// node is expanded.
 
129
                /// </summary>
 
130
                protected override void Initialize()
 
131
                {
 
132
                        if (dummyNode != null) {
 
133
                                Nodes.Clear();
 
134
                        }
 
135
                        
 
136
                        // Add class nodes for this namespace.
 
137
                        foreach (TestClass c in testClasses) {
 
138
                                TestClassTreeNode classNode = new TestClassTreeNode(TestProject, c);
 
139
                                classNode.AddTo(this);
 
140
                        }
 
141
                        
 
142
                        // Sort the nodes.
 
143
                        SortChildNodes();
 
144
                }
 
145
                
 
146
                /// <summary>
 
147
                /// Adds the child namespace to the namespace prefix.
 
148
                /// </summary>
 
149
                static string GetFullNamespace(string prefix, string name)
 
150
                {
 
151
                        if (prefix.Length > 0) {
 
152
                                return String.Concat(prefix, ".", name);
 
153
                        }
 
154
                        return name;
 
155
                }
 
156
                
 
157
                /// <summary>
 
158
                /// Updates this node's icon because one of its child namespace nodes
 
159
                /// has changed.
 
160
                /// </summary>
 
161
                void TestNamespaceNodeImageIndexChanged(object source, EventArgs e)
 
162
                {
 
163
                        UpdateImageListIndex();
 
164
                }
 
165
                
 
166
                /// <summary>
 
167
                /// Gets the test classes for this namespace.
 
168
                /// </summary>
 
169
                void GetTestClasses()
 
170
                {
 
171
                        testClasses = new TestClassCollection();
 
172
                        foreach (TestClass c in TestProject.GetTestClasses(fullNamespace)) {
 
173
                                testClasses.Add(c);
 
174
                        }
 
175
                        testClasses.ResultChanged += TestClassesResultChanged;
 
176
                }
 
177
                
 
178
                /// <summary>
 
179
                /// The overall test result for the classes in this namespace
 
180
                /// have changed so the node's icon is updated.
 
181
                /// </summary>
 
182
                void TestClassesResultChanged(object source, EventArgs e)
 
183
                {
 
184
                        UpdateImageListIndex();
 
185
                }
 
186
                
 
187
                /// <summary>
 
188
                /// Determines the image list index for this node based
 
189
                /// on the current state of all the child nodes.
 
190
                /// </summary>
 
191
                /// <remarks>
 
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.
 
195
                /// </remarks>
 
196
                void UpdateImageListIndex()
 
197
                {
 
198
                        int ignoredCount = 0;
 
199
                        int passedCount = 0;
 
200
                        int failedCount = 0;
 
201
                        
 
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:
 
207
                                                failedCount++;
 
208
                                                break;
 
209
                                        case (int)TestTreeViewImageListIndex.TestIgnored:
 
210
                                                ignoredCount++;
 
211
                                                break;
 
212
                                        case (int)TestTreeViewImageListIndex.TestPassed:
 
213
                                                passedCount++;
 
214
                                                break;
 
215
                                }
 
216
                        }
 
217
                        
 
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:
 
222
                                        failedCount++;
 
223
                                        break;
 
224
                                case TestResultType.Success:
 
225
                                        passedCount++;
 
226
                                        break;
 
227
                                case TestResultType.Ignored:
 
228
                                        ignoredCount++;
 
229
                                        break;
 
230
                        }
 
231
                        
 
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.
 
239
                                total++;
 
240
                        }
 
241
                        
 
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);
 
249
                        } else {
 
250
                                UpdateImageListIndex(TestResultType.None);
 
251
                        }
 
252
                }
 
253
                
 
254
                /// <summary>
 
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.
 
257
                /// </summary>
 
258
                void TestClassAdded(object source, TestClassEventArgs e)
 
259
                {
 
260
                        if (e.TestClass.Namespace == fullNamespace) {
 
261
                                // Add test class to our monitored test classes.
 
262
                                testClasses.Add(e.TestClass);
 
263
                                
 
264
                                // Add a new tree node.
 
265
                                TestClassTreeNode classNode = new TestClassTreeNode(TestProject, e.TestClass);
 
266
                                classNode.AddTo(this);
 
267
                                
 
268
                                // Sort the nodes.
 
269
                                SortChildNodes();
 
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);
 
276
                                        node.AddTo(this);
 
277
                                        
 
278
                                        // Sort the nodes.
 
279
                                        SortChildNodes();
 
280
                                }
 
281
                        }
 
282
                }
 
283
                
 
284
                /// <summary>
 
285
                /// Determines whether the namespace for this node starts
 
286
                /// with the namespace specified.
 
287
                /// </summary>
 
288
                bool NamespaceStartsWith(string ns)
 
289
                {
 
290
                        return ns.StartsWith(String.Concat(fullNamespace, "."));
 
291
                }
 
292
                
 
293
                /// <summary>
 
294
                /// A test class has been removed from the project so the
 
295
                /// corresponding tree node is removed if it belongs to this 
 
296
                /// namespace.
 
297
                /// </summary>
 
298
                void TestClassRemoved(object source, TestClassEventArgs e)
 
299
                {
 
300
                        if (e.TestClass.Namespace == fullNamespace) {
 
301
                                // Remove test class from our monitored test classes.
 
302
                                testClasses.Remove(e.TestClass);
 
303
                        
 
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) {
 
308
                                                classNode.Remove();
 
309
                                                classNode.Dispose();
 
310
                                                break;
 
311
                                        }
 
312
                                }
 
313
                                
 
314
                                // Remove this namespace node if there are no more child nodes.
 
315
                                RemoveIfEmpty();
 
316
                        }
 
317
                }
 
318
                
 
319
                /// <summary>
 
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
 
323
                /// remove itself.
 
324
                /// </summary>
 
325
                void RemoveIfEmpty()
 
326
                {
 
327
                        if (IsEmpty) {
 
328
                                Remove();
 
329
                                Dispose();
 
330
                                TestNamespaceTreeNode parentNode = Parent as TestNamespaceTreeNode;
 
331
                                if (parentNode != null) {
 
332
                                        parentNode.RemoveIfEmpty();
 
333
                                }
 
334
                        }
 
335
                }
 
336
        }
 
337
}