Browse Source
A lot of functionality gets moved from the main portion of the AddIn into the framework-specific providers. We no longer deal with test classes and members, but instead use the new ITest interface. A test can be a whole project, namespace, class, or just a single method. This can be used to support features like the NUnit [TestCase] attribute, where a single method might result in multiple tests.newNRvisualizers
68 changed files with 1447 additions and 1649 deletions
@ -1,398 +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.IO; |
|
||||||
using System.Linq; |
|
||||||
using ICSharpCode.Core; |
|
||||||
using ICSharpCode.SharpDevelop; |
|
||||||
using ICSharpCode.SharpDevelop.Gui; |
|
||||||
using ICSharpCode.SharpDevelop.Project; |
|
||||||
using ICSharpCode.SharpDevelop.Project.Commands; |
|
||||||
|
|
||||||
namespace ICSharpCode.UnitTesting |
|
||||||
{ |
|
||||||
public abstract class AbstractRunTestCommand : AbstractMenuCommand |
|
||||||
{ |
|
||||||
static AbstractRunTestCommand runningTestCommand; |
|
||||||
IUnitTestsPad unitTestsPad; |
|
||||||
SelectedTests selectedTests; |
|
||||||
IRunTestCommandContext context; |
|
||||||
ITestRunner testRunner; |
|
||||||
IProgressMonitor testProgressMonitor; |
|
||||||
int totalProjectCount; |
|
||||||
|
|
||||||
public AbstractRunTestCommand() |
|
||||||
: this(new RunTestCommandContext()) |
|
||||||
{ |
|
||||||
} |
|
||||||
|
|
||||||
public AbstractRunTestCommand(IRunTestCommandContext context) |
|
||||||
{ |
|
||||||
this.context = context; |
|
||||||
} |
|
||||||
|
|
||||||
protected IRunTestCommandContext Context { |
|
||||||
get { return context; } |
|
||||||
} |
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Gets the running test command.
|
|
||||||
/// </summary>
|
|
||||||
public static AbstractRunTestCommand RunningTestCommand { |
|
||||||
get { return runningTestCommand; } |
|
||||||
set { runningTestCommand = value; } |
|
||||||
} |
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Gets whether a test is currently running.
|
|
||||||
/// </summary>
|
|
||||||
public static bool IsRunningTest { |
|
||||||
get { return runningTestCommand != null; } |
|
||||||
} |
|
||||||
|
|
||||||
public override void Run() |
|
||||||
{ |
|
||||||
GetUnitTestsPad(); |
|
||||||
|
|
||||||
selectedTests = GetSelectedTests(); |
|
||||||
if (selectedTests.HasProjects) { |
|
||||||
runningTestCommand = this; |
|
||||||
BeforeRun(); |
|
||||||
BuildAndRunTests(); |
|
||||||
} |
|
||||||
} |
|
||||||
|
|
||||||
SelectedTests GetSelectedTests() |
|
||||||
{ |
|
||||||
return new SelectedTests(Owner, unitTestsPad.GetProjects()); |
|
||||||
} |
|
||||||
|
|
||||||
void GetUnitTestsPad() |
|
||||||
{ |
|
||||||
unitTestsPad = context.OpenUnitTestsPad; |
|
||||||
if (unitTestsPad == null) { |
|
||||||
unitTestsPad = CreateEmptyUnitTestsPad(); |
|
||||||
} |
|
||||||
} |
|
||||||
|
|
||||||
EmptyUnitTestsPad CreateEmptyUnitTestsPad() |
|
||||||
{ |
|
||||||
return new EmptyUnitTestsPad(context.OpenSolution); |
|
||||||
} |
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Sets the initial workbench state before starting
|
|
||||||
/// a test run.
|
|
||||||
/// </summary>
|
|
||||||
void BeforeRun() |
|
||||||
{ |
|
||||||
ClearTasks(); |
|
||||||
ClearUnitTestCategoryText(); |
|
||||||
|
|
||||||
ShowUnitTestsPad(); |
|
||||||
ShowOutputPad(); |
|
||||||
|
|
||||||
UpdateUnitTestsPadToolbar(); |
|
||||||
ResetAllTestResultsInUnitTestsPad(); |
|
||||||
|
|
||||||
OnBeforeBuild(); |
|
||||||
} |
|
||||||
|
|
||||||
void BuildAndRunTests() |
|
||||||
{ |
|
||||||
if (IsBuildNeededBeforeTestRun()) { |
|
||||||
BuildProjectBeforeRunningTests(selectedTests); |
|
||||||
} else { |
|
||||||
context.SaveAllFilesCommand.SaveAllFiles(); |
|
||||||
RunTests(selectedTests); |
|
||||||
} |
|
||||||
} |
|
||||||
|
|
||||||
bool IsBuildNeededBeforeTestRun() |
|
||||||
{ |
|
||||||
return selectedTests.Projects.Any(p => context.RegisteredTestFrameworks.IsBuildNeededBeforeTestRunForProject(p)); |
|
||||||
} |
|
||||||
|
|
||||||
void ClearTasks() |
|
||||||
{ |
|
||||||
context.TaskService.BuildMessageViewCategory.ClearText(); |
|
||||||
context.TaskService.InUpdate = true; |
|
||||||
context.TaskService.ClearExceptCommentTasks(); |
|
||||||
context.TaskService.InUpdate = false; |
|
||||||
} |
|
||||||
|
|
||||||
void ClearUnitTestCategoryText() |
|
||||||
{ |
|
||||||
context.UnitTestCategory.ClearText(); |
|
||||||
} |
|
||||||
|
|
||||||
void ShowUnitTestsPad() |
|
||||||
{ |
|
||||||
unitTestsPad.BringToFront(); |
|
||||||
} |
|
||||||
|
|
||||||
void StopProgressMonitor() |
|
||||||
{ |
|
||||||
if (testProgressMonitor != null) { |
|
||||||
testProgressMonitor.Dispose(); |
|
||||||
testProgressMonitor = null; |
|
||||||
} |
|
||||||
} |
|
||||||
|
|
||||||
void UpdateUnitTestsPadToolbar() |
|
||||||
{ |
|
||||||
unitTestsPad.UpdateToolbar(); |
|
||||||
} |
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Called before the build is started (even if no build needs to be performed).
|
|
||||||
/// If multiple projects are to be tested this is called only once.
|
|
||||||
/// </summary>
|
|
||||||
protected virtual void OnBeforeBuild() |
|
||||||
{ |
|
||||||
} |
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Called before all tests are run (after the build has finished successfully).
|
|
||||||
/// If multiple projects are to be tested this is called only once.
|
|
||||||
/// </summary>
|
|
||||||
protected virtual void OnBeforeRunTests() |
|
||||||
{ |
|
||||||
} |
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Runs the tests after building the project(s) under test.
|
|
||||||
/// </summary>
|
|
||||||
void BuildProjectBeforeRunningTests(SelectedTests selectedTests) |
|
||||||
{ |
|
||||||
BuildProject build = CreateBuildProjectBeforeTestRun(selectedTests); |
|
||||||
build.BuildComplete += delegate { |
|
||||||
OnBuildComplete(build.LastBuildResults, selectedTests); |
|
||||||
}; |
|
||||||
build.Run(); |
|
||||||
} |
|
||||||
|
|
||||||
BuildProject CreateBuildProjectBeforeTestRun(SelectedTests selectedTests) |
|
||||||
{ |
|
||||||
IEnumerable<IProject> projects = GetProjectsRequiringBuildBeforeTestRun(selectedTests); |
|
||||||
return context.BuildProjectFactory.CreateBuildProjectBeforeTestRun(projects); |
|
||||||
} |
|
||||||
|
|
||||||
IEnumerable<IProject> GetProjectsRequiringBuildBeforeTestRun(SelectedTests selectedTests) |
|
||||||
{ |
|
||||||
return selectedTests |
|
||||||
.Projects |
|
||||||
.Where(p => context.RegisteredTestFrameworks.IsBuildNeededBeforeTestRunForProject(p)); |
|
||||||
} |
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Stops running the tests.
|
|
||||||
/// </summary>
|
|
||||||
public void Stop() |
|
||||||
{ |
|
||||||
StopActiveTestRunner(); |
|
||||||
|
|
||||||
runningTestCommand = null; |
|
||||||
UpdateUnitTestsPadToolbar(); |
|
||||||
|
|
||||||
OnStop(); |
|
||||||
} |
|
||||||
|
|
||||||
void StopActiveTestRunner() |
|
||||||
{ |
|
||||||
if (testRunner != null) { |
|
||||||
testRunner.Stop(); |
|
||||||
testRunner.Dispose(); |
|
||||||
testRunner = null; |
|
||||||
} |
|
||||||
} |
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Called after all tests have been run even if there have
|
|
||||||
/// been errors. If multiple projects are to be tested this is called only once.
|
|
||||||
/// </summary>
|
|
||||||
protected virtual void OnAfterRunTests() |
|
||||||
{ |
|
||||||
} |
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Called by derived classes when a single test run
|
|
||||||
/// is finished.
|
|
||||||
/// </summary>
|
|
||||||
protected void TestRunCompleted() |
|
||||||
{ |
|
||||||
StopActiveTestRunner(); |
|
||||||
selectedTests.RemoveFirstProject(); |
|
||||||
if (selectedTests.HasProjects) { |
|
||||||
RunTests(selectedTests); |
|
||||||
} else { |
|
||||||
StopProgressMonitor(); |
|
||||||
runningTestCommand = null; |
|
||||||
UpdateUnitTestsPadToolbar(); |
|
||||||
ShowErrorList(); |
|
||||||
OnAfterRunTests(); |
|
||||||
} |
|
||||||
} |
|
||||||
|
|
||||||
void TestFinished(object source, TestFinishedEventArgs e) |
|
||||||
{ |
|
||||||
context.Workbench.SafeThreadAsyncCall(ShowResult, e.Result); |
|
||||||
} |
|
||||||
|
|
||||||
protected void ShowResult(TestResult result) |
|
||||||
{ |
|
||||||
if (IsTestResultFailureOrIsIgnored(result)) { |
|
||||||
AddTaskForTestResult(result); |
|
||||||
UpdateProgressMonitorStatus(result); |
|
||||||
} |
|
||||||
UpdateTestResult(result); |
|
||||||
} |
|
||||||
|
|
||||||
bool IsTestResultFailureOrIsIgnored(TestResult result) |
|
||||||
{ |
|
||||||
return result.IsFailure || result.IsIgnored; |
|
||||||
} |
|
||||||
|
|
||||||
void AddTaskForTestResult(TestResult testResult) |
|
||||||
{ |
|
||||||
TestProject project = GetTestProjectForProject(selectedTests.Project); |
|
||||||
SDTask task = TestResultTask.Create(testResult, project); |
|
||||||
context.TaskService.Add(task); |
|
||||||
} |
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Called when the test run should be stopped.
|
|
||||||
/// </summary>
|
|
||||||
protected virtual void OnStop() |
|
||||||
{ |
|
||||||
} |
|
||||||
|
|
||||||
void ShowOutputPad() |
|
||||||
{ |
|
||||||
ShowPad(context.Workbench.GetPad(typeof(CompilerMessageView))); |
|
||||||
} |
|
||||||
|
|
||||||
protected void ShowPad(PadDescriptor padDescriptor) |
|
||||||
{ |
|
||||||
context.Workbench.SafeThreadAsyncCall(padDescriptor.BringPadToFront); |
|
||||||
} |
|
||||||
|
|
||||||
void ShowErrorList() |
|
||||||
{ |
|
||||||
if (HasErrorsThatShouldBeDisplayed()) { |
|
||||||
ShowPad(context.Workbench.GetPad(typeof(ErrorListPad))); |
|
||||||
} |
|
||||||
} |
|
||||||
|
|
||||||
bool HasErrorsThatShouldBeDisplayed() |
|
||||||
{ |
|
||||||
return context.TaskService.SomethingWentWrong && |
|
||||||
context.BuildOptions.ShowErrorListAfterBuild; |
|
||||||
} |
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Runs the test for the project after a successful build.
|
|
||||||
/// </summary>
|
|
||||||
void OnBuildComplete(BuildResults results, SelectedTests selectedTests) |
|
||||||
{ |
|
||||||
if (BuildHasNoErrorsAndStillRunningTests(results)) { |
|
||||||
RunTests(selectedTests); |
|
||||||
} else { |
|
||||||
if (IsRunningTest) { |
|
||||||
Stop(); |
|
||||||
} |
|
||||||
ShowErrorList(); |
|
||||||
} |
|
||||||
} |
|
||||||
|
|
||||||
bool BuildHasNoErrorsAndStillRunningTests(BuildResults results) |
|
||||||
{ |
|
||||||
return (results.ErrorCount == 0) && IsRunningTest; |
|
||||||
} |
|
||||||
|
|
||||||
void RunTests(SelectedTests selectedTests) |
|
||||||
{ |
|
||||||
if (testProgressMonitor == null) { |
|
||||||
OnBeforeRunTests(); |
|
||||||
testProgressMonitor = context.StatusBarService.CreateProgressMonitor(); |
|
||||||
totalProjectCount = selectedTests.ProjectsCount; |
|
||||||
} |
|
||||||
testProgressMonitor.TaskName = GetProgressMonitorLabel(selectedTests.Project); |
|
||||||
testProgressMonitor.Progress = GetProgress(selectedTests.ProjectsCount); |
|
||||||
|
|
||||||
testRunner = CreateTestRunner(selectedTests.Project); |
|
||||||
if (testRunner != null) { |
|
||||||
StartTestRunner(); |
|
||||||
} |
|
||||||
} |
|
||||||
|
|
||||||
void StartTestRunner() |
|
||||||
{ |
|
||||||
testRunner.MessageReceived += TestRunnerMessageReceived; |
|
||||||
testRunner.AllTestsFinished += AllTestsFinished; |
|
||||||
testRunner.TestFinished += TestFinished; |
|
||||||
testRunner.Start(selectedTests); |
|
||||||
} |
|
||||||
|
|
||||||
string GetProgressMonitorLabel(IProject project) |
|
||||||
{ |
|
||||||
StringTagPair tagPair = new StringTagPair("Name", project.Name); |
|
||||||
return StringParser.Parse("${res:ICSharpCode.UnitTesting.StatusBarProgressLabel}", tagPair); |
|
||||||
} |
|
||||||
|
|
||||||
double GetProgress(int projectsLeftToRunCount) |
|
||||||
{ |
|
||||||
return (double)(totalProjectCount - projectsLeftToRunCount) / totalProjectCount; |
|
||||||
} |
|
||||||
|
|
||||||
protected virtual ITestRunner CreateTestRunner(IProject project) |
|
||||||
{ |
|
||||||
return null; |
|
||||||
} |
|
||||||
|
|
||||||
protected virtual void TestRunnerMessageReceived(object source, MessageReceivedEventArgs e) |
|
||||||
{ |
|
||||||
context.UnitTestCategory.AppendLine(e.Message); |
|
||||||
} |
|
||||||
|
|
||||||
void AllTestsFinished(object source, EventArgs e) |
|
||||||
{ |
|
||||||
context.Workbench.SafeThreadAsyncCall(TestRunCompleted); |
|
||||||
} |
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Clears the test results in the test tree view for all the
|
|
||||||
/// displayed projects.
|
|
||||||
/// </summary>
|
|
||||||
void ResetAllTestResultsInUnitTestsPad() |
|
||||||
{ |
|
||||||
unitTestsPad.ResetTestResults(); |
|
||||||
} |
|
||||||
|
|
||||||
TestProject GetTestProjectForProject(IProject project) |
|
||||||
{ |
|
||||||
return unitTestsPad.GetTestProject(project); |
|
||||||
} |
|
||||||
|
|
||||||
void UpdateTestResult(TestResult result) |
|
||||||
{ |
|
||||||
TestProject testProject = GetTestProjectForProject(selectedTests.Project); |
|
||||||
if (testProject != null) { |
|
||||||
testProject.UpdateTestResult(result); |
|
||||||
} |
|
||||||
} |
|
||||||
|
|
||||||
void UpdateProgressMonitorStatus(TestResult result) |
|
||||||
{ |
|
||||||
if (testProgressMonitor != null) { |
|
||||||
if (result.IsFailure) { |
|
||||||
testProgressMonitor.Status = OperationStatus.Error; |
|
||||||
} else if (result.IsIgnored && testProgressMonitor.Status == OperationStatus.Normal) { |
|
||||||
testProgressMonitor.Status = OperationStatus.Warning; |
|
||||||
} |
|
||||||
} |
|
||||||
} |
|
||||||
} |
|
||||||
} |
|
||||||
@ -1,25 +0,0 @@ |
|||||||
// Copyright (c) AlphaSierraPapa for the SharpDevelop Team (for details please see \doc\copyright.txt)
|
|
||||||
// This code is distributed under the GNU LGPL (for details please see \doc\license.txt)
|
|
||||||
|
|
||||||
using System; |
|
||||||
using ICSharpCode.Core; |
|
||||||
using ICSharpCode.SharpDevelop.Gui; |
|
||||||
using ICSharpCode.SharpDevelop.Project; |
|
||||||
|
|
||||||
namespace ICSharpCode.UnitTesting |
|
||||||
{ |
|
||||||
public interface IRunTestCommandContext |
|
||||||
{ |
|
||||||
IRegisteredTestFrameworks RegisteredTestFrameworks { get; } |
|
||||||
IUnitTestTaskService TaskService { get; } |
|
||||||
IUnitTestWorkbench Workbench { get; } |
|
||||||
IBuildProjectFactory BuildProjectFactory { get; } |
|
||||||
IBuildOptions BuildOptions { get; } |
|
||||||
MessageViewCategory UnitTestCategory { get; } |
|
||||||
IUnitTestsPad OpenUnitTestsPad { get; } |
|
||||||
IMessageService MessageService { get; } |
|
||||||
IUnitTestSaveAllFilesCommand SaveAllFilesCommand { get; } |
|
||||||
IStatusBarService StatusBarService { get; } |
|
||||||
Solution OpenSolution { get; } |
|
||||||
} |
|
||||||
} |
|
||||||
@ -0,0 +1,56 @@ |
|||||||
|
// 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.Core; |
||||||
|
using ICSharpCode.SharpDevelop.Project; |
||||||
|
using ICSharpCode.TreeView; |
||||||
|
|
||||||
|
namespace ICSharpCode.UnitTesting |
||||||
|
{ |
||||||
|
public class AddNUnitReferenceCommand : AbstractMenuCommand |
||||||
|
{ |
||||||
|
public void Run(IProject project) |
||||||
|
{ |
||||||
|
if (project != null) { |
||||||
|
ReferenceProjectItem nunitRef = new ReferenceProjectItem(project, "nunit.framework"); |
||||||
|
ProjectService.AddProjectItem(project, nunitRef); |
||||||
|
project.Save(); |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
public override void Run() |
||||||
|
{ |
||||||
|
Run(ProjectService.CurrentProject); |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
public class GotoDefinitionCommand : AbstractMenuCommand |
||||||
|
{ |
||||||
|
public override void Run() |
||||||
|
{ |
||||||
|
ITestTreeView treeView = Owner as ITestTreeView; |
||||||
|
if (treeView != null) { |
||||||
|
ITest test = treeView.SelectedTests.FirstOrDefault(); |
||||||
|
if (test != null && test.SupportsGoToDefinition) |
||||||
|
test.GoToDefinition(); |
||||||
|
} |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
public class CollapseAllTestsCommand : AbstractMenuCommand |
||||||
|
{ |
||||||
|
public override void Run() |
||||||
|
{ |
||||||
|
if (!(this.Owner is SharpTreeView)) |
||||||
|
return; |
||||||
|
|
||||||
|
var treeView = (SharpTreeView)this.Owner; |
||||||
|
if (treeView.Root != null) { |
||||||
|
foreach (var n in treeView.Root.Descendants()) |
||||||
|
n.IsExpanded = false; |
||||||
|
} |
||||||
|
} |
||||||
|
} |
||||||
|
} |
||||||
@ -1,26 +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; |
|
||||||
|
|
||||||
namespace ICSharpCode.UnitTesting |
|
||||||
{ |
|
||||||
public class RunAllTestsInPadCommand : RunTestInPadCommand |
|
||||||
{ |
|
||||||
public RunAllTestsInPadCommand() |
|
||||||
{ |
|
||||||
} |
|
||||||
|
|
||||||
public RunAllTestsInPadCommand(IRunTestCommandContext context) |
|
||||||
: base(context) |
|
||||||
{ |
|
||||||
} |
|
||||||
|
|
||||||
public override void Run() |
|
||||||
{ |
|
||||||
// To make sure all tests are run we set the Owner to null.
|
|
||||||
Owner = null; |
|
||||||
base.Run(); |
|
||||||
} |
|
||||||
} |
|
||||||
} |
|
||||||
@ -1,42 +0,0 @@ |
|||||||
// Copyright (c) AlphaSierraPapa for the SharpDevelop Team (for details please see \doc\copyright.txt)
|
|
||||||
// This code is distributed under the GNU LGPL (for details please see \doc\license.txt)
|
|
||||||
|
|
||||||
using System; |
|
||||||
using ICSharpCode.SharpDevelop.Project; |
|
||||||
|
|
||||||
namespace ICSharpCode.UnitTesting |
|
||||||
{ |
|
||||||
public class RunProjectTestsInPadCommand : RunTestInPadCommand, ITestTreeView |
|
||||||
{ |
|
||||||
public RunProjectTestsInPadCommand() |
|
||||||
{ |
|
||||||
} |
|
||||||
|
|
||||||
public RunProjectTestsInPadCommand(IRunTestCommandContext context) |
|
||||||
: base(context) |
|
||||||
{ |
|
||||||
} |
|
||||||
|
|
||||||
public override void Run() |
|
||||||
{ |
|
||||||
Owner = this; |
|
||||||
base.Run(); |
|
||||||
} |
|
||||||
|
|
||||||
public TestMember SelectedMember { |
|
||||||
get { return null; } |
|
||||||
} |
|
||||||
|
|
||||||
public TestClass SelectedClass { |
|
||||||
get { return null; } |
|
||||||
} |
|
||||||
|
|
||||||
public TestProject SelectedProject { |
|
||||||
get { return TestService.Solution.GetTestProject(ProjectService.CurrentProject); } |
|
||||||
} |
|
||||||
|
|
||||||
public string SelectedNamespace { |
|
||||||
get { return null; } |
|
||||||
} |
|
||||||
} |
|
||||||
} |
|
||||||
@ -1,68 +0,0 @@ |
|||||||
// Copyright (c) AlphaSierraPapa for the SharpDevelop Team (for details please see \doc\copyright.txt)
|
|
||||||
// This code is distributed under the GNU LGPL (for details please see \doc\license.txt)
|
|
||||||
|
|
||||||
using System; |
|
||||||
using ICSharpCode.Core; |
|
||||||
using ICSharpCode.SharpDevelop; |
|
||||||
using ICSharpCode.SharpDevelop.Gui; |
|
||||||
using ICSharpCode.SharpDevelop.Project; |
|
||||||
|
|
||||||
namespace ICSharpCode.UnitTesting |
|
||||||
{ |
|
||||||
public class RunTestCommandContext : IRunTestCommandContext |
|
||||||
{ |
|
||||||
UnitTestingOptions options = UnitTestingOptions.Instance.Clone(); |
|
||||||
IRegisteredTestFrameworks testFrameworks = TestService.RegisteredTestFrameworks; |
|
||||||
UnitTestTaskService taskService = new UnitTestTaskService(); |
|
||||||
UnitTestWorkbench workbench = new UnitTestWorkbench(); |
|
||||||
UnitTestBuildProjectFactory buildProjectFactory = new UnitTestBuildProjectFactory(); |
|
||||||
UnitTestBuildOptions buildOptions = new UnitTestBuildOptions(); |
|
||||||
MessageViewCategory unitTestCategory = TestService.UnitTestMessageView; |
|
||||||
UnitTestSaveAllFilesCommand saveAllFilesCommand = new UnitTestSaveAllFilesCommand(); |
|
||||||
IStatusBarService statusBarService = SD.StatusBar; |
|
||||||
|
|
||||||
public IRegisteredTestFrameworks RegisteredTestFrameworks { |
|
||||||
get { return testFrameworks; } |
|
||||||
} |
|
||||||
|
|
||||||
public IUnitTestTaskService TaskService { |
|
||||||
get { return taskService; } |
|
||||||
} |
|
||||||
|
|
||||||
public IUnitTestWorkbench Workbench { |
|
||||||
get { return workbench; } |
|
||||||
} |
|
||||||
|
|
||||||
public IBuildProjectFactory BuildProjectFactory { |
|
||||||
get { return buildProjectFactory; } |
|
||||||
} |
|
||||||
|
|
||||||
public IBuildOptions BuildOptions { |
|
||||||
get { return buildOptions; } |
|
||||||
} |
|
||||||
|
|
||||||
public MessageViewCategory UnitTestCategory { |
|
||||||
get { return unitTestCategory; } |
|
||||||
} |
|
||||||
|
|
||||||
public IUnitTestsPad OpenUnitTestsPad { |
|
||||||
get { return null; } |
|
||||||
} |
|
||||||
|
|
||||||
public IMessageService MessageService { |
|
||||||
get { return SD.MessageService; } |
|
||||||
} |
|
||||||
|
|
||||||
public IUnitTestSaveAllFilesCommand SaveAllFilesCommand { |
|
||||||
get { return saveAllFilesCommand; } |
|
||||||
} |
|
||||||
|
|
||||||
public IStatusBarService StatusBarService { |
|
||||||
get { return statusBarService; } |
|
||||||
} |
|
||||||
|
|
||||||
public Solution OpenSolution { |
|
||||||
get { return ProjectService.OpenSolution; } |
|
||||||
} |
|
||||||
} |
|
||||||
} |
|
||||||
@ -1,26 +0,0 @@ |
|||||||
// Copyright (c) AlphaSierraPapa for the SharpDevelop Team (for details please see \doc\copyright.txt)
|
|
||||||
// This code is distributed under the GNU LGPL (for details please see \doc\license.txt)
|
|
||||||
|
|
||||||
using System; |
|
||||||
using ICSharpCode.SharpDevelop.Project; |
|
||||||
using ICSharpCode.SharpDevelop.Util; |
|
||||||
|
|
||||||
namespace ICSharpCode.UnitTesting |
|
||||||
{ |
|
||||||
public class RunTestInPadCommand : AbstractRunTestCommand |
|
||||||
{ |
|
||||||
public RunTestInPadCommand() |
|
||||||
{ |
|
||||||
} |
|
||||||
|
|
||||||
public RunTestInPadCommand(IRunTestCommandContext context) |
|
||||||
: base(context) |
|
||||||
{ |
|
||||||
} |
|
||||||
|
|
||||||
protected override ITestRunner CreateTestRunner(IProject project) |
|
||||||
{ |
|
||||||
return Context.RegisteredTestFrameworks.CreateTestRunner(project); |
|
||||||
} |
|
||||||
} |
|
||||||
} |
|
||||||
@ -1,26 +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.Diagnostics; |
|
||||||
using ICSharpCode.SharpDevelop.Project; |
|
||||||
|
|
||||||
namespace ICSharpCode.UnitTesting |
|
||||||
{ |
|
||||||
public class RunTestWithDebuggerCommand : AbstractRunTestCommand |
|
||||||
{ |
|
||||||
public RunTestWithDebuggerCommand() |
|
||||||
{ |
|
||||||
} |
|
||||||
|
|
||||||
public RunTestWithDebuggerCommand(IRunTestCommandContext context) |
|
||||||
: base(context) |
|
||||||
{ |
|
||||||
} |
|
||||||
|
|
||||||
protected override ITestRunner CreateTestRunner(IProject project) |
|
||||||
{ |
|
||||||
return Context.RegisteredTestFrameworks.CreateTestDebugger(project); |
|
||||||
} |
|
||||||
} |
|
||||||
} |
|
||||||
@ -1,23 +0,0 @@ |
|||||||
// Copyright (c) AlphaSierraPapa for the SharpDevelop Team (for details please see \doc\copyright.txt)
|
|
||||||
// This code is distributed under the GNU LGPL (for details please see \doc\license.txt)
|
|
||||||
|
|
||||||
using System; |
|
||||||
using System.Collections.Generic; |
|
||||||
using ICSharpCode.NRefactory.TypeSystem; |
|
||||||
using ICSharpCode.SharpDevelop.Project; |
|
||||||
|
|
||||||
namespace ICSharpCode.UnitTesting |
|
||||||
{ |
|
||||||
public interface IRegisteredTestFrameworks |
|
||||||
{ |
|
||||||
ITestFramework GetTestFrameworkForProject(IProject project); |
|
||||||
ITestRunner CreateTestRunner(IProject project); |
|
||||||
ITestRunner CreateTestDebugger(IProject project); |
|
||||||
|
|
||||||
bool IsTestMember(IMember member); |
|
||||||
bool IsTestClass(ITypeDefinition typeDefinition); |
|
||||||
bool IsTestProject(IProject project); |
|
||||||
|
|
||||||
bool IsBuildNeededBeforeTestRunForProject(IProject project); |
|
||||||
} |
|
||||||
} |
|
||||||
@ -1,12 +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; |
|
||||||
|
|
||||||
namespace ICSharpCode.UnitTesting |
|
||||||
{ |
|
||||||
public interface ITestFrameworkFactory |
|
||||||
{ |
|
||||||
ITestFramework Create(string className); |
|
||||||
} |
|
||||||
} |
|
||||||
@ -0,0 +1,51 @@ |
|||||||
|
// 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.Threading.Tasks; |
||||||
|
using ICSharpCode.Core; |
||||||
|
using ICSharpCode.SharpDevelop.Gui; |
||||||
|
using ICSharpCode.SharpDevelop.Project; |
||||||
|
|
||||||
|
namespace ICSharpCode.UnitTesting |
||||||
|
{ |
||||||
|
[SDService] |
||||||
|
public interface ITestService |
||||||
|
{ |
||||||
|
/// <summary>
|
||||||
|
/// Gets the test framework that supports the specified project.
|
||||||
|
/// </summary>
|
||||||
|
ITestFramework GetTestFrameworkForProject(IProject project); |
||||||
|
|
||||||
|
MessageViewCategory UnitTestMessageView { get; } |
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets the current test solution.
|
||||||
|
/// This property should only be accessed by the main thread.
|
||||||
|
/// </summary>
|
||||||
|
ITestSolution OpenSolution { get; } |
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Occurs when the open test solution has changed.
|
||||||
|
/// </summary>
|
||||||
|
event EventHandler OpenSolutionChanged; |
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Builds the project (if necessary) and runs the specified tests.
|
||||||
|
/// If tests are already running, the existing run is cancelled.
|
||||||
|
/// </summary>
|
||||||
|
Task RunTestsAsync(IEnumerable<ITest> selectedTests, TestExecutionOptions options); |
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets whether tests are currently running.
|
||||||
|
/// </summary>
|
||||||
|
bool IsRunningTests { get; } |
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Aborts the current test run.
|
||||||
|
/// This method has no effect if no tests are running.
|
||||||
|
/// </summary>
|
||||||
|
void CancelRunningTests(); |
||||||
|
} |
||||||
|
} |
||||||
@ -1,99 +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; |
|
||||||
using ICSharpCode.SharpDevelop.Project; |
|
||||||
|
|
||||||
namespace ICSharpCode.UnitTesting |
|
||||||
{ |
|
||||||
public class RegisteredTestFrameworks : IRegisteredTestFrameworks |
|
||||||
{ |
|
||||||
IReadOnlyList<TestFrameworkDescriptor> testFrameworkDescriptors; |
|
||||||
public const string AddInPath = "/SharpDevelop/UnitTesting/TestFrameworks"; |
|
||||||
|
|
||||||
public RegisteredTestFrameworks(IAddInTree addInTree) |
|
||||||
{ |
|
||||||
testFrameworkDescriptors = addInTree.BuildItems<TestFrameworkDescriptor>(AddInPath, null); |
|
||||||
} |
|
||||||
|
|
||||||
public ITestFramework GetTestFrameworkForProject(IProject project) |
|
||||||
{ |
|
||||||
if (project != null) { |
|
||||||
foreach (TestFrameworkDescriptor descriptor in testFrameworkDescriptors) { |
|
||||||
if (descriptor.IsSupportedProject(project) && descriptor.TestFramework.IsTestProject(project)) { |
|
||||||
return descriptor.TestFramework; |
|
||||||
} |
|
||||||
} |
|
||||||
} |
|
||||||
return null; |
|
||||||
} |
|
||||||
|
|
||||||
public bool IsTestMember(IMember member) |
|
||||||
{ |
|
||||||
ITestFramework testFramework = GetTestFramework(member); |
|
||||||
if (testFramework != null) { |
|
||||||
return testFramework.IsTestMember(member); |
|
||||||
} |
|
||||||
return false; |
|
||||||
} |
|
||||||
|
|
||||||
ITestFramework GetTestFramework(IEntity entity) |
|
||||||
{ |
|
||||||
if (entity != null) { |
|
||||||
return GetTestFrameworkForProject(entity.ParentAssembly.GetProject()); |
|
||||||
} |
|
||||||
return null; |
|
||||||
} |
|
||||||
|
|
||||||
public bool IsTestClass(ITypeDefinition c) |
|
||||||
{ |
|
||||||
ITestFramework testFramework = GetTestFramework(c); |
|
||||||
if (testFramework != null) { |
|
||||||
return testFramework.IsTestClass(c); |
|
||||||
} |
|
||||||
return false; |
|
||||||
} |
|
||||||
|
|
||||||
public bool IsTestProject(IProject project) |
|
||||||
{ |
|
||||||
ITestFramework testFramework = GetTestFrameworkForProject(project); |
|
||||||
if (testFramework != null) { |
|
||||||
return testFramework.IsTestProject(project); |
|
||||||
} |
|
||||||
return false; |
|
||||||
} |
|
||||||
|
|
||||||
public ITestRunner CreateTestRunner(IProject project) |
|
||||||
{ |
|
||||||
ITestFramework testFramework = GetTestFrameworkForProject(project); |
|
||||||
if (testFramework != null) { |
|
||||||
return testFramework.CreateTestRunner(); |
|
||||||
} |
|
||||||
return null; |
|
||||||
} |
|
||||||
|
|
||||||
public ITestRunner CreateTestDebugger(IProject project) |
|
||||||
{ |
|
||||||
ITestFramework testFramework = GetTestFrameworkForProject(project); |
|
||||||
if (testFramework != null) { |
|
||||||
return testFramework.CreateTestDebugger(); |
|
||||||
} |
|
||||||
return null; |
|
||||||
} |
|
||||||
|
|
||||||
public bool IsBuildNeededBeforeTestRunForProject(IProject project) |
|
||||||
{ |
|
||||||
ITestFramework testFramework = GetTestFrameworkForProject(project); |
|
||||||
if (testFramework != null) { |
|
||||||
return testFramework.IsBuildNeededBeforeTestRun; |
|
||||||
} |
|
||||||
return true; |
|
||||||
} |
|
||||||
} |
|
||||||
} |
|
||||||
@ -0,0 +1,88 @@ |
|||||||
|
// 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.Threading; |
||||||
|
using System.Threading.Tasks; |
||||||
|
using ICSharpCode.SharpDevelop; |
||||||
|
using ICSharpCode.SharpDevelop.Gui; |
||||||
|
using ICSharpCode.SharpDevelop.Project; |
||||||
|
using ICSharpCode.UnitTesting.Frameworks; |
||||||
|
|
||||||
|
namespace ICSharpCode.UnitTesting |
||||||
|
{ |
||||||
|
sealed class SDTestService : ITestService |
||||||
|
{ |
||||||
|
#region Test Framework Management
|
||||||
|
const string AddInPath = "/SharpDevelop/UnitTesting/TestFrameworks"; |
||||||
|
IReadOnlyList<TestFrameworkDescriptor> testFrameworkDescriptors = SD.AddInTree.BuildItems<TestFrameworkDescriptor>(AddInPath, null); |
||||||
|
|
||||||
|
public ITestFramework GetTestFrameworkForProject(IProject project) |
||||||
|
{ |
||||||
|
if (project != null) { |
||||||
|
foreach (TestFrameworkDescriptor descriptor in testFrameworkDescriptors) { |
||||||
|
if (descriptor.IsSupportedProject(project)) { |
||||||
|
return descriptor.TestFramework; |
||||||
|
} |
||||||
|
} |
||||||
|
} |
||||||
|
return null; |
||||||
|
} |
||||||
|
#endregion
|
||||||
|
|
||||||
|
#region UnitTestMessageView
|
||||||
|
MessageViewCategory unitTestMessageView; |
||||||
|
|
||||||
|
public MessageViewCategory UnitTestMessageView { |
||||||
|
get { |
||||||
|
if (unitTestMessageView == null) { |
||||||
|
MessageViewCategory.Create(ref unitTestMessageView, |
||||||
|
"UnitTesting", |
||||||
|
"${res:ICSharpCode.NUnitPad.NUnitPadContent.PadName}"); |
||||||
|
} |
||||||
|
return unitTestMessageView; |
||||||
|
} |
||||||
|
} |
||||||
|
#endregion
|
||||||
|
|
||||||
|
#region OpenSolution
|
||||||
|
TestSolution solution; |
||||||
|
|
||||||
|
public ITestSolution OpenSolution { |
||||||
|
get { |
||||||
|
SD.MainThread.VerifyAccess(); |
||||||
|
if (solution == null) |
||||||
|
solution = new TestSolution(this, SD.ResourceService); |
||||||
|
return solution; |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
public event EventHandler OpenSolutionChanged { add {} remove {} } |
||||||
|
#endregion
|
||||||
|
|
||||||
|
#region RunTests
|
||||||
|
CancellationTokenSource runTestsCancellationTokenSource; |
||||||
|
|
||||||
|
public bool IsRunningTests { |
||||||
|
get { return runTestsCancellationTokenSource != null; } |
||||||
|
} |
||||||
|
|
||||||
|
public Task RunTestsAsync(IEnumerable<ITest> selectedTests, TestExecutionOptions options) |
||||||
|
{ |
||||||
|
CancelRunningTests(); |
||||||
|
runTestsCancellationTokenSource = new CancellationTokenSource(); |
||||||
|
var executionManager = new TestExecutionManager(); |
||||||
|
return executionManager.RunTestsAsync(selectedTests, options, runTestsCancellationTokenSource.Token); |
||||||
|
} |
||||||
|
|
||||||
|
public void CancelRunningTests() |
||||||
|
{ |
||||||
|
if (runTestsCancellationTokenSource != null) { |
||||||
|
runTestsCancellationTokenSource.Cancel(); |
||||||
|
runTestsCancellationTokenSource = null; |
||||||
|
} |
||||||
|
} |
||||||
|
#endregion
|
||||||
|
} |
||||||
|
} |
||||||
@ -0,0 +1,149 @@ |
|||||||
|
// 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.Diagnostics; |
||||||
|
using System.Linq; |
||||||
|
using System.Threading; |
||||||
|
using System.Threading.Tasks; |
||||||
|
|
||||||
|
using ICSharpCode.Core; |
||||||
|
using ICSharpCode.NRefactory.Utils; |
||||||
|
using ICSharpCode.SharpDevelop; |
||||||
|
using ICSharpCode.SharpDevelop.Gui; |
||||||
|
using ICSharpCode.SharpDevelop.Project; |
||||||
|
|
||||||
|
namespace ICSharpCode.UnitTesting.Frameworks |
||||||
|
{ |
||||||
|
/// <summary>
|
||||||
|
/// Manages the execution of tests across multiple projects.
|
||||||
|
/// Takes care of building the projects (if necessary) and showing progress in the UI.
|
||||||
|
/// </summary>
|
||||||
|
public class TestExecutionManager |
||||||
|
{ |
||||||
|
readonly IBuildProjectFactory buildProjectFactory; |
||||||
|
readonly IUnitTestTaskService taskService; |
||||||
|
readonly IUnitTestSaveAllFilesCommand saveAllFilesCommand; |
||||||
|
readonly ITestService testService; |
||||||
|
readonly IWorkbench workbench; |
||||||
|
readonly IStatusBarService statusBarService; |
||||||
|
readonly IBuildOptions buildOptions; |
||||||
|
|
||||||
|
public TestExecutionManager() |
||||||
|
{ |
||||||
|
this.buildProjectFactory = new UnitTestBuildProjectFactory(); |
||||||
|
this.taskService = new UnitTestTaskService(); |
||||||
|
this.saveAllFilesCommand = new UnitTestSaveAllFilesCommand(); |
||||||
|
this.testService = SD.GetRequiredService<ITestService>(); |
||||||
|
this.workbench = SD.Workbench; |
||||||
|
this.statusBarService = SD.StatusBar; |
||||||
|
this.buildOptions = new UnitTestBuildOptions(); |
||||||
|
} |
||||||
|
|
||||||
|
readonly MultiDictionary<ITestProject, ITest> testsByProject = new MultiDictionary<ITestProject, ITest>(); |
||||||
|
CancellationToken cancellationToken; |
||||||
|
|
||||||
|
public async Task RunTestsAsync(IEnumerable<ITest> selectedTests, TestExecutionOptions options, CancellationToken cancellationToken) |
||||||
|
{ |
||||||
|
this.cancellationToken = cancellationToken; |
||||||
|
GroupTestsByProject(selectedTests); |
||||||
|
|
||||||
|
ClearTasks(); |
||||||
|
ShowUnitTestsPad(); |
||||||
|
ShowOutputPad(); |
||||||
|
|
||||||
|
ResetTestResults(); |
||||||
|
saveAllFilesCommand.SaveAllFiles(); |
||||||
|
|
||||||
|
// Run the build, if necessary:
|
||||||
|
var projectsToBuild = testsByProject.Keys.Select(p => p.GetBuildableForTesting()).Where(b => b != null).ToList(); |
||||||
|
if (projectsToBuild.Count > 0) { |
||||||
|
var buildCommand = buildProjectFactory.CreateBuildProjectBeforeTestRun(projectsToBuild); |
||||||
|
var buildResults = await buildCommand.BuildAsync(cancellationToken); |
||||||
|
if (buildResults.Result != BuildResultCode.Success) |
||||||
|
return; |
||||||
|
} |
||||||
|
|
||||||
|
cancellationToken.ThrowIfCancellationRequested(); |
||||||
|
using (IProgressMonitor progressMonitor = statusBarService.CreateProgressMonitor(cancellationToken)) { |
||||||
|
int projectsLeftToRun = testsByProject.Count; |
||||||
|
foreach (IGrouping<ITestProject, ITest> g in testsByProject) { |
||||||
|
ITestProject project = g.Key; |
||||||
|
progressMonitor.TaskName = GetProgressMonitorLabel(project); |
||||||
|
progressMonitor.Progress = GetProgress(projectsLeftToRun); |
||||||
|
using (IProgressMonitor nested = progressMonitor.CreateSubTask(1.0 / testsByProject.Count)) { |
||||||
|
await project.RunTestsAsync(g, options, nested); |
||||||
|
} |
||||||
|
projectsLeftToRun--; |
||||||
|
progressMonitor.CancellationToken.ThrowIfCancellationRequested(); |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
ShowErrorList(); |
||||||
|
} |
||||||
|
|
||||||
|
void GroupTestsByProject(IEnumerable<ITest> selectedTests) |
||||||
|
{ |
||||||
|
foreach (ITest test in selectedTests) { |
||||||
|
if (test == null) |
||||||
|
continue; |
||||||
|
if (test.ParentProject == null) { |
||||||
|
// When a solution is selected, select all its projects individually
|
||||||
|
foreach (ITest project in test.NestedTests) { |
||||||
|
Debug.Assert(project == project.ParentProject); |
||||||
|
testsByProject.Add(project.ParentProject, project); |
||||||
|
} |
||||||
|
} else { |
||||||
|
testsByProject.Add(test.ParentProject, test); |
||||||
|
} |
||||||
|
cancellationToken.ThrowIfCancellationRequested(); |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
void ClearTasks() |
||||||
|
{ |
||||||
|
taskService.BuildMessageViewCategory.ClearText(); |
||||||
|
taskService.ClearExceptCommentTasks(); |
||||||
|
testService.UnitTestMessageView.ClearText(); |
||||||
|
} |
||||||
|
|
||||||
|
void ShowUnitTestsPad() |
||||||
|
{ |
||||||
|
workbench.GetPad(typeof(UnitTestsPad)).BringPadToFront(); |
||||||
|
} |
||||||
|
|
||||||
|
void ShowOutputPad() |
||||||
|
{ |
||||||
|
workbench.GetPad(typeof(CompilerMessageView)).BringPadToFront(); |
||||||
|
} |
||||||
|
|
||||||
|
void ResetTestResults() |
||||||
|
{ |
||||||
|
cancellationToken.ThrowIfCancellationRequested(); |
||||||
|
foreach (ITest test in testsByProject.Values) { |
||||||
|
test.ResetTestResults(); |
||||||
|
} |
||||||
|
cancellationToken.ThrowIfCancellationRequested(); |
||||||
|
} |
||||||
|
|
||||||
|
string GetProgressMonitorLabel(ITestProject project) |
||||||
|
{ |
||||||
|
StringTagPair tagPair = new StringTagPair("Name", project.DisplayName); |
||||||
|
return StringParser.Parse("${res:ICSharpCode.UnitTesting.StatusBarProgressLabel}", tagPair); |
||||||
|
} |
||||||
|
|
||||||
|
double GetProgress(int projectsLeftToRunCount) |
||||||
|
{ |
||||||
|
int totalProjectCount = testsByProject.Count; |
||||||
|
return (double)(totalProjectCount - projectsLeftToRunCount) / totalProjectCount; |
||||||
|
} |
||||||
|
|
||||||
|
void ShowErrorList() |
||||||
|
{ |
||||||
|
if (taskService.SomethingWentWrong && buildOptions.ShowErrorListAfterBuild) { |
||||||
|
workbench.GetPad(typeof(ErrorListPad)).BringPadToFront(); |
||||||
|
} |
||||||
|
} |
||||||
|
} |
||||||
|
} |
||||||
@ -0,0 +1,19 @@ |
|||||||
|
// 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 |
||||||
|
{ |
||||||
|
/// <summary>
|
||||||
|
/// Options used for test execution.
|
||||||
|
/// </summary>
|
||||||
|
public class TestExecutionOptions |
||||||
|
{ |
||||||
|
/// <summary>
|
||||||
|
/// Gets/Sets whether to debug the test execution.
|
||||||
|
/// The default is <c>false</c>.
|
||||||
|
/// </summary>
|
||||||
|
public bool UseDebugger { get; set; } |
||||||
|
} |
||||||
|
} |
||||||
@ -1,23 +0,0 @@ |
|||||||
// Copyright (c) AlphaSierraPapa for the SharpDevelop Team (for details please see \doc\copyright.txt)
|
|
||||||
// This code is distributed under the GNU LGPL (for details please see \doc\license.txt)
|
|
||||||
|
|
||||||
using System; |
|
||||||
using ICSharpCode.Core; |
|
||||||
|
|
||||||
namespace ICSharpCode.UnitTesting |
|
||||||
{ |
|
||||||
public class TestFrameworkFactory : ITestFrameworkFactory |
|
||||||
{ |
|
||||||
AddIn addin; |
|
||||||
|
|
||||||
public TestFrameworkFactory(AddIn addin) |
|
||||||
{ |
|
||||||
this.addin = addin; |
|
||||||
} |
|
||||||
|
|
||||||
public ITestFramework Create(string className) |
|
||||||
{ |
|
||||||
return addin.CreateObject(className) as ITestFramework; |
|
||||||
} |
|
||||||
} |
|
||||||
} |
|
||||||
@ -1,57 +0,0 @@ |
|||||||
// Copyright (c) AlphaSierraPapa for the SharpDevelop Team (for details please see \doc\copyright.txt)
|
|
||||||
// This code is distributed under the GNU LGPL (for details please see \doc\license.txt)
|
|
||||||
|
|
||||||
using System; |
|
||||||
using ICSharpCode.SharpDevelop; |
|
||||||
using ICSharpCode.SharpDevelop.Gui; |
|
||||||
|
|
||||||
namespace ICSharpCode.UnitTesting |
|
||||||
{ |
|
||||||
public static class TestService |
|
||||||
{ |
|
||||||
static IRegisteredTestFrameworks testFrameworks; |
|
||||||
static MessageViewCategory unitTestMessageView; |
|
||||||
|
|
||||||
public static IRegisteredTestFrameworks RegisteredTestFrameworks { |
|
||||||
get { |
|
||||||
CreateRegisteredTestFrameworks(); |
|
||||||
return testFrameworks; |
|
||||||
} |
|
||||||
set { testFrameworks = value; } |
|
||||||
} |
|
||||||
|
|
||||||
static void CreateRegisteredTestFrameworks() |
|
||||||
{ |
|
||||||
if (testFrameworks == null) { |
|
||||||
testFrameworks = new RegisteredTestFrameworks(SD.AddInTree); |
|
||||||
} |
|
||||||
} |
|
||||||
|
|
||||||
public static MessageViewCategory UnitTestMessageView { |
|
||||||
get { |
|
||||||
if (unitTestMessageView == null) { |
|
||||||
CreateUnitTestCategory(); |
|
||||||
} |
|
||||||
return unitTestMessageView; |
|
||||||
} |
|
||||||
} |
|
||||||
|
|
||||||
static void CreateUnitTestCategory() |
|
||||||
{ |
|
||||||
MessageViewCategory.Create(ref unitTestMessageView, |
|
||||||
"UnitTesting", |
|
||||||
"${res:ICSharpCode.NUnitPad.NUnitPadContent.PadName}"); |
|
||||||
} |
|
||||||
|
|
||||||
static TestSolution solution; |
|
||||||
|
|
||||||
public static TestSolution Solution { |
|
||||||
get { |
|
||||||
SD.MainThread.VerifyAccess(); |
|
||||||
if (solution == null) |
|
||||||
solution = new TestSolution(RegisteredTestFrameworks); |
|
||||||
return solution; |
|
||||||
} |
|
||||||
} |
|
||||||
} |
|
||||||
} |
|
||||||
@ -1,15 +0,0 @@ |
|||||||
// Copyright (c) AlphaSierraPapa for the SharpDevelop Team (for details please see \doc\copyright.txt)
|
|
||||||
// This code is distributed under the GNU LGPL (for details please see \doc\license.txt)
|
|
||||||
|
|
||||||
using System; |
|
||||||
using ICSharpCode.SharpDevelop; |
|
||||||
|
|
||||||
namespace ICSharpCode.UnitTesting |
|
||||||
{ |
|
||||||
public interface IUnitTestWorkbench |
|
||||||
{ |
|
||||||
PadDescriptor GetPad(Type type); |
|
||||||
void SafeThreadAsyncCall(Action method); |
|
||||||
void SafeThreadAsyncCall<A>(Action<A> method, A arg1); |
|
||||||
} |
|
||||||
} |
|
||||||
@ -1,27 +0,0 @@ |
|||||||
// Copyright (c) AlphaSierraPapa for the SharpDevelop Team (for details please see \doc\copyright.txt)
|
|
||||||
// This code is distributed under the GNU LGPL (for details please see \doc\license.txt)
|
|
||||||
|
|
||||||
using System; |
|
||||||
using ICSharpCode.SharpDevelop; |
|
||||||
using ICSharpCode.SharpDevelop.Gui; |
|
||||||
|
|
||||||
namespace ICSharpCode.UnitTesting |
|
||||||
{ |
|
||||||
public class UnitTestWorkbench : IUnitTestWorkbench |
|
||||||
{ |
|
||||||
public PadDescriptor GetPad(Type type) |
|
||||||
{ |
|
||||||
return WorkbenchSingleton.Workbench.GetPad(type); |
|
||||||
} |
|
||||||
|
|
||||||
public void SafeThreadAsyncCall(Action method) |
|
||||||
{ |
|
||||||
WorkbenchSingleton.SafeThreadAsyncCall(method); |
|
||||||
} |
|
||||||
|
|
||||||
public void SafeThreadAsyncCall<A>(Action<A> method, A arg1) |
|
||||||
{ |
|
||||||
WorkbenchSingleton.SafeThreadAsyncCall(method, arg1); |
|
||||||
} |
|
||||||
} |
|
||||||
} |
|
||||||
@ -0,0 +1,55 @@ |
|||||||
|
// 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.ObjectModel; |
||||||
|
|
||||||
|
namespace ICSharpCode.UnitTesting |
||||||
|
{ |
||||||
|
/// <summary>
|
||||||
|
/// Represents a unit test or a group of unit tests.
|
||||||
|
/// </summary>
|
||||||
|
public interface ITest |
||||||
|
{ |
||||||
|
/// <summary>
|
||||||
|
/// Gets the collection of nested tests.
|
||||||
|
/// </summary>
|
||||||
|
TestCollection NestedTests { get; } |
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets the parent project that owns this test.
|
||||||
|
/// </summary>
|
||||||
|
ITestProject ParentProject { get; } |
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Name to be displayed in the tests tree view.
|
||||||
|
/// </summary>
|
||||||
|
string DisplayName { get; } |
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Raised when the <see cref="Name"/> property changes.
|
||||||
|
/// </summary>
|
||||||
|
event EventHandler DisplayNameChanged; |
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets the result of the previous run of this test.
|
||||||
|
/// </summary>
|
||||||
|
TestResultType Result { get; } |
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Raised when the <see cref="Result"/> property changes.
|
||||||
|
/// </summary>
|
||||||
|
event EventHandler<TestResultTypeChangedEventArgs> ResultChanged; |
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Resets the test results for this test and all nested tests.
|
||||||
|
/// </summary>
|
||||||
|
void ResetTestResults(); |
||||||
|
|
||||||
|
bool SupportsGoToDefinition { get; } |
||||||
|
|
||||||
|
void GoToDefinition(); |
||||||
|
|
||||||
|
UnitTestNode CreateTreeNode(); |
||||||
|
} |
||||||
|
} |
||||||
@ -0,0 +1,47 @@ |
|||||||
|
// 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.Threading; |
||||||
|
using System.Threading.Tasks; |
||||||
|
using ICSharpCode.NRefactory.TypeSystem; |
||||||
|
using ICSharpCode.SharpDevelop.Gui; |
||||||
|
using ICSharpCode.SharpDevelop.Project; |
||||||
|
|
||||||
|
namespace ICSharpCode.UnitTesting |
||||||
|
{ |
||||||
|
/// <summary>
|
||||||
|
/// Represents the root node of a test project.
|
||||||
|
/// </summary>
|
||||||
|
public interface ITestProject : ITest |
||||||
|
{ |
||||||
|
/// <summary>
|
||||||
|
/// Gets the SharpDevelop project on which this test project is based.
|
||||||
|
/// </summary>
|
||||||
|
IProject Project { get; } |
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets the test for the specified entity.
|
||||||
|
/// Returns null if the entity is not a unit test.
|
||||||
|
/// </summary>
|
||||||
|
ITest GetTestForEntity(IEntity entity); |
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Returns a SharpDevelop <see cref="IBuildable"/> that builds the project
|
||||||
|
/// for test execution.
|
||||||
|
/// May return null if the project does not require compilation.
|
||||||
|
/// </summary>
|
||||||
|
IBuildable GetBuildableForTesting(); |
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Notifies the project that the parse information was changed.
|
||||||
|
/// </summary>
|
||||||
|
void NotifyParseInformationChanged(IUnresolvedFile oldUnresolvedFile, IUnresolvedFile newUnresolvedFile); |
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Runs the specified tests. The specified tests must belong to this project.
|
||||||
|
/// </summary>
|
||||||
|
Task RunTestsAsync(IEnumerable<ITest> tests, TestExecutionOptions options, IProgressMonitor progressMonitor); |
||||||
|
} |
||||||
|
} |
||||||
@ -0,0 +1,33 @@ |
|||||||
|
// 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.ObjectModel; |
||||||
|
using ICSharpCode.NRefactory.TypeSystem; |
||||||
|
using ICSharpCode.SharpDevelop.Project; |
||||||
|
|
||||||
|
namespace ICSharpCode.UnitTesting |
||||||
|
{ |
||||||
|
/// <summary>
|
||||||
|
/// A test that represents the whole solution.
|
||||||
|
/// </summary>
|
||||||
|
public interface ITestSolution : ITest |
||||||
|
{ |
||||||
|
// /// <summary>
|
||||||
|
// /// Gets the list of all test projects.
|
||||||
|
// /// </summary>
|
||||||
|
// ObservableCollection<ITestProject> TestableProjects { get; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets the test project for the specified project.
|
||||||
|
/// Returns null if the project is not a test project.
|
||||||
|
/// </summary>
|
||||||
|
ITestProject GetTestProject(IProject project); |
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets the test for the specified entity.
|
||||||
|
/// Returns null if the entity is not a unit test.
|
||||||
|
/// </summary>
|
||||||
|
ITest GetTestForEntity(IEntity entity); |
||||||
|
} |
||||||
|
} |
||||||
@ -0,0 +1,143 @@ |
|||||||
|
// 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.ObjectModel; |
||||||
|
using System.ComponentModel; |
||||||
|
|
||||||
|
namespace ICSharpCode.UnitTesting |
||||||
|
{ |
||||||
|
/// <summary>
|
||||||
|
/// Base class for <see cref="ITest"/> implementations.
|
||||||
|
/// </summary>
|
||||||
|
public abstract class TestBase : ITest |
||||||
|
{ |
||||||
|
public abstract string DisplayName { get; } |
||||||
|
public virtual event EventHandler DisplayNameChanged { add {} remove {} } |
||||||
|
|
||||||
|
public abstract ITestProject ParentProject { get; } |
||||||
|
|
||||||
|
#region Result
|
||||||
|
TestResultType result; |
||||||
|
bool useCompositeResultsOfNestedTests; |
||||||
|
|
||||||
|
public event EventHandler<TestResultTypeChangedEventArgs> ResultChanged; |
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets/Sets the test result.
|
||||||
|
/// </summary>
|
||||||
|
/// <remarks>
|
||||||
|
/// If the result is bound to the composite of the nested tests, setting this
|
||||||
|
/// property will remove the binding.
|
||||||
|
/// </remarks>
|
||||||
|
public TestResultType Result { |
||||||
|
get { return result; } |
||||||
|
protected set { |
||||||
|
if (useCompositeResultsOfNestedTests) { |
||||||
|
nestedTests.PropertyChanged -= nestedTestsCollection_PropertyChanged; |
||||||
|
useCompositeResultsOfNestedTests = false; |
||||||
|
} |
||||||
|
ChangeResult(value); |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
void ChangeResult(TestResultType newResult) |
||||||
|
{ |
||||||
|
TestResultType oldResult = result; |
||||||
|
if (oldResult != newResult) { |
||||||
|
result = newResult; |
||||||
|
OnResultChanged(new TestResultTypeChangedEventArgs(oldResult, newResult)); |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Binds the result to the composite result of the nested tests.
|
||||||
|
/// </summary>
|
||||||
|
protected void BindResultToCompositeResultOfNestedTests() |
||||||
|
{ |
||||||
|
if (!useCompositeResultsOfNestedTests) { |
||||||
|
useCompositeResultsOfNestedTests = true; |
||||||
|
if (nestedTests != null) { |
||||||
|
nestedTests.PropertyChanged += nestedTestsCollection_PropertyChanged; |
||||||
|
ChangeResult(nestedTests.CompositeResult); |
||||||
|
} else { |
||||||
|
ChangeResult(TestResultType.None); |
||||||
|
} |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
void nestedTestsCollection_PropertyChanged(object sender, PropertyChangedEventArgs e) |
||||||
|
{ |
||||||
|
if (e.PropertyName == null || e.PropertyName == "CompositeResult") { |
||||||
|
ChangeResult(nestedTests.CompositeResult); |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
protected virtual void OnResultChanged(TestResultTypeChangedEventArgs e) |
||||||
|
{ |
||||||
|
if (ResultChanged != null) { |
||||||
|
ResultChanged(this, e); |
||||||
|
} |
||||||
|
} |
||||||
|
#endregion
|
||||||
|
|
||||||
|
#region NestedTests
|
||||||
|
TestCollection nestedTests; |
||||||
|
|
||||||
|
public TestCollection NestedTests { |
||||||
|
get { |
||||||
|
if (nestedTests == null) { |
||||||
|
nestedTests = InitializeNestedTests(); |
||||||
|
OnNestedTestsInitialized(); |
||||||
|
} |
||||||
|
return nestedTests; |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
protected bool NestedTestsInitialized { |
||||||
|
get { return nestedTests != null; } |
||||||
|
} |
||||||
|
|
||||||
|
protected virtual TestCollection InitializeNestedTests() |
||||||
|
{ |
||||||
|
return new TestCollection(); |
||||||
|
} |
||||||
|
|
||||||
|
protected virtual void OnNestedTestsInitialized() |
||||||
|
{ |
||||||
|
// If we're supposed to be bound to the composite result of the nested tests,
|
||||||
|
// but the nested test collection wasn't initialized yet,
|
||||||
|
// we will recreate the binding.
|
||||||
|
if (useCompositeResultsOfNestedTests) { |
||||||
|
useCompositeResultsOfNestedTests = false; |
||||||
|
BindResultToCompositeResultOfNestedTests(); |
||||||
|
} |
||||||
|
} |
||||||
|
#endregion
|
||||||
|
|
||||||
|
public virtual void ResetTestResults() |
||||||
|
{ |
||||||
|
if (nestedTests != null) { |
||||||
|
foreach (ITest test in nestedTests) { |
||||||
|
test.ResetTestResults(); |
||||||
|
} |
||||||
|
} |
||||||
|
if (!useCompositeResultsOfNestedTests) |
||||||
|
this.Result = TestResultType.None; |
||||||
|
} |
||||||
|
|
||||||
|
public virtual bool SupportsGoToDefinition { |
||||||
|
get { return false; } |
||||||
|
} |
||||||
|
|
||||||
|
public void GoToDefinition() |
||||||
|
{ |
||||||
|
throw new NotSupportedException(); |
||||||
|
} |
||||||
|
|
||||||
|
public virtual UnitTestNode CreateTreeNode() |
||||||
|
{ |
||||||
|
return new UnitTestNode(this); |
||||||
|
} |
||||||
|
} |
||||||
|
} |
||||||
@ -0,0 +1,199 @@ |
|||||||
|
// 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.Collections.Specialized; |
||||||
|
using System.ComponentModel; |
||||||
|
|
||||||
|
namespace ICSharpCode.UnitTesting |
||||||
|
{ |
||||||
|
/// <summary>
|
||||||
|
/// Collection of tests that monitors the amount of tests for each result type,
|
||||||
|
/// allowing efficient updates of the overall result.
|
||||||
|
/// </summary>
|
||||||
|
public class TestCollection : ObservableCollection<ITest> |
||||||
|
{ |
||||||
|
#region Struct TestCounts
|
||||||
|
struct TestCounts |
||||||
|
{ |
||||||
|
internal int indeterminate; |
||||||
|
internal int successful; |
||||||
|
internal int failed; |
||||||
|
internal int ignored; |
||||||
|
|
||||||
|
public TestResultType CompositeResult { |
||||||
|
get { |
||||||
|
if (failed > 0) |
||||||
|
return TestResultType.Failure; |
||||||
|
if (indeterminate > 0) |
||||||
|
return TestResultType.None; |
||||||
|
if (ignored > 0) |
||||||
|
return TestResultType.Ignored; |
||||||
|
if (successful > 0) |
||||||
|
return TestResultType.Success; |
||||||
|
return TestResultType.None; |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
public void Add(TestResultType result) |
||||||
|
{ |
||||||
|
switch (result) { |
||||||
|
case TestResultType.None: |
||||||
|
indeterminate++; |
||||||
|
break; |
||||||
|
case TestResultType.Success: |
||||||
|
successful++; |
||||||
|
break; |
||||||
|
case TestResultType.Failure: |
||||||
|
failed++; |
||||||
|
break; |
||||||
|
case TestResultType.Ignored: |
||||||
|
ignored++; |
||||||
|
break; |
||||||
|
default: |
||||||
|
throw new NotSupportedException("Invalid value for TestResultType"); |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
public void Remove(TestResultType result) |
||||||
|
{ |
||||||
|
switch (result) { |
||||||
|
case TestResultType.None: |
||||||
|
indeterminate--; |
||||||
|
break; |
||||||
|
case TestResultType.Success: |
||||||
|
successful--; |
||||||
|
break; |
||||||
|
case TestResultType.Failure: |
||||||
|
failed--; |
||||||
|
break; |
||||||
|
case TestResultType.Ignored: |
||||||
|
ignored--; |
||||||
|
break; |
||||||
|
default: |
||||||
|
throw new NotSupportedException("Invalid value for TestResultType"); |
||||||
|
} |
||||||
|
} |
||||||
|
} |
||||||
|
#endregion
|
||||||
|
|
||||||
|
public static TestResultType GetCompositeResult(IEnumerable<ITest> tests) |
||||||
|
{ |
||||||
|
TestCounts c = new TestCounts(); |
||||||
|
foreach (ITest test in tests) { |
||||||
|
c.Add(test.Result); |
||||||
|
} |
||||||
|
return c.CompositeResult; |
||||||
|
} |
||||||
|
|
||||||
|
#region Properties
|
||||||
|
TestCounts counts; |
||||||
|
|
||||||
|
public int IndeterminateNestedTestCount { |
||||||
|
get { return counts.indeterminate; } |
||||||
|
} |
||||||
|
|
||||||
|
public int SuccessfulNestedTestCount { |
||||||
|
get { return counts.successful; } |
||||||
|
} |
||||||
|
|
||||||
|
public int FailedNestedTestCount { |
||||||
|
get { return counts.failed; } |
||||||
|
} |
||||||
|
|
||||||
|
public int IgnoredNestedTestCount { |
||||||
|
get { return counts.ignored; } |
||||||
|
} |
||||||
|
|
||||||
|
public TestResultType CompositeResult { |
||||||
|
get { return counts.CompositeResult; } |
||||||
|
} |
||||||
|
|
||||||
|
static readonly PropertyChangedEventArgs indeterminateArgs = new PropertyChangedEventArgs("IndeterminateNestedTestCount"); |
||||||
|
static readonly PropertyChangedEventArgs successfulArgs = new PropertyChangedEventArgs("SuccessfulNestedTestCount"); |
||||||
|
static readonly PropertyChangedEventArgs failedArgs = new PropertyChangedEventArgs("FailedNestedTestCount"); |
||||||
|
static readonly PropertyChangedEventArgs ignoredArgs = new PropertyChangedEventArgs("IgnoredNestedTestCount"); |
||||||
|
static readonly PropertyChangedEventArgs compositeResultArgs = new PropertyChangedEventArgs("CompositeResult"); |
||||||
|
|
||||||
|
void RaiseCountChangeEvents(TestCounts old) |
||||||
|
{ |
||||||
|
if (old.indeterminate != counts.indeterminate) |
||||||
|
OnPropertyChanged(indeterminateArgs); |
||||||
|
if (old.successful != counts.successful) |
||||||
|
OnPropertyChanged(successfulArgs); |
||||||
|
if (old.failed != counts.failed) |
||||||
|
OnPropertyChanged(failedArgs); |
||||||
|
if (old.ignored != counts.ignored) |
||||||
|
OnPropertyChanged(ignoredArgs); |
||||||
|
if (old.CompositeResult != counts.CompositeResult) |
||||||
|
OnPropertyChanged(compositeResultArgs); |
||||||
|
} |
||||||
|
|
||||||
|
// change visibility of PropertyChanged event to public
|
||||||
|
public new event PropertyChangedEventHandler PropertyChanged { |
||||||
|
add { base.PropertyChanged += value; } |
||||||
|
remove { base.PropertyChanged -= value; } |
||||||
|
} |
||||||
|
#endregion
|
||||||
|
|
||||||
|
void item_ResultChanged(object sender, TestResultTypeChangedEventArgs e) |
||||||
|
{ |
||||||
|
TestCounts old = counts; |
||||||
|
counts.Remove(e.OldResult); |
||||||
|
counts.Add(e.NewResult); |
||||||
|
RaiseCountChangeEvents(old); |
||||||
|
} |
||||||
|
|
||||||
|
protected override void ClearItems() |
||||||
|
{ |
||||||
|
TestCounts old = counts; |
||||||
|
counts = default(TestCounts); |
||||||
|
foreach (ITest test in Items) { |
||||||
|
counts.Remove(test.Result); |
||||||
|
test.ResultChanged -= item_ResultChanged; |
||||||
|
} |
||||||
|
base.ClearItems(); |
||||||
|
RaiseCountChangeEvents(old); |
||||||
|
} |
||||||
|
|
||||||
|
protected override void InsertItem(int index, ITest item) |
||||||
|
{ |
||||||
|
if (item == null) |
||||||
|
throw new ArgumentNullException("item"); |
||||||
|
TestCounts old = counts; |
||||||
|
counts.Add(item.Result); |
||||||
|
base.InsertItem(index, item); |
||||||
|
item.ResultChanged += item_ResultChanged; |
||||||
|
RaiseCountChangeEvents(old); |
||||||
|
} |
||||||
|
|
||||||
|
protected override void RemoveItem(int index) |
||||||
|
{ |
||||||
|
TestCounts old = counts; |
||||||
|
ITest oldItem = Items[index]; |
||||||
|
counts.Remove(oldItem.Result); |
||||||
|
oldItem.ResultChanged -= item_ResultChanged; |
||||||
|
base.RemoveItem(index); |
||||||
|
RaiseCountChangeEvents(old); |
||||||
|
} |
||||||
|
|
||||||
|
protected override void SetItem(int index, ITest item) |
||||||
|
{ |
||||||
|
if (item == null) |
||||||
|
throw new ArgumentNullException("item"); |
||||||
|
TestCounts old = counts; |
||||||
|
|
||||||
|
ITest oldItem = Items[index]; |
||||||
|
counts.Remove(oldItem.Result); |
||||||
|
oldItem.ResultChanged -= item_ResultChanged; |
||||||
|
|
||||||
|
counts.Add(item.Result); |
||||||
|
item.ResultChanged += item_ResultChanged; |
||||||
|
|
||||||
|
base.SetItem(index, item); |
||||||
|
RaiseCountChangeEvents(old); |
||||||
|
} |
||||||
|
} |
||||||
|
} |
||||||
@ -0,0 +1,46 @@ |
|||||||
|
// 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.ObjectModel; |
||||||
|
|
||||||
|
namespace ICSharpCode.UnitTesting |
||||||
|
{ |
||||||
|
/// <summary>
|
||||||
|
/// Represents a namespace of unit tests.
|
||||||
|
/// </summary>
|
||||||
|
public class TestNamespace : TestBase |
||||||
|
{ |
||||||
|
readonly ITestProject project; |
||||||
|
readonly string namespaceName; |
||||||
|
readonly string displayName; |
||||||
|
|
||||||
|
public TestNamespace(ITestProject project, string namespaceName, string displayName = null) |
||||||
|
{ |
||||||
|
if (project == null) |
||||||
|
throw new ArgumentNullException("project"); |
||||||
|
if (namespaceName == null) |
||||||
|
throw new ArgumentNullException("namespaceName"); |
||||||
|
this.project = project; |
||||||
|
this.namespaceName = namespaceName; |
||||||
|
if (displayName != null) { |
||||||
|
this.displayName = displayName; |
||||||
|
} else { |
||||||
|
this.displayName = namespaceName.Substring(namespaceName.IndexOf('.') + 1); |
||||||
|
} |
||||||
|
BindResultToCompositeResultOfNestedTests(); |
||||||
|
} |
||||||
|
|
||||||
|
public override ITestProject ParentProject { |
||||||
|
get { return project; } |
||||||
|
} |
||||||
|
|
||||||
|
public string NamespaceName { |
||||||
|
get { return namespaceName; } |
||||||
|
} |
||||||
|
|
||||||
|
public override string DisplayName { |
||||||
|
get { return displayName; } |
||||||
|
} |
||||||
|
} |
||||||
|
} |
||||||
@ -0,0 +1,58 @@ |
|||||||
|
// 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.Threading.Tasks; |
||||||
|
using ICSharpCode.NRefactory.TypeSystem; |
||||||
|
using ICSharpCode.SharpDevelop.Gui; |
||||||
|
using ICSharpCode.SharpDevelop.Project; |
||||||
|
|
||||||
|
namespace ICSharpCode.UnitTesting |
||||||
|
{ |
||||||
|
/// <summary>
|
||||||
|
/// Base class for <see cref="ITestProject"/> implementations.
|
||||||
|
/// </summary>
|
||||||
|
public abstract class TestProjectBase : TestBase, ITestProject |
||||||
|
{ |
||||||
|
IProject project; |
||||||
|
|
||||||
|
public TestProjectBase(IProject project) |
||||||
|
{ |
||||||
|
if (project == null) |
||||||
|
throw new ArgumentNullException("project"); |
||||||
|
this.project = project; |
||||||
|
BindResultToCompositeResultOfNestedTests(); |
||||||
|
} |
||||||
|
|
||||||
|
public IProject Project { |
||||||
|
get { return project; } |
||||||
|
} |
||||||
|
|
||||||
|
public override ITestProject ParentProject { |
||||||
|
get { return this; } |
||||||
|
} |
||||||
|
|
||||||
|
public override string DisplayName { |
||||||
|
get { return project.Name; } |
||||||
|
} |
||||||
|
|
||||||
|
public virtual ITest GetTestForEntity(IEntity entity) |
||||||
|
{ |
||||||
|
return null; |
||||||
|
} |
||||||
|
|
||||||
|
public virtual IBuildable GetBuildableForTesting() |
||||||
|
{ |
||||||
|
return project; |
||||||
|
} |
||||||
|
|
||||||
|
public void NotifyParseInformationChanged(IUnresolvedFile oldUnresolvedFile, IUnresolvedFile newUnresolvedFile) |
||||||
|
{ |
||||||
|
if (!NestedTestsInitialized) |
||||||
|
return; |
||||||
|
} |
||||||
|
|
||||||
|
public abstract Task RunTestsAsync(IEnumerable<ITest> tests, TestExecutionOptions options, IProgressMonitor progressMonitor); |
||||||
|
} |
||||||
|
} |
||||||
@ -0,0 +1,30 @@ |
|||||||
|
// 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 |
||||||
|
{ |
||||||
|
/// <summary>
|
||||||
|
/// EventArgs for ITest.ResultChanged.
|
||||||
|
/// </summary>
|
||||||
|
public class TestResultTypeChangedEventArgs : EventArgs |
||||||
|
{ |
||||||
|
readonly TestResultType oldResult; |
||||||
|
readonly TestResultType newResult; |
||||||
|
|
||||||
|
public TestResultTypeChangedEventArgs(TestResultType oldResult, TestResultType newResult) |
||||||
|
{ |
||||||
|
this.oldResult = oldResult; |
||||||
|
this.newResult = newResult; |
||||||
|
} |
||||||
|
|
||||||
|
public TestResultType NewResult { |
||||||
|
get { return newResult; } |
||||||
|
} |
||||||
|
|
||||||
|
public TestResultType OldResult { |
||||||
|
get { return oldResult; } |
||||||
|
} |
||||||
|
} |
||||||
|
} |
||||||
@ -0,0 +1,26 @@ |
|||||||
|
// Copyright (c) AlphaSierraPapa for the SharpDevelop Team (for details please see \doc\copyright.txt)
|
||||||
|
// This code is distributed under the GNU LGPL (for details please see \doc\license.txt)
|
||||||
|
|
||||||
|
using System; |
||||||
|
using System.Collections.Generic; |
||||||
|
using System.Threading.Tasks; |
||||||
|
using ICSharpCode.SharpDevelop.Gui; |
||||||
|
using ICSharpCode.SharpDevelop.Project; |
||||||
|
|
||||||
|
namespace ICSharpCode.UnitTesting |
||||||
|
{ |
||||||
|
/// <summary>
|
||||||
|
/// NUnit test project.
|
||||||
|
/// </summary>
|
||||||
|
public class NUnitTestProject : TestProjectBase |
||||||
|
{ |
||||||
|
public NUnitTestProject(IProject project) : base(project) |
||||||
|
{ |
||||||
|
} |
||||||
|
|
||||||
|
public override Task RunTestsAsync(IEnumerable<ITest> tests, TestExecutionOptions options, IProgressMonitor progressMonitor) |
||||||
|
{ |
||||||
|
throw new NotImplementedException(); |
||||||
|
} |
||||||
|
} |
||||||
|
} |
||||||
@ -1,53 +0,0 @@ |
|||||||
// Copyright (c) AlphaSierraPapa for the SharpDevelop Team (for details please see \doc\copyright.txt)
|
|
||||||
// This code is distributed under the GNU LGPL (for details please see \doc\license.txt)
|
|
||||||
|
|
||||||
using System; |
|
||||||
using System.Linq; |
|
||||||
using ICSharpCode.SharpDevelop.Project; |
|
||||||
|
|
||||||
namespace ICSharpCode.UnitTesting |
|
||||||
{ |
|
||||||
public class EmptyUnitTestsPad : IUnitTestsPad |
|
||||||
{ |
|
||||||
Solution solution; |
|
||||||
|
|
||||||
public EmptyUnitTestsPad() |
|
||||||
: this(null) |
|
||||||
{ |
|
||||||
} |
|
||||||
|
|
||||||
public EmptyUnitTestsPad(Solution solution) |
|
||||||
{ |
|
||||||
this.solution = solution; |
|
||||||
} |
|
||||||
|
|
||||||
public void UpdateToolbar() |
|
||||||
{ |
|
||||||
} |
|
||||||
|
|
||||||
public void BringToFront() |
|
||||||
{ |
|
||||||
} |
|
||||||
|
|
||||||
public void ResetTestResults() |
|
||||||
{ |
|
||||||
} |
|
||||||
|
|
||||||
public IProject[] GetProjects() |
|
||||||
{ |
|
||||||
if (solution != null) { |
|
||||||
return solution.Projects.ToArray(); |
|
||||||
} |
|
||||||
return new IProject[0]; |
|
||||||
} |
|
||||||
|
|
||||||
public TestProject GetTestProject(IProject project) |
|
||||||
{ |
|
||||||
return null; |
|
||||||
} |
|
||||||
|
|
||||||
public void CollapseAll() |
|
||||||
{ |
|
||||||
} |
|
||||||
} |
|
||||||
} |
|
||||||
@ -1,18 +0,0 @@ |
|||||||
// Copyright (c) AlphaSierraPapa for the SharpDevelop Team (for details please see \doc\copyright.txt)
|
|
||||||
// This code is distributed under the GNU LGPL (for details please see \doc\license.txt)
|
|
||||||
|
|
||||||
using System; |
|
||||||
using ICSharpCode.SharpDevelop.Project; |
|
||||||
|
|
||||||
namespace ICSharpCode.UnitTesting |
|
||||||
{ |
|
||||||
public interface IUnitTestsPad |
|
||||||
{ |
|
||||||
void UpdateToolbar(); |
|
||||||
void BringToFront(); |
|
||||||
void ResetTestResults(); |
|
||||||
IProject[] GetProjects(); |
|
||||||
TestProject GetTestProject(IProject project); |
|
||||||
void CollapseAll(); |
|
||||||
} |
|
||||||
} |
|
||||||
@ -1,91 +0,0 @@ |
|||||||
// Copyright (c) AlphaSierraPapa for the SharpDevelop Team (for details please see \doc\copyright.txt)
|
|
||||||
// This code is distributed under the GNU LGPL (for details please see \doc\license.txt)
|
|
||||||
|
|
||||||
using System; |
|
||||||
using System.Collections.Generic; |
|
||||||
using ICSharpCode.NRefactory.TypeSystem; |
|
||||||
using ICSharpCode.SharpDevelop.Project; |
|
||||||
|
|
||||||
namespace ICSharpCode.UnitTesting |
|
||||||
{ |
|
||||||
public class SelectedTests |
|
||||||
{ |
|
||||||
string namespaceFilter; |
|
||||||
TestClass c; |
|
||||||
TestMember member; |
|
||||||
List<IProject> projects = new List<IProject>(); |
|
||||||
|
|
||||||
public SelectedTests(IProject project, string namespaceFilter, TestClass c, TestMember member) |
|
||||||
{ |
|
||||||
this.namespaceFilter = namespaceFilter; |
|
||||||
this.c = c; |
|
||||||
this.member = member; |
|
||||||
|
|
||||||
if (project != null) { |
|
||||||
projects.Add(project); |
|
||||||
} |
|
||||||
} |
|
||||||
|
|
||||||
public SelectedTests(IProject project) |
|
||||||
: this(project, null, null, null) |
|
||||||
{ |
|
||||||
} |
|
||||||
|
|
||||||
public SelectedTests(object owner, IProject[] selectedProjects) |
|
||||||
{ |
|
||||||
IProject project = TestableCondition.GetProject(owner); |
|
||||||
if (project != null) { |
|
||||||
projects.Add(project); |
|
||||||
} else { |
|
||||||
projects.AddRange(selectedProjects); |
|
||||||
} |
|
||||||
|
|
||||||
TestProject testProject = TestService.Solution.GetTestProject(project); |
|
||||||
if (testProject != null) { |
|
||||||
member = testProject.GetTestMember(TestableCondition.GetMember(owner)); |
|
||||||
c = testProject.GetTestClass(TestableCondition.GetClassFromMemberOrCaller(owner)); |
|
||||||
} |
|
||||||
namespaceFilter = TestableCondition.GetNamespace(owner); |
|
||||||
} |
|
||||||
|
|
||||||
public bool HasProjects { |
|
||||||
get { return projects.Count > 0; } |
|
||||||
} |
|
||||||
|
|
||||||
public void RemoveFirstProject() |
|
||||||
{ |
|
||||||
if (HasProjects) { |
|
||||||
projects.RemoveAt(0); |
|
||||||
} |
|
||||||
} |
|
||||||
|
|
||||||
public IEnumerable<IProject> Projects { |
|
||||||
get { return projects; } |
|
||||||
} |
|
||||||
|
|
||||||
public int ProjectsCount { |
|
||||||
get {return projects.Count;} |
|
||||||
} |
|
||||||
|
|
||||||
public IProject Project { |
|
||||||
get { |
|
||||||
if (projects.Count > 0) { |
|
||||||
return projects[0]; |
|
||||||
} |
|
||||||
return null; |
|
||||||
} |
|
||||||
} |
|
||||||
|
|
||||||
public string NamespaceFilter { |
|
||||||
get { return namespaceFilter; } |
|
||||||
} |
|
||||||
|
|
||||||
public TestClass Class { |
|
||||||
get { return c; } |
|
||||||
} |
|
||||||
|
|
||||||
public TestMember Member { |
|
||||||
get { return member; } |
|
||||||
} |
|
||||||
} |
|
||||||
} |
|
||||||
@ -1,38 +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.NRefactory.Utils; |
|
||||||
using ICSharpCode.TreeView; |
|
||||||
|
|
||||||
namespace ICSharpCode.UnitTesting |
|
||||||
{ |
|
||||||
public abstract class UnitTestBaseNode : SharpTreeNode |
|
||||||
{ |
|
||||||
protected static readonly KeyComparer<SharpTreeNode, string> NodeTextComparer = KeyComparer.Create((SharpTreeNode n) => n.Text.ToString(), StringComparer.OrdinalIgnoreCase, StringComparer.OrdinalIgnoreCase); |
|
||||||
|
|
||||||
internal abstract TestResultType TestResultType { get; } |
|
||||||
|
|
||||||
public override object Icon { |
|
||||||
get { return GetIcon(TestResultType); } |
|
||||||
} |
|
||||||
|
|
||||||
object GetIcon(TestResultType testResultType) |
|
||||||
{ |
|
||||||
switch (testResultType) { |
|
||||||
case TestResultType.None: |
|
||||||
return Images.Grey; |
|
||||||
case TestResultType.Success: |
|
||||||
return Images.Green; |
|
||||||
case TestResultType.Failure: |
|
||||||
return Images.Red; |
|
||||||
case TestResultType.Ignored: |
|
||||||
return Images.Yellow; |
|
||||||
default: |
|
||||||
throw new Exception("Invalid value for TestResultType"); |
|
||||||
} |
|
||||||
} |
|
||||||
} |
|
||||||
} |
|
||||||
@ -0,0 +1,128 @@ |
|||||||
|
// 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 ICSharpCode.NRefactory.Utils; |
||||||
|
using ICSharpCode.SharpDevelop; |
||||||
|
using ICSharpCode.TreeView; |
||||||
|
|
||||||
|
namespace ICSharpCode.UnitTesting |
||||||
|
{ |
||||||
|
public class UnitTestNode : SharpTreeNode |
||||||
|
{ |
||||||
|
protected static readonly IComparer<SharpTreeNode> NodeTextComparer = KeyComparer.Create((SharpTreeNode n) => n.Text.ToString(), StringComparer.OrdinalIgnoreCase, StringComparer.OrdinalIgnoreCase); |
||||||
|
|
||||||
|
readonly ITest test; |
||||||
|
|
||||||
|
public UnitTestNode(ITest test) |
||||||
|
{ |
||||||
|
if (test == null) |
||||||
|
throw new ArgumentNullException("test"); |
||||||
|
this.test = test; |
||||||
|
test.DisplayNameChanged += test_NameChanged; |
||||||
|
test.ResultChanged += test_ResultChanged; |
||||||
|
LazyLoading = true; |
||||||
|
} |
||||||
|
|
||||||
|
void DetachEventHandlers() |
||||||
|
{ |
||||||
|
test.DisplayNameChanged -= test_NameChanged; |
||||||
|
test.ResultChanged -= test_ResultChanged; |
||||||
|
// If children loaded, also detach the collection change event handler
|
||||||
|
if (!LazyLoading) { |
||||||
|
test.NestedTests.CollectionChanged -= test_NestedTests_CollectionChanged; |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
public ITest Test { |
||||||
|
get { return test; } |
||||||
|
} |
||||||
|
|
||||||
|
#region Manage Children
|
||||||
|
protected override void LoadChildren() |
||||||
|
{ |
||||||
|
Children.Clear(); |
||||||
|
InsertNestedTests(test.NestedTests); |
||||||
|
test.NestedTests.CollectionChanged += test_NestedTests_CollectionChanged; |
||||||
|
} |
||||||
|
|
||||||
|
void InsertNestedTests(IEnumerable<ITest> nestedTests) |
||||||
|
{ |
||||||
|
foreach (var test in nestedTests) { |
||||||
|
Children.OrderedInsert(test.CreateTreeNode(), NodeTextComparer); |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
void test_NestedTests_CollectionChanged(object sender, NotifyCollectionChangedEventArgs e) |
||||||
|
{ |
||||||
|
if (!IsVisible) { |
||||||
|
SwitchBackToLazyLoading(); |
||||||
|
return; |
||||||
|
} |
||||||
|
switch (e.Action) { |
||||||
|
case NotifyCollectionChangedAction.Add: |
||||||
|
InsertNestedTests(e.NewItems.Cast<ITest>()); |
||||||
|
break; |
||||||
|
case NotifyCollectionChangedAction.Remove: |
||||||
|
Children.RemoveAll(n => e.OldItems.Contains(((UnitTestNode)n).Test)); |
||||||
|
break; |
||||||
|
case NotifyCollectionChangedAction.Reset: |
||||||
|
if (IsExpanded) { |
||||||
|
Children.Clear(); |
||||||
|
InsertNestedTests(test.NestedTests); |
||||||
|
} else { |
||||||
|
SwitchBackToLazyLoading(); |
||||||
|
} |
||||||
|
break; |
||||||
|
default: |
||||||
|
throw new NotSupportedException("Invalid value for NotifyCollectionChangedAction"); |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
void SwitchBackToLazyLoading() |
||||||
|
{ |
||||||
|
test.NestedTests.CollectionChanged -= test_NestedTests_CollectionChanged; |
||||||
|
Children.Clear(); |
||||||
|
LazyLoading = true; |
||||||
|
} |
||||||
|
#endregion
|
||||||
|
|
||||||
|
#region Icon + Text
|
||||||
|
public override object Icon { |
||||||
|
get { |
||||||
|
switch (test.Result) { |
||||||
|
case TestResultType.None: |
||||||
|
return Images.Grey; |
||||||
|
case TestResultType.Success: |
||||||
|
return Images.Green; |
||||||
|
case TestResultType.Failure: |
||||||
|
return Images.Red; |
||||||
|
case TestResultType.Ignored: |
||||||
|
return Images.Yellow; |
||||||
|
default: |
||||||
|
throw new NotSupportedException("Invalid value for TestResultType"); |
||||||
|
} |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
void test_ResultChanged(object sender, EventArgs e) |
||||||
|
{ |
||||||
|
RaisePropertyChanged("Icon"); |
||||||
|
RaisePropertyChanged("ExpandedIcon"); |
||||||
|
} |
||||||
|
|
||||||
|
public override object Text { |
||||||
|
get { return test.DisplayName; } |
||||||
|
} |
||||||
|
|
||||||
|
void test_NameChanged(object sender, EventArgs e) |
||||||
|
{ |
||||||
|
RaisePropertyChanged("Text"); |
||||||
|
} |
||||||
|
#endregion
|
||||||
|
} |
||||||
|
} |
||||||
Loading…
Reference in new issue