diff --git a/.editorconfig b/.editorconfig index 314583f2d1..a042fda14d 100644 --- a/.editorconfig +++ b/.editorconfig @@ -2,21 +2,18 @@ # maintain consistent coding styles between # different editors and IDEs -# http://EditorConfig.org +# https://editorconfig.org # top-most EditorConfig file root = true [*] indent_style = space -indent_size = 4 insert_final_newline = true charset = utf-8 -[*.{proj,csproj,vcxproj,xproj,json,config,nuspec,xml,xsd}] -indent_size = 2 - - +[*.{cs,cake}] +indent_size = 4 [*] # https://github.com/nunit/docs/wiki/Coding-Standards#namespace-class-structure-interface-enumeration-and-method-definitions @@ -59,21 +56,54 @@ dotnet_style_predefined_type_for_member_access = true:suggestion dotnet_naming_style.pascal_case.capitalization = pascal_case +# Required dotnet_naming_symbols.namespaces_types_and_non_field_members.applicable_kinds = namespace, class, struct, enum, interface, delegate, type_parameter, method, property, event -dotnet_naming_rule.namespaces_types_and_non_field_members.severity = suggestion +dotnet_naming_rule.namespaces_types_and_non_field_members.severity = error dotnet_naming_rule.namespaces_types_and_non_field_members.symbols = namespaces_types_and_non_field_members dotnet_naming_rule.namespaces_types_and_non_field_members.style = pascal_case -dotnet_naming_symbols.public_fields.applicable_kinds = field -dotnet_naming_symbols.public_fields.applicable_accessibilities = public -dotnet_naming_rule.public_fields.severity = suggestion -dotnet_naming_rule.public_fields.symbols = public_fields -dotnet_naming_rule.public_fields.style = pascal_case +# Required +dotnet_naming_symbols.visible_fields.applicable_kinds = field +dotnet_naming_symbols.visible_fields.applicable_accessibilities = public, protected, protected_internal +dotnet_naming_rule.visible_fields.severity = error +dotnet_naming_rule.visible_fields.symbols = visible_fields +dotnet_naming_rule.visible_fields.style = pascal_case + +# Defaults without diagnostics +dotnet_naming_symbols.internal_fields.applicable_kinds = field +dotnet_naming_symbols.internal_fields.applicable_accessibilities = internal +dotnet_naming_rule.internal_fields.severity = none +dotnet_naming_rule.internal_fields.symbols = internal_fields +dotnet_naming_rule.internal_fields.style = pascal_case + +# Defaults without diagnostics +dotnet_naming_symbols.static_readonly_fields.applicable_kinds = field +dotnet_naming_symbols.static_readonly_fields.required_modifiers = static, readonly +dotnet_naming_rule.static_readonly_fields.severity = none +dotnet_naming_rule.static_readonly_fields.symbols = static_readonly_fields +dotnet_naming_rule.static_readonly_fields.style = pascal_case + +# Defaults without diagnostics +dotnet_naming_symbols.constant_fields.applicable_kinds = field +dotnet_naming_symbols.constant_fields.required_modifiers = const +dotnet_naming_rule.constant_fields.severity = none +dotnet_naming_rule.constant_fields.symbols = constant_fields +dotnet_naming_rule.constant_fields.style = pascal_case + +dotnet_naming_style.underscore_camel_case.capitalization = camel_case +dotnet_naming_style.underscore_camel_case.required_prefix = _ + +# Required for newly added fields +dotnet_naming_symbols.remaining_fields.applicable_kinds = field +dotnet_naming_rule.remaining_fields.severity = suggestion +dotnet_naming_rule.remaining_fields.symbols = remaining_fields +dotnet_naming_rule.remaining_fields.style = underscore_camel_case dotnet_naming_style.camel_case.capitalization = camel_case +# Required dotnet_naming_symbols.parameters_and_locals.applicable_kinds = parameter, local -dotnet_naming_rule.parameters_and_locals.severity = suggestion +dotnet_naming_rule.parameters_and_locals.severity = error dotnet_naming_rule.parameters_and_locals.symbols = parameters_and_locals dotnet_naming_rule.parameters_and_locals.style = camel_case diff --git a/.gitignore b/.gitignore index 89d6996252..dac5e01856 100644 --- a/.gitignore +++ b/.gitignore @@ -1,4 +1,4 @@ -## Ignore Visual Studio temporary files, build results, and +## Ignore Visual Studio and Rider temporary files, build results, and ## files generated by popular Visual Studio add-ons. # User-specific files @@ -109,6 +109,9 @@ csx # Windows Store app package directory AppPackages/ +# Rider specific folder +\.idea/ + # Others sql/ *.Cache diff --git a/.travis.yml b/.travis.yml index 08479f4297..41fe67b720 100644 --- a/.travis.yml +++ b/.travis.yml @@ -7,7 +7,7 @@ mono: 5.10.0 # Need 5.2+ for the included MSBuild. matrix: include: - - os: linux + - dist: xenial install: - sudo apt-get install dotnet-sharedframework-microsoft.netcore.app-1.1.6 diff --git a/BUILDING.md b/BUILDING.md index 5eb0493393..3e0ac05e2e 100644 --- a/BUILDING.md +++ b/BUILDING.md @@ -1,6 +1,6 @@ # Building NUnit 3 -NUnit 3 consists of three separate layers: the Framework, the Engine and the Console Runner. The source code is kept in two GitHub repositories at http://github.com/nunit/nunit and http://github.com/nunit/nunit-console. +NUnit 3 consists of three separate layers: the Framework, the Engine and the Console Runner. The source code is kept in two GitHub repositories at https://github.com/nunit/nunit and https://github.com/nunit/nunit-console. There are two ways to build NUnit: using the solution file in an IDE or through the build script. See also [Building and testing for Linux on a Windows machine](#building-and-testing-for-linux-on-a-windows-machine). @@ -8,7 +8,7 @@ There are two ways to build NUnit: using the solution file in an IDE or through The framework is built using a single Visual Studio solution, `nunit.sln`, which may be built with [Visual Studio 2017](https://www.visualstudio.com/vs/) on Windows and [Visual Studio for Mac](https://www.visualstudio.com/vs/) on macOS. Currently, MonoDevelop does not support the new multi-targeted `csproj` project format. Once MonoDevelop is updated, it should start working again. Until then, we recommend [Visual Studio Code](https://code.visualstudio.com/) and compiling using the build scripts on non-Windows platforms. -On all platforms, you will need to install [.NET Core 2.0.3 SDK](https://www.microsoft.com/net/download/windows) or newer. On Mac or Linux, you will need to install [Mono 5.2.0](http://www.mono-project.com/download/). Currently (as of 5.4.1), newer versions of Mono are broken and crash during the compile. +On all platforms, you will need to install [.NET Core 2.0.3 SDK](https://www.microsoft.com/net/download/windows) or newer. On Mac or Linux, you will need to install [Mono 5.2.0](https://www.mono-project.com/download/). Currently (as of 5.4.1), newer versions of Mono are broken and crash during the compile. The solutions all place their output in a common bin directory under the solution root. @@ -23,7 +23,7 @@ Other test projects contain tests designed to fail purposely for integration tes ## Build Script -We use [Cake](http://cakebuild.net) to build NUnit for distribution. The primary script that controls building, running tests and packaging is build.cake. We modify build.cake when we need to add new targets or change the way the build is done. Normally build.cake is not invoked directly but through build.ps1 (on Windows) or build.sh (on Linux). These two scripts are provided by the Cake project and ensure that Cake is properly installed before trying to run the cake script. This helps the build to work on CI servers using newly created agents to run the build and we generally run it the same way on our own machines. +We use [Cake](https://cakebuild.net) to build NUnit for distribution. The primary script that controls building, running tests and packaging is build.cake. We modify build.cake when we need to add new targets or change the way the build is done. Normally build.cake is not invoked directly but through build.ps1 (on Windows) or build.sh (on Linux). These two scripts are provided by the Cake project and ensure that Cake is properly installed before trying to run the cake script. This helps the build to work on CI servers using newly created agents to run the build and we generally run it the same way on our own machines. The build shell script and build.cmd script are provided as an easy way to run the above commands. In addition to passing their arguments through to build.cake, they can supply added arguments through the CAKE_ARGS environment variable. The rest of this document will assume use of these commands. @@ -35,6 +35,8 @@ Key arguments to build.cmd / build: * -ShowDescription Shows all of the build tasks and their descriptions * -Experimental, -e Use the experimental build of Roslyn +Note that the above format for supplying arguments only work on Windows. On Linux one has to use double dashes to specify the argument, like `./build.sh --target=Test` or `./build.sh --target Test` to run the `Test` task. + The build.cake script contains a large number of interdependent tasks. The most important top-level tasks to use are listed here: ``` @@ -70,14 +72,14 @@ This brings clarity to the code and makes it easy to change the mapping between Feature constants are defined in [Directory.Build.props](src/NUnitFramework/Directory.Build.props): - - `ASYNC` enables asynchrony + - `TASK_PARALLEL_LIBRARY_API` exposes NUnit APIs which depend on the TPL framework types - `PARALLEL` enables running tests in parallel - `PLATFORM_DETECTION` enables platform detection - `THREAD_ABORT` enables timeouts and forcible cancellation - `APARTMENT_STATE` enables control of the thread apartment state Platform constants are defined by convention by the csproj SDK, one per target framework. -For example, `NET20` or `NET45`, `NETSTANDARD1_6`, `NETCOREAPP2_0`, and so on. +For example, `NET45`, `NETSTANDARD1_6`, `NETCOREAPP2_0`, and so on. It is most helpful to call out which platforms are the exception in rather than the rule in a given scenario. Keep in mind the effect the preprocessor would have on a newly added platform. @@ -92,7 +94,7 @@ For example, rather than this code: Consider this: ```cs -#if !(NET20 || NET35 || NET40) +#if !(NET35 || NET40) // Something that .NET Framework 4.0 can't do #endif ``` diff --git a/CHANGES.md b/CHANGES.md index d21193d83c..b0a2028d73 100644 --- a/CHANGES.md +++ b/CHANGES.md @@ -1,7 +1,81 @@ -### NUnit 3.11 - October 11, 2018 +### NUnit 3.12 - May 14, 2019 + +This release of NUnit finally drops support for .NET 2.0. If your application still +targets .NET 2.0, your tests will need to target at least .NET 3.5. Microsoft ended +support for .NET 2.0 on July 12, 2011. Microsoft recommends that everyone migrate +to at least .NET Framework 3.5 SP1 for security and performance fixes. + +This release dramatically improves NUnit support for async tests including returning +ValueTask and custom tasks from tests, improved handling of SynchronizationContexts +and better exception handling. + +The .NET Standard 2.0 version of NUnit continues to gain more functionality that +is found in the .NET 4.5 version of the framework like setting the ApartmentState +and enabling Timeout on tests. + +#### Issues Resolved + + * 474 TypeHelperTests.cs is orphaned + * 999 Support multiple TestOf attributes per test + * 1638 TimeoutAttribute not available when targeting netcoreapp framework + * 2168 ThrowsAsync reports OperationCanceledException as TaskCanceledException + * 2194 How to use `Contains.Substring` with `And` + * 2286 Add support for custom Task (i.e. ValueTask) + * 2579 AppVeyor Test Failures under .NET 3.5 + * 2614 TestExecutionContext.CurrentContext is saved in Remoting CallContext between test runs + * 2696 Getting WorkerId fails in debug + * 2772 Random failing of parallel test run: Unhandled Exception: System.InvalidOperationException: Stack empty. + * 2975 ComparisonConstraints are allocating string on construction + * 3014 Timeout failures on MacOS + * 3023 NUnit runner fails when test method returns ValueTask<> + * 3035 Apartment state can't be used for .NET Standard 2.0 tests + * 3036 Apartment state can't be used for .NET Standard 2.0 tests + * 3038 TestName in TestCase attribute not validated to be not empty + * 3042 RequiresThreadAttribute allows ApartmentState.Unknown, unlike ApartmentAttribute + * 3048 Add .idea folder to .gitignore + * 3053 Conversion from TestCase string parameter to DateTimeOffset + * 3059 Constraint Throws.Exception does not work with async return value + * 3068 First Chance Exception in RuntimeFramework + * 3070 End support for .NET Framework 2.0 (released in 2005) + * 3073 CollectionAssert.AreEquivalent fails for ValueTuple Wrapped Dictionary + * 3079 Regression from 3.10 to 3.11: Range in bytes + * 3082 Is.Ordered.By + * 3085 XML Test-Suite Assembly does not contain DLL path anymore + * 3089 Remove outdated comment + * 3093 Tests having TaskLike objects as their return type throws Exception + * 3094 Bad error message if collections have different types + * 3104 Removed NET20 compile output + * 3105 Add tests for use of ApartmentState.Unknown in RequiresThreadAttribute + * 3107 Declare class in Program.cs provided with NUnitLite Nuget package static + * 3109 Azure DevOps build fails in Save package artifacts + * 3124 Switch copyright notice + * 3128 Correct documentation on ParallelScope + * 3137 Fix doc-comments in NUnitTestAssemblyRunner + * 3138 Assert.Ignore breaks when a Task is returned w/o using async/await + * 3139 Add Azure pipelines badge to frontpage + * 3144 Retry attribute should not derive from PropertyAttribute + * 3145 Capture additional exception details in the test output + * 3156 UnexpectedExceptionTests should tolerate Mono on Azure DevOps Ubuntu + * 3159 Make tests more tolerant + * 3161 https url repo + * 3166 Allow static SetUpFixture classes + * 3171 Incorrect type for Test Fixtures when using running explore with a filter + * 3175 Improve user-facing messages + * 3181 Template Based Test Naming - Incorrect truncation for individual arguments + * 3186 Fix licenseUrl element in nuspec, will be deprecated + * 3193 Cake Build Fails with Visual Studio 2019 + * 3195 Drop or at least make Travis not required? + * 3231 Breaking change in filter functionality between framework 2.7 and 3.11 + * 3209 Test fail when posting to SynchronizationContext.Current + * 3211 Fix logging + * 3218 Remove todos from the code base + * 3222 Our build script tests hang when run with Mono on Windows + * 3233 AndConstraint should write additional information from failed constraint + +### NUnit 3.11 - October 6, 2018 * More informative assertion messages - * PlatformAttribute is available on and now detects .NET Core + * PlatformAttribute is available on .NET Standard and now detects .NET Core * ValuesAttribute now works with nullable types * Async tests detecting and running Windows Forms or WPF message pumps rather than deadlocking * Support for UWP 10.0 is back via .NET Standard 1.4 diff --git a/CODE_OF_CONDUCT.md b/CODE_OF_CONDUCT.md index abf4262b52..bc55002c25 100644 --- a/CODE_OF_CONDUCT.md +++ b/CODE_OF_CONDUCT.md @@ -40,7 +40,7 @@ Project maintainers who do not follow or enforce the Code of Conduct in good fai ## Attribution -This Code of Conduct is adapted from the [Contributor Covenant][homepage], version 1.4, available at [http://contributor-covenant.org/version/1/4][version] +This Code of Conduct is adapted from the [Contributor Covenant][homepage], version 1.4, available at [https://contributor-covenant.org/version/1/4][version] -[homepage]: http://contributor-covenant.org -[version]: http://contributor-covenant.org/version/1/4/ +[homepage]: https://contributor-covenant.org +[version]: https://contributor-covenant.org/version/1/4/ diff --git a/LICENSE.txt b/LICENSE.txt index d1fc75345e..b029a77c34 100644 --- a/LICENSE.txt +++ b/LICENSE.txt @@ -1,4 +1,4 @@ -Copyright (c) 2018 Charlie Poole, Rob Prouse +Copyright (c) 2019 Charlie Poole, Rob Prouse Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal diff --git a/NUnit.sln.DotSettings b/NUnit.sln.DotSettings index 3e5f493d31..d7fe019de8 100644 --- a/NUnit.sln.DotSettings +++ b/NUnit.sln.DotSettings @@ -1,5 +1,6 @@  True + ERROR SUGGESTION True True @@ -35,13 +36,41 @@ OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. *********************************************************************** + CDATA + CE + ID + ME + MTA + NT + OS + OSX + SSCLI + STA UI - <Policy Inspect="True" Prefix="_" Suffix="" Style="aaBb"><ExtraRule Prefix="" Suffix="" Style="aaBb" /></Policy> - <Policy Inspect="True" Prefix="_" Suffix="" Style="aaBb"><ExtraRule Prefix="" Suffix="" Style="aaBb" /></Policy> + XP + <Policy Inspect="False" Prefix="" Suffix="" Style="AaBb" /> + <Policy Inspect="True" Prefix="" Suffix="" Style="AaBb" /> + <Policy Inspect="True" Prefix="I" Suffix="" Style="AaBb" /> + <Policy Inspect="True" Prefix="" Suffix="" Style="aaBb" /> + <Policy Inspect="True" Prefix="" Suffix="" Style="AaBb" /> + <Policy Inspect="True" Prefix="" Suffix="" Style="aaBb" /> + <Policy Inspect="True" Prefix="" Suffix="" Style="AaBb" /> + <Policy Inspect="True" Prefix="" Suffix="" Style="aaBb" /> + <Policy Inspect="False" Prefix="" Suffix="" Style="AaBb" /> + <Policy Inspect="False" Prefix="_" Suffix="" Style="aaBb" /> + <Policy Inspect="False" Prefix="_" Suffix="" Style="aaBb" /> + <Policy Inspect="False" Prefix="" Suffix="" Style="AaBb" /> + <Policy Inspect="False" Prefix="" Suffix="" Style="AaBb" /> + <Policy Inspect="True" Prefix="T" Suffix="" Style="AaBb" /> + <Policy Inspect="True" Prefix="" Suffix="" Style="AaBb_AaBb"><ExtraRule Prefix="" Suffix="" Style="AA_BB" /></Policy> + <Policy><Descriptor Staticness="Static" AccessRightKinds="Private, Internal" Description="Non-visible static readonly and constant fields"><ElementKinds><Kind Name="READONLY_FIELD" /><Kind Name="CONSTANT_FIELD" /></ElementKinds></Descriptor><Policy Inspect="False" Prefix="" Suffix="" Style="AaBb" /></Policy> + <Policy><Descriptor Staticness="Static, Instance" AccessRightKinds="Protected, ProtectedInternal, Public" Description="Visible fields"><ElementKinds><Kind Name="FIELD" /><Kind Name="READONLY_FIELD" /><Kind Name="CONSTANT_FIELD" /></ElementKinds></Descriptor><Policy Inspect="True" Prefix="" Suffix="" Style="AaBb"><ExtraRule Prefix="" Suffix="" Style="AA_BB" /></Policy></Policy> + <Policy><Descriptor Staticness="Static, Instance" AccessRightKinds="Internal" Description="Internal fields"><ElementKinds><Kind Name="FIELD" /><Kind Name="READONLY_FIELD" /><Kind Name="CONSTANT_FIELD" /></ElementKinds></Descriptor><Policy Inspect="False" Prefix="" Suffix="" Style="AaBb" /></Policy> True True True True + True True True True @@ -173,4 +202,4 @@ namespace $NAMESPACE$ $END$ } } -} \ No newline at end of file +} diff --git a/README.md b/README.md index 64195c71f3..d044e2aeca 100644 --- a/README.md +++ b/README.md @@ -1,6 +1,6 @@ # NUnit 3 Framework # -[![AppVeyor Build status](https://ci.appveyor.com/api/projects/status/3xfkxtnkrts1x06q/branch/master?svg=true)](https://ci.appveyor.com/project/CharliePoole/nunit/branch/master) [![Travis Build Status](https://travis-ci.org/nunit/nunit.svg?branch=master)](https://travis-ci.org/nunit/nunit) [![NuGet Version and Downloads count](https://buildstats.info/nuget/NUnit)](https://www.nuget.org/packages/NUnit) +[![AppVeyor Build status](https://ci.appveyor.com/api/projects/status/3xfkxtnkrts1x06q/branch/master?svg=true)](https://ci.appveyor.com/project/CharliePoole/nunit/branch/master) [![Travis Build Status](https://travis-ci.org/nunit/nunit.svg?branch=master)](https://travis-ci.org/nunit/nunit) [![Azure Pipelines Build Status](https://nunit.visualstudio.com/NUnit/_apis/build/status/NUnit%20Framework/NUnit%20Framework%20CI?branchName=master)](https://nunit.visualstudio.com/NUnit/_build/latest?definitionId=11?branchName=master) [![NuGet Version and Downloads count](https://buildstats.info/nuget/NUnit)](https://www.nuget.org/packages/NUnit) [![Follow NUnit](https://img.shields.io/twitter/follow/nunit.svg?style=social)](https://twitter.com/nunit) [![Gitter](https://img.shields.io/gitter/room/nwjs/nw.js.svg)](https://gitter.im/nunit/nunit) [![nunit-discuss Google Groups](https://img.shields.io/badge/mailing%20list-nunit--discuss-blue.svg)](https://groups.google.com/forum/#!forum/nunit-discuss) @@ -44,7 +44,7 @@ set breakpoints and watch variables, [follow these steps](https://github.com/nun ## License ## -NUnit is Open Source software and NUnit 3 is released under the [MIT license](https://raw.githubusercontent.com/nunit/nunit/master/LICENSE.txt). Earlier releases used the [NUnit license](http://www.nunit.org/nuget/license.html). Both of these licenses allow the use of NUnit in free and commercial applications and libraries without restrictions. +NUnit is Open Source software and NUnit 3 is released under the [MIT license](https://raw.githubusercontent.com/nunit/nunit/master/LICENSE.txt). Earlier releases used the [NUnit license](https://nunit.org/nuget/license.html). Both of these licenses allow the use of NUnit in free and commercial applications and libraries without restrictions. ## NUnit Projects ## diff --git a/azure-pipelines.yml b/azure-pipelines.yml new file mode 100644 index 0000000000..fa8a31135f --- /dev/null +++ b/azure-pipelines.yml @@ -0,0 +1,165 @@ +trigger: + branches: + include: [ '*' ] + exclude: [ 'refs/tags/*' ] + +jobs: + +- job: Windows + pool: + vmImage: vs2017-win2016 + steps: + + - powershell: .\build.ps1 --target=Test + displayName: Build and test + + # Workaround for https://github.com/nunit/nunit/issues/3012#issuecomment-441517922 + - task: PublishTestResults@2 + displayName: Publish net45 test results + inputs: + testResultsFormat: NUnit + testResultsFiles: test-results\net45\*.xml + mergeTestResults: true + testRunTitle: net45/Windows + condition: succeededOrFailed() + - task: PublishTestResults@2 + displayName: Publish net40 test results + inputs: + testResultsFormat: NUnit + testResultsFiles: test-results\net40\*.xml + mergeTestResults: true + testRunTitle: net40/Windows + condition: succeededOrFailed() + - task: PublishTestResults@2 + displayName: Publish net35 test results + inputs: + testResultsFormat: NUnit + testResultsFiles: test-results\net35\*.xml + mergeTestResults: true + testRunTitle: net35/Windows + condition: succeededOrFailed() + - task: PublishTestResults@2 + displayName: Publish netcoreapp1.1 test results + inputs: + testResultsFormat: NUnit + testResultsFiles: test-results\netcoreapp1.1\*.xml + mergeTestResults: true + testRunTitle: netcoreapp1.1/Windows + condition: succeededOrFailed() + - task: PublishTestResults@2 + displayName: Publish netcoreapp2.0 test results + inputs: + testResultsFormat: NUnit + testResultsFiles: test-results\netcoreapp2.0\*.xml + mergeTestResults: true + testRunTitle: netcoreapp2.0/Windows + condition: succeededOrFailed() + + - powershell: .\build.ps1 --target=Package --artifact-dir='$(Build.ArtifactStagingDirectory)' + displayName: Package + + - task: PublishBuildArtifacts@1 + displayName: Save package artifacts + inputs: + PathtoPublish: $(Build.ArtifactStagingDirectory) + ArtifactName: Package + +- job: Linux + pool: + vmImage: ubuntu-16.04 + steps: + + - bash: ./build.sh --target=Test --configuration=Release + displayName: Build and test + + # Workaround for https://github.com/nunit/nunit/issues/3012#issuecomment-441517922 + - task: PublishTestResults@2 + displayName: Publish net45 test results + inputs: + testResultsFormat: NUnit + testResultsFiles: test-results/net45/*.xml + mergeTestResults: true + testRunTitle: net45/Linux + condition: succeededOrFailed() + - task: PublishTestResults@2 + displayName: Publish net40 test results + inputs: + testResultsFormat: NUnit + testResultsFiles: test-results/net40/*.xml + mergeTestResults: true + testRunTitle: net40/Linux + condition: succeededOrFailed() + - task: PublishTestResults@2 + displayName: Publish net35 test results + inputs: + testResultsFormat: NUnit + testResultsFiles: test-results/net35/*.xml + mergeTestResults: true + testRunTitle: net35/Linux + condition: succeededOrFailed() + - task: PublishTestResults@2 + displayName: Publish netcoreapp1.1 test results + inputs: + testResultsFormat: NUnit + testResultsFiles: test-results/netcoreapp1.1/*.xml + mergeTestResults: true + testRunTitle: netcoreapp1.1/Linux + condition: succeededOrFailed() + - task: PublishTestResults@2 + displayName: Publish netcoreapp2.0 test results + inputs: + testResultsFormat: NUnit + testResultsFiles: test-results/netcoreapp2.0/*.xml + mergeTestResults: true + testRunTitle: netcoreapp2.0/Linux + condition: succeededOrFailed() + +- job: macOS + pool: + vmImage: macOS-10.13 + steps: + + - bash: ./build.sh --target=Test --configuration=Release + displayName: Build and test + + # Workaround for https://github.com/nunit/nunit/issues/3012#issuecomment-441517922 + - task: PublishTestResults@2 + displayName: Publish net45 test results + inputs: + testResultsFormat: NUnit + testResultsFiles: test-results/net45/*.xml + mergeTestResults: true + testRunTitle: net45/macOS + condition: succeededOrFailed() + - task: PublishTestResults@2 + displayName: Publish net40 test results + inputs: + testResultsFormat: NUnit + testResultsFiles: test-results/net40/*.xml + mergeTestResults: true + testRunTitle: net40/macOS + condition: succeededOrFailed() + - task: PublishTestResults@2 + displayName: Publish net35 test results + inputs: + testResultsFormat: NUnit + testResultsFiles: test-results/net35/*.xml + mergeTestResults: true + testRunTitle: net35/macOS + condition: succeededOrFailed() + - task: PublishTestResults@2 + displayName: Publish netcoreapp1.1 test results + inputs: + testResultsFormat: NUnit + testResultsFiles: test-results/netcoreapp1.1/*.xml + mergeTestResults: true + testRunTitle: netcoreapp1.1/macOS + condition: succeededOrFailed() + - task: PublishTestResults@2 + displayName: Publish netcoreapp2.0 test results + inputs: + testResultsFormat: NUnit + testResultsFiles: test-results/netcoreapp2.0/*.xml + mergeTestResults: true + testRunTitle: netcoreapp2.0/macOS + condition: succeededOrFailed() diff --git a/build.cake b/build.cake index db672bb015..dffd75853a 100644 --- a/build.cake +++ b/build.cake @@ -18,7 +18,7 @@ var ErrorDetail = new List(); // SET PACKAGE VERSION ////////////////////////////////////////////////////////////////////// -var version = "3.11.0"; +var version = "3.12.0"; var modifier = ""; var dbgSuffix = configuration == "Debug" ? "-dbg" : ""; @@ -33,7 +33,6 @@ var AllFrameworks = new string[] "net45", "net40", "net35", - "net20", "netstandard1.4", "netstandard2.0" }; @@ -49,7 +48,7 @@ var NetCoreTests = new String[] ////////////////////////////////////////////////////////////////////// var PROJECT_DIR = Context.Environment.WorkingDirectory.FullPath + "/"; -var PACKAGE_DIR = PROJECT_DIR + "package/"; +var PACKAGE_DIR = Argument("artifact-dir", PROJECT_DIR + "package") + "/"; var BIN_DIR = PROJECT_DIR + "bin/" + configuration + "/"; var IMAGE_DIR = PROJECT_DIR + "images/"; @@ -166,7 +165,24 @@ MSBuildSettings CreateSettings() settings.WithProperty("DebugType", "pdbonly"); if (IsRunningOnWindows()) - settings.ToolVersion = MSBuildToolVersion.VS2017; + { + // Find MSBuild for Visual Studio 2019 and newer + DirectoryPath vsLatest = VSWhereLatest(); + FilePath msBuildPath = vsLatest?.CombineWithFilePath("./MSBuild/Current/Bin/MSBuild.exe"); + + // Find MSBuild for Visual Studio 2017 + if (msBuildPath != null && !FileExists(msBuildPath)) + msBuildPath = vsLatest.CombineWithFilePath("./MSBuild/15.0/Bin/MSBuild.exe"); + + // Have we found MSBuild yet? + if (!FileExists(msBuildPath)) + { + throw new Exception($"Failed to find MSBuild: {msBuildPath}"); + } + + Information("Building using MSBuild at " + msBuildPath); + settings.ToolPath = msBuildPath; + } else settings.ToolPath = Context.Tools.Resolve("msbuild"); @@ -217,18 +233,6 @@ Task("Test35") RunTest(dir + EXECUTABLE_NUNITLITE_TESTS_EXE, dir, runtime, ref ErrorDetail); }); -Task("Test20") - .Description("Tests the .NET 2.0 version of the framework") - .IsDependentOn("Build") - .OnError(exception => { ErrorDetail.Add(exception.Message); }) - .Does(() => - { - var runtime = "net20"; - var dir = BIN_DIR + runtime + "/"; - RunNUnitTests(dir, FRAMEWORK_TESTS, runtime, ref ErrorDetail); - RunTest(dir + EXECUTABLE_NUNITLITE_TESTS_EXE, dir, runtime, ref ErrorDetail); - }); - Task("TestNetStandard14") .Description("Tests the .NET Standard 1.4 version of the framework") .IsDependentOn("Build") @@ -237,7 +241,7 @@ Task("TestNetStandard14") { var runtime = "netcoreapp1.1"; var dir = BIN_DIR + runtime + "/"; - RunDotnetCoreTests(dir + NUNITLITE_RUNNER_DLL, dir, FRAMEWORK_TESTS, runtime, ref ErrorDetail); + RunDotnetCoreTests(dir + NUNITLITE_RUNNER_DLL, dir, FRAMEWORK_TESTS, runtime, GetResultXmlPath(FRAMEWORK_TESTS, runtime), ref ErrorDetail); RunDotnetCoreTests(dir + EXECUTABLE_NUNITLITE_TESTS_DLL, dir, runtime, ref ErrorDetail); }); @@ -249,7 +253,7 @@ Task("TestNetStandard20") { var runtime = "netcoreapp2.0"; var dir = BIN_DIR + runtime + "/"; - RunDotnetCoreTests(dir + NUNITLITE_RUNNER_DLL, dir, FRAMEWORK_TESTS, runtime, ref ErrorDetail); + RunDotnetCoreTests(dir + NUNITLITE_RUNNER_DLL, dir, FRAMEWORK_TESTS, runtime, GetResultXmlPath(FRAMEWORK_TESTS, runtime), ref ErrorDetail); RunDotnetCoreTests(dir + EXECUTABLE_NUNITLITE_TESTS_DLL, dir, runtime, ref ErrorDetail); }); @@ -267,7 +271,6 @@ var RootFiles = new FilePath[] // Not all of these are present in every framework // The Microsoft and System assemblies are part of the BCL // used by the .NET 4.0 framework. 4.0 tests will not run without them. -// NUnit.System.Linq is only present for the .NET 2.0 build. var FrameworkFiles = new FilePath[] { "mock-assembly.dll", @@ -275,7 +278,6 @@ var FrameworkFiles = new FilePath[] "nunit.framework.dll", "nunit.framework.pdb", "nunit.framework.xml", - "NUnit.System.Linq.dll", "nunit.framework.tests.dll", "nunit.testdata.dll", "nunitlite.dll", @@ -368,7 +370,6 @@ Task("PackageZip") var zipFiles = GetFiles(CurrentImageDir + "*.*") + - GetFiles(CurrentImageDir + "bin/net20/**/*.*") + GetFiles(CurrentImageDir + "bin/net35/**/*.*") + GetFiles(CurrentImageDir + "bin/net40/**/*.*") + GetFiles(CurrentImageDir + "bin/net45/**/*.*") + @@ -424,14 +425,27 @@ void CheckForError(ref List errorDetail) // HELPER METHODS - TEST ////////////////////////////////////////////////////////////////////// +FilePath GetResultXmlPath(string testAssembly, string framework) +{ + var assemblyName = System.IO.Path.GetFileNameWithoutExtension(testAssembly); + + CreateDirectory($@"test-results\{framework}"); + + return MakeAbsolute(new FilePath($@"test-results\{framework}\{assemblyName}.xml")); +} + void RunNUnitTests(DirectoryPath workingDir, string testAssembly, string framework, ref List errorDetail) { try { - var path = workingDir.CombineWithFilePath(new FilePath(testAssembly)); + var path = workingDir.CombineWithFilePath(testAssembly); + var settings = new NUnit3Settings(); - if(!IsRunningOnWindows()) + settings.Results = new[] { new NUnit3Result { FileName = GetResultXmlPath(testAssembly, framework) } }; + + if (!IsRunningOnWindows()) settings.Process = NUnit3ProcessOption.InProcess; + NUnit3(path.ToString(), settings); } catch(CakeException ce) @@ -449,9 +463,12 @@ void RunTest(FilePath exePath, DirectoryPath workingDir, string arguments, strin { int rc = StartProcess( MakeAbsolute(exePath), - new ProcessSettings() + new ProcessSettings { - Arguments = arguments, + Arguments = new ProcessArgumentBuilder() + .Append(arguments) + .AppendSwitchQuoted("--result", ":", GetResultXmlPath(exePath.FullPath, framework).FullPath) + .Render(), WorkingDirectory = workingDir }); @@ -463,16 +480,20 @@ void RunTest(FilePath exePath, DirectoryPath workingDir, string arguments, strin void RunDotnetCoreTests(FilePath exePath, DirectoryPath workingDir, string framework, ref List errorDetail) { - RunDotnetCoreTests(exePath, workingDir, null, framework, ref errorDetail); + RunDotnetCoreTests(exePath, workingDir, null, framework, GetResultXmlPath(exePath.FullPath, framework), ref errorDetail); } -void RunDotnetCoreTests(FilePath exePath, DirectoryPath workingDir, string arguments, string framework, ref List errorDetail) +void RunDotnetCoreTests(FilePath exePath, DirectoryPath workingDir, string arguments, string framework, FilePath resultFile, ref List errorDetail) { int rc = StartProcess( "dotnet", - new ProcessSettings() + new ProcessSettings { - Arguments = exePath + " " + arguments, + Arguments = new ProcessArgumentBuilder() + .AppendQuoted(exePath.FullPath) + .Append(arguments) + .AppendSwitchQuoted("--result", ":", resultFile.FullPath) + .Render(), WorkingDirectory = workingDir }); @@ -513,7 +534,6 @@ Task("Test") .IsDependentOn("Test45") .IsDependentOn("Test40") .IsDependentOn("Test35") - .IsDependentOn("Test20") .IsDependentOn("TestNetStandard14") .IsDependentOn("TestNetStandard20"); diff --git a/nuget/framework/nunit.nuspec b/nuget/framework/nunit.nuspec index 11c9aea172..6111c27749 100644 --- a/nuget/framework/nunit.nuspec +++ b/nuget/framework/nunit.nuspec @@ -6,8 +6,8 @@ $version$ Charlie Poole, Rob Prouse Charlie Poole, Rob Prouse - https://raw.githubusercontent.com/nunit/nunit/master/LICENSE.txt - http://nunit.org + LICENSE.txt + https://nunit.org https://cdn.rawgit.com/nunit/resources/master/images/icon/nunit_256.png false @@ -17,20 +17,20 @@ This package includes the NUnit 3 framework assembly, which is referenced by your tests. You will need to install version 3 of the nunit3-console program or a third-party runner that supports NUnit 3 in order to execute tests. Runners intended for use with NUnit 2.x will not run NUnit 3 tests correctly. Supported platforms: -- .NET Framework 2.0+ +- .NET Framework 3.5+ - .NET Standard 1.4+ - .NET Core This package includes the NUnit 3 framework assembly, which is referenced by your tests. You will need to install version 3 of the nunit3-console program or a third-party runner that supports NUnit 3 in order to execute tests. Runners intended for use with NUnit 2.x will not run NUnit 3 tests correctly. en-US nunit test testing tdd framework fluent assert theory plugin addin - Copyright (c) 2018 Charlie Poole, Rob Prouse + Copyright (c) 2019 Charlie Poole, Rob Prouse - + @@ -42,10 +42,6 @@ Supported platforms: - - - - diff --git a/nuget/nunitlite/Program.cs b/nuget/nunitlite/Program.cs index 23e9dc87eb..0a1a2f6968 100644 --- a/nuget/nunitlite/Program.cs +++ b/nuget/nunitlite/Program.cs @@ -25,7 +25,7 @@ namespace NUnitLite.Tests { - public class Program + public static class Program { /// /// The main program executes the tests. Output may be routed to @@ -38,4 +38,4 @@ public static int Main(string[] args) return new AutoRun().Execute(args); } } -} \ No newline at end of file +} diff --git a/nuget/nunitlite/Program.vb b/nuget/nunitlite/Program.vb index 7b2294fba1..3d204153ea 100644 --- a/nuget/nunitlite/Program.vb +++ b/nuget/nunitlite/Program.vb @@ -1,4 +1,4 @@ -' *********************************************************************** +' *********************************************************************** ' Copyright (c) 2015 Charlie Poole, Rob Prouse ' ' Permission is hereby granted, free of charge, to any person obtaining @@ -23,15 +23,15 @@ Imports NUnitLite -Public Class Program +Public Module Program ''' ''' The main program executes the tests. Output may be routed to ''' various locations, depending on the arguments passed. ''' ''' Run with --help for a full list of arguments supported - Public Shared Function Main(ByVal args() As String) As Integer + Public Function Main(ByVal args() As String) As Integer Return New AutoRun().Execute(args) End Function -End Class +End Module diff --git a/nuget/nunitlite/nunitlite.nuspec b/nuget/nunitlite/nunitlite.nuspec index bbc06b609e..f1106fa239 100644 --- a/nuget/nunitlite/nunitlite.nuspec +++ b/nuget/nunitlite/nunitlite.nuspec @@ -6,8 +6,8 @@ $version$ Charlie Poole, Rob Prouse Charlie Poole, Rob Prouse - https://raw.githubusercontent.com/nunit/nunit/master/LICENSE.txt - http://nunit.org + LICENSE.txt + https://nunit.org https://cdn.rawgit.com/nunit/resources/master/images/icon/nunit_256.png false @@ -26,11 +26,8 @@ How to use this package: 3. Add your tests to the test project and simply start the project to execute them. en-US test unit testing tdd framework fluent assert device phone embedded - Copyright (c) 2018 Charlie Poole, Rob Prouse + Copyright (c) 2019 Charlie Poole, Rob Prouse - - - @@ -55,8 +52,6 @@ How to use this package: - - @@ -67,8 +62,6 @@ How to use this package: - - diff --git a/src/CommonAssemblyInfo.cs b/src/CommonAssemblyInfo.cs index 0988974246..02a7009ba9 100644 --- a/src/CommonAssemblyInfo.cs +++ b/src/CommonAssemblyInfo.cs @@ -28,7 +28,7 @@ // [assembly: AssemblyCompany("NUnit Software")] [assembly: AssemblyProduct("NUnit 3")] -[assembly: AssemblyCopyright("Copyright (c) 2018 Charlie Poole, Rob Prouse")] +[assembly: AssemblyCopyright("Copyright (c) 2019 Charlie Poole, Rob Prouse")] [assembly: AssemblyTrademark("NUnit is a trademark of NUnit Software")] #if DEBUG @@ -38,8 +38,6 @@ [assembly: AssemblyConfiguration(".NET Framework 4.0 Debug")] #elif NET35 [assembly: AssemblyConfiguration(".NET Framework 3.5 Debug")] -#elif NET20 -[assembly: AssemblyConfiguration(".NET Framework 2.0 Debug")] #elif NETSTANDARD1_4 [assembly: AssemblyConfiguration(".NET Standard 1.4 Debug")] #elif NETSTANDARD2_0 @@ -58,8 +56,6 @@ [assembly: AssemblyConfiguration(".NET Framework 4.0")] #elif NET35 [assembly: AssemblyConfiguration(".NET Framework 3.5")] -#elif NET20 -[assembly: AssemblyConfiguration(".NET Framework 2.0")] #elif NETSTANDARD1_4 [assembly: AssemblyConfiguration(".NET Standard 1.4")] #elif NETSTANDARD2_0 diff --git a/src/NUnitFramework/Directory.Build.props b/src/NUnitFramework/Directory.Build.props index b986a3a789..b7420cd325 100644 --- a/src/NUnitFramework/Directory.Build.props +++ b/src/NUnitFramework/Directory.Build.props @@ -22,16 +22,15 @@ $(DefineConstants);PARALLEL;SERIALIZATION - $(DefineConstants);ASYNC + $(DefineConstants);TASK_PARALLEL_LIBRARY_API $(DefineConstants);THREAD_ABORT;APARTMENT_STATE + and '$(TargetFramework)' != 'netcoreapp2.0'">$(DefineConstants);THREAD_ABORT $(DefineConstants);PLATFORM_DETECTION + and '$(TargetFramework)' != 'netcoreapp1.1'">$(DefineConstants);PLATFORM_DETECTION;APARTMENT_STATE diff --git a/src/NUnitFramework/FrameworkVersion.cs b/src/NUnitFramework/FrameworkVersion.cs index 5962546d2e..da66111a20 100644 --- a/src/NUnitFramework/FrameworkVersion.cs +++ b/src/NUnitFramework/FrameworkVersion.cs @@ -26,5 +26,5 @@ // // Current version for the NUnit Framework // -[assembly: AssemblyVersion("3.11.0.0")] -[assembly: AssemblyFileVersion("3.11.0.0")] +[assembly: AssemblyVersion("3.12.0.0")] +[assembly: AssemblyFileVersion("3.12.0.0")] diff --git a/src/NUnitFramework/SchemaTestUtils.cs b/src/NUnitFramework/SchemaTestUtils.cs index 5b06d857d5..f8d86649f4 100644 --- a/src/NUnitFramework/SchemaTestUtils.cs +++ b/src/NUnitFramework/SchemaTestUtils.cs @@ -21,9 +21,9 @@ // WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. // *********************************************************************** -#if !NETCOREAPP1_1 // Schema validation doesn’t exist -#if !(NET20 || NET35) // Framework bug causes NRE: https://social.msdn.microsoft.com/Forums/en-US/53be44de-30b2-4d18-968d-d3414d0783b1 - // We don’t really need these tests to run on more than one platform. +#if !NETCOREAPP1_1 // Schema validation doesn’t exist +#if !NET35 // Framework bug causes NRE: https://social.msdn.microsoft.com/Forums/en-US/53be44de-30b2-4d18-968d-d3414d0783b1 + // We don’t really need these tests to run on more than one platform. using System; using System.IO; diff --git a/src/NUnitFramework/framework/Api/DefaultTestAssemblyBuilder.cs b/src/NUnitFramework/framework/Api/DefaultTestAssemblyBuilder.cs index 7c7ca9fa4f..31018e7359 100644 --- a/src/NUnitFramework/framework/Api/DefaultTestAssemblyBuilder.cs +++ b/src/NUnitFramework/framework/Api/DefaultTestAssemblyBuilder.cs @@ -85,7 +85,7 @@ public ITest Build(Assembly assembly, IDictionary options) string assemblyPath = AssemblyHelper.GetAssemblyPath(assembly); string suiteName = assemblyPath.Equals("") ? AssemblyHelper.GetAssemblyName(assembly).FullName - : Path.GetFileName(assemblyPath); + : assemblyPath; return Build(assembly, suiteName, options); } @@ -111,18 +111,18 @@ public ITest Build(string assemblyNameOrPath, IDictionary option try { var assembly = AssemblyHelper.Load(assemblyNameOrPath); - testAssembly = Build(assembly, Path.GetFileName(assemblyNameOrPath), options); + testAssembly = Build(assembly, assemblyNameOrPath, options); } catch (Exception ex) { - testAssembly = new TestAssembly(Path.GetFileName(assemblyNameOrPath)); + testAssembly = new TestAssembly(assemblyNameOrPath); testAssembly.MakeInvalid(ExceptionHelper.BuildMessage(ex, true)); } return testAssembly; } - private TestSuite Build(Assembly assembly, string suiteName, IDictionary options) + private TestSuite Build(Assembly assembly, string assemblyNameOrPath, IDictionary options) { TestSuite testAssembly = null; @@ -176,11 +176,11 @@ private TestSuite Build(Assembly assembly, string suiteName, IDictionary GetCandidateFixtureTypes(Assembly assembly) // Process class is used, so we can safely satisfy the link demand with a 'SecuritySafeCriticalAttribute' rather // than a 'SecurityCriticalAttribute' and allow use by security transparent callers. [SecuritySafeCritical] - private TestSuite BuildTestAssembly(Assembly assembly, string suiteName, IList fixtures) + private TestSuite BuildTestAssembly(Assembly assembly, string assemblyNameOrPath, IList fixtures) { - TestSuite testAssembly = new TestAssembly(assembly, suiteName); + TestSuite testAssembly = new TestAssembly(assembly, assemblyNameOrPath); if (fixtures.Count == 0) { - testAssembly.MakeInvalid("Has no TestFixtures"); + testAssembly.MakeInvalid("No test fixtures were found."); } else { @@ -267,7 +267,7 @@ private TestSuite BuildTestAssembly(Assembly assembly, string suiteName, IListThe XML result of exploring the tests public string ExploreTests(string filter) { - if (Runner.LoadedTest == null) - throw new InvalidOperationException("The Explore method was called but no test has been loaded"); - return Runner.ExploreTests(TestFilter.FromXml(filter)).ToXml(true).OuterXml; } @@ -236,8 +233,6 @@ public string RunTests(string filter) return result.OuterXml; } -#if !NET20 - class ActionCallback : ICallbackEventHandler { Action _callback; @@ -291,7 +286,6 @@ private void RunAsync(Action callback, string filter) Runner.RunAsync(new TestProgressReporter(handler), TestFilter.FromXml(filter)); } -#endif /// /// Stops the test run @@ -323,10 +317,7 @@ private void LoadTests(ICallbackEventHandler handler) private void ExploreTests(ICallbackEventHandler handler, string filter) { - if (Runner.LoadedTest == null) - throw new InvalidOperationException("The Explore method was called but no test has been loaded"); - - handler.RaiseCallbackEvent(Runner.ExploreTests(TestFilter.FromXml(filter)).ToXml(true).OuterXml); + handler.RaiseCallbackEvent(ExploreTests(filter)); } private void RunTests(ICallbackEventHandler handler, string filter) diff --git a/src/NUnitFramework/framework/Api/FrameworkPackageSettings.cs b/src/NUnitFramework/framework/Api/FrameworkPackageSettings.cs index 85d99c2825..c956a55587 100644 --- a/src/NUnitFramework/framework/Api/FrameworkPackageSettings.cs +++ b/src/NUnitFramework/framework/Api/FrameworkPackageSettings.cs @@ -71,7 +71,6 @@ public static class FrameworkPackageSettings /// /// A list of tests to be loaded. /// - // TODO: Remove? public const string LOAD = "LOAD"; /// diff --git a/src/NUnitFramework/framework/Api/NUnitTestAssemblyRunner.cs b/src/NUnitFramework/framework/Api/NUnitTestAssemblyRunner.cs index 4a7d17508a..ff2b8b2f06 100644 --- a/src/NUnitFramework/framework/Api/NUnitTestAssemblyRunner.cs +++ b/src/NUnitFramework/framework/Api/NUnitTestAssemblyRunner.cs @@ -32,7 +32,7 @@ using System.Diagnostics; using System.Security; -#if NET20 || NET35 || NET40 || NET45 +#if NET35 || NET40 || NET45 using System.Windows.Forms; #endif @@ -143,7 +143,7 @@ public bool IsTestComplete /// /// File name or path of the assembly to load /// Dictionary of option settings for loading the assembly - /// True if the load was successful + /// A Test Assembly containing all loaded tests public ITest Load(string assemblyNameOrPath, IDictionary settings) { Settings = settings; @@ -151,7 +151,8 @@ public ITest Load(string assemblyNameOrPath, IDictionary setting if (settings.ContainsKey(FrameworkPackageSettings.RandomSeed)) Randomizer.InitialSeed = (int)settings[FrameworkPackageSettings.RandomSeed]; - return LoadedTest = _builder.Build(assemblyNameOrPath, settings); + WrapInNUnitCallContext(() => LoadedTest = _builder.Build(assemblyNameOrPath, settings)); + return LoadedTest; } @@ -160,7 +161,7 @@ public ITest Load(string assemblyNameOrPath, IDictionary setting /// /// The assembly to load /// Dictionary of option settings for loading the assembly - /// True if the load was successful + /// A Test Assembly containing all loaded tests public ITest Load(Assembly assembly, IDictionary settings) { Settings = settings; @@ -168,7 +169,8 @@ public ITest Load(Assembly assembly, IDictionary settings) if (settings.ContainsKey(FrameworkPackageSettings.RandomSeed)) Randomizer.InitialSeed = (int)settings[FrameworkPackageSettings.RandomSeed]; - return LoadedTest = _builder.Build(assembly, settings); + WrapInNUnitCallContext(() => LoadedTest = _builder.Build(assembly, settings)); + return LoadedTest; } /// @@ -179,7 +181,7 @@ public ITest Load(Assembly assembly, IDictionary settings) public int CountTestCases(ITestFilter filter) { if (LoadedTest == null) - throw new InvalidOperationException("The CountTestCases method was called but no test has been loaded"); + throw new InvalidOperationException("Tests must be loaded before counting test cases."); return CountTestCases(LoadedTest, filter); } @@ -192,7 +194,7 @@ public int CountTestCases(ITestFilter filter) public ITest ExploreTests(ITestFilter filter) { if (LoadedTest == null) - throw new InvalidOperationException("The ExploreTests method was called but no test has been loaded"); + throw new InvalidOperationException("Tests must be loaded before exploring them."); if (filter == TestFilter.Empty) return LoadedTest; @@ -206,7 +208,7 @@ public ITest ExploreTests(ITestFilter filter) /// /// Interface to receive EventListener notifications. /// A test filter used to select tests to be run - /// + /// The test results from the run public ITestResult Run(ITestListener listener, ITestFilter filter) { RunAsync(listener, filter); @@ -227,7 +229,7 @@ public void RunAsync(ITestListener listener, ITestFilter filter) { log.Info("Running tests"); if (LoadedTest == null) - throw new InvalidOperationException("The Run method was called but no test has been loaded"); + throw new InvalidOperationException("Tests must be loaded before running them."); _runComplete.Reset(); @@ -237,7 +239,7 @@ public void RunAsync(ITestListener listener, ITestFilter filter) TopLevelWorkItem.InitializeContext(Context); TopLevelWorkItem.Completed += OnRunCompleted; - StartRun(listener); + WrapInNUnitCallContext(() => StartRun(listener)); } /// @@ -304,18 +306,18 @@ private void StartRun(ITestListener listener) } catch (SecurityException) { - TopLevelWorkItem.MarkNotRunnable("System.Security.Permissions.UIPermission is not set to start the debugger."); + TopLevelWorkItem.MarkNotRunnable("System.Security.Permissions.UIPermission must be granted in order to launch the debugger."); return; } //System.Diagnostics.Debugger.Launch() not implemented on mono catch (NotImplementedException) { - TopLevelWorkItem.MarkNotRunnable("Debugger unavailable on this platform."); + TopLevelWorkItem.MarkNotRunnable("This platform does not support launching the debugger."); return; } } -#if NET20 || NET35 || NET40 || NET45 +#if NET35 || NET40 || NET45 if (Settings.ContainsKey(FrameworkPackageSettings.PauseBeforeRun) && (bool)Settings[FrameworkPackageSettings.PauseBeforeRun]) PauseBeforeRun(); @@ -351,7 +353,7 @@ private void CreateTestExecutionContext(ITestListener listener) (bool)Settings[FrameworkPackageSettings.RunOnMainThread]) Context.Dispatcher = new MainThreadWorkItemDispatcher(); else if (levelOfParallelism > 0) - Context.Dispatcher = new ParallelWorkItemDispatcher(levelOfParallelism); + Context.Dispatcher = new ParallelWorkItemDispatcher(levelOfParallelism); else Context.Dispatcher = new SimpleWorkItemDispatcher(); #endif @@ -397,7 +399,7 @@ private int GetLevelOfParallelism() } #endif -#if NET20 || NET35 || NET40 || NET45 +#if NET35 || NET40 || NET45 // This method invokes members on the 'System.Diagnostics.Process' class and must satisfy the link demand of // the full-trust 'PermissionSetAttribute' on this class. Callers of this method have no influence on how the // Process class is used, so we can safely satisfy the link demand with a 'SecuritySafeCriticalAttribute' rather @@ -406,11 +408,39 @@ private int GetLevelOfParallelism() private static void PauseBeforeRun() { var process = Process.GetCurrentProcess(); - string attachMessage = string.Format("Attach debugger to Process {0}.exe with Id {1} if desired.", process.ProcessName, process.Id); - MessageBox.Show(attachMessage, process.ProcessName, MessageBoxButtons.OK, MessageBoxIcon.Information); + + MessageBox.Show( + $"Pausing as requested. If you would like to attach a debugger, the process name and ID are {process.ProcessName}.exe and {process.Id}." + Environment.NewLine + + Environment.NewLine + + "Click OK when you are ready to continue.", + $"{process.ProcessName} – paused", + MessageBoxButtons.OK, + MessageBoxIcon.Information); } #endif -#endregion +#if (NET35 || NET40 || NET45) + /// + /// Executes the action within an + /// which ensures the is cleaned up + /// suitably at the end of the test run. This method only has an effect running + /// the full .NET Framework. + /// +#else + /// + /// This method is a no-op in .NET Standard builds. + /// +#endif + protected void WrapInNUnitCallContext(Action action) + { +#if !(NET35 || NET40 || NET45) + action(); +#else + using (new NUnitCallContext()) + action(); +#endif + } } + +#endregion } diff --git a/src/NUnitFramework/framework/Assert.Exceptions.Async.cs b/src/NUnitFramework/framework/Assert.Exceptions.Async.cs index 8f15c6ab0b..d26905e0d7 100644 --- a/src/NUnitFramework/framework/Assert.Exceptions.Async.cs +++ b/src/NUnitFramework/framework/Assert.Exceptions.Async.cs @@ -21,7 +21,7 @@ // WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. // *********************************************************************** -#if ASYNC +#if TASK_PARALLEL_LIBRARY_API using System; using NUnit.Framework.Constraints; using NUnit.Framework.Internal; diff --git a/src/NUnitFramework/framework/Assert.That.cs b/src/NUnitFramework/framework/Assert.That.cs index 18eef31493..795751d4e4 100644 --- a/src/NUnitFramework/framework/Assert.That.cs +++ b/src/NUnitFramework/framework/Assert.That.cs @@ -59,7 +59,6 @@ public static void That(bool condition) Assert.That(condition, Is.True, null, null); } -#if !NET20 /// /// Asserts that a condition is true. If the condition is false the method throws /// an . @@ -70,13 +69,11 @@ public static void That(bool condition, Func getExceptionMessage) { Assert.That(condition, Is.True, getExceptionMessage); } -#endif #endregion #region Lambda returning Boolean -#if !NET20 /// /// Asserts that a condition is true. If the condition is false the method throws /// an . @@ -109,7 +106,7 @@ public static void That(Func condition, Func getExceptionMessage) { Assert.That(condition.Invoke(), Is.True, getExceptionMessage); } -#endif + #endregion #region ActualValueDelegate @@ -145,7 +142,6 @@ public static void That(ActualValueDelegate del, IResolveConst ReportFailure(result, message, args); } -#if !NET20 /// /// Apply a constraint to an actual value, succeeding if the constraint /// is satisfied and throwing an assertion exception on failure. @@ -166,7 +162,6 @@ public static void That(ActualValueDelegate del, IResolveConst if (!result.IsSuccess) ReportFailure(result, getExceptionMessage()); } -#endif #endregion @@ -196,7 +191,6 @@ public static void That(TestDelegate code, IResolveConstraint constraint, string Assert.That((object)code, constraint, message, args); } -#if !NET20 /// /// Asserts that the code represented by a delegate throws an exception /// that satisfies the constraint provided. @@ -208,7 +202,6 @@ public static void That(TestDelegate code, IResolveConstraint constraint, Func(TActual actual, IResolveConstraint expression, ReportFailure(result, message, args); } -#if !NET20 /// /// Apply a constraint to an actual value, succeeding if the constraint /// is satisfied and throwing an assertion exception on failure. @@ -268,7 +260,6 @@ public static void That(TActual actual, IResolveConstraint expression, if (!result.IsSuccess) ReportFailure(result, getExceptionMessage()); } -#endif #endregion diff --git a/src/NUnitFramework/framework/Assert.cs b/src/NUnitFramework/framework/Assert.cs index 5765b54de9..dbc325cc26 100644 --- a/src/NUnitFramework/framework/Assert.cs +++ b/src/NUnitFramework/framework/Assert.cs @@ -38,7 +38,7 @@ namespace NUnit.Framework /// public delegate void TestDelegate(); -#if ASYNC +#if TASK_PARALLEL_LIBRARY_API /// /// Delegate used by tests that execute async code and /// capture any thrown exception. @@ -65,7 +65,7 @@ public abstract partial class Assert [EditorBrowsable(EditorBrowsableState.Never)] public static new bool Equals(object a, object b) { - throw new InvalidOperationException("Assert.Equals should not be used for Assertions, use Assert.AreEqual(...) instead."); + throw new InvalidOperationException("Assert.Equals should not be used. Use Assert.AreEqual instead."); } /// @@ -78,7 +78,7 @@ public static new bool Equals(object a, object b) [EditorBrowsable(EditorBrowsableState.Never)] public static new void ReferenceEquals(object a, object b) { - throw new InvalidOperationException("Assert.ReferenceEquals should not be used for Assertions, use Assert.AreSame(...) instead."); + throw new InvalidOperationException("Assert.ReferenceEquals should not be used. Use Assert.AreSame instead."); } #endregion @@ -314,7 +314,7 @@ public static void Contains(object expected, ICollection actual) public static void Multiple(TestDelegate testDelegate) { TestExecutionContext context = TestExecutionContext.CurrentContext; - Guard.OperationValid(context != null, "Assert.Multiple called outside of a valid TestExecutionContext"); + Guard.OperationValid(context != null, "There is no current test execution context."); context.MultipleAssertLevel++; @@ -334,7 +334,7 @@ public static void Multiple(TestDelegate testDelegate) } } -#if ASYNC +#if TASK_PARALLEL_LIBRARY_API /// /// Wraps code containing a series of assertions, which should all /// be executed, even if they fail. Failed results are saved and @@ -344,7 +344,7 @@ public static void Multiple(TestDelegate testDelegate) public static void Multiple(AsyncTestDelegate testDelegate) { TestExecutionContext context = TestExecutionContext.CurrentContext; - Guard.OperationValid(context != null, "Assert.Multiple called outside of a valid TestExecutionContext"); + Guard.OperationValid(context != null, "There is no current test execution context."); context.MultipleAssertLevel++; @@ -365,9 +365,9 @@ public static void Multiple(AsyncTestDelegate testDelegate) } #endif -#endregion + #endregion -#region Helper Methods + #region Helper Methods private static void ReportFailure(ConstraintResult result, string message) { diff --git a/src/NUnitFramework/framework/AssertionHelper.cs b/src/NUnitFramework/framework/AssertionHelper.cs index d7b365430a..6b292e7e85 100644 --- a/src/NUnitFramework/framework/AssertionHelper.cs +++ b/src/NUnitFramework/framework/AssertionHelper.cs @@ -31,8 +31,8 @@ namespace NUnit.Framework /// AssertionHelper is an optional base class for user tests, /// allowing the use of shorter names in making asserts. /// - [Obsolete("The AssertionHelper class will be removed in a coming release. " + - "Consider using the NUnit.StaticExpect NuGet package as a replacement.")] + [Obsolete("The AssertionHelper class has been deprecated and will be removed in a future release. " + + "Please consider using the NUnit.StaticExpect NuGet package instead.")] public class AssertionHelper { #region Expect @@ -421,7 +421,7 @@ public UniqueItemsConstraint Unique } #endregion - + #if SERIALIZATION /// @@ -688,8 +688,14 @@ public SomeItemsConstraint Member(object expected) } /// + /// /// Returns a new checking for the /// presence of a particular object in the collection. + /// + /// + /// To search for a substring instead of a collection element, use the + /// overload. + /// /// public SomeItemsConstraint Contains(object expected) { @@ -701,12 +707,15 @@ public SomeItemsConstraint Contains(object expected) #region Contains /// + /// /// Returns a new ContainsConstraint. This constraint /// will, in turn, make use of the appropriate second-level /// constraint, depending on the type of the actual argument. - /// This overload is only used if the item sought is a string, - /// since any other type implies that we are looking for a - /// collection member. + /// + /// + /// To search for a collection element instead of a substring, use the + /// overload. + /// /// public ContainsConstraint Contains(string expected) { @@ -721,7 +730,7 @@ public ContainsConstraint Contains(string expected) /// Returns a constraint that succeeds if the actual /// value contains the substring supplied as an argument. /// - [Obsolete("Deprecated, use Contains")] + [Obsolete("This method has been deprecated and will be removed in a future release. Please use Contains instead.")] public SubstringConstraint StringContaining(string expected) { return new SubstringConstraint(expected); @@ -731,7 +740,7 @@ public SubstringConstraint StringContaining(string expected) /// Returns a constraint that succeeds if the actual /// value contains the substring supplied as an argument. /// - [Obsolete("Deprecated, use Contains")] + [Obsolete("This method has been deprecated and will be removed in a future release. Please use Contains instead.")] public SubstringConstraint ContainsSubstring(string expected) { return new SubstringConstraint(expected); @@ -745,7 +754,7 @@ public SubstringConstraint ContainsSubstring(string expected) /// Returns a constraint that fails if the actual /// value contains the substring supplied as an argument. /// - [Obsolete("Deprecated, use Does.Not.Contain")] + [Obsolete("This method has been deprecated and will be removed in a future release. Please use Does.Not.Contain instead.")] public SubstringConstraint DoesNotContain(string expected) { return new ConstraintExpression().Not.ContainsSubstring(expected); @@ -777,7 +786,7 @@ public StartsWithConstraint StartsWith(string expected) /// Returns a constraint that succeeds if the actual /// value starts with the substring supplied as an argument. /// - [Obsolete("Deprecated, use Does.StartWith or StartsWith")] + [Obsolete("This method has been deprecated and will be removed in a future release. Please use Does.StartWith or StartsWith instead.")] public StartsWithConstraint StringStarting(string expected) { return new StartsWithConstraint(expected); @@ -791,7 +800,7 @@ public StartsWithConstraint StringStarting(string expected) /// Returns a constraint that fails if the actual /// value starts with the substring supplied as an argument. /// - [Obsolete("Deprecated, use Does.Not.StartWith")] + [Obsolete("This method has been deprecated and will be removed in a future release. Please use Does.Not.StartWith instead.")] public StartsWithConstraint DoesNotStartWith(string expected) { return new ConstraintExpression().Not.StartsWith(expected); @@ -823,7 +832,7 @@ public EndsWithConstraint EndsWith(string expected) /// Returns a constraint that succeeds if the actual /// value ends with the substring supplied as an argument. /// - [Obsolete("Deprecated, use Does.EndWith or EndsWith")] + [Obsolete("This method has been deprecated and will be removed in a future release. Please use Does.EndWith or EndsWith instead.")] public EndsWithConstraint StringEnding(string expected) { return new EndsWithConstraint(expected); @@ -837,7 +846,7 @@ public EndsWithConstraint StringEnding(string expected) /// Returns a constraint that fails if the actual /// value ends with the substring supplied as an argument. /// - [Obsolete("Deprecated, use Does.Not.EndWith")] + [Obsolete("This method has been deprecated and will be removed in a future release. Please use Does.Not.EndWith instead.")] public EndsWithConstraint DoesNotEndWith(string expected) { return new ConstraintExpression().Not.EndsWith(expected); @@ -869,7 +878,7 @@ public RegexConstraint Matches(string pattern) /// Returns a constraint that succeeds if the actual /// value matches the regular expression supplied as an argument. /// - [Obsolete("Deprecated, use Does.Match or Matches")] + [Obsolete("This method has been deprecated and will be removed in a future release. Please use Does.Match or Matches instead.")] public RegexConstraint StringMatching(string pattern) { return new RegexConstraint(pattern); @@ -883,7 +892,7 @@ public RegexConstraint StringMatching(string pattern) /// Returns a constraint that fails if the actual /// value matches the pattern supplied as an argument. /// - [Obsolete("Deprecated, use Does.Not.Match")] + [Obsolete("This method has been deprecated and will be removed in a future release. Please use Does.Not.Match instead.")] public RegexConstraint DoesNotMatch(string pattern) { return new ConstraintExpression().Not.Matches(pattern); diff --git a/src/NUnitFramework/framework/Assume.cs b/src/NUnitFramework/framework/Assume.cs index e3fb63f7c8..0966eecb07 100644 --- a/src/NUnitFramework/framework/Assume.cs +++ b/src/NUnitFramework/framework/Assume.cs @@ -1,4 +1,4 @@ -// *********************************************************************** +// *********************************************************************** // Copyright (c) 2009 Charlie Poole, Rob Prouse // // Permission is hereby granted, free of charge, to any person obtaining @@ -8,10 +8,10 @@ // 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 @@ -40,7 +40,7 @@ public class Assume /// /// DO NOT USE! - /// The Equals method throws an InvalidOperationException. This is done + /// The Equals method throws an InvalidOperationException. This is done /// to make sure there is no mistake by calling this function. /// /// The left object. @@ -49,19 +49,19 @@ public class Assume [EditorBrowsable(EditorBrowsableState.Never)] public static new bool Equals(object a, object b) { - throw new InvalidOperationException("Assume.Equals should not be used for Assertions."); + throw new InvalidOperationException("Assume.Equals should not be used. Use Assume.That instead."); } /// /// DO NOT USE! - /// The ReferenceEquals method throws an InvalidOperationException. This is done + /// The ReferenceEquals method throws an InvalidOperationException. This is done /// to make sure there is no mistake by calling this function. /// /// The left object. /// The right object. public static new void ReferenceEquals(object a, object b) { - throw new InvalidOperationException("Assume.ReferenceEquals should not be used for Assertions."); + throw new InvalidOperationException("Assume.ReferenceEquals should not be used. Use Assume.That instead."); } #endregion @@ -109,7 +109,6 @@ private static void ReportFailure(ConstraintResult result, string message, objec throw new InconclusiveException(writer.ToString()); } -#if !NET20 /// /// Apply a constraint to an actual value, succeeding if the constraint /// is satisfied and throwing an InconclusiveException on failure. @@ -133,7 +132,6 @@ private static void ReportFailure(ConstraintResult result, string message, objec throw new InconclusiveException(getExceptionMessage()); } } -#endif #endregion @@ -142,7 +140,7 @@ private static void ReportFailure(ConstraintResult result, string message, objec /// /// Asserts that a condition is true. If the condition is false the method throws /// an . - /// + /// /// The evaluated condition /// The message to display if the condition is false /// Arguments to be used in formatting the message @@ -152,7 +150,7 @@ public static void That(bool condition, string message, params object[] args) } /// - /// Asserts that a condition is true. If the condition is false the + /// Asserts that a condition is true. If the condition is false the /// method throws an . /// /// The evaluated condition @@ -161,28 +159,25 @@ public static void That(bool condition) Assume.That(condition, Is.True, null, null); } -#if !NET20 /// /// Asserts that a condition is true. If the condition is false the method throws /// an . - /// + /// /// The evaluated condition /// A function to build the message included with the Exception public static void That(bool condition, Func getExceptionMessage) { Assume.That(condition, Is.True, getExceptionMessage); } -#endif #endregion #region Lambda returning Boolean -#if !NET20 /// /// Asserts that a condition is true. If the condition is false the method throws /// an . - /// + /// /// A lambda that returns a Boolean /// The message to display if the condition is false /// Arguments to be used in formatting the message @@ -204,14 +199,13 @@ public static void That(Func condition) /// /// Asserts that a condition is true. If the condition is false the method throws /// an . - /// + /// /// A lambda that returns a Boolean /// A function to build the message included with the Exception public static void That(Func condition, Func getExceptionMessage) { Assume.That(condition.Invoke(), Is.True, getExceptionMessage); } -#endif #endregion @@ -270,7 +264,6 @@ public static void That(TActual actual, IResolveConstraint expression, } } -#if !NET20 /// /// Apply a constraint to an actual value, succeeding if the constraint /// is satisfied and throwing an InconclusiveException on failure. @@ -294,7 +287,6 @@ public static void That(TActual actual, IResolveConstraint expression, throw new InconclusiveException(getExceptionMessage()); } } -#endif #endregion @@ -308,4 +300,4 @@ private static void CheckMultipleAssertLevel() #endregion } -} \ No newline at end of file +} diff --git a/src/NUnitFramework/framework/Attributes/CategoryAttribute.cs b/src/NUnitFramework/framework/Attributes/CategoryAttribute.cs index e68ae92511..05ebeebf9c 100644 --- a/src/NUnitFramework/framework/Attributes/CategoryAttribute.cs +++ b/src/NUnitFramework/framework/Attributes/CategoryAttribute.cs @@ -36,7 +36,11 @@ public class CategoryAttribute : NUnitAttribute, IApplyToTest /// /// The name of the category /// +#pragma warning disable IDE1006 + // ReSharper disable once InconsistentNaming + // Disregarding naming convention for back-compat protected string categoryName; +#pragma warning restore IDE1006 /// /// Construct attribute for a given category based on diff --git a/src/NUnitFramework/framework/Attributes/DataAttribute.cs b/src/NUnitFramework/framework/Attributes/DataAttribute.cs index 20d322c180..7e563e3ca3 100644 --- a/src/NUnitFramework/framework/Attributes/DataAttribute.cs +++ b/src/NUnitFramework/framework/Attributes/DataAttribute.cs @@ -1,4 +1,4 @@ -// *********************************************************************** +// *********************************************************************** // Copyright (c) 2010 Charlie Poole, Rob Prouse // // Permission is hereby granted, free of charge, to any person obtaining @@ -8,10 +8,10 @@ // 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 @@ -27,11 +27,11 @@ namespace NUnit.Framework { /// - /// Abstract base class for all data-providing attributes defined by NUnit. + /// Abstract base class for all data-providing attributes defined by NUnit. /// Used to select all data sources for a method, class or parameter. /// - [Obsolete("Holdover from NUnit v2. Please implement " + nameof(IParameterDataSource) + - " for your attribute instead.")] + [Obsolete("The DataAttribute class has been deprecated and will be removed in a future release. " + + "Please use " + nameof(IParameterDataSource) + " instead.")] public abstract class DataAttribute : NUnitAttribute { /// diff --git a/src/NUnitFramework/framework/Attributes/ParallelScope.cs b/src/NUnitFramework/framework/Attributes/ParallelScope.cs index d91982349c..7172e8a373 100644 --- a/src/NUnitFramework/framework/Attributes/ParallelScope.cs +++ b/src/NUnitFramework/framework/Attributes/ParallelScope.cs @@ -1,4 +1,4 @@ -// *********************************************************************** +// *********************************************************************** // Copyright (c) 2014 Charlie Poole, Rob Prouse // // Permission is hereby granted, free of charge, to any person obtaining @@ -41,15 +41,17 @@ public enum ParallelScope /// /// The test may be run in parallel with others at the same level. - /// Valid on classes and methods but not assemblies. + /// Valid on classes and methods but has no effect on assemblies. /// Self = 1, + /// /// Test may not be run in parallel with any others. Valid on /// classes and methods but not assemblies. /// [EditorBrowsable(EditorBrowsableState.Never)] None = 2, + /// /// Mask used to extract the flags that apply to the item on which a /// ParallelizableAttribute has been placed, as opposed to descendants. @@ -59,26 +61,29 @@ public enum ParallelScope /// /// Descendants of the test may be run in parallel with one another. - /// Valid on assemblies and classes but not on methods. + /// Valid on assemblies and classes but not on non-parameterized methods. /// Children = 256, + /// /// Descendants of the test down to the level of TestFixtures may be /// run in parallel with one another. Valid on assemblies and classes /// but not on methods. /// Fixtures = 512, + /// /// Mask used to extract all the flags that impact descendants of a /// test and place them in the TestExecutionContext. /// - [EditorBrowsable(EditorBrowsableState.Never)] ContextMask = Children + Fixtures, /// /// The test and its descendants may be run in parallel with others at - /// the same level. Valid on classes and methods but not assemblies. + /// the same level. Valid on classes and parameterized methods. + /// For assemblies it is recommended to use + /// instead, as has no effect on assemblies. /// All = Self + Children } diff --git a/src/NUnitFramework/framework/Attributes/RandomAttribute.cs b/src/NUnitFramework/framework/Attributes/RandomAttribute.cs index 52f98518a5..8f493dcca1 100644 --- a/src/NUnitFramework/framework/Attributes/RandomAttribute.cs +++ b/src/NUnitFramework/framework/Attributes/RandomAttribute.cs @@ -234,7 +234,7 @@ abstract class RandomDataSource : RandomDataSource private readonly List previousValues = new List(); - protected Randomizer _randomizer; + protected Randomizer Randomizer; protected RandomDataSource(int count) { @@ -258,7 +258,7 @@ public override IEnumerable GetData(IParameterInfo parameter) { //Guard.ArgumentValid(parameter.ParameterType == typeof(T), "Parameter type must be " + typeof(T).Name, "parameter"); - _randomizer = Randomizer.GetRandomizer(parameter.ParameterInfo); + Randomizer = Randomizer.GetRandomizer(parameter.ParameterInfo); Guard.OperationValid(!(Distinct && _inRange && !CanBeDistinct(_min, _max, _count)), $"The range of values is [{_min}, {_max}[ and the random value count is {_count} so the values cannot be distinct."); @@ -347,12 +347,12 @@ class IntDataSource : RandomDataSource protected override int GetNext() { - return _randomizer.Next(); + return Randomizer.Next(); } protected override int GetNext(int min, int max) { - return _randomizer.Next(min, max); + return Randomizer.Next(min, max); } protected override bool CanBeDistinct(int min, int max, int count) @@ -373,12 +373,12 @@ class UIntDataSource : RandomDataSource protected override uint GetNext() { - return _randomizer.NextUInt(); + return Randomizer.NextUInt(); } protected override uint GetNext(uint min, uint max) { - return _randomizer.NextUInt(min, max); + return Randomizer.NextUInt(min, max); } protected override bool CanBeDistinct(uint min, uint max, int count) @@ -399,12 +399,12 @@ class LongDataSource : RandomDataSource protected override long GetNext() { - return _randomizer.NextLong(); + return Randomizer.NextLong(); } protected override long GetNext(long min, long max) { - return _randomizer.NextLong(min, max); + return Randomizer.NextLong(min, max); } protected override bool CanBeDistinct(long min, long max, int count) @@ -425,12 +425,12 @@ class ULongDataSource : RandomDataSource protected override ulong GetNext() { - return _randomizer.NextULong(); + return Randomizer.NextULong(); } protected override ulong GetNext(ulong min, ulong max) { - return _randomizer.NextULong(min, max); + return Randomizer.NextULong(min, max); } protected override bool CanBeDistinct(ulong min, ulong max, int count) @@ -451,12 +451,12 @@ class ShortDataSource : RandomDataSource protected override short GetNext() { - return _randomizer.NextShort(); + return Randomizer.NextShort(); } protected override short GetNext(short min, short max) { - return _randomizer.NextShort(min, max); + return Randomizer.NextShort(min, max); } protected override bool CanBeDistinct(short min, short max, int count) @@ -477,12 +477,12 @@ class UShortDataSource : RandomDataSource protected override ushort GetNext() { - return _randomizer.NextUShort(); + return Randomizer.NextUShort(); } protected override ushort GetNext(ushort min, ushort max) { - return _randomizer.NextUShort(min, max); + return Randomizer.NextUShort(min, max); } protected override bool CanBeDistinct(ushort min, ushort max, int count) @@ -503,12 +503,12 @@ class DoubleDataSource : RandomDataSource protected override double GetNext() { - return _randomizer.NextDouble(); + return Randomizer.NextDouble(); } protected override double GetNext(double min, double max) { - return _randomizer.NextDouble(min, max); + return Randomizer.NextDouble(min, max); } protected override bool CanBeDistinct(double min, double max, int count) @@ -529,12 +529,12 @@ class FloatDataSource : RandomDataSource protected override float GetNext() { - return _randomizer.NextFloat(); + return Randomizer.NextFloat(); } protected override float GetNext(float min, float max) { - return _randomizer.NextFloat(min, max); + return Randomizer.NextFloat(min, max); } protected override bool CanBeDistinct(float min, float max, int count) @@ -555,12 +555,12 @@ class ByteDataSource : RandomDataSource protected override byte GetNext() { - return _randomizer.NextByte(); + return Randomizer.NextByte(); } protected override byte GetNext(byte min, byte max) { - return _randomizer.NextByte(min, max); + return Randomizer.NextByte(min, max); } protected override bool CanBeDistinct(byte min, byte max, int count) @@ -581,12 +581,12 @@ class SByteDataSource : RandomDataSource protected override sbyte GetNext() { - return _randomizer.NextSByte(); + return Randomizer.NextSByte(); } protected override sbyte GetNext(sbyte min, sbyte max) { - return _randomizer.NextSByte(min, max); + return Randomizer.NextSByte(min, max); } protected override bool CanBeDistinct(sbyte min, sbyte max, int count) @@ -658,12 +658,12 @@ class DecimalDataSource : RandomDataSource protected override decimal GetNext() { - return _randomizer.NextDecimal(); + return Randomizer.NextDecimal(); } protected override decimal GetNext(decimal min, decimal max) { - return _randomizer.NextDecimal(min, max); + return Randomizer.NextDecimal(min, max); } protected override bool CanBeDistinct(decimal min, decimal max, int count) diff --git a/src/NUnitFramework/framework/Attributes/RequiresThreadAttribute.cs b/src/NUnitFramework/framework/Attributes/RequiresThreadAttribute.cs index 2f747591fa..4d7b12c27d 100644 --- a/src/NUnitFramework/framework/Attributes/RequiresThreadAttribute.cs +++ b/src/NUnitFramework/framework/Attributes/RequiresThreadAttribute.cs @@ -48,6 +48,8 @@ public RequiresThreadAttribute() public RequiresThreadAttribute(ApartmentState apartment) : base(true) { + Guard.ArgumentValid(apartment != ApartmentState.Unknown, "must be STA or MTA", nameof(apartment)); + this.Properties.Add(PropertyNames.ApartmentState, apartment); } #endif diff --git a/src/NUnitFramework/framework/Attributes/RetryAttribute.cs b/src/NUnitFramework/framework/Attributes/RetryAttribute.cs index 088bb40748..a1670c3e52 100644 --- a/src/NUnitFramework/framework/Attributes/RetryAttribute.cs +++ b/src/NUnitFramework/framework/Attributes/RetryAttribute.cs @@ -33,7 +33,7 @@ namespace NUnit.Framework /// maximum number of times. /// [AttributeUsage(AttributeTargets.Method, AllowMultiple = false, Inherited = false)] - public class RetryAttribute : PropertyAttribute, IRepeatTest + public class RetryAttribute : NUnitAttribute, IRepeatTest { private readonly int _tryCount; @@ -41,7 +41,7 @@ public class RetryAttribute : PropertyAttribute, IRepeatTest /// Construct a /// /// The maximum number of times the test should be run if it fails - public RetryAttribute(int tryCount) : base(tryCount) + public RetryAttribute(int tryCount) { _tryCount = tryCount; } diff --git a/src/NUnitFramework/framework/Attributes/SetUpFixtureAttribute.cs b/src/NUnitFramework/framework/Attributes/SetUpFixtureAttribute.cs index 62fc9dd7e9..7ebb1841ed 100644 --- a/src/NUnitFramework/framework/Attributes/SetUpFixtureAttribute.cs +++ b/src/NUnitFramework/framework/Attributes/SetUpFixtureAttribute.cs @@ -36,7 +36,7 @@ namespace NUnit.Framework /// methods for all the test fixtures /// under a given namespace. /// - [AttributeUsage(AttributeTargets.Class, AllowMultiple=false, Inherited=true)] + [AttributeUsage(AttributeTargets.Class, AllowMultiple = false, Inherited = true)] public class SetUpFixtureAttribute : NUnitAttribute, IFixtureBuilder { #region ISuiteBuilder Members @@ -67,16 +67,19 @@ public IEnumerable BuildFrom(ITypeInfo typeInfo) private static bool IsValidFixtureType(ITypeInfo typeInfo, ref string reason) { - if (typeInfo.IsAbstract) + if (!typeInfo.IsStaticClass) { - reason = string.Format("{0} is an abstract class", typeInfo.FullName); - return false; - } + if (typeInfo.IsAbstract) + { + reason = string.Format("{0} is an abstract class", typeInfo.FullName); + return false; + } - if (!typeInfo.HasConstructor(new Type[0])) - { - reason = string.Format("{0} does not have a default constructor", typeInfo.FullName); - return false; + if (!typeInfo.HasConstructor(new Type[0])) + { + reason = string.Format("{0} does not have a default constructor", typeInfo.FullName); + return false; + } } var invalidAttributes = new Type[] { diff --git a/src/NUnitFramework/framework/Attributes/TestCaseAttribute.cs b/src/NUnitFramework/framework/Attributes/TestCaseAttribute.cs index c193864518..08649a799c 100644 --- a/src/NUnitFramework/framework/Attributes/TestCaseAttribute.cs +++ b/src/NUnitFramework/framework/Attributes/TestCaseAttribute.cs @@ -269,7 +269,7 @@ private TestCaseParameters GetParametersForTestCase(IMethodInfo method) // Special handling for ExpectedResult (see if it needs to be converted into method return type) object expectedResultInTargetType; if (parms.HasExpectedResult - && PerformSpecialConversion(parms.ExpectedResult, method.ReturnType.Type, out expectedResultInTargetType)) + && ParamAttributeTypeConversions.TryConvert(parms.ExpectedResult, method.ReturnType.Type, out expectedResultInTargetType)) { parms.ExpectedResult = expectedResultInTargetType; } @@ -335,9 +335,6 @@ private TestCaseParameters GetParametersForTestCase(IMethodInfo method) parms.Arguments = newArgList; } - //if (method.GetParameters().Length == 1 && method.GetParameters()[0].ParameterType == typeof(object[])) - // parms.Arguments = new object[]{parms.Arguments}; - // Special handling when sole argument is an object[] if (argsNeeded == 1 && method.GetParameters()[0].ParameterType == typeof(object[])) { @@ -373,73 +370,12 @@ private static void PerformSpecialConversions(object[] arglist, IParameterInfo[] object arg = arglist[i]; Type targetType = parameters[i].ParameterType; object argAsTargetType; - if (PerformSpecialConversion(arg, targetType, out argAsTargetType)) + if (ParamAttributeTypeConversions.TryConvert(arg, targetType, out argAsTargetType)) { arglist[i] = argAsTargetType; } } } - - /// - /// Performs several special conversions allowed by NUnit in order to - /// permit arguments with types that cannot be used in the constructor - /// of an Attribute such as TestCaseAttribute or to simplify their use. - /// - /// The argument to be converted - /// The target in which the should be converted - /// If conversion was successfully applied, the converted into - /// - /// true if was converted and should be used; - /// false is no conversion was applied and should be ignored - /// - private static bool PerformSpecialConversion(object arg, Type targetType, out object argAsTargetType) - { - argAsTargetType = null; - if (arg == null) - return false; - - if (targetType.IsInstanceOfType(arg)) - return false; - - if (arg.GetType().FullName == "System.DBNull") - { - argAsTargetType = null; - return true; - } - - bool convert = false; - - if (targetType == typeof(short) || targetType == typeof(byte) || targetType == typeof(sbyte) || targetType == typeof(long?) || - targetType == typeof(short?) || targetType == typeof(byte?) || targetType == typeof(sbyte?) || targetType == typeof(double?)) - { - convert = arg is int; - } - else if (targetType == typeof(decimal) || targetType == typeof(decimal?)) - { - convert = arg is double || arg is string || arg is int; - } - else if (targetType == typeof(DateTime) || targetType == typeof(DateTime?)) - { - convert = arg is string; - } - - if (convert) - { - Type convertTo = targetType.GetTypeInfo().IsGenericType && targetType.GetGenericTypeDefinition() == typeof(Nullable<>) ? - targetType.GetGenericArguments()[0] : targetType; - argAsTargetType = Convert.ChangeType(arg, convertTo, System.Globalization.CultureInfo.InvariantCulture); - return true; - } - - // Convert.ChangeType doesn't work for TimeSpan from string - if ((targetType == typeof(TimeSpan) || targetType == typeof(TimeSpan?)) && arg is string) - { - argAsTargetType = TimeSpan.Parse((string)arg); - return true; - } - - return false; - } #endregion #region ITestBuilder Members @@ -454,10 +390,15 @@ public IEnumerable BuildFrom(IMethodInfo method, Test suite) TestMethod test = new NUnitTestCaseBuilder().BuildTestMethod(method, suite, GetParametersForTestCase(method)); #if PLATFORM_DETECTION - if (test.RunState != RunState.NotRunnable && - test.RunState != RunState.Ignored) + if (IncludePlatform != null || ExcludePlatform != null) { - PlatformHelper platformHelper = new PlatformHelper(); + if (test.RunState == RunState.NotRunnable || test.RunState == RunState.Ignored) + { + yield return test; + yield break; + } + + var platformHelper = new PlatformHelper(); if (!platformHelper.IsPlatformSupported(this)) { diff --git a/src/NUnitFramework/framework/Attributes/TestFixtureAttribute.cs b/src/NUnitFramework/framework/Attributes/TestFixtureAttribute.cs index b7b2674d0e..22c83d7675 100644 --- a/src/NUnitFramework/framework/Attributes/TestFixtureAttribute.cs +++ b/src/NUnitFramework/framework/Attributes/TestFixtureAttribute.cs @@ -46,8 +46,7 @@ public class TestFixtureAttribute : NUnitAttribute, IFixtureBuilder2, ITestFixtu /// /// Construct with a object[] representing a set of arguments. - /// In .NET 2.0, the arguments may later be separated into - /// type arguments and constructor arguments. + /// The arguments may later be separated into type arguments and constructor arguments. /// /// public TestFixtureAttribute(params object[] arguments) diff --git a/src/NUnitFramework/framework/Attributes/TestOfAttribute.cs b/src/NUnitFramework/framework/Attributes/TestOfAttribute.cs index c0d48030b2..d4469c2321 100644 --- a/src/NUnitFramework/framework/Attributes/TestOfAttribute.cs +++ b/src/NUnitFramework/framework/Attributes/TestOfAttribute.cs @@ -35,7 +35,7 @@ namespace NUnit.Framework /// /// Indicates the method or class the assembly, test fixture or test method is testing. /// - [AttributeUsage(AttributeTargets.Method | AttributeTargets.Class | AttributeTargets.Assembly, AllowMultiple = false, Inherited = false)] + [AttributeUsage(AttributeTargets.Method | AttributeTargets.Class | AttributeTargets.Assembly, AllowMultiple = true, Inherited = false)] public class TestOfAttribute : PropertyAttribute { /// diff --git a/src/NUnitFramework/framework/Attributes/TimeoutAttribute.cs b/src/NUnitFramework/framework/Attributes/TimeoutAttribute.cs index ac1acbe39a..1f4ddbf9a7 100644 --- a/src/NUnitFramework/framework/Attributes/TimeoutAttribute.cs +++ b/src/NUnitFramework/framework/Attributes/TimeoutAttribute.cs @@ -1,5 +1,5 @@ // *********************************************************************** -// Copyright (c) 2008 Charlie Poole, Rob Prouse +// Copyright (c) 2008-2018 Charlie Poole, Rob Prouse // // Permission is hereby granted, free of charge, to any person obtaining // a copy of this software and associated documentation files (the @@ -21,7 +21,6 @@ // WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. // *********************************************************************** -#if THREAD_ABORT using System; using NUnit.Framework.Internal; using NUnit.Framework.Internal.Commands; @@ -49,7 +48,7 @@ public TimeoutAttribute(int timeout) _timeout = timeout; } - #region IApplyToContext Members + #region IApplyToContext void IApplyToContext.ApplyToContext(TestExecutionContext context) { @@ -59,4 +58,3 @@ void IApplyToContext.ApplyToContext(TestExecutionContext context) #endregion } } -#endif diff --git a/src/NUnitFramework/framework/Attributes/ValuesAttribute.cs b/src/NUnitFramework/framework/Attributes/ValuesAttribute.cs index 1c2b3b6096..a9d1096cfd 100644 --- a/src/NUnitFramework/framework/Attributes/ValuesAttribute.cs +++ b/src/NUnitFramework/framework/Attributes/ValuesAttribute.cs @@ -44,7 +44,11 @@ public class ValuesAttribute : NUnitAttribute, IParameterDataSource /// elements may have their type changed in GetData /// if necessary /// +#pragma warning disable IDE1006 + // ReSharper disable once InconsistentNaming + // Disregarding naming convention for back-compat protected object[] data; +#pragma warning restore IDE1006 /// /// Constructs for use with an Enum parameter. Will pass every enum diff --git a/src/NUnitFramework/framework/CollectionAssert.cs b/src/NUnitFramework/framework/CollectionAssert.cs index a6be30be9b..023e6372f5 100644 --- a/src/NUnitFramework/framework/CollectionAssert.cs +++ b/src/NUnitFramework/framework/CollectionAssert.cs @@ -8,10 +8,10 @@ // 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 @@ -38,7 +38,7 @@ public abstract class CollectionAssert /// /// DO NOT USE! Use CollectionAssert.AreEqual(...) instead. - /// The Equals method throws an InvalidOperationException. This is done + /// The Equals method throws an InvalidOperationException. This is done /// to make sure there is no mistake by calling this function. /// /// @@ -46,23 +46,23 @@ public abstract class CollectionAssert [EditorBrowsable(EditorBrowsableState.Never)] public static new bool Equals(object a, object b) { - throw new InvalidOperationException("CollectionAssert.Equals should not be used for Assertions, use CollectionAssert.AreEqual(...) instead."); + throw new InvalidOperationException("CollectionAssert.Equals should not be used. Use CollectionAssert.AreEqual instead."); } /// /// DO NOT USE! - /// The ReferenceEquals method throws an InvalidOperationException. This is done + /// The ReferenceEquals method throws an InvalidOperationException. This is done /// to make sure there is no mistake by calling this function. /// /// /// public static new void ReferenceEquals(object a, object b) { - throw new InvalidOperationException("CollectionAssert.ReferenceEquals should not be used for Assertions."); + throw new InvalidOperationException("CollectionAssert.ReferenceEquals should not be used."); } #endregion - + #region AllItemsAreInstancesOfType /// /// Asserts that all items contained in collection are of the type specified by expectedType. @@ -93,7 +93,7 @@ public static void AllItemsAreInstancesOfType (IEnumerable collection, Type expe /// Asserts that all items contained in collection are not equal to null. /// /// IEnumerable containing objects to be considered - public static void AllItemsAreNotNull (IEnumerable collection) + public static void AllItemsAreNotNull (IEnumerable collection) { AllItemsAreNotNull(collection, string.Empty, null); } @@ -104,7 +104,7 @@ public static void AllItemsAreNotNull (IEnumerable collection) /// IEnumerable of objects to be considered /// The message that will be displayed on failure /// Arguments to be used in formatting the message - public static void AllItemsAreNotNull (IEnumerable collection, string message, params object[] args) + public static void AllItemsAreNotNull (IEnumerable collection, string message, params object[] args) { Assert.That(collection, Is.All.Not.Null, message, args); } @@ -117,11 +117,11 @@ public static void AllItemsAreNotNull (IEnumerable collection, string message, p /// once and only once. /// /// IEnumerable of objects to be considered - public static void AllItemsAreUnique (IEnumerable collection) + public static void AllItemsAreUnique (IEnumerable collection) { AllItemsAreUnique(collection, string.Empty, null); } - + /// /// Ensures that every object contained in collection exists within the collection /// once and only once. @@ -129,7 +129,7 @@ public static void AllItemsAreUnique (IEnumerable collection) /// IEnumerable of objects to be considered /// The message that will be displayed on failure /// Arguments to be used in formatting the message - public static void AllItemsAreUnique (IEnumerable collection, string message, params object[] args) + public static void AllItemsAreUnique (IEnumerable collection, string message, params object[] args) { Assert.That(collection, Is.Unique, message, args); } @@ -138,44 +138,44 @@ public static void AllItemsAreUnique (IEnumerable collection, string message, pa #region AreEqual /// - /// Asserts that expected and actual are exactly equal. The collections must have the same count, + /// Asserts that expected and actual are exactly equal. The collections must have the same count, /// and contain the exact same objects in the same order. /// /// The first IEnumerable of objects to be considered /// The second IEnumerable of objects to be considered - public static void AreEqual (IEnumerable expected, IEnumerable actual) + public static void AreEqual (IEnumerable expected, IEnumerable actual) { AreEqual(expected, actual, string.Empty, null); } /// - /// Asserts that expected and actual are exactly equal. The collections must have the same count, + /// Asserts that expected and actual are exactly equal. The collections must have the same count, /// and contain the exact same objects in the same order. /// If comparer is not null then it will be used to compare the objects. /// /// The first IEnumerable of objects to be considered /// The second IEnumerable of objects to be considered /// The IComparer to use in comparing objects from each IEnumerable - public static void AreEqual (IEnumerable expected, IEnumerable actual, IComparer comparer) + public static void AreEqual (IEnumerable expected, IEnumerable actual, IComparer comparer) { AreEqual(expected, actual, comparer, string.Empty, null); } /// - /// Asserts that expected and actual are exactly equal. The collections must have the same count, + /// Asserts that expected and actual are exactly equal. The collections must have the same count, /// and contain the exact same objects in the same order. /// /// The first IEnumerable of objects to be considered /// The second IEnumerable of objects to be considered /// The message that will be displayed on failure /// Arguments to be used in formatting the message - public static void AreEqual (IEnumerable expected, IEnumerable actual, string message, params object[] args) + public static void AreEqual (IEnumerable expected, IEnumerable actual, string message, params object[] args) { Assert.That(actual, Is.EqualTo(expected).AsCollection, message, args); } /// - /// Asserts that expected and actual are exactly equal. The collections must have the same count, + /// Asserts that expected and actual are exactly equal. The collections must have the same count, /// and contain the exact same objects in the same order. /// If comparer is not null then it will be used to compare the objects. /// @@ -184,7 +184,7 @@ public static void AreEqual (IEnumerable expected, IEnumerable actual, string me /// The IComparer to use in comparing objects from each IEnumerable /// The message that will be displayed on failure /// Arguments to be used in formatting the message - public static void AreEqual (IEnumerable expected, IEnumerable actual, IComparer comparer, string message, params object[] args) + public static void AreEqual (IEnumerable expected, IEnumerable actual, IComparer comparer, string message, params object[] args) { Assert.That(actual, Is.EqualTo(expected).Using(comparer), message, args); } @@ -197,7 +197,7 @@ public static void AreEqual (IEnumerable expected, IEnumerable actual, IComparer /// /// The first IEnumerable of objects to be considered /// The second IEnumerable of objects to be considered - public static void AreEquivalent (IEnumerable expected, IEnumerable actual) + public static void AreEquivalent (IEnumerable expected, IEnumerable actual) { AreEquivalent(expected, actual, string.Empty, null); } @@ -209,7 +209,7 @@ public static void AreEquivalent (IEnumerable expected, IEnumerable actual) /// The second IEnumerable of objects to be considered /// The message that will be displayed on failure /// Arguments to be used in formatting the message - public static void AreEquivalent (IEnumerable expected, IEnumerable actual, string message, params object[] args) + public static void AreEquivalent (IEnumerable expected, IEnumerable actual, string message, params object[] args) { Assert.That(actual, Is.EquivalentTo(expected), message, args); } @@ -246,7 +246,7 @@ public static void AreNotEqual (IEnumerable expected, IEnumerable actual, ICompa /// The second IEnumerable of objects to be considered /// The message that will be displayed on failure /// Arguments to be used in formatting the message - public static void AreNotEqual (IEnumerable expected, IEnumerable actual, string message, params object[] args) + public static void AreNotEqual (IEnumerable expected, IEnumerable actual, string message, params object[] args) { Assert.That(actual, Is.Not.EqualTo(expected).AsCollection, message, args); } @@ -485,7 +485,7 @@ public static void IsNotEmpty(IEnumerable collection) IsNotEmpty(collection, string.Empty, null); } #endregion - + #region IsOrdered /// /// Assert that an array, list or other collection is ordered diff --git a/src/NUnitFramework/framework/Compatibility/ReaderWriterLockSlim.cs b/src/NUnitFramework/framework/Compatibility/ReaderWriterLockSlim.cs deleted file mode 100644 index 33fe2fdd51..0000000000 --- a/src/NUnitFramework/framework/Compatibility/ReaderWriterLockSlim.cs +++ /dev/null @@ -1,52 +0,0 @@ -using System; -using System.Linq; -using System.Collections.Generic; -using System.Text; -using System.Threading; - -namespace NUnit.Compatibility -{ -#if NET20 - /// - /// - /// - public static class ReaderWriterLockExtensions - { - /// - /// - /// - /// - public static void EnterReadLock(this ReaderWriterLock rwLock) - { - rwLock.AcquireReaderLock(Timeout.Infinite); - } - - /// - /// - /// - /// - public static void EnterWriteLock(this ReaderWriterLock rwLock) - { - rwLock.AcquireWriterLock(Timeout.Infinite); - } - - /// - /// - /// - /// - public static void ExitReadLock(this ReaderWriterLock rwLock) - { - rwLock.ReleaseReaderLock(); - } - - /// - /// - /// - /// - public static void ExitWriteLock(this ReaderWriterLock rwLock) - { - rwLock.ReleaseWriterLock(); - } - } -#endif -} diff --git a/src/NUnitFramework/framework/Compatibility/ReflectionExtensions.cs b/src/NUnitFramework/framework/Compatibility/ReflectionExtensions.cs index f27b0d2f7d..11ffc179e3 100644 --- a/src/NUnitFramework/framework/Compatibility/ReflectionExtensions.cs +++ b/src/NUnitFramework/framework/Compatibility/ReflectionExtensions.cs @@ -21,7 +21,7 @@ // WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. // *********************************************************************** -#if NET20 || NET35 || NET40 +#if NET35 || NET40 using System; using System.Reflection; @@ -89,6 +89,14 @@ public static Delegate CreateDelegate(this MethodInfo method, Type type) { return Delegate.CreateDelegate(type, method); } + + /// + /// See . + /// + public static Delegate CreateDelegate(this MethodInfo method, Type type, object target) + { + return Delegate.CreateDelegate(type, target, method); + } } } #endif diff --git a/src/NUnitFramework/framework/Compatibility/System.Collections.Concurrent/ConcurrentQueue.cs b/src/NUnitFramework/framework/Compatibility/System.Collections.Concurrent/ConcurrentQueue.cs index d6e3382288..ffdc0e051d 100644 --- a/src/NUnitFramework/framework/Compatibility/System.Collections.Concurrent/ConcurrentQueue.cs +++ b/src/NUnitFramework/framework/Compatibility/System.Collections.Concurrent/ConcurrentQueue.cs @@ -1,4 +1,7 @@ -#if NET20 || NET35 +// ReSharper disable InconsistentNaming +// Disregarding naming convention in polyfill code + +#if NET35 #pragma warning disable 0420 // ==++== diff --git a/src/NUnitFramework/framework/Compatibility/System.Collections.Concurrent/IProducerConsumerCollection.cs b/src/NUnitFramework/framework/Compatibility/System.Collections.Concurrent/IProducerConsumerCollection.cs index c025b0fc15..0077e2844b 100644 --- a/src/NUnitFramework/framework/Compatibility/System.Collections.Concurrent/IProducerConsumerCollection.cs +++ b/src/NUnitFramework/framework/Compatibility/System.Collections.Concurrent/IProducerConsumerCollection.cs @@ -1,4 +1,4 @@ -#if NET20 || NET35 +#if NET35 // ==++== // // Copyright (c) Microsoft Corporation. All rights reserved. diff --git a/src/NUnitFramework/framework/Compatibility/System.Collections/CollectionDebuggerView.cs b/src/NUnitFramework/framework/Compatibility/System.Collections/CollectionDebuggerView.cs index 4b84d5c7db..a667bf6ae8 100644 --- a/src/NUnitFramework/framework/Compatibility/System.Collections/CollectionDebuggerView.cs +++ b/src/NUnitFramework/framework/Compatibility/System.Collections/CollectionDebuggerView.cs @@ -1,10 +1,13 @@ +// ReSharper disable InconsistentNaming +// Disregarding naming convention in polyfill code + // // CollectionDebuggerView.cs // // Authors: // Marek Safar // -// Copyright (C) 2009 Novell, Inc (http://www.novell.com) +// Copyright (C) 2009 Novell, Inc (https://www.novell.com) // // Permission is hereby granted, free of charge, to any person obtaining // a copy of this software and associated documentation files (the @@ -26,7 +29,7 @@ // WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. // -#if NET20 || NET35 +#if NET35 using System; using System.Diagnostics; @@ -73,4 +76,4 @@ public CollectionDebuggerView (ICollection> col) } } } -#endif \ No newline at end of file +#endif diff --git a/src/NUnitFramework/framework/Compatibility/System.Threading/LazyThreadSafetyMode.cs b/src/NUnitFramework/framework/Compatibility/System.Threading/LazyThreadSafetyMode.cs index 475c5f3ed7..8dbe2bca86 100644 --- a/src/NUnitFramework/framework/Compatibility/System.Threading/LazyThreadSafetyMode.cs +++ b/src/NUnitFramework/framework/Compatibility/System.Threading/LazyThreadSafetyMode.cs @@ -26,7 +26,7 @@ // WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. // -#if NET20 || NET35 +#if NET35 using System; namespace System.Threading diff --git a/src/NUnitFramework/framework/Compatibility/System.Threading/ManualResetEventSlim.cs b/src/NUnitFramework/framework/Compatibility/System.Threading/ManualResetEventSlim.cs index 3bf3ea388c..3918294d20 100644 --- a/src/NUnitFramework/framework/Compatibility/System.Threading/ManualResetEventSlim.cs +++ b/src/NUnitFramework/framework/Compatibility/System.Threading/ManualResetEventSlim.cs @@ -21,7 +21,7 @@ // WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. // *********************************************************************** -#if NET20 || NET35 +#if NET35 namespace System.Threading { /// diff --git a/src/NUnitFramework/framework/Compatibility/System.Threading/SpinWait.cs b/src/NUnitFramework/framework/Compatibility/System.Threading/SpinWait.cs index 54be18d00e..fe931dfd86 100644 --- a/src/NUnitFramework/framework/Compatibility/System.Threading/SpinWait.cs +++ b/src/NUnitFramework/framework/Compatibility/System.Threading/SpinWait.cs @@ -1,4 +1,4 @@ -#if NET20 || NET35 +#if NET35 // ==++== // // Copyright (c) Microsoft Corporation. All rights reserved. diff --git a/src/NUnitFramework/framework/Compatibility/System.Web.UI/ICallbackEventHandler.cs b/src/NUnitFramework/framework/Compatibility/System.Web.UI/ICallbackEventHandler.cs index 04e79c8ad0..6395a1d8f5 100644 --- a/src/NUnitFramework/framework/Compatibility/System.Web.UI/ICallbackEventHandler.cs +++ b/src/NUnitFramework/framework/Compatibility/System.Web.UI/ICallbackEventHandler.cs @@ -21,7 +21,7 @@ // WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. // *********************************************************************** -#if !(NET20 || NET35 || NET40 || NET45) +#if !(NET35 || NET40 || NET45) namespace System.Web.UI { /// diff --git a/src/NUnitFramework/framework/Compatibility/System/Lazy.cs b/src/NUnitFramework/framework/Compatibility/System/Lazy.cs index 14df7cff60..04bb4eaa01 100644 --- a/src/NUnitFramework/framework/Compatibility/System/Lazy.cs +++ b/src/NUnitFramework/framework/Compatibility/System/Lazy.cs @@ -1,3 +1,6 @@ +// ReSharper disable InconsistentNaming +// Disregarding naming convention in polyfill code + // // Lazy.cs // @@ -26,7 +29,7 @@ // OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION // WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. // -#if NET20 || NET35 +#if NET35 using System; using System.Runtime.Serialization; using System.Runtime.InteropServices; @@ -229,4 +232,4 @@ public override string ToString () } } } -#endif \ No newline at end of file +#endif diff --git a/src/NUnitFramework/framework/Constraints/AndConstraint.cs b/src/NUnitFramework/framework/Constraints/AndConstraint.cs index b401ea10cd..7eed268146 100644 --- a/src/NUnitFramework/framework/Constraints/AndConstraint.cs +++ b/src/NUnitFramework/framework/Constraints/AndConstraint.cs @@ -76,7 +76,7 @@ class AndConstraintResult : ConstraintResult private readonly ConstraintResult rightResult; public AndConstraintResult(AndConstraint constraint, object actual, ConstraintResult leftResult, ConstraintResult rightResult) - : base(constraint, actual, leftResult.IsSuccess && rightResult.IsSuccess) + : base(constraint, actual, leftResult.IsSuccess && rightResult.IsSuccess) { this.leftResult = leftResult; this.rightResult = rightResult; @@ -98,8 +98,18 @@ public override void WriteActualValueTo(MessageWriter writer) else rightResult.WriteActualValueTo(writer); } + + public override void WriteAdditionalLinesTo(MessageWriter writer) + { + if (this.IsSuccess) + base.WriteAdditionalLinesTo(writer); + else if (!leftResult.IsSuccess) + leftResult.WriteAdditionalLinesTo(writer); + else + rightResult.WriteAdditionalLinesTo(writer); + } } #endregion } -} \ No newline at end of file +} diff --git a/src/NUnitFramework/framework/Constraints/CollectionContainsConstraint.cs b/src/NUnitFramework/framework/Constraints/CollectionContainsConstraint.cs index c5f6fc940f..f4a529a26e 100644 --- a/src/NUnitFramework/framework/Constraints/CollectionContainsConstraint.cs +++ b/src/NUnitFramework/framework/Constraints/CollectionContainsConstraint.cs @@ -8,10 +8,10 @@ // 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 @@ -36,14 +36,15 @@ public class CollectionContainsConstraint : CollectionItemsEqualConstraint /// Construct a CollectionContainsConstraint /// /// - [Obsolete("Deprecated, use 'new SomeItemsConstraint(new EqualConstraint(expected))' or 'Has.Some.EqualTo(expected)' instead.")] + [Obsolete("This constructor has been deprecated and will be removed in a future release. " + + "Please use 'new SomeItemsConstraint(new EqualConstraint(expected))' or 'Has.Some.EqualTo(expected)' instead.")] public CollectionContainsConstraint(object expected) : base(expected) { Expected = expected; } - /// + /// /// The display name of this Constraint for use by ToString(). /// The default value is the name of the constraint with /// trailing "Constraint" removed. Derived classes may set @@ -94,4 +95,4 @@ protected override bool Matches(IEnumerable actual) return this; } } -} \ No newline at end of file +} diff --git a/src/NUnitFramework/framework/Constraints/CollectionOrderedConstraint.cs b/src/NUnitFramework/framework/Constraints/CollectionOrderedConstraint.cs index 683014dcaf..377185b92a 100644 --- a/src/NUnitFramework/framework/Constraints/CollectionOrderedConstraint.cs +++ b/src/NUnitFramework/framework/Constraints/CollectionOrderedConstraint.cs @@ -223,15 +223,9 @@ protected override bool Matches(IEnumerable actual) { string propertyName = step.PropertyName; - PropertyInfo previousProp = previous.GetType().GetProperty(propertyName); - if (previousProp == null) - throw new ArgumentException($"Property {propertyName} not found at index {_breakingIndex - 1}", nameof(actual)); - var previousValue = previousProp.GetValue(previous, null); + object previousValue = ExtractValue(actual, previous, propertyName, _breakingIndex - 1); - PropertyInfo prop = current.GetType().GetProperty(propertyName); - if (prop == null) - throw new ArgumentException($"Property {propertyName} not found at index {_breakingIndex}", nameof(actual)); - var currentValue = prop.GetValue(current, null); + object currentValue = ExtractValue(actual, current, propertyName, _breakingIndex); int comparisonResult = step.Comparer.Compare(previousValue, currentValue); @@ -297,6 +291,23 @@ private void CreateNextStep(string propertyName) _steps.Add(_activeStep); } + private object ExtractValue(IEnumerable actual, object item, string propertyName, int index) + { + PropertyInfo property = item.GetType().GetProperty(propertyName); + if (property != null) + { + return property.GetValue(item, null); + } + + FieldInfo field = item.GetType().GetField(propertyName); + if (field != null) + { + return field.GetValue(item); + } + + throw new ArgumentException($"No property or field with name {propertyName} was found at index {index}", nameof(actual)); + } + #region Internal OrderingStep Class /// diff --git a/src/NUnitFramework/framework/Constraints/ComparisonConstraint.cs b/src/NUnitFramework/framework/Constraints/ComparisonConstraint.cs index 9eb732fb75..3d21f13d93 100644 --- a/src/NUnitFramework/framework/Constraints/ComparisonConstraint.cs +++ b/src/NUnitFramework/framework/Constraints/ComparisonConstraint.cs @@ -22,6 +22,7 @@ // *********************************************************************** using System; +using System.Text; using System.Collections; using System.Collections.Generic; @@ -128,7 +129,6 @@ public ComparisonConstraint Within(object amount) throw new InvalidOperationException("Within modifier may appear only once in a constraint expression"); _tolerance = new Tolerance(amount); - Description += " within " + MsgUtils.FormatValue(amount); return this; } @@ -143,11 +143,43 @@ public ComparisonConstraint Percent get { _tolerance = _tolerance.Percent; - Description += " percent"; return this; } } #endregion + + #region Protected Methods + + /// + /// Provides standard description of what the constraint tests + /// based on comparison text. + /// + /// Describes the comparison being tested, throws + /// if null + /// Is thrown when null passed to a method + protected string DefaultDescription(string comparisonText) + { + if (comparisonText == null) + throw new ArgumentNullException(nameof(comparisonText), "Comparison text can not be null"); + + StringBuilder sb = new StringBuilder(comparisonText); + sb.Append(MsgUtils.FormatValue(_expected)); + + if (_tolerance != null && !_tolerance.IsUnsetOrDefault) + { + sb.Append(" within "); + sb.Append(MsgUtils.FormatValue(_tolerance.Amount)); + + if (_tolerance.Mode == ToleranceMode.Percent) + { + sb.Append(" percent"); + } + } + + return sb.ToString(); + } + + #endregion } -} \ No newline at end of file +} diff --git a/src/NUnitFramework/framework/Constraints/Constraint.cs b/src/NUnitFramework/framework/Constraints/Constraint.cs index be5fd89577..7fc50fa2c1 100644 --- a/src/NUnitFramework/framework/Constraints/Constraint.cs +++ b/src/NUnitFramework/framework/Constraints/Constraint.cs @@ -116,10 +116,9 @@ protected Constraint(params object[] args) /// A ConstraintResult public virtual ConstraintResult ApplyTo(ActualValueDelegate del) { -#if ASYNC if (AsyncToSyncAdapter.IsAsyncOperation(del)) return ApplyTo(AsyncToSyncAdapter.Await(() => del.Invoke())); -#endif + return ApplyTo(GetTestObject(del)); } diff --git a/src/NUnitFramework/framework/Constraints/ConstraintExpression.cs b/src/NUnitFramework/framework/Constraints/ConstraintExpression.cs index 61cfa2237c..ca7baaf411 100644 --- a/src/NUnitFramework/framework/Constraints/ConstraintExpression.cs +++ b/src/NUnitFramework/framework/Constraints/ConstraintExpression.cs @@ -45,7 +45,11 @@ public class ConstraintExpression /// /// The ConstraintBuilder holding the elements recognized so far /// +#pragma warning disable IDE1006 + // ReSharper disable once InconsistentNaming + // Disregarding naming convention for back-compat protected readonly ConstraintBuilder builder; +#pragma warning restore IDE1006 #endregion @@ -725,8 +729,14 @@ public SomeItemsConstraint Member(object expected) #region Contains /// + /// /// Returns a new checking for the /// presence of a particular object in the collection. + /// + /// + /// To search for a substring instead of a collection element, use the + /// overload. + /// /// public SomeItemsConstraint Contains(object expected) { @@ -734,12 +744,15 @@ public SomeItemsConstraint Contains(object expected) } /// + /// /// Returns a new ContainsConstraint. This constraint /// will, in turn, make use of the appropriate second-level /// constraint, depending on the type of the actual argument. - /// This overload is only used if the item sought is a string, - /// since any other type implies that we are looking for a - /// collection member. + /// + /// + /// To search for a collection element instead of a substring, use the + /// overload. + /// /// public ContainsConstraint Contains(string expected) { @@ -798,7 +811,7 @@ public DictionaryContainsValueConstraint ContainValue(object expected) /// Returns a constraint that succeeds if the actual /// value contains the substring supplied as an argument. /// - [Obsolete("Deprecated, use Contains")] + [Obsolete("This method has been deprecated and will be removed in a future release. Please use Contains instead.")] public SubstringConstraint StringContaining(string expected) { return (SubstringConstraint)this.Append(new SubstringConstraint(expected)); @@ -808,7 +821,7 @@ public SubstringConstraint StringContaining(string expected) /// Returns a constraint that succeeds if the actual /// value contains the substring supplied as an argument. /// - [Obsolete("Deprecated, use Contains")] + [Obsolete("This method has been deprecated and will be removed in a future release. Please use Contains instead.")] public SubstringConstraint ContainsSubstring(string expected) { return (SubstringConstraint)this.Append(new SubstringConstraint(expected)); @@ -840,7 +853,7 @@ public StartsWithConstraint StartsWith(string expected) /// Returns a constraint that succeeds if the actual /// value starts with the substring supplied as an argument. /// - [Obsolete("Deprecated, use Does.StartWith or StartsWith")] + [Obsolete("This method has been deprecated and will be removed in a future release. Please use Does.StartWith or StartsWith instead.")] public StartsWithConstraint StringStarting(string expected) { return (StartsWithConstraint)this.Append(new StartsWithConstraint(expected)); @@ -872,7 +885,7 @@ public EndsWithConstraint EndsWith(string expected) /// Returns a constraint that succeeds if the actual /// value ends with the substring supplied as an argument. /// - [Obsolete("Deprecated, use Does.EndWith or EndsWith")] + [Obsolete("This method has been deprecated and will be removed in a future release. Please use Does.EndWith or EndsWith instead.")] public EndsWithConstraint StringEnding(string expected) { return (EndsWithConstraint)this.Append(new EndsWithConstraint(expected)); @@ -904,7 +917,7 @@ public RegexConstraint Matches(string pattern) /// Returns a constraint that succeeds if the actual /// value matches the regular expression supplied as an argument. /// - [Obsolete("Deprecated, use Does.Match or Matches")] + [Obsolete("This method has been deprecated and will be removed in a future release. Please use Does.Match or Matches instead.")] public RegexConstraint StringMatching(string pattern) { return (RegexConstraint)this.Append(new RegexConstraint(pattern)); diff --git a/src/NUnitFramework/framework/Constraints/ContainsConstraint.cs b/src/NUnitFramework/framework/Constraints/ContainsConstraint.cs index c6cefa9c57..3c294110b5 100644 --- a/src/NUnitFramework/framework/Constraints/ContainsConstraint.cs +++ b/src/NUnitFramework/framework/Constraints/ContainsConstraint.cs @@ -34,9 +34,9 @@ namespace NUnit.Framework.Constraints /// public class ContainsConstraint : Constraint { - readonly object _expected; - Constraint _realConstraint; - bool _ignoreCase; + private readonly object _expected; + private Constraint _realConstraint; + private bool _ignoreCase; /// /// Initializes a new instance of the class. @@ -53,9 +53,20 @@ public ContainsConstraint(object expected) /// public override string Description { - get { return _realConstraint != null ? - _realConstraint.Description : - "containing " + MsgUtils.FormatValue(_expected); } + get + { + if (_realConstraint != null) + { + return _realConstraint.Description; + } + + var description = "containing " + MsgUtils.FormatValue(_expected); + + if (_ignoreCase) + description += ", ignoring case"; + + return description; + } } /// @@ -81,7 +92,12 @@ public override ConstraintResult ApplyTo(TActual actual) _realConstraint = constraint; } else - _realConstraint = new SomeItemsConstraint(new EqualConstraint(_expected)); + { + var itemConstraint = new EqualConstraint(_expected); + if (_ignoreCase) + itemConstraint = itemConstraint.IgnoreCase; + _realConstraint = new SomeItemsConstraint(itemConstraint); + } return _realConstraint.ApplyTo(actual); } diff --git a/src/NUnitFramework/framework/Constraints/DelayedConstraint.cs b/src/NUnitFramework/framework/Constraints/DelayedConstraint.cs index 62e8b85d38..2932a90817 100644 --- a/src/NUnitFramework/framework/Constraints/DelayedConstraint.cs +++ b/src/NUnitFramework/framework/Constraints/DelayedConstraint.cs @@ -349,10 +349,8 @@ public override ConstraintResult ApplyTo(ref TActual actual) private static object InvokeDelegate(ActualValueDelegate del) { -#if ASYNC if (AsyncToSyncAdapter.IsAsyncOperation(del)) return AsyncToSyncAdapter.Await(() => del.Invoke()); -#endif return del(); } diff --git a/src/NUnitFramework/framework/Constraints/DictionaryContainsKeyConstraint.cs b/src/NUnitFramework/framework/Constraints/DictionaryContainsKeyConstraint.cs index 4374e2440a..43a9382aa5 100644 --- a/src/NUnitFramework/framework/Constraints/DictionaryContainsKeyConstraint.cs +++ b/src/NUnitFramework/framework/Constraints/DictionaryContainsKeyConstraint.cs @@ -8,10 +8,10 @@ // 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 @@ -38,7 +38,9 @@ namespace NUnit.Framework.Constraints /// public class DictionaryContainsKeyConstraint : CollectionItemsEqualConstraint { - private const string ObsoleteMessage = "DictionaryContainsKeyConstraint now uses the comparer which the dictionary is based on. To test using a comparer which the dictionary is not based on, use a collection constraint on the set of keys."; + private const string ComparerMemberObsoletionMessage = "This member has been deprecated and will be removed in a future release. " + + "To test using a comparer which the dictionary is not based on, use a collection constraint on the set of keys."; + private const string ContainsMethodName = "Contains"; private bool _isDeprecatedMode = false; @@ -52,7 +54,7 @@ public DictionaryContainsKeyConstraint(object expected) Expected = expected; } - /// + /// /// The display name of this Constraint for use by ToString(). /// The default value is the name of the constraint with /// trailing "Constraint" removed. Derived classes may set @@ -77,7 +79,7 @@ public override string Description /// /// Flag the constraint to ignore case and return self. /// - [Obsolete(ObsoleteMessage)] + [Obsolete(ComparerMemberObsoletionMessage)] public new CollectionItemsEqualConstraint IgnoreCase { get @@ -129,7 +131,7 @@ protected override bool Matches(IEnumerable collection) /// Flag the constraint to use the supplied predicate function /// /// The comparison function to use. - [Obsolete(ObsoleteMessage)] + [Obsolete(ComparerMemberObsoletionMessage)] public DictionaryContainsKeyConstraint Using(Func comparison) { // reverse the order of the arguments to match expectations of PredicateEqualityComparer @@ -144,7 +146,7 @@ protected override bool Matches(IEnumerable collection) /// Flag the constraint to use the supplied Comparison object. /// /// The Comparison object to use. - [Obsolete(ObsoleteMessage)] + [Obsolete(ComparerMemberObsoletionMessage)] public new CollectionItemsEqualConstraint Using(Comparison comparison) { _isDeprecatedMode = true; @@ -156,7 +158,7 @@ public new CollectionItemsEqualConstraint Using(Comparison comparison) /// Flag the constraint to use the supplied IComparer object. /// /// The IComparer object to use. - [Obsolete(ObsoleteMessage)] + [Obsolete(ComparerMemberObsoletionMessage)] public new CollectionItemsEqualConstraint Using(IComparer comparer) { _isDeprecatedMode = true; @@ -167,7 +169,7 @@ public new CollectionItemsEqualConstraint Using(IComparer comparer) /// Flag the constraint to use the supplied IComparer object. /// /// The IComparer object to use. - [Obsolete(ObsoleteMessage)] + [Obsolete(ComparerMemberObsoletionMessage)] public new CollectionItemsEqualConstraint Using(IComparer comparer) { _isDeprecatedMode = true; @@ -178,7 +180,7 @@ public new CollectionItemsEqualConstraint Using(IComparer comparer) /// Flag the constraint to use the supplied IEqualityComparer object. /// /// The IComparer object to use. - [Obsolete(ObsoleteMessage)] + [Obsolete(ComparerMemberObsoletionMessage)] public new CollectionItemsEqualConstraint Using(IEqualityComparer comparer) { _isDeprecatedMode = true; @@ -189,7 +191,7 @@ public new CollectionItemsEqualConstraint Using(IEqualityComparer comparer) /// Flag the constraint to use the supplied IEqualityComparer object. /// /// The IComparer object to use. - [Obsolete(ObsoleteMessage)] + [Obsolete(ComparerMemberObsoletionMessage)] public new CollectionItemsEqualConstraint Using(IEqualityComparer comparer) { _isDeprecatedMode = true; @@ -200,7 +202,7 @@ public new CollectionItemsEqualConstraint Using(IEqualityComparer comparer /// Flag the constraint to use the supplied boolean-returning delegate. /// /// The supplied boolean-returning delegate to use. - [Obsolete(ObsoleteMessage)] + [Obsolete(ComparerMemberObsoletionMessage)] public new CollectionItemsEqualConstraint Using(Func comparer) { _isDeprecatedMode = true; diff --git a/src/NUnitFramework/framework/Constraints/EqualConstraintResult.cs b/src/NUnitFramework/framework/Constraints/EqualConstraintResult.cs index 1cff796d48..2b89096b93 100644 --- a/src/NUnitFramework/framework/Constraints/EqualConstraintResult.cs +++ b/src/NUnitFramework/framework/Constraints/EqualConstraintResult.cs @@ -269,16 +269,14 @@ private void DisplayEnumerableDifferences(MessageWriter writer, IEnumerable expe failurePoint.ExpectedValue, failurePoint.ActualValue, ++depth); - //else if (failurePoint.ActualHasData) - //{ - // writer.Write(" Extra: "); - // writer.WriteCollectionElements(actual, failurePoint.Position, 3); - //} - //else - //{ - // writer.Write(" Missing: "); - // writer.WriteCollectionElements(expected, failurePoint.Position, 3); - //} + else if (failurePoint.ActualHasData) + { + writer.Write($" Extra: < {MsgUtils.FormatValue(failurePoint.ActualValue)}, ... >"); + } + else + { + writer.Write($" Missing: < {MsgUtils.FormatValue(failurePoint.ExpectedValue)}, ... >"); + } } } diff --git a/src/NUnitFramework/framework/Constraints/FileExistsConstraint.cs b/src/NUnitFramework/framework/Constraints/FileExistsConstraint.cs index b632aa7e3a..7c1c84174e 100644 --- a/src/NUnitFramework/framework/Constraints/FileExistsConstraint.cs +++ b/src/NUnitFramework/framework/Constraints/FileExistsConstraint.cs @@ -1,4 +1,4 @@ -// *********************************************************************** +// *********************************************************************** // Copyright (c) 2014 Charlie Poole, Rob Prouse // // Permission is hereby granted, free of charge, to any person obtaining @@ -28,7 +28,8 @@ namespace NUnit.Framework.Constraints /// /// FileExistsConstraint is used to determine if a file exists /// - [Obsolete("FileExistsConstraint is deprecated, please use FileOrDirectoryExistsConstraint instead.")] + [Obsolete("The FileExistsConstraint class has been deprecated and will be removed in a future release. " + + "Please use " + nameof(FileOrDirectoryExistsConstraint) + " instead.")] public class FileExistsConstraint : FileOrDirectoryExistsConstraint { /// diff --git a/src/NUnitFramework/framework/Constraints/FloatingPointNumerics.cs b/src/NUnitFramework/framework/Constraints/FloatingPointNumerics.cs index d8821db599..d653fd5cce 100644 --- a/src/NUnitFramework/framework/Constraints/FloatingPointNumerics.cs +++ b/src/NUnitFramework/framework/Constraints/FloatingPointNumerics.cs @@ -30,7 +30,7 @@ namespace NUnit.Framework.Constraints /// /// /// The floating point comparison code is based on this excellent article: - /// http://www.cygnus-software.com/papers/comparingfloats/comparingfloats.htm + /// https://randomascii.wordpress.com/2012/02/25/comparing-floating-point-numbers-2012-edition/ /// /// /// "ULP" means Unit in the Last Place and in the context of this library refers to diff --git a/src/NUnitFramework/framework/Constraints/GreaterThanConstraint.cs b/src/NUnitFramework/framework/Constraints/GreaterThanConstraint.cs index a0a0471fe7..298dd4f4e5 100644 --- a/src/NUnitFramework/framework/Constraints/GreaterThanConstraint.cs +++ b/src/NUnitFramework/framework/Constraints/GreaterThanConstraint.cs @@ -21,8 +21,6 @@ // WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. // *********************************************************************** -using System; - namespace NUnit.Framework.Constraints { /// @@ -30,13 +28,27 @@ namespace NUnit.Framework.Constraints /// public class GreaterThanConstraint : ComparisonConstraint { + private string _description; + /// /// Initializes a new instance of the class. /// /// The expected value. - public GreaterThanConstraint(object expected) : base(expected) + public GreaterThanConstraint(object expected) : base(expected) {} + + /// + /// The Description of what this constraint tests, for + /// use in messages and in the ConstraintResult. + /// + public override string Description { - Description = "greater than " + MsgUtils.FormatValue(expected); + get + { + if (_description == null) + _description = DefaultDescription("greater than "); + + return _description; + } } /// @@ -47,4 +59,4 @@ protected override bool PerformComparison(ComparisonAdapter comparer, object act return comparer.Compare(actual, tolerance.ApplyToValue(expected).LowerBound) > 0; } } -} \ No newline at end of file +} diff --git a/src/NUnitFramework/framework/Constraints/GreaterThanOrEqualConstraint.cs b/src/NUnitFramework/framework/Constraints/GreaterThanOrEqualConstraint.cs index 10d4af55d8..6ce7f6bb55 100644 --- a/src/NUnitFramework/framework/Constraints/GreaterThanOrEqualConstraint.cs +++ b/src/NUnitFramework/framework/Constraints/GreaterThanOrEqualConstraint.cs @@ -28,13 +28,27 @@ namespace NUnit.Framework.Constraints /// public class GreaterThanOrEqualConstraint : ComparisonConstraint { + private string _description; + /// /// Initializes a new instance of the class. /// /// The expected value. - public GreaterThanOrEqualConstraint(object expected) : base(expected) + public GreaterThanOrEqualConstraint(object expected) : base(expected) {} + + /// + /// The Description of what this constraint tests, for + /// use in messages and in the ConstraintResult. + /// + public override string Description { - Description = "greater than or equal to " + MsgUtils.FormatValue(expected); + get + { + if (_description == null) + _description = DefaultDescription("greater than or equal to "); + + return _description; + } } /// @@ -45,4 +59,4 @@ protected override bool PerformComparison(ComparisonAdapter comparer, object act return comparer.Compare(actual, tolerance.ApplyToValue(expected).LowerBound) >= 0; } } -} \ No newline at end of file +} diff --git a/src/NUnitFramework/framework/Constraints/LessThanConstraint.cs b/src/NUnitFramework/framework/Constraints/LessThanConstraint.cs index b8820abb76..3dd09588fc 100644 --- a/src/NUnitFramework/framework/Constraints/LessThanConstraint.cs +++ b/src/NUnitFramework/framework/Constraints/LessThanConstraint.cs @@ -28,13 +28,27 @@ namespace NUnit.Framework.Constraints /// public class LessThanConstraint : ComparisonConstraint { + private string _description; + /// /// Initializes a new instance of the class. /// /// The expected value. - public LessThanConstraint(object expected) : base(expected) + public LessThanConstraint(object expected) : base(expected) {} + + /// + /// The Description of what this constraint tests, for + /// use in messages and in the ConstraintResult. + /// + public override string Description { - Description = "less than " + MsgUtils.FormatValue(expected); + get + { + if (_description == null) + _description = DefaultDescription("less than "); + + return _description; + } } /// @@ -45,4 +59,4 @@ protected override bool PerformComparison(ComparisonAdapter comparer, object act return comparer.Compare(actual, tolerance.ApplyToValue(expected).UpperBound) < 0; } } -} \ No newline at end of file +} diff --git a/src/NUnitFramework/framework/Constraints/LessThanOrEqualConstraint.cs b/src/NUnitFramework/framework/Constraints/LessThanOrEqualConstraint.cs index 9f26555e26..ec36f3a092 100644 --- a/src/NUnitFramework/framework/Constraints/LessThanOrEqualConstraint.cs +++ b/src/NUnitFramework/framework/Constraints/LessThanOrEqualConstraint.cs @@ -28,13 +28,27 @@ namespace NUnit.Framework.Constraints /// public class LessThanOrEqualConstraint : ComparisonConstraint { + private string _description; + /// /// Initializes a new instance of the class. /// /// The expected value. - public LessThanOrEqualConstraint(object expected) : base(expected) + public LessThanOrEqualConstraint(object expected) : base(expected) {} + + /// + /// The Description of what this constraint tests, for + /// use in messages and in the ConstraintResult. + /// + public override string Description { - Description = "less than or equal to " + MsgUtils.FormatValue(expected); + get + { + if (_description == null) + _description = DefaultDescription("less than or equal to "); + + return _description; + } } /// @@ -45,4 +59,4 @@ protected override bool PerformComparison(ComparisonAdapter comparer, object act return comparer.Compare(actual, tolerance.ApplyToValue(expected).UpperBound) <= 0; } } -} \ No newline at end of file +} diff --git a/src/NUnitFramework/framework/Constraints/NUnitEqualityComparer.cs b/src/NUnitFramework/framework/Constraints/NUnitEqualityComparer.cs index 531658ec36..411b296936 100644 --- a/src/NUnitFramework/framework/Constraints/NUnitEqualityComparer.cs +++ b/src/NUnitFramework/framework/Constraints/NUnitEqualityComparer.cs @@ -67,10 +67,10 @@ public sealed class NUnitEqualityComparer /// public NUnitEqualityComparer() { - EnumerablesComparer _enumerablesComparer = new EnumerablesComparer(this); + var enumerablesComparer = new EnumerablesComparer(this); _comparers = new List { - new ArraysComparer(this, _enumerablesComparer), + new ArraysComparer(this, enumerablesComparer), new DictionariesComparer(this), new DictionaryEntriesComparer(this), new KeyValuePairsComparer(this), @@ -81,10 +81,10 @@ public NUnitEqualityComparer() new NumericsComparer(), new DateTimeOffsetsComparer(this), new TimeSpanToleranceComparer(), - new EquatablesComparer(this), new TupleComparer(this), new ValueTupleComparer(this), - _enumerablesComparer + new EquatablesComparer(this), + enumerablesComparer }; } @@ -93,7 +93,7 @@ public NUnitEqualityComparer() /// /// Returns the default NUnitEqualityComparer /// - [Obsolete("Deprecated. Use the default constructor instead.")] + [Obsolete("This property has been deprecated and will be removed in a future release. Please use 'new NUnitEqualityComparer()' instead.")] public static NUnitEqualityComparer Default { get { return new NUnitEqualityComparer(); } @@ -128,9 +128,6 @@ public IList ExternalComparers get { return externalComparers; } } - // TODO: Define some sort of FailurePoint struct or otherwise - // eliminate the type-unsafeness of the current approach - /// /// Gets the list of failure points for the last Match performed. /// The list consists of objects to be interpreted by the caller. diff --git a/src/NUnitFramework/framework/Constraints/Operators/ConstraintOperator.cs b/src/NUnitFramework/framework/Constraints/Operators/ConstraintOperator.cs index fd88fcaf62..e11a00dee8 100644 --- a/src/NUnitFramework/framework/Constraints/Operators/ConstraintOperator.cs +++ b/src/NUnitFramework/framework/Constraints/Operators/ConstraintOperator.cs @@ -41,13 +41,21 @@ public abstract class ConstraintOperator /// The precedence value used when the operator /// is about to be pushed to the stack. /// +#pragma warning disable IDE1006 + // ReSharper disable once InconsistentNaming + // Disregarding naming convention for back-compat protected int left_precedence; +#pragma warning restore IDE1006 /// /// The precedence value used when the operator /// is on the top of the stack. /// +#pragma warning disable IDE1006 + // ReSharper disable once InconsistentNaming + // Disregarding naming convention for back-compat protected int right_precedence; +#pragma warning restore IDE1006 /// /// The syntax element preceding this operator @@ -93,4 +101,4 @@ public virtual int RightPrecedence /// public abstract void Reduce(ConstraintBuilder.ConstraintStack stack); } -} \ No newline at end of file +} diff --git a/src/NUnitFramework/framework/Constraints/StringConstraint.cs b/src/NUnitFramework/framework/Constraints/StringConstraint.cs index 539eaf1ec2..36d45c1812 100644 --- a/src/NUnitFramework/framework/Constraints/StringConstraint.cs +++ b/src/NUnitFramework/framework/Constraints/StringConstraint.cs @@ -35,17 +35,29 @@ public abstract class StringConstraint : Constraint /// /// The expected value /// +#pragma warning disable IDE1006 + // ReSharper disable once InconsistentNaming + // Disregarding naming convention for back-compat protected string expected; +#pragma warning restore IDE1006 /// /// Indicates whether tests should be case-insensitive /// +#pragma warning disable IDE1006 + // ReSharper disable once InconsistentNaming + // Disregarding naming convention for back-compat protected bool caseInsensitive; +#pragma warning restore IDE1006 /// /// Description of this constraint /// +#pragma warning disable IDE1006 + // ReSharper disable once InconsistentNaming + // Disregarding naming convention for back-compat protected string descriptionText; +#pragma warning restore IDE1006 /// /// The Description of what this constraint tests, for diff --git a/src/NUnitFramework/framework/Constraints/ThrowsConstraint.cs b/src/NUnitFramework/framework/Constraints/ThrowsConstraint.cs index 5c8f9562bf..862f6b8e8c 100644 --- a/src/NUnitFramework/framework/Constraints/ThrowsConstraint.cs +++ b/src/NUnitFramework/framework/Constraints/ThrowsConstraint.cs @@ -69,23 +69,9 @@ public override string Description /// True if an exception is thrown and the constraint succeeds, otherwise false public override ConstraintResult ApplyTo(TActual actual) { - //TestDelegate code = actual as TestDelegate; - //if (code == null) - // throw new ArgumentException( - // string.Format("The actual value must be a TestDelegate but was {0}", actual.GetType().Name), "actual"); + var @delegate = ConstraintUtils.RequireActual(actual, nameof(actual)); - //caughtException = null; - - //try - //{ - // code(); - //} - //catch (Exception ex) - //{ - // caughtException = ex; - //} - - caughtException = ExceptionInterceptor.Intercept(actual); + caughtException = ExceptionHelper.RecordException(@delegate, nameof(actual)); return new ThrowsConstraintResult( this, @@ -103,9 +89,7 @@ public override ConstraintResult ApplyTo(TActual actual) /// public override ConstraintResult ApplyTo(ActualValueDelegate del) { - //TestDelegate testDelegate = new TestDelegate(delegate { del(); }); - //return ApplyTo((object)testDelegate); - return ApplyTo(new GenericInvocationDescriptor(del)); + return ApplyTo((Delegate)del); } #endregion @@ -145,134 +129,5 @@ public override void WriteActualValueTo(MessageWriter writer) } #endregion - - #region ExceptionInterceptor - - internal sealed class ExceptionInterceptor - { - private ExceptionInterceptor() { } - - internal static Exception Intercept(object invocation) - { - var invocationDescriptor = GetInvocationDescriptor(invocation); - -#if ASYNC - if (AsyncToSyncAdapter.IsAsyncOperation(invocationDescriptor.Delegate)) - { - try - { - AsyncToSyncAdapter.Await(invocationDescriptor.Invoke); - return null; - } - catch (Exception ex) - { - return ex; - } - } -#endif - { - using (new TestExecutionContext.IsolatedContext()) - { - try - { - invocationDescriptor.Invoke(); - return null; - } - catch (Exception ex) - { - return ex; - } - } - } - } - - private static IInvocationDescriptor GetInvocationDescriptor(object actual) - { - var invocationDescriptor = actual as IInvocationDescriptor; - - if (invocationDescriptor == null) - { - var testDelegate = actual as TestDelegate; - - if (testDelegate != null) - { - Guard.ArgumentNotAsyncVoid(testDelegate, nameof(actual)); - invocationDescriptor = new VoidInvocationDescriptor(testDelegate); - } - -#if ASYNC - else - { - var asyncTestDelegate = actual as AsyncTestDelegate; - if (asyncTestDelegate != null) - { - invocationDescriptor = new GenericInvocationDescriptor(() => asyncTestDelegate()); - } - } -#endif - } - if (invocationDescriptor == null) - throw new ArgumentException( - String.Format( - "The actual value must be a TestDelegate or AsyncTestDelegate but was {0}", - actual.GetType().Name), - nameof(actual)); - - return invocationDescriptor; - } - } - -#endregion - -#region InvocationDescriptor - - internal sealed class GenericInvocationDescriptor : IInvocationDescriptor - { - private readonly ActualValueDelegate _del; - - public GenericInvocationDescriptor(ActualValueDelegate del) - { - _del = del; - } - - public object Invoke() - { - return _del(); - } - - public Delegate Delegate - { - get { return _del; } - } - } - - private interface IInvocationDescriptor - { - Delegate Delegate { get; } - object Invoke(); - } - - private sealed class VoidInvocationDescriptor : IInvocationDescriptor - { - private readonly TestDelegate _del; - - public VoidInvocationDescriptor(TestDelegate del) - { - _del = del; - } - - public object Invoke() - { - _del(); - return null; - } - - public Delegate Delegate - { - get { return _del; } - } - } - -#endregion } } diff --git a/src/NUnitFramework/framework/Constraints/ThrowsExceptionConstraint.cs b/src/NUnitFramework/framework/Constraints/ThrowsExceptionConstraint.cs index d82c93e80a..9c57929bf9 100644 --- a/src/NUnitFramework/framework/Constraints/ThrowsExceptionConstraint.cs +++ b/src/NUnitFramework/framework/Constraints/ThrowsExceptionConstraint.cs @@ -22,11 +22,8 @@ // *********************************************************************** using System; - -#if ASYNC -using System.Threading.Tasks; +using System.Reflection; using NUnit.Framework.Internal; -#endif namespace NUnit.Framework.Constraints { @@ -52,41 +49,11 @@ public override string Description /// True if an exception is thrown, otherwise false public override ConstraintResult ApplyTo(TActual actual) { - TestDelegate code = actual as TestDelegate; - Exception caughtException = null; + var @delegate = ConstraintUtils.RequireActual(actual, nameof(actual)); - if (code != null) - { - try - { - code(); - } - catch (Exception ex) - { - caughtException = ex; - } - } -#if ASYNC - AsyncTestDelegate asyncCode = actual as AsyncTestDelegate; - if (asyncCode != null) - { - try - { - AsyncToSyncAdapter.Await(asyncCode.Invoke); - } - catch (Exception ex) - { - caughtException = ex; - } - } - if (code == null && asyncCode == null) -#else - else -#endif - { - throw new ArgumentException(string.Format("The actual value must be a TestDelegate or AsyncTestDelegate but was {0}", actual.GetType().Name), nameof(actual)); - } - return new ThrowsExceptionConstraintResult(this, caughtException); + var exception = ExceptionHelper.RecordException(@delegate, nameof(actual)); + + return new ThrowsExceptionConstraintResult(this, exception); } /// @@ -97,10 +64,7 @@ public override ConstraintResult ApplyTo(TActual actual) /// public override ConstraintResult ApplyTo(ActualValueDelegate del) { -#if ASYNC - if (typeof(TActual) == typeof(Task)) return ApplyTo(new AsyncTestDelegate(() => (Task)(object)del.Invoke())); -#endif - return ApplyTo(new TestDelegate(() => del.Invoke())); + return ApplyTo((Delegate)del); } #region Nested Result Class diff --git a/src/NUnitFramework/framework/Constraints/ThrowsNothingConstraint.cs b/src/NUnitFramework/framework/Constraints/ThrowsNothingConstraint.cs index 600bf35196..90fc0d7de5 100644 --- a/src/NUnitFramework/framework/Constraints/ThrowsNothingConstraint.cs +++ b/src/NUnitFramework/framework/Constraints/ThrowsNothingConstraint.cs @@ -22,6 +22,7 @@ // *********************************************************************** using System; +using NUnit.Framework.Internal; namespace NUnit.Framework.Constraints { @@ -49,7 +50,10 @@ public override string Description /// True if no exception is thrown, otherwise false public override ConstraintResult ApplyTo(TActual actual) { - caughtException = ThrowsConstraint.ExceptionInterceptor.Intercept(actual); + var @delegate = ConstraintUtils.RequireActual(actual, nameof(actual)); + + caughtException = ExceptionHelper.RecordException(@delegate, nameof(actual)); + return new ConstraintResult(this, caughtException, caughtException == null); } @@ -63,7 +67,7 @@ public override ConstraintResult ApplyTo(TActual actual) /// A ConstraintResult public override ConstraintResult ApplyTo(ActualValueDelegate del) { - return ApplyTo(new ThrowsConstraint.GenericInvocationDescriptor(del)); + return ApplyTo((Delegate)del); } } -} \ No newline at end of file +} diff --git a/src/NUnitFramework/framework/Constraints/TypeConstraint.cs b/src/NUnitFramework/framework/Constraints/TypeConstraint.cs index f7ffa23a2a..5e3debe8d5 100644 --- a/src/NUnitFramework/framework/Constraints/TypeConstraint.cs +++ b/src/NUnitFramework/framework/Constraints/TypeConstraint.cs @@ -34,12 +34,20 @@ public abstract class TypeConstraint : Constraint /// /// The expected Type used by the constraint /// +#pragma warning disable IDE1006 + // ReSharper disable once InconsistentNaming + // Disregarding naming convention for back-compat protected Type expectedType; +#pragma warning restore IDE1006 /// /// The type of the actual argument to which the constraint was applied /// +#pragma warning disable IDE1006 + // ReSharper disable once InconsistentNaming + // Disregarding naming convention for back-compat protected Type actualType; +#pragma warning restore IDE1006 /// /// Construct a TypeConstraint for a given Type @@ -75,4 +83,4 @@ public override ConstraintResult ApplyTo(TActual actual) /// True if the constraint succeeds, otherwise false. protected abstract bool Matches(object actual); } -} \ No newline at end of file +} diff --git a/src/NUnitFramework/framework/Constraints/UniqueItemsConstraint.cs b/src/NUnitFramework/framework/Constraints/UniqueItemsConstraint.cs index ecf896e7a1..5723a58aa6 100644 --- a/src/NUnitFramework/framework/Constraints/UniqueItemsConstraint.cs +++ b/src/NUnitFramework/framework/Constraints/UniqueItemsConstraint.cs @@ -164,7 +164,7 @@ private Type GetGenericTypeArgument(IEnumerable actual) { if (type.FullName.StartsWith("System.Collections.Generic.IEnumerable`1")) { -#if NET20 || NET35 || NET40 +#if NET35 || NET40 return type.GetGenericArguments()[0]; #else return type.GenericTypeArguments[0]; diff --git a/src/NUnitFramework/framework/DirectoryAssert.cs b/src/NUnitFramework/framework/DirectoryAssert.cs index fc57050211..049e4d1853 100644 --- a/src/NUnitFramework/framework/DirectoryAssert.cs +++ b/src/NUnitFramework/framework/DirectoryAssert.cs @@ -1,4 +1,4 @@ -// *********************************************************************** +// *********************************************************************** // Copyright (c) 2006 Charlie Poole, Rob Prouse // // Permission is hereby granted, free of charge, to any person obtaining @@ -8,10 +8,10 @@ // 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 @@ -37,7 +37,7 @@ public static class DirectoryAssert /// /// DO NOT USE! Use DirectoryAssert.AreEqual(...) instead. - /// The Equals method throws an InvalidOperationException. This is done + /// The Equals method throws an InvalidOperationException. This is done /// to make sure there is no mistake by calling this function. /// /// @@ -45,12 +45,12 @@ public static class DirectoryAssert [EditorBrowsable(EditorBrowsableState.Never)] public static new bool Equals(object a, object b) { - throw new InvalidOperationException("DirectoryAssert.Equals should not be used for Assertions, use DirectoryAssert.AreEqual(...) instead."); + throw new InvalidOperationException("DirectoryAssert.Equals should not be used. Use DirectoryAssert.AreEqual instead."); } /// /// DO NOT USE! - /// The ReferenceEquals method throws an InvalidOperationException. This is done + /// The ReferenceEquals method throws an InvalidOperationException. This is done /// to make sure there is no mistake by calling this function. /// /// @@ -58,7 +58,7 @@ public static new bool Equals(object a, object b) [EditorBrowsable(EditorBrowsableState.Never)] public static new void ReferenceEquals(object a, object b) { - throw new InvalidOperationException("DirectoryAssert.ReferenceEquals should not be used for Assertions."); + throw new InvalidOperationException("DirectoryAssert.ReferenceEquals should not be used."); } #endregion diff --git a/src/NUnitFramework/framework/FileAssert.cs b/src/NUnitFramework/framework/FileAssert.cs index 6d5ddcb523..db803fd897 100644 --- a/src/NUnitFramework/framework/FileAssert.cs +++ b/src/NUnitFramework/framework/FileAssert.cs @@ -8,10 +8,10 @@ // 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 @@ -37,7 +37,7 @@ public static class FileAssert /// /// DO NOT USE! Use FileAssert.AreEqual(...) instead. - /// The Equals method throws an InvalidOperationException. This is done + /// The Equals method throws an InvalidOperationException. This is done /// to make sure there is no mistake by calling this function. /// /// @@ -45,12 +45,12 @@ public static class FileAssert [EditorBrowsable(EditorBrowsableState.Never)] public static new bool Equals(object a, object b) { - throw new InvalidOperationException("FileAssert.Equals should not be used for Assertions, use FileAssert.AreEqual(...) instead."); + throw new InvalidOperationException("FileAssert.Equals should not be used. Use FileAssert.AreEqual instead."); } /// /// DO NOT USE! - /// The ReferenceEquals method throws an InvalidOperationException. This is done + /// The ReferenceEquals method throws an InvalidOperationException. This is done /// to make sure there is no mistake by calling this function. /// /// @@ -58,7 +58,7 @@ public static new bool Equals(object a, object b) [EditorBrowsable(EditorBrowsableState.Never)] public static new void ReferenceEquals(object a, object b) { - throw new InvalidOperationException("FileAssert.ReferenceEquals should not be used for Assertions."); + throw new InvalidOperationException("FileAssert.ReferenceEquals should not be used."); } #endregion diff --git a/src/NUnitFramework/framework/Interfaces/TNode.cs b/src/NUnitFramework/framework/Interfaces/TNode.cs index ea69a2f914..8852c7dfea 100644 --- a/src/NUnitFramework/framework/Interfaces/TNode.cs +++ b/src/NUnitFramework/framework/Interfaces/TNode.cs @@ -22,6 +22,7 @@ // *********************************************************************** using System; +using System.Text; using System.Text.RegularExpressions; using System.Xml; @@ -37,6 +38,8 @@ namespace NUnit.Framework.Interfaces /// System.Xml.Linq.XElement, providing a minimal set of methods /// for operating on the XML in a platform-independent manner. /// + // ReSharper disable once InconsistentNaming + // Disregarding naming convention for back-compat public class TNode { #region Constructors @@ -318,15 +321,69 @@ private static NodeList ApplySelection(NodeList nodeList, string xpath) : resultNodes; } - private static readonly Regex InvalidXmlCharactersRegex = new Regex("[^\u0009\u000a\u000d\u0020-\ufffd]|([\ud800-\udbff](?![\udc00-\udfff]))|((? 0x20 && c < 0x7F) + { + // ASCII characters - break quickly for these + if (builder != null) + builder.Append(c); + } + // From the XML specification: https://www.w3.org/TR/xml/#charsets + // Char ::= #x9 | #xA | #xD | [#x20-#xD7FF] | [#xE000-#xFFFD] | [#x10000-#x10FFFF] + // Any Unicode character, excluding the surrogate blocks, FFFE, and FFFF. + else if (!(0x0 <= c && c <= 0x8) && + c != 0xB && + c != 0xC && + !(0xE <= c && c <= 0x1F) && + !(0x7F <= c && c <= 0x84) && + !(0x86 <= c && c <= 0x9F) && + !(0xD800 <= c && c <= 0xDFFF) && + c != 0xFFFE && + c != 0xFFFF) + { + if (builder != null) + builder.Append(c); + } + // Also check if the char is actually a high/low surogate pair of two characters. + // If it is, then it is a valid XML character (from above based on the surrogate blocks). + else if (char.IsHighSurrogate(c) && + i + 1 != str.Length && + char.IsLowSurrogate(str[i + 1])) + { + if (builder != null) + { + builder.Append(c); + builder.Append(str[i + 1]); + } + i++; + } + else + { + // We keep the builder null so that we don't allocate a string + // when doing this conversion until we encounter a unicode character. + // Then, we allocate the rest of the string and escape the invalid + // character. + if (builder == null) + { + builder = new StringBuilder(); + for (int index = 0; index < i; index++) + builder.Append(str[index]); + } + builder.Append(CharToUnicodeSequence(c)); + } + } - return InvalidXmlCharactersRegex.Replace(str, match => CharToUnicodeSequence(match.Value[0])); + if (builder != null) + return builder.ToString(); + else + return str; } private static string CharToUnicodeSequence(char symbol) diff --git a/src/NUnitFramework/framework/Internal/AsyncToSyncAdapter.cs b/src/NUnitFramework/framework/Internal/AsyncToSyncAdapter.cs index 749acaf53a..678458bac9 100644 --- a/src/NUnitFramework/framework/Internal/AsyncToSyncAdapter.cs +++ b/src/NUnitFramework/framework/Internal/AsyncToSyncAdapter.cs @@ -22,7 +22,6 @@ // *********************************************************************** using System; -using System.Collections.Generic; using System.Linq; using System.Reflection; using System.Security; @@ -35,8 +34,8 @@ internal static class AsyncToSyncAdapter { public static bool IsAsyncOperation(MethodInfo method) { - return IsTaskType(method.ReturnType) || - method.GetCustomAttributes(false).Any(attr => attr.GetType().FullName == "System.Runtime.CompilerServices.AsyncStateMachineAttribute"); + return AwaitAdapter.IsAwaitable(method.ReturnType) + || method.GetCustomAttributes(false).Any(attr => attr.GetType().FullName == "System.Runtime.CompilerServices.AsyncStateMachineAttribute"); } public static bool IsAsyncOperation(Delegate @delegate) @@ -44,70 +43,22 @@ public static bool IsAsyncOperation(Delegate @delegate) return IsAsyncOperation(@delegate.GetMethodInfo()); } - private static bool IsTaskType(Type type) - { - for (; type != null; type = type.GetTypeInfo().BaseType) - { - if (type.GetTypeInfo().IsGenericType - ? type.GetGenericTypeDefinition().FullName == "System.Threading.Tasks.Task`1" - : type.FullName == "System.Threading.Tasks.Task") - { - return true; - } - } - - return false; - } - -#if ASYNC - private const string TaskWaitMethod = "Wait"; - private const string TaskResultProperty = "Result"; - private const string VoidTaskResultType = "VoidTaskResult"; - private const string SystemAggregateException = "System.AggregateException"; - private const string InnerExceptionsProperty = "InnerExceptions"; - private const BindingFlags TaskResultPropertyBindingFlags = BindingFlags.Instance | BindingFlags.Public; - public static object Await(Func invoke) { Guard.ArgumentNotNull(invoke, nameof(invoke)); - object invocationResult; using (InitializeExecutionEnvironment()) { - invocationResult = invoke.Invoke(); - if (invocationResult == null || !IsTaskType(invocationResult.GetType())) - throw new InvalidOperationException("The delegate did not return a Task."); // General awaitable support coming soon. - - var awaitAdapter = AwaitAdapter.FromAwaitable(invocationResult); + var awaitAdapter = AwaitAdapter.FromAwaitable(invoke.Invoke()); if (!awaitAdapter.IsCompleted) { var waitStrategy = MessagePumpStrategy.FromCurrentSynchronizationContext(); waitStrategy.WaitForCompletion(awaitAdapter); } - } - // Future: instead of Wait(), use GetAwaiter() to check awaiter.IsCompleted above - // and use awaiter.OnCompleted/awaiter.GetResult below. - // (Implement a ReflectionAwaitAdapter) - try - { - invocationResult.GetType().GetMethod(TaskWaitMethod, new Type[0]).Invoke(invocationResult, null); + return awaitAdapter.GetResult(); } - catch (TargetInvocationException e) - { - IList innerExceptions = GetAllExceptions(e.InnerException); - ExceptionHelper.Rethrow(innerExceptions[0]); - } - var genericArguments = invocationResult.GetType().GetGenericArguments(); - if (genericArguments.Length == 1 && genericArguments[0].Name == VoidTaskResultType) - { - return null; - } - - PropertyInfo taskResultProperty = invocationResult.GetType().GetProperty(TaskResultProperty, TaskResultPropertyBindingFlags); - - return taskResultProperty != null ? taskResultProperty.GetValue(invocationResult, null) : invocationResult; } private static IDisposable InitializeExecutionEnvironment() @@ -118,7 +69,9 @@ private static IDisposable InitializeExecutionEnvironment() var context = SynchronizationContext.Current; if (context == null || context.GetType() == typeof(SynchronizationContext)) { - var singleThreadedContext = new SingleThreadedTestSynchronizationContext(); + var singleThreadedContext = new SingleThreadedTestSynchronizationContext( + shutdownTimeout: TimeSpan.FromSeconds(10)); + SetSynchronizationContext(singleThreadedContext); return On.Dispose(() => @@ -137,14 +90,5 @@ private static void SetSynchronizationContext(SynchronizationContext syncContext { SynchronizationContext.SetSynchronizationContext(syncContext); } - - private static IList GetAllExceptions(Exception exception) - { - if (SystemAggregateException.Equals(exception.GetType().FullName)) - return (IList)exception.GetType().GetProperty(InnerExceptionsProperty).GetValue(exception, null); - - return new Exception[] { exception }; - } -#endif } } diff --git a/src/NUnitFramework/framework/Internal/AwaitAdapter.cs b/src/NUnitFramework/framework/Internal/AwaitAdapter.cs index b76e6f2858..0517a6c47e 100644 --- a/src/NUnitFramework/framework/Internal/AwaitAdapter.cs +++ b/src/NUnitFramework/framework/Internal/AwaitAdapter.cs @@ -21,11 +21,7 @@ // WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. // *********************************************************************** -#if ASYNC using System; -using System.Runtime.CompilerServices; -using System.Security; -using System.Threading.Tasks; namespace NUnit.Framework.Internal { @@ -34,81 +30,47 @@ internal abstract class AwaitAdapter public abstract bool IsCompleted { get; } public abstract void OnCompleted(Action action); public abstract void BlockUntilCompleted(); + public abstract object GetResult(); - public static AwaitAdapter FromAwaitable(object awaitable) + public static bool IsAwaitable(Type awaitableType) { - if (awaitable == null) throw new ArgumentNullException(nameof(awaitable)); - - var task = awaitable as Task; - if (task == null) - throw new NotImplementedException("Proper awaitable implementation to follow."); - -#if NET40 - // TODO: use the general reflection-based awaiter if net40 build is running against a newer BCL - return new Net40BclTaskAwaitAdapter(task); -#else - return new TaskAwaitAdapter(task); -#endif + return CSharpPatternBasedAwaitAdapter.IsAwaitable(awaitableType); } -#if NET40 - private sealed class Net40BclTaskAwaitAdapter : AwaitAdapter + public static Type GetResultType(Type awaitableType) { - private readonly Task _task; - - public Net40BclTaskAwaitAdapter(Task task) - { - _task = task; - } - - public override bool IsCompleted => _task.IsCompleted; - - public override void OnCompleted(Action action) - { - if (action == null) return; - - // Normally we would call TaskAwaiter.UnsafeOnCompleted (https://source.dot.net/#System.Private.CoreLib/src/System/Runtime/CompilerServices/TaskAwaiter.cs) - // We will have to polyfill on top of the TPL API. - // Compare TaskAwaiter.OnCompletedInternal from Microsoft.Threading.Tasks.dll in Microsoft.Bcl.Async.nupkg. - - _task.ContinueWith(_ => action.Invoke(), TaskScheduler.FromCurrentSynchronizationContext()); - } - - public override void BlockUntilCompleted() - { - // Normally we would call TaskAwaiter.GetResult (https://source.dot.net/#System.Private.CoreLib/src/System/Runtime/CompilerServices/TaskAwaiter.cs) - // We will have to polyfill on top of the TPL API. - // Compare TaskAwaiter.ValidateEnd from Microsoft.Threading.Tasks.dll in Microsoft.Bcl.Async.nupkg. - - try - { - _task.Wait(); // Wait even if the task is completed so that an exception is thrown for cancellation or failure. - } - catch (AggregateException ex) when (ex.InnerExceptions.Count == 1) // Task.Wait wraps every exception - { - ExceptionHelper.Rethrow(ex.InnerException); - } - } + return CSharpPatternBasedAwaitAdapter.GetResultType(awaitableType); } -#else - private sealed class TaskAwaitAdapter : AwaitAdapter - { - private readonly TaskAwaiter _awaiter; - public TaskAwaitAdapter(Task task) - { - _awaiter = task.GetAwaiter(); - } + public static AwaitAdapter FromAwaitable(object awaitable) + { + if (awaitable == null) + throw new InvalidOperationException("A null reference cannot be awaited."); + +#if !(NET35 || NET40) + // TaskAwaitAdapter is more efficient because it can rely on Task’s + // special quality of blocking until complete in GetResult. + // As long as the pattern-based adapters are reflection-based, this + // is much more efficient as well. + var task = awaitable as System.Threading.Tasks.Task; + if (task != null) return TaskAwaitAdapter.Create(task); +#endif - public override bool IsCompleted => _awaiter.IsCompleted; + // Await all the (C#) things + var patternBasedAdapter = CSharpPatternBasedAwaitAdapter.TryCreate(awaitable); + if (patternBasedAdapter != null) return patternBasedAdapter; - [SecuritySafeCritical] - public override void OnCompleted(Action action) => _awaiter.UnsafeOnCompleted(action); +#if NET40 + // If System.Threading.Tasks.Task does not have a GetAwaiter instance method + // (we don’t heuristically search for AsyncBridge-style extension methods), + // we still need to be able to await it to preserve NUnit behavior on machines + // which have a max .NET Framework version of 4.0 installed, such as the default + // for versions of Windows earlier than 8. + var task = awaitable as System.Threading.Tasks.Task; + if (task != null) return Net40BclTaskAwaitAdapter.Create(task); +#endif - // Assumption that GetResult blocks until complete is only valid for System.Threading.Tasks.Task. - public override void BlockUntilCompleted() => _awaiter.GetResult(); + throw new NotSupportedException("NUnit can only await objects which follow the C# specification for awaitable expressions."); } -#endif } } -#endif diff --git a/src/NUnitFramework/framework/Internal/Builders/NUnitTestCaseBuilder.cs b/src/NUnitFramework/framework/Internal/Builders/NUnitTestCaseBuilder.cs index a494ffc06f..c5acbb8ecd 100644 --- a/src/NUnitFramework/framework/Internal/Builders/NUnitTestCaseBuilder.cs +++ b/src/NUnitFramework/framework/Internal/Builders/NUnitTestCaseBuilder.cs @@ -177,28 +177,24 @@ private static bool CheckTestMethodSignature(TestMethod testMethod, TestCasePara return false; } - ITypeInfo returnType = testMethod.Method.ReturnType; + var returnType = testMethod.Method.ReturnType.Type; -#if ASYNC if (AsyncToSyncAdapter.IsAsyncOperation(testMethod.Method.MethodInfo)) { - if (returnType.IsType(typeof(void))) + if (returnType == typeof(void)) return MarkAsNotRunnable(testMethod, "Async test method must have non-void return type"); - var returnsGenericTask = returnType.IsGenericType && - returnType.GetGenericTypeDefinition() == typeof(System.Threading.Tasks.Task<>); + var voidResult = AwaitAdapter.GetResultType(returnType) == typeof(void); - if (returnsGenericTask && (parms == null || !parms.HasExpectedResult)) + if (!voidResult && (parms == null || !parms.HasExpectedResult)) return MarkAsNotRunnable(testMethod, - "Async test method must have non-generic Task return type when no result is expected"); + "Async test method must return an awaitable with a void result when no result is expected"); - if (!returnsGenericTask && parms != null && parms.HasExpectedResult) + if (voidResult && parms != null && parms.HasExpectedResult) return MarkAsNotRunnable(testMethod, - "Async test method must have Task return type when a result is expected"); + "Async test method must return an awaitable with a non-void result when a result is expected"); } - else -#endif - if (returnType.IsType(typeof(void))) + else if (returnType == typeof(void)) { if (parms != null && parms.HasExpectedResult) return MarkAsNotRunnable(testMethod, "Method returning void cannot have an expected result"); @@ -228,6 +224,9 @@ private static bool CheckTestMethodSignature(TestMethod testMethod, TestCasePara parameters = testMethod.Method.GetParameters(); } + if (parms != null && parms.TestName != null && parms.TestName.Trim() == "") + return MarkAsNotRunnable(testMethod, "Test name cannot be all white-space or empty."); + if (arglist != null && parameters != null) TypeHelper.ConvertArgumentList(arglist, parameters); diff --git a/src/NUnitFramework/framework/Internal/Builders/PairwiseStrategy.cs b/src/NUnitFramework/framework/Internal/Builders/PairwiseStrategy.cs index 2f1a5404bf..2797d8ac0d 100644 --- a/src/NUnitFramework/framework/Internal/Builders/PairwiseStrategy.cs +++ b/src/NUnitFramework/framework/Internal/Builders/PairwiseStrategy.cs @@ -45,7 +45,7 @@ namespace NUnit.Framework.Internal.Builders /// /// /// The PairwiseStrategy code is based on "jenny" tool by Bob Jenkins: - /// http://burtleburtle.net/bob/math/jenny.html + /// https://burtleburtle.net/bob/math/jenny.html /// /// public class PairwiseStrategy : ICombiningStrategy @@ -60,7 +60,7 @@ public class PairwiseStrategy : ICombiningStrategy /// /// FleaRand is a pseudo-random number generator developed by Bob Jenkins: - /// http://burtleburtle.net/bob/rand/talksmall.html#flea + /// https://burtleburtle.net/bob/rand/talksmall.html#flea /// internal class FleaRand { diff --git a/src/NUnitFramework/framework/Internal/CSharpPatternBasedAwaitAdapter.AwaitShapeInfo.cs b/src/NUnitFramework/framework/Internal/CSharpPatternBasedAwaitAdapter.AwaitShapeInfo.cs new file mode 100644 index 0000000000..cb94c0b4f8 --- /dev/null +++ b/src/NUnitFramework/framework/Internal/CSharpPatternBasedAwaitAdapter.AwaitShapeInfo.cs @@ -0,0 +1,103 @@ +// *********************************************************************** +// Copyright (c) 2018 Charlie Poole, Rob Prouse +// +// 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.Reflection; +using NUnit.Compatibility; + +namespace NUnit.Framework.Internal +{ + internal static partial class CSharpPatternBasedAwaitAdapter + { + private sealed class AwaitShapeInfo + { + private readonly MethodInfo _getAwaiterMethod; + private readonly MethodInfo _isCompletedGetter; + private readonly MethodInfo _onCompletedMethod; + private readonly MethodInfo _getResultMethod; + + public AwaitShapeInfo(MethodInfo getAwaiterMethod, MethodInfo isCompletedGetter, MethodInfo onCompletedMethod, MethodInfo getResultMethod) + { + _getAwaiterMethod = getAwaiterMethod; + _isCompletedGetter = isCompletedGetter; + _onCompletedMethod = onCompletedMethod; + _getResultMethod = getResultMethod; + } + + public static AwaitShapeInfo TryCreate(Type awaitableType) + { + // See https://docs.microsoft.com/dotnet/csharp/language-reference/language-specification/expressions#awaitable-expressions + // This section was first established in C# 5 and has not been updated as of C# 7.3. + + // Something we might consider doing is checking to see if the Microsoft.CSharp assembly is loadable + // and then driving it via reflection as though we were generating `return await ((dynamic)awaitable);`. + // That would automatically opt into future changes to the spec, if any, but hardly seems worthwhile + // since this code is needed as a fallback anyway. + + var getAwaiterMethod = awaitableType.GetNonGenericPublicInstanceMethod("GetAwaiter", Type.EmptyTypes); + if (getAwaiterMethod == null || getAwaiterMethod.GetGenericArguments().Length != 0) return null; + + var awaiterType = getAwaiterMethod.ReturnType; + var notifyCompletionInterface = awaiterType.GetInterface("System.Runtime.CompilerServices.INotifyCompletion"); + if (notifyCompletionInterface == null) return null; + var onCompletedMethod = notifyCompletionInterface.GetNonGenericPublicInstanceMethod("OnCompleted", new[] { typeof(Action) }); + if (onCompletedMethod == null) return null; + + var isCompletedProperty = awaiterType.GetPublicInstanceProperty("IsCompleted", Type.EmptyTypes); + if (isCompletedProperty == null || isCompletedProperty.PropertyType != typeof(bool)) return null; + var isCompletedGetter = isCompletedProperty.GetGetMethod(); + if (isCompletedGetter == null) return null; + + var getResultMethod = awaiterType.GetNonGenericPublicInstanceMethod("GetResult", Type.EmptyTypes); + if (getResultMethod == null) return null; + + var criticalNotifyCompletionInterface = awaiterType.GetInterface("System.Runtime.CompilerServices.ICriticalNotifyCompletion"); + var unsafeOnCompletedMethod = criticalNotifyCompletionInterface?.GetNonGenericPublicInstanceMethod("UnsafeOnCompleted", new[] { typeof(Action) }); + + return new AwaitShapeInfo( + getAwaiterMethod, + isCompletedGetter, + unsafeOnCompletedMethod ?? onCompletedMethod, + getResultMethod); + } + + public AwaitAdapter CreateAwaitAdapter(object awaitable) + { + // We could emit ideal implementations of AwaitAdapter, customized to each awaitable type. + // But generating executable code at runtime is unsupported by design on some platforms. + // By the same token, MakeGenericMethod is not supported for types not included at compile time. + + // So let’s start with a less efficient, reflection-based approach which works anywhere + // and is much easier to follow, and add the complex thing only if we need to hit a perf goal. + + return new ReflectionAdapter( + _getAwaiterMethod.InvokeWithTransparentExceptions(awaitable), + _isCompletedGetter, + _onCompletedMethod, + _getResultMethod); + } + + public Type ResultType => _getResultMethod.ReturnType; + } + } +} diff --git a/src/NUnitFramework/framework/Internal/CSharpPatternBasedAwaitAdapter.ReflectionAdapter.cs b/src/NUnitFramework/framework/Internal/CSharpPatternBasedAwaitAdapter.ReflectionAdapter.cs new file mode 100644 index 0000000000..8bcd76dc40 --- /dev/null +++ b/src/NUnitFramework/framework/Internal/CSharpPatternBasedAwaitAdapter.ReflectionAdapter.cs @@ -0,0 +1,54 @@ +// *********************************************************************** +// Copyright (c) 2018 Charlie Poole, Rob Prouse +// +// 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.Reflection; +using NUnit.Compatibility; + +namespace NUnit.Framework.Internal +{ + internal static partial class CSharpPatternBasedAwaitAdapter + { + private sealed class ReflectionAdapter : DefaultBlockingAwaitAdapter + { + private readonly object _awaiter; + private readonly Func _awaiterIsCompleted; + private readonly Action _awaiterOnCompleted; + private readonly MethodInfo _getResultMethod; + + public ReflectionAdapter(object awaiter, MethodInfo isCompletedGetter, MethodInfo onCompletedMethod, MethodInfo getResultMethod) + { + _awaiter = awaiter; + _awaiterIsCompleted = (Func)isCompletedGetter.CreateDelegate(typeof(Func), awaiter); + _awaiterOnCompleted = (Action)onCompletedMethod.CreateDelegate(typeof(Action), awaiter); + _getResultMethod = getResultMethod; + } + + public override bool IsCompleted => _awaiterIsCompleted.Invoke(); + + public override void OnCompleted(Action action) => _awaiterOnCompleted.Invoke(action); + + public override object GetResult() => _getResultMethod.InvokeWithTransparentExceptions(_awaiter); + } + } +} diff --git a/src/NUnitFramework/framework/Internal/CSharpPatternBasedAwaitAdapter.cs b/src/NUnitFramework/framework/Internal/CSharpPatternBasedAwaitAdapter.cs new file mode 100644 index 0000000000..39c2683624 --- /dev/null +++ b/src/NUnitFramework/framework/Internal/CSharpPatternBasedAwaitAdapter.cs @@ -0,0 +1,72 @@ +// *********************************************************************** +// Copyright (c) 2018 Charlie Poole, Rob Prouse +// +// 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.Collections.Concurrent; +using System.Collections.Generic; + +namespace NUnit.Framework.Internal +{ + internal static partial class CSharpPatternBasedAwaitAdapter + { +#if NET35 + private static readonly Dictionary ShapeInfoByType = new Dictionary(); +#else + private static readonly ConcurrentDictionary ShapeInfoByType = new ConcurrentDictionary(); +#endif + + public static AwaitAdapter TryCreate(object awaitable) + { + if (awaitable == null) return null; + + return GetShapeInfo(awaitable.GetType())?.CreateAwaitAdapter(awaitable); + } + + public static bool IsAwaitable(Type awaitableType) + { + return GetShapeInfo(awaitableType) != null; + } + + public static Type GetResultType(Type awaitableType) + { + return GetShapeInfo(awaitableType)?.ResultType; + } + + private static AwaitShapeInfo GetShapeInfo(Type type) + { +#if NET35 + AwaitShapeInfo info; + + lock (ShapeInfoByType) + { + if (!ShapeInfoByType.TryGetValue(type, out info)) + ShapeInfoByType.Add(type, info = AwaitShapeInfo.TryCreate(type)); + } + + return info; +#else + return ShapeInfoByType.GetOrAdd(type, AwaitShapeInfo.TryCreate); +#endif + } + } +} diff --git a/src/NUnitFramework/framework/Internal/Commands/DelegatingTestCommand.cs b/src/NUnitFramework/framework/Internal/Commands/DelegatingTestCommand.cs index a57e0c383b..b10399f92f 100644 --- a/src/NUnitFramework/framework/Internal/Commands/DelegatingTestCommand.cs +++ b/src/NUnitFramework/framework/Internal/Commands/DelegatingTestCommand.cs @@ -1,4 +1,4 @@ -// *********************************************************************** +// *********************************************************************** // Copyright (c) 2010 Charlie Poole, Rob Prouse // // Permission is hereby granted, free of charge, to any person obtaining @@ -31,12 +31,16 @@ namespace NUnit.Framework.Internal.Commands public abstract class DelegatingTestCommand : TestCommand { /// TODO: Documentation needed for field +#pragma warning disable IDE1006 + // ReSharper disable once InconsistentNaming + // Disregarding naming convention for back-compat protected TestCommand innerCommand; +#pragma warning restore IDE1006 /// - /// TODO: Documentation needed for constructor + /// Initializes a new instance of the class. /// - /// + /// The inner command. protected DelegatingTestCommand(TestCommand innerCommand) : base(innerCommand.Test) { diff --git a/src/NUnitFramework/framework/Internal/Commands/MaxTimeCommand.cs b/src/NUnitFramework/framework/Internal/Commands/MaxTimeCommand.cs index 0759a18eaa..64d2448b39 100644 --- a/src/NUnitFramework/framework/Internal/Commands/MaxTimeCommand.cs +++ b/src/NUnitFramework/framework/Internal/Commands/MaxTimeCommand.cs @@ -1,4 +1,4 @@ - // *********************************************************************** + // *********************************************************************** // Copyright (c) 2010-2017 Charlie Poole, Rob Prouse // // Permission is hereby granted, free of charge, to any person obtaining @@ -21,15 +21,15 @@ // WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. // *********************************************************************** -using System; using System.Diagnostics; -using NUnit.Compatibility; using NUnit.Framework.Interfaces; namespace NUnit.Framework.Internal.Commands { /// - /// TODO: Documentation needed for class + /// adjusts the result of a successful test + /// to a failure if the elapsed time has exceeded the specified maximum + /// time allowed. /// public class MaxTimeCommand : AfterTestCommand { @@ -67,4 +67,4 @@ public MaxTimeCommand(TestCommand innerCommand, int maxTime) }; } } -} \ No newline at end of file +} diff --git a/src/NUnitFramework/framework/Internal/Commands/SetUpTearDownItem.cs b/src/NUnitFramework/framework/Internal/Commands/SetUpTearDownItem.cs index d4d0d3e687..35d9d15001 100644 --- a/src/NUnitFramework/framework/Internal/Commands/SetUpTearDownItem.cs +++ b/src/NUnitFramework/framework/Internal/Commands/SetUpTearDownItem.cs @@ -103,11 +103,10 @@ public void RunTearDown(TestExecutionContext context) private static void RunSetUpOrTearDownMethod(TestExecutionContext context, MethodInfo method) { Guard.ArgumentNotAsyncVoid(method, nameof(method)); -#if ASYNC + if (AsyncToSyncAdapter.IsAsyncOperation(method)) AsyncToSyncAdapter.Await(() => InvokeMethod(method, context)); else -#endif InvokeMethod(method, context); } diff --git a/src/NUnitFramework/framework/Internal/Commands/TestMethodCommand.cs b/src/NUnitFramework/framework/Internal/Commands/TestMethodCommand.cs index 41adf06918..81ea787886 100644 --- a/src/NUnitFramework/framework/Internal/Commands/TestMethodCommand.cs +++ b/src/NUnitFramework/framework/Internal/Commands/TestMethodCommand.cs @@ -76,19 +76,11 @@ public override TestResult Execute(TestExecutionContext context) private object RunTestMethod(TestExecutionContext context) { -#if ASYNC if (AsyncToSyncAdapter.IsAsyncOperation(testMethod.Method.MethodInfo)) { - try - { - return AsyncToSyncAdapter.Await(() => InvokeTestMethod(context)); - } - catch (Exception e) - { - throw new NUnitException("Rethrown", e); - } + return AsyncToSyncAdapter.Await(() => InvokeTestMethod(context)); } -#endif + return InvokeTestMethod(context); } diff --git a/src/NUnitFramework/framework/Internal/Commands/TimeoutCommand.cs b/src/NUnitFramework/framework/Internal/Commands/TimeoutCommand.cs index c1e72902af..568c68a460 100644 --- a/src/NUnitFramework/framework/Internal/Commands/TimeoutCommand.cs +++ b/src/NUnitFramework/framework/Internal/Commands/TimeoutCommand.cs @@ -1,5 +1,5 @@ // *********************************************************************** -// Copyright (c) 2017 Charlie Poole, Rob Prouse +// Copyright (c) 2017-2018 Charlie Poole, Rob Prouse // // Permission is hereby granted, free of charge, to any person obtaining // a copy of this software and associated documentation files (the @@ -21,37 +21,40 @@ // WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. // *********************************************************************** -#if THREAD_ABORT using System; -using System.Collections.Generic; using System.Threading; +#if !THREAD_ABORT +using System.Threading.Tasks; +#endif +using NUnit.Framework.Interfaces; namespace NUnit.Framework.Internal.Commands { - using Execution; - using Interfaces; - /// - /// TimeoutCommand creates a timer in order to cancel + /// creates a timer in order to cancel /// a test if it exceeds a specified time and adjusts /// the test result if it did time out. /// public class TimeoutCommand : BeforeAndAfterTestCommand { + private readonly int _timeout; +#if THREAD_ABORT Timer _commandTimer; - private bool _commandTimedOut = false; + private bool _commandTimedOut; +#endif /// /// Initializes a new instance of the class. /// /// The inner command /// Timeout value - public TimeoutCommand(TestCommand innerCommand, int timeout) - : base(innerCommand) + public TimeoutCommand(TestCommand innerCommand, int timeout) : base(innerCommand) { + _timeout = timeout; Guard.ArgumentValid(innerCommand.Test is TestMethod, "TimeoutCommand may only apply to a TestMethod", nameof(innerCommand)); Guard.ArgumentValid(timeout > 0, "Timeout value must be greater than zero", nameof(timeout)); +#if THREAD_ABORT BeforeTest = (context) => { var testThread = Thread.CurrentThread; @@ -77,11 +80,40 @@ public TimeoutCommand(TestCommand innerCommand, int timeout) // If the timer cancelled the current thread, change the result if (_commandTimedOut) { - context.CurrentResult.SetResult(ResultState.Failure, - string.Format("Test exceeded Timeout value of {0}ms", timeout)); + context.CurrentResult.SetResult(ResultState.Failure, $"Test exceeded Timeout value of {timeout}ms"); } }; +#else + BeforeTest = _ => { }; + AfterTest = _ => { }; +#endif } + +#if !THREAD_ABORT + /// + /// Runs the test, saving a TestResult in the supplied TestExecutionContext. + /// + /// The context in which the test should run. + /// A TestResult + public override TestResult Execute(TestExecutionContext context) + { + try + { + if (!Task.Run(() => context.CurrentResult = innerCommand.Execute(context)).Wait(_timeout)) + { + context.CurrentResult.SetResult(new ResultState( + TestStatus.Failed, + $"Test exceeded Timeout value {_timeout}ms.", + FailureSite.Test)); + } + } + catch (Exception exception) + { + context.CurrentResult.RecordException(exception, FailureSite.Test); + } + + return context.CurrentResult; + } +#endif } } -#endif diff --git a/src/NUnitFramework/framework/Internal/DefaultBlockingAwaitAdapter.cs b/src/NUnitFramework/framework/Internal/DefaultBlockingAwaitAdapter.cs new file mode 100644 index 0000000000..f95522221a --- /dev/null +++ b/src/NUnitFramework/framework/Internal/DefaultBlockingAwaitAdapter.cs @@ -0,0 +1,69 @@ +// *********************************************************************** +// Copyright (c) 2018 Charlie Poole, Rob Prouse +// +// 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.Threading; + +namespace NUnit.Framework.Internal +{ + /// + /// Useful when wrapping awaitables whose GetResult method does not block until complete. + /// Contains a default mechanism to implement + /// via and . + /// + internal abstract class DefaultBlockingAwaitAdapter : AwaitAdapter + { + private volatile ManualResetEventSlim _completedEvent; + + public sealed override void BlockUntilCompleted() + { + if (IsCompleted) return; + + var completedEvent = _completedEvent; // Volatile read (would be Volatile.Read if not for net40 support) + if (completedEvent == null) + { + completedEvent = new ManualResetEventSlim(); + +#pragma warning disable 420 // Taking a ref to a volatile field is fine if the ref is only used by Interlocked or Volatile methods. + var previous = Interlocked.CompareExchange(ref _completedEvent, completedEvent, null); +#pragma warning restore 420 + + if (previous == null) + { + // We are the first thread. (Though by this time, other threads may now be + // waiting on this ManualResetEvent.) Register to signal the event on completion. + // If completion has already happened by this time, OnCompleted is still obligated + // to execute the action we pass. + OnCompleted(completedEvent.Set); + } + else + { + // We lost a race with another thread. + completedEvent.Dispose(); + completedEvent = previous; + } + } + + completedEvent.Wait(); + } + } +} diff --git a/src/NUnitFramework/framework/Internal/ExceptionHelper.cs b/src/NUnitFramework/framework/Internal/ExceptionHelper.cs index 5960e6d7d5..a88c95e02b 100644 --- a/src/NUnitFramework/framework/Internal/ExceptionHelper.cs +++ b/src/NUnitFramework/framework/Internal/ExceptionHelper.cs @@ -22,10 +22,13 @@ // *********************************************************************** using System; +using System.Collections; using System.Globalization; using System.Collections.Generic; +using System.Linq; using System.Reflection; using System.Text; +using NUnit.Compatibility; namespace NUnit.Framework.Internal { @@ -34,7 +37,7 @@ namespace NUnit.Framework.Internal /// public class ExceptionHelper { -#if NET20 || NET35 || NET40 +#if NET35 || NET40 private static readonly Action PreserveStackTrace; static ExceptionHelper() @@ -60,7 +63,7 @@ static ExceptionHelper() /// The exception to rethrow public static void Rethrow(Exception exception) { -#if NET20 || NET35 || NET40 +#if NET35 || NET40 PreserveStackTrace(exception); throw exception; #else @@ -84,6 +87,7 @@ public static string BuildMessage(Exception exception, bool excludeExceptionName if (!excludeExceptionNames) sb.AppendFormat("{0} : ", exception.GetType()); sb.Append(GetExceptionMessage(exception)); + AppendExceptionDataContents(exception, sb); foreach (Exception inner in FlattenExceptionHierarchy(exception)) { @@ -92,6 +96,7 @@ public static string BuildMessage(Exception exception, bool excludeExceptionName if (!excludeExceptionNames) sb.AppendFormat("{0} : ", inner.GetType()); sb.Append(GetExceptionMessage(inner)); + AppendExceptionDataContents(inner, sb); } return sb.ToString(); @@ -151,6 +156,22 @@ private static string GetExceptionMessage(Exception ex) return ex.Message; } + private static void AppendExceptionDataContents(Exception ex, StringBuilder sb) + { + if (ex.Data.Count == 0) + { + return; + } + + sb.AppendLine(); + sb.AppendLine("Data:"); + foreach (DictionaryEntry kvp in ex.Data) + { + sb.AppendFormat(" {0}: {1}", kvp.Key, kvp.Value?.ToString() ?? ""); + sb.AppendLine(); + } + } + private static List FlattenExceptionHierarchy(Exception exception) { var result = new List(); @@ -163,7 +184,7 @@ private static List FlattenExceptionHierarchy(Exception exception) foreach (var innerException in reflectionException.LoaderExceptions) result.AddRange(FlattenExceptionHierarchy(innerException)); } -#if ASYNC +#if TASK_PARALLEL_LIBRARY_API if (exception is AggregateException) { var aggregateException = (exception as AggregateException); @@ -182,5 +203,48 @@ private static List FlattenExceptionHierarchy(Exception exception) return result; } + + /// + /// Executes a parameterless synchronous or async delegate and returns the exception it throws, if any. + /// + internal static Exception RecordException(Delegate parameterlessDelegate, string parameterName) + { + Guard.ArgumentNotNull(parameterlessDelegate, parameterName); + + Guard.ArgumentValid( + parameterlessDelegate.GetMethodInfo().GetParameters().Length == 0, + $"The actual value must be a parameterless delegate but was {parameterlessDelegate.GetType().Name}.", + nameof(parameterName)); + + Guard.ArgumentNotAsyncVoid(parameterlessDelegate, parameterName); + + using (new TestExecutionContext.IsolatedContext()) + { + if (AsyncToSyncAdapter.IsAsyncOperation(parameterlessDelegate)) + { + try + { + AsyncToSyncAdapter.Await(parameterlessDelegate.DynamicInvokeWithTransparentExceptions); + } + catch (Exception ex) + { + return ex; + } + } + else + { + try + { + parameterlessDelegate.DynamicInvokeWithTransparentExceptions(); + } + catch (Exception ex) + { + return ex; + } + } + } + + return null; + } } } diff --git a/src/NUnitFramework/framework/Internal/Execution/CountdownEvent.cs b/src/NUnitFramework/framework/Internal/Execution/CountdownEvent.cs index f4145db59b..20afac4985 100644 --- a/src/NUnitFramework/framework/Internal/Execution/CountdownEvent.cs +++ b/src/NUnitFramework/framework/Internal/Execution/CountdownEvent.cs @@ -21,7 +21,7 @@ // WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. // *********************************************************************** -#if NET20 || NET35 +#if NET35 using System; using System.Threading; diff --git a/src/NUnitFramework/framework/Internal/Execution/EventPump.cs b/src/NUnitFramework/framework/Internal/Execution/EventPump.cs index 8585307712..c9bc3a13cf 100644 --- a/src/NUnitFramework/framework/Internal/Execution/EventPump.cs +++ b/src/NUnitFramework/framework/Internal/Execution/EventPump.cs @@ -185,13 +185,13 @@ private void PumpThreadProc() } catch (Exception ex) { - log.Error( "Exception in event handler\r\n {0}", ex ); + log.Error("Exception in event handler {0}", ExceptionHelper.BuildStackTrace(ex)); } } } catch (Exception ex) { - log.Error( "Exception in pump thread", ex ); + log.Error("Exception in pump thread {0}", ExceptionHelper.BuildStackTrace(ex)); } finally { diff --git a/src/NUnitFramework/framework/Internal/Execution/ParallelWorkItemDispatcher.cs b/src/NUnitFramework/framework/Internal/Execution/ParallelWorkItemDispatcher.cs index d9c1d09118..8cd2ea982d 100644 --- a/src/NUnitFramework/framework/Internal/Execution/ParallelWorkItemDispatcher.cs +++ b/src/NUnitFramework/framework/Internal/Execution/ParallelWorkItemDispatcher.cs @@ -278,15 +278,19 @@ internal void IsolateQueues(WorkItem work) } /// - /// Remove isolated queues and restore old ones + /// Try to remove isolated queues and restore old ones /// - private void RestoreQueues() + private void TryRestoreQueues() { - Guard.OperationValid(_isolationLevel > 0, $"Called {nameof(RestoreQueues)} with no saved queues."); - // Keep lock until we can remove for both methods lock (_queueLock) { + if (_isolationLevel <= 0) + { + log.Debug("Ignoring call to restore Queue State"); + return; + } + log.Info("Restoring Queue State"); foreach (WorkItemQueue queue in Queues) @@ -325,7 +329,7 @@ private void OnEndOfShift(WorkShift endingShift) // If the shift has ended for an isolated queue, restore // the queues and keep trying. Otherwise, we are done. if (_isolationLevel > 0) - RestoreQueues(); + TryRestoreQueues(); else break; } @@ -349,7 +353,7 @@ private WorkShift SelectNextShift() #region ParallelScopeHelper Class -#if NET20 || NET35 +#if NET35 static class ParallelScopeHelper { public static bool HasFlag(this ParallelScope scope, ParallelScope value) diff --git a/src/NUnitFramework/framework/Internal/Execution/SimpleWorkItem.cs b/src/NUnitFramework/framework/Internal/Execution/SimpleWorkItem.cs index d27602713d..53d0f7161c 100644 --- a/src/NUnitFramework/framework/Internal/Execution/SimpleWorkItem.cs +++ b/src/NUnitFramework/framework/Internal/Execution/SimpleWorkItem.cs @@ -1,5 +1,5 @@ // *********************************************************************** -// Copyright (c) 2012-2017 Charlie Poole, Rob Prouse +// Copyright (c) 2012-2018 Charlie Poole, Rob Prouse // // Permission is hereby granted, free of charge, to any person obtaining // a copy of this software and associated documentation files (the @@ -141,7 +141,6 @@ private TestCommand MakeTestCommand() command = new ApplyChangesToContextCommand(command, attr); // If a timeout is specified, create a TimeoutCommand -#if THREAD_ABORT // Timeout set at a higher level int timeout = Context.TestCaseTimeout; @@ -151,7 +150,6 @@ private TestCommand MakeTestCommand() if (timeout > 0) command = new TimeoutCommand(command, timeout); -#endif // Add wrappers for repeatable tests after timeout so the timeout is reset on each repeat foreach (var repeatableAttribute in method.MethodInfo.GetAttributes(true)) diff --git a/src/NUnitFramework/framework/Internal/Execution/SimpleWorkItemDispatcher.cs b/src/NUnitFramework/framework/Internal/Execution/SimpleWorkItemDispatcher.cs index 72c7535df8..4347da01ad 100644 --- a/src/NUnitFramework/framework/Internal/Execution/SimpleWorkItemDispatcher.cs +++ b/src/NUnitFramework/framework/Internal/Execution/SimpleWorkItemDispatcher.cs @@ -22,6 +22,7 @@ // *********************************************************************** #if PARALLEL +using System; using System.Collections.Generic; using System.Diagnostics; using System.Threading; @@ -59,8 +60,17 @@ public void Start(WorkItem topLevelWorkItem) _runnerThread = new Thread(RunnerThreadProc); #if APARTMENT_STATE - if (topLevelWorkItem.TargetApartment == ApartmentState.STA) - _runnerThread.SetApartmentState(ApartmentState.STA); + if (topLevelWorkItem.TargetApartment != ApartmentState.Unknown) + { + try + { + _runnerThread.SetApartmentState(topLevelWorkItem.TargetApartment); + } + catch (PlatformNotSupportedException) + { + topLevelWorkItem.MarkNotRunnable("Apartment state cannot be set on this platform."); + } + } #endif _runnerThread.Start(); diff --git a/src/NUnitFramework/framework/Internal/Execution/TestWorker.cs b/src/NUnitFramework/framework/Internal/Execution/TestWorker.cs index 11d77f3cdf..a7c23b8fd6 100644 --- a/src/NUnitFramework/framework/Internal/Execution/TestWorker.cs +++ b/src/NUnitFramework/framework/Internal/Execution/TestWorker.cs @@ -24,6 +24,7 @@ #if PARALLEL using System; using System.Threading; +using NUnit.Framework.Interfaces; namespace NUnit.Framework.Internal.Execution { @@ -123,10 +124,10 @@ private void TestWorkerThreadProc() _currentWorkItem.TestWorker = this; // During this Busy call, the queue state may be saved. - // This gives us a new set of queues, which are initially + // This gives us a new set of queues, which are initially // empty. The intention is that only children of the current // executing item should make use of the new set of queues. - // TODO: If we had a separate NonParallelTestWorker, it + // TODO: If we had a separate NonParallelTestWorker, it // could simply create the isolated queue without any // worrying about competing workers. Busy(this, _currentWorkItem); @@ -157,7 +158,13 @@ public void Start() _workerThread = new Thread(new ThreadStart(TestWorkerThreadProc)); _workerThread.Name = Name; #if APARTMENT_STATE - _workerThread.SetApartmentState(WorkQueue.TargetApartment); + try + { + _workerThread.SetApartmentState(WorkQueue.TargetApartment); + } + catch (PlatformNotSupportedException) + { + } #endif log.Info("{0} starting on thread [{1}]", Name, _workerThread.ManagedThreadId); _workerThread.Start(); diff --git a/src/NUnitFramework/framework/Internal/Execution/WorkItem.cs b/src/NUnitFramework/framework/Internal/Execution/WorkItem.cs index c272ae104b..364a557062 100644 --- a/src/NUnitFramework/framework/Internal/Execution/WorkItem.cs +++ b/src/NUnitFramework/framework/Internal/Execution/WorkItem.cs @@ -225,8 +225,9 @@ public virtual void Execute() #if APARTMENT_STATE CurrentApartment = Thread.CurrentThread.GetApartmentState(); var targetApartment = TargetApartment == ApartmentState.Unknown ? CurrentApartment : TargetApartment; + var needsNewThreadToSetApartmentState = targetApartment != CurrentApartment; - if (Test.RequiresThread || targetApartment != CurrentApartment) + if (Test.RequiresThread || needsNewThreadToSetApartmentState) #else if (Test.RequiresThread) #endif @@ -480,7 +481,18 @@ private void RunOnSeparateThread() RunOnCurrentThread(); }); #if APARTMENT_STATE - thread.SetApartmentState(apartment); + try + { + thread.SetApartmentState(apartment); + } + catch (PlatformNotSupportedException) + { + string msg = "Apartment state cannot be set on this platform."; + log.Error(msg); + Result.SetResult(ResultState.Skipped, msg); + WorkItemComplete(); + return; + } #endif thread.Start(); thread.Join(); @@ -571,7 +583,7 @@ static ApartmentState GetTargetApartment(ITest test) #endregion } -#if NET20 || NET35 +#if NET35 static class ActionTargetsExtensions { public static bool HasFlag(this ActionTargets targets, ActionTargets value) diff --git a/src/NUnitFramework/framework/Internal/Filters/NotFilter.cs b/src/NUnitFramework/framework/Internal/Filters/NotFilter.cs index e31a543dbd..1e51cdaef6 100644 --- a/src/NUnitFramework/framework/Internal/Filters/NotFilter.cs +++ b/src/NUnitFramework/framework/Internal/Filters/NotFilter.cs @@ -46,17 +46,21 @@ public NotFilter( TestFilter baseFilter) public TestFilter BaseFilter { get; } /// - /// Determine if a particular test passes the filter criteria. The default - /// implementation checks the test itself, its parents and any descendants. + /// Determine if a particular test passes the filter criteria. /// - /// Derived classes may override this method or any of the Match methods - /// to change the behavior of the filter. + /// Overriden in NotFilter so that + /// 1. Two nested NotFilters are simply ignored + /// 2. Otherwise, we only look at the test itself and parents, ignoring + /// any child test matches. /// /// The test to which the filter is applied /// True if the test passes the filter, otherwise false public override bool Pass(ITest test) { - return !BaseFilter.Match (test) && !BaseFilter.MatchParent (test); + var secondNotFilter = BaseFilter as NotFilter; + return secondNotFilter != null + ? secondNotFilter.BaseFilter.Pass(test) + : !BaseFilter.Match (test) && !BaseFilter.MatchParent (test); } /// diff --git a/src/NUnitFramework/framework/Internal/MessagePumpStrategy.cs b/src/NUnitFramework/framework/Internal/MessagePumpStrategy.cs index 99b2eb01b4..1ac0bfcc44 100644 --- a/src/NUnitFramework/framework/Internal/MessagePumpStrategy.cs +++ b/src/NUnitFramework/framework/Internal/MessagePumpStrategy.cs @@ -21,7 +21,6 @@ // WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. // *********************************************************************** -#if ASYNC using System; using System.Security; using System.Threading; @@ -170,4 +169,3 @@ private static void ContinueOnSameSynchronizationContext(AwaitAdapter adapter, A } } } -#endif diff --git a/src/NUnitFramework/framework/Internal/NUnitCallContext.cs b/src/NUnitFramework/framework/Internal/NUnitCallContext.cs new file mode 100644 index 0000000000..7a182b446c --- /dev/null +++ b/src/NUnitFramework/framework/Internal/NUnitCallContext.cs @@ -0,0 +1,60 @@ +// *********************************************************************** +// Copyright (c) 2018 Charlie Poole, Rob Prouse +// +// 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. +// *********************************************************************** + +#if NET35 || NET40 || NET45 +using System; +using System.Runtime.Remoting.Messaging; +using System.Security; + +namespace NUnit.Framework.Internal +{ + /// + /// This class ensures the is correctly cleared + /// or restored around framework actions. This is important if running multiple assemblies within the same + /// process, to ensure no leakage from one assembly to the next. See https://github.com/nunit/nunit-console/issues/325 + /// + internal class NUnitCallContext : IDisposable + { + private readonly object _oldContext; + public const string TestExecutionContextKey = "NUnit.Framework.TestExecutionContext"; + + // This method invokes security critical members on the 'System.Runtime.Remoting.Messaging.CallContext' class. + // Callers of this method have no influence on how these methods are used so we define a 'SecuritySafeCriticalAttribute' + // rather than a 'SecurityCriticalAttribute' to enable use by security transparent callers. + [SecuritySafeCritical] + public NUnitCallContext() + { + _oldContext = CallContext.GetData(TestExecutionContextKey); + } + + [SecuritySafeCritical] + public void Dispose() + { + if (_oldContext == null) + CallContext.FreeNamedDataSlot(TestExecutionContextKey); + else + CallContext.SetData(TestExecutionContextKey, _oldContext); + } + } +} +#endif diff --git a/src/NUnitFramework/framework/Internal/Net40BclTaskAwaitAdapter.cs b/src/NUnitFramework/framework/Internal/Net40BclTaskAwaitAdapter.cs new file mode 100644 index 0000000000..1134f55f80 --- /dev/null +++ b/src/NUnitFramework/framework/Internal/Net40BclTaskAwaitAdapter.cs @@ -0,0 +1,156 @@ +// *********************************************************************** +// Copyright (c) 2018 Charlie Poole, Rob Prouse +// +// 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. +// *********************************************************************** + +#if NET40 +using System; +using System.Linq; +using System.Threading.Tasks; + +namespace NUnit.Framework.Internal +{ + internal static class Net40BclTaskAwaitAdapter + { + public static AwaitAdapter Create(Task task) + { + var genericTaskType = task + .GetType() + .TypeAndBaseTypes() + .FirstOrDefault(t => t.IsGenericType && t.GetGenericTypeDefinition() == typeof(Task<>)); + + if (genericTaskType != null) + { + var typeArgument = genericTaskType.GetGenericArguments()[0]; + return (AwaitAdapter)typeof(GenericAdapter<>) + .MakeGenericType(typeArgument) + .GetConstructor(new[] { typeof(Task<>).MakeGenericType(typeArgument) }) + .Invoke(new object[] { task }); + } + + return new NonGenericAdapter(task); + } + + private class NonGenericAdapter : AwaitAdapter + { + private readonly Task _task; + + public NonGenericAdapter(Task task) + { + _task = task; + } + + public override bool IsCompleted => _task.IsCompleted; + + public override void OnCompleted(Action action) + { + if (action == null) return; + + // Normally we would call TaskAwaiter.UnsafeOnCompleted (https://source.dot.net/#System.Private.CoreLib/src/System/Runtime/CompilerServices/TaskAwaiter.cs) + // We will have to polyfill on top of the TPL API. + // Compare TaskAwaiter.OnCompletedInternal from Microsoft.Threading.Tasks.dll in Microsoft.Bcl.Async.nupkg. + + _task.ContinueWith(_ => action.Invoke(), TaskScheduler.FromCurrentSynchronizationContext()); + } + + public override void BlockUntilCompleted() + { + // Normally we would call TaskAwaiter.GetResult (https://source.dot.net/#System.Private.CoreLib/src/System/Runtime/CompilerServices/TaskAwaiter.cs) + // We will have to polyfill on top of the TPL API. + // Compare TaskAwaiter.ValidateEnd from Microsoft.Threading.Tasks.dll in Microsoft.Bcl.Async.nupkg. + + try + { + _task.Wait(); // Wait even if the task is completed so that an exception is thrown for cancellation or failure. + } + catch (AggregateException ex) when (ex.InnerExceptions.Count == 1) // Task.Wait wraps every exception + { + ExceptionHelper.Rethrow(ex.InnerException); + } + } + + public override object GetResult() + { + BlockUntilCompleted(); // Throw exceptions, if any + return null; + } + } + + private sealed class GenericAdapter : AwaitAdapter + { + private readonly Task _task; + + public GenericAdapter(Task task) + { + _task = task; + } + + public override bool IsCompleted => _task.IsCompleted; + + public override void OnCompleted(Action action) + { + if (action == null) return; + + // Normally we would call TaskAwaiter.UnsafeOnCompleted (https://source.dot.net/#System.Private.CoreLib/src/System/Runtime/CompilerServices/TaskAwaiter.cs) + // We will have to polyfill on top of the TPL API. + // Compare TaskAwaiter.OnCompletedInternal from Microsoft.Threading.Tasks.dll in Microsoft.Bcl.Async.nupkg. + + _task.ContinueWith(_ => action.Invoke(), TaskScheduler.FromCurrentSynchronizationContext()); + } + + public override void BlockUntilCompleted() + { + // Normally we would call TaskAwaiter.GetResult (https://source.dot.net/#System.Private.CoreLib/src/System/Runtime/CompilerServices/TaskAwaiter.cs) + // We will have to polyfill on top of the TPL API. + // Compare TaskAwaiter.ValidateEnd from Microsoft.Threading.Tasks.dll in Microsoft.Bcl.Async.nupkg. + + try + { + _task.Wait(); // Wait even if the task is completed so that an exception is thrown for cancellation or failure. + } + catch (AggregateException ex) when (ex.InnerExceptions.Count == 1) // Task.Wait wraps every exception + { + ExceptionHelper.Rethrow(ex.InnerException); + } + } + + public override object GetResult() + { + // Normally we would call TaskAwaiter.GetResult (https://source.dot.net/#System.Private.CoreLib/src/System/Runtime/CompilerServices/TaskAwaiter.cs) + // We will have to polyfill on top of the TPL API. + // Compare TaskAwaiter.ValidateEnd from Microsoft.Threading.Tasks.dll in Microsoft.Bcl.Async.nupkg. + + try + { + return _task.Result; + } + catch (AggregateException ex) when (ex.InnerExceptions.Count == 1) // Task.Wait wraps every exception + { + ExceptionHelper.Rethrow(ex.InnerException); + + // If this line is reached, ExceptionHelper.Rethrow is very broken. + throw new InvalidOperationException("ExceptionHelper.Rethrow failed to throw an exception."); + } + } + } + } +} +#endif diff --git a/src/NUnitFramework/framework/Internal/OSPlatform.cs b/src/NUnitFramework/framework/Internal/OSPlatform.cs index e94efeb298..260aefede0 100644 --- a/src/NUnitFramework/framework/Internal/OSPlatform.cs +++ b/src/NUnitFramework/framework/Internal/OSPlatform.cs @@ -61,7 +61,7 @@ public class OSPlatform } else if (CheckIfIsMacOSX(os.Platform)) { - // Mono returns PlatformID.Unix for OSX (see http://www.mono-project.com/docs/faq/technical/#how-to-detect-the-execution-platform) + // Mono returns PlatformID.Unix for OSX (see https://www.mono-project.com/docs/faq/technical/#how-to-detect-the-execution-platform) // The above check uses uname to confirm it is MacOSX and we change the PlatformId here. currentPlatform = new OSPlatform(PlatformID.MacOSX, os.Version); } @@ -73,7 +73,7 @@ public class OSPlatform /// - /// Platform ID for Unix as defined by Microsoft .NET 2.0 and greater + /// Platform ID for Unix as defined by .NET /// public static readonly PlatformID UnixPlatformID_Microsoft = (PlatformID)4; @@ -184,6 +184,7 @@ public enum ProductType [StructLayout(LayoutKind.Sequential)] struct OSVERSIONINFOEX { +#pragma warning disable IDE1006 // P/invoke doesn’t need to follow naming convention public uint dwOSVersionInfoSize; public readonly uint dwMajorVersion; public readonly uint dwMinorVersion; @@ -194,6 +195,7 @@ struct OSVERSIONINFOEX public readonly Int16 wServicePackMajor; public readonly Int16 wServicePackMinor; public readonly Int16 wSuiteMask; +#pragma warning restore IDE1006 public readonly Byte ProductType; public readonly Byte Reserved; } @@ -350,7 +352,9 @@ public bool IsMacOSX } [DllImport("libc")] +#pragma warning disable IDE1006 // P/invoke doesn’t need to follow naming convention static extern int uname(IntPtr buf); +#pragma warning restore IDE1006 static bool CheckIfIsMacOSX(PlatformID platform) { diff --git a/src/NUnitFramework/framework/Internal/ParamAttributeTypeConversions.cs b/src/NUnitFramework/framework/Internal/ParamAttributeTypeConversions.cs index 449f423892..6fd986d868 100644 --- a/src/NUnitFramework/framework/Internal/ParamAttributeTypeConversions.cs +++ b/src/NUnitFramework/framework/Internal/ParamAttributeTypeConversions.cs @@ -23,9 +23,12 @@ using System; using System.Collections; +using System.ComponentModel; +using System.Globalization; + +#if !(NET35 || NET40 || NET45) using System.Reflection; -using NUnit.Compatibility; -using NUnit.Framework.Interfaces; +#endif namespace NUnit.Framework.Internal { @@ -86,8 +89,17 @@ public static object Convert(object value, Type targetType) } /// - /// Converts a single value to the , if it is supported. + /// Performs several special conversions allowed by NUnit in order to + /// permit arguments with types that cannot be used in the constructor + /// of an Attribute such as TestCaseAttribute or to simplify their use. /// + /// The value to be converted + /// The target in which the should be converted + /// If conversion was successfully applied, the converted into + /// + /// true if was converted and should be used; + /// false is no conversion was applied and should be ignored + /// public static bool TryConvert(object value, Type targetType, out object convertedValue) { if (targetType.IsInstanceOfType(value)) @@ -103,23 +115,32 @@ public static bool TryConvert(object value, Type targetType, out object converte } bool convert = false; + var underlyingTargetType = Nullable.GetUnderlyingType(targetType) ?? targetType; - if (targetType == typeof(short) || targetType == typeof(byte) || targetType == typeof(sbyte)) + if (underlyingTargetType == typeof(short) || underlyingTargetType == typeof(byte) || underlyingTargetType == typeof(sbyte) + || underlyingTargetType == typeof(long) || underlyingTargetType == typeof(double)) { convert = value is int; } - else if (targetType == typeof(decimal)) + else if (underlyingTargetType == typeof(decimal)) { convert = value is double || value is string || value is int; } - else if (targetType == typeof(DateTime) || targetType == typeof(TimeSpan)) + else if (underlyingTargetType == typeof(DateTime)) { convert = value is string; } if (convert) { - convertedValue = System.Convert.ChangeType(value, targetType, System.Globalization.CultureInfo.InvariantCulture); + convertedValue = System.Convert.ChangeType(value, underlyingTargetType, CultureInfo.InvariantCulture); + return true; + } + + var converter = TypeDescriptor.GetConverter(underlyingTargetType); + if (converter.CanConvertFrom(value.GetType())) + { + convertedValue = converter.ConvertFrom(null, CultureInfo.InvariantCulture, value); return true; } diff --git a/src/NUnitFramework/framework/Internal/PropertyNames.cs b/src/NUnitFramework/framework/Internal/PropertyNames.cs index d6629e887e..415df42a86 100644 --- a/src/NUnitFramework/framework/Internal/PropertyNames.cs +++ b/src/NUnitFramework/framework/Internal/PropertyNames.cs @@ -46,7 +46,7 @@ public class PropertyNames /// /// The process ID of the executing assembly /// - public const string ProcessID = "_PID"; + public const string ProcessId = "_PID"; /// /// The stack trace from any data provider that threw diff --git a/src/NUnitFramework/framework/Internal/Reflect.cs b/src/NUnitFramework/framework/Internal/Reflect.cs index ab0bbcb8db..f6a6e4ad1f 100644 --- a/src/NUnitFramework/framework/Internal/Reflect.cs +++ b/src/NUnitFramework/framework/Internal/Reflect.cs @@ -25,7 +25,7 @@ using System.Collections.Generic; using System.Linq; using System.Reflection; -#if !(NET20 || NET35 || NETSTANDARD1_4) +#if !(NET35 || NETSTANDARD1_4) using System.Runtime.ExceptionServices; #endif using NUnit.Compatibility; @@ -258,7 +258,7 @@ public static object InvokeMethod(MethodInfo method, object fixture) /// The object on which to invoke the method /// The argument list for the method /// The return value from the invoked method -#if !(NET20 || NET35 || NETSTANDARD1_4) +#if !(NET35 || NETSTANDARD1_4) [HandleProcessCorruptedStateExceptions] //put here to handle C++ exceptions. #endif public static object InvokeMethod(MethodInfo method, object fixture, params object[] args) @@ -269,18 +269,22 @@ public static object InvokeMethod(MethodInfo method, object fixture, params obje { return method.Invoke(fixture, args); } -#if THREAD_ABORT - catch (System.Threading.ThreadAbortException) - { - // No need to wrap or rethrow ThreadAbortException - return null; - } -#endif catch (TargetInvocationException e) { throw new NUnitException("Rethrown", e.InnerException); } catch (Exception e) +#if THREAD_ABORT + // If ThreadAbortException is caught, it must be rethrown or else Mono 5.18.1 + // will not rethrow at the end of the catch block. Instead, it will resurrect + // the ThreadAbortException at the end of the next unrelated catch block that + // executes on the same thread after handling an unrelated exception. + // The end result is that an unrelated test will error with the message "Test + // cancelled by user." + + // This is just cleaner than catching and rethrowing: + when (!(e is System.Threading.ThreadAbortException)) +#endif { throw new NUnitException("Rethrown", e); } @@ -375,5 +379,111 @@ private static bool IsNullable(Type type) && !type.GetTypeInfo().IsGenericTypeDefinition && ReferenceEquals(type.GetGenericTypeDefinition(), typeof(Nullable<>)); } + + internal static IEnumerable TypeAndBaseTypes(this Type type) + { + for (; type != null; type = type.GetTypeInfo().BaseType) + { + yield return type; + } + } + +#if NETSTANDARD1_4 + internal static Type GetInterface(this Type type, string name) + { + return type.GetTypeInfo().ImplementedInterfaces + .SingleOrDefault(implementedInterface => implementedInterface.FullName == name); + } +#endif + + /// + /// Same as GetMethod(, | + /// , , , + /// ) except that it also chooses only non-generic methods. + /// Useful for avoiding the you can have with GetMethod. + /// + internal static MethodInfo GetNonGenericPublicInstanceMethod(this Type type, string name, Type[] parameterTypes) + { + foreach (var currentType in type.TypeAndBaseTypes()) + { + var method = currentType + .GetMethods(BindingFlags.Public | BindingFlags.Instance | BindingFlags.DeclaredOnly) + .SingleOrDefault(candidate => + { + if (candidate.Name != name || candidate.GetGenericArguments().Length != 0) return false; + + var parameters = candidate.GetParameters(); + if (parameters.Length != parameterTypes.Length) return false; + + for (var i = 0; i < parameterTypes.Length; i++) + if (parameters[i].ParameterType != parameterTypes[i]) + return false; + + return true; + }); + + if (method != null) return method; + } + + return null; + } + + internal static PropertyInfo GetPublicInstanceProperty(this Type type, string name, Type[] indexParameterTypes) + { + for (var currentType = type; currentType != null; currentType = currentType.GetTypeInfo().BaseType) + { + var property = currentType + .GetProperties(BindingFlags.Public | BindingFlags.Instance | BindingFlags.DeclaredOnly) + .SingleOrDefault(candidate => + { + if (candidate.Name != name) return false; + + var indexParameters = candidate.GetIndexParameters(); + if (indexParameters.Length != indexParameterTypes.Length) return false; + + for (var i = 0; i < indexParameterTypes.Length; i++) + if (indexParameters[i].ParameterType != indexParameterTypes[i]) return false; + + return true; + }); + + if (property != null) return property; + } + + return null; + } + + internal static object InvokeWithTransparentExceptions(this MethodBase methodBase, object instance) + { + // If we ever target .NET Core 2.1, we can keep from mucking with the exception stack trace + // using BindingFlags.DoNotWrapExceptions rather than try…catch. + + try + { + return methodBase.Invoke(instance, null); + } + catch (TargetInvocationException ex) + { + ExceptionHelper.Rethrow(ex.InnerException); + + // If this line is reached, ExceptionHelper.Rethrow is very broken. + throw new InvalidOperationException("ExceptionHelper.Rethrow failed to throw an exception."); + } + } + + internal static object DynamicInvokeWithTransparentExceptions(this Delegate @delegate) + { + try + { + return @delegate.DynamicInvoke(); + } + catch (TargetInvocationException ex) + { + ExceptionHelper.Rethrow(ex.InnerException); + + // If this line is reached, ExceptionHelper.Rethrow is very broken. + throw new InvalidOperationException("ExceptionHelper.Rethrow failed to throw an exception."); + } + } } } diff --git a/src/NUnitFramework/framework/Internal/Results/TestResult.cs b/src/NUnitFramework/framework/Internal/Results/TestResult.cs index 9074e5930e..2ea0bcfc0a 100644 --- a/src/NUnitFramework/framework/Internal/Results/TestResult.cs +++ b/src/NUnitFramework/framework/Internal/Results/TestResult.cs @@ -83,11 +83,7 @@ public abstract class TestResult : LongLivedMarshalByRefObject, ITestResult /// /// ReaderWriterLock /// -#if NET20 - protected ReaderWriterLock RwLock = new ReaderWriterLock(); -#else protected ReaderWriterLockSlim RwLock = new ReaderWriterLockSlim(LockRecursionPolicy.SupportsRecursion); -#endif #endif #endregion @@ -575,11 +571,14 @@ private struct ExceptionResult { public ResultState ResultState { get; } public string Message { get; } - public string StackTrace { get; } + public string StackTrace { get; } + public Exception Exception { get; } public ExceptionResult(Exception ex, FailureSite site) { - ex = ValidateAndUnwrap(ex); + ex = ValidateAndUnwrap(ex); + + Exception = ex; if (ex is ResultStateException) { diff --git a/src/NUnitFramework/framework/Internal/Results/TestSuiteResult.cs b/src/NUnitFramework/framework/Internal/Results/TestSuiteResult.cs index 3cc9721192..4b238457c7 100644 --- a/src/NUnitFramework/framework/Internal/Results/TestSuiteResult.cs +++ b/src/NUnitFramework/framework/Internal/Results/TestSuiteResult.cs @@ -28,9 +28,6 @@ #endif using NUnit.Framework.Interfaces; using System.Threading; -#if NET20 -using NUnit.Compatibility; -#endif namespace NUnit.Framework.Internal { diff --git a/src/NUnitFramework/framework/Internal/RuntimeFramework.cs b/src/NUnitFramework/framework/Internal/RuntimeFramework.cs index 2ed8079f61..a4f2adec6b 100644 --- a/src/NUnitFramework/framework/Internal/RuntimeFramework.cs +++ b/src/NUnitFramework/framework/Internal/RuntimeFramework.cs @@ -78,8 +78,19 @@ public sealed class RuntimeFramework private static readonly Lazy currentFramework = new Lazy(() => { - Type monoRuntimeType = Type.GetType("Mono.Runtime", false); - Type monoTouchType = Type.GetType("MonoTouch.UIKit.UIApplicationDelegate,monotouch"); + Type monoRuntimeType = null; + Type monoTouchType = null; + + try + { + monoRuntimeType = Type.GetType("Mono.Runtime", false); + monoTouchType = Type.GetType("MonoTouch.UIKit.UIApplicationDelegate,monotouch", false); + } + catch + { + //If exception thrown, assume no valid installation + } + bool isMonoTouch = monoTouchType != null; bool isMono = monoRuntimeType != null; bool isNetCore = !isMono && !isMonoTouch && IsNetCore(); @@ -121,26 +132,9 @@ public sealed class RuntimeFramework #else if (major == 2) { - using (RegistryKey key = Registry.LocalMachine.OpenSubKey(@"SOFTWARE\Microsoft\.NETFramework")) - { - if (key != null) - { - string installRoot = key.GetValue("InstallRoot") as string; - if (installRoot != null) - { - if (Directory.Exists(Path.Combine(installRoot, "v3.5"))) - { - major = 3; - minor = 5; - } - else if (Directory.Exists(Path.Combine(installRoot, "v3.0"))) - { - major = 3; - minor = 0; - } - } - } - } + // The only assembly we compile that can run on the v2 CLR uses .NET Framework 3.5. + major = 3; + minor = 5; } else if (major == 4 && Type.GetType("System.Reflection.AssemblyMetadataAttribute") != null) { diff --git a/src/NUnitFramework/framework/Internal/SingleThreadedSynchronizationContext.cs b/src/NUnitFramework/framework/Internal/SingleThreadedSynchronizationContext.cs index 756c6cdb47..9eab82da00 100644 --- a/src/NUnitFramework/framework/Internal/SingleThreadedSynchronizationContext.cs +++ b/src/NUnitFramework/framework/Internal/SingleThreadedSynchronizationContext.cs @@ -1,5 +1,5 @@ // *********************************************************************** -// Copyright (c) 2018 Charlie Poole, Rob Prouse +// Copyright (c) 2018–2019 Charlie Poole, Rob Prouse // // Permission is hereby granted, free of charge, to any person obtaining // a copy of this software and associated documentation files (the @@ -23,19 +23,32 @@ using System; using System.Collections.Generic; +using System.Diagnostics; using System.Threading; +using NUnit.Framework.Interfaces; namespace NUnit.Framework.Internal { internal sealed partial class SingleThreadedTestSynchronizationContext : SynchronizationContext, IDisposable { + private const string ShutdownTimeoutMessage = + "Work posted to the synchronization context did not complete within ten seconds. Consider explicitly waiting for the work to complete."; + + private readonly TimeSpan _shutdownTimeout; private readonly Queue _queue = new Queue(); - private Status status; + private Status _status; + private Stopwatch _timeSinceShutdown; + + public SingleThreadedTestSynchronizationContext(TimeSpan shutdownTimeout) + { + _shutdownTimeout = shutdownTimeout; + } private enum Status { NotStarted, Running, + ShuttingDown, ShutDown } @@ -74,7 +87,16 @@ private void AddWork(ScheduledWork work) { lock (_queue) { - if (status == Status.ShutDown) throw CreateInvalidWhenShutDownException(); + switch (_status) + { + case Status.ShuttingDown: + if (_timeSinceShutdown.Elapsed < _shutdownTimeout) break; + goto case Status.ShutDown; + + case Status.ShutDown: + throw ErrorAndGetExceptionForShutdownTimeout(); + } + _queue.Enqueue(work); Monitor.Pulse(_queue); } @@ -87,19 +109,19 @@ public void ShutDown() { lock (_queue) { - status = Status.ShutDown; - Monitor.Pulse(_queue); + switch (_status) + { + case Status.ShuttingDown: + case Status.ShutDown: + return; + } - if (_queue.Count != 0) - throw new InvalidOperationException("Shutting down SingleThreadedTestSynchronizationContext with work still in the queue."); + _timeSinceShutdown = Stopwatch.StartNew(); + _status = Status.ShuttingDown; + Monitor.Pulse(_queue); } } - private static InvalidOperationException CreateInvalidWhenShutDownException() - { - return new InvalidOperationException("This SingleThreadedTestSynchronizationContext has been shut down."); - } - /// /// May be called from any thread, but may only be called once. /// @@ -107,15 +129,17 @@ public void Run() { lock (_queue) { - switch (status) + switch (_status) { case Status.Running: throw new InvalidOperationException("SingleThreadedTestSynchronizationContext.Run may not be reentered."); + + case Status.ShuttingDown: case Status.ShutDown: - throw CreateInvalidWhenShutDownException(); + throw new InvalidOperationException("This SingleThreadedTestSynchronizationContext has been shut down."); } - status = Status.Running; + _status = Status.Running; } ScheduledWork scheduledWork; @@ -127,24 +151,39 @@ private bool TryTake(out ScheduledWork scheduledWork) { lock (_queue) { - for (;;) + while (_queue.Count == 0) { - if (status == Status.ShutDown) + if (_status == Status.ShuttingDown) { + _status = Status.ShutDown; scheduledWork = default(ScheduledWork); return false; } - if (_queue.Count != 0) break; Monitor.Wait(_queue); } + if (_status == Status.ShuttingDown && _timeSinceShutdown.Elapsed > _shutdownTimeout) + { + _status = Status.ShutDown; + throw ErrorAndGetExceptionForShutdownTimeout(); + } + scheduledWork = _queue.Dequeue(); } return true; } + private static Exception ErrorAndGetExceptionForShutdownTimeout() + { + var testExecutionContext = TestExecutionContext.CurrentContext; + + testExecutionContext?.CurrentResult.RecordAssertion(AssertionStatus.Error, ShutdownTimeoutMessage); + + return new InvalidOperationException(ShutdownTimeoutMessage); + } + public void Dispose() { ShutDown(); diff --git a/src/NUnitFramework/framework/Internal/TaskAwaitAdapter.cs b/src/NUnitFramework/framework/Internal/TaskAwaitAdapter.cs new file mode 100644 index 0000000000..6faba0bf34 --- /dev/null +++ b/src/NUnitFramework/framework/Internal/TaskAwaitAdapter.cs @@ -0,0 +1,104 @@ +// *********************************************************************** +// Copyright (c) 2018 Charlie Poole, Rob Prouse +// +// 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. +// *********************************************************************** + +#if TASK_PARALLEL_LIBRARY_API && !NET40 +using System; +using System.Linq; +using System.Reflection; +using System.Runtime.CompilerServices; +using System.Security; +using System.Threading.Tasks; +using NUnit.Compatibility; + +namespace NUnit.Framework.Internal +{ + internal static class TaskAwaitAdapter + { + public static AwaitAdapter Create(Task task) + { + var genericTaskType = task + .GetType() + .TypeAndBaseTypes() + .FirstOrDefault(t => t.GetTypeInfo().IsGenericType && t.GetGenericTypeDefinition() == typeof(Task<>)); + + if (genericTaskType != null) + { + var typeArgument = genericTaskType.GetGenericArguments()[0]; + return (AwaitAdapter)typeof(GenericAdapter<>) + .MakeGenericType(typeArgument) + .GetConstructor(new[] { typeof(Task<>).MakeGenericType(typeArgument) }) + .Invoke(new object[] { task }); + } + + return new NonGenericAdapter(task); + } + + private sealed class NonGenericAdapter : AwaitAdapter + { + private readonly TaskAwaiter _awaiter; + + public NonGenericAdapter(Task task) + { + _awaiter = task.GetAwaiter(); + } + + public override bool IsCompleted => _awaiter.IsCompleted; + + [SecuritySafeCritical] + public override void OnCompleted(Action action) => _awaiter.UnsafeOnCompleted(action); + + // Assumption that GetResult blocks until complete is only valid for System.Threading.Tasks.Task. + public override void BlockUntilCompleted() => _awaiter.GetResult(); + + public override object GetResult() + { + _awaiter.GetResult(); // Throws exceptions, if any + return null; + } + } + + private sealed class GenericAdapter : AwaitAdapter + { + private readonly TaskAwaiter _awaiter; + + public GenericAdapter(Task task) + { + _awaiter = task.GetAwaiter(); + } + + public override bool IsCompleted => _awaiter.IsCompleted; + + [SecuritySafeCritical] + public override void OnCompleted(Action action) => _awaiter.UnsafeOnCompleted(action); + + // Assumption that GetResult blocks until complete is only valid for System.Threading.Tasks.Task. + public override void BlockUntilCompleted() => _awaiter.GetResult(); + + public override object GetResult() + { + return _awaiter.GetResult(); // Throws exceptions, if any + } + } + } +} +#endif diff --git a/src/NUnitFramework/framework/Internal/TestExecutionContext.cs b/src/NUnitFramework/framework/Internal/TestExecutionContext.cs index 27ca0570ec..f37dfc4a66 100644 --- a/src/NUnitFramework/framework/Internal/TestExecutionContext.cs +++ b/src/NUnitFramework/framework/Internal/TestExecutionContext.cs @@ -37,7 +37,7 @@ using System.Security.Principal; #endif -#if NET20 || NET35 || NET40 || NET45 +#if NET35 || NET40 || NET45 using System.Runtime.Remoting.Messaging; #endif @@ -49,7 +49,7 @@ namespace NUnit.Framework.Internal /// or which might be changed by the user tests. /// public class TestExecutionContext : LongLivedMarshalByRefObject -#if NET20 || NET35 || NET40 || NET45 +#if NET35 || NET40 || NET45 , ILogicalThreadAffinative #endif { @@ -144,7 +144,7 @@ public TestExecutionContext(TestExecutionContext other) // NOTE: We use different implementations for various platforms. -#if !(NET20 || NET35 || NET40 || NET45) +#if !(NET35 || NET40 || NET45) private static readonly AsyncLocal _currentContext = new AsyncLocal(); /// /// Gets and sets the current context. @@ -162,39 +162,37 @@ public static TestExecutionContext CurrentContext } #else // In all other builds, we use the CallContext - private static readonly string CONTEXT_KEY = "NUnit.Framework.TestContext"; - /// /// Gets and sets the current context. /// public static TestExecutionContext CurrentContext { - // This getter invokes security critical members on the 'System.Runtime.Remoting.Messaging.CallContext' class. + // This method invokes security critical members on the 'System.Runtime.Remoting.Messaging.CallContext' class. // Callers of this method have no influence on how these methods are used so we define a 'SecuritySafeCriticalAttribute' // rather than a 'SecurityCriticalAttribute' to enable use by security transparent callers. [SecuritySafeCritical] get { - var context = CallContext.GetData(CONTEXT_KEY) as TestExecutionContext; + var context = CallContext.GetData(NUnitCallContext.TestExecutionContextKey) as TestExecutionContext; if (context == null) { context = new AdhocContext(); - CallContext.SetData(CONTEXT_KEY, context); + CallContext.SetData(NUnitCallContext.TestExecutionContextKey, context); } return context; } - // This setter invokes security critical members on the 'System.Runtime.Remoting.Messaging.CallContext' class. + // This method invokes security critical members on the 'System.Runtime.Remoting.Messaging.CallContext' class. // Callers of this method have no influence on how these methods are used so we define a 'SecuritySafeCriticalAttribute' // rather than a 'SecurityCriticalAttribute' to enable use by security transparent callers. [SecuritySafeCritical] private set { if (value == null) - CallContext.FreeNamedDataSlot(CONTEXT_KEY); + CallContext.FreeNamedDataSlot(NUnitCallContext.TestExecutionContextKey); else - CallContext.SetData(CONTEXT_KEY, value); + CallContext.SetData(NUnitCallContext.TestExecutionContextKey, value); } } #endif diff --git a/src/NUnitFramework/framework/Internal/TestListener.cs b/src/NUnitFramework/framework/Internal/TestListener.cs index 7314da8b24..551e1374dd 100644 --- a/src/NUnitFramework/framework/Internal/TestListener.cs +++ b/src/NUnitFramework/framework/Internal/TestListener.cs @@ -64,6 +64,8 @@ public class TestListener : ITestListener /// /// Get a listener that does nothing /// + // ReSharper disable once InconsistentNaming + // Disregarding naming convention for back-compat public static ITestListener NULL { get { return new TestListener();} diff --git a/src/NUnitFramework/framework/Internal/TestNameGenerator.cs b/src/NUnitFramework/framework/Internal/TestNameGenerator.cs index 245cdc4d8c..31c98fdcf7 100644 --- a/src/NUnitFramework/framework/Internal/TestNameGenerator.cs +++ b/src/NUnitFramework/framework/Internal/TestNameGenerator.cs @@ -154,7 +154,7 @@ private static List BuildFragmentList(string pattern) case "{8}": case "{9}": int index = token[1] - '0'; - fragments.Add(new ArgumentFragment(index, 40)); + fragments.Add(new ArgumentFragment(index, 0)); break; default: char c = token[1]; @@ -230,9 +230,9 @@ protected static string GetDisplayString(object arg, int stringMax) var builder = new StringBuilder(); builder.Append("["); - const int MaxNumItemsToEnumerate = 5; + const int maxNumItemsToEnumerate = 5; - var numItemsToEnumerate = Math.Min(argArray.Length, MaxNumItemsToEnumerate); + var numItemsToEnumerate = Math.Min(argArray.Length, maxNumItemsToEnumerate); for (int i = 0; i < numItemsToEnumerate; i++) { if (i > 0) @@ -253,7 +253,7 @@ protected static string GetDisplayString(object arg, int stringMax) } } - if (argArray.Length > MaxNumItemsToEnumerate) + if (argArray.Length > maxNumItemsToEnumerate) builder.Append(", ..."); builder.Append("]"); diff --git a/src/NUnitFramework/framework/Internal/Tests/ParameterizedFixtureSuite.cs b/src/NUnitFramework/framework/Internal/Tests/ParameterizedFixtureSuite.cs index 37338f45f2..27193968c1 100644 --- a/src/NUnitFramework/framework/Internal/Tests/ParameterizedFixtureSuite.cs +++ b/src/NUnitFramework/framework/Internal/Tests/ParameterizedFixtureSuite.cs @@ -42,6 +42,16 @@ public ParameterizedFixtureSuite(ITypeInfo typeInfo) : base(typeInfo.Namespace, _genericFixture = typeInfo.ContainsGenericParameters; } + /// + /// Creates a copy of the given suite with only the descendants that pass the specified filter. + /// + /// The to copy. + /// Determines which descendants are copied. + public ParameterizedFixtureSuite(ParameterizedFixtureSuite suite, ITestFilter filter) + : base(suite, filter) + { + } + /// /// Gets a string representing the type of test /// @@ -54,5 +64,14 @@ public override string TestType : "ParameterizedFixture"; } } + + /// + /// Creates a filtered copy of the test suite. + /// + /// Determines which descendants are copied. + public override TestSuite Copy(ITestFilter filter) + { + return new ParameterizedFixtureSuite(this, filter); + } } } diff --git a/src/NUnitFramework/framework/Internal/Tests/ParameterizedMethodSuite.cs b/src/NUnitFramework/framework/Internal/Tests/ParameterizedMethodSuite.cs index 87783a16f6..e377c99d37 100644 --- a/src/NUnitFramework/framework/Internal/Tests/ParameterizedMethodSuite.cs +++ b/src/NUnitFramework/framework/Internal/Tests/ParameterizedMethodSuite.cs @@ -44,6 +44,16 @@ public ParameterizedMethodSuite(IMethodInfo method) this.MaintainTestOrder = true; } + /// + /// Creates a copy of the given suite with only the descendants that pass the specified filter. + /// + /// The to copy. + /// Determines which descendants are copied. + public ParameterizedMethodSuite(ParameterizedMethodSuite suite, ITestFilter filter) + : base(suite, filter) + { + } + /// /// Gets a string representing the type of test /// @@ -60,5 +70,14 @@ public override string TestType return "ParameterizedMethod"; } } + + /// + /// Creates a filtered copy of the test suite. + /// + /// Determines which descendants are copied. + public override TestSuite Copy(ITestFilter filter) + { + return new ParameterizedMethodSuite(this, filter); + } } } diff --git a/src/NUnitFramework/framework/Internal/Tests/SetUpFixture.cs b/src/NUnitFramework/framework/Internal/Tests/SetUpFixture.cs index 44e0efcdcf..8b34a102ac 100644 --- a/src/NUnitFramework/framework/Internal/Tests/SetUpFixture.cs +++ b/src/NUnitFramework/framework/Internal/Tests/SetUpFixture.cs @@ -52,6 +52,29 @@ public SetUpFixture(ITypeInfo type) : base(type) CheckSetUpTearDownMethods(OneTimeTearDownMethods); } + /// + /// Creates a copy of the given suite with only the descendants that pass the specified filter. + /// + /// The to copy. + /// Determines which descendants are copied. + public SetUpFixture(SetUpFixture setUpFixture, ITestFilter filter) + : base(setUpFixture, filter) + { + } + + #endregion + + #region Test Suite Overrides + + /// + /// Creates a filtered copy of the test suite. + /// + /// Determines which descendants are copied. + public override TestSuite Copy(ITestFilter filter) + { + return new SetUpFixture(this, filter); + } + #endregion } } diff --git a/src/NUnitFramework/framework/Internal/Tests/TestAssembly.cs b/src/NUnitFramework/framework/Internal/Tests/TestAssembly.cs index 22cbde800f..a6c5b4eada 100644 --- a/src/NUnitFramework/framework/Internal/Tests/TestAssembly.cs +++ b/src/NUnitFramework/framework/Internal/Tests/TestAssembly.cs @@ -21,8 +21,8 @@ // WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. // *********************************************************************** +using System.IO; using System.Reflection; - using NUnit.Framework.Interfaces; namespace NUnit.Framework.Internal @@ -38,30 +38,32 @@ public class TestAssembly : TestSuite /// specifying the Assembly and the suite name. /// /// The assembly this test represents. - /// The desired name for the test suite. - public TestAssembly(Assembly assembly, string name) - : base(name) + /// + /// This becomes the full name of the suite and the filename part is used as the suite name. + /// + public TestAssembly(Assembly assembly, string assemblyNameOrPath) + : this(assemblyNameOrPath) { this.Assembly = assembly; - this.Name = name; } /// /// Initializes a new instance of the class /// specifying the suite name for an assembly that could not be loaded. /// - /// The desired name for the test suite. - public TestAssembly(string name) : base(name) + /// + /// This becomes the full name of the suite and the filename part is used as the suite name. + /// + public TestAssembly(string assemblyNameOrPath) : base(assemblyNameOrPath) { - this.Name = name; + this.Name = Path.GetFileName(assemblyNameOrPath); } /// - /// Copy-constructor style to create a filtered copy of the test assemblies - /// test cases + /// Creates a copy of the given assembly with only the descendants that pass the specified filter. /// - /// - /// + /// The to copy. + /// Determines which descendants are copied. public TestAssembly(TestAssembly assembly, ITestFilter filter) : base(assembly as TestSuite, filter) { @@ -95,6 +97,15 @@ public override TAttr[] GetCustomAttributes(bool inherit) ? Assembly.GetAttributes() : new TAttr[0]; } + + /// + /// Creates a filtered copy of the test suite. + /// + /// Determines which descendants are copied. + public override TestSuite Copy(ITestFilter filter) + { + return new TestAssembly(this, filter); + } } } diff --git a/src/NUnitFramework/framework/Internal/Tests/TestFixture.cs b/src/NUnitFramework/framework/Internal/Tests/TestFixture.cs index 65df13e401..23b6f8e0d2 100644 --- a/src/NUnitFramework/framework/Internal/Tests/TestFixture.cs +++ b/src/NUnitFramework/framework/Internal/Tests/TestFixture.cs @@ -51,6 +51,29 @@ public TestFixture(ITypeInfo fixtureType, object[] arguments = null) : base(fixt CheckSetUpTearDownMethods(TearDownMethods); } + /// + /// Creates a copy of the given suite with only the descendants that pass the specified filter. + /// + /// The to copy. + /// Determines which descendants are copied. + private TestFixture(TestFixture fixture, ITestFilter filter) + : base(fixture, filter) + { + } + + #endregion + + #region Test Suite Overrides + + /// + /// Creates a filtered copy of the test suite. + /// + /// Determines which descendants are copied. + public override TestSuite Copy(ITestFilter filter) + { + return new TestFixture(this, filter); + } + #endregion } } diff --git a/src/NUnitFramework/framework/Internal/Tests/TestSuite.cs b/src/NUnitFramework/framework/Internal/Tests/TestSuite.cs index 413e49a7a4..2ddb90837b 100644 --- a/src/NUnitFramework/framework/Internal/Tests/TestSuite.cs +++ b/src/NUnitFramework/framework/Internal/Tests/TestSuite.cs @@ -25,11 +25,6 @@ using System.Collections.Generic; using System.Reflection; using NUnit.Framework.Interfaces; -using NUnit.Framework.Internal.Commands; - -#if ASYNC -using System.Threading.Tasks; -#endif namespace NUnit.Framework.Internal { @@ -99,10 +94,10 @@ public TestSuite(Type fixtureType) } /// - /// Copy constructor style to create a filtered copy of the given test suite + /// Creates a copy of the given suite with only the descendants that pass the specified filter. /// - /// Test Suite to copy - /// Filter to be applied + /// The to copy. + /// Determines which descendants are copied. public TestSuite(TestSuite suite, ITestFilter filter) : base(suite.Name) { @@ -117,7 +112,7 @@ public TestSuite(TestSuite suite, ITestFilter filter) { if(child.IsSuite) { - TestSuite childSuite = new TestSuite(child as TestSuite, filter); + TestSuite childSuite = ((TestSuite)child).Copy(filter); childSuite.Parent = this; this.tests.Add(childSuite); } @@ -179,6 +174,15 @@ public void Add(Test test) tests.Add(test); } + /// + /// Creates a filtered copy of the test suite. + /// + /// Determines which descendants are copied. + public virtual TestSuite Copy(ITestFilter filter) + { + return new TestSuite(this, filter); + } + #endregion #region Properties @@ -300,19 +304,32 @@ public override TNode AddToXml(TNode parentNode, bool recursive) protected void CheckSetUpTearDownMethods(MethodInfo[] methods) { foreach (MethodInfo method in methods) - if (method.IsAbstract || - !method.IsPublic && !method.IsFamily || - method.GetParameters().Length > 0 || - method.ReturnType != typeof(void) -#if ASYNC - && - method.ReturnType != typeof(Task) -#endif - ) + { + if (method.IsAbstract) { - this.MakeInvalid(string.Format("Invalid signature for SetUp or TearDown method: {0}", method.Name)); - break; + MakeInvalid("An abstract SetUp and TearDown methods cannot be run: " + method.Name); } + else if (!(method.IsPublic || method.IsFamily)) + { + MakeInvalid("SetUp and TearDown methods must be public or internal: " + method.Name); + } + else if (method.GetParameters().Length != 0) + { + MakeInvalid("SetUp and TearDown methods must not have parameters: " + method.Name); + } + else if (AsyncToSyncAdapter.IsAsyncOperation(method)) + { + if (method.ReturnType == typeof(void)) + MakeInvalid("SetUp and TearDown methods must not be async void: " + method.Name); + else if (AwaitAdapter.GetResultType(method.ReturnType) != typeof(void)) + MakeInvalid("SetUp and TearDown methods must return void or an awaitable type with a void result: " + method.Name); + } + else + { + if (method.ReturnType != typeof(void)) + MakeInvalid("SetUp and TearDown methods must return void or an awaitable type with a void result: " + method.Name); + } + } } #endregion } diff --git a/src/NUnitFramework/framework/Internal/ThreadUtility.cs b/src/NUnitFramework/framework/Internal/ThreadUtility.cs index de4a8d304e..20dadd1cd5 100644 --- a/src/NUnitFramework/framework/Internal/ThreadUtility.cs +++ b/src/NUnitFramework/framework/Internal/ThreadUtility.cs @@ -211,6 +211,8 @@ private static void PostThreadCloseMessage(int nativeId) { if (!PostThreadMessage(nativeId, WM.CLOSE, IntPtr.Zero, IntPtr.Zero)) { + // ReSharper disable once InconsistentNaming + // P/invoke doesn’t need to follow naming convention const int ERROR_INVALID_THREAD_ID = 0x5A4; var errorCode = Marshal.GetLastWin32Error(); if (errorCode != ERROR_INVALID_THREAD_ID) @@ -227,6 +229,8 @@ private static void PostThreadCloseMessage(int nativeId) private enum WM : uint { + // ReSharper disable once InconsistentNaming + // P/invoke doesn’t need to follow naming convention CLOSE = 0x0010 } #endif diff --git a/src/NUnitFramework/framework/Internal/TypeNameDifferenceResolver.cs b/src/NUnitFramework/framework/Internal/TypeNameDifferenceResolver.cs index dc31f5461e..ad56266f34 100644 --- a/src/NUnitFramework/framework/Internal/TypeNameDifferenceResolver.cs +++ b/src/NUnitFramework/framework/Internal/TypeNameDifferenceResolver.cs @@ -117,21 +117,21 @@ private void GetShortenedGenericParams(Type expectedFullType, Type actualFullTyp /// /// Obtain a shortened name of the given . /// - public string FullyShortenTypeName(Type GenericType) + public string FullyShortenTypeName(Type genericType) { - if (IsTypeGeneric(GenericType)) + if (IsTypeGeneric(genericType)) { - string genericType = GenericType.GetGenericTypeDefinition().Name; + string genericTypeDefinition = genericType.GetGenericTypeDefinition().Name; - List genericParams = new List(GenericType.GetGenericArguments()); + List genericParams = new List(genericType.GetGenericArguments()); List shortenedGenericParams = new List(); genericParams.ForEach(x => shortenedGenericParams.Add(FullyShortenTypeName(x))); - return ReconstructGenericTypeName(genericType, shortenedGenericParams); + return ReconstructGenericTypeName(genericTypeDefinition, shortenedGenericParams); } else { - return GenericType.Name; + return genericType.Name; } } @@ -207,11 +207,11 @@ public string GetGenericTypeName(Type type) /// Reconstruct a generic type name using the provided generic type name, and a /// of the template parameters. /// - /// The name of the generic type, including the number of template parameters expected. - /// A of names of the template parameters of the provided generic type. - public string ReconstructGenericTypeName(string GenericTypeName, List TemplateParamNames) + /// The name of the generic type, including the number of template parameters expected. + /// A of names of the template parameters of the provided generic type. + public string ReconstructGenericTypeName(string genericTypeName, List templateParamNames) { - return GenericTypeName + "[" + string.Join(",", TemplateParamNames.ToArray()) + "]"; + return genericTypeName + "[" + string.Join(",", templateParamNames.ToArray()) + "]"; } /// diff --git a/src/NUnitFramework/framework/Internal/ValueGenerator.ByteValueGenerator.cs b/src/NUnitFramework/framework/Internal/ValueGenerator.ByteValueGenerator.cs index 4478500ef9..a777a9c884 100644 --- a/src/NUnitFramework/framework/Internal/ValueGenerator.ByteValueGenerator.cs +++ b/src/NUnitFramework/framework/Internal/ValueGenerator.ByteValueGenerator.cs @@ -31,7 +31,7 @@ public override bool TryCreateStep(object value, out ValueGenerator.Step step) { if (value is byte) { - step = new ComparableStep((byte)value, (prev, stepValue) => unchecked((byte)(prev + stepValue))); + step = new ComparableStep((byte)value, (prev, stepValue) => checked((byte)(prev + stepValue))); return true; } @@ -40,7 +40,7 @@ public override bool TryCreateStep(object value, out ValueGenerator.Step step) // -1 can be converted natively to Int16, SByte and Decimal, so we can fall back on the automatic conversion for them. if (value is int) { - step = new ComparableStep((int)value, (prev, stepValue) => unchecked((byte)(prev + stepValue))); + step = new ComparableStep((int)value, (prev, stepValue) => checked((byte)(prev + stepValue))); return true; } diff --git a/src/NUnitFramework/framework/Properties/AssemblyInfo.cs b/src/NUnitFramework/framework/Properties/AssemblyInfo.cs index 4db23a4310..5e272dd133 100644 --- a/src/NUnitFramework/framework/Properties/AssemblyInfo.cs +++ b/src/NUnitFramework/framework/Properties/AssemblyInfo.cs @@ -56,8 +56,6 @@ [assembly: AssemblyTitle("NUnit Framework (.NET Framework 4.0)")] #elif NET35 [assembly: AssemblyTitle("NUnit Framework (.NET Framework 3.5)")] -#elif NET20 -[assembly: AssemblyTitle("NUnit Framework (.NET Framework 2.0)")] #elif NETSTANDARD1_4 [assembly: AssemblyTitle("NUnit Framework (.NET Standard 1.4)")] #elif NETSTANDARD2_0 diff --git a/src/NUnitFramework/framework/StringAssert.cs b/src/NUnitFramework/framework/StringAssert.cs index 99141d163f..c7cac24d71 100644 --- a/src/NUnitFramework/framework/StringAssert.cs +++ b/src/NUnitFramework/framework/StringAssert.cs @@ -8,10 +8,10 @@ // 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 @@ -37,7 +37,7 @@ public abstract class StringAssert /// /// DO NOT USE! Use StringAssert.AreEqualIgnoringCase(...) or Assert.AreEqual(...) instead. - /// The Equals method throws an InvalidOperationException. This is done + /// The Equals method throws an InvalidOperationException. This is done /// to make sure there is no mistake by calling this function. /// /// @@ -45,12 +45,12 @@ public abstract class StringAssert [EditorBrowsable(EditorBrowsableState.Never)] public static new bool Equals(object a, object b) { - throw new InvalidOperationException("StringAssert.Equals should not be used for Assertions, use StringAssert.AreEqualIgnoringCase(...) or Assert.AreEqual(...) instead."); + throw new InvalidOperationException("StringAssert.Equals should not be used. Use StringAssert.AreEqualIgnoringCase or Assert.AreEqual instead."); } /// /// DO NOT USE! - /// The ReferenceEquals method throws an InvalidOperationException. This is done + /// The ReferenceEquals method throws an InvalidOperationException. This is done /// to make sure there is no mistake by calling this function. /// /// @@ -58,7 +58,7 @@ public static new bool Equals(object a, object b) [EditorBrowsable(EditorBrowsableState.Never)] public static new void ReferenceEquals(object a, object b) { - throw new InvalidOperationException("StringAssert.ReferenceEquals should not be used for Assertions."); + throw new InvalidOperationException("StringAssert.ReferenceEquals should not be used."); } #endregion @@ -302,7 +302,7 @@ static public void IsMatch(string pattern, string actual) static public void DoesNotMatch(string pattern, string actual, string message, params object[] args) { Assert.That(actual, Does.Not.Match(pattern), message, args); - } + } /// /// Asserts that a string does not match an expected regular expression pattern. diff --git a/src/NUnitFramework/framework/TestContext.cs b/src/NUnitFramework/framework/TestContext.cs index 475fe702db..8ee34fd67d 100644 --- a/src/NUnitFramework/framework/TestContext.cs +++ b/src/NUnitFramework/framework/TestContext.cs @@ -121,7 +121,7 @@ public ResultAdapter Result /// public string WorkerId { - get { return _testExecutionContext.TestWorker.Name; } + get { return _testExecutionContext.TestWorker?.Name; } } #endif @@ -337,11 +337,11 @@ public static void AddTestAttachment(string filePath, string description = null) /// is the only criterion for selection of the formatter, since /// it can be used without getting involved with a compound function. /// - /// The type supported by this formatter + /// The type supported by this formatter /// The ValueFormatter delegate - public static void AddFormatter(ValueFormatter formatter) + public static void AddFormatter(ValueFormatter formatter) { - AddFormatter(next => val => (val is TSUPPORTED) ? formatter(val) : next(val)); + AddFormatter(next => val => (val is TSupported) ? formatter(val) : next(val)); } #endregion diff --git a/src/NUnitFramework/framework/Warn.cs b/src/NUnitFramework/framework/Warn.cs index 51d3406f8d..799ece3fe0 100644 --- a/src/NUnitFramework/framework/Warn.cs +++ b/src/NUnitFramework/framework/Warn.cs @@ -8,10 +8,10 @@ // 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 @@ -29,7 +29,7 @@ namespace NUnit.Framework { /// - /// Provides static methods to express conditions + /// Provides static methods to express conditions /// that must be met for the test to succeed. If /// any test fails, a warning is issued. /// @@ -39,7 +39,7 @@ public class Warn /// /// DO NOT USE! - /// The Equals method throws an InvalidOperationException. This is done + /// The Equals method throws an InvalidOperationException. This is done /// to make sure there is no mistake by calling this function. /// /// The left object. @@ -48,12 +48,12 @@ public class Warn [EditorBrowsable(EditorBrowsableState.Never)] public static new bool Equals(object a, object b) { - throw new InvalidOperationException("Warn.Equals should not be used for Assertions."); + throw new InvalidOperationException("Warn.Equals should not be used."); } /// /// DO NOT USE! - /// The ReferenceEquals method throws an InvalidOperationException. This is done + /// The ReferenceEquals method throws an InvalidOperationException. This is done /// to make sure there is no mistake by calling this function. /// /// The left object. @@ -61,7 +61,7 @@ public static new bool Equals(object a, object b) [EditorBrowsable(EditorBrowsableState.Never)] public static new void ReferenceEquals(object a, object b) { - throw new InvalidOperationException("Warn.ReferenceEquals should not be used for Assertions."); + throw new InvalidOperationException("Warn.ReferenceEquals should not be used."); } #endregion @@ -109,7 +109,6 @@ private static void IssueWarning(ConstraintResult result, string message, object Assert.Warn(writer.ToString()); } -#if !NET20 /// /// Apply a constraint to an actual value, succeeding if the constraint /// is satisfied and issuing a warning on failure. @@ -131,7 +130,6 @@ private static void IssueWarning(ConstraintResult result, string message, object if (!result.IsSuccess) IssueWarning(result, getExceptionMessage(), null); } -#endif #endregion @@ -139,7 +137,7 @@ private static void IssueWarning(ConstraintResult result, string message, object /// /// Asserts that a condition is true. If the condition is false a warning is issued. - /// + /// /// The evaluated condition /// The message to display if the condition is false /// Arguments to be used in formatting the message @@ -149,7 +147,7 @@ public static void Unless(bool condition, string message, params object[] args) } /// - /// Asserts that a condition is true. If the condition is false a warning is issued. + /// Asserts that a condition is true. If the condition is false a warning is issued. /// /// The evaluated condition public static void Unless(bool condition) @@ -157,27 +155,24 @@ public static void Unless(bool condition) Warn.Unless(condition, Is.True, null, null); } -#if !NET20 /// /// Asserts that a condition is true. If the condition is false a warning is issued. - /// + /// /// The evaluated condition /// A function to build the message included with the Exception public static void Unless(bool condition, Func getExceptionMessage) { Warn.Unless(condition, Is.True, getExceptionMessage); } -#endif #endregion #region Lambda returning Boolean -#if !NET20 /// /// Asserts that a condition is true. If the condition is false the method throws /// an . - /// + /// /// A lambda that returns a Boolean /// The message to display if the condition is false /// Arguments to be used in formatting the message @@ -199,14 +194,13 @@ public static void Unless(Func condition) /// /// Asserts that a condition is true. If the condition is false the method throws /// an . - /// + /// /// A lambda that returns a Boolean /// A function to build the message included with the Exception public static void Unless(Func condition, Func getExceptionMessage) { Warn.Unless(condition.Invoke(), Is.True, getExceptionMessage); } -#endif #endregion @@ -259,7 +253,6 @@ public static void Unless(TActual actual, IResolveConstraint expression IssueWarning(result, message, args); } -#if !NET20 /// /// Apply a constraint to an actual value, succeeding if the constraint /// is satisfied and issuing a warning on failure. @@ -281,7 +274,6 @@ public static void Unless(TActual actual, IResolveConstraint expression if (!result.IsSuccess) IssueWarning(result, getExceptionMessage(), null); } -#endif #endregion @@ -330,7 +322,6 @@ public static void If(ActualValueDelegate del, IResolveConstra // Assert.Warn(writer.ToString()); //} -#if !NET20 /// /// Apply a constraint to an actual value, succeeding if the constraint /// fails and issuing a warning on failure. @@ -352,7 +343,6 @@ public static void If(ActualValueDelegate del, IResolveConstra if (!result.IsSuccess) IssueWarning(result, getExceptionMessage(), null); } -#endif #endregion @@ -360,7 +350,7 @@ public static void If(ActualValueDelegate del, IResolveConstra /// /// Asserts that a condition is true. If the condition is false a warning is issued. - /// + /// /// The evaluated condition /// The message to display if the condition is false /// Arguments to be used in formatting the message @@ -370,7 +360,7 @@ public static void If(bool condition, string message, params object[] args) } /// - /// Asserts that a condition is true. If the condition is false a warning is issued. + /// Asserts that a condition is true. If the condition is false a warning is issued. /// /// The evaluated condition public static void If(bool condition) @@ -378,26 +368,23 @@ public static void If(bool condition) Warn.If(condition, Is.True, null, null); } -#if !NET20 /// /// Asserts that a condition is true. If the condition is false a warning is issued. - /// + /// /// The evaluated condition /// A function to build the message included with the Exception public static void If(bool condition, Func getExceptionMessage) { Warn.If(condition, Is.True, getExceptionMessage); } -#endif #endregion #region Lambda returning Boolean -#if !NET20 /// /// Asserts that a condition is false. If the condition is true a warning is issued. - /// + /// /// A lambda that returns a Boolean /// The message to display if the condition is true /// Arguments to be used in formatting the message @@ -417,14 +404,13 @@ public static void If(Func condition) /// /// Asserts that a condition is false. If the condition is true a warning is issued. - /// + /// /// A lambda that returns a Boolean /// A function to build the message included with the Exception public static void If(Func condition, Func getExceptionMessage) { Warn.If(condition.Invoke(), Is.True, getExceptionMessage); } -#endif #endregion @@ -462,7 +448,6 @@ public static void If(TActual actual, IResolveConstraint expression, st IssueWarning(result, message, args); } -#if !NET20 /// /// Apply a constraint to an actual value, succeeding if the constraint /// is satisfied and issuing a warning on failure. @@ -484,7 +469,6 @@ public static void If(TActual actual, IResolveConstraint expression, st if (!result.IsSuccess) IssueWarning(result, getExceptionMessage(), null); } -#endif #endregion diff --git a/src/NUnitFramework/framework/nunit.framework.csproj b/src/NUnitFramework/framework/nunit.framework.csproj index 3ba2ffe322..0059668395 100644 --- a/src/NUnitFramework/framework/nunit.framework.csproj +++ b/src/NUnitFramework/framework/nunit.framework.csproj @@ -1,32 +1,24 @@ - + - net20;net35;net40;net45;netstandard1.4;netstandard2.0 + net35;net40;net45;netstandard1.4;netstandard2.0 NUnit.Framework true - - full - true - - - - - - + - + diff --git a/src/NUnitFramework/mock-assembly/mock-assembly.csproj b/src/NUnitFramework/mock-assembly/mock-assembly.csproj index e8c75fb8cc..3ce7bbbff9 100644 --- a/src/NUnitFramework/mock-assembly/mock-assembly.csproj +++ b/src/NUnitFramework/mock-assembly/mock-assembly.csproj @@ -1,7 +1,7 @@  - net20;net35;net40;net45;netcoreapp1.1;netcoreapp2.0 + net35;net40;net45;netcoreapp1.1;netcoreapp2.0 NUnit.Tests diff --git a/src/NUnitFramework/nunitlite-runner/nunitlite-runner.csproj b/src/NUnitFramework/nunitlite-runner/nunitlite-runner.csproj index 11c2870f00..9a70a7dfb4 100644 --- a/src/NUnitFramework/nunitlite-runner/nunitlite-runner.csproj +++ b/src/NUnitFramework/nunitlite-runner/nunitlite-runner.csproj @@ -1,7 +1,7 @@  - net20;net35;net40;net45;netcoreapp1.1;netcoreapp2.0 + net35;net40;net45;netcoreapp1.1;netcoreapp2.0 Exe NUnitLite diff --git a/src/NUnitFramework/nunitlite.tests/SchemaTests.cs b/src/NUnitFramework/nunitlite.tests/SchemaTests.cs index 04afd9d309..8c9be5b4c6 100644 --- a/src/NUnitFramework/nunitlite.tests/SchemaTests.cs +++ b/src/NUnitFramework/nunitlite.tests/SchemaTests.cs @@ -22,9 +22,9 @@ // *********************************************************************** -#if !NETCOREAPP1_1 // Schema validation doesn’t exist -#if !(NET20 || NET35) // Framework bug causes NRE: https://social.msdn.microsoft.com/Forums/en-US/53be44de-30b2-4d18-968d-d3414d0783b1 - // We don’t really need these tests to run on more than one platform. +#if !NETCOREAPP1_1 // Schema validation doesn’t exist +#if !NET35 // Framework bug causes NRE: https://social.msdn.microsoft.com/Forums/en-US/53be44de-30b2-4d18-968d-d3414d0783b1 + // We don’t really need these tests to run on more than one platform. using System.Collections.Generic; using System.IO; diff --git a/src/NUnitFramework/nunitlite.tests/TextUITests.cs b/src/NUnitFramework/nunitlite.tests/TextUITests.cs index 752fee3c9e..a3d8b0a0c0 100644 --- a/src/NUnitFramework/nunitlite.tests/TextUITests.cs +++ b/src/NUnitFramework/nunitlite.tests/TextUITests.cs @@ -1,4 +1,4 @@ -// *********************************************************************** +// *********************************************************************** // Copyright (c) 2015-2017 Charlie Poole, Rob Prouse // // Permission is hereby granted, free of charge, to any person obtaining @@ -249,7 +249,7 @@ public void SuiteFinished(string labelsOption, TestStatus resultStatus, string r } #pragma warning disable 414 - static TestCaseData[] ImmediateOutputData = new[] { + static readonly TestCaseData[] ImmediateOutputData = new[] { new TestCaseData("Off", new [] { new TestOutput("OUTPUT\n", "", null, "SomeMethod") }, "OUTPUT\n"), diff --git a/src/NUnitFramework/nunitlite.tests/nunitlite.tests.csproj b/src/NUnitFramework/nunitlite.tests/nunitlite.tests.csproj index 665abedd0e..e79407c21e 100644 --- a/src/NUnitFramework/nunitlite.tests/nunitlite.tests.csproj +++ b/src/NUnitFramework/nunitlite.tests/nunitlite.tests.csproj @@ -1,7 +1,7 @@ - net20;net35;net40;net45;netcoreapp1.1;netcoreapp2.0 + net35;net40;net45;netcoreapp1.1;netcoreapp2.0 Exe NUnitLite.Tests Full diff --git a/src/NUnitFramework/nunitlite/ColorConsoleWriter.cs b/src/NUnitFramework/nunitlite/ColorConsoleWriter.cs index 06762cd60a..89020a5a08 100644 --- a/src/NUnitFramework/nunitlite/ColorConsoleWriter.cs +++ b/src/NUnitFramework/nunitlite/ColorConsoleWriter.cs @@ -1,4 +1,4 @@ -// *********************************************************************** +// *********************************************************************** // Copyright (c) 2014 Charlie Poole, Rob Prouse // // Permission is hereby granted, free of charge, to any person obtaining @@ -29,6 +29,8 @@ namespace NUnit.Common { public class ColorConsoleWriter : ExtendedTextWrapper { + // ReSharper disable once InconsistentNaming + // Disregarding naming convention for back-compat public bool _colorEnabled; /// diff --git a/src/NUnitFramework/nunitlite/Options.cs b/src/NUnitFramework/nunitlite/Options.cs index 2221738456..5e5bcb34af 100644 --- a/src/NUnitFramework/nunitlite/Options.cs +++ b/src/NUnitFramework/nunitlite/Options.cs @@ -4,7 +4,7 @@ // Authors: // Jonathan Pryor // -// Copyright (C) 2008 Novell (http://www.novell.com) +// Copyright (C) 2008 Novell (https://www.novell.com) // // Permission is hereby granted, free of charge, to any person obtaining // a copy of this software and associated documentation files (the @@ -515,7 +515,7 @@ public override void GetObjectData (SerializationInfo info, StreamingContext con public class OptionSet : KeyedCollection { - string localizer(string msg) + string Localizer(string msg) { return msg; } @@ -536,7 +536,7 @@ protected override string GetKeyForItem (Option item) throw new InvalidOperationException ("Option has no names!"); } - [Obsolete ("Use KeyedCollection.this[string]")] + [Obsolete("This method has been deprecated and will be removed in a future release. Please use the default indexer instead.")] protected Option GetOptionForName (string option) { if (option == null) @@ -742,7 +742,7 @@ private static bool Unprocessed (ICollection extra, Option def, OptionCo return false; } - private readonly Regex ValueOption = new Regex ( + private readonly static Regex ValueOption = new Regex( @"^(?--|-|/)(?[^:=]+)((?[:=])(?.*))?$"); protected bool GetOptionParts (string argument, out string flag, out string name, out string sep, out string value) @@ -814,7 +814,7 @@ private void ParseValue (string option, OptionContext c) c.Option.OptionValueType == OptionValueType.Optional) c.Option.Invoke (c); else if (c.OptionValues.Count > c.Option.MaxValueCount) { - throw new OptionException (localizer (string.Format ( + throw new OptionException (Localizer (string.Format ( "Error: Found {0} option values when expecting {1}.", c.OptionValues.Count, c.Option.MaxValueCount)), c.OptionName); @@ -849,7 +849,7 @@ private bool ParseBundledValue (string f, string n, OptionContext c) if (!Contains (rn)) { if (i == 0) return false; - throw new OptionException (string.Format (localizer ( + throw new OptionException (string.Format (Localizer ( "Cannot bundle unregistered option '{0}'."), opt), opt); } p = this [rn]; @@ -898,7 +898,7 @@ public void WriteOptionDescriptions (TextWriter o) bool indent = false; string prefix = new string (' ', OptionWidth+2); - foreach (string line in GetLines (localizer (GetDescription (p.Description)))) { + foreach (string line in GetLines (Localizer (GetDescription (p.Description)))) { if (indent) o.Write (prefix); o.WriteLine (line); @@ -934,17 +934,17 @@ bool WriteOptionPrototype (TextWriter o, Option p, ref int written) if (p.OptionValueType == OptionValueType.Optional || p.OptionValueType == OptionValueType.Required) { if (p.OptionValueType == OptionValueType.Optional) { - Write (o, ref written, localizer ("[")); + Write (o, ref written, Localizer ("[")); } - Write (o, ref written, localizer ("=" + GetArgumentName (0, p.MaxValueCount, p.Description))); + Write (o, ref written, Localizer ("=" + GetArgumentName (0, p.MaxValueCount, p.Description))); string sep = p.ValueSeparators != null && p.ValueSeparators.Length > 0 ? p.ValueSeparators [0] : " "; for (int c = 1; c < p.MaxValueCount; ++c) { - Write (o, ref written, localizer (sep + GetArgumentName (c, p.MaxValueCount, p.Description))); + Write (o, ref written, Localizer (sep + GetArgumentName (c, p.MaxValueCount, p.Description))); } if (p.OptionValueType == OptionValueType.Optional) { - Write (o, ref written, localizer ("]")); + Write (o, ref written, Localizer ("]")); } } return true; diff --git a/src/NUnitFramework/nunitlite/Properties/AssemblyInfo.cs b/src/NUnitFramework/nunitlite/Properties/AssemblyInfo.cs index 0da4638e91..2bb2aa2b52 100644 --- a/src/NUnitFramework/nunitlite/Properties/AssemblyInfo.cs +++ b/src/NUnitFramework/nunitlite/Properties/AssemblyInfo.cs @@ -38,8 +38,6 @@ [assembly: AssemblyTitle("NUnitLite Runner (.NET Framework 4.0)")] #elif NET35 [assembly: AssemblyTitle("NUnitLite Runner (.NET Framework 3.5)")] -#elif NET20 -[assembly: AssemblyTitle("NUnitLite Runner (.NET Framework 2.0)")] #elif NETSTANDARD1_4 [assembly: AssemblyTitle("NUnitLite Runner (.NET Standard 1.4)")] #elif NETSTANDARD2_0 diff --git a/src/NUnitFramework/nunitlite/TextRunner.cs b/src/NUnitFramework/nunitlite/TextRunner.cs index 8322042148..697ec3ecdb 100644 --- a/src/NUnitFramework/nunitlite/TextRunner.cs +++ b/src/NUnitFramework/nunitlite/TextRunner.cs @@ -428,7 +428,7 @@ private void InitializeInternalTrace() private string GetLogFileName() { - const string LOG_FILE_FORMAT = "InternalTrace.{0}.{1}.{2}"; + const string logFileFormat = "InternalTrace.{0}.{1}.{2}"; // Some mobiles don't have an Open With menu item, // so we use .txt, which is opened easily. @@ -445,7 +445,7 @@ private string GetLogFileName() var id = Process.GetCurrentProcess().Id; #endif - return string.Format(LOG_FILE_FORMAT, id, baseName, ext); + return string.Format(logFileFormat, id, baseName, ext); } #endregion diff --git a/src/NUnitFramework/nunitlite/TextUI.cs b/src/NUnitFramework/nunitlite/TextUI.cs index bd2a261a68..bca4cd9f25 100644 --- a/src/NUnitFramework/nunitlite/TextUI.cs +++ b/src/NUnitFramework/nunitlite/TextUI.cs @@ -73,7 +73,7 @@ public void DisplayHeader() Assembly executingAssembly = GetType().GetTypeInfo().Assembly; AssemblyName assemblyName = AssemblyHelper.GetAssemblyName(executingAssembly); Version version = assemblyName.Version; - string copyright = "Copyright (C) 2018 Charlie Poole, Rob Prouse"; + string copyright = "Copyright (C) 2019 Charlie Poole, Rob Prouse"; string build = ""; var copyrightAttr = executingAssembly.GetCustomAttribute(); @@ -511,27 +511,27 @@ private void DisplayTestResult(ITestResult result) string fullName = result.FullName; string message = result.Message; string stackTrace = result.StackTrace; - string reportID = (++_reportIndex).ToString(); + string reportId = (++_reportIndex).ToString(); int numAsserts = result.AssertionResults.Count; if (numAsserts > 0) { int assertionCounter = 0; - string assertID = reportID; + string assertId = reportId; foreach (var assertion in result.AssertionResults) { if (numAsserts > 1) - assertID = string.Format("{0}-{1}", reportID, ++assertionCounter); + assertId = string.Format("{0}-{1}", reportId, ++assertionCounter); ColorStyle style = GetColorStyle(resultState); string status = assertion.Status.ToString(); - DisplayTestResult(style, assertID, status, fullName, assertion.Message, assertion.StackTrace); + DisplayTestResult(style, assertId, status, fullName, assertion.Message, assertion.StackTrace); } } else { ColorStyle style = GetColorStyle(resultState); string status = GetResultStatus(resultState); - DisplayTestResult(style, reportID, status, fullName, message, stackTrace); + DisplayTestResult(style, reportId, status, fullName, message, stackTrace); } } diff --git a/src/NUnitFramework/nunitlite/Tokenizer.cs b/src/NUnitFramework/nunitlite/Tokenizer.cs index f6c9c053e3..56feb30ff8 100644 --- a/src/NUnitFramework/nunitlite/Tokenizer.cs +++ b/src/NUnitFramework/nunitlite/Tokenizer.cs @@ -109,7 +109,7 @@ public class Tokenizer private const char EOF_CHAR = '\0'; private const string WORD_BREAK_CHARS = "=!()&|"; - private readonly string[] DOUBLE_CHAR_SYMBOLS = new string[] { "==", "=~", "!=", "!~", "&&", "||" }; + private static readonly string[] DOUBLE_CHAR_SYMBOLS = new string[] { "==", "=~", "!=", "!~", "&&", "||" }; private Token _lookahead; diff --git a/src/NUnitFramework/nunitlite/nunitlite.csproj b/src/NUnitFramework/nunitlite/nunitlite.csproj index 1f016905e5..f43b7d270a 100644 --- a/src/NUnitFramework/nunitlite/nunitlite.csproj +++ b/src/NUnitFramework/nunitlite/nunitlite.csproj @@ -1,23 +1,14 @@  - net20;net35;net40;net45;netstandard1.4;netstandard2.0 + net35;net40;net45;netstandard1.4;netstandard2.0 NUnitLite - - full - true - - - - - - diff --git a/src/NUnitFramework/slow-tests/slow-nunit-tests.csproj b/src/NUnitFramework/slow-tests/slow-nunit-tests.csproj index 9c340f663e..42681b37db 100644 --- a/src/NUnitFramework/slow-tests/slow-nunit-tests.csproj +++ b/src/NUnitFramework/slow-tests/slow-nunit-tests.csproj @@ -1,7 +1,7 @@  - net20;net35;net40;net45;netcoreapp1.1;netcoreapp2.0 + net35;net40;net45;netcoreapp1.1;netcoreapp2.0 NUnit.Tests diff --git a/src/NUnitFramework/testdata/ApartmentData.cs b/src/NUnitFramework/testdata/ApartmentData.cs new file mode 100644 index 0000000000..2c4d6ff1be --- /dev/null +++ b/src/NUnitFramework/testdata/ApartmentData.cs @@ -0,0 +1,40 @@ +// *********************************************************************** +// Copyright (c) 2018 Charlie Poole, Rob Prouse +// +// 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.Threading; +using NUnit.Framework; + +namespace NUnit.TestData +{ +#if APARTMENT_STATE + [RequiresThread(ApartmentState.Unknown)] + public class ApartmentDataRequiresThreadAttribute + { + } + + [Apartment(ApartmentState.Unknown)] + public class ApartmentDataApartmentAttribute + { + } +#endif +} diff --git a/src/NUnitFramework/testdata/AssertMultipleData.cs b/src/NUnitFramework/testdata/AssertMultipleData.cs index 318c4ba80b..a32fb7da1b 100644 --- a/src/NUnitFramework/testdata/AssertMultipleData.cs +++ b/src/NUnitFramework/testdata/AssertMultipleData.cs @@ -1,7 +1,7 @@ using System; using NUnit.Framework; -#if ASYNC +#if TASK_PARALLEL_LIBRARY_API using System.Threading.Tasks; #if NET40 using Task = System.Threading.Tasks.TaskEx; @@ -11,8 +11,8 @@ namespace NUnit.TestData.AssertMultipleData { // NOTE: Some of these methods were getting optimized out of - // existence in the .NET 2.0 AppVeyor build. For that reason, - // we turned optimization off for the testdata assembly. + // existence in the AppVeyor build. For that reason, we turned + // optimization off for the testdata assembly. public class AssertMultipleFixture { @@ -353,7 +353,7 @@ public void AssumptionInBlock() }); } -#if ASYNC +#if TASK_PARALLEL_LIBRARY_API [Test] public void ThreeAssertsSucceed_Async() { diff --git a/src/NUnitFramework/testdata/AsyncDummyFixture.cs b/src/NUnitFramework/testdata/AsyncDummyFixture.cs index e9139307c9..7d07ee5f3d 100644 --- a/src/NUnitFramework/testdata/AsyncDummyFixture.cs +++ b/src/NUnitFramework/testdata/AsyncDummyFixture.cs @@ -21,7 +21,7 @@ // WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. // *********************************************************************** -#if ASYNC +#if TASK_PARALLEL_LIBRARY_API using System.Threading.Tasks; using NUnit.Framework; using System; diff --git a/src/NUnitFramework/testdata/AsyncExecutionApiAdapter.Fixture-based.cs b/src/NUnitFramework/testdata/AsyncExecutionApiAdapter.Fixture-based.cs index 4a751f3c73..b33eb280af 100644 --- a/src/NUnitFramework/testdata/AsyncExecutionApiAdapter.Fixture-based.cs +++ b/src/NUnitFramework/testdata/AsyncExecutionApiAdapter.Fixture-based.cs @@ -21,7 +21,7 @@ // WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. // *********************************************************************** -#if ASYNC +#if TASK_PARALLEL_LIBRARY_API using System.Threading.Tasks; using NUnit.Framework; diff --git a/src/NUnitFramework/testdata/AsyncRealFixture.cs b/src/NUnitFramework/testdata/AsyncRealFixture.cs index 7eb57fe5e2..68ecd46049 100644 --- a/src/NUnitFramework/testdata/AsyncRealFixture.cs +++ b/src/NUnitFramework/testdata/AsyncRealFixture.cs @@ -8,10 +8,10 @@ // 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 @@ -21,7 +21,7 @@ // WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. // *********************************************************************** -#if ASYNC +#if TASK_PARALLEL_LIBRARY_API using System; using System.Threading.Tasks; using NUnit.Framework; @@ -30,6 +30,9 @@ using Task = System.Threading.Tasks.TaskEx; #endif +// Don’t warn when async is used without await +#pragma warning disable CS1998 + namespace NUnit.TestData { public class AsyncRealFixture @@ -68,9 +71,30 @@ public async System.Threading.Tasks.Task AsyncTaskError() Assert.Fail("Should never get here"); } -#endregion + [Test] + public async System.Threading.Tasks.Task AsyncTaskPass() + { + Assert.Pass(); + throw new Exception("This test expects Assert.Pass() to throw an exception."); + } + + [Test] + public async System.Threading.Tasks.Task AsyncTaskIgnore() + { + Assert.Ignore(); + throw new Exception("This test expects Assert.Ignore() to throw an exception."); + } + + [Test] + public async System.Threading.Tasks.Task AsyncTaskInconclusive() + { + Assert.Inconclusive(); + throw new Exception("This test expects Assert.Inconclusive() to throw an exception."); + } -#region non-async Task + #endregion + + #region non-async Task [Test] public System.Threading.Tasks.Task TaskSuccess() @@ -90,7 +114,28 @@ public System.Threading.Tasks.Task TaskError() throw new InvalidOperationException(); } -#endregion + [Test] + public System.Threading.Tasks.Task TaskPass() + { + Assert.Pass(); + throw new Exception("This test expects Assert.Pass() to throw an exception."); + } + + [Test] + public System.Threading.Tasks.Task TaskIgnore() + { + Assert.Ignore(); + throw new Exception("This test expects Assert.Ignore() to throw an exception."); + } + + [Test] + public System.Threading.Tasks.Task TaskInconclusive() + { + Assert.Inconclusive(); + throw new Exception("This test expects Assert.Inconclusive() to throw an exception."); + } + + #endregion [Test] @@ -253,4 +298,4 @@ private static Task ThrowException() } } } -#endif \ No newline at end of file +#endif diff --git a/src/NUnitFramework/testdata/AsyncSetupTearDownFixture.cs b/src/NUnitFramework/testdata/AsyncSetupTearDownFixture.cs index 17207439f5..1ae71e0e2b 100644 --- a/src/NUnitFramework/testdata/AsyncSetupTearDownFixture.cs +++ b/src/NUnitFramework/testdata/AsyncSetupTearDownFixture.cs @@ -1,4 +1,4 @@ -#if ASYNC +#if TASK_PARALLEL_LIBRARY_API using System; using System.Threading.Tasks; diff --git a/src/NUnitFramework/testdata/AsyncWorkload.cs b/src/NUnitFramework/testdata/AsyncWorkload.cs new file mode 100644 index 0000000000..909193052c --- /dev/null +++ b/src/NUnitFramework/testdata/AsyncWorkload.cs @@ -0,0 +1,56 @@ +using System; + +namespace NUnit.TestData +{ + public struct AsyncWorkload + { + private readonly Action _beforeReturningAwaitable; + private readonly Action _beforeReturningAwaiter; + private readonly Func _isCompleted; + private readonly Action _onCompleted; + private readonly Func _getResult; + + public AsyncWorkload(bool isCompleted, Action onCompleted, Func getResult) + : this(null, null, () => isCompleted, onCompleted, getResult) + { + } + + public AsyncWorkload(Func isCompleted, Action onCompleted, Func getResult) + : this(null, null, isCompleted, onCompleted, getResult) + { + } + + public AsyncWorkload( + Action beforeReturningAwaitable, + Action beforeReturningAwaiter, + Func isCompleted, + Action onCompleted, + Func getResult) + { + _beforeReturningAwaitable = beforeReturningAwaitable; + _beforeReturningAwaiter = beforeReturningAwaiter; + _isCompleted = isCompleted; + _onCompleted = onCompleted; + _getResult = getResult; + } + + public void BeforeReturningAwaitable() => _beforeReturningAwaitable?.Invoke(); + + public void BeforeReturningAwaiter() => _beforeReturningAwaiter?.Invoke(); + + public bool IsCompleted => _isCompleted.Invoke(); + + public void OnCompleted(Action continuation) + { + if (IsCompleted) + continuation.Invoke(); + else + _onCompleted.Invoke(continuation); + } + + public object GetResult() + { + return _getResult.Invoke(); + } + } +} diff --git a/src/NUnitFramework/testdata/AttributeInheritanceData.cs b/src/NUnitFramework/testdata/AttributeInheritanceData.cs index bfa29c0c2c..769be81888 100644 --- a/src/NUnitFramework/testdata/AttributeInheritanceData.cs +++ b/src/NUnitFramework/testdata/AttributeInheritanceData.cs @@ -53,7 +53,7 @@ class SpecAttribute : TestAttribute public class When_collecting_test_fixtures { [Spec] - public void should_include_classes_with_an_attribute_derived_from_TestFixtureAttribute() + public void Should_include_classes_with_an_attribute_derived_from_TestFixtureAttribute() { } } diff --git a/src/NUnitFramework/testdata/AwaitableReturnTypeFixture.cs b/src/NUnitFramework/testdata/AwaitableReturnTypeFixture.cs new file mode 100644 index 0000000000..a81800c2a0 --- /dev/null +++ b/src/NUnitFramework/testdata/AwaitableReturnTypeFixture.cs @@ -0,0 +1,388 @@ +using System; +using System.Runtime.CompilerServices; +using NUnit.Framework; + +#if TASK_PARALLEL_LIBRARY_API +using System.Threading.Tasks; +#endif + +namespace NUnit.TestData +{ + public sealed class AwaitableReturnTypeFixture + { + private readonly AsyncWorkload _workload; + + public AwaitableReturnTypeFixture(AsyncWorkload workload) + { + _workload = workload; + } + + #region Void result + +#if TASK_PARALLEL_LIBRARY_API +#pragma warning disable 1998 + public Task ReturnsTask() +#pragma warning restore 1998 + { + _workload.BeforeReturningAwaitable(); + _workload.BeforeReturningAwaiter(); + + var source = new TaskCompletionSource(); + + var complete = new Action(() => + { + try + { + _workload.GetResult(); + source.SetResult(null); + } + catch (Exception ex) + { + source.SetException(ex); + } + }); + + if (_workload.IsCompleted) + complete.Invoke(); + else + _workload.OnCompleted(complete); + + return source.Task; + } + + public CustomTask ReturnsCustomTask() + { + _workload.BeforeReturningAwaitable(); + _workload.BeforeReturningAwaiter(); + + var task = new CustomTask(() => _workload.GetResult()); + + if (_workload.IsCompleted) + task.Start(); + else + _workload.OnCompleted(task.Start); + + return task; + } + + public sealed class CustomTask : Task + { + public CustomTask(Action action) : base(action) + { + } + } +#endif + + public CustomAwaitable ReturnsCustomAwaitable() + { + _workload.BeforeReturningAwaitable(); + return new CustomAwaitable(_workload); + } + + public struct CustomAwaitable + { + private readonly AsyncWorkload _workload; + + public CustomAwaitable(AsyncWorkload workload) + { + _workload = workload; + } + + public CustomAwaiter GetAwaiter() + { + _workload.BeforeReturningAwaiter(); + return new CustomAwaiter(_workload); + } + + public struct CustomAwaiter : ICriticalNotifyCompletion + { + private readonly AsyncWorkload _workload; + + public CustomAwaiter(AsyncWorkload workload) + { + _workload = workload; + } + + public bool IsCompleted => _workload.IsCompleted; + + public void OnCompleted(Action continuation) + { + Assert.Fail("This method should not be used because UnsafeOnCompleted is available."); + } + + public void UnsafeOnCompleted(Action continuation) => _workload.OnCompleted(continuation); + + public void GetResult() => _workload.GetResult(); + } + } + + public CustomAwaitableWithImplicitOnCompleted ReturnsCustomAwaitableWithImplicitOnCompleted() + { + _workload.BeforeReturningAwaitable(); + return new CustomAwaitableWithImplicitOnCompleted(_workload); + } + + public struct CustomAwaitableWithImplicitOnCompleted + { + private readonly AsyncWorkload _workload; + + public CustomAwaitableWithImplicitOnCompleted(AsyncWorkload workload) + { + _workload = workload; + } + + public CustomAwaiterWithImplicitOnCompleted GetAwaiter() + { + _workload.BeforeReturningAwaiter(); + return new CustomAwaiterWithImplicitOnCompleted(_workload); + } + + public struct CustomAwaiterWithImplicitOnCompleted : INotifyCompletion + { + private readonly AsyncWorkload _workload; + + public CustomAwaiterWithImplicitOnCompleted(AsyncWorkload workload) + { + _workload = workload; + } + + public bool IsCompleted => _workload.IsCompleted; + + void INotifyCompletion.OnCompleted(Action continuation) => _workload.OnCompleted(continuation); + + public void GetResult() => _workload.GetResult(); + } + } + + public CustomAwaitableWithImplicitUnsafeOnCompleted ReturnsCustomAwaitableWithImplicitUnsafeOnCompleted() + { + _workload.BeforeReturningAwaitable(); + return new CustomAwaitableWithImplicitUnsafeOnCompleted(_workload); + } + + public struct CustomAwaitableWithImplicitUnsafeOnCompleted + { + private readonly AsyncWorkload _workload; + + public CustomAwaitableWithImplicitUnsafeOnCompleted(AsyncWorkload workload) + { + _workload = workload; + } + + public CustomAwaiterWithImplicitUnsafeOnCompleted GetAwaiter() + { + _workload.BeforeReturningAwaiter(); + return new CustomAwaiterWithImplicitUnsafeOnCompleted(_workload); + } + + public struct CustomAwaiterWithImplicitUnsafeOnCompleted : ICriticalNotifyCompletion + { + private readonly AsyncWorkload _workload; + + public CustomAwaiterWithImplicitUnsafeOnCompleted(AsyncWorkload workload) + { + _workload = workload; + } + + public bool IsCompleted => _workload.IsCompleted; + + public void OnCompleted(Action continuation) + { + Assert.Fail("This method should not be used because UnsafeOnCompleted is available."); + } + + void ICriticalNotifyCompletion.UnsafeOnCompleted(Action continuation) => _workload.OnCompleted(continuation); + + public void GetResult() => _workload.GetResult(); + } + } + + #endregion + + #region Non-void result + +#if TASK_PARALLEL_LIBRARY_API +#pragma warning disable 1998 + [Test(ExpectedResult = 42)] + public Task ReturnsNonVoidResultTask() +#pragma warning restore 1998 + { + _workload.BeforeReturningAwaitable(); + _workload.BeforeReturningAwaiter(); + + var source = new TaskCompletionSource(); + + var complete = new Action(() => + { + try + { + source.SetResult(_workload.GetResult()); + } + catch (Exception ex) + { + source.SetException(ex); + } + }); + + if (_workload.IsCompleted) + complete.Invoke(); + else + _workload.OnCompleted(complete); + + return source.Task; + } + + [Test(ExpectedResult = 42)] + public NonVoidResultCustomTask ReturnsNonVoidResultCustomTask() + { + _workload.BeforeReturningAwaitable(); + _workload.BeforeReturningAwaiter(); + + var task = new NonVoidResultCustomTask(_workload.GetResult); + + if (_workload.IsCompleted) + task.Start(); + else + _workload.OnCompleted(task.Start); + + return task; + } + + public sealed class NonVoidResultCustomTask : Task + { + public NonVoidResultCustomTask(Func function) : base(function) + { + } + } +#endif + + [Test(ExpectedResult = 42)] + public NonVoidResultCustomAwaitable ReturnsNonVoidResultCustomAwaitable() + { + _workload.BeforeReturningAwaitable(); + return new NonVoidResultCustomAwaitable(_workload); + } + + public struct NonVoidResultCustomAwaitable + { + private readonly AsyncWorkload _workload; + + public NonVoidResultCustomAwaitable(AsyncWorkload workload) + { + _workload = workload; + } + + public NonVoidResultCustomAwaiter GetAwaiter() + { + _workload.BeforeReturningAwaiter(); + return new NonVoidResultCustomAwaiter(_workload); + } + + public struct NonVoidResultCustomAwaiter : ICriticalNotifyCompletion + { + private readonly AsyncWorkload _workload; + + public NonVoidResultCustomAwaiter(AsyncWorkload workload) + { + _workload = workload; + } + + public bool IsCompleted => _workload.IsCompleted; + + public void OnCompleted(Action continuation) + { + Assert.Fail("This method should not be used because UnsafeOnCompleted is available."); + } + + public void UnsafeOnCompleted(Action continuation) => _workload.OnCompleted(continuation); + + public object GetResult() => _workload.GetResult(); + } + } + + [Test(ExpectedResult = 42)] + public NonVoidResultCustomAwaitableWithImplicitOnCompleted ReturnsNonVoidResultCustomAwaitableWithImplicitOnCompleted() + { + _workload.BeforeReturningAwaitable(); + return new NonVoidResultCustomAwaitableWithImplicitOnCompleted(_workload); + } + + public struct NonVoidResultCustomAwaitableWithImplicitOnCompleted + { + private readonly AsyncWorkload _workload; + + public NonVoidResultCustomAwaitableWithImplicitOnCompleted(AsyncWorkload workload) + { + _workload = workload; + } + + public NonVoidResultCustomAwaiterWithImplicitOnCompleted GetAwaiter() + { + _workload.BeforeReturningAwaiter(); + return new NonVoidResultCustomAwaiterWithImplicitOnCompleted(_workload); + } + + public struct NonVoidResultCustomAwaiterWithImplicitOnCompleted : INotifyCompletion + { + private readonly AsyncWorkload _workload; + + public NonVoidResultCustomAwaiterWithImplicitOnCompleted(AsyncWorkload workload) + { + _workload = workload; + } + + public bool IsCompleted => _workload.IsCompleted; + + void INotifyCompletion.OnCompleted(Action continuation) => _workload.OnCompleted(continuation); + + public object GetResult() => _workload.GetResult(); + } + } + + [Test(ExpectedResult = 42)] + public NonVoidResultCustomAwaitableWithImplicitUnsafeOnCompleted ReturnsNonVoidResultCustomAwaitableWithImplicitUnsafeOnCompleted() + { + _workload.BeforeReturningAwaitable(); + return new NonVoidResultCustomAwaitableWithImplicitUnsafeOnCompleted(_workload); + } + + public struct NonVoidResultCustomAwaitableWithImplicitUnsafeOnCompleted + { + private readonly AsyncWorkload _workload; + + public NonVoidResultCustomAwaitableWithImplicitUnsafeOnCompleted(AsyncWorkload workload) + { + _workload = workload; + } + + public NonVoidResultCustomAwaiterWithImplicitUnsafeOnCompleted GetAwaiter() + { + _workload.BeforeReturningAwaiter(); + return new NonVoidResultCustomAwaiterWithImplicitUnsafeOnCompleted(_workload); + } + + public struct NonVoidResultCustomAwaiterWithImplicitUnsafeOnCompleted : ICriticalNotifyCompletion + { + private readonly AsyncWorkload _workload; + + public NonVoidResultCustomAwaiterWithImplicitUnsafeOnCompleted(AsyncWorkload workload) + { + _workload = workload; + } + + public bool IsCompleted => _workload.IsCompleted; + + public void OnCompleted(Action continuation) + { + Assert.Fail("This method should not be used because UnsafeOnCompleted is available."); + } + + void ICriticalNotifyCompletion.UnsafeOnCompleted(Action continuation) => _workload.OnCompleted(continuation); + + public object GetResult() => _workload.GetResult(); + } + } + + #endregion + } +} diff --git a/src/NUnitFramework/testdata/OneTimeSetUpTearDownData.cs b/src/NUnitFramework/testdata/OneTimeSetUpTearDownData.cs index 6db6513799..6c03ef2a99 100644 --- a/src/NUnitFramework/testdata/OneTimeSetUpTearDownData.cs +++ b/src/NUnitFramework/testdata/OneTimeSetUpTearDownData.cs @@ -30,22 +30,22 @@ namespace NUnit.TestData.OneTimeSetUpTearDownData [TestFixture] public class SetUpAndTearDownFixture { - public int setUpCount = 0; - public int tearDownCount = 0; - public bool throwInBaseSetUp = false; + public int SetUpCount = 0; + public int TearDownCount = 0; + public bool ThrowInBaseSetUp = false; [OneTimeSetUp] public virtual void Init() { - setUpCount++; - if (throwInBaseSetUp) + SetUpCount++; + if (ThrowInBaseSetUp) throw new Exception("Error in base OneTimeSetUp"); } [OneTimeTearDown] public virtual void Destroy() { - tearDownCount++; + TearDownCount++; } [Test] @@ -58,19 +58,19 @@ public virtual void Destroy() [TestFixture] public class SetUpAndTearDownFixtureWithTestCases { - public int setUpCount = 0; - public int tearDownCount = 0; + public int SetUpCount = 0; + public int TearDownCount = 0; [OneTimeSetUp] public virtual void Init() { - setUpCount++; + SetUpCount++; } [OneTimeTearDown] public virtual void Destroy() { - tearDownCount++; + TearDownCount++; } [TestCase(1)] @@ -86,19 +86,19 @@ public void Success(int i) [TestFixture] public class SetUpAndTearDownFixtureWithTheories { - public int setUpCount = 0; - public int tearDownCount = 0; + public int SetUpCount = 0; + public int TearDownCount = 0; [OneTimeSetUp] public virtual void Init() { - setUpCount++; + SetUpCount++; } [OneTimeTearDown] public virtual void Destroy() { - tearDownCount++; + TearDownCount++; } public struct Data @@ -107,7 +107,7 @@ public struct Data } [DatapointSource] - public IEnumerable fetchAllRows() + public IEnumerable FetchAllRows() { yield return new Data { Id = 1 }; yield return new Data { Id = 2 }; @@ -125,19 +125,19 @@ public void TheoryTest(Data entry) [TestFixture, Explicit] public class ExplicitSetUpAndTearDownFixture { - public int setUpCount = 0; - public int tearDownCount = 0; + public int SetUpCount = 0; + public int TearDownCount = 0; [OneTimeSetUp] public virtual void Init() { - setUpCount++; + SetUpCount++; } [OneTimeTearDown] public virtual void Destroy() { - tearDownCount++; + TearDownCount++; } [Test] @@ -160,19 +160,19 @@ public class InheritSetUpAndTearDown : SetUpAndTearDownFixture [TestFixture] public class OverrideSetUpAndTearDown : SetUpAndTearDownFixture { - public int derivedSetUpCount; - public int derivedTearDownCount; + public int DerivedSetUpCount; + public int DerivedTearDownCount; [OneTimeSetUp] public override void Init() { - derivedSetUpCount++; + DerivedSetUpCount++; } [OneTimeTearDown] public override void Destroy() { - derivedTearDownCount++; + DerivedTearDownCount++; } [Test] @@ -185,24 +185,24 @@ public override void Destroy() [TestFixture] public class DerivedSetUpAndTearDownFixture : SetUpAndTearDownFixture { - public int derivedSetUpCount; - public int derivedTearDownCount; + public int DerivedSetUpCount; + public int DerivedTearDownCount; - public bool baseSetUpCalledFirst; - public bool baseTearDownCalledLast; + public bool BaseSetUpCalledFirst; + public bool BaseTearDownCalledLast; [OneTimeSetUp] public void Init2() { - derivedSetUpCount++; - baseSetUpCalledFirst = this.setUpCount > 0; + DerivedSetUpCount++; + BaseSetUpCalledFirst = this.SetUpCount > 0; } [OneTimeTearDown] public void Destroy2() { - derivedTearDownCount++; - baseTearDownCalledLast = this.tearDownCount == 0; + DerivedTearDownCount++; + BaseTearDownCalledLast = this.TearDownCount == 0; } [Test] @@ -215,19 +215,19 @@ public void Destroy2() [TestFixture] public class StaticSetUpAndTearDownFixture { - public static int setUpCount = 0; - public static int tearDownCount = 0; + public static int SetUpCount = 0; + public static int TearDownCount = 0; [OneTimeSetUp] public static void Init() { - setUpCount++; + SetUpCount++; } [OneTimeTearDown] public static void Destroy() { - tearDownCount++; + TearDownCount++; } [Test] @@ -237,25 +237,25 @@ public static void Destroy() [TestFixture] public class DerivedStaticSetUpAndTearDownFixture : StaticSetUpAndTearDownFixture { - public static int derivedSetUpCount; - public static int derivedTearDownCount; + public static int DerivedSetUpCount; + public static int DerivedTearDownCount; - public static bool baseSetUpCalledFirst; - public static bool baseTearDownCalledLast; + public static bool BaseSetUpCalledFirst; + public static bool BaseTearDownCalledLast; [OneTimeSetUp] public static void Init2() { - derivedSetUpCount++; - baseSetUpCalledFirst = setUpCount > 0; + DerivedSetUpCount++; + BaseSetUpCalledFirst = SetUpCount > 0; } [OneTimeTearDown] public static void Destroy2() { - derivedTearDownCount++; - baseTearDownCalledLast = tearDownCount == 0; + DerivedTearDownCount++; + BaseTearDownCalledLast = TearDownCount == 0; } [Test] @@ -265,19 +265,19 @@ public static void Destroy2() [TestFixture] public static class StaticClassSetUpAndTearDownFixture { - public static int setUpCount = 0; - public static int tearDownCount = 0; + public static int SetUpCount = 0; + public static int TearDownCount = 0; [OneTimeSetUp] public static void Init() { - setUpCount++; + SetUpCount++; } [OneTimeTearDown] public static void Destroy() { - tearDownCount++; + TearDownCount++; } [Test] @@ -298,42 +298,42 @@ public class FixtureWithParallelizableOnOneTimeSetUp [TestFixture] public class MisbehavingFixture { - public bool blowUpInSetUp = false; - public bool blowUpInTest = false; - public bool blowUpInTearDown = false; + public bool BlowUpInSetUp = false; + public bool BlowUpInTest = false; + public bool BlowUpInTearDown = false; - public int setUpCount = 0; - public int tearDownCount = 0; + public int SetUpCount = 0; + public int TearDownCount = 0; public void Reinitialize() { - setUpCount = 0; - tearDownCount = 0; + SetUpCount = 0; + TearDownCount = 0; - blowUpInSetUp = false; - blowUpInTearDown = false; + BlowUpInSetUp = false; + BlowUpInTearDown = false; } [OneTimeSetUp] - public void BlowUpInSetUp() + public void SetUp() { - setUpCount++; - if (blowUpInSetUp) + SetUpCount++; + if (BlowUpInSetUp) throw new Exception("This was thrown from fixture setup"); } [OneTimeTearDown] - public void BlowUpInTearDown() + public void TearDown() { - tearDownCount++; - if ( blowUpInTearDown ) + TearDownCount++; + if (BlowUpInTearDown) throw new Exception("This was thrown from fixture teardown"); } [Test] - public void BlowUpInTest() + public void Test() { - if (blowUpInTest) + if (BlowUpInTest) throw new Exception("This was thrown from a test"); } } @@ -347,7 +347,7 @@ public ExceptionInConstructor() } [Test] - public void nothingToTest() + public void NothingToTest() { } } @@ -362,7 +362,7 @@ public void SetUpCallsIgnore() } [Test] - public void nothingToTest() + public void NothingToTest() { } } @@ -370,19 +370,19 @@ public void nothingToTest() [TestFixture] public class SetUpAndTearDownWithTestInName { - public int setUpCount = 0; - public int tearDownCount = 0; + public int SetUpCount = 0; + public int TearDownCount = 0; [OneTimeSetUp] public virtual void OneTimeSetUp() { - setUpCount++; + SetUpCount++; } [OneTimeTearDown] public virtual void OneTimeTearDown() { - tearDownCount++; + TearDownCount++; } [Test] @@ -395,19 +395,19 @@ public virtual void OneTimeTearDown() [TestFixture, Ignore( "Do Not Run This" )] public class IgnoredFixture { - public bool setupCalled = false; - public bool teardownCalled = false; + public bool SetupCalled = false; + public bool TeardownCalled = false; [OneTimeSetUp] public virtual void ShouldNotRun() { - setupCalled = true; + SetupCalled = true; } [OneTimeTearDown] public virtual void NeitherShouldThis() { - teardownCalled = true; + TeardownCalled = true; } [Test] @@ -420,26 +420,26 @@ public virtual void NeitherShouldThis() [TestFixture] public class FixtureWithNoTests { - public bool setupCalled = false; - public bool teardownCalled = false; + public bool SetupCalled = false; + public bool TeardownCalled = false; [OneTimeSetUp] public virtual void Init() { - setupCalled = true; + SetupCalled = true; } [OneTimeTearDown] public virtual void Destroy() { - teardownCalled = true; + TeardownCalled = true; } } [TestFixture] public class DisposableFixture : IDisposable { - public int disposeCalled = 0; + public int DisposeCalled = 0; public List Actions = new List(); [OneTimeSetUp] @@ -460,14 +460,14 @@ public void OneTimeTearDown() public void Dispose() { Actions.Add("Dispose"); - disposeCalled++; + DisposeCalled++; } } [TestFixture] public class DisposableFixtureWithTestCases : IDisposable { - public int disposeCalled = 0; + public int DisposeCalled = 0; [TestCase(1)] [TestCase(2)] @@ -477,7 +477,7 @@ public class DisposableFixtureWithTestCases : IDisposable public void Dispose() { - disposeCalled++; + DisposeCalled++; } } } diff --git a/src/NUnitFramework/testdata/Polyfills.cs b/src/NUnitFramework/testdata/Polyfills.cs new file mode 100644 index 0000000000..26725197d1 --- /dev/null +++ b/src/NUnitFramework/testdata/Polyfills.cs @@ -0,0 +1,18 @@ +#if NET35 + +// ReSharper disable CheckNamespace + +namespace System.Runtime.CompilerServices +{ + internal interface INotifyCompletion + { + void OnCompleted(Action continuation); + } + + internal interface ICriticalNotifyCompletion : INotifyCompletion + { + void UnsafeOnCompleted(Action continuation); + } +} + +#endif diff --git a/src/NUnitFramework/testdata/RepeatedTestFixture.cs b/src/NUnitFramework/testdata/RepeatedTestFixture.cs index cb1ec7b019..bb48aee261 100644 --- a/src/NUnitFramework/testdata/RepeatedTestFixture.cs +++ b/src/NUnitFramework/testdata/RepeatedTestFixture.cs @@ -38,7 +38,7 @@ public class RepeatSuccessFixture : RepeatingTestsFixtureBase [Test, Repeat(3)] public void RepeatSuccess() { - count++; + Count++; Assert.IsTrue (true); } } @@ -48,7 +48,7 @@ public class RepeatFailOnFirstTryFixture : RepeatingTestsFixtureBase [Test, Repeat(3)] public void RepeatFailOnFirst() { - count++; + Count++; Assert.IsFalse (true); } } @@ -58,9 +58,9 @@ public class RepeatFailOnSecondTryFixture : RepeatingTestsFixtureBase [Test, Repeat(3)] public void RepeatFailOnThird() { - count++; + Count++; - if (count == 2) + if (Count == 2) Assert.IsTrue(false); } } @@ -70,9 +70,9 @@ public class RepeatFailOnThirdTryFixture : RepeatingTestsFixtureBase [Test, Repeat(3)] public void RepeatFailOnThird() { - count++; + Count++; - if (count == 3) + if (Count == 3) Assert.IsTrue(false); } } @@ -91,7 +91,7 @@ public class RepeatIgnoredOnFirstTryFixture : RepeatingTestsFixtureBase [Test, Repeat(3)] public void Test() { - count++; + Count++; Assert.Ignore("Ignoring"); } } @@ -101,9 +101,9 @@ public class RepeatIgnoredOnSecondTryFixture : RepeatingTestsFixtureBase [Test, Repeat(3)] public void Test() { - count++; + Count++; - if (count == 2) + if (Count == 2) Assert.Ignore("Ignoring"); } } @@ -113,9 +113,9 @@ public class RepeatIgnoredOnThirdTryFixture : RepeatingTestsFixtureBase [Test, Repeat(3)] public void Test() { - count++; + Count++; - if (count == 3) + if (Count == 3) Assert.Ignore("Ignoring"); } } @@ -125,7 +125,7 @@ public class RepeatErrorOnFirstTryFixture : RepeatingTestsFixtureBase [Test, Repeat(3)] public void Test() { - count++; + Count++; throw new Exception("Deliberate Exception"); } } @@ -135,9 +135,9 @@ public class RepeatErrorOnSecondTryFixture : RepeatingTestsFixtureBase [Test, Repeat(3)] public void Test() { - count++; + Count++; - if (count == 2) + if (Count == 2) throw new Exception("Deliberate Exception"); } } @@ -147,9 +147,9 @@ public class RepeatErrorOnThirdTryFixture : RepeatingTestsFixtureBase [Test, Repeat(3)] public void Test() { - count++; + Count++; - if (count == 3) + if (Count == 3) throw new Exception("Deliberate Exception"); } } @@ -159,7 +159,7 @@ public class RepeatedTestWithCategory : RepeatingTestsFixtureBase [Test, Repeat(3), Category("SAMPLE")] public void TestWithCategory() { - count++; + Count++; Assert.IsTrue(true); } } diff --git a/src/NUnitFramework/testdata/RepeatingTestsFixtureBase.cs b/src/NUnitFramework/testdata/RepeatingTestsFixtureBase.cs index 1458ab1524..376165b636 100644 --- a/src/NUnitFramework/testdata/RepeatingTestsFixtureBase.cs +++ b/src/NUnitFramework/testdata/RepeatingTestsFixtureBase.cs @@ -36,7 +36,6 @@ public class RepeatingTestsFixtureBase private int setupCount; private int teardownCount; private readonly List tearDownResults = new List(); - protected int count; [OneTimeSetUp] public void FixtureSetUp() @@ -84,9 +83,6 @@ public List TearDownResults { get { return tearDownResults; } } - public int Count - { - get { return count; } - } + public int Count { get; protected set; } } } diff --git a/src/NUnitFramework/testdata/RetryFixture.cs b/src/NUnitFramework/testdata/RetryFixture.cs index f662bb1267..0f34ec1bee 100644 --- a/src/NUnitFramework/testdata/RetryFixture.cs +++ b/src/NUnitFramework/testdata/RetryFixture.cs @@ -32,7 +32,7 @@ public class RetrySucceedsOnFirstTryFixture : RepeatingTestsFixtureBase [Test, Retry(3)] public void SucceedsEveryTime() { - count++; + Count++; Assert.IsTrue(true); } } @@ -42,7 +42,7 @@ public class RetryFailsEveryTimeFixture : RepeatingTestsFixtureBase [Test, Retry(3)] public void FailsEveryTime() { - count++; + Count++; Assert.IsFalse(true); } } @@ -52,9 +52,9 @@ public class RetrySucceedsOnSecondTryFixture : RepeatingTestsFixtureBase [Test, Retry(3)] public void SucceedsOnSecondTry() { - count++; + Count++; - if (count < 2) + if (Count < 2) Assert.IsTrue(false); } } @@ -64,9 +64,9 @@ public class RetrySucceedsOnThirdTryFixture : RepeatingTestsFixtureBase [Test, Retry(3)] public void SucceedsOnThirdTry() { - count++; + Count++; - if (count < 3) + if (Count < 3) Assert.IsTrue(false); } } @@ -85,7 +85,7 @@ public class RetryIgnoredOnFirstTryFixture : RepeatingTestsFixtureBase [Test, Retry(3)] public void Test() { - count++; + Count++; Assert.Ignore("Ignoring"); } } @@ -95,9 +95,9 @@ public class RetryIgnoredOnSecondTryFixture : RepeatingTestsFixtureBase [Test, Retry(3)] public void Test() { - count++; + Count++; - if (count < 2) + if (Count < 2) Assert.Fail("Failed"); Assert.Ignore("Ignoring"); @@ -109,9 +109,9 @@ public class RetryIgnoredOnThirdTryFixture : RepeatingTestsFixtureBase [Test, Retry(3)] public void Test() { - count++; + Count++; - if (count < 3) + if (Count < 3) Assert.Fail("Failed"); Assert.Ignore("Ignoring"); @@ -123,7 +123,7 @@ public class RetryErrorOnFirstTryFixture : RepeatingTestsFixtureBase [Test, Retry(3)] public void Test() { - count++; + Count++; throw new Exception("Deliberate Exception"); } } @@ -133,9 +133,9 @@ public class RetryErrorOnSecondTryFixture : RepeatingTestsFixtureBase [Test, Retry(3)] public void Test() { - count++; + Count++; - if (count < 2) + if (Count < 2) Assert.Fail("Failed"); throw new Exception("Deliberate Exception"); @@ -147,9 +147,9 @@ public class RetryErrorOnThirdTryFixture : RepeatingTestsFixtureBase [Test, Retry(3)] public void Test() { - count++; + Count++; - if (count < 3) + if (Count < 3) Assert.Fail("Failed"); throw new Exception("Deliberate Exception"); @@ -161,7 +161,7 @@ public class RetryTestWithCategoryFixture : RepeatingTestsFixtureBase [Test, Retry(3), Category("SAMPLE")] public void TestWithCategory() { - count++; + Count++; Assert.IsTrue(true); } } @@ -172,7 +172,7 @@ public class RetryTestCaseFixture : RepeatingTestsFixtureBase [TestCase(0)] public void FailsEveryTime(int unused) { - count++; + Count++; Assert.IsTrue(false); } } @@ -210,17 +210,17 @@ public class RetryTestVerifyAttempt : RepeatingTestsFixtureBase [Test, Retry(3)] public void NeverPasses() { - count = TestContext.CurrentContext.CurrentRepeatCount; + Count = TestContext.CurrentContext.CurrentRepeatCount; Assert.Fail("forcing a failure so we retry maximum times"); } [Test, Retry(3)] public void PassesOnLastRetry() { - Assert.That(count, Is.EqualTo(TestContext.CurrentContext.CurrentRepeatCount), "expected CurrentRepeatCount to be incremented only after first attempt"); - if (count < 2) // second Repeat is 3rd Retry (i.e. end of attempts) + Assert.That(Count, Is.EqualTo(TestContext.CurrentContext.CurrentRepeatCount), "expected CurrentRepeatCount to be incremented only after first attempt"); + if (Count < 2) // second Repeat is 3rd Retry (i.e. end of attempts) { - count++; + Count++; Assert.Fail("forced failure so we will use maximum number of Retries for PassesOnLastRetry"); } } diff --git a/src/NUnitFramework/testdata/SetUpData.cs b/src/NUnitFramework/testdata/SetUpData.cs index fbbda2f7ff..976101ec5d 100644 --- a/src/NUnitFramework/testdata/SetUpData.cs +++ b/src/NUnitFramework/testdata/SetUpData.cs @@ -29,22 +29,22 @@ namespace NUnit.TestData.SetUpData [TestFixture] public class SetUpAndTearDownFixture { - public bool wasSetUpCalled; - public bool wasTearDownCalled; - public bool throwInBaseSetUp; + public bool WasSetUpCalled; + public bool WasTearDownCalled; + public bool ThrowInBaseSetUp; [SetUp] public virtual void Init() { - wasSetUpCalled = true; - if (throwInBaseSetUp) + WasSetUpCalled = true; + if (ThrowInBaseSetUp) throw (new Exception("Exception in base setup")); } [TearDown] public virtual void Destroy() { - wasTearDownCalled = true; + WasTearDownCalled = true; } [Test] @@ -55,19 +55,19 @@ public virtual void Destroy() [TestFixture] public class SetUpAndTearDownCounterFixture { - public int setUpCounter; - public int tearDownCounter; + public int SetUpCounter; + public int TearDownCounter; [SetUp] public virtual void Init() { - setUpCounter++; + SetUpCounter++; } [TearDown] public virtual void Destroy() { - tearDownCounter++; + TearDownCounter++; } [Test] @@ -90,19 +90,19 @@ public class InheritSetUpAndTearDown : SetUpAndTearDownFixture [TestFixture] public class DefineInheritSetUpAndTearDown : SetUpAndTearDownFixture { - public bool derivedSetUpCalled; - public bool derivedTearDownCalled; + public bool DerivedSetUpCalled; + public bool DerivedTearDownCalled; [SetUp] public override void Init() { - derivedSetUpCalled = true; + DerivedSetUpCalled = true; } [TearDown] public override void Destroy() { - derivedTearDownCalled = true; + DerivedTearDownCalled = true; } [Test] @@ -111,37 +111,37 @@ public override void Destroy() public class MultipleSetUpTearDownFixture { - public bool wasSetUp1Called; - public bool wasSetUp2Called; - public bool wasSetUp3Called; - public bool wasTearDown1Called; - public bool wasTearDown2Called; + public bool WasSetUp1Called; + public bool WasSetUp2Called; + public bool WasSetUp3Called; + public bool WasTearDown1Called; + public bool WasTearDown2Called; [SetUp] public virtual void Init1() { - wasSetUp1Called = true; + WasSetUp1Called = true; } [SetUp] public virtual void Init2() { - wasSetUp2Called = true; + WasSetUp2Called = true; } [SetUp] public virtual void Init3() { - wasSetUp3Called = true; + WasSetUp3Called = true; } [TearDown] public virtual void TearDown1() { - wasTearDown1Called = true; + WasTearDown1Called = true; } [TearDown] public virtual void TearDown2() { - wasTearDown2Called = true; + WasTearDown2Called = true; } [Test] @@ -151,42 +151,42 @@ public virtual void TearDown2() [TestFixture] public class DerivedClassWithSeparateSetUp : SetUpAndTearDownFixture { - public bool wasDerivedSetUpCalled; - public bool wasDerivedTearDownCalled; - public bool wasBaseSetUpCalledFirst; - public bool wasBaseTearDownCalledLast; + public bool WasDerivedSetUpCalled; + public bool WasDerivedTearDownCalled; + public bool WasBaseSetUpCalledFirst; + public bool WasBaseTearDownCalledLast; [SetUp] public void DerivedInit() { - wasDerivedSetUpCalled = true; - wasBaseSetUpCalledFirst = wasSetUpCalled; + WasDerivedSetUpCalled = true; + WasBaseSetUpCalledFirst = WasSetUpCalled; } [TearDown] public void DerivedTearDown() { - wasDerivedTearDownCalled = true; - wasBaseTearDownCalledLast = !wasTearDownCalled; + WasDerivedTearDownCalled = true; + WasBaseTearDownCalledLast = !WasTearDownCalled; } } [TestFixture] public class SetupAndTearDownExceptionFixture { - public Exception setupException; - public Exception tearDownException; + public Exception SetupException; + public Exception TearDownException; [SetUp] public void SetUp() { - if (setupException != null) throw setupException; + if (SetupException != null) throw SetupException; } [TearDown] public void TearDown() { - if (tearDownException!=null) throw tearDownException; + if (TearDownException!=null) throw TearDownException; } [Test] diff --git a/src/NUnitFramework/testdata/SetUpFixtureData.cs b/src/NUnitFramework/testdata/SetUpFixtureData.cs index d5eb5f82b5..3109d0f376 100644 --- a/src/NUnitFramework/testdata/SetUpFixtureData.cs +++ b/src/NUnitFramework/testdata/SetUpFixtureData.cs @@ -167,6 +167,62 @@ public static void Clear() namespace NUnit.TestData.SetupFixture { + namespace StaticFixture + { + #region SomeFixture + [TestFixture] + public class TestSetupFixtureStuff + { + [OneTimeSetUp] + public void FixtureSetup() + { + TestUtilities.SimpleEventRecorder.RegisterEvent("StaticFixture.Fixture.SetUp"); + } + + [SetUp] + public void Setup() + { + TestUtilities.SimpleEventRecorder.RegisterEvent("StaticFixture.Test.SetUp"); + } + + [Test] + public void Test() + { + TestUtilities.SimpleEventRecorder.RegisterEvent("StaticFixture.Test"); + } + + [TearDown] + public void TearDown() + { + TestUtilities.SimpleEventRecorder.RegisterEvent("StaticFixture.Test.TearDown"); + } + + [OneTimeTearDown] + public void FixtureTearDown() + { + TestUtilities.SimpleEventRecorder.RegisterEvent("StaticFixture.Fixture.TearDown"); + } + } + #endregion SomeFixture + + + [SetUpFixture] + public static class StaticSetupTeardown + { + [OneTimeSetUp] + public static void DoNamespaceSetUp() + { + NUnit.TestUtilities.SimpleEventRecorder.RegisterEvent("StaticFixture.OneTimeSetUp"); + } + + [OneTimeTearDown] + public static void DoNamespaceTearDown() + { + NUnit.TestUtilities.SimpleEventRecorder.RegisterEvent("StaticFixture.OneTimeTearDown"); + } + } + } + namespace Namespace1 { #region SomeFixture diff --git a/src/NUnitFramework/testdata/TestCaseSourceAttributeFixture.cs b/src/NUnitFramework/testdata/TestCaseSourceAttributeFixture.cs index 69d0c65e20..6587c47acd 100644 --- a/src/NUnitFramework/testdata/TestCaseSourceAttributeFixture.cs +++ b/src/NUnitFramework/testdata/TestCaseSourceAttributeFixture.cs @@ -49,12 +49,12 @@ public void MethodCallsIgnore(int x, int y, int z) #region Test With Ignored TestCaseData - [TestCaseSource(nameof(ignored_source))] + [TestCaseSource(nameof(IgnoredSource))] public void MethodWithIgnoredTestCases(int num) { } - private static IEnumerable ignored_source + private static IEnumerable IgnoredSource { get { @@ -69,12 +69,12 @@ private static IEnumerable ignored_source #region Test With Explicit TestCaseData - [TestCaseSource(nameof(explicit_source))] + [TestCaseSource(nameof(ExplicitSource))] public void MethodWithExplicitTestCases(int num) { } - private static IEnumerable explicit_source + private static IEnumerable ExplicitSource { get { @@ -139,7 +139,7 @@ public void SourceInAnotherClassPassingSomeDataToConstructorWrongNumberParam(int { } - [TestCaseSource(nameof(exception_source))] + [TestCaseSource(nameof(ExceptionSource))] public void MethodWithSourceThrowingException(string lhs, string rhs) { } @@ -154,7 +154,7 @@ public void MethodWithArrayArguments(object o) { } - static IEnumerable exception_source + static IEnumerable ExceptionSource { get { diff --git a/src/NUnitFramework/testdata/TestContextData.cs b/src/NUnitFramework/testdata/TestContextData.cs index 2e7a613a01..600b17e2f1 100644 --- a/src/NUnitFramework/testdata/TestContextData.cs +++ b/src/NUnitFramework/testdata/TestContextData.cs @@ -1,4 +1,4 @@ -// *********************************************************************** +// *********************************************************************** // Copyright (c) 2015 Charlie Poole, Rob Prouse // // Permission is hereby granted, free of charge, to any person obtaining @@ -30,39 +30,39 @@ namespace NUnit.TestData.TestContextData [TestFixture] public class TestStateRecordingFixture { - public string stateList; + public string StateList; - public bool testFailure; - public bool testInconclusive; - public bool setUpFailure; - public bool setUpIgnore; + public bool TestFailure; + public bool TestInconclusive; + public bool SetUpFailure; + public bool SetUpIgnore; [SetUp] public void SetUp() { - stateList = TestContext.CurrentContext.Result.Outcome + "=>"; + StateList = TestContext.CurrentContext.Result.Outcome + "=>"; - if (setUpFailure) + if (SetUpFailure) Assert.Fail("Failure in SetUp"); - if (setUpIgnore) + if (SetUpIgnore) Assert.Ignore("Ignored in SetUp"); } [Test] public void TheTest() { - stateList += TestContext.CurrentContext.Result.Outcome; + StateList += TestContext.CurrentContext.Result.Outcome; - if (testFailure) + if (TestFailure) Assert.Fail("Deliberate failure"); - if (testInconclusive) + if (TestInconclusive) Assert.Inconclusive("Inconclusive test"); } [TearDown] public void TearDown() { - stateList += "=>" + TestContext.CurrentContext.Result.Outcome; + StateList += "=>" + TestContext.CurrentContext.Result.Outcome; } } diff --git a/src/NUnitFramework/testdata/TestNameFixture.cs b/src/NUnitFramework/testdata/TestNameFixture.cs new file mode 100644 index 0000000000..2e7c2ae046 --- /dev/null +++ b/src/NUnitFramework/testdata/TestNameFixture.cs @@ -0,0 +1,55 @@ +// *********************************************************************** +// Copyright (c) 2018 Charlie Poole, Rob Prouse +// +// 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 NUnit.Framework; + +namespace NUnit.TestData +{ + public class TestNameFixture + { + [TestCase("ImplicitNull")] + public void ImplicitNull(string name) + { + } + + [TestCase("ExplicitNull", TestName = null)] + public void ExplicitNull(string name) + { + } + + [TestCase("Empty", TestName = "")] + public void EmptyTest(string name) + { + } + + [TestCase("WhiteSpace", TestName = " ")] + public void WhiteSpaceTest(string name) + { + } + + [TestCase("ProperName", TestName = "ProperName")] + public void ProperNameTest(string name) + { + } + } +} diff --git a/src/NUnitFramework/testdata/TestOfFixture.cs b/src/NUnitFramework/testdata/TestOfFixture.cs index ac9ffd0659..872ace82a2 100644 --- a/src/NUnitFramework/testdata/TestOfFixture.cs +++ b/src/NUnitFramework/testdata/TestOfFixture.cs @@ -25,12 +25,15 @@ #region Using Directives using NUnit.Framework; +using NUnit.Framework.Internal; #endregion namespace NUnit.TestData { [TestFixture(TestOf = typeof(TestOfAttribute))] + [TestOf(typeof(TestOfAttribute))] + [TestOf(typeof(TestFixtureAttribute))] public class TestOfFixture { [Test(TestOf = typeof(TestOfAttribute))] @@ -55,5 +58,10 @@ public void SeparateTestOfStringMethod() [TestCase(5, TestOf = typeof(TestCaseAttribute))] public void TestCaseWithTestOf(int x) { } + + [Test] + [TestOf(typeof(TestOfAttribute))][TestOf(typeof(TestAttribute))] + public void TestOfMultipleAttributesMethod() + { } } } \ No newline at end of file diff --git a/src/NUnitFramework/testdata/TheoryFixture.cs b/src/NUnitFramework/testdata/TheoryFixture.cs index e37f29aa49..572a0a9a28 100644 --- a/src/NUnitFramework/testdata/TheoryFixture.cs +++ b/src/NUnitFramework/testdata/TheoryFixture.cs @@ -1,4 +1,4 @@ -// *********************************************************************** +// *********************************************************************** // Copyright (c) 2009 Charlie Poole, Rob Prouse // // Permission is hereby granted, free of charge, to any person obtaining @@ -35,7 +35,7 @@ public class TheoryFixture static int i1 = 1; #pragma warning restore 414 [Datapoint] - public int i100 = 100; + public int I100 = 100; [Theory] public void TheoryWithNoArguments() @@ -105,4 +105,4 @@ public void TestWithNullableEnumAsArgument(System.AttributeTargets? targets) Assert.Pass(); } } -} \ No newline at end of file +} diff --git a/src/NUnitFramework/testdata/UnexpectedExceptionFixture.cs b/src/NUnitFramework/testdata/UnexpectedExceptionFixture.cs index 39d5165e5d..cbf58792de 100644 --- a/src/NUnitFramework/testdata/UnexpectedExceptionFixture.cs +++ b/src/NUnitFramework/testdata/UnexpectedExceptionFixture.cs @@ -43,7 +43,7 @@ public void ThrowsWithNestedInnerException() new Exception("Inner Inner Exception"))); } -#if ASYNC +#if TASK_PARALLEL_LIBRARY_API [Test] public void ThrowsWithAggregateException() { diff --git a/src/NUnitFramework/testdata/WarningFixture.cs b/src/NUnitFramework/testdata/WarningFixture.cs index 75a1797772..86fb5d3648 100644 --- a/src/NUnitFramework/testdata/WarningFixture.cs +++ b/src/NUnitFramework/testdata/WarningFixture.cs @@ -26,7 +26,7 @@ using NUnit.Framework; using NUnit.Framework.Constraints; -#if ASYNC +#if TASK_PARALLEL_LIBRARY_API using System.Threading.Tasks; #endif @@ -77,7 +77,6 @@ public void WarnIf_Passes_BooleanWithMessageAndArgs() Warn.If(2 + 2 != 4, "Not Equal to {0}", 4); } -#if !NET20 [Test] public void WarnUnless_Passes_BooleanWithMessageStringFunc() { @@ -141,7 +140,6 @@ public void WarnIf_Passes_BooleanLambdaWithWithMessageStringFunc() Func getExceptionMessage = () => string.Format("Not Equal to {0}", 4); Warn.If(() => 2 + 2 != 4, getExceptionMessage); } -#endif [Test] public void WarnUnless_Passes_ActualAndConstraint() @@ -179,7 +177,6 @@ public void WarnIf_Passes_ActualAndConstraintWithMessageAndArgs() Warn.If(2 + 2, Is.Not.EqualTo(4), "Should be {0}", 4); } -#if !NET20 [Test] public void WarnUnless_Passes_ActualAndConstraintWithMessageStringFunc() { @@ -243,7 +240,6 @@ public void WarnIf_Passes_ActualLambdaAndConstraintWithMessageStringFunc() Func getExceptionMessage = () => string.Format("Not Equal to {0}", 4); Warn.If(() => 2 + 2, Is.Not.EqualTo(4), getExceptionMessage); } -#endif [Test] public void WarnUnless_Passes_DelegateAndConstraint() @@ -281,7 +277,6 @@ public void WarnIf_Passes_DelegateAndConstraintWithMessageAndArgs() Warn.If(new ActualValueDelegate(ReturnsFour), Is.Not.EqualTo(4), "Should be {0}", 4); } -#if !NET20 [Test] public void WarnUnless_Passes_DelegateAndConstraintWithMessageStringFunc() { @@ -295,9 +290,8 @@ public void WarnIf_Passes_DelegateAndConstraintWithMessageStringFunc() Func getExceptionMessage = () => string.Format("Not Equal to {0}", 4); Warn.If(new ActualValueDelegate(ReturnsFour), Is.Not.EqualTo(4), getExceptionMessage); } -#endif -#if ASYNC +#if TASK_PARALLEL_LIBRARY_API [Test] public void WarnUnless_Passes_Async() { @@ -363,7 +357,6 @@ public void WarnIf_Fails_BooleanWithMessageAndArgs() Warn.If(2 + 2 != 5, "got {0}", 5); } -#if !NET20 [Test] public void WarnUnless_Fails_BooleanWithMessageStringFunc() { @@ -427,7 +420,6 @@ public void WarnIf_Fails_BooleanLambdaWithMessageStringFunc() Func getExceptionMessage = () => "got 5"; Warn.If(() => 2 + 2 != 5, getExceptionMessage); } -#endif [Test] public void WarnUnless_Fails_ActualAndConstraint() @@ -465,7 +457,6 @@ public void WarnIf_Fails_ActualAndConstraintWithMessageAndArgs() Warn.If(2 + 2, Is.Not.EqualTo(5), "Should be {0}", 5); } -#if !NET20 [Test] public void WarnUnless_Fails_ActualAndConstraintWithMessageStringFunc() { @@ -529,7 +520,6 @@ public void WarnIf_Fails_ActualLambdaAndConstraintWithMessageStringFunc() Func getExceptionMessage = () => "Should be 5"; Warn.If(() => 2 + 2, Is.Not.EqualTo(5), getExceptionMessage); } -#endif [Test] public void WarnUnless_Fails_DelegateAndConstraint() @@ -567,7 +557,6 @@ public void WarnIf_Fails_DelegateAndConstraintWithMessageAndArgs() Warn.If(new ActualValueDelegate(ReturnsFive), Is.Not.EqualTo(4), "Should be {0}", 4); } -#if !NET20 [Test] public void WarnUnless_Fails_DelegateAndConstraintWithMessageStringFunc() { @@ -581,9 +570,8 @@ public void WarnIf_Fails_DelegateAndConstraintWithMessageStringFunc() Func getExceptionMessage = () => "Should be 4"; Warn.If(new ActualValueDelegate(ReturnsFive), Is.Not.EqualTo(4), getExceptionMessage); } -#endif -#if ASYNC +#if TASK_PARALLEL_LIBRARY_API [Test] public void WarnUnless_Fails_Async() { @@ -639,7 +627,7 @@ private int ReturnsFive() return 5; } -#if ASYNC +#if TASK_PARALLEL_LIBRARY_API private static Task One() { return Task.Run(() => 1); @@ -656,9 +644,6 @@ public static void WarningSynchronous() Assert.Warn("(Warning message)"); } -#if NET20 - private delegate void Action(); -#endif [Test] public static void WarningInBeginInvoke() { @@ -724,7 +709,7 @@ public static void WarningInThreadPoolQueueUserWorkItem() } } -#if ASYNC +#if TASK_PARALLEL_LIBRARY_API [Test] public static void WarningInTaskRun() { diff --git a/src/NUnitFramework/testdata/nunit.testdata.csproj b/src/NUnitFramework/testdata/nunit.testdata.csproj index 016a887cac..4735133493 100644 --- a/src/NUnitFramework/testdata/nunit.testdata.csproj +++ b/src/NUnitFramework/testdata/nunit.testdata.csproj @@ -1,7 +1,7 @@  - net20;net35;net40;net45;netcoreapp1.1;netcoreapp2.0 + net35;net40;net45;netcoreapp1.1;netcoreapp2.0 NUnit.TestData System.Exception : Inner Exception 1 of 2" + Environment.NewLine + " ----> System.Exception : Inner Exception 2 of 2"; @@ -79,18 +75,15 @@ public void FailRecordsInnerExceptionsAsPartOfAggregateException() "ThrowsWithAggregateException"); Assert.AreEqual(ResultState.Error, result.ResultState); - Assert.AreEqual(expectedMessage, result.Message); + Assert.That(result.Message, Does.StartWith(expectedStartOfMessage)); + Assert.That(result.Message, Does.EndWith(expectedEndOfMessage)); } [Test] public void FailRecordsNestedInnerExceptionAsPartOfAggregateException() { - string expectedMessage = -#if NETCOREAPP1_1 || NETCOREAPP2_0 - "System.AggregateException : Outer Aggregate Exception (Inner Exception)" + Environment.NewLine + -#else - "System.AggregateException : Outer Aggregate Exception" + Environment.NewLine + -#endif + string expectedStartOfMessage = "System.AggregateException : Outer Aggregate Exception"; + string expectedEndOfMessage = " ----> System.Exception : Inner Exception" + Environment.NewLine + " ----> System.Exception : Inner Inner Exception"; @@ -99,7 +92,8 @@ public void FailRecordsNestedInnerExceptionAsPartOfAggregateException() "ThrowsWithAggregateExceptionContainingNestedInnerException"); Assert.AreEqual(ResultState.Error, result.ResultState); - Assert.AreEqual(expectedMessage, result.Message); + Assert.That(result.Message, Does.StartWith(expectedStartOfMessage)); + Assert.That(result.Message, Does.EndWith(expectedEndOfMessage)); } #endif diff --git a/src/NUnitFramework/tests/NonVoidResultAwaitableReturnTypeTests.cs b/src/NUnitFramework/tests/NonVoidResultAwaitableReturnTypeTests.cs new file mode 100644 index 0000000000..397b5f1d61 --- /dev/null +++ b/src/NUnitFramework/tests/NonVoidResultAwaitableReturnTypeTests.cs @@ -0,0 +1,35 @@ +using NUnit.Framework.Interfaces; +using NUnit.TestData; +using F = NUnit.TestData.AwaitableReturnTypeFixture; + +namespace NUnit.Framework +{ +#if TASK_PARALLEL_LIBRARY_API + [TestFixture(nameof(F.ReturnsNonVoidResultTask))] + [TestFixture(nameof(F.ReturnsNonVoidResultCustomTask))] +#endif + [TestFixture(nameof(F.ReturnsNonVoidResultCustomAwaitable))] + [TestFixture(nameof(F.ReturnsNonVoidResultCustomAwaitableWithImplicitOnCompleted))] + [TestFixture(nameof(F.ReturnsNonVoidResultCustomAwaitableWithImplicitUnsafeOnCompleted))] + public sealed class NonVoidResultAwaitableReturnTypeTests : AwaitableReturnTypeTests + { + public NonVoidResultAwaitableReturnTypeTests(string methodName) + : base(methodName) + { + + } + + [Test] + public void ResultMustMatchExpectedResult() + { + var result = RunCurrentTestMethod(new AsyncWorkload( + isCompleted: true, + onCompleted: continuation => continuation.Invoke(), + getResult: () => 41)); + + Assert.That(result.ResultState.Status, Is.EqualTo(TestStatus.Failed)); + Assert.That(result.Message, Contains.Substring("41")); + Assert.That(result.Message, Contains.Substring("42")); + } + } +} diff --git a/src/NUnitFramework/tests/SynchronizationContextTests.cs b/src/NUnitFramework/tests/SynchronizationContextTests.cs index 40e8d4faa4..2034735f7b 100644 --- a/src/NUnitFramework/tests/SynchronizationContextTests.cs +++ b/src/NUnitFramework/tests/SynchronizationContextTests.cs @@ -21,7 +21,7 @@ // WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. // *********************************************************************** -#if ASYNC +#if TASK_PARALLEL_LIBRARY_API using System; using System.Collections.Generic; using System.Linq; @@ -41,7 +41,7 @@ public static class SynchronizationContextTests [Test] public static void SynchronizationContextIsRestoredBetweenTestCases() { - using (RestoreSynchronizationContext()) // Restore the synchronization context so as not to affect other tests if this test fails + using (TestUtils.RestoreSynchronizationContext()) // Restore the synchronization context so as not to affect other tests if this test fails { var result = TestBuilder.RunParameterizedMethodSuite( typeof(SynchronizationContextFixture), @@ -54,7 +54,7 @@ public static void SynchronizationContextIsRestoredBetweenTestCases() [Test] public static void SynchronizationContextIsRestoredBetweenTestCaseSources() { - using (RestoreSynchronizationContext()) // Restore the synchronization context so as not to affect other tests if this test fails + using (TestUtils.RestoreSynchronizationContext()) // Restore the synchronization context so as not to affect other tests if this test fails { var fixture = TestBuilder.MakeFixture(typeof(SynchronizationContextFixture)); @@ -73,6 +73,9 @@ public static void SynchronizationContextIsRestoredBetweenTestCaseSources() public static IEnumerable ApiAdapters => AsyncExecutionApiAdapter.All; #if APARTMENT_STATE +#if NETCOREAPP2_0 + [Platform(Include = "Win, Mono")] +#endif [Apartment(ApartmentState.STA)] [TestCaseSource(nameof(ApiAdapters))] public static void ContinuationStaysOnStaThread(AsyncExecutionApiAdapter apiAdapter) @@ -86,6 +89,9 @@ public static void ContinuationStaysOnStaThread(AsyncExecutionApiAdapter apiAdap }); } +#if NETCOREAPP2_0 + [Platform(Include = "Win, Mono")] +#endif [Apartment(ApartmentState.STA)] [TestCaseSource(nameof(ApiAdapters))] public static void AsyncDelegatesAreExecutedOnStaThread(AsyncExecutionApiAdapter apiAdapter) @@ -137,7 +143,7 @@ private static SynchronizationContext CreateSynchronizationContext(Type knownSyn { var createdOnThisThread = CreateSynchronizationContext(knownSynchronizationContextType); - using (TemporarySynchronizationContext(createdOnThisThread)) + using (TestUtils.TemporarySynchronizationContext(createdOnThisThread)) { apiAdapter.Execute(async () => await TaskEx.Yield()); } @@ -150,7 +156,7 @@ private static SynchronizationContext CreateSynchronizationContext(Type knownSyn { var createdOnThisThread = CreateSynchronizationContext(knownSynchronizationContextType); - using (TemporarySynchronizationContext(createdOnThisThread)) + using (TestUtils.TemporarySynchronizationContext(createdOnThisThread)) { apiAdapter.Execute(() => { @@ -167,7 +173,7 @@ private static SynchronizationContext CreateSynchronizationContext(Type knownSyn { var createdOnThisThread = CreateSynchronizationContext(knownSynchronizationContextType); - using (TemporarySynchronizationContext(createdOnThisThread)) + using (TestUtils.TemporarySynchronizationContext(createdOnThisThread)) { apiAdapter.Execute(async () => await TaskEx.Yield()); @@ -175,19 +181,6 @@ private static SynchronizationContext CreateSynchronizationContext(Type knownSyn } } #endif - - private static IDisposable TemporarySynchronizationContext(SynchronizationContext synchronizationContext) - { - var restore = RestoreSynchronizationContext(); - SynchronizationContext.SetSynchronizationContext(synchronizationContext); - return restore; - } - - private static IDisposable RestoreSynchronizationContext() - { - var originalContext = SynchronizationContext.Current; - return On.Dispose(() => SynchronizationContext.SetSynchronizationContext(originalContext)); - } } } #endif diff --git a/src/NUnitFramework/tests/Syntax/AfterTests.cs b/src/NUnitFramework/tests/Syntax/AfterTests.cs index e5f51becce..e6d157ff66 100644 --- a/src/NUnitFramework/tests/Syntax/AfterTests.cs +++ b/src/NUnitFramework/tests/Syntax/AfterTests.cs @@ -36,9 +36,9 @@ public class AfterTest_SimpleConstraint : SyntaxTest [SetUp] public void SetUp() { - parseTree = ">"; - staticSyntax = Is.EqualTo(10).After(1000); - builderSyntax = Builder().EqualTo(10).After(1000); + ParseTree = ">"; + StaticSyntax = Is.EqualTo(10).After(1000); + BuilderSyntax = Builder().EqualTo(10).After(1000); } } @@ -47,9 +47,9 @@ public class AfterMinutesTest_SimpleConstraint : SyntaxTest [SetUp] public void SetUp() { - parseTree = ">"; - staticSyntax = Is.EqualTo(10).After(1).Minutes; - builderSyntax = Builder().EqualTo(10).After(1).Minutes; + ParseTree = ">"; + StaticSyntax = Is.EqualTo(10).After(1).Minutes; + BuilderSyntax = Builder().EqualTo(10).After(1).Minutes; } } @@ -58,9 +58,9 @@ public class AfterSecondsTest_SimpleConstraint : SyntaxTest [SetUp] public void SetUp() { - parseTree = ">"; - staticSyntax = Is.EqualTo(10).After(20).Seconds; - builderSyntax = Builder().EqualTo(10).After(20).Seconds; + ParseTree = ">"; + StaticSyntax = Is.EqualTo(10).After(20).Seconds; + BuilderSyntax = Builder().EqualTo(10).After(20).Seconds; } } @@ -69,9 +69,9 @@ public class AfterMillisecondsTest_SimpleConstraint : SyntaxTest [SetUp] public void SetUp() { - parseTree = ">"; - staticSyntax = Is.EqualTo(10).After(500).MilliSeconds; - builderSyntax = Builder().EqualTo(10).After(500).MilliSeconds; + ParseTree = ">"; + StaticSyntax = Is.EqualTo(10).After(500).MilliSeconds; + BuilderSyntax = Builder().EqualTo(10).After(500).MilliSeconds; } } @@ -81,9 +81,9 @@ public class AfterTest_PropertyTest : SyntaxTest [SetUp] public void SetUp() { - parseTree = ">>"; - staticSyntax = Has.Property("X").EqualTo(10).After(1000); - builderSyntax = Builder().Property("X").EqualTo(10).After(1000); + ParseTree = ">>"; + StaticSyntax = Has.Property("X").EqualTo(10).After(1000); + BuilderSyntax = Builder().Property("X").EqualTo(10).After(1000); } } @@ -92,33 +92,33 @@ public class AfterTest_AndOperator : SyntaxTest [SetUp] public void SetUp() { - parseTree = " >>"; - staticSyntax = Is.GreaterThan(0).And.LessThan(10).After(1000); - builderSyntax = Builder().GreaterThan(0).And.LessThan(10).After(1000); + ParseTree = " >>"; + StaticSyntax = Is.GreaterThan(0).And.LessThan(10).After(1000); + BuilderSyntax = Builder().GreaterThan(0).And.LessThan(10).After(1000); } } public abstract class AfterSyntaxTests { - protected bool flag; - protected int num; - protected object ob1, ob2, ob3; - protected List list; - protected string greeting; + protected bool Flag; + protected int Num; + protected object Ob1, Ob2, Ob3; + protected List List; + protected string Greeting; [SetUp] public void InitializeValues() { - this.flag = false; - this.num = 0; - this.ob1 = new object(); - this.ob2 = new object(); - this.ob3 = new object(); - this.list = new List(); - this.list.Add(1); - this.list.Add(2); - this.list.Add(3); - this.greeting = "hello"; + this.Flag = false; + this.Num = 0; + this.Ob1 = new object(); + this.Ob2 = new object(); + this.Ob3 = new object(); + this.List = new List(); + this.List.Add(1); + this.List.Add(2); + this.List.Add(3); + this.Greeting = "hello"; new Thread(ModifyValuesAfterDelay).Start(); } @@ -127,12 +127,12 @@ private void ModifyValuesAfterDelay() { Thread.Sleep(100); - this.flag = true; - this.num = 1; - this.ob1 = ob2; - this.ob3 = null; - this.list.Add(4); - this.greeting += "world"; + this.Flag = true; + this.Num = 1; + this.Ob1 = Ob2; + this.Ob3 = null; + this.List.Add(4); + this.Greeting += "world"; } } @@ -141,43 +141,43 @@ public class AfterSyntaxUsingAnonymousDelegates : AfterSyntaxTests [Test] public void TrueTest() { - Assert.That(delegate { return flag; }, Is.True.After(5000, 200)); + Assert.That(delegate { return Flag; }, Is.True.After(5000, 200)); } [Test] public void EqualToTest() { - Assert.That(delegate { return num; }, Is.EqualTo(1).After(5000, 200)); + Assert.That(delegate { return Num; }, Is.EqualTo(1).After(5000, 200)); } [Test] public void SameAsTest() { - Assert.That(delegate { return ob1; }, Is.SameAs(ob2).After(5000, 200)); + Assert.That(delegate { return Ob1; }, Is.SameAs(Ob2).After(5000, 200)); } [Test] public void GreaterTest() { - Assert.That(delegate { return num; }, Is.GreaterThan(0).After(5000,200)); + Assert.That(delegate { return Num; }, Is.GreaterThan(0).After(5000,200)); } [Test] public void HasMemberTest() { - Assert.That(delegate { return list; }, Has.Member(4).After(5000, 200)); + Assert.That(delegate { return List; }, Has.Member(4).After(5000, 200)); } [Test] public void NullTest() { - Assert.That(delegate { return ob3; }, Is.Null.After(5000, 200)); + Assert.That(delegate { return Ob3; }, Is.Null.After(5000, 200)); } [Test] public void TextTest() { - Assert.That(delegate { return greeting; }, Does.EndWith("world").After(5000, 200)); + Assert.That(delegate { return Greeting; }, Does.EndWith("world").After(5000, 200)); } } @@ -186,43 +186,43 @@ public class AfterSyntaxUsingLambda : AfterSyntaxTests [Test] public void TrueTest() { - Assert.That(() => flag, Is.True.After(5000, 200)); + Assert.That(() => Flag, Is.True.After(5000, 200)); } [Test] public void EqualToTest() { - Assert.That(() => num, Is.EqualTo(1).After(5000, 200)); + Assert.That(() => Num, Is.EqualTo(1).After(5000, 200)); } [Test] public void SameAsTest() { - Assert.That(() => ob1, Is.SameAs(ob2).After(5000, 200)); + Assert.That(() => Ob1, Is.SameAs(Ob2).After(5000, 200)); } [Test] public void GreaterTest() { - Assert.That(() => num, Is.GreaterThan(0).After(5000, 200)); + Assert.That(() => Num, Is.GreaterThan(0).After(5000, 200)); } [Test] public void HasMemberTest() { - Assert.That(() => list, Has.Member(4).After(5000, 200)); + Assert.That(() => List, Has.Member(4).After(5000, 200)); } [Test] public void NullTest() { - Assert.That(() => ob3, Is.Null.After(5000, 200)); + Assert.That(() => Ob3, Is.Null.After(5000, 200)); } [Test] public void TextTest() { - Assert.That(() => greeting, Does.EndWith("world").After(5000, 200)); + Assert.That(() => Greeting, Does.EndWith("world").After(5000, 200)); } } } diff --git a/src/NUnitFramework/tests/Syntax/AnyOfTests.cs b/src/NUnitFramework/tests/Syntax/AnyOfTests.cs index b8126ac036..4ef055b29e 100644 --- a/src/NUnitFramework/tests/Syntax/AnyOfTests.cs +++ b/src/NUnitFramework/tests/Syntax/AnyOfTests.cs @@ -28,9 +28,9 @@ public class AnyOfTests : SyntaxTest [SetUp] public void SetUp() { - parseTree = ""; - staticSyntax = Is.AnyOf(1, 2, 3); - builderSyntax = Builder().AnyOf(1, 2, 3); + ParseTree = ""; + StaticSyntax = Is.AnyOf(1, 2, 3); + BuilderSyntax = Builder().AnyOf(1, 2, 3); } [Test] @@ -51,9 +51,9 @@ public class AnyOf_NullValue_Tests : SyntaxTest [SetUp] public void SetUp() { - parseTree = ""; - staticSyntax = Is.AnyOf(null); - builderSyntax = Builder().AnyOf(null); + ParseTree = ""; + StaticSyntax = Is.AnyOf(null); + BuilderSyntax = Builder().AnyOf(null); } } } diff --git a/src/NUnitFramework/tests/Syntax/CollectionTests.cs b/src/NUnitFramework/tests/Syntax/CollectionTests.cs index ae77bb7ac9..0ee35f8c29 100644 --- a/src/NUnitFramework/tests/Syntax/CollectionTests.cs +++ b/src/NUnitFramework/tests/Syntax/CollectionTests.cs @@ -1,4 +1,4 @@ -// *********************************************************************** +// *********************************************************************** // Copyright (c) 2009 Charlie Poole, Rob Prouse // // Permission is hereby granted, free of charge, to any person obtaining @@ -32,9 +32,9 @@ public class UniqueTest : SyntaxTest [SetUp] public void SetUp() { - parseTree = ""; - staticSyntax = Is.Unique; - builderSyntax = Builder().Unique; + ParseTree = ""; + StaticSyntax = Is.Unique; + BuilderSyntax = Builder().Unique; } } @@ -43,9 +43,9 @@ public class CollectionOrderedTest : SyntaxTest [SetUp] public void SetUp() { - parseTree = ""; - staticSyntax = Is.Ordered; - builderSyntax = Builder().Ordered; + ParseTree = ""; + StaticSyntax = Is.Ordered; + BuilderSyntax = Builder().Ordered; } } @@ -54,9 +54,9 @@ public class CollectionOrderedTest_Descending : SyntaxTest [SetUp] public void SetUp() { - parseTree = ""; - staticSyntax = Is.Ordered.Descending; - builderSyntax = Builder().Ordered.Descending; + ParseTree = ""; + StaticSyntax = Is.Ordered.Descending; + BuilderSyntax = Builder().Ordered.Descending; } } @@ -66,9 +66,9 @@ public class CollectionOrderedTest_Comparer : SyntaxTest public void SetUp() { IComparer comparer = ObjectComparer.Default; - parseTree = ""; - staticSyntax = Is.Ordered.Using(comparer); - builderSyntax = Builder().Ordered.Using(comparer); + ParseTree = ""; + StaticSyntax = Is.Ordered.Using(comparer); + BuilderSyntax = Builder().Ordered.Using(comparer); } } @@ -78,9 +78,9 @@ public class CollectionOrderedTest_Comparer_Descending : SyntaxTest public void SetUp() { IComparer comparer = ObjectComparer.Default; - parseTree = ""; - staticSyntax = Is.Ordered.Using(comparer).Descending; - builderSyntax = Builder().Ordered.Using(comparer).Descending; + ParseTree = ""; + StaticSyntax = Is.Ordered.Using(comparer).Descending; + BuilderSyntax = Builder().Ordered.Using(comparer).Descending; } } @@ -89,9 +89,9 @@ public class CollectionOrderedByTest : SyntaxTest [SetUp] public void SetUp() { - parseTree = ""; - staticSyntax = Is.Ordered.By("SomePropertyName"); - builderSyntax = Builder().Ordered.By("SomePropertyName"); + ParseTree = ""; + StaticSyntax = Is.Ordered.By("SomePropertyName"); + BuilderSyntax = Builder().Ordered.By("SomePropertyName"); } } @@ -100,9 +100,9 @@ public class CollectionOrderedByTest_Descending : SyntaxTest [SetUp] public void SetUp() { - parseTree = ""; - staticSyntax = Is.Ordered.By("SomePropertyName").Descending; - builderSyntax = Builder().Ordered.By("SomePropertyName").Descending; + ParseTree = ""; + StaticSyntax = Is.Ordered.By("SomePropertyName").Descending; + BuilderSyntax = Builder().Ordered.By("SomePropertyName").Descending; } } @@ -111,9 +111,9 @@ public class CollectionOrderedByTest_Comparer : SyntaxTest [SetUp] public void SetUp() { - parseTree = ""; - staticSyntax = Is.Ordered.By("SomePropertyName").Using(ObjectComparer.Default); - builderSyntax = Builder().Ordered.By("SomePropertyName").Using(ObjectComparer.Default); + ParseTree = ""; + StaticSyntax = Is.Ordered.By("SomePropertyName").Using(ObjectComparer.Default); + BuilderSyntax = Builder().Ordered.By("SomePropertyName").Using(ObjectComparer.Default); } } @@ -122,9 +122,9 @@ public class CollectionOrderedByTest_Comparer_Descending : SyntaxTest [SetUp] public void SetUp() { - parseTree = ""; - staticSyntax = Is.Ordered.By("SomePropertyName").Using(ObjectComparer.Default).Descending; - builderSyntax = Builder().Ordered.By("SomePropertyName").Using(ObjectComparer.Default).Descending; + ParseTree = ""; + StaticSyntax = Is.Ordered.By("SomePropertyName").Using(ObjectComparer.Default).Descending; + BuilderSyntax = Builder().Ordered.By("SomePropertyName").Using(ObjectComparer.Default).Descending; } } @@ -133,9 +133,9 @@ public class CollectionContainsTest : SyntaxTest [SetUp] public void SetUp() { - parseTree = ">"; - staticSyntax = Has.Member(42); - builderSyntax = Builder().Contains(42); + ParseTree = ">"; + StaticSyntax = Has.Member(42); + BuilderSyntax = Builder().Contains(42); } } @@ -145,9 +145,9 @@ public class CollectionSubsetTest : SyntaxTest public void SetUp() { int[] ints = new int[] { 1, 2, 3 }; - parseTree = ""; - staticSyntax = Is.SubsetOf(ints); - builderSyntax = Builder().SubsetOf(ints); + ParseTree = ""; + StaticSyntax = Is.SubsetOf(ints); + BuilderSyntax = Builder().SubsetOf(ints); } } @@ -157,9 +157,9 @@ public class CollectionEquivalentTest : SyntaxTest public void SetUp() { int[] ints = new int[] { 1, 2, 3 }; - parseTree = ""; - staticSyntax = Is.EquivalentTo(ints); - builderSyntax = Builder().EquivalentTo(ints); + ParseTree = ""; + StaticSyntax = Is.EquivalentTo(ints); + BuilderSyntax = Builder().EquivalentTo(ints); } } } diff --git a/src/NUnitFramework/tests/Syntax/ComparisonTests.cs b/src/NUnitFramework/tests/Syntax/ComparisonTests.cs index 3e7052b1b6..cf61e7cc21 100644 --- a/src/NUnitFramework/tests/Syntax/ComparisonTests.cs +++ b/src/NUnitFramework/tests/Syntax/ComparisonTests.cs @@ -1,4 +1,4 @@ -// *********************************************************************** +// *********************************************************************** // Copyright (c) 2009 Charlie Poole, Rob Prouse // // Permission is hereby granted, free of charge, to any person obtaining @@ -30,9 +30,9 @@ public class GreaterThanTest : SyntaxTest [SetUp] public void SetUp() { - parseTree = ""; - staticSyntax = Is.GreaterThan(7); - builderSyntax = Builder().GreaterThan(7); + ParseTree = ""; + StaticSyntax = Is.GreaterThan(7); + BuilderSyntax = Builder().GreaterThan(7); } } @@ -41,9 +41,9 @@ public class GreaterThanOrEqualTest : SyntaxTest [SetUp] public void SetUp() { - parseTree = ""; - staticSyntax = Is.GreaterThanOrEqualTo(7); - builderSyntax = Builder().GreaterThanOrEqualTo(7); + ParseTree = ""; + StaticSyntax = Is.GreaterThanOrEqualTo(7); + BuilderSyntax = Builder().GreaterThanOrEqualTo(7); } } @@ -52,9 +52,9 @@ public class AtLeastTest : SyntaxTest [SetUp] public void SetUp() { - parseTree = ""; - staticSyntax = Is.AtLeast(7); - builderSyntax = Builder().AtLeast(7); + ParseTree = ""; + StaticSyntax = Is.AtLeast(7); + BuilderSyntax = Builder().AtLeast(7); } } @@ -63,9 +63,9 @@ public class LessThanTest : SyntaxTest [SetUp] public void SetUp() { - parseTree = ""; - staticSyntax = Is.LessThan(7); - builderSyntax = Builder().LessThan(7); + ParseTree = ""; + StaticSyntax = Is.LessThan(7); + BuilderSyntax = Builder().LessThan(7); } } @@ -74,9 +74,9 @@ public class LessThanOrEqualTest : SyntaxTest [SetUp] public void SetUp() { - parseTree = ""; - staticSyntax = Is.LessThanOrEqualTo(7); - builderSyntax = Builder().LessThanOrEqualTo(7); + ParseTree = ""; + StaticSyntax = Is.LessThanOrEqualTo(7); + BuilderSyntax = Builder().LessThanOrEqualTo(7); } } @@ -85,9 +85,9 @@ public class AtMostTest : SyntaxTest [SetUp] public void SetUp() { - parseTree = ""; - staticSyntax = Is.AtMost(7); - builderSyntax = Builder().AtMost(7); + ParseTree = ""; + StaticSyntax = Is.AtMost(7); + BuilderSyntax = Builder().AtMost(7); } } } diff --git a/src/NUnitFramework/tests/Syntax/EqualityTests.cs b/src/NUnitFramework/tests/Syntax/EqualityTests.cs index 9eff2ba0ec..87eef2a79e 100644 --- a/src/NUnitFramework/tests/Syntax/EqualityTests.cs +++ b/src/NUnitFramework/tests/Syntax/EqualityTests.cs @@ -1,4 +1,4 @@ -// *********************************************************************** +// *********************************************************************** // Copyright (c) 2009 Charlie Poole, Rob Prouse // // Permission is hereby granted, free of charge, to any person obtaining @@ -31,9 +31,9 @@ public class EqualToTest : SyntaxTest [SetUp] public void SetUp() { - parseTree = ""; - staticSyntax = Is.EqualTo(999); - builderSyntax = Builder().EqualTo(999); + ParseTree = ""; + StaticSyntax = Is.EqualTo(999); + BuilderSyntax = Builder().EqualTo(999); } } @@ -42,9 +42,9 @@ public class EqualToTest_IgnoreCase : SyntaxTest [SetUp] public void SetUp() { - parseTree = @""; - staticSyntax = Is.EqualTo("X").IgnoreCase; - builderSyntax = Builder().EqualTo("X").IgnoreCase; + ParseTree = @""; + StaticSyntax = Is.EqualTo("X").IgnoreCase; + BuilderSyntax = Builder().EqualTo("X").IgnoreCase; } } @@ -53,9 +53,9 @@ public class EqualToTest_WithinTolerance : SyntaxTest [SetUp] public void SetUp() { - parseTree = ""; - staticSyntax = Is.EqualTo(0.7).Within(.005); - builderSyntax = Builder().EqualTo(0.7).Within(.005); + ParseTree = ""; + StaticSyntax = Is.EqualTo(0.7).Within(.005); + BuilderSyntax = Builder().EqualTo(0.7).Within(.005); } } diff --git a/src/NUnitFramework/tests/Syntax/OperatorOverrides.cs b/src/NUnitFramework/tests/Syntax/OperatorOverrides.cs index 3f06b6e05b..40199169b9 100644 --- a/src/NUnitFramework/tests/Syntax/OperatorOverrides.cs +++ b/src/NUnitFramework/tests/Syntax/OperatorOverrides.cs @@ -1,4 +1,4 @@ -// *********************************************************************** +// *********************************************************************** // Copyright (c) 2009 Charlie Poole, Rob Prouse // // Permission is hereby granted, free of charge, to any person obtaining @@ -31,9 +31,9 @@ public class NotOperatorOverride : SyntaxTest [SetUp] public void SetUp() { - parseTree = ">"; - staticSyntax = !Is.Null; - builderSyntax = !Builder().Null; + ParseTree = ">"; + StaticSyntax = !Is.Null; + BuilderSyntax = !Builder().Null; } } @@ -42,9 +42,9 @@ public class AndOperatorOverride : SyntaxTest [SetUp] public void SetUp() { - parseTree = " >"; - staticSyntax = Is.GreaterThan(5) & Is.LessThan(10); - builderSyntax = Builder().GreaterThan(5) & Builder().LessThan(10); + ParseTree = " >"; + StaticSyntax = Is.GreaterThan(5) & Is.LessThan(10); + BuilderSyntax = Builder().GreaterThan(5) & Builder().LessThan(10); } } @@ -53,9 +53,9 @@ public class OrOperatorOverride : SyntaxTest [SetUp] public void SetUp() { - parseTree = " >"; - staticSyntax = Is.LessThan(5) | Is.GreaterThan(10); - builderSyntax = Builder().LessThan(5) | Is.GreaterThan(10); + ParseTree = " >"; + StaticSyntax = Is.LessThan(5) | Is.GreaterThan(10); + BuilderSyntax = Builder().LessThan(5) | Is.GreaterThan(10); } } diff --git a/src/NUnitFramework/tests/Syntax/OperatorTests.cs b/src/NUnitFramework/tests/Syntax/OperatorTests.cs index d30f858395..581b3c1e04 100644 --- a/src/NUnitFramework/tests/Syntax/OperatorTests.cs +++ b/src/NUnitFramework/tests/Syntax/OperatorTests.cs @@ -1,4 +1,4 @@ -// *********************************************************************** +// *********************************************************************** // Copyright (c) 2009 Charlie Poole, Rob Prouse // // Permission is hereby granted, free of charge, to any person obtaining @@ -31,9 +31,9 @@ public class NotTest : SyntaxTest [SetUp] public void SetUp() { - parseTree = ">"; - staticSyntax = Is.Not.Null; - builderSyntax = Builder().Not.Null; + ParseTree = ">"; + StaticSyntax = Is.Not.Null; + BuilderSyntax = Builder().Not.Null; } } @@ -42,9 +42,9 @@ public class NotTest_Cascaded : SyntaxTest [SetUp] public void SetUp() { - parseTree = ">>>"; - staticSyntax = Is.Not.Not.Not.Null; - builderSyntax = Builder().Not.Not.Not.Null; + ParseTree = ">>>"; + StaticSyntax = Is.Not.Not.Not.Null; + BuilderSyntax = Builder().Not.Not.Not.Null; } } #endregion @@ -55,9 +55,9 @@ public class AllTest : SyntaxTest [SetUp] public void SetUp() { - parseTree = ">"; - staticSyntax = Is.All.GreaterThan(0); - builderSyntax = Builder().All.GreaterThan(0); + ParseTree = ">"; + StaticSyntax = Is.All.GreaterThan(0); + BuilderSyntax = Builder().All.GreaterThan(0); } } #endregion @@ -68,9 +68,9 @@ public class SomeTest : SyntaxTest [SetUp] public void SetUp() { - parseTree = ">"; - staticSyntax = Has.Some.EqualTo(3); - builderSyntax = Builder().Some.EqualTo(3); + ParseTree = ">"; + StaticSyntax = Has.Some.EqualTo(3); + BuilderSyntax = Builder().Some.EqualTo(3); } } @@ -79,9 +79,9 @@ public class SomeTest_BeforeBinaryOperators : SyntaxTest [SetUp] public void SetUp() { - parseTree = " > >>"; - staticSyntax = Has.Some.GreaterThan(0).And.LessThan(100).Or.EqualTo(999); - builderSyntax = Builder().Some.GreaterThan(0).And.LessThan(100).Or.EqualTo(999); + ParseTree = " > >>"; + StaticSyntax = Has.Some.GreaterThan(0).And.LessThan(100).Or.EqualTo(999); + BuilderSyntax = Builder().Some.GreaterThan(0).And.LessThan(100).Or.EqualTo(999); } } @@ -90,9 +90,9 @@ public class SomeTest_NestedSome : SyntaxTest [SetUp] public void SetUp() { - parseTree = ">>"; - staticSyntax = Has.Some.With.Some.LessThan(100); - builderSyntax = Builder().Some.With.Some.LessThan(100); + ParseTree = ">>"; + StaticSyntax = Has.Some.With.Some.LessThan(100); + BuilderSyntax = Builder().Some.With.Some.LessThan(100); } } @@ -102,9 +102,9 @@ public class SomeTest_UseOfAndSome : SyntaxTest [SetUp] public void SetUp() { - parseTree = "> >>"; - staticSyntax = Has.Some.GreaterThan(0).And.Some.LessThan(100); - builderSyntax = Builder().Some.GreaterThan(0).And.Some.LessThan(100); + ParseTree = "> >>"; + StaticSyntax = Has.Some.GreaterThan(0).And.Some.LessThan(100); + BuilderSyntax = Builder().Some.GreaterThan(0).And.Some.LessThan(100); } } #endregion @@ -115,9 +115,9 @@ public class NoneTest : SyntaxTest [SetUp] public void SetUp() { - parseTree = ">"; - staticSyntax = Has.None.LessThan(0); - builderSyntax = Builder().None.LessThan(0); + ParseTree = ">"; + StaticSyntax = Has.None.LessThan(0); + BuilderSyntax = Builder().None.LessThan(0); } } #endregion @@ -128,9 +128,9 @@ public class Exactly_WithoutConstraint : SyntaxTest [SetUp] public void SetUp() { - parseTree = ""; - staticSyntax = Has.Exactly(3).Items; - builderSyntax = Builder().Exactly(3).Items; + ParseTree = ""; + StaticSyntax = Has.Exactly(3).Items; + BuilderSyntax = Builder().Exactly(3).Items; } } @@ -139,9 +139,9 @@ public class Exactly_WithConstraint : SyntaxTest [SetUp] public void SetUp() { - parseTree = ">"; - staticSyntax = Has.Exactly(3).Items.LessThan(0); - builderSyntax = Builder().Exactly(3).Items.LessThan(0); + ParseTree = ">"; + StaticSyntax = Has.Exactly(3).Items.LessThan(0); + BuilderSyntax = Builder().Exactly(3).Items.LessThan(0); } } @@ -150,9 +150,9 @@ public class Exactly_WithConstraint_BeforeBinaryOperators : SyntaxTest [SetUp] public void SetUp() { - parseTree = " >>>"; - staticSyntax = Has.Exactly(3).Items.LessThan(0).Or.GreaterThan(10).And.LessThan(20); - builderSyntax = Builder().Exactly(3).Items.LessThan(0).Or.GreaterThan(10).And.LessThan(20); + ParseTree = " >>>"; + StaticSyntax = Has.Exactly(3).Items.LessThan(0).Or.GreaterThan(10).And.LessThan(20); + BuilderSyntax = Builder().Exactly(3).Items.LessThan(0).Or.GreaterThan(10).And.LessThan(20); } } @@ -161,9 +161,9 @@ public class Exactly_WithConstraint_BeforeAndAfterBinaryOperators : SyntaxTest [SetUp] public void SetUp() { - parseTree = "> >>"; - staticSyntax = Has.Exactly(3).Items.LessThan(0).And.Exactly(3).Items.GreaterThan(10); - builderSyntax = Builder().Exactly(3).Items.LessThan(0).And.Exactly(3).Items.GreaterThan(10); + ParseTree = "> >>"; + StaticSyntax = Has.Exactly(3).Items.LessThan(0).And.Exactly(3).Items.GreaterThan(10); + BuilderSyntax = Builder().Exactly(3).Items.LessThan(0).And.Exactly(3).Items.GreaterThan(10); } } #endregion @@ -175,9 +175,9 @@ public class One_WithoutConstraint : SyntaxTest [SetUp] public void SetUp() { - parseTree = ""; - staticSyntax = Has.One.Items; - builderSyntax = Builder().One.Items; + ParseTree = ""; + StaticSyntax = Has.One.Items; + BuilderSyntax = Builder().One.Items; } } @@ -186,9 +186,9 @@ public class One_WithConstraint : SyntaxTest [SetUp] public void SetUp() { - parseTree = ">"; - staticSyntax = Has.One.Items.LessThan(0); - builderSyntax = Builder().One.Items.LessThan(0); + ParseTree = ">"; + StaticSyntax = Has.One.Items.LessThan(0); + BuilderSyntax = Builder().One.Items.LessThan(0); } } @@ -197,9 +197,9 @@ public class One_WithConstraint_BeforeBinaryOperators : SyntaxTest [SetUp] public void SetUp() { - parseTree = " >>>"; - staticSyntax = Has.One.Items.LessThan(0).Or.GreaterThan(10).And.LessThan(20); - builderSyntax = Builder().One.Items.LessThan(0).Or.GreaterThan(10).And.LessThan(20); + ParseTree = " >>>"; + StaticSyntax = Has.One.Items.LessThan(0).Or.GreaterThan(10).And.LessThan(20); + BuilderSyntax = Builder().One.Items.LessThan(0).Or.GreaterThan(10).And.LessThan(20); } } @@ -208,9 +208,9 @@ public class One_WithConstraint_BeforeAndAfterBinaryOperators : SyntaxTest [SetUp] public void SetUp() { - parseTree = "> >>"; - staticSyntax = Has.One.Items.LessThan(0).And.One.Items.GreaterThan(10); - builderSyntax = Builder().One.Items.LessThan(0).And.One.Items.GreaterThan(10); + ParseTree = "> >>"; + StaticSyntax = Has.One.Items.LessThan(0).And.One.Items.GreaterThan(10); + BuilderSyntax = Builder().One.Items.LessThan(0).And.One.Items.GreaterThan(10); } } @@ -222,9 +222,9 @@ public class AndTest : SyntaxTest [SetUp] public void SetUp() { - parseTree = " >"; - staticSyntax = Is.GreaterThan(5).And.LessThan(10); - builderSyntax = Builder().GreaterThan(5).And.LessThan(10); + ParseTree = " >"; + StaticSyntax = Is.GreaterThan(5).And.LessThan(10); + BuilderSyntax = Builder().GreaterThan(5).And.LessThan(10); } } @@ -233,9 +233,9 @@ public class AndTest_ThreeAndsWithNot : SyntaxTest [SetUp] public void SetUp() { - parseTree = "> > >>>"; - staticSyntax = Is.Not.Null.And.Not.LessThan(5).And.Not.GreaterThan(10); - builderSyntax = Builder().Not.Null.And.Not.LessThan(5).And.Not.GreaterThan(10); + ParseTree = "> > >>>"; + StaticSyntax = Is.Not.Null.And.Not.LessThan(5).And.Not.GreaterThan(10); + BuilderSyntax = Builder().Not.Null.And.Not.LessThan(5).And.Not.GreaterThan(10); } } #endregion @@ -246,9 +246,9 @@ public class OrTest : SyntaxTest [SetUp] public void SetUp() { - parseTree = " >"; - staticSyntax = Is.LessThan(5).Or.GreaterThan(10); - builderSyntax = Builder().LessThan(5).Or.GreaterThan(10); + ParseTree = " >"; + StaticSyntax = Is.LessThan(5).Or.GreaterThan(10); + BuilderSyntax = Builder().LessThan(5).Or.GreaterThan(10); } } @@ -257,9 +257,9 @@ public class OrTest_ThreeOrs : SyntaxTest [SetUp] public void SetUp() { - parseTree = " >>"; - staticSyntax = Is.LessThan(5).Or.GreaterThan(10).Or.EqualTo(7); - builderSyntax = Builder().LessThan(5).Or.GreaterThan(10).Or.EqualTo(7); + ParseTree = " >>"; + StaticSyntax = Is.LessThan(5).Or.GreaterThan(10).Or.EqualTo(7); + BuilderSyntax = Builder().LessThan(5).Or.GreaterThan(10).Or.EqualTo(7); } } #endregion @@ -270,9 +270,9 @@ public class AndIsEvaluatedBeforeFollowingOr : SyntaxTest [SetUp] public void SetUp() { - parseTree = " > >"; - staticSyntax = Is.LessThan(100).And.GreaterThan(0).Or.EqualTo(999); - builderSyntax = Builder().LessThan(100).And.GreaterThan(0).Or.EqualTo(999); + ParseTree = " > >"; + StaticSyntax = Is.LessThan(100).And.GreaterThan(0).Or.EqualTo(999); + BuilderSyntax = Builder().LessThan(100).And.GreaterThan(0).Or.EqualTo(999); } } @@ -281,9 +281,9 @@ public class AndIsEvaluatedBeforePrecedingOr : SyntaxTest [SetUp] public void SetUp() { - parseTree = " >>"; - staticSyntax = Is.EqualTo(999).Or.GreaterThan(0).And.LessThan(100); - builderSyntax = Builder().EqualTo(999).Or.GreaterThan(0).And.LessThan(100); + ParseTree = " >>"; + StaticSyntax = Is.EqualTo(999).Or.GreaterThan(0).And.LessThan(100); + BuilderSyntax = Builder().EqualTo(999).Or.GreaterThan(0).And.LessThan(100); } } #endregion diff --git a/src/NUnitFramework/tests/Syntax/PathConstraintTests.cs b/src/NUnitFramework/tests/Syntax/PathConstraintTests.cs index 6fe1ec4f48..44287d177b 100644 --- a/src/NUnitFramework/tests/Syntax/PathConstraintTests.cs +++ b/src/NUnitFramework/tests/Syntax/PathConstraintTests.cs @@ -1,4 +1,4 @@ -// *********************************************************************** +// *********************************************************************** // Copyright (c) 2009 Charlie Poole, Rob Prouse // // Permission is hereby granted, free of charge, to any person obtaining @@ -35,9 +35,9 @@ public void SetUp() string defaultCaseSensitivity = Path.DirectorySeparatorChar == '\\' ? "ignorecase" : "respectcase"; - parseTree = string.Format(@"", path, defaultCaseSensitivity); - staticSyntax = Is.SamePath(path); - builderSyntax = Builder().SamePath(path); + ParseTree = string.Format(@"", path, defaultCaseSensitivity); + StaticSyntax = Is.SamePath(path); + BuilderSyntax = Builder().SamePath(path); } } @@ -48,9 +48,9 @@ public void SetUp() { string path = "/path/to/match"; - parseTree = string.Format(@"", path); - staticSyntax = Is.SamePath(path).IgnoreCase; - builderSyntax = Builder().SamePath(path).IgnoreCase; + ParseTree = string.Format(@"", path); + StaticSyntax = Is.SamePath(path).IgnoreCase; + BuilderSyntax = Builder().SamePath(path).IgnoreCase; } } @@ -61,9 +61,9 @@ public void SetUp() { string path = "/path/to/match"; - parseTree = string.Format(@">", path); - staticSyntax = Is.Not.SamePath(path).IgnoreCase; - builderSyntax = Builder().Not.SamePath(path).IgnoreCase; + ParseTree = string.Format(@">", path); + StaticSyntax = Is.Not.SamePath(path).IgnoreCase; + BuilderSyntax = Builder().Not.SamePath(path).IgnoreCase; } } @@ -74,9 +74,9 @@ public void SetUp() { string path = "/path/to/match"; - parseTree = string.Format(@"", path); - staticSyntax = Is.SamePath(path).RespectCase; - builderSyntax = Builder().SamePath(path).RespectCase; + ParseTree = string.Format(@"", path); + StaticSyntax = Is.SamePath(path).RespectCase; + BuilderSyntax = Builder().SamePath(path).RespectCase; } } @@ -87,9 +87,9 @@ public void SetUp() { string path = "/path/to/match"; - parseTree = string.Format(@">", path); - staticSyntax = Is.Not.SamePath(path).RespectCase; - builderSyntax = Builder().Not.SamePath(path).RespectCase; + ParseTree = string.Format(@">", path); + StaticSyntax = Is.Not.SamePath(path).RespectCase; + BuilderSyntax = Builder().Not.SamePath(path).RespectCase; } } @@ -102,9 +102,9 @@ public void SetUp() string defaultCaseSensitivity = Path.DirectorySeparatorChar == '\\' ? "ignorecase" : "respectcase"; - parseTree = string.Format(@"", path, defaultCaseSensitivity); - staticSyntax = Is.SamePathOrUnder(path); - builderSyntax = Builder().SamePathOrUnder(path); + ParseTree = string.Format(@"", path, defaultCaseSensitivity); + StaticSyntax = Is.SamePathOrUnder(path); + BuilderSyntax = Builder().SamePathOrUnder(path); } } @@ -115,9 +115,9 @@ public void SetUp() { string path = "/path/to/match"; - parseTree = string.Format(@"", path); - staticSyntax = Is.SamePathOrUnder(path).IgnoreCase; - builderSyntax = Builder().SamePathOrUnder(path).IgnoreCase; + ParseTree = string.Format(@"", path); + StaticSyntax = Is.SamePathOrUnder(path).IgnoreCase; + BuilderSyntax = Builder().SamePathOrUnder(path).IgnoreCase; } } @@ -128,9 +128,9 @@ public void SetUp() { string path = "/path/to/match"; - parseTree = string.Format(@">", path); - staticSyntax = Is.Not.SamePathOrUnder(path).IgnoreCase; - builderSyntax = Builder().Not.SamePathOrUnder(path).IgnoreCase; + ParseTree = string.Format(@">", path); + StaticSyntax = Is.Not.SamePathOrUnder(path).IgnoreCase; + BuilderSyntax = Builder().Not.SamePathOrUnder(path).IgnoreCase; } } @@ -141,9 +141,9 @@ public void SetUp() { string path = "/path/to/match"; - parseTree = string.Format(@"", path); - staticSyntax = Is.SamePathOrUnder(path).RespectCase; - builderSyntax = Builder().SamePathOrUnder(path).RespectCase; + ParseTree = string.Format(@"", path); + StaticSyntax = Is.SamePathOrUnder(path).RespectCase; + BuilderSyntax = Builder().SamePathOrUnder(path).RespectCase; } } @@ -154,9 +154,9 @@ public void SetUp() { string path = "/path/to/match"; - parseTree = string.Format(@">", path); - staticSyntax = Is.Not.SamePathOrUnder(path).RespectCase; - builderSyntax = Builder().Not.SamePathOrUnder(path).RespectCase; + ParseTree = string.Format(@">", path); + StaticSyntax = Is.Not.SamePathOrUnder(path).RespectCase; + BuilderSyntax = Builder().Not.SamePathOrUnder(path).RespectCase; } } } diff --git a/src/NUnitFramework/tests/Syntax/PropertyTests.cs b/src/NUnitFramework/tests/Syntax/PropertyTests.cs index e51d571807..f211940274 100644 --- a/src/NUnitFramework/tests/Syntax/PropertyTests.cs +++ b/src/NUnitFramework/tests/Syntax/PropertyTests.cs @@ -1,4 +1,4 @@ -// *********************************************************************** +// *********************************************************************** // Copyright (c) 2009 Charlie Poole, Rob Prouse // // Permission is hereby granted, free of charge, to any person obtaining @@ -31,9 +31,9 @@ public class PropertyExistsTest : SyntaxTest [SetUp] public void SetUp() { - parseTree = ""; - staticSyntax = Has.Property("X"); - builderSyntax = Builder().Property("X"); + ParseTree = ""; + StaticSyntax = Has.Property("X"); + BuilderSyntax = Builder().Property("X"); } } @@ -42,9 +42,9 @@ public class PropertyExistsTest_AndFollows : SyntaxTest [SetUp] public void SetUp() { - parseTree = " >"; - staticSyntax = Has.Property("X").And.EqualTo(7); - builderSyntax = Builder().Property("X").And.EqualTo(7); + ParseTree = " >"; + StaticSyntax = Has.Property("X").And.EqualTo(7); + BuilderSyntax = Builder().Property("X").And.EqualTo(7); } } @@ -53,9 +53,9 @@ public class PropertyTest_ConstraintFollows : SyntaxTest [SetUp] public void SetUp() { - parseTree = ">"; - staticSyntax = Has.Property("X").GreaterThan(5); - builderSyntax = Builder().Property("X").GreaterThan(5); + ParseTree = ">"; + StaticSyntax = Has.Property("X").GreaterThan(5); + BuilderSyntax = Builder().Property("X").GreaterThan(5); } } @@ -64,9 +64,9 @@ public class PropertyTest_NotFollows : SyntaxTest [SetUp] public void SetUp() { - parseTree = ">>"; - staticSyntax = Has.Property("X").Not.GreaterThan(5); - builderSyntax = Builder().Property("X").Not.GreaterThan(5); + ParseTree = ">>"; + StaticSyntax = Has.Property("X").Not.GreaterThan(5); + BuilderSyntax = Builder().Property("X").Not.GreaterThan(5); } } @@ -75,9 +75,9 @@ public class LengthTest : SyntaxTest [SetUp] public void SetUp() { - parseTree = ">"; - staticSyntax = Has.Length.GreaterThan(5); - builderSyntax = Builder().Length.GreaterThan(5); + ParseTree = ">"; + StaticSyntax = Has.Length.GreaterThan(5); + BuilderSyntax = Builder().Length.GreaterThan(5); } } @@ -86,9 +86,9 @@ public class CountTest : SyntaxTest [SetUp] public void SetUp() { - parseTree = ">"; - staticSyntax = Has.Count.EqualTo(5); - builderSyntax = Builder().Count.EqualTo(5); + ParseTree = ">"; + StaticSyntax = Has.Count.EqualTo(5); + BuilderSyntax = Builder().Count.EqualTo(5); } } @@ -97,9 +97,9 @@ public class MessageTest : SyntaxTest [SetUp] public void SetUp() { - parseTree = @">"; - staticSyntax = Has.Message.StartsWith("Expected"); - builderSyntax = Builder().Message.StartsWith("Expected"); + ParseTree = @">"; + StaticSyntax = Has.Message.StartsWith("Expected"); + BuilderSyntax = Builder().Message.StartsWith("Expected"); } } @@ -121,4 +121,4 @@ public void SeparateConstraintTest() Assert.That(ints, Has.Length.EqualTo(3)); } } -} \ No newline at end of file +} diff --git a/src/NUnitFramework/tests/Syntax/SerializableConstraints.cs b/src/NUnitFramework/tests/Syntax/SerializableConstraints.cs index 2fce168b1b..b47ccc3bc8 100644 --- a/src/NUnitFramework/tests/Syntax/SerializableConstraints.cs +++ b/src/NUnitFramework/tests/Syntax/SerializableConstraints.cs @@ -30,9 +30,9 @@ public class BinarySerializableTest : SyntaxTest [SetUp] public void SetUp() { - parseTree = ""; - staticSyntax = Is.BinarySerializable; - builderSyntax = Builder().BinarySerializable; + ParseTree = ""; + StaticSyntax = Is.BinarySerializable; + BuilderSyntax = Builder().BinarySerializable; } } @@ -42,9 +42,9 @@ public class XmlSerializableTest : SyntaxTest [SetUp] public void SetUp() { - parseTree = ""; - staticSyntax = Is.XmlSerializable; - builderSyntax = Builder().XmlSerializable; + ParseTree = ""; + StaticSyntax = Is.XmlSerializable; + BuilderSyntax = Builder().XmlSerializable; } } } diff --git a/src/NUnitFramework/tests/Syntax/SimpleConstraints.cs b/src/NUnitFramework/tests/Syntax/SimpleConstraints.cs index 073d182256..32158710f9 100644 --- a/src/NUnitFramework/tests/Syntax/SimpleConstraints.cs +++ b/src/NUnitFramework/tests/Syntax/SimpleConstraints.cs @@ -1,4 +1,4 @@ -// *********************************************************************** +// *********************************************************************** // Copyright (c) 2009 Charlie Poole, Rob Prouse // // Permission is hereby granted, free of charge, to any person obtaining @@ -30,9 +30,9 @@ public class NullTest : SyntaxTest [SetUp] public void SetUp() { - parseTree = ""; - staticSyntax = Is.Null; - builderSyntax = Builder().Null; + ParseTree = ""; + StaticSyntax = Is.Null; + BuilderSyntax = Builder().Null; } } @@ -41,9 +41,9 @@ public class TrueTest : SyntaxTest [SetUp] public void SetUp() { - parseTree = ""; - staticSyntax = Is.True; - builderSyntax = Builder().True; + ParseTree = ""; + StaticSyntax = Is.True; + BuilderSyntax = Builder().True; } } @@ -52,9 +52,9 @@ public class FalseTest : SyntaxTest [SetUp] public void SetUp() { - parseTree = ""; - staticSyntax = Is.False; - builderSyntax = Builder().False; + ParseTree = ""; + StaticSyntax = Is.False; + BuilderSyntax = Builder().False; } } @@ -63,9 +63,9 @@ public class PositiveTest : SyntaxTest [SetUp] public void SetUp() { - parseTree = ""; - staticSyntax = Is.Positive; - builderSyntax = Builder().Positive; + ParseTree = ""; + StaticSyntax = Is.Positive; + BuilderSyntax = Builder().Positive; } } @@ -74,9 +74,9 @@ public class NegativeTest : SyntaxTest [SetUp] public void SetUp() { - parseTree = ""; - staticSyntax = Is.Negative; - builderSyntax = Builder().Negative; + ParseTree = ""; + StaticSyntax = Is.Negative; + BuilderSyntax = Builder().Negative; } } @@ -85,9 +85,9 @@ public class ZeroTest : SyntaxTest [SetUp] public void SetUp() { - parseTree = ""; - staticSyntax = Is.Zero; - builderSyntax = Builder().Zero; + ParseTree = ""; + StaticSyntax = Is.Zero; + BuilderSyntax = Builder().Zero; } } @@ -96,9 +96,9 @@ public class NaNTest : SyntaxTest [SetUp] public void SetUp() { - parseTree = ""; - staticSyntax = Is.NaN; - builderSyntax = Builder().NaN; + ParseTree = ""; + StaticSyntax = Is.NaN; + BuilderSyntax = Builder().NaN; } } } diff --git a/src/NUnitFramework/tests/Syntax/StringConstraints.cs b/src/NUnitFramework/tests/Syntax/StringConstraints.cs index 6f0251092f..69b5caa9d4 100644 --- a/src/NUnitFramework/tests/Syntax/StringConstraints.cs +++ b/src/NUnitFramework/tests/Syntax/StringConstraints.cs @@ -1,4 +1,4 @@ -// *********************************************************************** +// *********************************************************************** // Copyright (c) 2009 Charlie Poole, Rob Prouse // // Permission is hereby granted, free of charge, to any person obtaining @@ -30,9 +30,9 @@ public class ContainsTest : SyntaxTest [SetUp] public void SetUp() { - parseTree = @""; - staticSyntax = Does.Contain("X"); - builderSyntax = Builder().Contains("X"); + ParseTree = @""; + StaticSyntax = Does.Contain("X"); + BuilderSyntax = Builder().Contains("X"); } } @@ -41,9 +41,9 @@ public class ContainsTest_IgnoreCase : SyntaxTest [SetUp] public void SetUp() { - parseTree = @""; - staticSyntax = Does.Contain("X").IgnoreCase; - builderSyntax = Builder().Contains("X").IgnoreCase; + ParseTree = @""; + StaticSyntax = Does.Contain("X").IgnoreCase; + BuilderSyntax = Builder().Contains("X").IgnoreCase; } } @@ -52,9 +52,9 @@ public class StartsWithTest : SyntaxTest [SetUp] public void SetUp() { - parseTree = @""; - staticSyntax = Does.StartWith("X"); - builderSyntax = Builder().StartsWith("X"); + ParseTree = @""; + StaticSyntax = Does.StartWith("X"); + BuilderSyntax = Builder().StartsWith("X"); } } @@ -63,9 +63,9 @@ public class TextStartsWithTest : SyntaxTest [SetUp] public void SetUp() { - parseTree = @""; - staticSyntax = Does.StartWith("X"); - builderSyntax = Builder().StartsWith("X"); + ParseTree = @""; + StaticSyntax = Does.StartWith("X"); + BuilderSyntax = Builder().StartsWith("X"); } } @@ -74,9 +74,9 @@ public class StartsWithTest_IgnoreCase : SyntaxTest [SetUp] public void SetUp() { - parseTree = @""; - staticSyntax = Does.StartWith("X").IgnoreCase; - builderSyntax = Builder().StartsWith("X").IgnoreCase; + ParseTree = @""; + StaticSyntax = Does.StartWith("X").IgnoreCase; + BuilderSyntax = Builder().StartsWith("X").IgnoreCase; } } @@ -85,9 +85,9 @@ public class EndsWithTest : SyntaxTest [SetUp] public void SetUp() { - parseTree = @""; - staticSyntax = Does.EndWith("X"); - builderSyntax = Builder().EndsWith("X"); + ParseTree = @""; + StaticSyntax = Does.EndWith("X"); + BuilderSyntax = Builder().EndsWith("X"); } } @@ -96,9 +96,9 @@ public class EndsWithTest_IgnoreCase : SyntaxTest [SetUp] public void SetUp() { - parseTree = @""; - staticSyntax = Does.EndWith("X").IgnoreCase; - builderSyntax = Builder().EndsWith("X").IgnoreCase; + ParseTree = @""; + StaticSyntax = Does.EndWith("X").IgnoreCase; + BuilderSyntax = Builder().EndsWith("X").IgnoreCase; } } @@ -107,9 +107,9 @@ public class RegexTest : SyntaxTest [SetUp] public void SetUp() { - parseTree = @""; - staticSyntax = Does.Match("X"); - builderSyntax = Builder().Matches("X"); + ParseTree = @""; + StaticSyntax = Does.Match("X"); + BuilderSyntax = Builder().Matches("X"); } } @@ -118,9 +118,9 @@ public class RegexTest_IgnoreCase : SyntaxTest [SetUp] public void SetUp() { - parseTree = @""; - staticSyntax = Does.Match("X").IgnoreCase; - builderSyntax = Builder().Matches("X").IgnoreCase; + ParseTree = @""; + StaticSyntax = Does.Match("X").IgnoreCase; + BuilderSyntax = Builder().Matches("X").IgnoreCase; } } } diff --git a/src/NUnitFramework/tests/Syntax/SyntaxTest.cs b/src/NUnitFramework/tests/Syntax/SyntaxTest.cs index 3e8bf85c6d..f1e9fd5e1a 100644 --- a/src/NUnitFramework/tests/Syntax/SyntaxTest.cs +++ b/src/NUnitFramework/tests/Syntax/SyntaxTest.cs @@ -1,4 +1,4 @@ -// *********************************************************************** +// *********************************************************************** // Copyright (c) 2009 Charlie Poole, Rob Prouse // // Permission is hereby granted, free of charge, to any person obtaining @@ -28,9 +28,9 @@ namespace NUnit.Framework.Syntax { public abstract class SyntaxTest { - protected string parseTree; - protected IResolveConstraint staticSyntax; - protected IResolveConstraint builderSyntax; + protected string ParseTree; + protected IResolveConstraint StaticSyntax; + protected IResolveConstraint BuilderSyntax; protected ConstraintExpression Builder() { @@ -41,16 +41,16 @@ protected ConstraintExpression Builder() public void SupportedByStaticSyntax() { Assert.That( - staticSyntax.Resolve().ToString(), - Is.EqualTo(parseTree).NoClip); + StaticSyntax.Resolve().ToString(), + Is.EqualTo(ParseTree).NoClip); } [Test] public void SupportedByConstraintBuilder() { Assert.That( - builderSyntax.Resolve().ToString(), - Is.EqualTo(parseTree).NoClip); + BuilderSyntax.Resolve().ToString(), + Is.EqualTo(ParseTree).NoClip); } } } diff --git a/src/NUnitFramework/tests/Syntax/TypeConstraints.cs b/src/NUnitFramework/tests/Syntax/TypeConstraints.cs index 1af4927161..63ccefe315 100644 --- a/src/NUnitFramework/tests/Syntax/TypeConstraints.cs +++ b/src/NUnitFramework/tests/Syntax/TypeConstraints.cs @@ -1,4 +1,4 @@ -// *********************************************************************** +// *********************************************************************** // Copyright (c) 2009 Charlie Poole, Rob Prouse // // Permission is hereby granted, free of charge, to any person obtaining @@ -31,9 +31,9 @@ public class ExactTypeTest : SyntaxTest [SetUp] public void SetUp() { - parseTree = ""; - staticSyntax = Is.TypeOf(typeof(string)); - builderSyntax = Builder().TypeOf(typeof(string)); + ParseTree = ""; + StaticSyntax = Is.TypeOf(typeof(string)); + BuilderSyntax = Builder().TypeOf(typeof(string)); } } @@ -43,9 +43,9 @@ public class InstanceOfTest : SyntaxTest [SetUp] public void SetUp() { - parseTree = ""; - staticSyntax = Is.InstanceOf(typeof(string)); - builderSyntax = Builder().InstanceOf(typeof(string)); + ParseTree = ""; + StaticSyntax = Is.InstanceOf(typeof(string)); + BuilderSyntax = Builder().InstanceOf(typeof(string)); } } @@ -55,9 +55,9 @@ public class AssignableFromTest : SyntaxTest [SetUp] public void SetUp() { - parseTree = ""; - staticSyntax = Is.AssignableFrom(typeof(string)); - builderSyntax = Builder().AssignableFrom(typeof(string)); + ParseTree = ""; + StaticSyntax = Is.AssignableFrom(typeof(string)); + BuilderSyntax = Builder().AssignableFrom(typeof(string)); } } @@ -67,9 +67,9 @@ public class AssignableToTest : SyntaxTest [SetUp] public void SetUp() { - parseTree = ""; - staticSyntax = Is.AssignableTo(typeof(string)); - builderSyntax = Builder().AssignableTo(typeof(string)); + ParseTree = ""; + StaticSyntax = Is.AssignableTo(typeof(string)); + BuilderSyntax = Builder().AssignableTo(typeof(string)); } } @@ -79,9 +79,9 @@ public class AttributeTest : SyntaxTest [SetUp] public void SetUp() { - parseTree = ""; - staticSyntax = Has.Attribute(typeof(TestFixtureAttribute)); - builderSyntax = Builder().Attribute(typeof(TestFixtureAttribute)); + ParseTree = ""; + StaticSyntax = Has.Attribute(typeof(TestFixtureAttribute)); + BuilderSyntax = Builder().Attribute(typeof(TestFixtureAttribute)); } } @@ -91,9 +91,9 @@ public class AttributeTestWithFollowingConstraint : SyntaxTest [SetUp] public void SetUp() { - parseTree = @">>>"; - staticSyntax = Has.Attribute(typeof(TestFixtureAttribute)).Property("Description").Not.Null; - builderSyntax = Builder().Attribute(typeof(TestFixtureAttribute)).Property("Description").Not.Null; + ParseTree = @">>>"; + StaticSyntax = Has.Attribute(typeof(TestFixtureAttribute)).Property("Description").Not.Null; + BuilderSyntax = Builder().Attribute(typeof(TestFixtureAttribute)).Property("Description").Not.Null; } } @@ -103,9 +103,9 @@ public class ExactTypeTest_Generic : SyntaxTest [SetUp] public void SetUp() { - parseTree = ""; - staticSyntax = Is.TypeOf(); - builderSyntax = Builder().TypeOf(); + ParseTree = ""; + StaticSyntax = Is.TypeOf(); + BuilderSyntax = Builder().TypeOf(); } } @@ -115,9 +115,9 @@ public class InstanceOfTest_Generic : SyntaxTest [SetUp] public void SetUp() { - parseTree = ""; - staticSyntax = Is.InstanceOf(); - builderSyntax = Builder().InstanceOf(); + ParseTree = ""; + StaticSyntax = Is.InstanceOf(); + BuilderSyntax = Builder().InstanceOf(); } } @@ -127,9 +127,9 @@ public class AssignableFromTest_Generic : SyntaxTest [SetUp] public void SetUp() { - parseTree = ""; - staticSyntax = Is.AssignableFrom(); - builderSyntax = Builder().AssignableFrom(); + ParseTree = ""; + StaticSyntax = Is.AssignableFrom(); + BuilderSyntax = Builder().AssignableFrom(); } } @@ -139,9 +139,9 @@ public class AssignableToTest_Generic : SyntaxTest [SetUp] public void SetUp() { - parseTree = ""; - staticSyntax = Is.AssignableTo(); - builderSyntax = Builder().AssignableTo(); + ParseTree = ""; + StaticSyntax = Is.AssignableTo(); + BuilderSyntax = Builder().AssignableTo(); } } @@ -151,9 +151,9 @@ public class AttributeTest_Generic : SyntaxTest [SetUp] public void SetUp() { - parseTree = ""; - staticSyntax = Has.Attribute(); - builderSyntax = Builder().Attribute(); + ParseTree = ""; + StaticSyntax = Has.Attribute(); + BuilderSyntax = Builder().Attribute(); } } } diff --git a/src/NUnitFramework/tests/TestContextTests.cs b/src/NUnitFramework/tests/TestContextTests.cs index 7e790caa70..3fef617479 100644 --- a/src/NUnitFramework/tests/TestContextTests.cs +++ b/src/NUnitFramework/tests/TestContextTests.cs @@ -25,7 +25,7 @@ using System.IO; using System.Collections.Generic; using System.Linq; -#if ASYNC +#if TASK_PARALLEL_LIBRARY_API using System.Threading.Tasks; #endif using NUnit.Framework.Interfaces; @@ -282,34 +282,34 @@ public void TestCanAccessTestState_PassingTest() { TestStateRecordingFixture fixture = new TestStateRecordingFixture(); TestBuilder.RunTestFixture(fixture); - Assert.That(fixture.stateList, Is.EqualTo("Inconclusive=>Inconclusive=>Passed")); + Assert.That(fixture.StateList, Is.EqualTo("Inconclusive=>Inconclusive=>Passed")); } [Test] public void TestCanAccessTestState_FailureInSetUp() { TestStateRecordingFixture fixture = new TestStateRecordingFixture(); - fixture.setUpFailure = true; + fixture.SetUpFailure = true; TestBuilder.RunTestFixture(fixture); - Assert.That(fixture.stateList, Is.EqualTo("Inconclusive=>=>Failed")); + Assert.That(fixture.StateList, Is.EqualTo("Inconclusive=>=>Failed")); } [Test] public void TestCanAccessTestState_FailingTest() { TestStateRecordingFixture fixture = new TestStateRecordingFixture(); - fixture.testFailure = true; + fixture.TestFailure = true; TestBuilder.RunTestFixture(fixture); - Assert.That(fixture.stateList, Is.EqualTo("Inconclusive=>Inconclusive=>Failed")); + Assert.That(fixture.StateList, Is.EqualTo("Inconclusive=>Inconclusive=>Failed")); } [Test] public void TestCanAccessTestState_IgnoredInSetUp() { TestStateRecordingFixture fixture = new TestStateRecordingFixture(); - fixture.setUpIgnore = true; + fixture.SetUpIgnore = true; TestBuilder.RunTestFixture(fixture); - Assert.That(fixture.stateList, Is.EqualTo("Inconclusive=>=>Skipped:Ignored")); + Assert.That(fixture.StateList, Is.EqualTo("Inconclusive=>=>Skipped:Ignored")); } [Test] @@ -340,7 +340,7 @@ public void TestContextStoresFailureInfoForOneTimeTearDown() #region Out -#if ASYNC +#if TASK_PARALLEL_LIBRARY_API [Test] public async Task TestContextOut_ShouldFlowWithAsyncExecution() { diff --git a/src/NUnitFramework/tests/TestUtilities/AsyncTestDelegates.cs b/src/NUnitFramework/tests/TestUtilities/AsyncTestDelegates.cs index ed28f0b761..1af5155f72 100644 --- a/src/NUnitFramework/tests/TestUtilities/AsyncTestDelegates.cs +++ b/src/NUnitFramework/tests/TestUtilities/AsyncTestDelegates.cs @@ -1,4 +1,4 @@ -#if ASYNC +#if TASK_PARALLEL_LIBRARY_API using System; using System.Threading.Tasks; @@ -61,4 +61,4 @@ public static Task Delay(int milliseconds) } } -#endif \ No newline at end of file +#endif diff --git a/src/NUnitFramework/tests/TestUtilities/CallbackEventHandler.cs b/src/NUnitFramework/tests/TestUtilities/CallbackEventHandler.cs new file mode 100644 index 0000000000..778d772f33 --- /dev/null +++ b/src/NUnitFramework/tests/TestUtilities/CallbackEventHandler.cs @@ -0,0 +1,40 @@ +// *********************************************************************** +// Copyright (c) 2014 Charlie Poole, Rob Prouse +// +// 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. +// *********************************************************************** + +namespace NUnit.TestUtilities +{ + public class CallbackEventHandler : System.Web.UI.ICallbackEventHandler + { + private string _result; + + public string GetCallbackResult() + { + return _result; + } + + public void RaiseCallbackEvent(string eventArgument) + { + _result = eventArgument; + } + } +} diff --git a/src/NUnitFramework/tests/TestUtilities/CallbackWatcher.cs b/src/NUnitFramework/tests/TestUtilities/CallbackWatcher.cs new file mode 100644 index 0000000000..6f1101541b --- /dev/null +++ b/src/NUnitFramework/tests/TestUtilities/CallbackWatcher.cs @@ -0,0 +1,107 @@ +// *********************************************************************** +// Copyright (c) 2019 Charlie Poole, Rob Prouse +// +// 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 NUnit.Framework; +using NUnit.Framework.Internal; + +namespace NUnit.TestUtilities +{ + /// + /// Provides idiomatic callback-based assertions. + /// + /// + /// + /// var watcher = new CallbackWatcher(); + /// + /// systemUnderTest.PropertyChanged += (sender, e) => watcher.OnCallback(); + /// + /// using (watcher.ExpectCallback()) + /// { + /// systemUnderTest.SomeProperty = 42; + /// } // Fails if PropertyChanged did not fire + /// + /// systemUnderTest.SomeProperty = 42; // Fails if PropertyChanged fires + /// + /// + public sealed class CallbackWatcher + { + private int _expectedCount; + private int _actualCount; + + /// + /// Begins expecting callbacks. When the returned scope is disposed, stops expecting callbacks and throws + /// if was not called the expected number of times between beginning and ending. + /// + /// + /// The number of times that is expected to be called before the returned scope is disposed. + /// + /// Thrown when is less than 1. + /// Thrown when the returned scope from the previous call has not been disposed. + /// Thrown when was not called the expected number of times between beginning and ending. + public IDisposable ExpectCallback(int count = 1) + { + if (count < 0) + throw new ArgumentOutOfRangeException(nameof(count), _expectedCount, "Expected callback count must be greater than or equal to zero."); + + if (_expectedCount != 0) + throw new InvalidOperationException($"The previous {nameof(ExpectCallback)} scope must be disposed before calling again."); + + _expectedCount = count; + _actualCount = 0; + + return On.Dispose(() => + { + try + { + if (_actualCount < _expectedCount) + Assert.Fail($"Expected {(_expectedCount == 1 ? "a single call" : _expectedCount + " calls")}, but there {(_actualCount == 1 ? "was" : "were")} {_actualCount}."); + } + finally + { + _expectedCount = 0; + } + }); + } + + /// + /// Call this from the callback being tested. + /// Throws if this watcher is not currently expecting a callback + /// (see ) or if the expected number of callbacks has been exceeded. + /// + /// + /// Thrown when this watcher is not currently expecting a callback (see ) + /// or if the expected number of callbacks has been exceeded. + /// + public void OnCallback() + { + _actualCount++; + if (_actualCount > _expectedCount) + { + Assert.Fail(_expectedCount == 0 + ? "Expected no callback." + : $"Expected {(_expectedCount == 1 ? "a single call" : _expectedCount + " calls")}, but there were more."); + } + } + } +} diff --git a/src/NUnitFramework/tests/TestUtilities/StressUtility.cs b/src/NUnitFramework/tests/TestUtilities/StressUtility.cs index b4bff7e68a..b13335b2b3 100644 --- a/src/NUnitFramework/tests/TestUtilities/StressUtility.cs +++ b/src/NUnitFramework/tests/TestUtilities/StressUtility.cs @@ -58,7 +58,7 @@ public static void RunParallel(Action action, int times, int maxParallelism, boo } catch (Exception ex) { -#if NET20 || NET35 || NET40 +#if NET35 || NET40 exception = ex; times = 0; Thread.MemoryBarrier(); @@ -91,7 +91,7 @@ public static void RunParallel(Action action, int times, int maxParallelism, boo noMoreThreadsEvent.Wait(); -#if NET20 || NET35 || NET40 +#if NET35 || NET40 Thread.MemoryBarrier(); if (exception != null) #else diff --git a/src/NUnitFramework/tests/TestUtilities/TestUtils.cs b/src/NUnitFramework/tests/TestUtilities/TestUtils.cs new file mode 100644 index 0000000000..d5853db70e --- /dev/null +++ b/src/NUnitFramework/tests/TestUtilities/TestUtils.cs @@ -0,0 +1,45 @@ +// *********************************************************************** +// Copyright (c) 2019 Charlie Poole, Rob Prouse +// +// 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.Internal; + +namespace NUnit.TestUtilities +{ + internal static class TestUtils + { + public static IDisposable TemporarySynchronizationContext(SynchronizationContext synchronizationContext) + { + var restore = RestoreSynchronizationContext(); + SynchronizationContext.SetSynchronizationContext(synchronizationContext); + return restore; + } + + public static IDisposable RestoreSynchronizationContext() + { + var originalContext = SynchronizationContext.Current; + return On.Dispose(() => SynchronizationContext.SetSynchronizationContext(originalContext)); + } + } +} diff --git a/src/NUnitFramework/tests/nunit.framework.tests.csproj b/src/NUnitFramework/tests/nunit.framework.tests.csproj index ccda099ae1..e9847b45d6 100644 --- a/src/NUnitFramework/tests/nunit.framework.tests.csproj +++ b/src/NUnitFramework/tests/nunit.framework.tests.csproj @@ -1,7 +1,7 @@ - net20;net35;net40;net45;netcoreapp1.1;netcoreapp2.0 + net35;net40;net45;netcoreapp1.1;netcoreapp2.0 NUnit.Framework Full @@ -16,7 +16,7 @@ - + @@ -27,14 +27,14 @@ - + - + diff --git a/tools/packages.config b/tools/packages.config index d654602931..05018882e8 100644 --- a/tools/packages.config +++ b/tools/packages.config @@ -1,4 +1,4 @@ - +