20 changed files with 373 additions and 934 deletions
@ -1,198 +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.Collections.ObjectModel; |
|
||||||
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.Widgets; |
|
||||||
|
|
||||||
namespace ICSharpCode.UnitTesting |
|
||||||
{ |
|
||||||
/// <summary>
|
|
||||||
/// Represents a class that can be tested.
|
|
||||||
/// </summary>
|
|
||||||
public class TestClass |
|
||||||
{ |
|
||||||
readonly ITestFramework testFramework; |
|
||||||
readonly ObservableCollection<TestMember> testMembers; |
|
||||||
readonly ObservableCollection<TestClass> nestedClasses; |
|
||||||
IList<IUnresolvedTypeDefinition> parts; |
|
||||||
|
|
||||||
public TestClass(ITypeDefinition definition, ITestFramework testFramework) |
|
||||||
{ |
|
||||||
if (definition == null) |
|
||||||
throw new ArgumentNullException("definition"); |
|
||||||
if (testFramework == null) |
|
||||||
throw new ArgumentNullException("testFramework"); |
|
||||||
this.testFramework = testFramework; |
|
||||||
this.parts = new ObservableCollection<IUnresolvedTypeDefinition>(); |
|
||||||
this.testMembers = new ObservableCollection<TestMember>(); |
|
||||||
this.nestedClasses = new ObservableCollection<TestClass>(); |
|
||||||
UpdateClass(definition); |
|
||||||
} |
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Gets the underlying IUnresolvedTypeDefinitions for this test class.
|
|
||||||
/// </summary>
|
|
||||||
public IList<IUnresolvedTypeDefinition> Parts { |
|
||||||
get { return parts; } |
|
||||||
} |
|
||||||
|
|
||||||
public ObservableCollection<TestMember> Members { |
|
||||||
get { return testMembers; } |
|
||||||
} |
|
||||||
|
|
||||||
public ObservableCollection<TestClass> NestedClasses { |
|
||||||
get { return nestedClasses; } |
|
||||||
} |
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Gets the name of the class.
|
|
||||||
/// </summary>
|
|
||||||
public string Name { |
|
||||||
get { return parts[0].Name; } |
|
||||||
} |
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Gets the fully qualified name of the class.
|
|
||||||
/// </summary>
|
|
||||||
public string QualifiedName { |
|
||||||
get { return parts[0].ReflectionName; } |
|
||||||
} |
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Gets the namespace of this class.
|
|
||||||
/// </summary>
|
|
||||||
public string Namespace { |
|
||||||
get { return parts[0].Namespace; } |
|
||||||
} |
|
||||||
|
|
||||||
TestResultType testResult; |
|
||||||
|
|
||||||
public event EventHandler TestResultChanged; |
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Gets the test result for this class.
|
|
||||||
/// </summary>
|
|
||||||
public TestResultType TestResult { |
|
||||||
get { return testResult; } |
|
||||||
set { |
|
||||||
if (testResult != value) { |
|
||||||
testResult = value; |
|
||||||
if (TestResultChanged != null) |
|
||||||
TestResultChanged(this, EventArgs.Empty); |
|
||||||
} |
|
||||||
} |
|
||||||
} |
|
||||||
|
|
||||||
static TestResultType GetTestResult(TestClass testClass) |
|
||||||
{ |
|
||||||
if (testClass.nestedClasses.Count == 0 && testClass.testMembers.Count == 0) |
|
||||||
return TestResultType.None; |
|
||||||
if (testClass.nestedClasses.Any(c => c.TestResult == TestResultType.Failure) |
|
||||||
|| testClass.testMembers.Any(m => m.TestResult == TestResultType.Failure)) |
|
||||||
return TestResultType.Failure; |
|
||||||
if (testClass.nestedClasses.Any(c => c.TestResult == TestResultType.None) |
|
||||||
|| testClass.testMembers.Any(m => m.TestResult == TestResultType.None)) |
|
||||||
return TestResultType.None; |
|
||||||
if (testClass.nestedClasses.Any(c => c.TestResult == TestResultType.Ignored) |
|
||||||
|| testClass.testMembers.Any(m => m.TestResult == TestResultType.Ignored)) |
|
||||||
return TestResultType.Ignored; |
|
||||||
return TestResultType.Success; |
|
||||||
} |
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Updates the test member with the specified test result.
|
|
||||||
/// </summary>
|
|
||||||
public void UpdateTestResult(TestResult testResult) |
|
||||||
{ |
|
||||||
var member = testMembers.SingleOrDefault(m => m.Member.ReflectionName == testResult.Name); |
|
||||||
member.TestResult = testResult.ResultType; |
|
||||||
this.TestResult = GetTestResult(this); |
|
||||||
} |
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Resets all the test results back to none.
|
|
||||||
/// </summary>
|
|
||||||
public void ResetTestResults() |
|
||||||
{ |
|
||||||
foreach (var testClass in this.NestedClasses) { |
|
||||||
testClass.ResetTestResults(); |
|
||||||
} |
|
||||||
foreach (var member in this.Members) { |
|
||||||
member.ResetTestResults(); |
|
||||||
} |
|
||||||
} |
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Updates the members and class based on the new class
|
|
||||||
/// information that has been parsed.
|
|
||||||
/// </summary>
|
|
||||||
public void UpdateClass(ITypeDefinition typeDefinition) |
|
||||||
{ |
|
||||||
this.parts = typeDefinition.Parts; |
|
||||||
|
|
||||||
testMembers.Clear(); |
|
||||||
testMembers.AddRange(testFramework.GetTestMembersFor(typeDefinition)); |
|
||||||
|
|
||||||
|
|
||||||
/*var oldParts = this.parts; |
|
||||||
nestedClasses.UpdateTestClasses(testFrameworks, |
|
||||||
|
|
||||||
int i = 0; |
|
||||||
while (i < parts.Count) { |
|
||||||
var part = parts[i]; |
|
||||||
if (!definition.Parts.Any(p => p.UnresolvedFile.FileName == part.UnresolvedFile.FileName && p.Region == part.Region)) |
|
||||||
parts.RemoveAt(i); |
|
||||||
else |
|
||||||
i++; |
|
||||||
} |
|
||||||
|
|
||||||
foreach (var part in definition.Parts) { |
|
||||||
if (!parts.Any(p => p.UnresolvedFile.FileName == part.UnresolvedFile.FileName && p.Region == part.Region)) |
|
||||||
parts.Add(part); |
|
||||||
} |
|
||||||
testMembers.RemoveWhere(m => !definition.Methods.Any(dm => dm.ReflectionName == m.Member.ReflectionName && testFrameworks.IsTestMethod(dm))); |
|
||||||
testMembers.AddRange( |
|
||||||
definition.Methods.Where(m => testFrameworks.IsTestMethod(m, definition.Compilation) |
|
||||||
&& !testMembers.Any(dm => dm.Member.ReflectionName == m.ReflectionName)) |
|
||||||
.Select(m => new TestMember(Project, (IUnresolvedMethod)m.UnresolvedMember, testFrameworks.IsTestCase(m, definition.Compilation)))); |
|
||||||
|
|
||||||
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, Project); |
|
||||||
*/ |
|
||||||
} |
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Gets the first dotted part of the namespace.
|
|
||||||
/// </summary>
|
|
||||||
static string GetRootNamespace(string ns) |
|
||||||
{ |
|
||||||
int index = ns.IndexOf('.'); |
|
||||||
if (index > 0) { |
|
||||||
return ns.Substring(0, index); |
|
||||||
} |
|
||||||
return ns; |
|
||||||
} |
|
||||||
|
|
||||||
public ITypeDefinition Resolve(TestProject project) |
|
||||||
{ |
|
||||||
if (project == null) |
|
||||||
return null; |
|
||||||
ICompilation compilation = SD.ParserService.GetCompilation(project.Project); |
|
||||||
return parts[0].Resolve(new SimpleTypeResolveContext(compilation.MainAssembly)).GetDefinition(); |
|
||||||
} |
|
||||||
|
|
||||||
public override string ToString() |
|
||||||
{ |
|
||||||
return string.Format("[TestClass TestResult={0}, Name={1}]", testResult, this.QualifiedName); |
|
||||||
} |
|
||||||
} |
|
||||||
} |
|
@ -1,67 +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.NRefactory.TypeSystem; |
|
||||||
using ICSharpCode.NRefactory.TypeSystem.Implementation; |
|
||||||
using ICSharpCode.SharpDevelop; |
|
||||||
using ICSharpCode.SharpDevelop.Widgets; |
|
||||||
|
|
||||||
namespace ICSharpCode.UnitTesting |
|
||||||
{ |
|
||||||
/// <summary>
|
|
||||||
/// Represents a member that can be tested.
|
|
||||||
/// </summary>
|
|
||||||
public class TestMember |
|
||||||
{ |
|
||||||
readonly IUnresolvedMember member; |
|
||||||
|
|
||||||
public IUnresolvedMember Member { |
|
||||||
get { return member; } |
|
||||||
} |
|
||||||
|
|
||||||
public TestMember(IUnresolvedMember member) |
|
||||||
{ |
|
||||||
if (member == null) |
|
||||||
throw new ArgumentNullException("member"); |
|
||||||
this.member = member; |
|
||||||
} |
|
||||||
|
|
||||||
public string Name { |
|
||||||
get { return member.Name; } |
|
||||||
} |
|
||||||
|
|
||||||
public event EventHandler TestResultChanged; |
|
||||||
|
|
||||||
TestResultType testResult; |
|
||||||
|
|
||||||
public TestResultType TestResult { |
|
||||||
get { return testResult; } |
|
||||||
set { |
|
||||||
if (testResult != value) { |
|
||||||
testResult = value; |
|
||||||
if (TestResultChanged != null) |
|
||||||
TestResultChanged(this, EventArgs.Empty); |
|
||||||
} |
|
||||||
} |
|
||||||
} |
|
||||||
|
|
||||||
public virtual void ResetTestResults() |
|
||||||
{ |
|
||||||
testResult = TestResultType.None; |
|
||||||
} |
|
||||||
|
|
||||||
public IMember Resolve(TestProject project) |
|
||||||
{ |
|
||||||
if (project == null) |
|
||||||
return null; |
|
||||||
ICompilation compilation = SD.ParserService.GetCompilation(project.Project); |
|
||||||
return member.Resolve(new SimpleTypeResolveContext(compilation.MainAssembly)); |
|
||||||
} |
|
||||||
|
|
||||||
public override string ToString() |
|
||||||
{ |
|
||||||
return string.Format("[TestMember Method={0}, TestResult={1}]", member, testResult); |
|
||||||
} |
|
||||||
} |
|
||||||
} |
|
@ -1,196 +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.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; |
|
||||||
using ICSharpCode.SharpDevelop.Widgets; |
|
||||||
|
|
||||||
namespace ICSharpCode.UnitTesting |
|
||||||
{ |
|
||||||
/// <summary>
|
|
||||||
/// Represents a project that has a reference to a unit testing
|
|
||||||
/// framework assembly. Currently only NUnit is supported.
|
|
||||||
/// </summary>
|
|
||||||
public class TestProject : ViewModelBase |
|
||||||
{ |
|
||||||
readonly IProject project; |
|
||||||
readonly ITestFramework testFramework; |
|
||||||
readonly ObservableCollection<TestClass> testClasses; |
|
||||||
|
|
||||||
public TestProject(IProject project, ITestFramework testFramework) |
|
||||||
{ |
|
||||||
this.testFramework = testFramework; |
|
||||||
this.project = project; |
|
||||||
var compilation = SD.ParserService.GetCompilation(project); |
|
||||||
testClasses = new ObservableCollection<TestClass>( |
|
||||||
from td in compilation.MainAssembly.TopLevelTypeDefinitions |
|
||||||
where this.testFramework.IsTestClass(td) |
|
||||||
select new TestClass(td, this.testFramework) |
|
||||||
); |
|
||||||
} |
|
||||||
|
|
||||||
HashSet<FullNameAndTypeParameterCount> dirtyTypeDefinitions = new HashSet<FullNameAndTypeParameterCount>(); |
|
||||||
|
|
||||||
public void NotifyParseInformationChanged(IUnresolvedFile oldUnresolvedFile, IUnresolvedFile newUnresolvedFile) |
|
||||||
{ |
|
||||||
AddToDirtyList(oldUnresolvedFile); |
|
||||||
AddToDirtyList(newUnresolvedFile); |
|
||||||
ProcessUpdates(); |
|
||||||
} |
|
||||||
|
|
||||||
void AddToDirtyList(IUnresolvedFile unresolvedFile) |
|
||||||
{ |
|
||||||
if (unresolvedFile != null) { |
|
||||||
foreach (var td in unresolvedFile.TopLevelTypeDefinitions) { |
|
||||||
dirtyTypeDefinitions.Add(new FullNameAndTypeParameterCount(td.Namespace, td.Name, td.TypeParameters.Count)); |
|
||||||
} |
|
||||||
} |
|
||||||
} |
|
||||||
|
|
||||||
void ProcessUpdates() |
|
||||||
{ |
|
||||||
var compilation = SD.ParserService.GetCompilation(project); |
|
||||||
var context = new SimpleTypeResolveContext(compilation.MainAssembly); |
|
||||||
|
|
||||||
var testClassNameToIndex = new Dictionary<FullNameAndTypeParameterCount, int>(); |
|
||||||
for (int i = 0; i < testClasses.Count; i++) { |
|
||||||
var primaryPart = testClasses[i].Parts[0]; |
|
||||||
testClassNameToIndex[new FullNameAndTypeParameterCount(primaryPart.Namespace, primaryPart.Name, primaryPart.TypeParameters.Count)] = i; |
|
||||||
} |
|
||||||
|
|
||||||
List<int> testClassesToRemove = new List<int>(); |
|
||||||
foreach (var dirtyTypeDef in dirtyTypeDefinitions) { |
|
||||||
ITypeDefinition typeDef = compilation.MainAssembly.GetTypeDefinition(dirtyTypeDef.Namespace, dirtyTypeDef.Name, dirtyTypeDef.TypeParameterCount); |
|
||||||
int pos; |
|
||||||
if (testClassNameToIndex.TryGetValue(dirtyTypeDef, out pos)) { |
|
||||||
if (typeDef == null) { |
|
||||||
// Test class was removed completely (no parts left)
|
|
||||||
|
|
||||||
// Removing the class messes up the indices stored in the dictionary,
|
|
||||||
// so we'll just remember that we need to remove the class
|
|
||||||
testClassesToRemove.Add(pos); |
|
||||||
} else { |
|
||||||
// Test class was modified
|
|
||||||
// Check if it's still a test class:
|
|
||||||
if (testFramework.IsTestClass(typeDef)) |
|
||||||
testClasses[pos].UpdateClass(typeDef); |
|
||||||
else |
|
||||||
testClassesToRemove.Add(pos); |
|
||||||
} |
|
||||||
} else if (typeDef != null && testFramework.IsTestClass(typeDef)) { |
|
||||||
// Test class was added
|
|
||||||
testClasses.Add(new TestClass(typeDef, testFramework)); |
|
||||||
} |
|
||||||
} |
|
||||||
dirtyTypeDefinitions.Clear(); |
|
||||||
// Now remove the outdated test classes
|
|
||||||
testClassesToRemove.Sort(); |
|
||||||
foreach (int index in testClassesToRemove) { |
|
||||||
testClasses.RemoveAt(index); |
|
||||||
} |
|
||||||
} |
|
||||||
|
|
||||||
public ITestFramework TestFramework { |
|
||||||
get { return testFramework; } |
|
||||||
} |
|
||||||
|
|
||||||
public IProject Project { |
|
||||||
get { return project; } |
|
||||||
} |
|
||||||
|
|
||||||
public ObservableCollection<TestClass> TestClasses { |
|
||||||
get { return testClasses; } |
|
||||||
} |
|
||||||
|
|
||||||
public TestMember GetTestMember(IMember member) |
|
||||||
{ |
|
||||||
if (member != null) |
|
||||||
return GetTestMember(member.ReflectionName); |
|
||||||
else |
|
||||||
return null; |
|
||||||
} |
|
||||||
|
|
||||||
public TestMember GetTestMember(string reflectionName) |
|
||||||
{ |
|
||||||
return TreeTraversal.PostOrder(testClasses, c => c.NestedClasses) |
|
||||||
.SelectMany(c => c.Members) |
|
||||||
.FirstOrDefault(m => reflectionName.Equals(m.Member.ReflectionName, StringComparison.Ordinal)); |
|
||||||
} |
|
||||||
|
|
||||||
public TestClass GetTestClass(ITypeDefinition typeDefinition) |
|
||||||
{ |
|
||||||
if (typeDefinition != null) |
|
||||||
return GetTestClass(typeDefinition.ReflectionName); |
|
||||||
else |
|
||||||
return null; |
|
||||||
} |
|
||||||
|
|
||||||
public TestClass GetTestClass(string reflectionName) |
|
||||||
{ |
|
||||||
int pos = reflectionName.LastIndexOf('+'); |
|
||||||
if (pos < 0) { |
|
||||||
// top-level class
|
|
||||||
foreach (var tc in testClasses) { |
|
||||||
if (tc.QualifiedName == reflectionName) |
|
||||||
return tc; |
|
||||||
} |
|
||||||
} else { |
|
||||||
// nested class
|
|
||||||
TestClass declaringClass = GetTestClass(reflectionName.Substring(0, pos)); |
|
||||||
if (declaringClass != null) { |
|
||||||
return declaringClass.NestedClasses.FirstOrDefault(t => t.QualifiedName == reflectionName); |
|
||||||
} |
|
||||||
} |
|
||||||
return null; |
|
||||||
} |
|
||||||
|
|
||||||
public void UpdateTestResult(TestResult result) |
|
||||||
{ |
|
||||||
TestClass testClass = GetTestClass(result.Name); |
|
||||||
if (testClass != null) { |
|
||||||
testClass.UpdateTestResult(result); |
|
||||||
TestResult = GetTestResult(testClasses); |
|
||||||
} |
|
||||||
} |
|
||||||
|
|
||||||
public void ResetTestResults() |
|
||||||
{ |
|
||||||
foreach (var testClass in testClasses) |
|
||||||
testClass.ResetTestResults(); |
|
||||||
TestResult = TestResultType.None; |
|
||||||
} |
|
||||||
|
|
||||||
TestResultType testResult; |
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Gets the test result for this project.
|
|
||||||
/// </summary>
|
|
||||||
public TestResultType TestResult { |
|
||||||
get { return testResult; } |
|
||||||
set { SetAndNotifyPropertyChanged(ref testResult, value); } |
|
||||||
} |
|
||||||
|
|
||||||
static TestResultType GetTestResult(IList<TestClass> testClasses) |
|
||||||
{ |
|
||||||
if (testClasses.Count == 0) |
|
||||||
return TestResultType.None; |
|
||||||
if (testClasses.Any(c => c.TestResult == TestResultType.Failure)) |
|
||||||
return TestResultType.Failure; |
|
||||||
if (testClasses.Any(c => c.TestResult == TestResultType.None)) |
|
||||||
return TestResultType.None; |
|
||||||
if (testClasses.Any(c => c.TestResult == TestResultType.Ignored)) |
|
||||||
return TestResultType.Ignored; |
|
||||||
return TestResultType.Success; |
|
||||||
} |
|
||||||
} |
|
||||||
} |
|
@ -0,0 +1,83 @@ |
|||||||
|
// 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.Linq; |
||||||
|
using ICSharpCode.NRefactory.TypeSystem; |
||||||
|
using ICSharpCode.SharpDevelop; |
||||||
|
|
||||||
|
namespace ICSharpCode.UnitTesting |
||||||
|
{ |
||||||
|
/// <summary>
|
||||||
|
/// NUnit test fixture.
|
||||||
|
/// </summary>
|
||||||
|
public class NUnitTestClass : TestBase |
||||||
|
{ |
||||||
|
ITestProject parentProject; |
||||||
|
IUnresolvedTypeDefinition primaryPart; |
||||||
|
|
||||||
|
public NUnitTestClass(ITestProject parentProject, ITypeDefinition typeDefinition) |
||||||
|
{ |
||||||
|
this.parentProject = parentProject; |
||||||
|
UpdateTestClass(typeDefinition); |
||||||
|
BindResultToCompositeResultOfNestedTests(); |
||||||
|
} |
||||||
|
|
||||||
|
public override ITestProject ParentProject { |
||||||
|
get { return parentProject; } |
||||||
|
} |
||||||
|
|
||||||
|
public override string DisplayName { |
||||||
|
get { return primaryPart.Name; } |
||||||
|
} |
||||||
|
|
||||||
|
public string ReflectionName { |
||||||
|
get { return primaryPart.ReflectionName; } |
||||||
|
} |
||||||
|
|
||||||
|
public override bool SupportsGoToDefinition { |
||||||
|
get { return true; } |
||||||
|
} |
||||||
|
|
||||||
|
ITypeDefinition Resolve() |
||||||
|
{ |
||||||
|
ICompilation compilation = SD.ParserService.GetCompilation(parentProject.Project); |
||||||
|
IType type = primaryPart.Resolve(new SimpleTypeResolveContext(compilation.MainAssembly)); |
||||||
|
return type.GetDefinition(); |
||||||
|
} |
||||||
|
|
||||||
|
public override void GoToDefinition() |
||||||
|
{ |
||||||
|
ITypeDefinition typeDefinition = Resolve(); |
||||||
|
if (typeDefinition != null) |
||||||
|
NavigationService.NavigateTo(typeDefinition); |
||||||
|
} |
||||||
|
|
||||||
|
public void UpdateTestClass(ITypeDefinition typeDefinition) |
||||||
|
{ |
||||||
|
primaryPart = typeDefinition.Parts[0]; |
||||||
|
if (this.NestedTestsInitialized) { |
||||||
|
this.NestedTests.Clear(); |
||||||
|
this.NestedTests.AddRange(from nt in typeDefinition.NestedTypes |
||||||
|
where NUnitTestFramework.IsTestClass(nt) |
||||||
|
select new NUnitTestClass(parentProject, nt)); |
||||||
|
this.NestedTests.AddRange(from m in typeDefinition.Methods |
||||||
|
where NUnitTestFramework.IsTestMember(m) |
||||||
|
select new NUnitTestMethod(parentProject, (IUnresolvedMethod)m.UnresolvedMember)); |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
public override bool CanExpandNestedTests { |
||||||
|
get { return true; } |
||||||
|
} |
||||||
|
|
||||||
|
protected override void OnNestedTestsInitialized() |
||||||
|
{ |
||||||
|
ITypeDefinition typeDefinition = Resolve(); |
||||||
|
if (typeDefinition != null) { |
||||||
|
UpdateTestClass(typeDefinition); |
||||||
|
} |
||||||
|
base.OnNestedTestsInitialized(); |
||||||
|
} |
||||||
|
} |
||||||
|
} |
@ -0,0 +1,35 @@ |
|||||||
|
// 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.NRefactory.TypeSystem; |
||||||
|
|
||||||
|
namespace ICSharpCode.UnitTesting |
||||||
|
{ |
||||||
|
/// <summary>
|
||||||
|
/// NUnit test method.
|
||||||
|
/// </summary>
|
||||||
|
public class NUnitTestMethod : TestBase |
||||||
|
{ |
||||||
|
ITestProject parentProject; |
||||||
|
IUnresolvedMethod method; |
||||||
|
|
||||||
|
public NUnitTestMethod(ITestProject parentProject, IUnresolvedMethod method) |
||||||
|
{ |
||||||
|
if (parentProject == null) |
||||||
|
throw new ArgumentNullException("parentProject"); |
||||||
|
if (method == null) |
||||||
|
throw new ArgumentNullException("method"); |
||||||
|
this.parentProject = parentProject; |
||||||
|
this.method = method; |
||||||
|
} |
||||||
|
|
||||||
|
public override ITestProject ParentProject { |
||||||
|
get { return parentProject; } |
||||||
|
} |
||||||
|
|
||||||
|
public override string DisplayName { |
||||||
|
get { return method.Name; } |
||||||
|
} |
||||||
|
} |
||||||
|
} |
@ -1,100 +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.Specialized; |
|
||||||
using System.ComponentModel; |
|
||||||
|
|
||||||
using ICSharpCode.SharpDevelop; |
|
||||||
|
|
||||||
namespace ICSharpCode.UnitTesting |
|
||||||
{ |
|
||||||
/// <summary>
|
|
||||||
/// Represents a TestClass in the tree view.
|
|
||||||
/// </summary>
|
|
||||||
public class ClassUnitTestNode : UnitTestNode |
|
||||||
{ |
|
||||||
TestClass testClass; |
|
||||||
|
|
||||||
public TestClass TestClass { |
|
||||||
get { return testClass; } |
|
||||||
} |
|
||||||
|
|
||||||
public ClassUnitTestNode(TestClass testClass) |
|
||||||
{ |
|
||||||
this.testClass = testClass; |
|
||||||
this.testClass.TestResultChanged += delegate { |
|
||||||
RaisePropertyChanged("Icon"); |
|
||||||
RaisePropertyChanged("ExpandedIcon"); |
|
||||||
var parentNode = Parent; |
|
||||||
while (parentNode is NamespaceUnitTestNode) { |
|
||||||
parentNode.RaisePropertyChanged("Icon"); |
|
||||||
parentNode.RaisePropertyChanged("ExpandedIcon"); |
|
||||||
parentNode = parentNode.Parent; |
|
||||||
} |
|
||||||
}; |
|
||||||
testClass.Members.CollectionChanged += TestMembersCollectionChanged; |
|
||||||
testClass.NestedClasses.CollectionChanged += NestedClassesCollectionChanged; |
|
||||||
LazyLoading = true; |
|
||||||
} |
|
||||||
|
|
||||||
void NestedClassesCollectionChanged(object sender, NotifyCollectionChangedEventArgs e) |
|
||||||
{ |
|
||||||
switch (e.Action) { |
|
||||||
case NotifyCollectionChangedAction.Add: |
|
||||||
foreach (TestClass c in e.NewItems) { |
|
||||||
Children.OrderedInsert(new ClassUnitTestNode(c), NodeTextComparer); |
|
||||||
} |
|
||||||
break; |
|
||||||
case NotifyCollectionChangedAction.Remove: |
|
||||||
foreach (TestClass c in e.OldItems) { |
|
||||||
Children.RemoveAll(n => n is ClassUnitTestNode && ((ClassUnitTestNode)n).TestClass == c); |
|
||||||
} |
|
||||||
break; |
|
||||||
case NotifyCollectionChangedAction.Reset: |
|
||||||
LoadChildren(); |
|
||||||
break; |
|
||||||
default: |
|
||||||
throw new NotSupportedException(); |
|
||||||
} |
|
||||||
} |
|
||||||
|
|
||||||
void TestMembersCollectionChanged(object sender, NotifyCollectionChangedEventArgs e) |
|
||||||
{ |
|
||||||
switch (e.Action) { |
|
||||||
case NotifyCollectionChangedAction.Add: |
|
||||||
foreach (TestMember m in e.NewItems) { |
|
||||||
Children.OrderedInsert(new MemberUnitTestNode(m), NodeTextComparer); |
|
||||||
} |
|
||||||
break; |
|
||||||
case NotifyCollectionChangedAction.Remove: |
|
||||||
foreach (TestMember m in e.OldItems) { |
|
||||||
Children.RemoveAll(n => n is MemberUnitTestNode && ((MemberUnitTestNode)n).TestMember == m); |
|
||||||
} |
|
||||||
break; |
|
||||||
case NotifyCollectionChangedAction.Reset: |
|
||||||
LoadChildren(); |
|
||||||
break; |
|
||||||
default: |
|
||||||
throw new NotSupportedException(); |
|
||||||
} |
|
||||||
} |
|
||||||
|
|
||||||
protected override void LoadChildren() |
|
||||||
{ |
|
||||||
Children.Clear(); |
|
||||||
foreach (TestClass c in testClass.NestedClasses) |
|
||||||
Children.Add(new ClassUnitTestNode(c)); |
|
||||||
foreach (TestMember m in testClass.Members) |
|
||||||
Children.Add(new MemberUnitTestNode(m)); |
|
||||||
} |
|
||||||
|
|
||||||
public override object Text { |
|
||||||
get { return testClass.Name; } |
|
||||||
} |
|
||||||
|
|
||||||
internal override TestResultType TestResultType { |
|
||||||
get { return testClass.TestResult; } |
|
||||||
} |
|
||||||
} |
|
||||||
} |
|
@ -1,44 +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.Specialized; |
|
||||||
using System.ComponentModel; |
|
||||||
using ICSharpCode.Core; |
|
||||||
using ICSharpCode.SharpDevelop; |
|
||||||
using ICSharpCode.TreeView; |
|
||||||
|
|
||||||
namespace ICSharpCode.UnitTesting |
|
||||||
{ |
|
||||||
public class MemberUnitTestNode : UnitTestNode |
|
||||||
{ |
|
||||||
TestMember testMember; |
|
||||||
|
|
||||||
public TestMember TestMember { |
|
||||||
get { return testMember; } |
|
||||||
} |
|
||||||
|
|
||||||
public MemberUnitTestNode(TestMember testMember) |
|
||||||
{ |
|
||||||
this.testMember = testMember; |
|
||||||
this.testMember.TestResultChanged += delegate { |
|
||||||
RaisePropertyChanged("Icon"); |
|
||||||
RaisePropertyChanged("ExpandedIcon"); |
|
||||||
}; |
|
||||||
} |
|
||||||
|
|
||||||
internal override TestResultType TestResultType { |
|
||||||
get { return this.testMember.TestResult; } |
|
||||||
} |
|
||||||
|
|
||||||
public override object Text { |
|
||||||
get { return testMember.Member.Name; } |
|
||||||
} |
|
||||||
|
|
||||||
public override void ActivateItem(System.Windows.RoutedEventArgs e) |
|
||||||
{ |
|
||||||
var region = testMember.Member.Region; |
|
||||||
SD.FileService.JumpToFilePosition(new FileName(region.FileName), region.BeginLine, region.BeginColumn); |
|
||||||
} |
|
||||||
} |
|
||||||
} |
|
@ -1,63 +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.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 : UnitTestNode |
|
||||||
{ |
|
||||||
readonly string shortName; |
|
||||||
readonly string namespaceName; |
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Gets the namespace suffix (namespace portion after the root namespace)
|
|
||||||
/// </summary>
|
|
||||||
public string ShortName { |
|
||||||
get { return shortName; } |
|
||||||
} |
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Gets the full namespace
|
|
||||||
/// </summary>
|
|
||||||
public string NamespaceName { |
|
||||||
get { return namespaceName; } |
|
||||||
} |
|
||||||
|
|
||||||
public NamespaceUnitTestNode(string namespaceName) |
|
||||||
{ |
|
||||||
if (namespaceName == null) |
|
||||||
throw new ArgumentNullException("namespaceName"); |
|
||||||
this.namespaceName = namespaceName; |
|
||||||
this.shortName = namespaceName.Substring(namespaceName.IndexOf('.') + 1); |
|
||||||
} |
|
||||||
|
|
||||||
public override object Text { |
|
||||||
get { return shortName; } |
|
||||||
} |
|
||||||
|
|
||||||
internal override TestResultType TestResultType { |
|
||||||
get { |
|
||||||
if (Children.Count == 0) return TestResultType.None; |
|
||||||
if (Children.OfType<UnitTestNode>().Any(node => node.TestResultType == TestResultType.Failure)) |
|
||||||
return TestResultType.Failure; |
|
||||||
if (Children.OfType<UnitTestNode>().Any(node => node.TestResultType == TestResultType.None)) |
|
||||||
return TestResultType.None; |
|
||||||
if (Children.OfType<UnitTestNode>().Any(node => node.TestResultType == TestResultType.Ignored)) |
|
||||||
return TestResultType.Ignored; |
|
||||||
return TestResultType.Success; |
|
||||||
} |
|
||||||
} |
|
||||||
} |
|
||||||
} |
|
@ -1,136 +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.Specialized; |
|
||||||
using System.ComponentModel; |
|
||||||
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 ProjectUnitTestNode : UnitTestNode |
|
||||||
{ |
|
||||||
TestProject project; |
|
||||||
|
|
||||||
public TestProject Project { |
|
||||||
get { return project; } |
|
||||||
} |
|
||||||
|
|
||||||
public ProjectUnitTestNode(TestProject project) |
|
||||||
{ |
|
||||||
this.project = project; |
|
||||||
project.TestClasses.CollectionChanged += TestClassesCollectionChanged; |
|
||||||
project.PropertyChanged += ProjectPropertyChanged; |
|
||||||
LazyLoading = true; |
|
||||||
} |
|
||||||
|
|
||||||
void ProjectPropertyChanged(object sender, PropertyChangedEventArgs e) |
|
||||||
{ |
|
||||||
if (e.PropertyName == "TestResult") { |
|
||||||
RaisePropertyChanged("Icon"); |
|
||||||
RaisePropertyChanged("ExpandedIcon"); |
|
||||||
} |
|
||||||
} |
|
||||||
|
|
||||||
void TestClassesCollectionChanged(object sender, NotifyCollectionChangedEventArgs e) |
|
||||||
{ |
|
||||||
switch (e.Action) { |
|
||||||
case NotifyCollectionChangedAction.Add: |
|
||||||
foreach (TestClass c in e.NewItems) { |
|
||||||
if (c.Namespace == "<invalid>") continue; |
|
||||||
UnitTestNode node = FindOrCreateNamespace(this, project.Project.RootNamespace, c.Namespace); |
|
||||||
node.Children.OrderedInsert(new ClassUnitTestNode(c), NodeTextComparer); |
|
||||||
} |
|
||||||
break; |
|
||||||
case NotifyCollectionChangedAction.Remove: |
|
||||||
foreach (TestClass c in e.OldItems) { |
|
||||||
if (c.Namespace == "<invalid>") continue; |
|
||||||
SharpTreeNode node = FindNamespace(this, project.Project.RootNamespace, c.Namespace); |
|
||||||
node.Children.RemoveAll(n => n is ClassUnitTestNode && ((ClassUnitTestNode)n).TestClass == c); |
|
||||||
while (node is NamespaceUnitTestNode && node.Children.Count == 0) { |
|
||||||
var parent = node.Parent; |
|
||||||
if (parent == null) break; |
|
||||||
parent.Children.Remove(node); |
|
||||||
node = parent; |
|
||||||
} |
|
||||||
} |
|
||||||
break; |
|
||||||
case NotifyCollectionChangedAction.Reset: |
|
||||||
LoadChildren(); |
|
||||||
break; |
|
||||||
} |
|
||||||
} |
|
||||||
|
|
||||||
static UnitTestNode FindOrCreateNamespace(UnitTestNode parent, string parentNamespace, string @namespace) |
|
||||||
{ |
|
||||||
if (parentNamespace == @namespace) |
|
||||||
return parent; |
|
||||||
foreach (var node in parent.Children.OfType<NamespaceUnitTestNode>()) { |
|
||||||
if (@namespace == node.NamespaceName) |
|
||||||
return node; |
|
||||||
if (@namespace.StartsWith(node.NamespaceName + ".", StringComparison.Ordinal)) { |
|
||||||
return FindOrCreateNamespace(node, node.NamespaceName, @namespace); |
|
||||||
} |
|
||||||
} |
|
||||||
// Create missing namespace node:
|
|
||||||
|
|
||||||
// Figure out which part of the namespace we can remove due to the parent namespace:
|
|
||||||
int startPos = 0; |
|
||||||
if (@namespace.StartsWith(parentNamespace + ".", StringComparison.Ordinal)) { |
|
||||||
startPos = parentNamespace.Length + 1; |
|
||||||
} |
|
||||||
// Get the next dot
|
|
||||||
int dotPos = @namespace.IndexOf('.', startPos); |
|
||||||
if (dotPos < 0) { |
|
||||||
var newNode = new NamespaceUnitTestNode(@namespace); |
|
||||||
parent.Children.OrderedInsert(newNode, NodeTextComparer); |
|
||||||
return newNode; |
|
||||||
} else { |
|
||||||
var newNode = new NamespaceUnitTestNode(@namespace.Substring(0, dotPos)); |
|
||||||
parent.Children.OrderedInsert(newNode, NodeTextComparer); |
|
||||||
return FindOrCreateNamespace(newNode, newNode.NamespaceName, @namespace); |
|
||||||
} |
|
||||||
} |
|
||||||
|
|
||||||
static UnitTestNode FindNamespace(UnitTestNode parent, string parentNamespace, string @namespace) |
|
||||||
{ |
|
||||||
if (parentNamespace == @namespace) |
|
||||||
return parent; |
|
||||||
foreach (var node in parent.Children.OfType<NamespaceUnitTestNode>()) { |
|
||||||
if (@namespace == node.NamespaceName) |
|
||||||
return node; |
|
||||||
if (@namespace.StartsWith(node.NamespaceName + ".", StringComparison.Ordinal)) { |
|
||||||
return FindNamespace(node, node.NamespaceName, @namespace); |
|
||||||
} |
|
||||||
} |
|
||||||
return null; |
|
||||||
} |
|
||||||
|
|
||||||
protected override void LoadChildren() |
|
||||||
{ |
|
||||||
Children.Clear(); |
|
||||||
foreach (var g in project.TestClasses.Select(c => new ClassUnitTestNode(c)).GroupBy(tc => tc.TestClass.Namespace)) { |
|
||||||
if (g.Key == "<invalid>") continue; |
|
||||||
UnitTestNode node = FindOrCreateNamespace(this, project.Project.RootNamespace, g.Key); |
|
||||||
node.Children.AddRange(g.OrderBy(NodeTextComparer)); |
|
||||||
} |
|
||||||
} |
|
||||||
|
|
||||||
public override object Text { |
|
||||||
get { return project.Project.Name; } |
|
||||||
} |
|
||||||
|
|
||||||
internal override TestResultType TestResultType { |
|
||||||
get { return project.TestResult; } |
|
||||||
} |
|
||||||
} |
|
||||||
} |
|
@ -1,76 +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.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 |
|
||||||
{ |
|
||||||
/// <summary>
|
|
||||||
/// Description of RootUnitTestNode.
|
|
||||||
/// </summary>
|
|
||||||
public class RootUnitTestNode : UnitTestNode |
|
||||||
{ |
|
||||||
readonly TestSolution testSolution; |
|
||||||
|
|
||||||
public RootUnitTestNode(TestSolution testSolution) |
|
||||||
{ |
|
||||||
this.testSolution = testSolution; |
|
||||||
testSolution.TestableProjects.CollectionChanged += TestSolution_TestableProjects_CollectionChanged; |
|
||||||
LazyLoading = true; |
|
||||||
} |
|
||||||
|
|
||||||
void TestSolution_TestableProjects_CollectionChanged(object sender, NotifyCollectionChangedEventArgs e) |
|
||||||
{ |
|
||||||
switch (e.Action) { |
|
||||||
case NotifyCollectionChangedAction.Add: |
|
||||||
Children.AddRange(e.NewItems.OfType<TestProject>().Select(p => new ProjectUnitTestNode(p))); |
|
||||||
break; |
|
||||||
case NotifyCollectionChangedAction.Remove: |
|
||||||
Children.RemoveAll(node => node is ProjectUnitTestNode && e.OldItems.OfType<TestProject>().Any(p => p.Project == ((ProjectUnitTestNode)node).Project)); |
|
||||||
break; |
|
||||||
case NotifyCollectionChangedAction.Reset: |
|
||||||
LoadChildren(); |
|
||||||
break; |
|
||||||
} |
|
||||||
} |
|
||||||
|
|
||||||
protected override void LoadChildren() |
|
||||||
{ |
|
||||||
Children.Clear(); |
|
||||||
Children.AddRange(testSolution.TestableProjects.Select(p => new ProjectUnitTestNode(p))); |
|
||||||
} |
|
||||||
|
|
||||||
public override object Text { |
|
||||||
get { return ResourceService.GetString("ICSharpCode.UnitTesting.AllTestsTreeNode.Text"); } |
|
||||||
} |
|
||||||
|
|
||||||
internal override TestResultType TestResultType { |
|
||||||
get { |
|
||||||
if (Children.Count == 0) return TestResultType.None; |
|
||||||
if (Children.OfType<UnitTestNode>().Any(node => node.TestResultType == TestResultType.Failure)) |
|
||||||
return TestResultType.Failure; |
|
||||||
if (Children.OfType<UnitTestNode>().Any(node => node.TestResultType == TestResultType.None)) |
|
||||||
return TestResultType.None; |
|
||||||
if (Children.OfType<UnitTestNode>().Any(node => node.TestResultType == TestResultType.Ignored)) |
|
||||||
return TestResultType.Ignored; |
|
||||||
return TestResultType.Success; |
|
||||||
} |
|
||||||
} |
|
||||||
} |
|
||||||
} |
|
Loading…
Reference in new issue