diff --git a/.gitignore b/.gitignore index 29b7afec0..de69fc2e0 100644 --- a/.gitignore +++ b/.gitignore @@ -177,4 +177,6 @@ test-results package images MockAssemblyResult.xml -PortabilityAnalysis*.html \ No newline at end of file +PortabilityAnalysis*.html +tools +!tools/packages.config diff --git a/.travis.yml b/.travis.yml index 0fbf932db..593e92bd8 100644 --- a/.travis.yml +++ b/.travis.yml @@ -3,14 +3,10 @@ sudo: false mono: - latest - 4.2.4 - - 3.2.8 os: - linux - osx matrix: - exclude: - - os: osx - mono: 3.2.8 allow_failures: - mono: latest fast_finish: true diff --git a/NUnitConsole.sln b/NUnitConsole.sln index a33e06ec9..70d3fbbe0 100644 --- a/NUnitConsole.sln +++ b/NUnitConsole.sln @@ -51,23 +51,6 @@ Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "engine", "engine", "{43A219 nuget\engine\nunit.nuget.addins = nuget\engine\nunit.nuget.addins EndProjectSection EndProject -Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "framework", "framework", "{BC87F477-1A7A-45D0-9AC1-9F7315264732}" - ProjectSection(SolutionItems) = preProject - nuget\framework\nunit.nuspec = nuget\framework\nunit.nuspec - nuget\framework\nunitCF.nuspec = nuget\framework\nunitCF.nuspec - nuget\framework\nunitSL.nuspec = nuget\framework\nunitSL.nuspec - EndProjectSection -EndProject -Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "nunitlite", "nunitlite", "{140CDAD6-6E11-4A97-94F3-B23A14391117}" - ProjectSection(SolutionItems) = preProject - nuget\nunitlite\install.ps1 = nuget\nunitlite\install.ps1 - nuget\nunitlite\nunitlite.nuspec = nuget\nunitlite\nunitlite.nuspec - nuget\nunitlite\nunitliteCF.nuspec = nuget\nunitlite\nunitliteCF.nuspec - nuget\nunitlite\nunitliteSL.nuspec = nuget\nunitlite\nunitliteSL.nuspec - nuget\nunitlite\Program.cs = nuget\nunitlite\Program.cs - nuget\nunitlite\Program.vb = nuget\nunitlite\Program.vb - EndProjectSection -EndProject Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "runners", "runners", "{F3E87D0F-6F06-4C0B-AE06-42C0834C3C6E}" ProjectSection(SolutionItems) = preProject nuget\runners\nunit.console-runner-with-extensions.nuspec = nuget\runners\nunit.console-runner-with-extensions.nuspec @@ -129,8 +112,6 @@ Global {B310A760-8AE1-41CA-81F8-03B12E2FCE30} = {576DB1E6-C5EC-4FEF-A826-EC19D8BEE572} {28B605B2-E2E9-417E-8369-49E263F1F31B} = {31B45C4C-206F-4F31-9CC6-33BF11DFEE39} {43A219A8-2995-4884-806F-FDB9CD25D403} = {A972031D-2F61-4183-AF75-99EE1A9F6B32} - {BC87F477-1A7A-45D0-9AC1-9F7315264732} = {A972031D-2F61-4183-AF75-99EE1A9F6B32} - {140CDAD6-6E11-4A97-94F3-B23A14391117} = {A972031D-2F61-4183-AF75-99EE1A9F6B32} {F3E87D0F-6F06-4C0B-AE06-42C0834C3C6E} = {A972031D-2F61-4183-AF75-99EE1A9F6B32} {D2C80E4B-1117-4F02-AB02-E453BDA0C58E} = {31B45C4C-206F-4F31-9CC6-33BF11DFEE39} EndGlobalSection diff --git a/build.cake b/build.cake index e6e4dfa1e..ba2fa9786 100644 --- a/build.cake +++ b/build.cake @@ -334,20 +334,6 @@ Task("PackageConsole") }); }); -Task("PackageZip") - .IsDependentOn("CreateImage") - .Does(() => - { - CreateDirectory(PACKAGE_DIR); - - var currentImageDir = IMAGE_DIR + "NUnit-" + packageVersion + "/"; - - var zipFiles = - GetFiles(currentImageDir + "*.*") + - GetFiles(currentImageDir + "bin/*.*"); - Zip(currentImageDir, File(ZIP_PACKAGE), zipFiles); - }); - ////////////////////////////////////////////////////////////////////// // SETUP AND TEARDOWN TASKS ////////////////////////////////////////////////////////////////////// @@ -472,8 +458,7 @@ Task("Test") Task("Package") .IsDependentOn("CheckForError") .IsDependentOn("PackageEngine") - .IsDependentOn("PackageConsole") - .IsDependentOn("PackageZip"); + .IsDependentOn("PackageConsole"); Task("Appveyor") .IsDependentOn("Build") diff --git a/build.ps1 b/build.ps1 index 519ad09eb..44de57932 100644 --- a/build.ps1 +++ b/build.ps1 @@ -1,3 +1,44 @@ +########################################################################## +# This is the Cake bootstrapper script for PowerShell. +# This file was downloaded from https://github.com/cake-build/resources +# Feel free to change this file to fit your needs. +########################################################################## + +<# + +.SYNOPSIS +This is a Powershell script to bootstrap a Cake build. + +.DESCRIPTION +This Powershell script will download NuGet if missing, restore NuGet tools (including Cake) +and execute your Cake build script with the parameters you provide. + +.PARAMETER Script +The build script to execute. +.PARAMETER Target +The build script target to run. +.PARAMETER Configuration +The build configuration to use. +.PARAMETER Verbosity +Specifies the amount of information to be displayed. +.PARAMETER Experimental +Tells Cake to use the latest Roslyn release. +.PARAMETER WhatIf +Performs a dry run of the build script. +No tasks will be executed. +.PARAMETER Mono +Tells Cake to use the Mono scripting engine. +.PARAMETER SkipToolPackageRestore +Skips restoring of packages. +.PARAMETER ScriptArgs +Remaining arguments are added here. + +.LINK +http://cakebuild.net + +#> + +[CmdletBinding()] Param( [string]$Script = "build.cake", [string]$Target = "Default", @@ -6,16 +47,63 @@ Param( [ValidateSet("Quiet", "Minimal", "Normal", "Verbose", "Diagnostic")] [string]$Verbosity = "Verbose", [switch]$Experimental, - [switch]$WhatIf + [Alias("DryRun","Noop")] + [switch]$WhatIf, + [switch]$Mono, + [switch]$SkipToolPackageRestore, + [Parameter(Position=0,Mandatory=$false,ValueFromRemainingArguments=$true)] + [string[]]$ScriptArgs ) +[Reflection.Assembly]::LoadWithPartialName("System.Security") | Out-Null +function MD5HashFile([string] $filePath) +{ + if ([string]::IsNullOrEmpty($filePath) -or !(Test-Path $filePath -PathType Leaf)) + { + return $null + } + + [System.IO.Stream] $file = $null; + [System.Security.Cryptography.MD5] $md5 = $null; + try + { + $md5 = [System.Security.Cryptography.MD5]::Create() + $file = [System.IO.File]::OpenRead($filePath) + return [System.BitConverter]::ToString($md5.ComputeHash($file)) + } + finally + { + if ($file -ne $null) + { + $file.Dispose() + } + } +} + +Write-Host "Preparing to run build script..." + +if(!$PSScriptRoot){ + $PSScriptRoot = Split-Path $MyInvocation.MyCommand.Path -Parent +} + $TOOLS_DIR = Join-Path $PSScriptRoot "tools" $NUGET_EXE = Join-Path $TOOLS_DIR "nuget.exe" $CAKE_EXE = Join-Path $TOOLS_DIR "Cake/Cake.exe" +$NUGET_URL = "https://dist.nuget.org/win-x86-commandline/latest/nuget.exe" +$PACKAGES_CONFIG = Join-Path $TOOLS_DIR "packages.config" +$PACKAGES_CONFIG_MD5 = Join-Path $TOOLS_DIR "packages.config.md5sum" + +# Should we use mono? +$UseMono = ""; +if($Mono.IsPresent) { + Write-Verbose -Message "Using the Mono based scripting engine." + $UseMono = "-mono" +} -# Should we use experimental build of Roslyn? +# Should we use the new Roslyn? $UseExperimental = ""; -if($Experimental.IsPresent) { +if($Experimental.IsPresent -and !($Mono.IsPresent)) { + Write-Verbose -Message "Using experimental version of Roslyn." $UseExperimental = "-experimental" } @@ -25,31 +113,77 @@ if($WhatIf.IsPresent) { $UseDryRun = "-dryrun" } -# Try download NuGet.exe if do not exist. +# Make sure tools folder exists +if ((Test-Path $PSScriptRoot) -and !(Test-Path $TOOLS_DIR)) { + Write-Verbose -Message "Creating tools directory..." + New-Item -Path $TOOLS_DIR -Type directory | out-null +} + +# Make sure that packages.config exist. +if (!(Test-Path $PACKAGES_CONFIG)) { + Write-Verbose -Message "Downloading packages.config..." + try { (New-Object System.Net.WebClient).DownloadFile("http://cakebuild.net/download/bootstrapper/packages", $PACKAGES_CONFIG) } catch { + Throw "Could not download packages.config." + } +} + +# Try find NuGet.exe in path if not exists if (!(Test-Path $NUGET_EXE)) { - Invoke-WebRequest -Uri http://nuget.org/nuget.exe -OutFile $NUGET_EXE + Write-Verbose -Message "Trying to find nuget.exe in PATH..." + $existingPaths = $Env:Path -Split ';' | Where-Object { (![string]::IsNullOrEmpty($_)) -and (Test-Path $_) } + $NUGET_EXE_IN_PATH = Get-ChildItem -Path $existingPaths -Filter "nuget.exe" | Select -First 1 + if ($NUGET_EXE_IN_PATH -ne $null -and (Test-Path $NUGET_EXE_IN_PATH.FullName)) { + Write-Verbose -Message "Found in PATH at $($NUGET_EXE_IN_PATH.FullName)." + $NUGET_EXE = $NUGET_EXE_IN_PATH.FullName + } } -# Make sure NuGet exists where we expect it. +# Try download NuGet.exe if not exists if (!(Test-Path $NUGET_EXE)) { - Throw "Could not find NuGet.exe" + Write-Verbose -Message "Downloading NuGet.exe..." + try { + (New-Object System.Net.WebClient).DownloadFile($NUGET_URL, $NUGET_EXE) + } catch { + Throw "Could not download NuGet.exe." + } } -# Restore tools from NuGet. -Push-Location -Set-Location $TOOLS_DIR -Invoke-Expression "$NUGET_EXE install -ExcludeVersion" -Pop-Location -if ($LASTEXITCODE -ne 0) { - exit $LASTEXITCODE +# Save nuget.exe path to environment to be available to child processed +$ENV:NUGET_EXE = $NUGET_EXE + +# Restore tools from NuGet? +if(-Not $SkipToolPackageRestore.IsPresent) { + Push-Location + Set-Location $TOOLS_DIR + + # Check for changes in packages.config and remove installed tools if true. + [string] $md5Hash = MD5HashFile($PACKAGES_CONFIG) + if((!(Test-Path $PACKAGES_CONFIG_MD5)) -Or + ($md5Hash -ne (Get-Content $PACKAGES_CONFIG_MD5 ))) { + Write-Verbose -Message "Missing or changed package.config hash..." + Remove-Item * -Recurse -Exclude packages.config,nuget.exe + } + + Write-Verbose -Message "Restoring tools from NuGet..." + $NuGetOutput = Invoke-Expression "&`"$NUGET_EXE`" install -ExcludeVersion -OutputDirectory `"$TOOLS_DIR`"" + + if ($LASTEXITCODE -ne 0) { + Throw "An error occured while restoring NuGet tools." + } + else + { + $md5Hash | Out-File $PACKAGES_CONFIG_MD5 -Encoding "ASCII" + } + Write-Verbose -Message ($NuGetOutput | out-string) + Pop-Location } # Make sure that Cake has been installed. if (!(Test-Path $CAKE_EXE)) { - Throw "Could not find Cake.exe" + Throw "Could not find Cake.exe at $CAKE_EXE" } # Start Cake -Invoke-Expression "$CAKE_EXE `"$Script`" -target=`"$Target`" -configuration=`"$Configuration`" -verbosity=`"$Verbosity`" $UseDryRun $UseExperimental" -Write-Host +Write-Host "Running build script..." +Invoke-Expression "& `"$CAKE_EXE`" `"$Script`" -target=`"$Target`" -configuration=`"$Configuration`" -verbosity=`"$Verbosity`" $UseMono $UseDryRun $UseExperimental $ScriptArgs" exit $LASTEXITCODE \ No newline at end of file diff --git a/build.sh b/build.sh index b9f997fc7..6e8f207c8 100755 --- a/build.sh +++ b/build.sh @@ -1,22 +1,35 @@ -#!/bin/bash -############################################################### -# This is the Cake bootstrapper script that is responsible for -# downloading Cake and all specified tools from NuGet. -############################################################### +#!/usr/bin/env bash + +########################################################################## +# This is the Cake bootstrapper script for Linux and OS X. +# This file was downloaded from https://github.com/cake-build/resources +# Feel free to change this file to fit your needs. +########################################################################## # Define directories. SCRIPT_DIR=$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd ) TOOLS_DIR=$SCRIPT_DIR/tools NUGET_EXE=$TOOLS_DIR/nuget.exe CAKE_EXE=$TOOLS_DIR/Cake/Cake.exe +PACKAGES_CONFIG=$TOOLS_DIR/packages.config +PACKAGES_CONFIG_MD5=$TOOLS_DIR/packages.config.md5sum + +# Define md5sum or md5 depending on Linux/OSX +MD5_EXE= +if [[ "$(uname -s)" == "Darwin" ]]; then + MD5_EXE="md5 -r" +else + MD5_EXE="md5sum" +fi # Define default arguments. SCRIPT="build.cake" TARGET="Default" CONFIGURATION="Release" VERBOSITY="verbose" -DRYRUN=false +DRYRUN= SHOW_VERSION=false +SCRIPT_ARGUMENTS=() # Parse arguments. for i in "$@"; do @@ -25,16 +38,33 @@ for i in "$@"; do -t|--target) TARGET="$2"; shift ;; -c|--configuration) CONFIGURATION="$2"; shift ;; -v|--verbosity) VERBOSITY="$2"; shift ;; - -d|--dryrun) DRYRUN=true ;; + -d|--dryrun) DRYRUN="-dryrun" ;; --version) SHOW_VERSION=true ;; + --) shift; SCRIPT_ARGUMENTS+=("$@"); break ;; + *) SCRIPT_ARGUMENTS+=("$1") ;; esac shift done +# Make sure the tools folder exist. +if [ ! -d "$TOOLS_DIR" ]; then + mkdir "$TOOLS_DIR" +fi + +# Make sure that packages.config exist. +if [ ! -f "$TOOLS_DIR/packages.config" ]; then + echo "Downloading packages.config..." + curl -Lsfo "$TOOLS_DIR/packages.config" http://cakebuild.net/download/bootstrapper/packages + if [ $? -ne 0 ]; then + echo "An error occured while downloading packages.config." + exit 1 + fi +fi + # Download NuGet if it does not exist. -if [ ! -f $NUGET_EXE ]; then +if [ ! -f "$NUGET_EXE" ]; then echo "Downloading NuGet..." - curl -Lsfo $NUGET_EXE https://www.nuget.org/nuget.exe + curl -Lsfo "$NUGET_EXE" https://dist.nuget.org/win-x86-commandline/latest/nuget.exe if [ $? -ne 0 ]; then echo "An error occured while downloading nuget.exe." exit 1 @@ -42,24 +72,30 @@ if [ ! -f $NUGET_EXE ]; then fi # Restore tools from NuGet. -pushd $TOOLS_DIR >/dev/null -mono $NUGET_EXE install -ExcludeVersion +pushd "$TOOLS_DIR" >/dev/null +if [ ! -f $PACKAGES_CONFIG_MD5 ] || [ "$( cat $PACKAGES_CONFIG_MD5 | sed 's/\r$//' )" != "$( $MD5_EXE $PACKAGES_CONFIG | awk '{ print $1 }' )" ]; then + find . -type d ! -name . | xargs rm -rf +fi + +mono "$NUGET_EXE" install -ExcludeVersion +if [ $? -ne 0 ]; then + echo "Could not restore NuGet packages." + exit 1 +fi + +$MD5_EXE $PACKAGES_CONFIG | awk '{ print $1 }' >| $PACKAGES_CONFIG_MD5 + popd >/dev/null # Make sure that Cake has been installed. -if [ ! -f $CAKE_EXE ]; then - echo "Could not find Cake.exe." +if [ ! -f "$CAKE_EXE" ]; then + echo "Could not find Cake.exe at '$CAKE_EXE'." exit 1 fi # Start Cake if $SHOW_VERSION; then - mono $CAKE_EXE -version -elif $DRYRUN; then - mono $CAKE_EXE $SCRIPT -verbosity=$VERBOSITY -configuration=$CONFIGURATION -target=$TARGET -dryrun + exec mono "$CAKE_EXE" -version else - mono $CAKE_EXE $SCRIPT -verbosity=$VERBOSITY -configuration=$CONFIGURATION -target=$TARGET -fi - -exit $? - + exec mono "$CAKE_EXE" $SCRIPT -verbosity=$VERBOSITY -configuration=$CONFIGURATION -target=$TARGET $DRYRUN "${SCRIPT_ARGUMENTS[@]}" +fi \ No newline at end of file diff --git a/packages/repositories.config b/packages/repositories.config index 98e54c9fb..d0745c6e6 100644 --- a/packages/repositories.config +++ b/packages/repositories.config @@ -1,21 +1,12 @@  - - - - - - - - - \ No newline at end of file diff --git a/src/NUnitConsole/nunit3-console.tests/CommandLineTests.cs b/src/NUnitConsole/nunit3-console.tests/CommandLineTests.cs index 74f365c4a..3d32ec454 100644 --- a/src/NUnitConsole/nunit3-console.tests/CommandLineTests.cs +++ b/src/NUnitConsole/nunit3-console.tests/CommandLineTests.cs @@ -104,6 +104,7 @@ public void CanRecognizeBooleanOptions(string propertyName, string pattern) [TestCase("DisplayTestLabels", "labels", new string[] { "Off", "On", "All" }, new string[] { "JUNK" })] [TestCase("InternalTraceLevel", "trace", new string[] { "Off", "Error", "Warning", "Info", "Debug", "Verbose" }, new string[] { "JUNK" })] [TestCase("DefaultTestNamePattern", "test-name-format", new string[] { "{m}{a}" }, new string[0])] + [TestCase("ConsoleEncoding", "encoding", new string[] { "utf-8", "ascii", "unicode" }, new string[0])] public void CanRecognizeStringOptions(string propertyName, string pattern, string[] goodValues, string[] badValues) { string[] prototypes = pattern.Split('|'); @@ -209,6 +210,7 @@ public void CanRecognizeIntOptions(string propertyName, string pattern) [TestCase("--trace")] [TestCase("--test-name-format")] [TestCase("--params")] + [TestCase("--encoding")] public void MissingValuesAreReported(string option) { ConsoleOptions options = new ConsoleOptions(option + "="); diff --git a/src/NUnitConsole/nunit3-console.tests/ConsoleOutputTests.cs b/src/NUnitConsole/nunit3-console.tests/ConsoleOutputTests.cs index a0adf1a97..70a12bb1b 100644 --- a/src/NUnitConsole/nunit3-console.tests/ConsoleOutputTests.cs +++ b/src/NUnitConsole/nunit3-console.tests/ConsoleOutputTests.cs @@ -21,10 +21,8 @@ // WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. // *********************************************************************** -using System; -using System.Collections.Generic; -using System.Text; using NUnit.Framework; +using System; namespace NUnit.ConsoleRunner.Tests { @@ -71,5 +69,11 @@ public void Test() Console.Error.WriteLine("Test: Console.Error.WriteLine()"); TestContext.WriteLine("Test: TestContext.WriteLine()"); } + + [Test] + public void ConsoleEncoding() + { + TestContext.WriteLine("•ÑÜńĭŧ·"); + } } } diff --git a/src/NUnitConsole/nunit3-console.tests/TestEventHandlerTests.cs b/src/NUnitConsole/nunit3-console.tests/TestEventHandlerTests.cs index 4f6d436c9..8d0e9239f 100644 --- a/src/NUnitConsole/nunit3-console.tests/TestEventHandlerTests.cs +++ b/src/NUnitConsole/nunit3-console.tests/TestEventHandlerTests.cs @@ -58,16 +58,16 @@ public void EventsWriteExpectedOutput(string report, string labels, string expec static TestCaseData[] EventData = new TestCaseData[] { // Start Events - new TestCaseData("", "Off", ""), - new TestCaseData("", "On", ""), - new TestCaseData("", "All", ""), - new TestCaseData("", "Off", ""), - new TestCaseData("", "On", ""), - new TestCaseData("", "All", ""), + new TestCaseData("", "Off", ""), + new TestCaseData("", "On", ""), + new TestCaseData("", "All", "=> SomeName\r\n"), + new TestCaseData("", "Off", ""), + new TestCaseData("", "On", ""), + new TestCaseData("", "All", ""), // Finish Events - No Output new TestCaseData("", "Off", ""), new TestCaseData("", "On", ""), - new TestCaseData("", "All", "=> SomeName\r\n"), + new TestCaseData("", "All", ""), new TestCaseData("", "Off", ""), new TestCaseData("", "On", ""), new TestCaseData("", "All", ""), @@ -83,7 +83,7 @@ public void EventsWriteExpectedOutput(string report, string labels, string expec new TestCaseData( "OUTPUT", "All", - "=> SomeName\r\nOUTPUT\r\n"), + "OUTPUT\r\n"), new TestCaseData( "OUTPUT", "Off", @@ -95,7 +95,7 @@ public void EventsWriteExpectedOutput(string report, string labels, string expec new TestCaseData( "OUTPUT", "All", - "=> SomeName\r\nOUTPUT\r\n"), + "OUTPUT\r\n"), // Output Events new TestCaseData( "OUTPUT", diff --git a/src/NUnitConsole/nunit3-console/CommandLineOptions.cs b/src/NUnitConsole/nunit3-console/CommandLineOptions.cs index bca033a59..c9519506b 100644 --- a/src/NUnitConsole/nunit3-console/CommandLineOptions.cs +++ b/src/NUnitConsole/nunit3-console/CommandLineOptions.cs @@ -109,6 +109,8 @@ public CommandLineOptions(params string[] args) // Output Control + public string ConsoleEncoding { get; private set; } + public bool NoHeader { get; private set; } public bool NoColor { get; private set; } @@ -373,6 +375,9 @@ protected virtual void ConfigureOptions() this.Add("version|V", "Display the header and exit.", v => ShowVersion = v != null); + this.Add("encoding=", "Specifies the encoding to use for Console standard output, for example utf-8, ascii, unicode.", + v => ConsoleEncoding = RequiredValue(v, "--encoding")); + // Default this.Add("<>", v => { diff --git a/src/NUnitConsole/nunit3-console/Program.cs b/src/NUnitConsole/nunit3-console/Program.cs index 961bc6b33..0f2b1709c 100644 --- a/src/NUnitConsole/nunit3-console/Program.cs +++ b/src/NUnitConsole/nunit3-console/Program.cs @@ -24,6 +24,7 @@ using System; using System.IO; using System.Reflection; +using System.Text; using NUnit.Common; using NUnit.Options; using NUnit.Engine; @@ -64,6 +65,20 @@ public static int Main(string[] args) return ConsoleRunner.INVALID_ARG; } + if (!string.IsNullOrEmpty(Options.ConsoleEncoding)) + { + try + { + Console.OutputEncoding = Encoding.GetEncoding(Options.ConsoleEncoding); + } + catch (Exception error) + { + WriteHeader(); + OutWriter.WriteLine(ColorStyle.Error, string.Format("Unsupported Encoding, {0}", error.Message)); + return ConsoleRunner.INVALID_ARG; + } + } + //ColorConsole.Enabled = !Options.NoColor; // Create SettingsService early so we know the trace level right at the start diff --git a/src/NUnitConsole/nunit3-console/TestEventHandler.cs b/src/NUnitConsole/nunit3-console/TestEventHandler.cs index a9f85ac0d..f411bcd35 100644 --- a/src/NUnitConsole/nunit3-console/TestEventHandler.cs +++ b/src/NUnitConsole/nunit3-console/TestEventHandler.cs @@ -55,6 +55,10 @@ public void OnTestEvent(string report) var testEvent = doc.FirstChild; switch (testEvent.Name) { + case "start-test": + TestStarted(testEvent); + break; + case "test-case": TestFinished(testEvent); break; @@ -73,13 +77,18 @@ public void OnTestEvent(string report) #region Individual Handlers - private void TestFinished(XmlNode testResult) + private void TestStarted(XmlNode testResult) { var testName = testResult.Attributes["fullname"].Value; - var outputNode = testResult.SelectSingleNode("output"); if (_displayLabels == "ALL") WriteLabelLine(testName); + } + + private void TestFinished(XmlNode testResult) + { + var testName = testResult.Attributes["fullname"].Value; + var outputNode = testResult.SelectSingleNode("output"); if (outputNode != null) { @@ -97,7 +106,7 @@ private void SuiteFinished(XmlNode testResult) if (outputNode != null) { - if (_displayLabels == "ON" || _displayLabels == "ALL") + if (_displayLabels == "ON") WriteLabelLine(suiteName); WriteOutputLine(outputNode.InnerText); diff --git a/src/NUnitEngine/nunit.engine.tests/HangingAppDomainFixture.cs b/src/NUnitEngine/nunit.engine.tests/HangingAppDomainFixture.cs new file mode 100644 index 000000000..f278b2976 --- /dev/null +++ b/src/NUnitEngine/nunit.engine.tests/HangingAppDomainFixture.cs @@ -0,0 +1,44 @@ +// *********************************************************************** +// Copyright (c) 2016 Charlie Poole +// +// Permission is hereby granted, free of charge, to any person obtaining +// a copy of this software and associated documentation files (the +// "Software"), to deal in the Software without restriction, including +// without limitation the rights to use, copy, modify, merge, publish, +// distribute, sublicense, and/or sell copies of the Software, and to +// permit persons to whom the Software is furnished to do so, subject to +// the following conditions: +// +// The above copyright notice and this permission notice shall be +// included in all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +// *********************************************************************** + +using System; +using System.Threading; +using NUnit.Framework; + +namespace NUnit.Engine.Tests +{ + [Explicit] + public class HangingAppDomainFixture + { + [Test] + public void PassingTest() + { + Assert.Pass(); + } + + ~HangingAppDomainFixture() + { + Thread.Sleep(TimeSpan.FromDays(1)); + } + } +} diff --git a/src/NUnitEngine/nunit.engine.tests/nunit.engine.tests.csproj b/src/NUnitEngine/nunit.engine.tests/nunit.engine.tests.csproj index 9cda4d402..b26b82456 100644 --- a/src/NUnitEngine/nunit.engine.tests/nunit.engine.tests.csproj +++ b/src/NUnitEngine/nunit.engine.tests/nunit.engine.tests.csproj @@ -70,6 +70,7 @@ + diff --git a/src/NUnitEngine/nunit.engine/Runners/ProcessRunner.cs b/src/NUnitEngine/nunit.engine/Runners/ProcessRunner.cs index 3a9bfb958..5395f81d6 100644 --- a/src/NUnitEngine/nunit.engine/Runners/ProcessRunner.cs +++ b/src/NUnitEngine/nunit.engine/Runners/ProcessRunner.cs @@ -215,27 +215,58 @@ public override void StopRun(bool force) protected override void Dispose(bool disposing) { - base.Dispose(disposing); - - try + // Disposal has to perform two actions, unloading the runner and + // stopping the agent. Both must be tried even if one fails so + // there can be up to two independent errors to be reported + // through an NUnitEngineException. We do that by combining messages. + if (!_disposed && disposing) { - if (disposing && _agent != null) + _disposed = true; + + string unloadError = null; + + try { - log.Debug("Stopping remote agent"); - _agent.Stop(); - _agent = null; + Unload(); } - } - catch (Exception e) - { - log.Error("Failed to stop the remote agent. {0}", e.Message); - _agent = null; + catch(Exception ex) + { + // Save and log the unload error + unloadError = ex.Message; + log.Error(unloadError); + } + + if (_agent != null) + { + try + { + log.Debug("Stopping remote agent"); + _agent.Stop(); + _agent = null; + } + catch (Exception e) + { + string stopError = string.Format("Failed to stop the remote agent. {0}", e.Message); + log.Error(stopError); + _agent = null; + + // Stop error with no unload error, just rethrow + if (unloadError == null) + throw; + + // Both kinds of errors, throw exception with combined message + throw new NUnitEngineException(unloadError + Environment.NewLine + stopError); + } + } + + if (unloadError != null) // Add message line indicating we managed to stop agent anyway + throw (new NUnitEngineException(unloadError + "\nAgent Process was terminated successfully after error.")); } } - #endregion +#endregion - #region Helper Methods +#region Helper Methods private void CreateAgentAndRunner() { @@ -283,6 +314,6 @@ TestEngineResult CreateFailedResult(Exception e) return new TestEngineResult(suite); } - #endregion +#endregion } } diff --git a/src/NUnitEngine/nunit.engine/Services/DomainManager.cs b/src/NUnitEngine/nunit.engine/Services/DomainManager.cs index 3bfeb84a9..e72a212de 100644 --- a/src/NUnitEngine/nunit.engine/Services/DomainManager.cs +++ b/src/NUnitEngine/nunit.engine/Services/DomainManager.cs @@ -157,7 +157,7 @@ public void Unload() if (!_unloadThread.Join(30000)) { - string msg = "Unable to unload AppDomain, Unload thread timed out"; + string msg = "Unable to unload AppDomain, Unload thread timed out."; log.Error(msg); Kill(_unloadThread); diff --git a/src/NUnitEngine/nunit.engine/Services/DriverService.cs b/src/NUnitEngine/nunit.engine/Services/DriverService.cs index cc75ce2d2..c45f1fd38 100644 --- a/src/NUnitEngine/nunit.engine/Services/DriverService.cs +++ b/src/NUnitEngine/nunit.engine/Services/DriverService.cs @@ -98,8 +98,6 @@ public override void StartService() try { - _factories.Add(new NUnit3DriverFactory()); - var extensionService = ServiceContext.GetService(); if (extensionService != null) { @@ -110,7 +108,9 @@ public override void StartService() if (node != null) _factories.Add(new NUnit2DriverFactory(node)); } - + + _factories.Add(new NUnit3DriverFactory()); + Status = ServiceStatus.Started; } catch(Exception) diff --git a/tools/packages.config b/tools/packages.config index c5cdd6bb2..ff1c6fed5 100644 --- a/tools/packages.config +++ b/tools/packages.config @@ -1,4 +1,4 @@ - +