From 4cd4b871a00d6cab9d74229748b227e24ed4945f Mon Sep 17 00:00:00 2001 From: Daniel Cazzulino Date: Fri, 20 Mar 2015 09:32:35 -0300 Subject: [PATCH 1/8] Ignore Xamarin.iOS target framework assemblies too --- xunit.runner.visualstudio.testadapter/VsTestRunner.cs | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/xunit.runner.visualstudio.testadapter/VsTestRunner.cs b/xunit.runner.visualstudio.testadapter/VsTestRunner.cs index 6b77394a..6ad5962d 100644 --- a/xunit.runner.visualstudio.testadapter/VsTestRunner.cs +++ b/xunit.runner.visualstudio.testadapter/VsTestRunner.cs @@ -104,7 +104,8 @@ void DiscoverTests(IEnumerable sources, { var targetFramework = framework.TargetFramework; if (targetFramework.StartsWith("MonoTouch", StringComparison.OrdinalIgnoreCase) || - targetFramework.StartsWith("MonoAndroid", StringComparison.OrdinalIgnoreCase)) + targetFramework.StartsWith("MonoAndroid", StringComparison.OrdinalIgnoreCase) || + targetFramework.StartsWith("Xamarin.iOS", StringComparison.OrdinalIgnoreCase)) { if (configuration.DiagnosticMessagesOrDefault) logger.SendMessage(TestMessageLevel.Informational, String.Format("[xUnit.net {0}] Skipping: {1} (unsupported target framework '{2}')", stopwatch.Elapsed, fileName, targetFramework)); From 8a86cf242b73d90bca12a05c9376d49b9f6f2b86 Mon Sep 17 00:00:00 2001 From: Brad Wilson Date: Sun, 3 May 2015 13:26:57 -0700 Subject: [PATCH 2/8] Switch to `TestMessageLevel.Warning` for discovery exceptions (fixes #62) --- xunit.runner.visualstudio.testadapter/VsTestRunner.cs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/xunit.runner.visualstudio.testadapter/VsTestRunner.cs b/xunit.runner.visualstudio.testadapter/VsTestRunner.cs index 6ad5962d..9d02d0c8 100644 --- a/xunit.runner.visualstudio.testadapter/VsTestRunner.cs +++ b/xunit.runner.visualstudio.testadapter/VsTestRunner.cs @@ -150,7 +150,7 @@ void DiscoverTests(IEnumerable sources, String.Format("[xUnit.net {0}] Skipping: {1} (could not find dependent assembly '{2}')", stopwatch.Elapsed, fileName, Path.GetFileNameWithoutExtension(fileLoad.FileName))); #endif else - logger.SendMessage(TestMessageLevel.Error, + logger.SendMessage(TestMessageLevel.Warning, String.Format("[xUnit.net {0}] Exception discovering tests from {1}: {2}", stopwatch.Elapsed, fileName, ex)); } } @@ -158,7 +158,7 @@ void DiscoverTests(IEnumerable sources, } catch (Exception e) { - logger.SendMessage(TestMessageLevel.Error, + logger.SendMessage(TestMessageLevel.Warning, String.Format("[xUnit.net {0}] Exception discovering tests: {1}", stopwatch.Elapsed, e.Unwrap())); } From 0505932b05527a49068f997ea5493ac0a4053f67 Mon Sep 17 00:00:00 2001 From: Brad Wilson Date: Sun, 3 May 2015 13:34:46 -0700 Subject: [PATCH 3/8] Fixes #60: Diagnostic messages do not include banner/time --- .../Visitors/DiagnosticMessageVisitor.cs | 7 +++++-- xunit.runner.visualstudio.testadapter/VsTestRunner.cs | 4 ++-- 2 files changed, 7 insertions(+), 4 deletions(-) diff --git a/xunit.runner.visualstudio.testadapter/Visitors/DiagnosticMessageVisitor.cs b/xunit.runner.visualstudio.testadapter/Visitors/DiagnosticMessageVisitor.cs index 05be6c93..f98f6931 100644 --- a/xunit.runner.visualstudio.testadapter/Visitors/DiagnosticMessageVisitor.cs +++ b/xunit.runner.visualstudio.testadapter/Visitors/DiagnosticMessageVisitor.cs @@ -1,4 +1,5 @@ using System; +using System.Diagnostics; using Microsoft.VisualStudio.TestPlatform.ObjectModel.Logging; using Xunit.Abstractions; @@ -9,18 +10,20 @@ public class DiagnosticMessageVisitor : TestMessageVisitor readonly string assemblyDisplayName; readonly IMessageLogger logger; readonly bool showDiagnostics; + readonly Stopwatch stopwatch; - public DiagnosticMessageVisitor(IMessageLogger logger, string assemblyDisplayName, bool showDiagnostics) + public DiagnosticMessageVisitor(IMessageLogger logger, string assemblyDisplayName, bool showDiagnostics, Stopwatch stopwatch) { this.logger = logger; this.assemblyDisplayName = assemblyDisplayName; this.showDiagnostics = showDiagnostics; + this.stopwatch = stopwatch; } protected override bool Visit(IDiagnosticMessage diagnosticMessage) { if (showDiagnostics) - logger.SendMessage(TestMessageLevel.Warning, String.Format("{0}: {1}", assemblyDisplayName, diagnosticMessage.Message)); + logger.SendMessage(TestMessageLevel.Warning, String.Format("[xUnit.net {0}] {1}: {2}", stopwatch.Elapsed, assemblyDisplayName, diagnosticMessage.Message)); return base.Visit(diagnosticMessage); } diff --git a/xunit.runner.visualstudio.testadapter/VsTestRunner.cs b/xunit.runner.visualstudio.testadapter/VsTestRunner.cs index 9d02d0c8..cd2bf2ca 100644 --- a/xunit.runner.visualstudio.testadapter/VsTestRunner.cs +++ b/xunit.runner.visualstudio.testadapter/VsTestRunner.cs @@ -98,7 +98,7 @@ void DiscoverTests(IEnumerable sources, } else { - var diagnosticMessageVisitor = new DiagnosticMessageVisitor(logger, fileName, configuration.DiagnosticMessagesOrDefault); + var diagnosticMessageVisitor = new DiagnosticMessageVisitor(logger, fileName, configuration.DiagnosticMessagesOrDefault, stopwatch); using (var framework = new XunitFrontController(assemblyFileName, configFileName: null, shadowCopy: true, diagnosticMessageSink: diagnosticMessageVisitor)) { @@ -313,7 +313,7 @@ void RunTestsInAssembly(IFrameworkHandle frameworkHandle, assemblyFileName = Path.Combine(Windows.ApplicationModel.Package.Current.InstalledLocation.Path, Path.GetFileName(assemblyFileName)); #endif - var diagnosticMessageVisitor = new DiagnosticMessageVisitor(frameworkHandle, assemblyDisplayName, runInfo.Configuration.DiagnosticMessagesOrDefault); + var diagnosticMessageVisitor = new DiagnosticMessageVisitor(frameworkHandle, assemblyDisplayName, runInfo.Configuration.DiagnosticMessagesOrDefault, stopwatch); var controller = new XunitFrontController(assemblyFileName, configFileName: null, shadowCopy: true, diagnosticMessageSink: diagnosticMessageVisitor); lock (toDispose) From a02eeffdf9ec609dcac40b9e9fa651a830b423f9 Mon Sep 17 00:00:00 2001 From: Brad Wilson Date: Mon, 18 May 2015 16:10:30 -0700 Subject: [PATCH 4/8] Standardized .gitignore file --- .gitattributes | 28 +++++++++++++++ .gitignore | 94 +++++++++++++++++++++++++++++++++++++++++--------- 2 files changed, 106 insertions(+), 16 deletions(-) create mode 100644 .gitattributes diff --git a/.gitattributes b/.gitattributes new file mode 100644 index 00000000..7a6c1d3d --- /dev/null +++ b/.gitattributes @@ -0,0 +1,28 @@ +*.ico binary +*.snk binary +*.xls binary + +*.bat text +*.config text +*.cs text diff=csharp +*.csproj text merge=union +*.manifest text +*.msbuild text +*.nuspec text +*.resx text merge=union +*.ruleset text +*.settings text +*.shfb text +*.targets text +*.tdnet text +*.txt text +*.vb text +*.vbproj text merge=union +*.vsixmanifest text +*.vstemplate text +*.xml text +*.xsl text +*.xslt text +*.xunit text + +*.sln text eol=crlf merge=union diff --git a/.gitignore b/.gitignore index 04702a58..7332a94e 100644 --- a/.gitignore +++ b/.gitignore @@ -1,24 +1,86 @@ -[Bb]in -[Oo]bj -packages -help +## -------------------------------------------- +## xUnit.net specific ignores -*.suo -*.user -*.[Cc]ache -*[Rr]esharper* +Test*.html +Test*.xml *.zip +nuget.exe + +## -------------------------------------------- +## Adapted from https://raw.githubusercontent.com/github/gitignore/a4ec7f03ca5ae0bf09fad42c0fb7d1e8346bcf25/VisualStudio.gitignore + +# User-specific files *.suo *.user -*.cache -*.nupkg -*.exe -*.dll -*.ncrunch* -*.vsix +*.userosscache +*.sln.docstates -Test*.html -Test*.xml +# User-specific files (MonoDevelop/Xamarin Studio) +*.userprefs +# Build results +[Dd]ebug/ +[Dd]ebugPublic/ +[Rr]elease/ +[Rr]eleases/ +x64/ +x86/ +build/ +bld/ +[Bb]in/ +[Oo]bj/ + +# Visual Studio 2015 cache/options directory +.vs/ + +# Visual Studio test runner +[Tt]est[Rr]esult*/ Index.dat Storage.dat + +# DNX +project.lock.json +artifacts/ + +# Visual Studio profiler +*.psess +*.vsp +*.vspx + +# ReSharper is a .NET coding add-in +_ReSharper*/ +*.[Rr]e[Ss]harper +*.DotSettings.user + +# JustCode is a .NET coding add-in +.JustCode + +# TeamCity is a build add-in +_TeamCity* + +# DotCover is a Code Coverage Tool +*.dotCover + +# NCrunch +_NCrunch_* +.*crunch*.local.xml + +# NuGet Packages +*.nupkg +**/packages/* +!**/packages/build/ + +# Windows Store app package directory +AppPackages/ + +# Visual Studio cache files +*.[Cc]ache +!*.[Cc]ache/ + +# Backup & report files from converting an old project file +# to a newer Visual Studio version. Backup files are not needed, +# because we have git ;-) +_UpgradeReport_Files/ +Backup*/ +UpgradeLog*.XML +UpgradeLog*.htm From 1362bca70184707e2922c838c765264f602620ea Mon Sep 17 00:00:00 2001 From: Brad Wilson Date: Fri, 3 Jul 2015 12:26:14 -0700 Subject: [PATCH 5/8] Add a bunch of diagnostic messages, plus fix an issue with TestStarting that should've been TestCaseStarting --- common/WinRTFile.cs | 2 +- .../Utility/AssemblyExtensions.cs | 2 +- .../Utility/LoggerHelper.cs | 53 +++++ .../Visitors/DiagnosticMessageVisitor.cs | 2 +- .../Visitors/VsDiscoveryVisitor.cs | 31 +-- .../Visitors/VsExecutionVisitor.cs | 83 +++++--- .../VsTestRunner.cs | 184 +++++++++--------- ...nit.runner.visualstudio.testadapter.csproj | 1 + .../xunit.runner.visualstudio.win8.csproj | 3 + .../xunit.runner.visualstudio.wpa81.csproj | 3 + 10 files changed, 231 insertions(+), 133 deletions(-) create mode 100644 xunit.runner.visualstudio.testadapter/Utility/LoggerHelper.cs diff --git a/common/WinRTFile.cs b/common/WinRTFile.cs index 3745bcc2..b24eac0f 100644 --- a/common/WinRTFile.cs +++ b/common/WinRTFile.cs @@ -6,7 +6,7 @@ internal static class File { public static bool Exists(string path) { - if (String.IsNullOrWhiteSpace(path)) + if (string.IsNullOrWhiteSpace(path)) return false; var folder = Package.Current.InstalledLocation; diff --git a/xunit.runner.visualstudio.testadapter/Utility/AssemblyExtensions.cs b/xunit.runner.visualstudio.testadapter/Utility/AssemblyExtensions.cs index e3997912..f332d0bd 100644 --- a/xunit.runner.visualstudio.testadapter/Utility/AssemblyExtensions.cs +++ b/xunit.runner.visualstudio.testadapter/Utility/AssemblyExtensions.cs @@ -11,7 +11,7 @@ public static string GetLocalCodeBase(this Assembly assembly) return null; if (!codeBase.StartsWith("file:///")) - throw new ArgumentException(String.Format("Code base {0} in wrong format; must start with file:///", codeBase), "assembly"); + throw new ArgumentException(string.Format("Code base {0} in wrong format; must start with file:///", codeBase), "assembly"); codeBase = codeBase.Substring(8); if (Path.DirectorySeparatorChar == '/') diff --git a/xunit.runner.visualstudio.testadapter/Utility/LoggerHelper.cs b/xunit.runner.visualstudio.testadapter/Utility/LoggerHelper.cs new file mode 100644 index 00000000..9c88b358 --- /dev/null +++ b/xunit.runner.visualstudio.testadapter/Utility/LoggerHelper.cs @@ -0,0 +1,53 @@ +using System.Diagnostics; +using System.IO; +using Microsoft.VisualStudio.TestPlatform.ObjectModel.Logging; +using Xunit.Abstractions; + +public class LoggerHelper +{ + public LoggerHelper(IMessageLogger logger, Stopwatch stopwatch) + { + InnerLogger = logger; + Stopwatch = stopwatch; + } + + public IMessageLogger InnerLogger { get; private set; } + + public Stopwatch Stopwatch { get; private set; } + + public void Log(string format, params object[] args) + { + SendMessage(TestMessageLevel.Informational, null, string.Format(format, args)); + } + + public void Log(ITestCase testCase, string format, params object[] args) + { + SendMessage(TestMessageLevel.Informational, testCase.TestMethod.TestClass.TestCollection.TestAssembly.Assembly.AssemblyPath, string.Format(format, args)); + } + + public void LogError(string format, params object[] args) + { + SendMessage(TestMessageLevel.Error, null, string.Format(format, args)); + } + + public void LogError(ITestCase testCase, string format, params object[] args) + { + SendMessage(TestMessageLevel.Error, testCase.TestMethod.TestClass.TestCollection.TestAssembly.Assembly.AssemblyPath, string.Format(format, args)); + } + + public void LogWarning(string format, params object[] args) + { + SendMessage(TestMessageLevel.Warning, null, string.Format(format, args)); + } + + public void LogWarning(ITestCase testCase, string format, params object[] args) + { + SendMessage(TestMessageLevel.Warning, testCase.TestMethod.TestClass.TestCollection.TestAssembly.Assembly.AssemblyPath, string.Format(format, args)); + } + + void SendMessage(TestMessageLevel level, string assemblyName, string message) + { + var assemblyText = assemblyName == null ? "" : string.Format("{0}: ", Path.GetFileNameWithoutExtension(assemblyName)); + InnerLogger.SendMessage(level, string.Format("[xUnit.net {0}] {1}{2}", Stopwatch.Elapsed, assemblyText, message)); + } +} diff --git a/xunit.runner.visualstudio.testadapter/Visitors/DiagnosticMessageVisitor.cs b/xunit.runner.visualstudio.testadapter/Visitors/DiagnosticMessageVisitor.cs index f98f6931..6db6ad2c 100644 --- a/xunit.runner.visualstudio.testadapter/Visitors/DiagnosticMessageVisitor.cs +++ b/xunit.runner.visualstudio.testadapter/Visitors/DiagnosticMessageVisitor.cs @@ -23,7 +23,7 @@ public DiagnosticMessageVisitor(IMessageLogger logger, string assemblyDisplayNam protected override bool Visit(IDiagnosticMessage diagnosticMessage) { if (showDiagnostics) - logger.SendMessage(TestMessageLevel.Warning, String.Format("[xUnit.net {0}] {1}: {2}", stopwatch.Elapsed, assemblyDisplayName, diagnosticMessage.Message)); + logger.SendMessage(TestMessageLevel.Warning, string.Format("[xUnit.net {0}] {1}: {2}", stopwatch.Elapsed, assemblyDisplayName, diagnosticMessage.Message)); return base.Visit(diagnosticMessage); } diff --git a/xunit.runner.visualstudio.testadapter/Visitors/VsDiscoveryVisitor.cs b/xunit.runner.visualstudio.testadapter/Visitors/VsDiscoveryVisitor.cs index 7eb8d0ff..1836b655 100644 --- a/xunit.runner.visualstudio.testadapter/Visitors/VsDiscoveryVisitor.cs +++ b/xunit.runner.visualstudio.testadapter/Visitors/VsDiscoveryVisitor.cs @@ -1,18 +1,16 @@ using System; using System.Collections.Generic; using System.Linq.Expressions; -using System.Reflection; using System.Text; using Microsoft.VisualStudio.TestPlatform.ObjectModel; using Microsoft.VisualStudio.TestPlatform.ObjectModel.Adapter; -using Microsoft.VisualStudio.TestPlatform.ObjectModel.Logging; using Xunit.Abstractions; #if WINDOWS_PHONE_APP -using Xunit.Serialization; +using System.Reflection; +using System.Runtime.InteropServices.WindowsRuntime; using Windows.Security.Cryptography; using Windows.Security.Cryptography.Core; -using System.Runtime.InteropServices.WindowsRuntime; #else using System.Security.Cryptography; #endif @@ -29,14 +27,14 @@ public class VsDiscoveryVisitor : TestMessageVisitor, readonly ITestFrameworkDiscoveryOptions discoveryOptions; readonly ITestCaseDiscoverySink discoverySink; readonly List lastTestClassTestCases = new List(); - readonly IMessageLogger logger; + readonly LoggerHelper logger; readonly string source; string lastTestClass; public VsDiscoveryVisitor(string source, ITestFrameworkDiscoverer discoverer, - IMessageLogger logger, + LoggerHelper logger, ITestCaseDiscoverySink discoverySink, ITestFrameworkDiscoveryOptions discoveryOptions, Func cancelThunk) @@ -51,13 +49,13 @@ public VsDiscoveryVisitor(string source, public int TotalTests { get; private set; } - public static TestCase CreateVsTestCase(string source, ITestFrameworkDiscoverer discoverer, ITestCase xunitTestCase, bool forceUniqueNames, IMessageLogger logger, bool logDiscovery) + public static TestCase CreateVsTestCase(string source, ITestFrameworkDiscoverer discoverer, ITestCase xunitTestCase, bool forceUniqueNames, LoggerHelper logger) { try { var serializedTestCase = discoverer.Serialize(xunitTestCase); - var fqTestMethodName = String.Format("{0}.{1}", xunitTestCase.TestMethod.TestClass.Class.Name, xunitTestCase.TestMethod.Method.Name); - var uniqueName = forceUniqueNames ? String.Format("{0} ({1})", fqTestMethodName, xunitTestCase.UniqueID) : fqTestMethodName; + var fqTestMethodName = string.Format("{0}.{1}", xunitTestCase.TestMethod.TestClass.Class.Name, xunitTestCase.TestMethod.Method.Name); + var uniqueName = forceUniqueNames ? string.Format("{0} ({1})", fqTestMethodName, xunitTestCase.UniqueID) : fqTestMethodName; var result = new TestCase(uniqueName, uri, source) { DisplayName = Escape(xunitTestCase.DisplayName) }; result.SetPropertyValue(VsTestRunner.SerializedTestCaseProperty, serializedTestCase); @@ -75,7 +73,7 @@ public static TestCase CreateVsTestCase(string source, ITestFrameworkDiscoverer } catch (Exception ex) { - logger.SendMessage(TestMessageLevel.Error, String.Format("Error creating Visual Studio test case for {0}: {1}", xunitTestCase.DisplayName, ex)); + logger.LogError(xunitTestCase, "Error creating Visual Studio test case for {0}: {1}", xunitTestCase.DisplayName, ex); return null; } } @@ -83,7 +81,7 @@ public static TestCase CreateVsTestCase(string source, ITestFrameworkDiscoverer static string Escape(string value) { if (value == null) - return String.Empty; + return string.Empty; return value.Replace("\r", "\\r").Replace("\n", "\\n").Replace("\t", "\\t"); } @@ -134,7 +132,7 @@ static Action GetAddTraitThunk() protected override bool Visit(ITestCaseDiscoveryMessage discovery) { var testCase = discovery.TestCase; - var testClass = String.Format("{0}.{1}", testCase.TestMethod.TestClass.Class.Name, testCase.TestMethod.Method.Name); + var testClass = string.Format("{0}.{1}", testCase.TestMethod.TestClass.Class.Name, testCase.TestMethod.Method.Name); if (lastTestClass != testClass) SendExistingTestCases(); @@ -158,9 +156,16 @@ private void SendExistingTestCases() foreach (var testCase in lastTestClassTestCases) { - var vsTestCase = CreateVsTestCase(source, discoverer, testCase, forceUniqueNames, logger, discoveryOptions.GetDiagnosticMessagesOrDefault()); + var vsTestCase = CreateVsTestCase(source, discoverer, testCase, forceUniqueNames, logger); if (vsTestCase != null) + { + if (discoveryOptions.GetDiagnosticMessagesOrDefault()) + logger.Log(testCase, "Discovered test case '{0}' (ID = '{1}', VS FQN = '{2}')", testCase.DisplayName, testCase.UniqueID, vsTestCase.FullyQualifiedName); + discoverySink.SendTestCase(vsTestCase); + } + else + logger.LogWarning(testCase, "Could not create VS test case for '{0}' (ID = '{1}', VS FQN = '{2}')", testCase.DisplayName, testCase.UniqueID, vsTestCase.FullyQualifiedName); } lastTestClassTestCases.Clear(); diff --git a/xunit.runner.visualstudio.testadapter/Visitors/VsExecutionVisitor.cs b/xunit.runner.visualstudio.testadapter/Visitors/VsExecutionVisitor.cs index 16480966..df7e9450 100644 --- a/xunit.runner.visualstudio.testadapter/Visitors/VsExecutionVisitor.cs +++ b/xunit.runner.visualstudio.testadapter/Visitors/VsExecutionVisitor.cs @@ -3,7 +3,6 @@ using System.Linq; using Microsoft.VisualStudio.TestPlatform.ObjectModel; using Microsoft.VisualStudio.TestPlatform.ObjectModel.Adapter; -using Microsoft.VisualStudio.TestPlatform.ObjectModel.Logging; using Xunit.Abstractions; using VsTestResult = Microsoft.VisualStudio.TestPlatform.ObjectModel.TestResult; using VsTestResultMessage = Microsoft.VisualStudio.TestPlatform.ObjectModel.TestResultMessage; @@ -14,15 +13,18 @@ public class VsExecutionVisitor : TestMessageVisitor { readonly Func cancelledThunk; readonly ITestFrameworkExecutionOptions executionOptions; + readonly LoggerHelper logger; readonly ITestExecutionRecorder recorder; readonly Dictionary testCases; public VsExecutionVisitor(ITestExecutionRecorder recorder, + LoggerHelper logger, Dictionary testCases, ITestFrameworkExecutionOptions executionOptions, Func cancelledThunk) { this.recorder = recorder; + this.logger = logger; this.testCases = testCases; this.executionOptions = executionOptions; this.cancelledThunk = cancelledThunk; @@ -38,13 +40,28 @@ TestCase FindTestCase(ITestCase testCase) if (result != null) return result; - recorder.SendMessage(TestMessageLevel.Error, String.Format("Result reported for unknown test case: {0}", testCase.DisplayName)); + logger.LogError(testCase, "Result reported for unknown test case: {0}", testCase.DisplayName); return null; } + private void TryAndReport(string actionDescription, ITestCase testCase, Action action) + { + try + { + if (executionOptions.GetDiagnosticMessagesOrDefault()) + logger.Log(testCase, "Performing {0} for test case {1}", actionDescription, testCase.DisplayName); + + action(); + } + catch (Exception ex) + { + logger.LogError(testCase, "Error occured while {0} for test case {1}: {2}", actionDescription, testCase.DisplayName, ex); + } + } + protected override bool Visit(IErrorMessage error) { - recorder.SendMessage(TestMessageLevel.Error, String.Format("Catastrophic failure: {0}", ExceptionUtility.CombineMessages(error))); + logger.LogError("Catastrophic failure: {0}", ExceptionUtility.CombineMessages(error)); return !cancelledThunk(); } @@ -57,9 +74,10 @@ protected override bool Visit(ITestFailed testFailed) result.ErrorMessage = ExceptionUtility.CombineMessages(testFailed); result.ErrorStackTrace = ExceptionUtility.CombineStackTraces(testFailed); - recorder.RecordEnd(result.TestCase, result.Outcome); - recorder.RecordResult(result); + TryAndReport("RecordResult (Fail)", testFailed.TestCase, () => recorder.RecordResult(result)); } + else + logger.LogWarning(testFailed.TestCase, "(Fail) Could not find VS test case for {0} (ID = {1})", testFailed.TestCase.DisplayName, testFailed.TestCase.UniqueID); return !cancelledThunk(); } @@ -68,10 +86,9 @@ protected override bool Visit(ITestPassed testPassed) { var result = MakeVsTestResult(TestOutcome.Passed, testPassed); if (result != null) - { - recorder.RecordEnd(result.TestCase, result.Outcome); - recorder.RecordResult(result); - } + TryAndReport("RecordResult (Pass)", testPassed.TestCase, () => recorder.RecordResult(result)); + else + logger.LogWarning(testPassed.TestCase, "(Pass) Could not find VS test case for {0} (ID = {1})", testPassed.TestCase.DisplayName, testPassed.TestCase.UniqueID); return !cancelledThunk(); } @@ -80,51 +97,63 @@ protected override bool Visit(ITestSkipped testSkipped) { var result = MakeVsTestResult(TestOutcome.Skipped, testSkipped); if (result != null) - { - recorder.RecordEnd(result.TestCase, result.Outcome); - recorder.RecordResult(result); - } + TryAndReport("RecordResult (Skip)", testSkipped.TestCase, () => recorder.RecordResult(result)); + else + logger.LogWarning(testSkipped.TestCase, "(Skip) Could not find VS test case for {0} (ID = {1})", testSkipped.TestCase.DisplayName, testSkipped.TestCase.UniqueID); + + return !cancelledThunk(); + } + + protected override bool Visit(ITestCaseStarting testCaseStarting) + { + var vsTestCase = FindTestCase(testCaseStarting.TestCase); + if (vsTestCase != null) + TryAndReport("RecordStart", testCaseStarting.TestCase, () => recorder.RecordStart(vsTestCase)); + else + logger.LogWarning(testCaseStarting.TestCase, "(Starting) Could not find VS test case for {0} (ID = {1})", testCaseStarting.TestCase.DisplayName, testCaseStarting.TestCase.UniqueID); return !cancelledThunk(); } - protected override bool Visit(ITestStarting testStarting) + protected override bool Visit(ITestCaseFinished testCaseFinished) { - var vsTestCase = FindTestCase(testStarting.TestCase); + var vsTestCase = FindTestCase(testCaseFinished.TestCase); if (vsTestCase != null) - recorder.RecordStart(vsTestCase); + TryAndReport("RecordEnd", testCaseFinished.TestCase, () => recorder.RecordEnd(vsTestCase, TestOutcome.Passed)); // TODO: Don't have an aggregate outcome here! + else + logger.LogWarning(testCaseFinished.TestCase, "(Finished) Could not find VS test case for {0} (ID = {1})", testCaseFinished.TestCase.DisplayName, testCaseFinished.TestCase.UniqueID); return !cancelledThunk(); } protected override bool Visit(ITestAssemblyCleanupFailure cleanupFailure) { - return WriteError(String.Format("Test Assembly Cleanup Failure ({0})", cleanupFailure.TestAssembly.Assembly.AssemblyPath), cleanupFailure, cleanupFailure.TestCases); + return WriteError(string.Format("Test Assembly Cleanup Failure ({0})", cleanupFailure.TestAssembly.Assembly.AssemblyPath), cleanupFailure, cleanupFailure.TestCases); } protected override bool Visit(ITestCaseCleanupFailure cleanupFailure) { - return WriteError(String.Format("Test Case Cleanup Failure ({0})", cleanupFailure.TestCase.DisplayName), cleanupFailure, cleanupFailure.TestCases); + return WriteError(string.Format("Test Case Cleanup Failure ({0})", cleanupFailure.TestCase.DisplayName), cleanupFailure, cleanupFailure.TestCases); } protected override bool Visit(ITestClassCleanupFailure cleanupFailure) { - return WriteError(String.Format("Test Class Cleanup Failure ({0})", cleanupFailure.TestClass.Class.Name), cleanupFailure, cleanupFailure.TestCases); + return WriteError(string.Format("Test Class Cleanup Failure ({0})", cleanupFailure.TestClass.Class.Name), cleanupFailure, cleanupFailure.TestCases); } protected override bool Visit(ITestCollectionCleanupFailure cleanupFailure) { - return WriteError(String.Format("Test Collection Cleanup Failure ({0})", cleanupFailure.TestCollection.DisplayName), cleanupFailure, cleanupFailure.TestCases); + return WriteError(string.Format("Test Collection Cleanup Failure ({0})", cleanupFailure.TestCollection.DisplayName), cleanupFailure, cleanupFailure.TestCases); } protected override bool Visit(ITestCleanupFailure cleanupFailure) { - return WriteError(String.Format("Test Cleanup Failure ({0})", cleanupFailure.Test.DisplayName), cleanupFailure, cleanupFailure.TestCases); + return WriteError(string.Format("Test Cleanup Failure ({0})", cleanupFailure.Test.DisplayName), cleanupFailure, cleanupFailure.TestCases); } protected override bool Visit(ITestMethodCleanupFailure cleanupFailure) { - return WriteError(String.Format("Test Method Cleanup Failure ({0})", cleanupFailure.TestMethod.Method.Name), cleanupFailure, cleanupFailure.TestCases); + return WriteError(string.Format("Test Method Cleanup Failure ({0})", cleanupFailure.TestMethod.Method.Name), cleanupFailure, cleanupFailure.TestCases); } protected bool WriteError(string failureName, IFailureInformation failureInfo, IEnumerable testCases) @@ -134,12 +163,14 @@ protected bool WriteError(string failureName, IFailureInformation failureInfo, I var result = MakeVsTestResult(TestOutcome.Failed, testCase, testCase.DisplayName); if (result != null) { - result.ErrorMessage = String.Format("[{0}]: {1}", failureName, ExceptionUtility.CombineMessages(failureInfo)); + result.ErrorMessage = string.Format("[{0}]: {1}", failureName, ExceptionUtility.CombineMessages(failureInfo)); result.ErrorStackTrace = ExceptionUtility.CombineStackTraces(failureInfo); - recorder.RecordEnd(result.TestCase, result.Outcome); - recorder.RecordResult(result); + TryAndReport("RecordEnd (Failure)", testCase, () => recorder.RecordEnd(result.TestCase, result.Outcome)); + TryAndReport("RecordResult (Failure)", testCase, () => recorder.RecordResult(result)); } + else + logger.LogWarning(testCase, "(Failure) Could not find VS test case for {0} (ID = {1})", testCase.DisplayName, testCase.UniqueID); } return !cancelledThunk(); @@ -170,7 +201,7 @@ private VsTestResult MakeVsTestResult(TestOutcome outcome, ITestCase testCase, s if (result.Duration.TotalMilliseconds == 0) result.Duration = TimeSpan.FromMilliseconds(1); - if (!String.IsNullOrEmpty(output)) + if (!string.IsNullOrEmpty(output)) result.Messages.Add(new VsTestResultMessage(VsTestResultMessage.StandardOutCategory, output)); return result; diff --git a/xunit.runner.visualstudio.testadapter/VsTestRunner.cs b/xunit.runner.visualstudio.testadapter/VsTestRunner.cs index cd2bf2ca..66bc6ee8 100644 --- a/xunit.runner.visualstudio.testadapter/VsTestRunner.cs +++ b/xunit.runner.visualstudio.testadapter/VsTestRunner.cs @@ -24,13 +24,13 @@ public class VsTestRunner : ITestDiscoverer, ITestExecutor static readonly HashSet platformAssemblies = new HashSet(StringComparer.OrdinalIgnoreCase) { - "microsoft.visualstudio.testplatform.unittestframework.dll", - "microsoft.visualstudio.testplatform.core.dll", - "microsoft.visualstudio.testplatform.testexecutor.core.dll", - "microsoft.visualstudio.testplatform.extensions.msappcontaineradapter.dll", - "microsoft.visualstudio.testplatform.objectmodel.dll", - "microsoft.visualstudio.testplatform.utilities.dll", - "vstest.executionengine.appcontainer.exe", + "microsoft.visualstudio.testplatform.unittestframework.dll", + "microsoft.visualstudio.testplatform.core.dll", + "microsoft.visualstudio.testplatform.testexecutor.core.dll", + "microsoft.visualstudio.testplatform.extensions.msappcontaineradapter.dll", + "microsoft.visualstudio.testplatform.objectmodel.dll", + "microsoft.visualstudio.testplatform.utilities.dll", + "vstest.executionengine.appcontainer.exe", "vstest.executionengine.appcontainer.x86.exe", "xunit.execution.desktop.dll", "xunit.execution.win8.dll", @@ -40,7 +40,8 @@ public class VsTestRunner : ITestDiscoverer, ITestExecutor "xunit.runner.utility.universal.dll", "xunit.runner.visualstudio.testadapter.dll", "xunit.core.dll", - "xunit.assert.dll" + "xunit.assert.dll", + "xunit.dll" }; bool cancelled; @@ -57,23 +58,70 @@ public void DiscoverTests(IEnumerable sources, IDiscoveryContext discove Guard.ArgumentNotNull("discoverySink", discoverySink); Guard.ArgumentValid("sources", "AppX not supported for discovery", !ContainsAppX(sources)); + var stopwatch = Stopwatch.StartNew(); + var loggerHelper = new LoggerHelper(logger, stopwatch); + DiscoverTests( sources, - logger, - (source, discoverer, discoveryOptions) => new VsDiscoveryVisitor(source, discoverer, logger, discoverySink, discoveryOptions, () => cancelled) + loggerHelper, + stopwatch, + (source, discoverer, discoveryOptions) => new VsDiscoveryVisitor(source, discoverer, loggerHelper, discoverySink, discoveryOptions, () => cancelled) + ); + } + + public void RunTests(IEnumerable sources, IRunContext runContext, IFrameworkHandle frameworkHandle) + { + Guard.ArgumentNotNull("sources", sources); + + var stopwatch = Stopwatch.StartNew(); + var logger = new LoggerHelper(frameworkHandle, stopwatch); + + // In this case, we need to go thru the files manually + if (ContainsAppX(sources)) + { +#if WINDOWS_PHONE_APP || WINDOWS_APP + var sourcePath = Windows.ApplicationModel.Package.Current.InstalledLocation.Path; +#else + var sourcePath = Environment.CurrentDirectory; +#endif + sources = Directory.GetFiles(sourcePath, "*.dll") + .Where(file => !platformAssemblies.Contains(Path.GetFileName(file))) + .ToList(); + } + + RunTests(runContext, frameworkHandle, logger, stopwatch, () => GetTests(sources, logger, stopwatch)); + } + + public void RunTests(IEnumerable tests, IRunContext runContext, IFrameworkHandle frameworkHandle) + { + Guard.ArgumentNotNull("tests", tests); + Guard.ArgumentValid("tests", "AppX not supported in this overload", !ContainsAppX(tests.Select(t => t.Source))); + + var stopwatch = Stopwatch.StartNew(); + var logger = new LoggerHelper(frameworkHandle, stopwatch); + + RunTests( + runContext, frameworkHandle, logger, stopwatch, + () => tests.GroupBy(testCase => testCase.Source) + .Select(group => new AssemblyRunInfo { AssemblyFileName = group.Key, Configuration = ConfigReader.Load(group.Key), TestCases = group }) + .ToList() ); } + // Helpers + + static bool ContainsAppX(IEnumerable sources) + { + return sources.Any(s => string.Compare(Path.GetExtension(s), ".appx", StringComparison.OrdinalIgnoreCase) == 0); + } + void DiscoverTests(IEnumerable sources, - IMessageLogger logger, + LoggerHelper logger, + Stopwatch stopwatch, Func visitorFactory, - Action visitComplete = null, - Stopwatch stopwatch = null) + Action visitComplete = null) where TVisitor : IVsDiscoveryVisitor, IDisposable { - if (stopwatch == null) - stopwatch = Stopwatch.StartNew(); - try { RemotingUtility.CleanUpRegisteredChannels(); @@ -93,12 +141,11 @@ void DiscoverTests(IEnumerable sources, if (!IsXunitTestAssembly(assemblyFileName)) { if (configuration.DiagnosticMessagesOrDefault) - logger.SendMessage(TestMessageLevel.Informational, - String.Format("[xUnit.net {0}] Skipping: {1} (no reference to xUnit.net)", stopwatch.Elapsed, fileName)); + logger.Log("Skipping: {0} (no reference to xUnit.net)", fileName); } else { - var diagnosticMessageVisitor = new DiagnosticMessageVisitor(logger, fileName, configuration.DiagnosticMessagesOrDefault, stopwatch); + var diagnosticMessageVisitor = new DiagnosticMessageVisitor(logger.InnerLogger, fileName, configuration.DiagnosticMessagesOrDefault, stopwatch); using (var framework = new XunitFrontController(assemblyFileName, configFileName: null, shadowCopy: true, diagnosticMessageSink: diagnosticMessageVisitor)) { @@ -108,15 +155,14 @@ void DiscoverTests(IEnumerable sources, targetFramework.StartsWith("Xamarin.iOS", StringComparison.OrdinalIgnoreCase)) { if (configuration.DiagnosticMessagesOrDefault) - logger.SendMessage(TestMessageLevel.Informational, String.Format("[xUnit.net {0}] Skipping: {1} (unsupported target framework '{2}')", stopwatch.Elapsed, fileName, targetFramework)); + logger.Log("Skipping: {0} (unsupported target framework '{1}')", fileName, targetFramework); } else { var discoveryOptions = TestFrameworkOptions.ForDiscovery(configuration); if (configuration.DiagnosticMessagesOrDefault) - logger.SendMessage(TestMessageLevel.Informational, - String.Format("[xUnit.net {0}] Discovery starting: {1} (name display = {2})", stopwatch.Elapsed, fileName, discoveryOptions.GetMethodDisplayOrDefault())); + logger.Log("Discovering: {0} (method display = {1})", fileName, discoveryOptions.GetMethodDisplayOrDefault()); using (var visitor = visitorFactory(assemblyFileName, framework, discoveryOptions)) { @@ -127,8 +173,7 @@ void DiscoverTests(IEnumerable sources, visitComplete(assemblyFileName, framework, discoveryOptions, visitor); if (configuration.DiagnosticMessagesOrDefault) - logger.SendMessage(TestMessageLevel.Informational, - String.Format("[xUnit.net {0}] Discovery finished: {1} ({2} tests)", stopwatch.Elapsed, fileName, totalTests)); + logger.Log("Discovered: {0} ({1} tests)", fileName, totalTests); } } } @@ -142,24 +187,20 @@ void DiscoverTests(IEnumerable sources, var fileLoad = ex as FileLoadException; #endif if (fileNotFound != null) - logger.SendMessage(TestMessageLevel.Informational, - String.Format("[xUnit.net {0}] Skipping: {1} (could not find dependent assembly '{2}')", stopwatch.Elapsed, fileName, Path.GetFileNameWithoutExtension(fileNotFound.FileName))); + logger.LogWarning("Skipping: {0} (could not find dependent assembly '{1}')", fileName, Path.GetFileNameWithoutExtension(fileNotFound.FileName)); #if !WINDOWS_PHONE_APP && !WINDOWS_PHONE else if (fileLoad != null) - logger.SendMessage(TestMessageLevel.Informational, - String.Format("[xUnit.net {0}] Skipping: {1} (could not find dependent assembly '{2}')", stopwatch.Elapsed, fileName, Path.GetFileNameWithoutExtension(fileLoad.FileName))); + logger.LogWarning("Skipping: {0} (could not find dependent assembly '{1}')", fileName, Path.GetFileNameWithoutExtension(fileLoad.FileName)); #endif else - logger.SendMessage(TestMessageLevel.Warning, - String.Format("[xUnit.net {0}] Exception discovering tests from {1}: {2}", stopwatch.Elapsed, fileName, ex)); + logger.LogWarning("Exception discovering tests from {0}: {1}", fileName, ex); } } } } catch (Exception e) { - logger.SendMessage(TestMessageLevel.Warning, - String.Format("[xUnit.net {0}] Exception discovering tests: {1}", stopwatch.Elapsed, e.Unwrap())); + logger.LogWarning("Exception discovering tests: {0}", e.Unwrap()); } stopwatch.Stop(); @@ -170,13 +211,13 @@ static TestProperty GetTestProperty() return TestProperty.Register("XunitTestCase", "xUnit.net Test Case", typeof(string), typeof(VsTestRunner)); } - List GetTests(IEnumerable sources, IMessageLogger logger, Stopwatch stopwatch) + List GetTests(IEnumerable sources, LoggerHelper logger, Stopwatch stopwatch) { #if WIN8_STORE // For store apps, the files are copied to the AppX dir, we need to load it from there sources = sources.Select(s => Path.Combine(Path.GetDirectoryName(Assembly.GetExecutingAssembly().Location), Path.GetFileName(s))); #elif WINDOWS_PHONE_APP - sources = sources.Select(s => Path.Combine(Windows.ApplicationModel.Package.Current.InstalledLocation.Path, Path.GetFileName(s))); ; + sources = sources.Select(s => Path.Combine(Windows.ApplicationModel.Package.Current.InstalledLocation.Path, Path.GetFileName(s))); #endif var result = new List(); @@ -184,6 +225,7 @@ List GetTests(IEnumerable sources, IMessageLogger logge DiscoverTests( sources, logger, + stopwatch, (source, discoverer, discoveryOptions) => new VsExecutionDiscoveryVisitor(), (source, discoverer, discoveryOptions, visitor) => result.Add( @@ -192,17 +234,15 @@ List GetTests(IEnumerable sources, IMessageLogger logge AssemblyFileName = source, Configuration = ConfigReader.Load(source), TestCases = visitor.TestCases - .GroupBy(tc => String.Format("{0}.{1}", tc.TestMethod.TestClass.Class.Name, tc.TestMethod.Method.Name)) + .GroupBy(tc => string.Format("{0}.{1}", tc.TestMethod.TestClass.Class.Name, tc.TestMethod.Method.Name)) .SelectMany(group => group.Select(testCase => VsDiscoveryVisitor.CreateVsTestCase(source, discoverer, testCase, forceUniqueNames: group.Count() > 1, - logger: logger, - logDiscovery: discoveryOptions.GetDiagnosticMessagesOrDefault())) + logger: logger)) .Where(vsTestCase => vsTestCase != null)) .ToList() - }), - stopwatch + }) ); return result; @@ -219,45 +259,13 @@ static bool IsXunitTestAssembly(string assemblyFileName) return File.Exists(xunitPath) || File.Exists(xunitExecutionPath); } - public void RunTests(IEnumerable sources, IRunContext runContext, IFrameworkHandle frameworkHandle) - { - Guard.ArgumentNotNull("sources", sources); - - // In this case, we need to go thru the files manually - if (ContainsAppX(sources)) - { -#if WINDOWS_PHONE_APP - var sourcePath = Windows.ApplicationModel.Package.Current.InstalledLocation.Path; -#else - var sourcePath = Environment.CurrentDirectory; -#endif - sources = Directory.GetFiles(sourcePath, "*.dll") - .Where(file => !platformAssemblies.Contains(Path.GetFileName(file))) - .ToList(); - } - - var stopwatch = Stopwatch.StartNew(); - RunTests(runContext, frameworkHandle, stopwatch, () => GetTests(sources, frameworkHandle, stopwatch)); - stopwatch.Stop(); - } - - public void RunTests(IEnumerable tests, IRunContext runContext, IFrameworkHandle frameworkHandle) - { - Guard.ArgumentNotNull("tests", tests); - Guard.ArgumentValid("tests", "AppX not supported in this overload", !ContainsAppX(tests.Select(t => t.Source))); - - var stopwatch = Stopwatch.StartNew(); - RunTests(runContext, frameworkHandle, stopwatch, () => tests.GroupBy(testCase => testCase.Source) - .Select(group => new AssemblyRunInfo { AssemblyFileName = group.Key, Configuration = ConfigReader.Load(group.Key), TestCases = group }) - .ToList()); - stopwatch.Stop(); - } - - void RunTests(IRunContext runContext, IFrameworkHandle frameworkHandle, Stopwatch stopwatch, Func> testCaseAccessor) + void RunTests(IRunContext runContext, IFrameworkHandle frameworkHandle, LoggerHelper logger, Stopwatch stopwatch, Func> testCaseAccessor) { Guard.ArgumentNotNull("runContext", runContext); Guard.ArgumentNotNull("frameworkHandle", frameworkHandle); + Debugger.Break(); + var toDispose = new List(); try @@ -272,12 +280,12 @@ void RunTests(IRunContext runContext, IFrameworkHandle frameworkHandle, Stopwatc using (AssemblyHelper.SubscribeResolve()) if (parallelizeAssemblies) assemblies - .Select(runInfo => RunTestsInAssemblyAsync(frameworkHandle, toDispose, runInfo, stopwatch)) + .Select(runInfo => RunTestsInAssemblyAsync(frameworkHandle, logger, toDispose, runInfo, stopwatch)) .ToList() .ForEach(@event => @event.WaitOne()); else assemblies - .ForEach(runInfo => RunTestsInAssembly(frameworkHandle, toDispose, runInfo, stopwatch)); + .ForEach(runInfo => RunTestsInAssembly(frameworkHandle, logger, toDispose, runInfo, stopwatch)); } finally { @@ -286,6 +294,7 @@ void RunTests(IRunContext runContext, IFrameworkHandle frameworkHandle, Stopwatc } void RunTestsInAssembly(IFrameworkHandle frameworkHandle, + LoggerHelper logger, List toDispose, AssemblyRunInfo runInfo, Stopwatch stopwatch) @@ -298,12 +307,10 @@ void RunTestsInAssembly(IFrameworkHandle frameworkHandle, if (runInfo.Configuration.DiagnosticMessagesOrDefault) lock (stopwatch) - frameworkHandle.SendMessage(TestMessageLevel.Informational, String.Format("[xUnit.net {0}] Execution starting: {1} (method display = {2}, parallel test collections = {3}, max threads = {4})", - stopwatch.Elapsed, - assemblyDisplayName, - runInfo.Configuration.MethodDisplayOrDefault, - runInfo.Configuration.ParallelizeTestCollectionsOrDefault, - runInfo.Configuration.MaxParallelThreadsOrDefault)); + logger.Log("Starting: {0} (parallel test collections = {1}, max threads = {2})", + assemblyDisplayName, + runInfo.Configuration.ParallelizeTestCollectionsOrDefault ? "on" : "off", + runInfo.Configuration.MaxParallelThreadsOrDefault); #if WIN8_STORE // For store apps, the files are copied to the AppX dir, we need to load it from there @@ -322,18 +329,18 @@ void RunTestsInAssembly(IFrameworkHandle frameworkHandle, var xunitTestCases = runInfo.TestCases.ToDictionary(tc => controller.Deserialize(tc.GetPropertyValue(SerializedTestCaseProperty, null))); var executionOptions = TestFrameworkOptions.ForExecution(runInfo.Configuration); - using (var executionVisitor = new VsExecutionVisitor(frameworkHandle, xunitTestCases, executionOptions, () => cancelled)) + using (var executionVisitor = new VsExecutionVisitor(frameworkHandle, logger, xunitTestCases, executionOptions, () => cancelled)) { controller.RunTests(xunitTestCases.Keys.ToList(), executionVisitor, executionOptions); executionVisitor.Finished.WaitOne(); } if (runInfo.Configuration.DiagnosticMessagesOrDefault) - lock (stopwatch) - frameworkHandle.SendMessage(TestMessageLevel.Informational, String.Format("[xUnit.net {0}] Execution finished: {1}", stopwatch.Elapsed, assemblyDisplayName)); + logger.Log("Finished: {0}", assemblyDisplayName); } ManualResetEvent RunTestsInAssemblyAsync(IFrameworkHandle frameworkHandle, + LoggerHelper logger, List toDispose, AssemblyRunInfo runInfo, Stopwatch stopwatch) @@ -343,7 +350,7 @@ ManualResetEvent RunTestsInAssemblyAsync(IFrameworkHandle frameworkHandle, { try { - RunTestsInAssembly(frameworkHandle, toDispose, runInfo, stopwatch); + RunTestsInAssembly(frameworkHandle, logger, toDispose, runInfo, stopwatch); } finally { @@ -361,11 +368,6 @@ ManualResetEvent RunTestsInAssemblyAsync(IFrameworkHandle frameworkHandle, } - private static bool ContainsAppX(IEnumerable sources) - { - return sources.Any(s => string.Compare(Path.GetExtension(s), ".appx", StringComparison.OrdinalIgnoreCase) == 0); - } - class Grouping : IGrouping { readonly IEnumerable elements; diff --git a/xunit.runner.visualstudio.testadapter/xunit.runner.visualstudio.testadapter.csproj b/xunit.runner.visualstudio.testadapter/xunit.runner.visualstudio.testadapter.csproj index b4fdc8d7..0245948d 100644 --- a/xunit.runner.visualstudio.testadapter/xunit.runner.visualstudio.testadapter.csproj +++ b/xunit.runner.visualstudio.testadapter/xunit.runner.visualstudio.testadapter.csproj @@ -63,6 +63,7 @@ + diff --git a/xunit.runner.visualstudio.win8/xunit.runner.visualstudio.win8.csproj b/xunit.runner.visualstudio.win8/xunit.runner.visualstudio.win8.csproj index 7ae16ecf..653b0949 100644 --- a/xunit.runner.visualstudio.win8/xunit.runner.visualstudio.win8.csproj +++ b/xunit.runner.visualstudio.win8/xunit.runner.visualstudio.win8.csproj @@ -72,6 +72,9 @@ Utility\Guard.cs + + Utility\LoggerHelper.cs + Visitors\DiagnosticMessageVisitor.cs diff --git a/xunit.runner.visualstudio.wpa81/xunit.runner.visualstudio.wpa81.csproj b/xunit.runner.visualstudio.wpa81/xunit.runner.visualstudio.wpa81.csproj index fc0f7c29..bfcd5db8 100644 --- a/xunit.runner.visualstudio.wpa81/xunit.runner.visualstudio.wpa81.csproj +++ b/xunit.runner.visualstudio.wpa81/xunit.runner.visualstudio.wpa81.csproj @@ -113,6 +113,9 @@ Utility\Guard.cs + + Utility\LoggerHelper.cs + Visitors\DiagnosticMessageVisitor.cs From 90a250f780a4bc2f8e620bacacd237a9827bb11c Mon Sep 17 00:00:00 2001 From: Brad Wilson Date: Sat, 4 Jul 2015 08:40:50 -0700 Subject: [PATCH 6/8] Sneaky little Debugger.Break() :-p --- xunit.runner.visualstudio.testadapter/VsTestRunner.cs | 2 -- 1 file changed, 2 deletions(-) diff --git a/xunit.runner.visualstudio.testadapter/VsTestRunner.cs b/xunit.runner.visualstudio.testadapter/VsTestRunner.cs index 66bc6ee8..1dba5383 100644 --- a/xunit.runner.visualstudio.testadapter/VsTestRunner.cs +++ b/xunit.runner.visualstudio.testadapter/VsTestRunner.cs @@ -264,8 +264,6 @@ void RunTests(IRunContext runContext, IFrameworkHandle frameworkHandle, LoggerHe Guard.ArgumentNotNull("runContext", runContext); Guard.ArgumentNotNull("frameworkHandle", frameworkHandle); - Debugger.Break(); - var toDispose = new List(); try From 1212fd020aad13fa4ab9608d1d6e00a5d98a8c4f Mon Sep 17 00:00:00 2001 From: Brad Wilson Date: Sat, 4 Jul 2015 11:45:37 -0700 Subject: [PATCH 7/8] Add ForcePushMyGet variable to visualstudio.xunit.proj --- visualstudio.xunit.proj | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/visualstudio.xunit.proj b/visualstudio.xunit.proj index 287e4837..9c9f7a89 100644 --- a/visualstudio.xunit.proj +++ b/visualstudio.xunit.proj @@ -91,7 +91,7 @@ - + From 0fbff321a56ca7b0f388557602ce6607916b2b00 Mon Sep 17 00:00:00 2001 From: Lucas Loegel Date: Thu, 2 Jul 2015 14:46:13 +0200 Subject: [PATCH 8/8] Fix issue #66 - Test discovery may fail if the test display name is longer than 447 characters. --- .../Visitors/VsDiscoveryVisitor.cs | 13 ++++++++++++- 1 file changed, 12 insertions(+), 1 deletion(-) diff --git a/xunit.runner.visualstudio.testadapter/Visitors/VsDiscoveryVisitor.cs b/xunit.runner.visualstudio.testadapter/Visitors/VsDiscoveryVisitor.cs index 1836b655..67bfced2 100644 --- a/xunit.runner.visualstudio.testadapter/Visitors/VsDiscoveryVisitor.cs +++ b/xunit.runner.visualstudio.testadapter/Visitors/VsDiscoveryVisitor.cs @@ -19,6 +19,9 @@ namespace Xunit.Runner.VisualStudio.TestAdapter { public class VsDiscoveryVisitor : TestMessageVisitor, IVsDiscoveryVisitor { + const string Ellipsis = "..."; + const int MaximumDisplayNameLength = 447; + static readonly Action addTraitThunk = GetAddTraitThunk(); static readonly Uri uri = new Uri(Constants.ExecutorUri); @@ -83,7 +86,15 @@ static string Escape(string value) if (value == null) return string.Empty; - return value.Replace("\r", "\\r").Replace("\n", "\\n").Replace("\t", "\\t"); + return Truncate(value.Replace("\r", "\\r").Replace("\n", "\\n").Replace("\t", "\\t")); + } + + static string Truncate(string value) + { + if (value.Length <= MaximumDisplayNameLength) + return value; + + return value.Substring(0, MaximumDisplayNameLength - Ellipsis.Length) + Ellipsis; } public int Finish()