19 changed files with 299 additions and 1153 deletions
@ -0,0 +1,81 @@ |
|||||||
|
// Copyright (c) AlphaSierraPapa for the SharpDevelop Team (for details please see \doc\copyright.txt)
|
||||||
|
// This code is distributed under the GNU LGPL (for details please see \doc\license.txt)
|
||||||
|
|
||||||
|
using System; |
||||||
|
using System.Collections.Generic; |
||||||
|
using System.Collections.Specialized; |
||||||
|
using System.Linq; |
||||||
|
using System.Reflection; |
||||||
|
using System.Windows.Controls; |
||||||
|
using System.Windows.Media; |
||||||
|
using System.Windows.Media.Imaging; |
||||||
|
|
||||||
|
using ICSharpCode.Core; |
||||||
|
using ICSharpCode.NRefactory.TypeSystem; |
||||||
|
using ICSharpCode.NRefactory.TypeSystem.Implementation; |
||||||
|
using ICSharpCode.SharpDevelop; |
||||||
|
using ICSharpCode.SharpDevelop.Parser; |
||||||
|
using ICSharpCode.SharpDevelop.Project; |
||||||
|
using ICSharpCode.TreeView; |
||||||
|
using NUnit.Framework; |
||||||
|
|
||||||
|
namespace ICSharpCode.UnitTesting |
||||||
|
{ |
||||||
|
public static class Extensions |
||||||
|
{ |
||||||
|
static readonly ITypeReference testAttribute = new GetClassTypeReference("NUnit.Framework", "TestAttribute", 0); |
||||||
|
|
||||||
|
public static bool IsTestProject(this IProject project) |
||||||
|
{ |
||||||
|
if (project == null) |
||||||
|
throw new ArgumentNullException("project"); |
||||||
|
if (project.ProjectContent == null) |
||||||
|
return false; |
||||||
|
return testAttribute.Resolve(SD.ParserService.GetCompilation(project).TypeResolveContext).Kind != TypeKind.Unknown; |
||||||
|
} |
||||||
|
|
||||||
|
public static bool IsTestMethod(this IMethod method, ICompilation compilation) |
||||||
|
{ |
||||||
|
if (method == null) |
||||||
|
throw new ArgumentNullException("method"); |
||||||
|
var testAttribute = Extensions.testAttribute.Resolve(compilation.TypeResolveContext); |
||||||
|
return method.Attributes.Any(a => a.AttributeType.Equals(testAttribute)); |
||||||
|
} |
||||||
|
|
||||||
|
public static bool HasTests(this ITypeDefinition type, ICompilation compilation) |
||||||
|
{ |
||||||
|
if (type == null) |
||||||
|
throw new ArgumentNullException("type"); |
||||||
|
var testAttribute = Extensions.testAttribute.Resolve(compilation.TypeResolveContext); |
||||||
|
return type.Methods.Any(m => m.Attributes.Any(a => a.AttributeType.Equals(testAttribute))); |
||||||
|
} |
||||||
|
|
||||||
|
public static IEnumerable<TResult> FullOuterJoin<TOuter, TInner, TKey, TResult>(this IEnumerable<TOuter> outer, IEnumerable<TInner> inner, Func<TOuter,TKey> outerKeySelector, Func<TInner,TKey> innerKeySelector, Func<TOuter,TInner,TResult> resultSelector) |
||||||
|
where TInner : class |
||||||
|
where TOuter : class |
||||||
|
{ |
||||||
|
var innerLookup = inner.ToLookup(innerKeySelector); |
||||||
|
var outerLookup = outer.ToLookup(outerKeySelector); |
||||||
|
|
||||||
|
var innerJoinItems = inner |
||||||
|
.Where(innerItem => !outerLookup.Contains(innerKeySelector(innerItem))) |
||||||
|
.Select(innerItem => resultSelector(null, innerItem)); |
||||||
|
|
||||||
|
return outer |
||||||
|
.SelectMany(outerItem => { |
||||||
|
var innerItems = innerLookup[outerKeySelector(outerItem)]; |
||||||
|
|
||||||
|
return innerItems.Any() ? innerItems : new TInner[] { null }; |
||||||
|
}, resultSelector) |
||||||
|
.Concat(innerJoinItems); |
||||||
|
} |
||||||
|
|
||||||
|
public static void OrderedInsert<T>(this IList<T> list, T item, Func<T, T, int> comparer) |
||||||
|
{ |
||||||
|
int index = 0; |
||||||
|
while (index < list.Count && comparer(list[index], item) < 0) |
||||||
|
index++; |
||||||
|
list.Insert(index, item); |
||||||
|
} |
||||||
|
} |
||||||
|
} |
@ -1,102 +0,0 @@ |
|||||||
// Copyright (c) AlphaSierraPapa for the SharpDevelop Team (for details please see \doc\copyright.txt)
|
|
||||||
// This code is distributed under the GNU LGPL (for details please see \doc\license.txt)
|
|
||||||
|
|
||||||
using System; |
|
||||||
using ICSharpCode.Core; |
|
||||||
|
|
||||||
namespace ICSharpCode.UnitTesting |
|
||||||
{ |
|
||||||
/// <summary>
|
|
||||||
/// All Tests root tree node that is added to the test tree when the
|
|
||||||
/// solution has multiple test projects.
|
|
||||||
/// </summary>
|
|
||||||
public class AllTestsTreeNode : TestTreeNode |
|
||||||
{ |
|
||||||
public AllTestsTreeNode() |
|
||||||
: base(null, StringParser.Parse("${res:ICSharpCode.UnitTesting.AllTestsTreeNode.Text}")) |
|
||||||
{ |
|
||||||
} |
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Raised when the all tests tree node is disposed.
|
|
||||||
/// </summary>
|
|
||||||
public event EventHandler Disposed; |
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Disposes this tree node.
|
|
||||||
/// </summary>
|
|
||||||
public override void Dispose() |
|
||||||
{ |
|
||||||
base.Dispose(); |
|
||||||
if (Disposed != null) { |
|
||||||
Disposed(this, new EventArgs()); |
|
||||||
} |
|
||||||
} |
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Adds a new project node as a child of the All Tests node.
|
|
||||||
/// </summary>
|
|
||||||
public void AddProjectNode(TestProjectTreeNode node) |
|
||||||
{ |
|
||||||
node.AddTo(this); |
|
||||||
node.ImageIndexChanged += TestProjectTreeNodeImageIndexChanged; |
|
||||||
} |
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Removes the project node.
|
|
||||||
/// </summary>
|
|
||||||
public void RemoveProjectNode(TestProjectTreeNode node) |
|
||||||
{ |
|
||||||
if (Nodes.Contains(node)) { |
|
||||||
node.ImageIndexChanged -= TestProjectTreeNodeImageIndexChanged; |
|
||||||
node.Remove(); |
|
||||||
} |
|
||||||
} |
|
||||||
|
|
||||||
void TestProjectTreeNodeImageIndexChanged(object source, EventArgs e) |
|
||||||
{ |
|
||||||
UpdateImageListIndex(); |
|
||||||
} |
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Sets the All Tests image index based on the current image
|
|
||||||
/// indexes of the child project tree nodes.
|
|
||||||
/// </summary>
|
|
||||||
void UpdateImageListIndex() |
|
||||||
{ |
|
||||||
int ignored = 0; |
|
||||||
int failed = 0; |
|
||||||
int passed = 0; |
|
||||||
int notRun = 0; |
|
||||||
int total = Nodes.Count; |
|
||||||
|
|
||||||
foreach (TestProjectTreeNode projectNode in Nodes) { |
|
||||||
switch (projectNode.ImageIndex) { |
|
||||||
case (int)TestTreeViewImageListIndex.TestFailed: |
|
||||||
failed++; |
|
||||||
break; |
|
||||||
case (int)TestTreeViewImageListIndex.TestPassed: |
|
||||||
passed++; |
|
||||||
break; |
|
||||||
case (int)TestTreeViewImageListIndex.TestIgnored: |
|
||||||
ignored++; |
|
||||||
break; |
|
||||||
default: // Not run.
|
|
||||||
notRun++; |
|
||||||
break; |
|
||||||
} |
|
||||||
} |
|
||||||
|
|
||||||
// Update the image index based on the test project results.
|
|
||||||
if (failed > 0) { |
|
||||||
UpdateImageListIndex(TestResultType.Failure); |
|
||||||
} else if (ignored > 0) { |
|
||||||
UpdateImageListIndex(TestResultType.Ignored); |
|
||||||
} else if (passed > 0 && notRun == 0) { |
|
||||||
UpdateImageListIndex(TestResultType.Success); |
|
||||||
} else { |
|
||||||
UpdateImageListIndex(TestResultType.None); |
|
||||||
} |
|
||||||
} |
|
||||||
} |
|
||||||
} |
|
@ -0,0 +1,26 @@ |
|||||||
|
// Copyright (c) AlphaSierraPapa for the SharpDevelop Team (for details please see \doc\copyright.txt)
|
||||||
|
// This code is distributed under the GNU LGPL (for details please see \doc\license.txt)
|
||||||
|
|
||||||
|
using System; |
||||||
|
using System.Collections.Specialized; |
||||||
|
|
||||||
|
namespace ICSharpCode.UnitTesting |
||||||
|
{ |
||||||
|
public class MemberUnitTestNode : UnitTestBaseNode |
||||||
|
{ |
||||||
|
TestMember testMember; |
||||||
|
|
||||||
|
public TestMember TestMember { |
||||||
|
get { return testMember; } |
||||||
|
} |
||||||
|
|
||||||
|
public MemberUnitTestNode(TestMember testMember) |
||||||
|
{ |
||||||
|
this.testMember = testMember; |
||||||
|
} |
||||||
|
|
||||||
|
public override object Text { |
||||||
|
get { return testMember.Method.Name; } |
||||||
|
} |
||||||
|
} |
||||||
|
} |
@ -0,0 +1,38 @@ |
|||||||
|
// Copyright (c) AlphaSierraPapa for the SharpDevelop Team (for details please see \doc\copyright.txt)
|
||||||
|
// This code is distributed under the GNU LGPL (for details please see \doc\license.txt)
|
||||||
|
|
||||||
|
using System; |
||||||
|
using System.Collections.Specialized; |
||||||
|
using System.Linq; |
||||||
|
using System.Reflection; |
||||||
|
using System.Windows.Controls; |
||||||
|
using System.Windows.Media; |
||||||
|
using System.Windows.Media.Imaging; |
||||||
|
|
||||||
|
using ICSharpCode.Core; |
||||||
|
using ICSharpCode.SharpDevelop; |
||||||
|
using ICSharpCode.SharpDevelop.Project; |
||||||
|
using ICSharpCode.TreeView; |
||||||
|
|
||||||
|
namespace ICSharpCode.UnitTesting |
||||||
|
{ |
||||||
|
public class NamespaceUnitTestNode : UnitTestBaseNode |
||||||
|
{ |
||||||
|
string name; |
||||||
|
|
||||||
|
public string Namespace { |
||||||
|
get { return name; } |
||||||
|
} |
||||||
|
|
||||||
|
public NamespaceUnitTestNode(string name) |
||||||
|
{ |
||||||
|
if (string.IsNullOrEmpty(name)) |
||||||
|
throw new ArgumentException("name"); |
||||||
|
this.name = name; |
||||||
|
} |
||||||
|
|
||||||
|
public override object Text { |
||||||
|
get { return name.Substring(name.LastIndexOf('.') + 1); } |
||||||
|
} |
||||||
|
} |
||||||
|
} |
@ -1,98 +0,0 @@ |
|||||||
// Copyright (c) AlphaSierraPapa for the SharpDevelop Team (for details please see \doc\copyright.txt)
|
|
||||||
// This code is distributed under the GNU LGPL (for details please see \doc\license.txt)
|
|
||||||
|
|
||||||
using System; |
|
||||||
|
|
||||||
using ICSharpCode.SharpDevelop.Gui; |
|
||||||
using ICSharpCode.SharpDevelop.Project; |
|
||||||
|
|
||||||
namespace ICSharpCode.UnitTesting |
|
||||||
{ |
|
||||||
/// <summary>
|
|
||||||
/// Represents a class that has the [TestFixture] attribute
|
|
||||||
/// associated with it.
|
|
||||||
/// </summary>
|
|
||||||
public class TestClassTreeNode : TestTreeNode |
|
||||||
{ |
|
||||||
TestClass testClass; |
|
||||||
|
|
||||||
public TestClassTreeNode(TestProject project, TestClass testClass) |
|
||||||
: base(project, testClass.Name) |
|
||||||
{ |
|
||||||
this.testClass = testClass; |
|
||||||
testClass.ResultChanged += TestClassResultChanged; |
|
||||||
Nodes.Add(new ExtTreeNode()); |
|
||||||
UpdateImageListIndex(testClass.Result); |
|
||||||
} |
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Gets the underlying IClass for this test class.
|
|
||||||
/// </summary>
|
|
||||||
public itd Class { |
|
||||||
get { return testClass.Class; } |
|
||||||
} |
|
||||||
|
|
||||||
public override void Dispose() |
|
||||||
{ |
|
||||||
if (!IsDisposed) { |
|
||||||
testClass.ResultChanged -= TestClassResultChanged; |
|
||||||
testClass.TestMembers.TestMemberAdded -= TestMemberAdded; |
|
||||||
testClass.TestMembers.TestMemberRemoved -= TestMemberRemoved; |
|
||||||
} |
|
||||||
base.Dispose(); |
|
||||||
} |
|
||||||
|
|
||||||
protected override void Initialize() |
|
||||||
{ |
|
||||||
Nodes.Clear(); |
|
||||||
|
|
||||||
foreach (TestMember member in testClass.TestMembers) { |
|
||||||
AddTestMemberTreeNode(member); |
|
||||||
} |
|
||||||
testClass.TestMembers.TestMemberAdded += TestMemberAdded; |
|
||||||
testClass.TestMembers.TestMemberRemoved += TestMemberRemoved; |
|
||||||
} |
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Adds a new TestMemberTreeNode to this node.
|
|
||||||
/// </summary>
|
|
||||||
void AddTestMemberTreeNode(TestMember member) |
|
||||||
{ |
|
||||||
TestMemberTreeNode node = new TestMemberTreeNode(TestProject, member); |
|
||||||
node.AddTo(this); |
|
||||||
} |
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Updates the node's icon based on the test class test result.
|
|
||||||
/// </summary>
|
|
||||||
void TestClassResultChanged(object source, EventArgs e) |
|
||||||
{ |
|
||||||
UpdateImageListIndex(testClass.Result); |
|
||||||
} |
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Adds a new test member tree node to this class node after a new
|
|
||||||
/// TestMember has been added to the TestClass.
|
|
||||||
/// </summary>
|
|
||||||
void TestMemberAdded(object source, TestMemberEventArgs e) |
|
||||||
{ |
|
||||||
AddTestMemberTreeNode(e.TestMember); |
|
||||||
SortChildNodes(); |
|
||||||
} |
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Removes the corresponding test member node after it has been
|
|
||||||
/// removed from the TestClass.
|
|
||||||
/// </summary>
|
|
||||||
void TestMemberRemoved(object source, TestMemberEventArgs e) |
|
||||||
{ |
|
||||||
foreach (TestMemberTreeNode memberNode in Nodes) { |
|
||||||
if (memberNode.Text == e.TestMember.Name) { |
|
||||||
Nodes.Remove(memberNode); |
|
||||||
memberNode.Dispose(); |
|
||||||
break; |
|
||||||
} |
|
||||||
} |
|
||||||
} |
|
||||||
} |
|
||||||
} |
|
@ -1,53 +0,0 @@ |
|||||||
// Copyright (c) AlphaSierraPapa for the SharpDevelop Team (for details please see \doc\copyright.txt)
|
|
||||||
// This code is distributed under the GNU LGPL (for details please see \doc\license.txt)
|
|
||||||
|
|
||||||
using System; |
|
||||||
|
|
||||||
using ICSharpCode.SharpDevelop.Gui; |
|
||||||
using ICSharpCode.SharpDevelop.Project; |
|
||||||
|
|
||||||
namespace ICSharpCode.UnitTesting |
|
||||||
{ |
|
||||||
/// <summary>
|
|
||||||
/// Represents a member that has the [Test] attribute associated with it.
|
|
||||||
/// </summary>
|
|
||||||
public class TestMemberTreeNode : TestTreeNode |
|
||||||
{ |
|
||||||
TestMember testMember; |
|
||||||
|
|
||||||
public TestMemberTreeNode(TestProject project, TestMember testMember) |
|
||||||
: base(project, testMember.Name) |
|
||||||
{ |
|
||||||
this.testMember = testMember; |
|
||||||
testMember.ResultChanged += TestMemberResultChanged; |
|
||||||
UpdateImageListIndex(testMember.Result); |
|
||||||
} |
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Gets the underlying IMember for this test member.
|
|
||||||
/// </summary>
|
|
||||||
public IMember Member { |
|
||||||
get { return testMember.Member; } |
|
||||||
} |
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Removes the TestMember.ResultChanged event handler.
|
|
||||||
/// </summary>
|
|
||||||
public override void Dispose() |
|
||||||
{ |
|
||||||
if (!IsDisposed) { |
|
||||||
testMember.ResultChanged -= TestMemberResultChanged; |
|
||||||
} |
|
||||||
base.Dispose(); |
|
||||||
} |
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Updates the node's icon after the test member result
|
|
||||||
/// has changed.
|
|
||||||
/// </summary>
|
|
||||||
void TestMemberResultChanged(object source, EventArgs e) |
|
||||||
{ |
|
||||||
UpdateImageListIndex(testMember.Result); |
|
||||||
} |
|
||||||
} |
|
||||||
} |
|
@ -1,55 +0,0 @@ |
|||||||
// Copyright (c) AlphaSierraPapa for the SharpDevelop Team (for details please see \doc\copyright.txt)
|
|
||||||
// This code is distributed under the GNU LGPL (for details please see \doc\license.txt)
|
|
||||||
|
|
||||||
using System; |
|
||||||
using ICSharpCode.SharpDevelop.Dom; |
|
||||||
using ICSharpCode.SharpDevelop.Gui; |
|
||||||
using ICSharpCode.SharpDevelop.Project; |
|
||||||
|
|
||||||
namespace ICSharpCode.UnitTesting |
|
||||||
{ |
|
||||||
/// <summary>
|
|
||||||
/// Represents a method that has the [Test] attribute associated with it.
|
|
||||||
/// </summary>
|
|
||||||
public class TestMethodTreeNode : TestTreeNode |
|
||||||
{ |
|
||||||
TestMethod testMethod; |
|
||||||
|
|
||||||
public TestMethodTreeNode(TestProject project, TestMethod testMethod) |
|
||||||
: base(project, testMethod.Name) |
|
||||||
{ |
|
||||||
this.testMethod = testMethod; |
|
||||||
testMethod.ResultChanged += TestMethodResultChanged; |
|
||||||
UpdateImageListIndex(testMethod.Result); |
|
||||||
} |
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Gets the underlying IMethod for this test method.
|
|
||||||
/// </summary>
|
|
||||||
public IMember Method { |
|
||||||
get { |
|
||||||
return testMethod.Method; |
|
||||||
} |
|
||||||
} |
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Removes the TestMethod.ResultChanged event handler.
|
|
||||||
/// </summary>
|
|
||||||
public override void Dispose() |
|
||||||
{ |
|
||||||
if (!IsDisposed) { |
|
||||||
testMethod.ResultChanged -= TestMethodResultChanged; |
|
||||||
} |
|
||||||
base.Dispose(); |
|
||||||
} |
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Updates the node's icon after the test method result
|
|
||||||
/// has changed.
|
|
||||||
/// </summary>
|
|
||||||
void TestMethodResultChanged(object source, EventArgs e) |
|
||||||
{ |
|
||||||
UpdateImageListIndex(testMethod.Result); |
|
||||||
} |
|
||||||
} |
|
||||||
} |
|
@ -1,336 +0,0 @@ |
|||||||
// Copyright (c) AlphaSierraPapa for the SharpDevelop Team (for details please see \doc\copyright.txt)
|
|
||||||
// This code is distributed under the GNU LGPL (for details please see \doc\license.txt)
|
|
||||||
|
|
||||||
using System; |
|
||||||
using System.Collections.Generic; |
|
||||||
using ICSharpCode.SharpDevelop.Gui; |
|
||||||
using ICSharpCode.SharpDevelop.Project; |
|
||||||
|
|
||||||
namespace ICSharpCode.UnitTesting |
|
||||||
{ |
|
||||||
/// <summary>
|
|
||||||
/// Represents a namespace in the TestTreeView.
|
|
||||||
/// </summary>
|
|
||||||
public class TestNamespaceTreeNode : TestTreeNode |
|
||||||
{ |
|
||||||
string ns = String.Empty; |
|
||||||
string namespacePrefix = String.Empty; |
|
||||||
string fullNamespace; |
|
||||||
TestClassCollection testClasses; |
|
||||||
List<TestNamespaceTreeNode> namespaceChildNodes = new List<TestNamespaceTreeNode>(); |
|
||||||
ExtTreeNode dummyNode; |
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Creates a new TestNamespaceTreeNode
|
|
||||||
/// </summary>
|
|
||||||
/// <remarks>
|
|
||||||
/// Note that the Namespace child nodes are added in
|
|
||||||
/// the constructor not whilst the node is expanding
|
|
||||||
/// via the Initialize method. This is so the icon for the
|
|
||||||
/// node can be updated even if the parent node is not
|
|
||||||
/// expanded. The alternative is to have each namespace node,
|
|
||||||
/// even if it does not have any class child nodes, to
|
|
||||||
/// store all the classes that are below it in the tree and
|
|
||||||
/// update the icon based on their results. The assumption
|
|
||||||
/// is that there are fewer namespace nodes than classes so
|
|
||||||
/// adding the namespace nodes here does not matter.
|
|
||||||
/// </remarks>
|
|
||||||
/// <param name="namespacePrefix">The first part of the
|
|
||||||
/// namespace (including any dot characters) before this
|
|
||||||
/// particular namespace.</param>
|
|
||||||
/// <param name="name">The name of the namespace without any
|
|
||||||
/// dot characters (e.g. the name at this particular
|
|
||||||
/// location in the tree).</param>
|
|
||||||
public TestNamespaceTreeNode(TestProject testProject, string namespacePrefix, string name) |
|
||||||
: base(testProject, name) |
|
||||||
{ |
|
||||||
ns = name; |
|
||||||
this.namespacePrefix = namespacePrefix; |
|
||||||
fullNamespace = GetFullNamespace(namespacePrefix, ns); |
|
||||||
GetTestClasses(); |
|
||||||
testProject.TestClasses.TestClassAdded += TestClassAdded; |
|
||||||
testProject.TestClasses.TestClassRemoved += TestClassRemoved; |
|
||||||
|
|
||||||
// Add namespace nodes - do not add them on node expansion.
|
|
||||||
foreach (string namespaceName in TestProject.GetChildNamespaces(fullNamespace)) { |
|
||||||
TestNamespaceTreeNode node = new TestNamespaceTreeNode(TestProject, fullNamespace, namespaceName); |
|
||||||
node.AddTo(this); |
|
||||||
namespaceChildNodes.Add(node); |
|
||||||
node.ImageIndexChanged += TestNamespaceNodeImageIndexChanged; |
|
||||||
} |
|
||||||
|
|
||||||
// Add a dummy node if there are no namespaces since
|
|
||||||
// there might be class nodes which will be added
|
|
||||||
// lazily when the node is expanded.
|
|
||||||
if (namespaceChildNodes.Count == 0) { |
|
||||||
dummyNode = new ExtTreeNode(); |
|
||||||
Nodes.Add(dummyNode); |
|
||||||
} |
|
||||||
|
|
||||||
UpdateImageListIndex(); |
|
||||||
} |
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Creates a new TestNamespaceTreeNode with the specified
|
|
||||||
/// namespace name. This node will have no namespace prefix.
|
|
||||||
/// </summary>
|
|
||||||
public TestNamespaceTreeNode(TestProject testProject, string name) |
|
||||||
: this(testProject, String.Empty, name) |
|
||||||
{ |
|
||||||
} |
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Frees any resources held by this class.
|
|
||||||
/// </summary>
|
|
||||||
public override void Dispose() |
|
||||||
{ |
|
||||||
if (!IsDisposed) { |
|
||||||
TestProject.TestClasses.TestClassAdded -= TestClassAdded; |
|
||||||
TestProject.TestClasses.TestClassRemoved -= TestClassRemoved; |
|
||||||
testClasses.ResultChanged -= TestClassesResultChanged; |
|
||||||
} |
|
||||||
base.Dispose(); |
|
||||||
} |
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Gets whether this namespace node is considered empty. If
|
|
||||||
/// the node has been expanded then the node is empty if it
|
|
||||||
/// has no child nodes. If it has not been expanded then there
|
|
||||||
/// will be a dummy child node or a set of namespace
|
|
||||||
/// nodes but no test class nodes.
|
|
||||||
/// </summary>
|
|
||||||
public bool IsEmpty { |
|
||||||
get { |
|
||||||
if (isInitialized) { |
|
||||||
return Nodes.Count == 0; |
|
||||||
} else if (dummyNode != null) { |
|
||||||
return testClasses.Count == 0; |
|
||||||
} else { |
|
||||||
return Nodes.Count == 0 && testClasses.Count == 0; |
|
||||||
} |
|
||||||
} |
|
||||||
} |
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Gets the full namespace of this tree node. This includes any
|
|
||||||
/// parent namespaces prefixed to the namespace associated
|
|
||||||
/// with this tree node.
|
|
||||||
/// </summary>
|
|
||||||
public string FullNamespace { |
|
||||||
get { |
|
||||||
return fullNamespace; |
|
||||||
} |
|
||||||
} |
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Adds the test class nodes for this namespace when the
|
|
||||||
/// node is expanded.
|
|
||||||
/// </summary>
|
|
||||||
protected override void Initialize() |
|
||||||
{ |
|
||||||
if (dummyNode != null) { |
|
||||||
Nodes.Clear(); |
|
||||||
} |
|
||||||
|
|
||||||
// Add class nodes for this namespace.
|
|
||||||
foreach (TestClass c in testClasses) { |
|
||||||
TestClassTreeNode classNode = new TestClassTreeNode(TestProject, c); |
|
||||||
classNode.AddTo(this); |
|
||||||
} |
|
||||||
|
|
||||||
// Sort the nodes.
|
|
||||||
SortChildNodes(); |
|
||||||
} |
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Adds the child namespace to the namespace prefix.
|
|
||||||
/// </summary>
|
|
||||||
static string GetFullNamespace(string prefix, string name) |
|
||||||
{ |
|
||||||
if (prefix.Length > 0) { |
|
||||||
return String.Concat(prefix, ".", name); |
|
||||||
} |
|
||||||
return name; |
|
||||||
} |
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Updates this node's icon because one of its child namespace nodes
|
|
||||||
/// has changed.
|
|
||||||
/// </summary>
|
|
||||||
void TestNamespaceNodeImageIndexChanged(object source, EventArgs e) |
|
||||||
{ |
|
||||||
UpdateImageListIndex(); |
|
||||||
} |
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Gets the test classes for this namespace.
|
|
||||||
/// </summary>
|
|
||||||
void GetTestClasses() |
|
||||||
{ |
|
||||||
testClasses = new TestClassCollection(); |
|
||||||
foreach (TestClass c in TestProject.GetTestClasses(fullNamespace)) { |
|
||||||
testClasses.Add(c); |
|
||||||
} |
|
||||||
testClasses.ResultChanged += TestClassesResultChanged; |
|
||||||
} |
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// The overall test result for the classes in this namespace
|
|
||||||
/// have changed so the node's icon is updated.
|
|
||||||
/// </summary>
|
|
||||||
void TestClassesResultChanged(object source, EventArgs e) |
|
||||||
{ |
|
||||||
UpdateImageListIndex(); |
|
||||||
} |
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Determines the image list index for this node based
|
|
||||||
/// on the current state of all the child nodes.
|
|
||||||
/// </summary>
|
|
||||||
/// <remarks>
|
|
||||||
/// Since the test classes overall test result is
|
|
||||||
/// available via the TestClassCollection we do not
|
|
||||||
/// need to sum all the individual test classes.
|
|
||||||
/// </remarks>
|
|
||||||
void UpdateImageListIndex() |
|
||||||
{ |
|
||||||
int ignoredCount = 0; |
|
||||||
int passedCount = 0; |
|
||||||
int failedCount = 0; |
|
||||||
|
|
||||||
// Count the passes, failures and ignores for the
|
|
||||||
// namespace child nodes.
|
|
||||||
foreach (ExtTreeNode node in namespaceChildNodes) { |
|
||||||
switch (node.ImageIndex) { |
|
||||||
case (int)TestTreeViewImageListIndex.TestFailed: |
|
||||||
failedCount++; |
|
||||||
break; |
|
||||||
case (int)TestTreeViewImageListIndex.TestIgnored: |
|
||||||
ignoredCount++; |
|
||||||
break; |
|
||||||
case (int)TestTreeViewImageListIndex.TestPassed: |
|
||||||
passedCount++; |
|
||||||
break; |
|
||||||
} |
|
||||||
} |
|
||||||
|
|
||||||
// Check the passes, failures and ignores for the
|
|
||||||
// test classes that belong to this namespace.
|
|
||||||
switch (testClasses.Result) { |
|
||||||
case TestResultType.Failure: |
|
||||||
failedCount++; |
|
||||||
break; |
|
||||||
case TestResultType.Success: |
|
||||||
passedCount++; |
|
||||||
break; |
|
||||||
case TestResultType.Ignored: |
|
||||||
ignoredCount++; |
|
||||||
break; |
|
||||||
} |
|
||||||
|
|
||||||
// Work out the total number of passes we are expecting
|
|
||||||
int total = namespaceChildNodes.Count; |
|
||||||
if (testClasses.Count > 0) { |
|
||||||
// Only add one for the testClasses since the
|
|
||||||
// overall pass or failure is indicated via
|
|
||||||
// the TestClassCollection so we do not need
|
|
||||||
// to add all the test classes.
|
|
||||||
total++; |
|
||||||
} |
|
||||||
|
|
||||||
// Determine the correct image list index for this node.
|
|
||||||
if (failedCount > 0) { |
|
||||||
UpdateImageListIndex(TestResultType.Failure); |
|
||||||
} else if (ignoredCount > 0) { |
|
||||||
UpdateImageListIndex(TestResultType.Ignored); |
|
||||||
} else if (passedCount == total) { |
|
||||||
UpdateImageListIndex(TestResultType.Success); |
|
||||||
} else { |
|
||||||
UpdateImageListIndex(TestResultType.None); |
|
||||||
} |
|
||||||
} |
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// A new test class has been added to the project so a new
|
|
||||||
/// tree node is added if the class belongs to this namespace.
|
|
||||||
/// </summary>
|
|
||||||
void TestClassAdded(object source, TestClassEventArgs e) |
|
||||||
{ |
|
||||||
if (e.TestClass.Namespace == fullNamespace) { |
|
||||||
// Add test class to our monitored test classes.
|
|
||||||
testClasses.Add(e.TestClass); |
|
||||||
|
|
||||||
// Add a new tree node.
|
|
||||||
TestClassTreeNode classNode = new TestClassTreeNode(TestProject, e.TestClass); |
|
||||||
classNode.AddTo(this); |
|
||||||
|
|
||||||
// Sort the nodes.
|
|
||||||
SortChildNodes(); |
|
||||||
} else if (isInitialized && NamespaceStartsWith(e.TestClass.Namespace)) { |
|
||||||
// Check if there is a child namespace node for the class.
|
|
||||||
string childNamespace = TestClass.GetChildNamespace(e.TestClass.Namespace, fullNamespace); |
|
||||||
if (!NamespaceNodeExists(childNamespace)) { |
|
||||||
// Add a new namespace node.
|
|
||||||
TestNamespaceTreeNode node = new TestNamespaceTreeNode(TestProject, fullNamespace, childNamespace); |
|
||||||
node.AddTo(this); |
|
||||||
|
|
||||||
// Sort the nodes.
|
|
||||||
SortChildNodes(); |
|
||||||
} |
|
||||||
} |
|
||||||
} |
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Determines whether the namespace for this node starts
|
|
||||||
/// with the namespace specified.
|
|
||||||
/// </summary>
|
|
||||||
bool NamespaceStartsWith(string ns) |
|
||||||
{ |
|
||||||
return ns.StartsWith(String.Concat(fullNamespace, ".")); |
|
||||||
} |
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// A test class has been removed from the project so the
|
|
||||||
/// corresponding tree node is removed if it belongs to this
|
|
||||||
/// namespace.
|
|
||||||
/// </summary>
|
|
||||||
void TestClassRemoved(object source, TestClassEventArgs e) |
|
||||||
{ |
|
||||||
if (e.TestClass.Namespace == fullNamespace) { |
|
||||||
// Remove test class from our monitored test classes.
|
|
||||||
testClasses.Remove(e.TestClass); |
|
||||||
|
|
||||||
// Remove the corresponding tree node.
|
|
||||||
foreach (ExtTreeNode node in Nodes) { |
|
||||||
TestClassTreeNode classNode = node as TestClassTreeNode; |
|
||||||
if (classNode != null && classNode.Text == e.TestClass.Name) { |
|
||||||
classNode.Remove(); |
|
||||||
classNode.Dispose(); |
|
||||||
break; |
|
||||||
} |
|
||||||
} |
|
||||||
|
|
||||||
// Remove this namespace node if there are no more child nodes.
|
|
||||||
RemoveIfEmpty(); |
|
||||||
} |
|
||||||
} |
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Removes this node if it has no child nodes. This
|
|
||||||
/// method also calls the same method on the parent
|
|
||||||
/// namespace node so it can check whether it should
|
|
||||||
/// remove itself.
|
|
||||||
/// </summary>
|
|
||||||
void RemoveIfEmpty() |
|
||||||
{ |
|
||||||
if (IsEmpty) { |
|
||||||
Remove(); |
|
||||||
Dispose(); |
|
||||||
TestNamespaceTreeNode parentNode = Parent as TestNamespaceTreeNode; |
|
||||||
if (parentNode != null) { |
|
||||||
parentNode.RemoveIfEmpty(); |
|
||||||
} |
|
||||||
} |
|
||||||
} |
|
||||||
} |
|
||||||
} |
|
@ -1,113 +0,0 @@ |
|||||||
// Copyright (c) AlphaSierraPapa for the SharpDevelop Team (for details please see \doc\copyright.txt)
|
|
||||||
// This code is distributed under the GNU LGPL (for details please see \doc\license.txt)
|
|
||||||
|
|
||||||
using System; |
|
||||||
|
|
||||||
using ICSharpCode.SharpDevelop.Gui; |
|
||||||
using ICSharpCode.SharpDevelop.Project; |
|
||||||
|
|
||||||
namespace ICSharpCode.UnitTesting |
|
||||||
{ |
|
||||||
/// <summary>
|
|
||||||
/// The root tree node for a project that has tests.
|
|
||||||
/// </summary>
|
|
||||||
public class TestProjectTreeNode : TestTreeNode |
|
||||||
{ |
|
||||||
public TestProjectTreeNode(TestProject project) |
|
||||||
: base(project, project.Name) |
|
||||||
{ |
|
||||||
Nodes.Add(new ExtTreeNode()); |
|
||||||
TestProject.TestClasses.ResultChanged += TestClassesResultChanged; |
|
||||||
TestProject.TestClasses.TestClassAdded += TestClassAdded; |
|
||||||
TestProject.TestClasses.TestClassRemoved += TestClassRemoved; |
|
||||||
} |
|
||||||
|
|
||||||
public override void Dispose() |
|
||||||
{ |
|
||||||
if (!IsDisposed) { |
|
||||||
TestProject.TestClasses.ResultChanged -= TestClassesResultChanged; |
|
||||||
TestProject.TestClasses.TestClassAdded -= TestClassAdded; |
|
||||||
TestProject.TestClasses.TestClassRemoved -= TestClassRemoved; |
|
||||||
} |
|
||||||
base.Dispose(); |
|
||||||
} |
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Adds the child nodes after this node has been expanded.
|
|
||||||
/// </summary>
|
|
||||||
protected override void Initialize() |
|
||||||
{ |
|
||||||
Nodes.Clear(); |
|
||||||
|
|
||||||
// Add namespace nodes.
|
|
||||||
foreach (string rootNamespace in TestProject.RootNamespaces) { |
|
||||||
TestNamespaceTreeNode node = new TestNamespaceTreeNode(TestProject, rootNamespace); |
|
||||||
node.AddTo(this); |
|
||||||
} |
|
||||||
|
|
||||||
// Add class nodes.
|
|
||||||
foreach (TestClass c in TestProject.GetTestClasses(String.Empty)) { |
|
||||||
AddClassNode(c); |
|
||||||
} |
|
||||||
|
|
||||||
// Sort the nodes.
|
|
||||||
SortChildNodes(); |
|
||||||
} |
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Updates this node's icon based on the overall result of the
|
|
||||||
/// test classes.
|
|
||||||
/// </summary>
|
|
||||||
void TestClassesResultChanged(object source, EventArgs e) |
|
||||||
{ |
|
||||||
UpdateImageListIndex(TestProject.TestClasses.Result); |
|
||||||
} |
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Adds a new class node to this project node if the
|
|
||||||
/// class added has no root namespace.
|
|
||||||
/// </summary>
|
|
||||||
void TestClassAdded(object source, TestClassEventArgs e) |
|
||||||
{ |
|
||||||
if (e.TestClass.Namespace == String.Empty) { |
|
||||||
AddClassNode(e.TestClass); |
|
||||||
SortChildNodes(); |
|
||||||
} else if (isInitialized) { |
|
||||||
// Check that we have a namespace node for this class.
|
|
||||||
if (!NamespaceNodeExists(e.TestClass.RootNamespace)) { |
|
||||||
// Add a new namespace node.
|
|
||||||
TestNamespaceTreeNode node = new TestNamespaceTreeNode(TestProject, e.TestClass.RootNamespace); |
|
||||||
node.AddTo(this); |
|
||||||
SortChildNodes(); |
|
||||||
} |
|
||||||
} |
|
||||||
} |
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Removes the corresponding tree node that is a child of
|
|
||||||
/// this project tree node if the class has no root namespace.
|
|
||||||
/// </summary>
|
|
||||||
void TestClassRemoved(object source, TestClassEventArgs e) |
|
||||||
{ |
|
||||||
if (e.TestClass.Namespace == String.Empty) { |
|
||||||
foreach (ExtTreeNode node in Nodes) { |
|
||||||
TestClassTreeNode classNode = node as TestClassTreeNode; |
|
||||||
if (classNode != null && classNode.Text == e.TestClass.Name) { |
|
||||||
classNode.Remove(); |
|
||||||
classNode.Dispose(); |
|
||||||
break; |
|
||||||
} |
|
||||||
} |
|
||||||
} |
|
||||||
} |
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Adds a new TestClassTreeNode to this node.
|
|
||||||
/// </summary>
|
|
||||||
void AddClassNode(TestClass c) |
|
||||||
{ |
|
||||||
TestClassTreeNode node = new TestClassTreeNode(TestProject, c); |
|
||||||
node.AddTo(this); |
|
||||||
} |
|
||||||
} |
|
||||||
} |
|
@ -1,103 +0,0 @@ |
|||||||
// Copyright (c) AlphaSierraPapa for the SharpDevelop Team (for details please see \doc\copyright.txt)
|
|
||||||
// This code is distributed under the GNU LGPL (for details please see \doc\license.txt)
|
|
||||||
|
|
||||||
using System; |
|
||||||
using ICSharpCode.SharpDevelop.Gui; |
|
||||||
using ICSharpCode.SharpDevelop.Project; |
|
||||||
using ICSharpCode.TreeView; |
|
||||||
|
|
||||||
namespace ICSharpCode.UnitTesting |
|
||||||
{ |
|
||||||
/// <summary>
|
|
||||||
/// Base class for all test tree nodes.
|
|
||||||
/// </summary>
|
|
||||||
public abstract class TestTreeNode : SharpTreeNode |
|
||||||
{ |
|
||||||
TestProject testProject; |
|
||||||
|
|
||||||
public event EventHandler ImageIndexChanged; |
|
||||||
|
|
||||||
public TestTreeNode(TestProject testProject, string text) |
|
||||||
{ |
|
||||||
this.testProject = testProject; |
|
||||||
this.Text = text; |
|
||||||
ImageIndex = (int)TestTreeViewImageListIndex.TestNotRun; |
|
||||||
} |
|
||||||
|
|
||||||
public IProject Project { |
|
||||||
get { |
|
||||||
return testProject.Project; |
|
||||||
} |
|
||||||
} |
|
||||||
|
|
||||||
public TestProject TestProject { |
|
||||||
get { |
|
||||||
return testProject; |
|
||||||
} |
|
||||||
} |
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Changes the node's icon based on the specified test result.
|
|
||||||
/// </summary>
|
|
||||||
protected void UpdateImageListIndex(TestResultType result) |
|
||||||
{ |
|
||||||
int previousImageIndex = ImageIndex; |
|
||||||
switch (result) { |
|
||||||
case TestResultType.Failure: |
|
||||||
ImageIndex = (int)TestTreeViewImageListIndex.TestFailed; |
|
||||||
break; |
|
||||||
case TestResultType.Success: |
|
||||||
ImageIndex = (int)TestTreeViewImageListIndex.TestPassed; |
|
||||||
break; |
|
||||||
case TestResultType.Ignored: |
|
||||||
ImageIndex = (int)TestTreeViewImageListIndex.TestIgnored; |
|
||||||
break; |
|
||||||
case TestResultType.None: |
|
||||||
ImageIndex = (int)TestTreeViewImageListIndex.TestNotRun; |
|
||||||
break; |
|
||||||
} |
|
||||||
SelectedImageIndex = ImageIndex; |
|
||||||
if (previousImageIndex != ImageIndex) { |
|
||||||
OnImageIndexChanged(); |
|
||||||
} |
|
||||||
} |
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Raises the ImageIndexChanged event.
|
|
||||||
/// </summary>
|
|
||||||
protected void OnImageIndexChanged() |
|
||||||
{ |
|
||||||
if (ImageIndexChanged != null) { |
|
||||||
ImageIndexChanged(this, new EventArgs()); |
|
||||||
} |
|
||||||
} |
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Checks all the child nodes of this node to see
|
|
||||||
/// if the root namespace (i.e. the first part of the
|
|
||||||
/// namespace) exists in the tree.
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="rootNamespace">The first dotted part
|
|
||||||
/// of the namespace.</param>
|
|
||||||
protected bool NamespaceNodeExists(string rootNamespace) |
|
||||||
{ |
|
||||||
foreach (ExtTreeNode node in Nodes) { |
|
||||||
TestNamespaceTreeNode namespaceNode = node as TestNamespaceTreeNode; |
|
||||||
if (namespaceNode != null && namespaceNode.Text == rootNamespace) { |
|
||||||
return true; |
|
||||||
} |
|
||||||
} |
|
||||||
return false; |
|
||||||
} |
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Sorts the immediate child nodes of this node. The sort
|
|
||||||
/// is not done recursively.
|
|
||||||
/// </summary>
|
|
||||||
protected void SortChildNodes() |
|
||||||
{ |
|
||||||
ExtTreeView treeView = (ExtTreeView)TreeView; |
|
||||||
treeView.SortNodes(Nodes, false); |
|
||||||
} |
|
||||||
} |
|
||||||
} |
|
Loading…
Reference in new issue