diff --git a/src/AddIns/Analysis/UnitTesting/Gui/UnitTestsPad.cs b/src/AddIns/Analysis/UnitTesting/Gui/UnitTestsPad.cs
index 3a782a7abc..b725b0dc10 100644
--- a/src/AddIns/Analysis/UnitTesting/Gui/UnitTestsPad.cs
+++ b/src/AddIns/Analysis/UnitTesting/Gui/UnitTestsPad.cs
@@ -53,13 +53,7 @@ namespace ICSharpCode.UnitTesting
SD.ParserService.LoadSolutionProjectsThread.Finished += LoadSolutionProjectsThreadFinished;
OnAddedLoadSolutionProjectsThreadEndedHandler();
- // Display currently open solution.
- if (!IsParserLoadingSolution) {
- Solution openSolution = GetOpenSolution();
- if (openSolution != null) {
- SolutionLoaded(openSolution);
- }
- }
+ treeView.Root = new RootUnitTestNode();
SD.ParserService.ParseInformationUpdated += ParseInformationUpdated;
ProjectService.SolutionClosed += SolutionClosed;
@@ -133,22 +127,6 @@ namespace ICSharpCode.UnitTesting
// treeView.CollapseAll();
// }
- ///
- /// Called when a solution has been loaded.
- ///
- protected void SolutionLoaded(Solution solution)
- {
- // SolutionLoaded will be invoked from another thread.
- // The UnitTestsPad might be disposed by the time the event is processed by the main thread.
- if (treeView != null) {
- if (solution != null) {
- treeView.Root = new RootUnitTestNode(solution);
- } else {
- treeView.Root = null;
- }
- }
- }
-
///
/// Called when a solution has been closed.
///
@@ -161,15 +139,6 @@ namespace ICSharpCode.UnitTesting
// {
// treeView.RemoveSolutionFolder(solutionFolder);
// }
-//
- ///
- /// The project is added to the tree view only if it has a
- /// reference to a unit testing framework.
- ///
- protected void ProjectAdded(IProject project)
- {
- SolutionLoaded(GetOpenSolution());
- }
///
/// If the project item removed is a reference to a unit
@@ -193,7 +162,7 @@ namespace ICSharpCode.UnitTesting
{
RootUnitTestNode root = (RootUnitTestNode)treeView.Root;
if (root == null) {
- SolutionLoaded(GetOpenSolution());
+// SolutionLoaded(GetOpenSolution());
root = (RootUnitTestNode)treeView.Root;
if (root == null) return;
}
@@ -271,7 +240,6 @@ namespace ICSharpCode.UnitTesting
void ProjectAdded(object source, ProjectEventArgs e)
{
- ProjectAdded(e.Project);
UpdateToolbar();
}
diff --git a/src/AddIns/Analysis/UnitTesting/Service/TestClass.cs b/src/AddIns/Analysis/UnitTesting/Model/TestClass.cs
similarity index 59%
rename from src/AddIns/Analysis/UnitTesting/Service/TestClass.cs
rename to src/AddIns/Analysis/UnitTesting/Model/TestClass.cs
index d7424aa54a..4d582eb3f9 100644
--- a/src/AddIns/Analysis/UnitTesting/Service/TestClass.cs
+++ b/src/AddIns/Analysis/UnitTesting/Model/TestClass.cs
@@ -2,6 +2,7 @@
// This code is distributed under the GNU LGPL (for details please see \doc\license.txt)
using System;
+using System.Collections.ObjectModel;
using System.Linq;
using System.Collections.Generic;
using ICSharpCode.Core;
@@ -14,7 +15,8 @@ namespace ICSharpCode.UnitTesting
///
public class TestClass
{
- List parts;
+ string fullName;
+ ObservableCollection parts;
// TestMemberCollection testMembers;
TestResultType testResultType;
IRegisteredTestFrameworks testFrameworks;
@@ -24,10 +26,11 @@ namespace ICSharpCode.UnitTesting
///
public event EventHandler ResultChanged;
- public TestClass(IRegisteredTestFrameworks testFrameworks, params IUnresolvedTypeDefinition[] parts)
+ public TestClass(IRegisteredTestFrameworks testFrameworks, string fullName, IEnumerable parts)
{
- this.parts = new List(parts);
+ this.parts = new ObservableCollection(parts);
this.testFrameworks = testFrameworks;
+ this.fullName = fullName;
}
///
@@ -36,6 +39,10 @@ namespace ICSharpCode.UnitTesting
public IEnumerable Parts {
get { return parts; }
}
+
+ public string FullName {
+ get { return fullName; }
+ }
///
/// Gets the list of other (e.g. base types) classes where from which test members included in this test class come from.
@@ -71,71 +78,27 @@ namespace ICSharpCode.UnitTesting
return matchedClasses.ToArray();
}
- ///
- /// Gets all child namespaces that starts with the specified string.
- ///
- ///
- /// If the starts with string is 'ICSharpCode' and there is a code coverage
- /// method with a namespace of 'ICSharpCode.XmlEditor.Tests', then this
- /// method will return 'XmlEditor' as one of its strings.
- ///
- public static string[] GetChildNamespaces(ICollection classes, string parentNamespace) {
- List items = new List();
- foreach (TestClass c in classes) {
- string ns = c.GetChildNamespace(parentNamespace);
- if (ns.Length > 0) {
- if (!items.Contains(ns)) {
- items.Add(ns);
- }
- }
- }
- return items.ToArray();
- }
-
///
/// Gets the name of the class.
///
public string Name {
- get
- {
-// var currentClass = c;
-// var name = c.Name;
-// while(currentClass.DeclaringType != null)
-// {
-// name = String.Concat(currentClass.DeclaringType.Name, "+", name);
-// currentClass = currentClass.DeclaringType;
-// }
- return "";//name;
- }
+ get { return parts.First().Name; }
}
///
/// Gets the fully qualified name of the class.
///
public string QualifiedName {
- get { return ""; }// c.DotNetName; }
+ get { return parts.First().ReflectionName; }
}
///
/// Gets the namespace of this class.
///
public string Namespace {
- get {
-// var currentClass = c;
-// while (currentClass.DeclaringType != null)
-// currentClass = currentClass.DeclaringType;
-// return currentClass.Namespace;
- throw new NotImplementedException();
- }
+ get { return parts.First().Namespace; }
}
- ///
- /// Gets the root namespace for this class.
- ///
-// public string RootNamespace {
-// get { return GetRootNamespace(c.Namespace); }
-// }
-
///
/// Gets the test result for this class.
///
@@ -150,59 +113,6 @@ namespace ICSharpCode.UnitTesting
}
}
- ///
- /// Gets the child namespace from the specified namespace
- /// based on the parent namespace.
- ///
- /// Can contain multiple namespaces
- /// (e.g. ICSharpCode.XmlEditor).
- public static string GetChildNamespace(string ns, string parentNamespace)
- {
- if (parentNamespace.Length > 0) {
- if (ns.StartsWith(String.Concat(parentNamespace, "."))) {
- string end = ns.Substring(parentNamespace.Length + 1);
- return GetRootNamespace(end);
- }
- return String.Empty;
- }
- return ns;
- }
-
- ///
- /// Gets the child namespace based on the parent namespace
- /// from this class.
- ///
- /// Can contain multiple namespaces
- /// (e.g. ICSharpCode.XmlEditor).
- public string GetChildNamespace(string parentNamespace)
- {
- return GetChildNamespace(Namespace, parentNamespace);
- }
-
- ///
- /// Gets the test members in this class.
- ///
-// public TestMemberCollection TestMembers {
-// get {
-// if (testMembers == null) {
-// GetTestMembers();
-// }
-// return testMembers;
-// }
-// }
-
- ///
- /// Gets the test member with the specified name.
- ///
- /// Null if the member cannot be found.
-// public TestMember GetTestMember(string name)
-// {
-// if (TestMembers.Contains(name)) {
-// return TestMembers[name];
-// }
-// return null;
-// }
-
///
/// Updates the test member with the specified test result.
///
@@ -234,9 +144,8 @@ namespace ICSharpCode.UnitTesting
/// Updates the members and class based on the new class
/// information that has been parsed.
///
- public void UpdateClass(IUnresolvedTypeDefinition c)
+ public void UpdateClass(ITypeDefinition definition)
{
- #warning not implemented!
// this.c = c.GetCompoundClass();
//
// // Remove missing members.
@@ -281,44 +190,6 @@ namespace ICSharpCode.UnitTesting
// testMembers.ResultChanged += TestMembersResultChanged;
}
- ///
- /// Gets the test members for the specified class.
- ///
-// TestMemberCollection GetTestMembers(IUnresolvedTypeDefinition c)
-// {
-// TestMemberCollection testMembers = new TestMemberCollection();
-// foreach (var member in testFrameworks.GetTestMembersFor(c))
-// if (!testMembers.Contains(member.Name)) {
-// testMembers.Add(member);
-// }
-//
-// // Add base class test members.
-// IClass declaringType = c;
-// while (c.BaseClass != null)
-// {
-// foreach (var testMember in testFrameworks.GetTestMembersFor(c.BaseClass)) {
-// BaseTestMember baseTestMethod = new BaseTestMember(declaringType, testMember.Member);
-// TestMember testMethod = new TestMember(c.BaseClass, baseTestMethod);
-// if (testMember.Member.IsVirtual) {
-// if (!testMembers.Contains(testMember.Name)) {
-// testMembers.Add(testMethod);
-// }
-// } else {
-// if (!testMembers.Contains(testMethod.Name)) {
-// testMembers.Add(testMethod);
-// }
-// }
-// }
-// c = c.BaseClass;
-// }
-//
-// baseClassesFQNames.Clear();
-// foreach (var memberDeclaringClass in testMembers.Select(member => member.DeclaringType).Distinct())
-// if (memberDeclaringClass.CompareTo(declaringType) != 0)
-// baseClassesFQNames.Add(memberDeclaringClass.FullyQualifiedName);
-// return testMembers;
-// }
-
///
/// Updates the test class's test result after the test member's
/// test result has changed.
diff --git a/src/AddIns/Analysis/UnitTesting/Service/TestMember.cs b/src/AddIns/Analysis/UnitTesting/Model/TestMember.cs
similarity index 100%
rename from src/AddIns/Analysis/UnitTesting/Service/TestMember.cs
rename to src/AddIns/Analysis/UnitTesting/Model/TestMember.cs
diff --git a/src/AddIns/Analysis/UnitTesting/Model/TestProject.cs b/src/AddIns/Analysis/UnitTesting/Model/TestProject.cs
new file mode 100644
index 0000000000..68a4c4b6a2
--- /dev/null
+++ b/src/AddIns/Analysis/UnitTesting/Model/TestProject.cs
@@ -0,0 +1,85 @@
+// 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.ObjectModel;
+using System.Diagnostics;
+using System.Linq;
+using ICSharpCode.Core;
+using ICSharpCode.NRefactory.TypeSystem;
+using ICSharpCode.NRefactory.TypeSystem.Implementation;
+using ICSharpCode.NRefactory.Utils;
+using ICSharpCode.SharpDevelop;
+using ICSharpCode.SharpDevelop.Parser;
+using ICSharpCode.SharpDevelop.Project;
+
+namespace ICSharpCode.UnitTesting
+{
+ ///
+ /// Represents a project that has a reference to a unit testing
+ /// framework assembly. Currently only NUnit is supported.
+ ///
+ public class TestProject
+ {
+ IProject project;
+ IRegisteredTestFrameworks testFrameworks;
+ readonly ObservableCollection testClasses;
+
+ public TestProject(IProject project)
+ {
+ this.project = project;
+ this.testFrameworks = TestService.RegisteredTestFrameworks;
+ project.ParseInformationUpdated += project_ParseInformationUpdated;
+ var compilation = SD.ParserService.GetCompilation(project);
+ var classes = project.ProjectContent
+ .Resolve(compilation.TypeResolveContext)
+ .GetAllTypeDefinitions()
+ .Where(td => td.HasTests(compilation))
+ .Select(g => new TestClass(testFrameworks, g.ReflectionName, g.Parts));
+ testClasses = new ObservableCollection(classes);
+ }
+
+ void project_ParseInformationUpdated(object sender, ParseInformationEventArgs e)
+ {
+ var context = new SimpleTypeResolveContext(SD.ParserService.GetCompilation(project).MainAssembly);
+ IEnumerable @new;
+ if (e.NewParsedFile != null)
+ @new = e.NewParsedFile.TopLevelTypeDefinitions.Select(utd => utd.Resolve(context).GetDefinition()).Where(x => x != null && x.HasTests(SD.ParserService.GetCompilation(project)));
+ else
+ @new = Enumerable.Empty();
+ UpdateTestClasses(testClasses.Where(tc => tc.Parts.Any(td => td.ParsedFile.FileName == e.OldParsedFile.FileName)).Select(tc => new DefaultResolvedTypeDefinition(context, tc.Parts.ToArray())).ToList(), @new.ToList());
+ }
+
+ void UpdateTestClasses(IReadOnlyList oldTypes, IReadOnlyList newTypes)
+ {
+ var mappings = oldTypes.FullOuterJoin(newTypes, t => t.ReflectionName, t => t.ReflectionName, Tuple.Create);
+ foreach (Tuple mapping in mappings) {
+ if (mapping.Item2 == null)
+ testClasses.RemoveWhere(c => c.FullName == mapping.Item1.ReflectionName);
+ else if (mapping.Item1 == null)
+ testClasses.Add(new TestClass(testFrameworks, mapping.Item2.ReflectionName, mapping.Item2.Parts));
+ else {
+ var testClass = testClasses.SingleOrDefault(c => c.FullName == mapping.Item1.ReflectionName);
+ if (testClass == null)
+ testClasses.Add(new TestClass(testFrameworks, mapping.Item2.ReflectionName, mapping.Item2.Parts));
+ else
+ testClass.UpdateClass(mapping.Item2);
+ }
+ }
+ }
+
+ public IProject Project {
+ get { return project; }
+ }
+
+ public ObservableCollection TestClasses {
+ get { return testClasses; }
+ }
+
+ public void UpdateTestResult(TestResult result)
+ {
+
+ }
+ }
+}
diff --git a/src/AddIns/Analysis/UnitTesting/Nodes/ClassUnitTestNode.cs b/src/AddIns/Analysis/UnitTesting/Nodes/ClassUnitTestNode.cs
new file mode 100644
index 0000000000..89ca050aa2
--- /dev/null
+++ b/src/AddIns/Analysis/UnitTesting/Nodes/ClassUnitTestNode.cs
@@ -0,0 +1,28 @@
+// 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;
+
+namespace ICSharpCode.UnitTesting
+{
+ ///
+ /// Description of ClassUnitTestNode.
+ ///
+ public class ClassUnitTestNode : UnitTestBaseNode
+ {
+ TestClass testClass;
+
+ public TestClass TestClass {
+ get { return testClass; }
+ }
+
+ public ClassUnitTestNode(TestClass testClass)
+ {
+ this.testClass = testClass;
+ }
+
+ public override object Text {
+ get { return testClass.Name; }
+ }
+ }
+}
diff --git a/src/AddIns/Analysis/UnitTesting/Nodes/ProjectUnitTestNode.cs b/src/AddIns/Analysis/UnitTesting/Nodes/ProjectUnitTestNode.cs
index a77a30dc26..cb96a9b28e 100644
--- a/src/AddIns/Analysis/UnitTesting/Nodes/ProjectUnitTestNode.cs
+++ b/src/AddIns/Analysis/UnitTesting/Nodes/ProjectUnitTestNode.cs
@@ -2,12 +2,15 @@
// 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;
@@ -24,15 +27,78 @@ namespace ICSharpCode.UnitTesting
public ProjectUnitTestNode(TestProject project)
{
this.project = project;
+ project.TestClasses.CollectionChanged += TestClassesCollectionChanged;
+ LazyLoading = true;
+ }
+
+ void TestClassesCollectionChanged(object sender, NotifyCollectionChangedEventArgs e)
+ {
+ switch (e.Action) {
+ case NotifyCollectionChangedAction.Add:
+ foreach (TestClass c in e.NewItems) {
+ var node = FindNamespace(c.Namespace);
+ if (node == null) {
+ node = new NamespaceUnitTestNode(c.Namespace);
+ Children.OrderedInsert(node, (a, b) => string.CompareOrdinal(a.Text.ToString(), b.Text.ToString()));
+ }
+ node.Children.OrderedInsert(new ClassUnitTestNode(c), (a, b) => string.CompareOrdinal(a.Text.ToString(), b.Text.ToString()));
+ }
+ break;
+ case NotifyCollectionChangedAction.Remove:
+ foreach (TestClass c in e.OldItems) {
+ var node = FindNamespace(c.Namespace);
+ if (node == null) continue;
+ node.Children.RemoveWhere(n => n is ClassUnitTestNode && ((ClassUnitTestNode)n).TestClass.FullName == c.FullName);
+ if (node.Children.Count == 0)
+ Children.Remove(node);
+ }
+ break;
+ case NotifyCollectionChangedAction.Reset:
+ LoadChildren();
+ break;
+ }
+ }
+
+ NamespaceUnitTestNode FindNamespace(string @namespace)
+ {
+ foreach (var node in Children.OfType()) {
+ // TODO use language-specific StringComparer
+ if (string.Equals(node.Namespace, @namespace, StringComparison.Ordinal))
+ return node;
+ }
+ return null;
}
protected override void LoadChildren()
{
- base.LoadChildren();
+ Children.Clear();
+ foreach (var g in project.TestClasses.Select(c => new ClassUnitTestNode(c)).GroupBy(tc => tc.TestClass.Namespace)) {
+ var namespaceNode = new NamespaceUnitTestNode(g.Key);
+ namespaceNode.Children.AddRange(g);
+ Children.Add(namespaceNode);
+ }
+ }
+
+ public override object Text {
+ get { return project.Project.Name; }
+ }
+ }
+
+ public class NamespaceUnitTestNode : UnitTestBaseNode
+ {
+ string name;
+
+ public string Namespace {
+ get { return name; }
+ }
+
+ public NamespaceUnitTestNode(string name)
+ {
+ this.name = name;
}
public override object Text {
- get { return project.Name; }
+ get { return string.IsNullOrEmpty(name) ? "" : name; }
}
}
}
diff --git a/src/AddIns/Analysis/UnitTesting/Nodes/RootUnitTestNode.cs b/src/AddIns/Analysis/UnitTesting/Nodes/RootUnitTestNode.cs
index d7cd39000c..d3efabbb2c 100644
--- a/src/AddIns/Analysis/UnitTesting/Nodes/RootUnitTestNode.cs
+++ b/src/AddIns/Analysis/UnitTesting/Nodes/RootUnitTestNode.cs
@@ -2,11 +2,14 @@
// 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;
@@ -23,32 +26,31 @@ namespace ICSharpCode.UnitTesting
///
public class RootUnitTestNode : UnitTestBaseNode
{
- Solution solution;
-
- public RootUnitTestNode(Solution solution)
+ public RootUnitTestNode()
{
- this.solution = solution;
- ProjectService.ProjectAdded += OnProjectAdded;
- ProjectService.ProjectRemoved += OnProjectRemoved;
- SD.ParserService.LoadSolutionProjectsThread.Finished += delegate { LoadChildren(); };
+ TestService.TestableProjects.CollectionChanged += TestService_TestableProjects_CollectionChanged;
LazyLoading = true;
}
- void OnProjectRemoved(object sender, ProjectEventArgs e)
- {
- LoadChildren();
- }
-
- void OnProjectAdded(object sender, ProjectEventArgs e)
+ void TestService_TestableProjects_CollectionChanged(object sender, NotifyCollectionChangedEventArgs e)
{
- LoadChildren();
+ switch (e.Action) {
+ case NotifyCollectionChangedAction.Add:
+ Children.AddRange(e.NewItems.OfType().Select(p => new ProjectUnitTestNode(p)));
+ break;
+ case NotifyCollectionChangedAction.Remove:
+ Children.RemoveWhere(node => node is ProjectUnitTestNode && e.OldItems.OfType().Any(p => p.Project == ((ProjectUnitTestNode)node).Project));
+ break;
+ case NotifyCollectionChangedAction.Reset:
+ LoadChildren();
+ break;
+ }
}
protected override void LoadChildren()
{
- this.Children.Clear();
- if (!SD.ParserService.LoadSolutionProjectsThread.IsRunning)
- this.Children.AddRange(solution.Projects.Where(p => p.IsTestProject()).Select(p => new ProjectUnitTestNode(new TestProject(p))));
+ Children.Clear();
+ Children.AddRange(TestService.TestableProjects.Select(p => new ProjectUnitTestNode(p)));
}
public override object Text {
@@ -58,13 +60,51 @@ 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 SD.ParserService.GetCompilation(project).FindType("NUnit.Framework.TestAttribute").Kind != TypeKind.Unknown;
+ return testAttribute.Resolve(SD.ParserService.GetCompilation(project).TypeResolveContext).Kind != TypeKind.Unknown;
+ }
+
+ 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 FullOuterJoin(this IEnumerable outer, IEnumerable inner, Func outerKeySelector, Func innerKeySelector, Func 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(this IList list, T item, Func comparer)
+ {
+ int index = 0;
+ while (index < list.Count && comparer(list[index], item) < 0)
+ index++;
+ list.Insert(index, item);
}
}
}
diff --git a/src/AddIns/Analysis/UnitTesting/Service/TestProject.cs b/src/AddIns/Analysis/UnitTesting/Service/TestProject.cs
deleted file mode 100644
index ba712be570..0000000000
--- a/src/AddIns/Analysis/UnitTesting/Service/TestProject.cs
+++ /dev/null
@@ -1,298 +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 System.Linq;
-using ICSharpCode.Core;
-using ICSharpCode.NRefactory.TypeSystem;
-using ICSharpCode.SharpDevelop.Parser;
-using ICSharpCode.SharpDevelop.Project;
-
-namespace ICSharpCode.UnitTesting
-{
- ///
- /// Represents a project that has a reference to a unit testing
- /// framework assembly. Currently only NUnit is supported.
- ///
- public class TestProject
- {
- IProject project;
- IProjectContent projectContent;
- List testClasses;
- List rootNamespaces;
- IRegisteredTestFrameworks testFrameworks;
-
- public TestProject(IProject project)
- {
- this.project = project;
- this.projectContent = project.ProjectContent;
- this.testFrameworks = TestService.RegisteredTestFrameworks;
-// project.ProjectContent.GetAllTypeDefinitions().Where(td => td.Attributes.Select(a => a.CreateResolvedAttribute(project.ProjectContent.CreateCompilation().
- }
-
- public IProject Project {
- get { return project; }
- }
-
- ///
- /// Gets the test classes in this project.
- ///
-// public TestClassCollection TestClasses {
-// get {
-// if (testClasses == null) {
-// GetTestClasses();
-// }
-// return testClasses;
-// }
-// }
-
- ///
- /// Gets the test classes that exist in the specified namespace.
- ///
- public TestClass[] GetTestClasses(string ns)
- {
- throw new NotImplementedException();
-// return TestClass.GetTestClasses(TestClasses, ns);
- }
-
- ///
- /// Gets the test classes whose namespaces start with the specified string.
- ///
- public TestClass[] GetAllTestClasses(string namespaceStartsWith)
- {
- throw new NotImplementedException();
-// return TestClass.GetAllTestClasses(TestClasses, namespaceStartsWith);
- }
-
- ///
- /// Gets all the child namespaces with the specified parent
- /// namespace. The parent namespace can be one or more
- /// namespaces separated with a period.
- ///
- public string[] GetChildNamespaces(string parentNamespace)
- {
- throw new NotImplementedException();
-// return TestClass.GetChildNamespaces(TestClasses, parentNamespace);
- }
-
- ///
- /// Gets the project's name.
- ///
- public string Name {
- get { return project.Name; }
- }
-
- ///
- /// Gets the distinct root namespaces for all this project.
- ///
- ///
- /// If one of the namespaces is 'ICSharpCode.XmlEditor' then this
- /// method will return 'ICSharpCode' as one of the root namespaces.
- ///
- public IList RootNamespaces {
- get {
- if (rootNamespaces == null) {
- GetRootNamespaces();
- }
- return rootNamespaces;
- }
- }
-
- ///
- /// Updates the test method based on the test result.
- ///
- public void UpdateTestResult(TestResult testResult)
- {
-// TestClasses.UpdateTestResult(testResult);
- }
-
- ///
- /// Sets all the test results back to none.
- ///
- public void ResetTestResults()
- {
-// TestClasses.ResetTestResults();
- }
-
- ///
- /// Updates the classes and methods based on the new parse information.
- ///
- /// The old compiliation unit
- /// (ParseInformationEventArgs.ParseInformation.BestCompilationUnit as ICompilationUnit)
- /// The new compilation unit
- /// (ParseInformationEventArgs.CompilationUnit).
- public void UpdateParseInfo(IParsedFile oldUnit, IParsedFile newUnit)
- {
- if (!IsParseInfoForThisProject(oldUnit, newUnit)) {
- return;
- }
-
-// RemovedClasses removedClasses = new RemovedClasses();
-//
-// if (oldUnit != null) {
-// removedClasses.Add(oldUnit.Classes);
-// }
-// if (newUnit != null) {
-// foreach (IClass c in newUnit.Classes) {
-// UpdateTestClass(c);
-// foreach (IClass innerClass in new InnerClassEnumerator(c)) {
-// UpdateTestClass(innerClass);
-// removedClasses.Remove(innerClass);
-// }
-// removedClasses.Remove(c);
-// }
-// }
-//
-// // Remove missing classes.
-// foreach (IClass c in removedClasses.GetMissingClasses()) {
-// IClass existingClass = GetExistingTestClassInProject(c);
-// if (existingClass != null) {
-// UpdateTestClass(existingClass);
-// } else {
-// TestClasses.Remove(c.DotNetName);
-// }
-// }
- }
-
- ///
- /// Determines whether the new parse information is for this test
- /// project.
- ///
- public bool IsParseInfoForThisProject(IParsedFile oldUnit, IParsedFile newUnit)
- {
-// ICompilationUnit unit = oldUnit;
-// if (unit == null) {
-// unit = newUnit;
-// }
-// if (unit != null) {
-// return Object.ReferenceEquals(unit.ProjectContent, this.projectContent);
-// }
- return false;
- }
-
- ///
- /// Adds a new class to the test project's classes only if
- /// the class is a test class.
- ///
- void AddNewTestClass(IUnresolvedTypeDefinition c)
- {
- if (IsTestClass(c)) {
- TestClass testClass = CreateTestClass(c);
-// TestClasses.Add(testClass);
- }
- }
-
- TestClass CreateTestClass(IUnresolvedTypeDefinition c)
- {
- throw new NotImplementedException();
-// return new TestClass(c, testFrameworks);
- }
-
- ///
- /// Updates the test class methods based on the newly parsed class
- /// information.
- ///
- void UpdateTestClass(IUnresolvedTypeDefinition c)
- {
-// if (TestClasses.Contains(c.DotNetName))
-// {
-// if (IsTestClass(c))
-// {
-// TestClass testClass = TestClasses[c.DotNetName];
-// testClass.UpdateClass(c);
-// }
-// else
-// {
-// // TestFixture attribute has been removed so
-// // remove the class from the set of TestClasses.
-// TestClasses.Remove(c.DotNetName);
-// }
-// }
-// else
-// {
-// // TestFixture attribute may have been recently added to
-// // this class so call AddNewTestClass. No need to
-// // check if the class is actually a test class since
-// // AddNewTestClass does this anyway.
-// AddNewTestClass(c);
-// }
-//
-// var derivedTestClasses = GetTestClassesDerivedFrom(c);
-// if (derivedTestClasses.Any())
-// UpdateClassesFromProjectContent(derivedTestClasses);
-
- }
-
- private IEnumerable GetTestClassesDerivedFrom(IUnresolvedTypeDefinition c)
- {
- throw new NotImplementedException();
-// return TestClasses
-// .Where(testClass => testClass.IsDerivedFrom(c))
-// .Select(testClass => testClass.Class)
-// .ToArray();
- }
-
- private void UpdateClassesFromProjectContent(IEnumerable classes)
- {
-// foreach (var c in classes)
-// {
-// var classInProjectContent = projectContent.GetClass(c.FullyQualifiedName, c.TypeParameters.Count);
-// if (classInProjectContent != null)
-// UpdateTestClass(classInProjectContent);
-// }
- }
-
- void GetTestClasses()
- {
-// testClasses = new TestClassCollection();
-// foreach (IClass c in projectContent.Classes) {
-// if (IsTestClass(c)) {
-// if (!testClasses.Contains(c.FullyQualifiedName)) {
-// testClasses.Add(CreateTestClass(c));
-// }
-// }
-// foreach (IClass innerClass in new InnerClassEnumerator(c)) {
-// if (IsTestClass(innerClass)) {
-// if (!testClasses.Contains(innerClass.DotNetName)) {
-// testClasses.Add(CreateTestClass(innerClass));
-// }
-// }
-// }
-// }
- }
-
- bool IsTestClass(IUnresolvedTypeDefinition c)
- {
- return testFrameworks.IsTestClass(c);
- }
-
- void GetRootNamespaces()
- {
-// rootNamespaces = new List();
-// foreach (TestClass c in TestClasses) {
-// string rootNamespace = c.RootNamespace;
-// if ((rootNamespace.Length > 0) && !rootNamespaces.Contains(rootNamespace)) {
-// rootNamespaces.Add(rootNamespace);
-// }
-// }
- }
-
- ///
- /// Gets an existing test class with the same name in the project. This
- /// method is used to check that we do not remove a class after an existing duplicate class name
- /// is changed.
- ///
- TestClass GetExistingTestClassInProject(IUnresolvedTypeDefinition c)
- {
-// foreach (IClass existingClass in projectContent.Classes) {
-// if (IsTestClass(existingClass)) {
-// if (existingClass.DotNetName == c.DotNetName) {
-// return existingClass;
-// }
-// }
-// }
- return null;
- }
- }
-}
diff --git a/src/AddIns/Analysis/UnitTesting/Service/TestService.cs b/src/AddIns/Analysis/UnitTesting/Service/TestService.cs
index 20d0aa36e2..87104a2a26 100644
--- a/src/AddIns/Analysis/UnitTesting/Service/TestService.cs
+++ b/src/AddIns/Analysis/UnitTesting/Service/TestService.cs
@@ -2,7 +2,13 @@
// This code is distributed under the GNU LGPL (for details please see \doc\license.txt)
using System;
+using System.Collections.Generic;
+using System.Collections.ObjectModel;
+using System.Linq;
+
+using ICSharpCode.SharpDevelop;
using ICSharpCode.SharpDevelop.Gui;
+using ICSharpCode.SharpDevelop.Project;
namespace ICSharpCode.UnitTesting
{
@@ -28,7 +34,7 @@ namespace ICSharpCode.UnitTesting
}
public static MessageViewCategory UnitTestMessageView {
- get {
+ get {
if (unitTestMessageView == null) {
CreateUnitTestCategory();
}
@@ -38,10 +44,73 @@ namespace ICSharpCode.UnitTesting
static void CreateUnitTestCategory()
{
- MessageViewCategory.Create(ref unitTestMessageView,
- "UnitTesting",
- "${res:ICSharpCode.NUnitPad.NUnitPadContent.PadName}");
+ MessageViewCategory.Create(ref unitTestMessageView,
+ "UnitTesting",
+ "${res:ICSharpCode.NUnitPad.NUnitPadContent.PadName}");
+ }
+
+ static readonly ObservableCollection testableProjects = new ObservableCollection();
+
+ public static ObservableCollection TestableProjects {
+ get { return testableProjects; }
+ }
+
+ static TestService()
+ {
+ ProjectService.SolutionCreated += ProjectService_SolutionCreated;
+ ProjectService.SolutionLoaded += ProjectService_SolutionLoaded;
+ ProjectService.SolutionClosed += ProjectService_SolutionClosed;
+ ProjectService.ProjectCreated += ProjectService_ProjectCreated;
+ ProjectService.ProjectAdded += ProjectService_ProjectAdded;
+ ProjectService.ProjectRemoved += ProjectService_ProjectRemoved;
+ SD.ParserService.LoadSolutionProjectsThread.Finished += SD_ParserService_LoadSolutionProjectsThread_Finished;
}
+ static void SD_ParserService_LoadSolutionProjectsThread_Finished(object sender, EventArgs e)
+ {
+ testableProjects.Clear();
+ testableProjects.AddRange(GetTestableProjects());
+ }
+
+ static void ProjectService_ProjectCreated(object sender, ProjectEventArgs e)
+ {
+ if (e.Project.IsTestProject())
+ testableProjects.Add(new TestProject(e.Project));
+ }
+
+ static void ProjectService_ProjectAdded(object sender, ProjectEventArgs e)
+ {
+ if (e.Project.IsTestProject())
+ testableProjects.Add(new TestProject(e.Project));
+ }
+
+ static void ProjectService_ProjectRemoved(object sender, ProjectEventArgs e)
+ {
+ testableProjects.RemoveWhere(test => test.Project == e.Project);
+ }
+
+ static void ProjectService_SolutionCreated(object sender, SolutionEventArgs e)
+ {
+ testableProjects.Clear();
+ testableProjects.AddRange(GetTestableProjects());
+ }
+
+ static void ProjectService_SolutionClosed(object sender, EventArgs e)
+ {
+ testableProjects.Clear();
+ }
+
+ static void ProjectService_SolutionLoaded(object sender, SolutionEventArgs e)
+ {
+ testableProjects.Clear();
+ testableProjects.AddRange(GetTestableProjects());
+ }
+
+ static IEnumerable GetTestableProjects()
+ {
+ if (ProjectService.OpenSolution == null)
+ return Enumerable.Empty();
+ return ProjectService.OpenSolution.Projects.Where(p => p.IsTestProject()).Select(p => new TestProject(p));
+ }
}
}
diff --git a/src/AddIns/Analysis/UnitTesting/UnitTesting.csproj b/src/AddIns/Analysis/UnitTesting/UnitTesting.csproj
index bf8350692e..fca20029a7 100644
--- a/src/AddIns/Analysis/UnitTesting/UnitTesting.csproj
+++ b/src/AddIns/Analysis/UnitTesting/UnitTesting.csproj
@@ -17,7 +17,7 @@
4096
4
false
- v4.0
+ v4.5
@@ -37,8 +37,7 @@
- ..\..\..\..\bin\Tools\NUnit\nunit.framework.dll
- False
+ ..\..\..\Tools\NUnit\nunit.framework.dll
3.0
@@ -103,7 +102,10 @@
+
+
+
@@ -113,12 +115,10 @@
-
-
@@ -179,6 +179,7 @@
+
diff --git a/src/Main/Base/Project/Src/Util/ExtensionMethods.cs b/src/Main/Base/Project/Src/Util/ExtensionMethods.cs
index a9ae133b98..edd80bf93f 100644
--- a/src/Main/Base/Project/Src/Util/ExtensionMethods.cs
+++ b/src/Main/Base/Project/Src/Util/ExtensionMethods.cs
@@ -113,7 +113,7 @@ namespace ICSharpCode.SharpDevelop
///
/// Adds all to .
///
- public static void AddRange(this WinForms.ComboBox.ObjectCollection list, IEnumerable elements)
+ internal static void AddRange(this WinForms.ComboBox.ObjectCollection list, IEnumerable elements)
{
foreach (var o in elements)
list.Add(o);