Browse Source

fix some bugs in test run handling and complete support for TestCase

newNRvisualizers
Siegfried Pammer 13 years ago
parent
commit
9a14ac1e52
  1. 2
      SharpDevelop.sln
  2. 0
      src/AddIns/Analysis/UnitTesting/Commands/RunProjectTestsInPadCommand.cs
  3. 2
      src/AddIns/Analysis/UnitTesting/Commands/RunTestCommands.cs
  4. 51
      src/AddIns/Analysis/UnitTesting/Commands/UnitTestCommands.cs
  5. 6
      src/AddIns/Analysis/UnitTesting/Extensions.cs
  6. 32
      src/AddIns/Analysis/UnitTesting/Gui/UnitTestsPad.cs
  7. 1
      src/AddIns/Analysis/UnitTesting/Interfaces/IRegisteredTestFrameworks.cs
  8. 1
      src/AddIns/Analysis/UnitTesting/Interfaces/ITestFramework.cs
  9. 2
      src/AddIns/Analysis/UnitTesting/Interfaces/ITestTreeView.cs
  10. 30
      src/AddIns/Analysis/UnitTesting/Model/TestClass.cs
  11. 23
      src/AddIns/Analysis/UnitTesting/Model/TestMember.cs
  12. 4
      src/AddIns/Analysis/UnitTesting/Model/TestProject.cs
  13. 9
      src/AddIns/Analysis/UnitTesting/NUnit/NUnitTestFramework.cs
  14. 2
      src/AddIns/Analysis/UnitTesting/Nodes/ClassUnitTestNode.cs
  15. 1
      src/AddIns/Analysis/UnitTesting/Nodes/MemberUnitTestNode.cs
  16. 19
      src/AddIns/Analysis/UnitTesting/Nodes/NamespaceUnitTestNode.cs
  17. 4
      src/AddIns/Analysis/UnitTesting/Nodes/ProjectUnitTestNode.cs
  18. 9
      src/AddIns/Analysis/UnitTesting/Service/RegisteredTestFrameworks.cs
  19. 24
      src/AddIns/Analysis/UnitTesting/Service/TestResult.cs
  20. 5
      src/AddIns/Analysis/UnitTesting/Service/TestService.cs
  21. 4
      src/AddIns/Analysis/UnitTesting/Service/TestableCondition.cs
  22. 341
      src/AddIns/Analysis/UnitTesting/TestTreeView.cs
  23. 2
      src/AddIns/Analysis/UnitTesting/UnitTesting.csproj

2
SharpDevelop.sln

@ -1,7 +1,7 @@
 
Microsoft Visual Studio Solution File, Format Version 11.00 Microsoft Visual Studio Solution File, Format Version 11.00
# Visual Studio 2010 # Visual Studio 2010
# SharpDevelop 4.2.0.8774-RC # SharpDevelop 4.2.0.8783
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Main", "Main", "{256F5C28-532C-44C0-8AB8-D8EC5E492E01}" Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Main", "Main", "{256F5C28-532C-44C0-8AB8-D8EC5E492E01}"
ProjectSection(SolutionItems) = postProject ProjectSection(SolutionItems) = postProject
EndProjectSection EndProjectSection

0
src/AddIns/Analysis/UnitTesting/RunProjectTestsInPadCommand.cs → src/AddIns/Analysis/UnitTesting/Commands/RunProjectTestsInPadCommand.cs

2
src/AddIns/Analysis/UnitTesting/Commands/RunTestCommands.cs

@ -527,7 +527,7 @@ namespace ICSharpCode.UnitTesting
base.Run(); base.Run();
} }
public IMethod SelectedMethod { public TestMember SelectedMethod {
get { return null; } get { return null; }
} }

51
src/AddIns/Analysis/UnitTesting/UnitTestCommands.cs → src/AddIns/Analysis/UnitTesting/Commands/UnitTestCommands.cs

@ -7,6 +7,7 @@ using ICSharpCode.NRefactory.TypeSystem;
using ICSharpCode.SharpDevelop; using ICSharpCode.SharpDevelop;
using ICSharpCode.SharpDevelop.Gui; using ICSharpCode.SharpDevelop.Gui;
using ICSharpCode.SharpDevelop.Project; using ICSharpCode.SharpDevelop.Project;
using ICSharpCode.TreeView;
namespace ICSharpCode.UnitTesting namespace ICSharpCode.UnitTesting
{ {
@ -40,14 +41,14 @@ namespace ICSharpCode.UnitTesting
public class GotoDefinitionCommand : AbstractMenuCommand public class GotoDefinitionCommand : AbstractMenuCommand
{ {
IUnitTestFileService fileService; IFileService fileService;
public GotoDefinitionCommand() public GotoDefinitionCommand()
: this(new UnitTestFileService()) : this(SD.FileService)
{ {
} }
public GotoDefinitionCommand(IUnitTestFileService fileService) public GotoDefinitionCommand(IFileService fileService)
{ {
this.fileService = fileService; this.fileService = fileService;
} }
@ -56,46 +57,32 @@ namespace ICSharpCode.UnitTesting
{ {
ITestTreeView treeView = Owner as ITestTreeView; ITestTreeView treeView = Owner as ITestTreeView;
if (treeView != null) { if (treeView != null) {
IMember member = GetMember(treeView); IMethod method = treeView.SelectedMethod.Resolve();
IClass c = treeView.SelectedClass; ITypeDefinition c = treeView.SelectedClass;
if (member != null) { if (method != null) {
GotoMember(member); GotoMember(method);
} else if (c != null) { } else if (c != null) {
GotoClass(c); GotoClass(c);
} }
} }
} }
IMember GetMember(ITestTreeView treeView)
{
IMember member = treeView.SelectedMember;
if (member != null) {
BaseTestMember baseTestMethod = member as BaseTestMember;
if (baseTestMethod != null) {
return baseTestMethod.Member;
}
}
return member;
}
void GotoMember(IMember member) void GotoMember(IMember member)
{ {
MemberResolveResult resolveResult = new MemberResolveResult(null, null, member); GotoFilePosition(member.Region);
GotoFilePosition(resolveResult.GetDefinitionPosition());
} }
void GotoClass(IClass c) void GotoClass(ITypeDefinition c)
{ {
TypeResolveResult resolveResult = new TypeResolveResult(null, null, c); GotoFilePosition(c.Region);
GotoFilePosition(resolveResult.GetDefinitionPosition());
} }
void GotoFilePosition(DomRegion filePosition) void GotoFilePosition(DomRegion filePosition)
{ {
if (filePosition.Position.IsEmpty) { if (filePosition.IsEmpty) {
fileService.OpenFile(filePosition.FileName); fileService.OpenFile(new FileName(filePosition.FileName));
} else { } else {
fileService.JumpToFilePosition(filePosition.FileName, filePosition.Line - 1, filePosition.Column - 1); fileService.JumpToFilePosition(new FileName(filePosition.FileName), filePosition.BeginLine, filePosition.BeginColumn);
} }
} }
} }
@ -104,14 +91,14 @@ namespace ICSharpCode.UnitTesting
{ {
public override void Run() public override void Run()
{ {
if (!(this.Owner is TreeView)) if (!(this.Owner is SharpTreeView))
return; return;
var treeView = (TreeView)this.Owner; var treeView = (SharpTreeView)this.Owner;
treeView.CollapseAll(); NRefactory.Utils.TreeTraversal.PreOrder(treeView.Root, n => n.Children).ForEach(n => n.IsExpanded = false);
if (treeView.Nodes.Count > 0) { if (treeView.Root.Children.Count > 0) {
treeView.Nodes[0].Expand(); treeView.Root.IsExpanded = true;
} }
} }
} }

6
src/AddIns/Analysis/UnitTesting/Extensions.cs

@ -51,18 +51,18 @@ namespace ICSharpCode.UnitTesting
list.Insert(index, item); list.Insert(index, item);
} }
public static void UpdateTestClasses(this IList<TestClass> testClasses, IRegisteredTestFrameworks testFrameworks, IReadOnlyList<ITypeDefinition> oldTypes, IReadOnlyList<ITypeDefinition> newTypes, TestClass parent) public static void UpdateTestClasses(this IList<TestClass> testClasses, IRegisteredTestFrameworks testFrameworks, IReadOnlyList<ITypeDefinition> oldTypes, IReadOnlyList<ITypeDefinition> newTypes, TestClass parent, TestProject project)
{ {
var mappings = oldTypes.FullOuterJoin(newTypes, t => t.ReflectionName, t => t.ReflectionName, Tuple.Create); var mappings = oldTypes.FullOuterJoin(newTypes, t => t.ReflectionName, t => t.ReflectionName, Tuple.Create);
foreach (Tuple<ITypeDefinition, ITypeDefinition> mapping in mappings) { foreach (Tuple<ITypeDefinition, ITypeDefinition> mapping in mappings) {
if (mapping.Item2 == null) if (mapping.Item2 == null)
testClasses.RemoveWhere(c => c.FullName == mapping.Item1.ReflectionName); testClasses.RemoveWhere(c => c.FullName == mapping.Item1.ReflectionName);
else if (mapping.Item1 == null) else if (mapping.Item1 == null)
testClasses.Add(new TestClass(testFrameworks, mapping.Item2.ReflectionName, mapping.Item2, parent)); testClasses.Add(new TestClass(project, testFrameworks, mapping.Item2.ReflectionName, mapping.Item2, parent));
else { else {
var testClass = testClasses.SingleOrDefault(c => c.FullName == mapping.Item1.ReflectionName); var testClass = testClasses.SingleOrDefault(c => c.FullName == mapping.Item1.ReflectionName);
if (testClass == null) if (testClass == null)
testClasses.Add(new TestClass(testFrameworks, mapping.Item2.ReflectionName, mapping.Item2, parent)); testClasses.Add(new TestClass(project, testFrameworks, mapping.Item2.ReflectionName, mapping.Item2, parent));
else else
testClass.UpdateClass(mapping.Item2); testClass.UpdateClass(mapping.Item2);
} }

32
src/AddIns/Analysis/UnitTesting/Gui/UnitTestsPad.cs

@ -20,7 +20,7 @@ namespace ICSharpCode.UnitTesting
{ {
public class UnitTestsPad : AbstractPadContent public class UnitTestsPad : AbstractPadContent
{ {
SharpTreeView treeView; TestTreeView treeView;
bool disposed; bool disposed;
DockPanel panel; DockPanel panel;
ToolBar toolBar; ToolBar toolBar;
@ -42,9 +42,7 @@ namespace ICSharpCode.UnitTesting
panel.Children.Add(toolBar); panel.Children.Add(toolBar);
DockPanel.SetDock(toolBar, Dock.Top); DockPanel.SetDock(toolBar, Dock.Top);
treeView = new SharpTreeView(); treeView = new TestTreeView(testFrameworks);
treeView.MouseDoubleClick += TestTreeViewDoubleClick;
// treeView.KeyDown += TestTreeViewKeyPress;
panel.Children.Add(treeView); panel.Children.Add(treeView);
// Add the load solution projects thread ended handler before // Add the load solution projects thread ended handler before
@ -55,7 +53,6 @@ namespace ICSharpCode.UnitTesting
treeView.Root = new RootUnitTestNode(); treeView.Root = new RootUnitTestNode();
SD.ParserService.ParseInformationUpdated += ParseInformationUpdated;
ProjectService.SolutionClosed += SolutionClosed; ProjectService.SolutionClosed += SolutionClosed;
ProjectService.SolutionFolderRemoved += SolutionFolderRemoved; ProjectService.SolutionFolderRemoved += SolutionFolderRemoved;
ProjectService.ProjectAdded += ProjectAdded; ProjectService.ProjectAdded += ProjectAdded;
@ -83,7 +80,6 @@ namespace ICSharpCode.UnitTesting
ProjectService.ProjectAdded -= ProjectAdded; ProjectService.ProjectAdded -= ProjectAdded;
ProjectService.SolutionFolderRemoved -= SolutionFolderRemoved; ProjectService.SolutionFolderRemoved -= SolutionFolderRemoved;
ProjectService.SolutionClosed -= SolutionClosed; ProjectService.SolutionClosed -= SolutionClosed;
SD.ParserService.ParseInformationUpdated -= ParseInformationUpdated;
SD.ParserService.LoadSolutionProjectsThread.Finished -= LoadSolutionProjectsThreadFinished; SD.ParserService.LoadSolutionProjectsThread.Finished -= LoadSolutionProjectsThreadFinished;
} }
} }
@ -250,30 +246,6 @@ namespace ICSharpCode.UnitTesting
// WorkbenchSingleton.SafeThreadAsyncCall(SolutionLoaded, solution); // WorkbenchSingleton.SafeThreadAsyncCall(SolutionLoaded, solution);
} }
void ParseInformationUpdated(object source, ParseInformationEventArgs e)
{
lock (pending) {
var files = Tuple.Create(e.OldParsedFile, e.NewParsedFile);
pending.Add(files);
}
WorkbenchSingleton.SafeThreadAsyncCall(UpdateParseInfo);
}
void UpdateParseInfo()
{
lock (pending) {
foreach (var files in pending) {
UpdateParseInfo(files.Item1, files.Item2);
}
pending.Clear();
}
}
void TestTreeViewDoubleClick(object source, EventArgs e)
{
GotoDefinition();
}
// void TestTreeViewKeyPress(object source, KeyPressEventArgs e) // void TestTreeViewKeyPress(object source, KeyPressEventArgs e)
// { // {
// if (e.KeyChar == '\r') { // if (e.KeyChar == '\r') {

1
src/AddIns/Analysis/UnitTesting/Interfaces/IRegisteredTestFrameworks.cs

@ -15,6 +15,7 @@ namespace ICSharpCode.UnitTesting
ITestRunner CreateTestDebugger(IProject project); ITestRunner CreateTestDebugger(IProject project);
bool IsTestMethod(IMethod method, ICompilation compilation); bool IsTestMethod(IMethod method, ICompilation compilation);
bool IsTestCase(IMethod method, ICompilation compilation);
bool IsTestClass(ITypeDefinition typeDefinition, ICompilation compilation); bool IsTestClass(ITypeDefinition typeDefinition, ICompilation compilation);
bool IsTestProject(IProject project); bool IsTestProject(IProject project);

1
src/AddIns/Analysis/UnitTesting/Interfaces/ITestFramework.cs

@ -11,6 +11,7 @@ namespace ICSharpCode.UnitTesting
public interface ITestFramework public interface ITestFramework
{ {
bool IsTestMethod(IMethod method, ICompilation compilation); bool IsTestMethod(IMethod method, ICompilation compilation);
bool IsTestCase(IMethod method, ICompilation compilation);
bool IsTestClass(ITypeDefinition testClass, ICompilation compilation); bool IsTestClass(ITypeDefinition testClass, ICompilation compilation);
bool IsTestProject(IProject project); bool IsTestProject(IProject project);

2
src/AddIns/Analysis/UnitTesting/Interfaces/ITestTreeView.cs

@ -13,7 +13,7 @@ namespace ICSharpCode.UnitTesting
/// <summary> /// <summary>
/// Gets the selected member in the test tree view. /// Gets the selected member in the test tree view.
/// </summary> /// </summary>
IMethod SelectedMethod {get;} TestMember SelectedMethod {get;}
/// <summary> /// <summary>
/// Gets the selected class in the test tree view. /// Gets the selected class in the test tree view.

30
src/AddIns/Analysis/UnitTesting/Model/TestClass.cs

@ -26,19 +26,22 @@ namespace ICSharpCode.UnitTesting
readonly ObservableCollection<TestClass> nestedClasses; readonly ObservableCollection<TestClass> nestedClasses;
IRegisteredTestFrameworks testFrameworks; IRegisteredTestFrameworks testFrameworks;
public TestClass(IRegisteredTestFrameworks testFrameworks, string fullName, ITypeDefinition definition, TestClass parent = null) public TestClass(TestProject project, IRegisteredTestFrameworks testFrameworks, string fullName, ITypeDefinition definition, TestClass parent = null)
{ {
this.parts = new ObservableCollection<IUnresolvedTypeDefinition>(); this.parts = new ObservableCollection<IUnresolvedTypeDefinition>();
this.testMembers = new ObservableCollection<TestMember>(); this.testMembers = new ObservableCollection<TestMember>();
this.nestedClasses = new ObservableCollection<TestClass>(); this.nestedClasses = new ObservableCollection<TestClass>();
this.testFrameworks = testFrameworks; this.testFrameworks = testFrameworks;
this.fullName = fullName; this.fullName = fullName;
Project = project;
Parent = parent; Parent = parent;
UpdateClass(definition); UpdateClass(definition);
} }
public TestClass Parent { get; private set; } public TestClass Parent { get; private set; }
public TestProject Project { get; private set; }
/// <summary> /// <summary>
/// Gets the underlying IClass for this test class. /// Gets the underlying IClass for this test class.
/// </summary> /// </summary>
@ -126,7 +129,7 @@ namespace ICSharpCode.UnitTesting
{ {
foreach (var testClass in TreeTraversal.PostOrder(this, c => c.NestedClasses)) { foreach (var testClass in TreeTraversal.PostOrder(this, c => c.NestedClasses)) {
foreach (var member in testClass.Members) foreach (var member in testClass.Members)
member.TestResult = TestResultType.None; member.ResetTestResult();
testClass.TestResult = TestResultType.None; testClass.TestResult = TestResultType.None;
} }
var parent = this; var parent = this;
@ -156,10 +159,10 @@ namespace ICSharpCode.UnitTesting
parts.Add(part); parts.Add(part);
} }
testMembers.RemoveWhere(m => !definition.Methods.Any(dm => dm.ReflectionName == m.Method.ReflectionName && testFrameworks.IsTestMethod(dm, definition.Compilation))); testMembers.RemoveWhere(m => !definition.Methods.Any(dm => dm.ReflectionName == m.Method.ReflectionName && testFrameworks.IsTestMethod(dm, definition.Compilation)));
testMembers.AddRange(definition.Methods.Where(m => testFrameworks.IsTestMethod(m, definition.Compilation) && !testMembers.Any(dm => dm.Method.ReflectionName == m.ReflectionName)).Select(m => new TestMember((IUnresolvedMethod)m.UnresolvedMember))); testMembers.AddRange(definition.Methods.Where(m => testFrameworks.IsTestMethod(m, definition.Compilation) && !testMembers.Any(dm => dm.Method.ReflectionName == m.ReflectionName)).Select(m => new TestMember(Project, (IUnresolvedMethod)m.UnresolvedMember, testFrameworks.IsTestCase(m, definition.Compilation))));
var context = new SimpleTypeResolveContext(definition); var context = new SimpleTypeResolveContext(definition);
nestedClasses.UpdateTestClasses(testFrameworks, nestedClasses.Select(tc => new DefaultResolvedTypeDefinition(context, tc.Parts.ToArray())).ToList(), definition.NestedTypes.Where(nt => testFrameworks.IsTestClass(nt, definition.Compilation)).ToList(), this); nestedClasses.UpdateTestClasses(testFrameworks, nestedClasses.Select(tc => new DefaultResolvedTypeDefinition(context, tc.Parts.ToArray())).ToList(), definition.NestedTypes.Where(nt => testFrameworks.IsTestClass(nt, definition.Compilation)).ToList(), this, Project);
} }
/// <summary> /// <summary>
@ -174,28 +177,15 @@ namespace ICSharpCode.UnitTesting
return ns; return ns;
} }
/// <summary> public ITypeDefinition Resolve()
/// Gets the test members for the class.
/// </summary>
void GetTestMembers()
{ {
// testMembers = GetTestMembers(c); ICompilation compilation = SD.ParserService.GetCompilation(Project.Project);
// testMembers.ResultChanged += TestMembersResultChanged; return parts.First().Resolve(new SimpleTypeResolveContext(compilation.MainAssembly)).GetDefinition();
}
/// <summary>
/// Updates the test class's test result after the test member's
/// test result has changed.
/// </summary>
void TestMembersResultChanged(object source, EventArgs e)
{
// Result = testMembers.Result;
} }
public override string ToString() public override string ToString()
{ {
return string.Format("[TestClass TestResult={0}, FullName={1}]", testResult, fullName); return string.Format("[TestClass TestResult={0}, FullName={1}]", testResult, fullName);
} }
} }
} }

23
src/AddIns/Analysis/UnitTesting/Model/TestMember.cs

@ -3,6 +3,8 @@
using System; using System;
using ICSharpCode.NRefactory.TypeSystem; using ICSharpCode.NRefactory.TypeSystem;
using ICSharpCode.NRefactory.TypeSystem.Implementation;
using ICSharpCode.SharpDevelop;
using ICSharpCode.SharpDevelop.Widgets; using ICSharpCode.SharpDevelop.Widgets;
namespace ICSharpCode.UnitTesting namespace ICSharpCode.UnitTesting
@ -18,11 +20,17 @@ namespace ICSharpCode.UnitTesting
get { return method; } get { return method; }
} }
public TestMember(IUnresolvedMethod method) public TestProject Project { get; private set; }
public bool IsTestCase { get; private set; }
public TestMember(TestProject project, IUnresolvedMethod method, bool isTestCase)
{ {
if (method == null) if (method == null)
throw new ArgumentNullException("method"); throw new ArgumentNullException("method");
this.method = method; this.method = method;
this.Project = project;
this.IsTestCase = isTestCase;
} }
TestResultType testResult; TestResultType testResult;
@ -30,13 +38,24 @@ namespace ICSharpCode.UnitTesting
public TestResultType TestResult { public TestResultType TestResult {
get { return testResult; } get { return testResult; }
set { set {
if (testResult != value) { if (testResult < value) {
testResult = value; testResult = value;
OnPropertyChanged(); OnPropertyChanged();
} }
} }
} }
public void ResetTestResult()
{
testResult = TestResultType.None;
}
public IMethod Resolve()
{
ICompilation compilation = SD.ParserService.GetCompilation(Project.Project);
return method.Resolve(new SimpleTypeResolveContext(compilation.MainAssembly));
}
public override string ToString() public override string ToString()
{ {
return string.Format("[TestMember Method={0}, TestResult={1}]", method, testResult); return string.Format("[TestMember Method={0}, TestResult={1}]", method, testResult);

4
src/AddIns/Analysis/UnitTesting/Model/TestProject.cs

@ -37,7 +37,7 @@ namespace ICSharpCode.UnitTesting
.Resolve(compilation.TypeResolveContext) .Resolve(compilation.TypeResolveContext)
.TopLevelTypeDefinitions .TopLevelTypeDefinitions
.Where(td => testFrameworks.IsTestClass(td, compilation)) .Where(td => testFrameworks.IsTestClass(td, compilation))
.Select(g => new TestClass(testFrameworks, g.ReflectionName, g)); .Select(g => new TestClass(this, testFrameworks, g.ReflectionName, g));
testClasses = new ObservableCollection<TestClass>(classes); testClasses = new ObservableCollection<TestClass>(classes);
} }
@ -49,7 +49,7 @@ namespace ICSharpCode.UnitTesting
@new = e.NewParsedFile.TopLevelTypeDefinitions.Select(utd => utd.Resolve(context).GetDefinition()).Where(x => x != null && testFrameworks.IsTestClass(x, SD.ParserService.GetCompilation(project))); @new = e.NewParsedFile.TopLevelTypeDefinitions.Select(utd => utd.Resolve(context).GetDefinition()).Where(x => x != null && testFrameworks.IsTestClass(x, SD.ParserService.GetCompilation(project)));
else else
@new = Enumerable.Empty<ITypeDefinition>(); @new = Enumerable.Empty<ITypeDefinition>();
testClasses.UpdateTestClasses(testFrameworks, testClasses.Where(tc => tc.Parts.Any(td => td.ParsedFile.FileName == e.OldParsedFile.FileName)).Select(tc => new DefaultResolvedTypeDefinition(context, tc.Parts.ToArray())).ToList(), @new.ToList(), null); testClasses.UpdateTestClasses(testFrameworks, testClasses.Where(tc => tc.Parts.Any(td => td.ParsedFile.FileName == e.OldParsedFile.FileName)).Select(tc => new DefaultResolvedTypeDefinition(context, tc.Parts.ToArray())).ToList(), @new.ToList(), null, this);
} }
public IProject Project { public IProject Project {

9
src/AddIns/Analysis/UnitTesting/NUnit/NUnitTestFramework.cs

@ -50,8 +50,15 @@ namespace ICSharpCode.UnitTesting
if (method == null) if (method == null)
throw new ArgumentNullException("method"); throw new ArgumentNullException("method");
var testAttribute = NUnitTestFramework.testAttribute.Resolve(compilation.TypeResolveContext); var testAttribute = NUnitTestFramework.testAttribute.Resolve(compilation.TypeResolveContext);
return IsTestCase(method, compilation) || method.Attributes.Any(a => a.AttributeType.Equals(testAttribute));
}
public bool IsTestCase(IMethod method, ICompilation compilation)
{
if (method == null)
throw new ArgumentNullException("method");
var testCaseAttribute = NUnitTestFramework.testCaseAttribute.Resolve(compilation.TypeResolveContext); var testCaseAttribute = NUnitTestFramework.testCaseAttribute.Resolve(compilation.TypeResolveContext);
return method.Attributes.Any(a => a.AttributeType.Equals(testAttribute) || a.AttributeType.Equals(testCaseAttribute)); return method.Attributes.Any(a => a.AttributeType.Equals(testCaseAttribute));
} }
public bool IsTestClass(ITypeDefinition type, ICompilation compilation) public bool IsTestClass(ITypeDefinition type, ICompilation compilation)

2
src/AddIns/Analysis/UnitTesting/Nodes/ClassUnitTestNode.cs

@ -24,9 +24,11 @@ namespace ICSharpCode.UnitTesting
this.testClass.PropertyChanged += delegate(object sender, PropertyChangedEventArgs e) { this.testClass.PropertyChanged += delegate(object sender, PropertyChangedEventArgs e) {
if (e.PropertyName == "TestResult") { if (e.PropertyName == "TestResult") {
RaisePropertyChanged("Icon"); RaisePropertyChanged("Icon");
RaisePropertyChanged("ExpandedIcon");
var parentNode = Parent; var parentNode = Parent;
while (parentNode is NamespaceUnitTestNode) { while (parentNode is NamespaceUnitTestNode) {
parentNode.RaisePropertyChanged("Icon"); parentNode.RaisePropertyChanged("Icon");
parentNode.RaisePropertyChanged("ExpandedIcon");
parentNode = parentNode.Parent; parentNode = parentNode.Parent;
} }
} }

1
src/AddIns/Analysis/UnitTesting/Nodes/MemberUnitTestNode.cs

@ -24,6 +24,7 @@ namespace ICSharpCode.UnitTesting
this.testMember.PropertyChanged += delegate(object sender, PropertyChangedEventArgs e) { this.testMember.PropertyChanged += delegate(object sender, PropertyChangedEventArgs e) {
if (e.PropertyName == "TestResult") { if (e.PropertyName == "TestResult") {
RaisePropertyChanged("Icon"); RaisePropertyChanged("Icon");
RaisePropertyChanged("ExpandedIcon");
} }
}; };
} }

19
src/AddIns/Analysis/UnitTesting/Nodes/NamespaceUnitTestNode.cs

@ -24,6 +24,15 @@ namespace ICSharpCode.UnitTesting
get { return name; } get { return name; }
} }
public string FullNamespace {
get {
TestProject p = GetProject();
if (p != null)
return p.Project.RootNamespace + "." + name;
return name;
}
}
public NamespaceUnitTestNode(string name) public NamespaceUnitTestNode(string name)
{ {
if (string.IsNullOrEmpty(name)) if (string.IsNullOrEmpty(name))
@ -47,5 +56,15 @@ namespace ICSharpCode.UnitTesting
return TestResultType.Success; return TestResultType.Success;
} }
} }
public TestProject GetProject()
{
UnitTestBaseNode parent = this;
while (parent is NamespaceUnitTestNode)
parent = (UnitTestBaseNode)parent.Parent;
if (parent is ProjectUnitTestNode)
return ((ProjectUnitTestNode)parent).Project;
return null;
}
} }
} }

4
src/AddIns/Analysis/UnitTesting/Nodes/ProjectUnitTestNode.cs

@ -35,8 +35,10 @@ namespace ICSharpCode.UnitTesting
void ProjectPropertyChanged(object sender, PropertyChangedEventArgs e) void ProjectPropertyChanged(object sender, PropertyChangedEventArgs e)
{ {
if (e.PropertyName == "TestResult") if (e.PropertyName == "TestResult") {
RaisePropertyChanged("Icon"); RaisePropertyChanged("Icon");
RaisePropertyChanged("ExpandedIcon");
}
} }
void TestClassesCollectionChanged(object sender, NotifyCollectionChangedEventArgs e) void TestClassesCollectionChanged(object sender, NotifyCollectionChangedEventArgs e)

9
src/AddIns/Analysis/UnitTesting/Service/RegisteredTestFrameworks.cs

@ -40,6 +40,15 @@ namespace ICSharpCode.UnitTesting
return false; return false;
} }
public bool IsTestCase(IMethod method, ICompilation compilation)
{
ITestFramework testFramework = GetTestFramework(method, compilation);
if (testFramework != null) {
return testFramework.IsTestCase(method, compilation);
}
return false;
}
public IEnumerable<IMethod> GetTestMethodsFor(ITypeDefinition type, ICompilation compilation) public IEnumerable<IMethod> GetTestMethodsFor(ITypeDefinition type, ICompilation compilation)
{ {
ITestFramework testFramework = GetTestFramework(type, compilation); ITestFramework testFramework = GetTestFramework(type, compilation);

24
src/AddIns/Analysis/UnitTesting/Service/TestResult.cs

@ -20,12 +20,12 @@ namespace ICSharpCode.UnitTesting
/// <summary> /// <summary>
/// The test failed. /// The test failed.
/// </summary> /// </summary>
Failure = 2, Failure = 3,
/// <summary> /// <summary>
/// The test was ignored. /// The test was ignored.
/// </summary> /// </summary>
Ignored = 3 Ignored = 2
} }
/// <summary> /// <summary>
@ -33,15 +33,27 @@ namespace ICSharpCode.UnitTesting
/// </summary> /// </summary>
public class TestResult public class TestResult
{ {
string name = String.Empty; string name = string.Empty;
string message = String.Empty; string values = string.Empty;
string stackTrace = String.Empty; string message = string.Empty;
string stackTrace = string.Empty;
TestResultType resultType = TestResultType.None; TestResultType resultType = TestResultType.None;
DomRegion stackTraceFilePosition = DomRegion.Empty; DomRegion stackTraceFilePosition = DomRegion.Empty;
public TestResult(string name) public TestResult(string name)
{ {
this.name = name; this.name = ParseName(name, out values);
}
string ParseName(string name, out string values)
{
int i = name.IndexOf('(');
values = "";
if (i > -1) {
values = name.Substring(i);
return name.Substring(0, i);
} else
return name;
} }
public string Name { public string Name {

5
src/AddIns/Analysis/UnitTesting/Service/TestService.cs

@ -112,5 +112,10 @@ namespace ICSharpCode.UnitTesting
return Enumerable.Empty<TestProject>(); return Enumerable.Empty<TestProject>();
return ProjectService.OpenSolution.Projects.Where(p => RegisteredTestFrameworks.IsTestProject(p)).Select(p => new TestProject(p)); return ProjectService.OpenSolution.Projects.Where(p => RegisteredTestFrameworks.IsTestProject(p)).Select(p => new TestProject(p));
} }
public static TestProject GetTestProject(IProject currentProject)
{
return testableProjects.FirstOrDefault(p => p.Project == currentProject);
}
} }
} }

4
src/AddIns/Analysis/UnitTesting/Service/TestableCondition.cs

@ -31,8 +31,8 @@ namespace ICSharpCode.UnitTesting
public static IMethod GetMethod(object caller) public static IMethod GetMethod(object caller)
{ {
ITestTreeView testTreeView = caller as ITestTreeView; ITestTreeView testTreeView = caller as ITestTreeView;
if (testTreeView != null) { if (testTreeView != null && testTreeView.SelectedMethod != null) {
return testTreeView.SelectedMethod; return testTreeView.SelectedMethod.Resolve();
} }
// MemberNode memberNode = caller as MemberNode; // MemberNode memberNode = caller as MemberNode;
// if (memberNode != null) // if (memberNode != null)

341
src/AddIns/Analysis/UnitTesting/TestTreeView.cs

@ -3,19 +3,19 @@
using System; using System;
using System.Collections.Generic; using System.Collections.Generic;
using ICSharpCode.Core; using ICSharpCode.Core;
using ICSharpCode.NRefactory.TypeSystem;
using ICSharpCode.SharpDevelop; using ICSharpCode.SharpDevelop;
using ICSharpCode.SharpDevelop.Gui; using ICSharpCode.SharpDevelop.Gui;
using ICSharpCode.SharpDevelop.Project; using ICSharpCode.SharpDevelop.Project;
using ICSharpCode.TreeView;
namespace ICSharpCode.UnitTesting namespace ICSharpCode.UnitTesting
{ {
/// <summary> /// <summary>
/// Tree view that shows all the unit tests in a project. /// Tree view that shows all the unit tests in a project.
/// </summary> /// </summary>
public class TestTreeView : sharptr, ITestTreeView, IOwnerState public class TestTreeView : SharpTreeView, ITestTreeView, IOwnerState
{ {
/// <summary> /// <summary>
/// The current state of the tree view. /// The current state of the tree view.
@ -27,18 +27,16 @@ namespace ICSharpCode.UnitTesting
} }
/// <summary> /// <summary>
/// The All Tests tree root node that is added if multiple /// The All Tests tree root node that is added if multiple
/// test projects exist in the solution. If the solution contains /// test projects exist in the solution. If the solution contains
/// only one test project then no such node will be added. /// only one test project then no such node will be added.
/// </summary> /// </summary>
AllTestsTreeNode allTestsNode;
IRegisteredTestFrameworks testFrameworks; IRegisteredTestFrameworks testFrameworks;
public TestTreeView(IRegisteredTestFrameworks testFrameworks) public TestTreeView(IRegisteredTestFrameworks testFrameworks)
{ {
this.testFrameworks = testFrameworks; this.testFrameworks = testFrameworks;
ImageList = TestTreeViewImageList.ImageList; TestService.TestableProjects.CollectionChanged += delegate { ShowRoot = TestService.TestableProjects.Count > 1; };
CanClearSelection = false;
} }
/// <summary> /// <summary>
@ -46,154 +44,25 @@ namespace ICSharpCode.UnitTesting
/// </summary> /// </summary>
public Enum InternalState { public Enum InternalState {
get { get {
TestTreeNode selectedNode = SelectedNode as TestTreeNode; if (SelectedItem is ClassUnitTestNode || SelectedItem is MemberUnitTestNode)
if ((selectedNode is TestClassTreeNode) || (selectedNode is TestMemberTreeNode)) {
return TestTreeViewState.SourceCodeItemSelected; return TestTreeViewState.SourceCodeItemSelected;
}
return TestTreeViewState.None; return TestTreeViewState.None;
} }
} }
/// <summary>
/// Adds the solution's projects to the test tree view.
/// Only test projects are displayed.
/// </summary>
public void AddSolution(Solution solution)
{
Clear();
AddProjects(solution.Projects);
}
/// <summary>
/// Adds the projects to the test tree view. Only those projects
/// which are determined to have a reference to a supported
/// test framework will be added to the tree.
/// </summary>
public void AddProjects(IEnumerable<IProject> projects)
{
foreach (IProject project in projects) {
AddProject(project);
}
}
/// <summary>
/// Adds the project to the test tree view if the project
/// is a test project.
/// </summary>
/// <remarks>
/// If the project is already in the tree then it will
/// not be added again. If a project is already in the tree then
/// an All Tests root node will be added.
/// </remarks>
public void AddProject(IProject project)
{
if (IsTestProject(project)) {
if (GetProjectTreeNode(project) == null) {
AddProjectTreeNode(project);
}
}
}
bool IsTestProject(IProject project) bool IsTestProject(IProject project)
{ {
return testFrameworks.IsTestProject(project); return testFrameworks.IsTestProject(project);
} }
void AddProjectTreeNode(IProject project)
{
TestProjectTreeNode node = CreateProjectTreeNode(project);
if (node != null) {
AddProjectTreeNodeToTree(node);
SortNodes(Nodes, true);
}
}
TestProjectTreeNode CreateProjectTreeNode(IProject project)
{
IProjectContent projectContent = GetProjectContent(project);
if (projectContent != null) {
TestProject testProject = new TestProject(project, projectContent, testFrameworks);
return new TestProjectTreeNode(testProject);
}
return null;
}
void AddProjectTreeNodeToTree(TestProjectTreeNode node)
{
if (Nodes.Count == 0) {
node.AddTo(this);
} else {
AllTestsTreeNode allTestsNode = GetAllTestsNode();
allTestsNode.AddProjectNode(node);
}
}
public void RemoveSolutionFolder(ISolutionFolder solutionFolder)
{
IProject project = solutionFolder as IProject;
if (project != null) {
RemoveProject(project);
}
ISolutionFolderContainer solutionFolderContainer = solutionFolder as ISolutionFolderContainer;
if (solutionFolderContainer != null) {
foreach (ISolutionFolder subSolutionFolder in solutionFolderContainer.Folders) {
RemoveSolutionFolder(subSolutionFolder);
}
}
}
/// <summary>
/// Removes the specified project from the test tree view.
/// </summary>
public void RemoveProject(IProject project)
{
TestProjectTreeNode projectNode = GetProjectTreeNode(project);
RemoveProjectNode(projectNode);
RemoveAllTestsNodeIfOnlyOneProjectLeft();
}
void RemoveAllTestsNodeIfOnlyOneProjectLeft()
{
if (allTestsNode != null) {
if (GetProjectNodes().Count == 1) {
RemoveAllTestsNode();
}
}
}
/// <summary>
/// Gets the projects displayed in the tree.
/// </summary>
public IProject[] GetProjects()
{
List<IProject> projects = new List<IProject>();
foreach (TestProjectTreeNode projectNode in GetProjectNodes()) {
projects.Add(projectNode.Project);
}
return projects.ToArray();
}
/// <summary>
/// Returns the TestProject associated with the specified project.
/// </summary>
public TestProject GetTestProject(IProject project)
{
TestProjectTreeNode node = GetProjectTreeNode(project);
if (node != null) {
return node.TestProject;
}
return null;
}
/// <summary> /// <summary>
/// Gets the member of the currently selected tree node. /// Gets the member of the currently selected tree node.
/// </summary> /// </summary>
public IMember SelectedMember { public TestMember SelectedMethod {
get { get {
TestMemberTreeNode memberNode = SelectedNode as TestMemberTreeNode; MemberUnitTestNode memberNode = SelectedItem as MemberUnitTestNode;
if (memberNode != null) { if (memberNode != null) {
return memberNode.Member; return memberNode.TestMember;
} }
return null; return null;
} }
@ -202,25 +71,25 @@ namespace ICSharpCode.UnitTesting
/// <summary> /// <summary>
/// Gets the class of the currently selected tree node. /// Gets the class of the currently selected tree node.
/// </summary> /// </summary>
public IClass SelectedClass { public ITypeDefinition SelectedClass {
get { get {
TestClassTreeNode classNode = SelectedNode as TestClassTreeNode; ClassUnitTestNode classNode = SelectedItem as ClassUnitTestNode;
if (classNode == null) { if (classNode == null) {
classNode = GetClassNodeFromSelectedMemberNode(); classNode = GetClassNodeFromSelectedMemberNode();
} }
if (classNode != null) { if (classNode != null) {
return classNode.Class; return classNode.TestClass.Resolve();
} }
return null; return null;
} }
} }
TestClassTreeNode GetClassNodeFromSelectedMemberNode() ClassUnitTestNode GetClassNodeFromSelectedMemberNode()
{ {
TestMemberTreeNode memberNode = SelectedNode as TestMemberTreeNode; MemberUnitTestNode memberNode = SelectedItem as MemberUnitTestNode;
if (memberNode != null) { if (memberNode != null) {
return memberNode.Parent as TestClassTreeNode; return memberNode.Parent as ClassUnitTestNode;
} }
return null; return null;
} }
@ -240,13 +109,13 @@ namespace ICSharpCode.UnitTesting
} }
/// <summary> /// <summary>
/// If a namespace node is selected then the fully qualified namespace /// If a namespace node is selected then the fully qualified namespace
/// for this node is returned (i.e. includes the parent namespace prefixed /// for this node is returned (i.e. includes the parent namespace prefixed
/// to it). For all other nodes this returns null. /// to it). For all other nodes this returns null.
/// </summary> /// </summary>
public string SelectedNamespace { public string SelectedNamespace {
get { get {
TestNamespaceTreeNode selectedNode = SelectedNode as TestNamespaceTreeNode; NamespaceUnitTestNode selectedNode = SelectedItem as NamespaceUnitTestNode;
if (selectedNode != null) { if (selectedNode != null) {
return selectedNode.FullNamespace; return selectedNode.FullNamespace;
} }
@ -259,176 +128,16 @@ namespace ICSharpCode.UnitTesting
/// </summary> /// </summary>
public TestProject SelectedTestProject { public TestProject SelectedTestProject {
get { get {
TestTreeNode selectedNode = SelectedNode as TestTreeNode; if (SelectedItem is MemberUnitTestNode)
if (selectedNode != null) { return ((MemberUnitTestNode)SelectedItem).TestMember.Project;
return selectedNode.TestProject; if (SelectedItem is ClassUnitTestNode)
} return ((ClassUnitTestNode)SelectedItem).TestClass.Project;
if (SelectedItem is NamespaceUnitTestNode)
return ((NamespaceUnitTestNode)SelectedItem).GetProject();
if (SelectedItem is ProjectUnitTestNode)
return ((ProjectUnitTestNode)SelectedItem).Project;
return null; return null;
} }
} }
/// <summary>
/// Updates the classes and members in the test tree view based on the
/// parse information.
/// </summary>
public void UpdateParseInfo(ICompilationUnit oldUnit, ICompilationUnit newUnit)
{
foreach (TestProjectTreeNode projectNode in GetProjectNodes()) {
TestProject testProject = projectNode.TestProject;
testProject.UpdateParseInfo(oldUnit, newUnit);
}
}
/// <summary>
/// Resets the test results for all the projects in the
/// test tree view.
/// </summary>
public void ResetTestResults()
{
foreach (TestProjectTreeNode projectNode in GetProjectNodes()) {
TestProject testProject = projectNode.TestProject;
testProject.ResetTestResults();
}
}
/// <summary>
/// Returns the project content for the specified project.
/// </summary>
public virtual IProjectContent GetProjectContent(IProject project)
{
return ParserService.GetProjectContent(project);
}
/// <summary>
/// A tree node has been selected. Here we make sure the tree node
/// uses the context menu strip that the tree view is using. This
/// ensures that if the user brings up the context menu using a keyboard
/// shortcut (Shift+F10) then it appears over the node rather than in
/// the middle of the Unit Tests window.
/// </summary>
protected override void OnBeforeSelect(TreeViewCancelEventArgs e)
{
TreeNode node = e.Node;
if (node.ContextMenuStrip == null) {
node.ContextMenuStrip = ContextMenuStrip;
}
}
/// <summary>
/// Returns the project tree node that is associated with the
/// specified project.
/// </summary>
TestProjectTreeNode GetProjectTreeNode(IProject project)
{
foreach (TestProjectTreeNode projectNode in GetProjectNodes()) {
if (Object.ReferenceEquals(projectNode.Project, project)) {
return projectNode;
}
}
return null;
}
/// <summary>
/// Returns the test project tree nodes taking into account
/// if the All Tests root node exists.
/// </summary>
TreeNodeCollection GetProjectNodes()
{
if (allTestsNode != null) {
return allTestsNode.Nodes;
}
return Nodes;
}
/// <summary>
/// Removes the project node from the tree.
/// </summary>
void RemoveProjectNode(TestProjectTreeNode projectNode)
{
if (projectNode != null) {
if (allTestsNode != null) {
allTestsNode.RemoveProjectNode(projectNode);
} else {
projectNode.Remove();
}
}
}
/// <summary>
/// Gets the All Tests root node which is added if the tree is
/// showing multiple test projects. The All Tests root node will
/// be added if it does not exist.
/// </summary>
AllTestsTreeNode GetAllTestsNode()
{
if (allTestsNode == null) {
AddAllTestsNode();
}
return allTestsNode;
}
/// <summary>
/// Adds a new All Tests root node.
/// </summary>
void AddAllTestsNode()
{
// Save existing nodes (should only be one) before
// clearing so we can add these to the new All Tests node.
TreeNode[] projectNodes = new TreeNode[Nodes.Count];
Nodes.CopyTo(projectNodes, 0);
Nodes.Clear();
allTestsNode = new AllTestsTreeNode();
allTestsNode.Disposed += AllTestsNodeDisposed;
Nodes.Add(allTestsNode);
// Add the original project nodes to the new
// All Tests node.
foreach (TestProjectTreeNode node in projectNodes) {
allTestsNode.AddProjectNode(node);
}
}
/// <summary>
/// Removes the all tests node.
/// </summary>
void RemoveAllTestsNode()
{
allTestsNode.Remove();
// Copy project nodes to the root.
foreach (TestTreeNode node in allTestsNode.Nodes) {
Nodes.Add(node);
}
AllTestsNodeDisposed(null, null);
}
/// <summary>
/// Ensures that if the TreeView's Clear member is called
/// directly the test tree does not think there is still
/// an All Tests node.
/// </summary>
void AllTestsNodeDisposed(object source, EventArgs e)
{
allTestsNode.Disposed -= AllTestsNodeDisposed;
allTestsNode = null;
}
/// <summary>
/// Adds the test project to the test tree view if it is now recognised as a
/// test project and is not already in the test tree.
/// </summary>
public void ProjectItemAdded(ProjectItem projectItem)
{
AddProject(projectItem.Project);
}
public void ProjectItemRemoved(ProjectItem projectItem)
{
if (!testFrameworks.IsTestProject(projectItem.Project)) {
RemoveProject(projectItem.Project);
}
}
} }
} }

2
src/AddIns/Analysis/UnitTesting/UnitTesting.csproj

@ -71,6 +71,7 @@
</ItemGroup> </ItemGroup>
<ItemGroup> <ItemGroup>
<Compile Include="Commands\RunTestCommands.cs" /> <Compile Include="Commands\RunTestCommands.cs" />
<Compile Include="Commands\UnitTestCommands.cs" />
<Compile Include="Extensions.cs" /> <Compile Include="Extensions.cs" />
<Compile Include="Gui\EmptyUnitTestsPad.cs" /> <Compile Include="Gui\EmptyUnitTestsPad.cs" />
<Compile Include="Gui\UnitTestingOptionsPanel.xaml.cs"> <Compile Include="Gui\UnitTestingOptionsPanel.xaml.cs">
@ -138,6 +139,7 @@
<Compile Include="TestResultsMonitor.cs" /> <Compile Include="TestResultsMonitor.cs" />
<Compile Include="TestResultsReader.cs" /> <Compile Include="TestResultsReader.cs" />
<Compile Include="TestResultTask.cs" /> <Compile Include="TestResultTask.cs" />
<Compile Include="TestTreeView.cs" />
<Compile Include="UnitTestApplicationStartHelper.cs" /> <Compile Include="UnitTestApplicationStartHelper.cs" />
<Compile Include="UnitTestingOptions.cs" /> <Compile Include="UnitTestingOptions.cs" />
<Compile Include="UnitTestProcessRunner.cs" /> <Compile Include="UnitTestProcessRunner.cs" />

Loading…
Cancel
Save