diff --git a/.gitignore b/.gitignore
index 6c8304f..b23ad87 100644
--- a/.gitignore
+++ b/.gitignore
@@ -4,3 +4,5 @@
*.user
_ReSharper.*/
output/*
+resharper.log
+TestResults/
\ No newline at end of file
diff --git a/src/AgUnit.Runner.Resharper60.TaskRunner/AgUnit.Runner.Resharper60.TaskRunner.csproj b/src/AgUnit.Runner.Resharper60.TaskRunner/AgUnit.Runner.Resharper60.TaskRunner.csproj
index f628203..02b34a7 100644
--- a/src/AgUnit.Runner.Resharper60.TaskRunner/AgUnit.Runner.Resharper60.TaskRunner.csproj
+++ b/src/AgUnit.Runner.Resharper60.TaskRunner/AgUnit.Runner.Resharper60.TaskRunner.csproj
@@ -12,11 +12,11 @@
AgUnit.Runner.Resharper60.TaskRunner
v4.0
512
-
- $(Registry:HKEY_LOCAL_MACHINE\SOFTWARE\JetBrains\ReSharper\v6.0\vs10.0@InstallDir)
- Program
- $(DevEnvDir)devenv.exe
- /ReSharper.Plugin AgUnit.Runner.Resharper60.dll /ReSharper.LogFile C:\resharper.log /ReSharper.LogLevel Verbose ..\src\DummyTests\VS2010\DummyTests.sln
+
+ $(Registry:HKEY_LOCAL_MACHINE\SOFTWARE\JetBrains\ReSharper\v6.0\vs10.0@InstallDir)
+ Program
+ $(DevEnvDir)devenv.exe
+ /ReSharper.Plugin AgUnit.Runner.Resharper60.dll /ReSharper.LogFile C:\resharper.log /ReSharper.LogLevel Verbose ..\src\DummyTests\VS2010\DummyTests.sln
..\..\output\
@@ -54,9 +54,23 @@
+
+
+
+
+
+
+
+
+
+
+
Code
+
+
+
diff --git a/src/AgUnit.Runner.Resharper60.TaskRunner/UnitTestProvider/MSTest/MsTestAssemblyTaskProvider.cs b/src/AgUnit.Runner.Resharper60.TaskRunner/UnitTestProvider/MSTest/MsTestAssemblyTaskProvider.cs
new file mode 100644
index 0000000..7329903
--- /dev/null
+++ b/src/AgUnit.Runner.Resharper60.TaskRunner/UnitTestProvider/MSTest/MsTestAssemblyTaskProvider.cs
@@ -0,0 +1,26 @@
+using AgUnit.Runner.Resharper60.TaskRunner.UnitTestRunner.Silverlight.Providers;
+using JetBrains.ReSharper.TaskRunnerFramework;
+using JetBrains.ReSharper.UnitTestRunner.MSTest;
+
+namespace AgUnit.Runner.Resharper60.TaskRunner.UnitTestProvider.MSTest
+{
+ public class MsTestAssemblyTaskProvider : IAssemblyTaskProvider
+ {
+ public bool IsAssemblyTask(RemoteTask task)
+ {
+ return task is MsTestTestAssemblyTask;
+ }
+
+ private MsTestTestAssemblyTask GetTask(RemoteTask task)
+ {
+ return (MsTestTestAssemblyTask)task;
+ }
+
+ public string GetXapPath(RemoteTask task)
+ {
+ var assemblyTask = GetTask(task);
+
+ return assemblyTask.AssemblyLocation.Replace(".dll", ".xap"); // TODO: Find a way to get this from the project settings.
+ }
+ }
+}
\ No newline at end of file
diff --git a/src/AgUnit.Runner.Resharper60.TaskRunner/UnitTestProvider/MSTest/MsTestClassTaskProvider.cs b/src/AgUnit.Runner.Resharper60.TaskRunner/UnitTestProvider/MSTest/MsTestClassTaskProvider.cs
new file mode 100644
index 0000000..7e5e429
--- /dev/null
+++ b/src/AgUnit.Runner.Resharper60.TaskRunner/UnitTestProvider/MSTest/MsTestClassTaskProvider.cs
@@ -0,0 +1,26 @@
+using AgUnit.Runner.Resharper60.TaskRunner.UnitTestRunner.Silverlight.Providers;
+using JetBrains.ReSharper.TaskRunnerFramework;
+using JetBrains.ReSharper.UnitTestRunner.MSTest;
+
+namespace AgUnit.Runner.Resharper60.TaskRunner.UnitTestProvider.MSTest
+{
+ public class MsTestClassTaskProvider : IClassTaskProvider
+ {
+ public bool IsClassTask(RemoteTask task)
+ {
+ return task is MsTestTestClassTask;
+ }
+
+ private MsTestTestClassTask GetTask(RemoteTask task)
+ {
+ return (MsTestTestClassTask)task;
+ }
+
+ public string GetFullClassName(RemoteTask task)
+ {
+ var classTask = GetTask(task);
+
+ return classTask.TypeName;
+ }
+ }
+}
\ No newline at end of file
diff --git a/src/AgUnit.Runner.Resharper60.TaskRunner/UnitTestProvider/MSTest/MsTestMethodTaskProvider.cs b/src/AgUnit.Runner.Resharper60.TaskRunner/UnitTestProvider/MSTest/MsTestMethodTaskProvider.cs
new file mode 100644
index 0000000..e07b673
--- /dev/null
+++ b/src/AgUnit.Runner.Resharper60.TaskRunner/UnitTestProvider/MSTest/MsTestMethodTaskProvider.cs
@@ -0,0 +1,26 @@
+using AgUnit.Runner.Resharper60.TaskRunner.UnitTestRunner.Silverlight.Providers;
+using JetBrains.ReSharper.TaskRunnerFramework;
+using JetBrains.ReSharper.UnitTestRunner.MSTest;
+
+namespace AgUnit.Runner.Resharper60.TaskRunner.UnitTestProvider.MSTest
+{
+ public class MsTestMethodTaskProvider : IMethodTaskProvider
+ {
+ public bool IsMethodTask(RemoteTask task)
+ {
+ return task is MsTestTestMethodTask;
+ }
+
+ private MsTestTestMethodTask GetTask(RemoteTask task)
+ {
+ return (MsTestTestMethodTask)task;
+ }
+
+ public string GetFullMethodName(RemoteTask task)
+ {
+ var methodTask = GetTask(task);
+
+ return string.Format("{0}.{1}", methodTask.TypeName, methodTask.ShortName);
+ }
+ }
+}
\ No newline at end of file
diff --git a/src/AgUnit.Runner.Resharper60.TaskRunner/UnitTestRunner/Silverlight/DebugLogger.cs b/src/AgUnit.Runner.Resharper60.TaskRunner/UnitTestRunner/Silverlight/DebugLogger.cs
new file mode 100644
index 0000000..7a25ba3
--- /dev/null
+++ b/src/AgUnit.Runner.Resharper60.TaskRunner/UnitTestRunner/Silverlight/DebugLogger.cs
@@ -0,0 +1,69 @@
+using StatLight.Core.Common;
+using StatLight.Core.Properties;
+
+namespace AgUnit.Runner.Resharper60.TaskRunner.UnitTestRunner.Silverlight
+{
+ // TODO: Move this to StatLight
+ public class DebugLogger : LoggerBase
+ {
+ private readonly Settings settings;
+
+ public DebugLogger()
+ : this(LogChatterLevels.Error | LogChatterLevels.Warning | LogChatterLevels.Information, Settings.Default)
+ { }
+
+ public DebugLogger(LogChatterLevels logChatterLevel)
+ : this(logChatterLevel, Settings.Default)
+ { }
+
+ public DebugLogger(LogChatterLevels logChatterLevel, Settings settings)
+ : base(logChatterLevel)
+ {
+ this.settings = settings;
+ }
+
+ public override void Information(string message)
+ {
+ if (ShouldLog(LogChatterLevels.Information))
+ Write(message, "Information", false);
+ }
+
+ public override void Debug(string message)
+ {
+ if (ShouldLog(LogChatterLevels.Debug))
+ Write(message, "Debug", true);
+ }
+
+ public override void Debug(string message, bool writeNewLine)
+ {
+ if (ShouldLog(LogChatterLevels.Debug))
+ Write(message, "Debug", writeNewLine);
+ }
+
+ public override void Warning(string message)
+ {
+ if (ShouldLog(LogChatterLevels.Warning))
+ Write(message, "Warning", false);
+ }
+
+ public override void Error(string message)
+ {
+ if (ShouldLog(LogChatterLevels.Error))
+ Write(message, "Error", true);
+ }
+
+ private void Write(string message, string type, bool useNewLine)
+ {
+ message = string.Format("[{0}]: {1}", type, message);
+
+ if (useNewLine)
+ {
+ System.Diagnostics.Debug.WriteLine(message);
+ }
+ else
+ {
+ System.Diagnostics.Debug.Write(message);
+ }
+ }
+ }
+}
diff --git a/src/AgUnit.Runner.Resharper60.TaskRunner/UnitTestRunner/Silverlight/Execution/AssemblyTask.cs b/src/AgUnit.Runner.Resharper60.TaskRunner/UnitTestRunner/Silverlight/Execution/AssemblyTask.cs
new file mode 100644
index 0000000..c643f11
--- /dev/null
+++ b/src/AgUnit.Runner.Resharper60.TaskRunner/UnitTestRunner/Silverlight/Execution/AssemblyTask.cs
@@ -0,0 +1,27 @@
+using System;
+using AgUnit.Runner.Resharper60.TaskRunner.UnitTestRunner.Silverlight.Providers;
+
+namespace AgUnit.Runner.Resharper60.TaskRunner.UnitTestRunner.Silverlight.Execution
+{
+ public class AssemblyTask
+ {
+ public TaskNode Node { get; private set; }
+ public IAssemblyTaskProvider AssemblyTaskProvider { get; private set; }
+
+ public AssemblyTask(TaskNode node, IAssemblyTaskProvider assemblyTaskProvider)
+ {
+ Node = node;
+ AssemblyTaskProvider = assemblyTaskProvider;
+ }
+
+ public void Execute(Action execute)
+ {
+ Node.Execute(execute, this);
+ }
+
+ public string GetXapPath()
+ {
+ return AssemblyTaskProvider.GetXapPath(Node.Task);
+ }
+ }
+}
\ No newline at end of file
diff --git a/src/AgUnit.Runner.Resharper60.TaskRunner/UnitTestRunner/Silverlight/Execution/ClassTask.cs b/src/AgUnit.Runner.Resharper60.TaskRunner/UnitTestRunner/Silverlight/Execution/ClassTask.cs
new file mode 100644
index 0000000..97ea8d9
--- /dev/null
+++ b/src/AgUnit.Runner.Resharper60.TaskRunner/UnitTestRunner/Silverlight/Execution/ClassTask.cs
@@ -0,0 +1,21 @@
+using AgUnit.Runner.Resharper60.TaskRunner.UnitTestRunner.Silverlight.Providers;
+
+namespace AgUnit.Runner.Resharper60.TaskRunner.UnitTestRunner.Silverlight.Execution
+{
+ public class ClassTask
+ {
+ public TaskNode Node { get; private set; }
+ public IClassTaskProvider ClassTaskProvider { get; private set; }
+
+ public ClassTask(TaskNode node, IClassTaskProvider classTaskProvider)
+ {
+ Node = node;
+ ClassTaskProvider = classTaskProvider;
+ }
+
+ public string GetFullClassName()
+ {
+ return ClassTaskProvider.GetFullClassName(Node.Task);
+ }
+ }
+}
\ No newline at end of file
diff --git a/src/AgUnit.Runner.Resharper60.TaskRunner/UnitTestRunner/Silverlight/Execution/MethodTask.cs b/src/AgUnit.Runner.Resharper60.TaskRunner/UnitTestRunner/Silverlight/Execution/MethodTask.cs
new file mode 100644
index 0000000..b087367
--- /dev/null
+++ b/src/AgUnit.Runner.Resharper60.TaskRunner/UnitTestRunner/Silverlight/Execution/MethodTask.cs
@@ -0,0 +1,21 @@
+using AgUnit.Runner.Resharper60.TaskRunner.UnitTestRunner.Silverlight.Providers;
+
+namespace AgUnit.Runner.Resharper60.TaskRunner.UnitTestRunner.Silverlight.Execution
+{
+ public class MethodTask
+ {
+ public TaskNode Node { get; private set; }
+ public IMethodTaskProvider MethodTaskProvider { get; private set; }
+
+ public MethodTask(TaskNode node, IMethodTaskProvider methodTaskProvider)
+ {
+ Node = node;
+ MethodTaskProvider = methodTaskProvider;
+ }
+
+ public string GetFullMethodName()
+ {
+ return MethodTaskProvider.GetFullMethodName(Node.Task);
+ }
+ }
+}
\ No newline at end of file
diff --git a/src/AgUnit.Runner.Resharper60.TaskRunner/UnitTestRunner/Silverlight/Execution/TaskEnvironment.cs b/src/AgUnit.Runner.Resharper60.TaskRunner/UnitTestRunner/Silverlight/Execution/TaskEnvironment.cs
new file mode 100644
index 0000000..a8808be
--- /dev/null
+++ b/src/AgUnit.Runner.Resharper60.TaskRunner/UnitTestRunner/Silverlight/Execution/TaskEnvironment.cs
@@ -0,0 +1,25 @@
+using System.Collections.Generic;
+using AgUnit.Runner.Resharper60.TaskRunner.UnitTestRunner.Silverlight.Providers;
+using JetBrains.ReSharper.TaskRunnerFramework;
+
+namespace AgUnit.Runner.Resharper60.TaskRunner.UnitTestRunner.Silverlight.Execution
+{
+ public class TaskEnvironment
+ {
+ public IRemoteTaskServer Server { get; private set; }
+ public IEnumerable AssemblyTaskProviders { get; private set; }
+ public IEnumerable ClassTaskProviders { get; private set; }
+ public IEnumerable MethodTaskProviders { get; private set; }
+
+ public TaskEnvironment(IRemoteTaskServer server,
+ IEnumerable assemblyTaskProviders,
+ IEnumerable classTaskProviders,
+ IEnumerable methodTaskProviders)
+ {
+ Server = server;
+ AssemblyTaskProviders = assemblyTaskProviders;
+ ClassTaskProviders = classTaskProviders;
+ MethodTaskProviders = methodTaskProviders;
+ }
+ }
+}
\ No newline at end of file
diff --git a/src/AgUnit.Runner.Resharper60.TaskRunner/UnitTestRunner/Silverlight/Execution/TaskNode.cs b/src/AgUnit.Runner.Resharper60.TaskRunner/UnitTestRunner/Silverlight/Execution/TaskNode.cs
new file mode 100644
index 0000000..05122cd
--- /dev/null
+++ b/src/AgUnit.Runner.Resharper60.TaskRunner/UnitTestRunner/Silverlight/Execution/TaskNode.cs
@@ -0,0 +1,107 @@
+using System;
+using System.Linq;
+using JetBrains.ReSharper.TaskRunnerFramework;
+using StatLight.Client.Harness.Events;
+
+namespace AgUnit.Runner.Resharper60.TaskRunner.UnitTestRunner.Silverlight.Execution
+{
+ public enum TaskStatus
+ {
+ NotStarted,
+ Running,
+ Finished
+ }
+
+ public class TaskNode
+ {
+ public RemoteTask Task { get; private set; }
+ public TaskEnvironment Environment { get; private set; }
+ public TaskNode Parent { get; private set; }
+ public TaskNode[] Children { get; private set; }
+ public TaskStatus Status { get; private set; }
+ public TaskResult Result { get; private set; }
+
+ public TaskNode(TaskExecutionNode node, TaskEnvironment environment, TaskNode parent = null)
+ {
+ Task = node.RemoteTask;
+ Environment = environment;
+ Parent = parent;
+ Status = TaskStatus.NotStarted;
+ Result = TaskResult.Skipped;
+ Children = node.Children.Select(child => new TaskNode(child, environment, this)).ToArray();
+ }
+
+ public void Execute(Action execute, T task)
+ {
+ try
+ {
+ NotifyStarting();
+ execute(task);
+ NotifyFinished(null, TaskResult.Success);
+ }
+ catch (Exception e)
+ {
+ NotifyFinishedWithException(e);
+ throw;
+ }
+ }
+
+ public void NotifyStarting()
+ {
+ if (Status == TaskStatus.NotStarted)
+ {
+ if (Parent != null)
+ {
+ Parent.NotifyStarting();
+ }
+
+ Status = TaskStatus.Running;
+
+ Environment.Server.TaskStarting(Task);
+ }
+ }
+
+ public void NotifyFinished(string output = null, TaskResult? result = null)
+ {
+ NotifyStarting();
+
+ if (Status == TaskStatus.Running)
+ {
+ Status = TaskStatus.Finished;
+ Result = result ?? (Children.Any() ? Children.Max(c => c.Result) : TaskResult.Success);
+
+ foreach (var child in Children)
+ {
+ child.NotifyFinished(null, TaskResult.Skipped);
+ }
+
+ Environment.Server.TaskFinished(Task, output, Result);
+
+ if (Parent != null && Parent.Children.All(c => c.Status == TaskStatus.Finished))
+ {
+ Parent.NotifyFinished(null);
+ }
+ }
+ }
+
+ public void NotifyFinishedWithException(Exception e, TaskResult result = TaskResult.Exception)
+ {
+ NotifyStarting();
+
+ Environment.Server.TaskException(Task, new[] { new TaskException(e) });
+
+ NotifyFinished(e.Message, result);
+ }
+
+ public void NotifyFinishedWithException(ExceptionInfo e, TaskResult result = TaskResult.Exception)
+ {
+ NotifyStarting();
+
+ // TODO: We should pass the TypeName instead of FullMessage
+ // TODO: Report inner exceptions recursively
+ Environment.Server.TaskException(Task, new[] { new TaskException(e.FullMessage, e.Message, e.StackTrace) });
+
+ NotifyFinished(e.Message, result);
+ }
+ }
+}
\ No newline at end of file
diff --git a/src/AgUnit.Runner.Resharper60.TaskRunner/UnitTestRunner/Silverlight/Providers/IAssemblyTaskProvider.cs b/src/AgUnit.Runner.Resharper60.TaskRunner/UnitTestRunner/Silverlight/Providers/IAssemblyTaskProvider.cs
new file mode 100644
index 0000000..e44ea33
--- /dev/null
+++ b/src/AgUnit.Runner.Resharper60.TaskRunner/UnitTestRunner/Silverlight/Providers/IAssemblyTaskProvider.cs
@@ -0,0 +1,10 @@
+using JetBrains.ReSharper.TaskRunnerFramework;
+
+namespace AgUnit.Runner.Resharper60.TaskRunner.UnitTestRunner.Silverlight.Providers
+{
+ public interface IAssemblyTaskProvider
+ {
+ bool IsAssemblyTask(RemoteTask task);
+ string GetXapPath(RemoteTask task);
+ }
+}
\ No newline at end of file
diff --git a/src/AgUnit.Runner.Resharper60.TaskRunner/UnitTestRunner/Silverlight/Providers/IClassTaskProvider.cs b/src/AgUnit.Runner.Resharper60.TaskRunner/UnitTestRunner/Silverlight/Providers/IClassTaskProvider.cs
new file mode 100644
index 0000000..84d6310
--- /dev/null
+++ b/src/AgUnit.Runner.Resharper60.TaskRunner/UnitTestRunner/Silverlight/Providers/IClassTaskProvider.cs
@@ -0,0 +1,10 @@
+using JetBrains.ReSharper.TaskRunnerFramework;
+
+namespace AgUnit.Runner.Resharper60.TaskRunner.UnitTestRunner.Silverlight.Providers
+{
+ public interface IClassTaskProvider
+ {
+ bool IsClassTask(RemoteTask task);
+ string GetFullClassName(RemoteTask task);
+ }
+}
\ No newline at end of file
diff --git a/src/AgUnit.Runner.Resharper60.TaskRunner/UnitTestRunner/Silverlight/Providers/IMethodTaskProvider.cs b/src/AgUnit.Runner.Resharper60.TaskRunner/UnitTestRunner/Silverlight/Providers/IMethodTaskProvider.cs
new file mode 100644
index 0000000..3c5e42c
--- /dev/null
+++ b/src/AgUnit.Runner.Resharper60.TaskRunner/UnitTestRunner/Silverlight/Providers/IMethodTaskProvider.cs
@@ -0,0 +1,10 @@
+using JetBrains.ReSharper.TaskRunnerFramework;
+
+namespace AgUnit.Runner.Resharper60.TaskRunner.UnitTestRunner.Silverlight.Providers
+{
+ public interface IMethodTaskProvider
+ {
+ bool IsMethodTask(RemoteTask task);
+ string GetFullMethodName(RemoteTask task);
+ }
+}
\ No newline at end of file
diff --git a/src/AgUnit.Runner.Resharper60.TaskRunner/UnitTestRunner/Silverlight/Providers/TaskNodeExtensions.cs b/src/AgUnit.Runner.Resharper60.TaskRunner/UnitTestRunner/Silverlight/Providers/TaskNodeExtensions.cs
new file mode 100644
index 0000000..5171d43
--- /dev/null
+++ b/src/AgUnit.Runner.Resharper60.TaskRunner/UnitTestRunner/Silverlight/Providers/TaskNodeExtensions.cs
@@ -0,0 +1,57 @@
+using System.Collections.Generic;
+using System.Linq;
+using AgUnit.Runner.Resharper60.TaskRunner.UnitTestRunner.Silverlight.Execution;
+
+namespace AgUnit.Runner.Resharper60.TaskRunner.UnitTestRunner.Silverlight.Providers
+{
+ public static class TaskNodeExtensions
+ {
+ public static IEnumerable GetAssemblyTasks(this TaskNode node)
+ {
+ foreach (var assemblyTaskProvider in node.Environment.AssemblyTaskProviders)
+ {
+ if (assemblyTaskProvider.IsAssemblyTask(node.Task))
+ {
+ yield return new AssemblyTask(node, assemblyTaskProvider);
+ }
+ }
+
+ foreach (var child in node.Children.SelectMany(child => child.GetAssemblyTasks()))
+ {
+ yield return child;
+ }
+ }
+
+ public static IEnumerable GetClassTasks(this TaskNode node)
+ {
+ foreach (var classTaskProvider in node.Environment.ClassTaskProviders)
+ {
+ if (classTaskProvider.IsClassTask(node.Task))
+ {
+ yield return new ClassTask(node, classTaskProvider);
+ }
+ }
+
+ foreach (var child in node.Children.SelectMany(child => child.GetClassTasks()))
+ {
+ yield return child;
+ }
+ }
+
+ public static IEnumerable GetMethodTasks(this TaskNode node)
+ {
+ foreach (var methodTaskProvider in node.Environment.MethodTaskProviders)
+ {
+ if (methodTaskProvider.IsMethodTask(node.Task))
+ {
+ yield return new MethodTask(node, methodTaskProvider);
+ }
+ }
+
+ foreach (var child in node.Children.SelectMany(child => child.GetMethodTasks()))
+ {
+ yield return child;
+ }
+ }
+ }
+}
\ No newline at end of file
diff --git a/src/AgUnit.Runner.Resharper60.TaskRunner/UnitTestRunner/Silverlight/SilverlightResultsHandler.cs b/src/AgUnit.Runner.Resharper60.TaskRunner/UnitTestRunner/Silverlight/SilverlightResultsHandler.cs
new file mode 100644
index 0000000..1b2b65c
--- /dev/null
+++ b/src/AgUnit.Runner.Resharper60.TaskRunner/UnitTestRunner/Silverlight/SilverlightResultsHandler.cs
@@ -0,0 +1,124 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using AgUnit.Runner.Resharper60.TaskRunner.UnitTestRunner.Silverlight.Execution;
+using EventAggregatorNet;
+using JetBrains.ReSharper.TaskRunnerFramework;
+using StatLight.Client.Harness.Events;
+using StatLight.Core.Events;
+
+namespace AgUnit.Runner.Resharper60.TaskRunner.UnitTestRunner.Silverlight
+{
+ public class SilverlightResultsHandler : ITestingReportEvents,
+ IListener,
+ IListener,
+ IListener
+ {
+ public IEnumerable TestClasses { get; private set; }
+ public IEnumerable TestMethods { get; private set; }
+
+ public SilverlightResultsHandler(IEnumerable testClasses, IEnumerable testMethods)
+ {
+ TestClasses = testClasses;
+ TestMethods = testMethods;
+ }
+
+ public void Handle(TestCaseResult message)
+ {
+ if (message.MethodName != null)
+ {
+ var testMethod = GetTestMethod(message.FullMethodName());
+ if (testMethod != null)
+ {
+ var taskResult = ToTaskResult(message.ResultType);
+
+ if (message.ExceptionInfo != null)
+ {
+ testMethod.Node.NotifyFinishedWithException(message.ExceptionInfo, taskResult);
+ }
+ else
+ {
+ testMethod.Node.NotifyFinished(null, taskResult);
+ }
+ }
+ }
+ }
+
+ private TaskResult ToTaskResult(ResultType resultType)
+ {
+ switch (resultType)
+ {
+ case ResultType.Passed:
+ return TaskResult.Success;
+ case ResultType.Failed:
+ return TaskResult.Exception;
+ case ResultType.Ignored:
+ return TaskResult.Skipped;
+ case ResultType.SystemGeneratedFailure:
+ return TaskResult.Error;
+ }
+
+ throw new ArgumentOutOfRangeException();
+ }
+
+ public void Handle(TraceClientEvent message)
+ {
+ // TODO: Note sure what to do with this, maybe ask Jason Jarrett ...
+ // TODO: Apparently a test method with ExpectedException, that is not throwing an exception, is not returning a test result (See TestFixture1.FailingTest3 in DummyTests)
+ }
+
+ public void Handle(BrowserHostCommunicationTimeoutServerEvent message)
+ {
+ throw new Exception(message.Message);
+ }
+
+ public void Handle(FatalSilverlightExceptionServerEvent message)
+ {
+ throw new Exception(message.Message);
+ }
+
+ public void Handle(UnhandledExceptionClientEvent message)
+ {
+ throw new Exception(message.ExceptionInfo.FullMessage);
+ }
+
+ public void Handle(TestExecutionClassBeginClientEvent message)
+ {
+ var testClass = GetTestClass(message);
+ if (testClass != null)
+ {
+ testClass.Node.NotifyStarting();
+ }
+ }
+
+ public void Handle(TestExecutionClassCompletedClientEvent message)
+ {
+ var testClass = GetTestClass(message);
+ if (testClass != null)
+ {
+ testClass.Node.NotifyFinished();
+ }
+ }
+
+ public void Handle(TestExecutionMethodBeginClientEvent message)
+ {
+ // TODO: For some reason this is triggered AFTER the method is run, so the test timings are incorrect
+ var testMethod = GetTestMethod(message.FullMethodName);
+ if (testMethod != null)
+ {
+ testMethod.Node.NotifyStarting();
+ }
+ }
+
+ private ClassTask GetTestClass(TestExecutionClass message)
+ {
+ var fullClassName = string.Format("{0}.{1}", message.NamespaceName, message.ClassName);
+ return TestClasses.FirstOrDefault(c => c.GetFullClassName() == fullClassName);
+ }
+
+ private MethodTask GetTestMethod(string fullMethodName)
+ {
+ return TestMethods.FirstOrDefault(c => c.GetFullMethodName() == fullMethodName);
+ }
+ }
+}
\ No newline at end of file
diff --git a/src/AgUnit.Runner.Resharper60.TaskRunner/UnitTestRunner/Silverlight/SilverlightUnitTestTaskRunner.cs b/src/AgUnit.Runner.Resharper60.TaskRunner/UnitTestRunner/Silverlight/SilverlightUnitTestTaskRunner.cs
index d6f698d..8246080 100644
--- a/src/AgUnit.Runner.Resharper60.TaskRunner/UnitTestRunner/Silverlight/SilverlightUnitTestTaskRunner.cs
+++ b/src/AgUnit.Runner.Resharper60.TaskRunner/UnitTestRunner/Silverlight/SilverlightUnitTestTaskRunner.cs
@@ -1,14 +1,14 @@
-using System;
-using System.Collections.Generic;
+using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.Diagnostics;
using System.Linq;
+using AgUnit.Runner.Resharper60.TaskRunner.UnitTestProvider.MSTest;
+using AgUnit.Runner.Resharper60.TaskRunner.UnitTestRunner.Silverlight.Execution;
+using AgUnit.Runner.Resharper60.TaskRunner.UnitTestRunner.Silverlight.Providers;
+using EventAggregatorNet;
using JetBrains.ReSharper.TaskRunnerFramework;
-using JetBrains.ReSharper.UnitTestRunner.MSTest;
-using StatLight.Client.Harness.Events;
using StatLight.Core.Common;
using StatLight.Core.Configuration;
-using StatLight.Core.Events;
using StatLight.Core.Runners;
using StatLight.Core.WebBrowser;
@@ -39,201 +39,72 @@ public override void ExecuteRecursive(TaskExecutionNode node)
{
//Debugger.Break();
- try
- {
- Server.TaskStarting(node.RemoteTask);
-
- foreach (var assemblyTaskNode in node.Children)
- {
- Execute(assemblyTaskNode, (MsTestTestAssemblyTask)assemblyTaskNode.RemoteTask);
- }
-
- Server.TaskFinished(node.RemoteTask, null, TaskResult.Success);
- }
- catch (Exception e)
- {
- Server.TaskException(node.RemoteTask, new[] { new TaskException(e) });
- Server.TaskFinished(node.RemoteTask, null, TaskResult.Exception);
-
- throw;
- }
- }
-
- private void Execute(TaskExecutionNode assemblyTaskNode, MsTestTestAssemblyTask assemblyTask)
- {
- try
- {
- Server.TaskStarting(assemblyTask);
-
- var xapPath = assemblyTask.AssemblyLocation.Replace(".dll", ".xap");
- var testMethods = assemblyTaskNode.GetTasks().Select(m => m.GetFullMethodName()).ToList();
-
- ILogger logger = new ConsoleLogger(LogChatterLevels.Full);
- var eventAggregator = EventAggregatorFactory.Create(logger);
-
- // Create our custom listener and add it to the event aggregator
- var reSharperTestingReportEventsHandler = new ReSharperTestingReportEventsHandler(Server, assemblyTaskNode, testMethods);
- eventAggregator.AddListener(reSharperTestingReportEventsHandler);
-
- var statLightConfigurationFactory = new StatLightConfigurationFactory(logger);
-
- var config = statLightConfigurationFactory.GetStatLightConfigurationForXap(
- unitTestProviderType: UnitTestProviderType.Undefined, // Let StatLight figure it out
- xapPath: xapPath,
- microsoftTestingFrameworkVersion: null, // Let StatLight figure it out
- methodsToTest: new Collection(testMethods),
- tagFilters: null,
- numberOfBrowserHosts: 1, // Maybe you spin up 3 or 4 here if you know you're running a ton of tests
- isRemoteRun: false,
- queryString: "", // This is passed to the browser host page (say your test need some configuration - could be passed here - probably not a use case in ReSharper runner)
- webBrowserType: WebBrowserType.SelfHosted,
- forceBrowserStart: false,
- showTestingBrowserHost: false // If you need UI support this needs to be true
- );
-
- var statLightRunnerFactory = new StatLightRunnerFactory(logger, eventAggregator, eventAggregator);
-
- var onetimeConsoleRunner = statLightRunnerFactory.CreateOnetimeConsoleRunner(config);
-
- // This will be the blocking/slow operation that runs the tests...
- var testReport = onetimeConsoleRunner.Run();
-
- reSharperTestingReportEventsHandler.ReportIgnoredMethods();
- reSharperTestingReportEventsHandler.ReportOtherTasks();
-
- Server.TaskFinished(assemblyTask, null, TaskResult.Success);
- }
- catch (Exception e)
- {
- Server.TaskException(assemblyTask, new[] { new TaskException(e) });
- Server.TaskFinished(assemblyTask, null, TaskResult.Exception);
-
- throw;
- }
- }
- }
-
- public class ReSharperTestingReportEventsHandler : ITestingReportEvents
- {
- private readonly IRemoteTaskServer server;
- private readonly TaskExecutionNode rootNode;
- private readonly IList methodsToRun;
- private readonly IList finishedTasks;
+ var assemblyProviders = new IAssemblyTaskProvider[] { new MsTestAssemblyTaskProvider() };
+ var classProviders = new IClassTaskProvider[] { new MsTestClassTaskProvider() };
+ var methodProviders = new IMethodTaskProvider[] { new MsTestMethodTaskProvider() };
- public ReSharperTestingReportEventsHandler(IRemoteTaskServer server, TaskExecutionNode rootNode, IList methodsToRun)
- {
- this.server = server;
- this.rootNode = rootNode;
- this.methodsToRun = methodsToRun;
-
- finishedTasks = new List();
- }
+ var taskEnvironment = new TaskEnvironment(Server, assemblyProviders, classProviders, methodProviders);
+ var taskNode = new TaskNode(node, taskEnvironment);
- public void Handle(TestCaseResult message)
- {
- if (message.MethodName != null)
+ foreach (var assemblyTaskNode in taskNode.GetAssemblyTasks())
{
- var remoteTask = rootNode.GetTasks().FirstOrDefault(t => t.GetFullMethodName() == message.FullMethodName());
- if (remoteTask != null)
- {
- server.TaskStarting(remoteTask);
- var output = message.ExceptionInfo != null ? message.ExceptionInfo.ToString() : null;
- methodsToRun.Remove(message.FullMethodName());
- server.TaskFinished(remoteTask, output, ToTaskResult(message.ResultType));
- finishedTasks.Add(remoteTask);
- }
+ assemblyTaskNode.Execute(Execute);
}
}
- private TaskResult ToTaskResult(ResultType resultType)
+ private void Execute(AssemblyTask assemblyTask)
{
- switch (resultType)
- {
- case ResultType.Passed:
- return TaskResult.Success;
- case ResultType.Failed:
- return TaskResult.Exception;
- case ResultType.Ignored:
- return TaskResult.Skipped;
- case ResultType.SystemGeneratedFailure:
- return TaskResult.Error;
- }
+ var xapPath = assemblyTask.GetXapPath();
+ var testMethods = assemblyTask.Node.GetMethodTasks().ToArray();
+ var testClasses = assemblyTask.Node.GetClassTasks().ToArray();
- throw new ArgumentOutOfRangeException();
- }
+ var logger = CreateStatLightLogger();
+ var eventAggregator = CreateStatLightEventAggregator(testClasses, testMethods, logger);
+ var configuration = CreateStatLightConfiguration(testMethods, logger, xapPath);
+ var runner = CreateStatLightRunner(configuration, logger, eventAggregator);
- public void Handle(TraceClientEvent message)
- {
- server.TaskOutput(rootNode.RemoteTask, message.Message, TaskOutputType.STDOUT);
+ var testReport = runner.Run();
}
- public void Handle(BrowserHostCommunicationTimeoutServerEvent message)
+ private static DebugLogger CreateStatLightLogger()
{
- server.TaskError(rootNode.RemoteTask, message.Message);
+ return new DebugLogger(LogChatterLevels.Full);
}
- public void Handle(FatalSilverlightExceptionServerEvent message)
+ private static EventAggregator CreateStatLightEventAggregator(IEnumerable testClasses, IEnumerable testMethods, ILogger logger)
{
- server.TaskError(rootNode.RemoteTask, message.Message);
- }
+ var eventsHandler = new SilverlightResultsHandler(testClasses, testMethods);
+ var eventAggregator = EventAggregatorFactory.Create(logger);
- public void Handle(UnhandledExceptionClientEvent message)
- {
- server.TaskError(rootNode.RemoteTask, message.ExceptionInfo.FullMessage);
- }
+ eventAggregator.AddListener(eventsHandler);
- public void ReportIgnoredMethods()
- {
- foreach (var method in methodsToRun)
- {
- var remoteTask = rootNode.GetTasks().FirstOrDefault(t => t.GetFullMethodName() == method);
- if (remoteTask != null)
- {
- server.TaskFinished(remoteTask, null, TaskResult.Skipped);
- finishedTasks.Add(remoteTask);
- }
- }
+ return eventAggregator;
}
- public void ReportOtherTasks()
+ private static StatLightConfiguration CreateStatLightConfiguration(IEnumerable testMethods, ILogger logger, string xapPath)
{
- var allTaskNodes = rootNode.Children.FlattenNodesHierarchy().ToList();
+ var configurationFactory = new StatLightConfigurationFactory(logger);
- foreach (var taskNode in allTaskNodes.Where(t => !finishedTasks.Contains(t.RemoteTask)))
- {
- server.TaskFinished(taskNode.RemoteTask, null, TaskResult.Success);
- }
- }
- }
-
- public static class TaskExecutionNodeHelper
- {
- public static IEnumerable GetTasks(this TaskExecutionNode parentNode) where T : RemoteTask
- {
- return FlattenNodesHierarchy(new[] { parentNode }).Select(node => node.RemoteTask).OfType();
- }
-
- public static IEnumerable GetNodesWithTask(this TaskExecutionNode parentNode) where T : RemoteTask
- {
- return FlattenNodesHierarchy(new[] { parentNode }).Where(node => node.RemoteTask is T);
+ return configurationFactory.GetStatLightConfigurationForXap(
+ unitTestProviderType: UnitTestProviderType.Undefined, // Let StatLight figure it out
+ xapPath: xapPath,
+ microsoftTestingFrameworkVersion: null, // Let StatLight figure it out
+ methodsToTest: new Collection(testMethods.Select(m => m.GetFullMethodName()).ToList()),
+ tagFilters: null,
+ numberOfBrowserHosts: 1, // Maybe you spin up 3 or 4 here if you know you're running a ton of tests
+ isRemoteRun: false,
+ queryString: "", // This is passed to the browser host page (say your test need some configuration - could be passed here - probably not a use case in ReSharper runner)
+ webBrowserType: WebBrowserType.SelfHosted,
+ forceBrowserStart: false,
+ showTestingBrowserHost: false // If you need UI support this needs to be true
+ );
}
- public static IEnumerable FlattenNodesHierarchy(this IEnumerable nodes)
+ private static IRunner CreateStatLightRunner(StatLightConfiguration config, ILogger logger, EventAggregator eventAggregator)
{
- foreach (var node in nodes)
- {
- foreach (var childNode in FlattenNodesHierarchy(node.Children))
- {
- yield return childNode;
- }
+ var runnerFactory = new StatLightRunnerFactory(logger, eventAggregator, eventAggregator);
- yield return node;
- }
- }
-
- public static string GetFullMethodName(this MsTestTestMethodTask methodTask)
- {
- return string.Format("{0}.{1}", methodTask.TypeName, methodTask.ShortName);
+ return runnerFactory.CreateOnetimeConsoleRunner(config);
}
}
}
\ No newline at end of file
diff --git a/src/AgUnit.Runner.Resharper60/AgUnit.Runner.Resharper60.csproj b/src/AgUnit.Runner.Resharper60/AgUnit.Runner.Resharper60.csproj
index 67098e9..720ef70 100644
--- a/src/AgUnit.Runner.Resharper60/AgUnit.Runner.Resharper60.csproj
+++ b/src/AgUnit.Runner.Resharper60/AgUnit.Runner.Resharper60.csproj
@@ -16,7 +16,7 @@
$(Registry:HKEY_LOCAL_MACHINE\SOFTWARE\JetBrains\ReSharper\v6.0\vs10.0@InstallDir)
Program
$(DevEnvDir)devenv.exe
- /ReSharper.Plugin AgUnit.Runner.Resharper60.dll /ReSharper.LogFile C:\resharper.log /ReSharper.LogLevel Verbose ..\src\DummyTests\VS2010\DummyTests.sln
+ /ReSharper.Plugin AgUnit.Runner.Resharper60.dll /ReSharper.LogFile "..\resharper.log" /ReSharper.LogLevel Verbose ..\src\DummyTests\VS2010\DummyTests.sln
..\..\output\
diff --git a/src/DummyTests/VS2010/DummyTests.DotNetMSTest/DummyTests1.cs b/src/DummyTests/VS2010/DummyTests.DotNetMSTest/DummyTests1.cs
index 1f24cc4..aebff2a 100644
--- a/src/DummyTests/VS2010/DummyTests.DotNetMSTest/DummyTests1.cs
+++ b/src/DummyTests/VS2010/DummyTests.DotNetMSTest/DummyTests1.cs
@@ -58,6 +58,12 @@ public void FailingTest3()
{
}
+ [TestMethod]
+ public void FailingTest4()
+ {
+ throw new InvalidOperationException();
+ }
+
[TestCleanup]
public void TestCleanup1()
{
diff --git a/src/DummyTests/VS2010/DummyTests.DotNetNUnit/DummyTests1NUnit.cs b/src/DummyTests/VS2010/DummyTests.DotNetNUnit/DummyTests1NUnit.cs
index dd53744..2054284 100644
--- a/src/DummyTests/VS2010/DummyTests.DotNetNUnit/DummyTests1NUnit.cs
+++ b/src/DummyTests/VS2010/DummyTests.DotNetNUnit/DummyTests1NUnit.cs
@@ -53,6 +53,12 @@ public void FailingTest3()
{
}
+ [Test]
+ public void FailingTest4()
+ {
+ throw new InvalidOperationException();
+ }
+
[TearDown]
public void TestCleanup1()
{
diff --git a/src/DummyTests/VS2010/DummyTests.Silverlight3/DummyTests1.cs b/src/DummyTests/VS2010/DummyTests.Silverlight3/DummyTests1.cs
index ab71bc2..6392cc3 100644
--- a/src/DummyTests/VS2010/DummyTests.Silverlight3/DummyTests1.cs
+++ b/src/DummyTests/VS2010/DummyTests.Silverlight3/DummyTests1.cs
@@ -58,6 +58,12 @@ public void FailingTest3()
{
}
+ [TestMethod]
+ public void FailingTest4()
+ {
+ throw new InvalidOperationException();
+ }
+
[TestCleanup]
public void TestCleanup1()
{
diff --git a/src/DummyTests/VS2010/DummyTests.Silverlight4.Other/DummyTests1.cs b/src/DummyTests/VS2010/DummyTests.Silverlight4.Other/DummyTests1.cs
index 597df1a..6534a85 100644
--- a/src/DummyTests/VS2010/DummyTests.Silverlight4.Other/DummyTests1.cs
+++ b/src/DummyTests/VS2010/DummyTests.Silverlight4.Other/DummyTests1.cs
@@ -58,6 +58,12 @@ public void FailingTest3()
{
}
+ [TestMethod]
+ public void FailingTest4()
+ {
+ throw new InvalidOperationException();
+ }
+
[TestCleanup]
public void TestCleanup1()
{
diff --git a/src/DummyTests/VS2010/DummyTests.Silverlight4/DummyTests1.cs b/src/DummyTests/VS2010/DummyTests.Silverlight4/DummyTests1.cs
index 569e6a5..b4bd8e5 100644
--- a/src/DummyTests/VS2010/DummyTests.Silverlight4/DummyTests1.cs
+++ b/src/DummyTests/VS2010/DummyTests.Silverlight4/DummyTests1.cs
@@ -24,6 +24,8 @@ public void TestInitialize1()
[TestMethod]
public void PassingTest1()
{
+
+ System.Threading.Thread.Sleep(2000);
}
[TestMethod]
@@ -58,6 +60,12 @@ public void FailingTest3()
{
}
+ [TestMethod]
+ public void FailingTest4()
+ {
+ throw new InvalidOperationException();
+ }
+
[TestCleanup]
public void TestCleanup1()
{