Skip to content

Commit 0f4c624

Browse files
authored
Test Formatting assemblies w/ net6.0 (#384)
- expand our text matrix to include a modern (and LTS) TFM - change how Formatting test assemblies are found - `netcoreapp` is no longer the only relevant folder prefix - use the latest .NET 6 SDK - install the 2.1.x runtime in the pipeline - don't require .NET in VS - will use binplaced `msbuild` instead - have `git` ignore the new .msbuild/ folder - react to new `Exception.Message`s in `netcoreapp3.1` - handle different formatting of argument info in `ArgumentException.Message`s - handle slightly greater `decimal` precision in a `JsonReaderException.Message` - react to new `Exception.Message`s and other changes in `net6.0` - handle different `Message` in `InvalidOperationException`s about invalid request URIs - react to other changes in `net6.0` - handle inability to mock a `Stream` if a writer passes a `ReadOnlySpan<byte>` in `net6.0` - see devlooped/moq#829, devlooped/moq#979, and dotnet/runtime#45152 about the issue - skip tests failing due to `HttpResponseMessage` changes - see #386 and dotnet/runtime@b48900f (which introduced this) - fix coming **Real Soon Now:tm:** :grin: - nits: - simplify define use now that `NETCOREAPP3_1_OR_GREATER` and so on are available - clean up .gitignore - clean up a few comments and tighten scripting up
1 parent 169d95f commit 0f4c624

18 files changed

+163
-63
lines changed

.gitignore

Lines changed: 13 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -1,22 +1,20 @@
1-
[Bb]in
2-
[Oo]bj
3-
[Tt]est[Rr]esults
4-
*.suo
5-
*.user
1+
.msbuild/
2+
.vs/
3+
bin/
4+
obj/
5+
packages/
6+
67
*.[Cc]ache
7-
*[Rr]esharper*
8-
packages
9-
NuGet.exe
10-
_[Ss]cripts
118
*.binlog
12-
*.exe
139
*.dll
14-
*.nupkg
1510
*.dot[Cc]over
16-
*.vsp
17-
*.psess
11+
*.exe
12+
*.nupkg
1813
*.orig
14+
*.psess
1915
*.sln.ide
20-
.vs/
21-
project.lock.json
16+
*.suo
17+
*.user
18+
*.vsp
19+
*[Rr]esharper*
2220
*launchSettings.json

Runtime.msbuild

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -115,12 +115,12 @@
115115
XmlPath=$(TestResultsDirectory)%(_TestDLLsXunit.FileName)-XunitResults.xml</Properties>
116116
</_XunitProject>
117117

118-
<_VSTestDLLs Include="bin\$(Configuration)\test\*\netcoreapp*\*.Test.dll"
119-
Condition=" '$(BuildPortable)' == 'true' "/>
120-
<_XunitProject Include="tools\WebStack.testing.targets"
121-
Condition=" '$(BuildPortable)' == 'true' ">
118+
<_VSTestDLLs Include="bin\$(Configuration)\test\NetCore\**\*.Test.dll;
119+
bin\$(Configuration)\test\NetStandard\**\*.Test.dll"
120+
Exclude="bin\$(Configuration)\test\Net*\net4*\*.Test.dll" />
121+
<_XunitProject Include="tools\WebStack.testing.targets" Condition=" '$(BuildPortable)' == 'true' ">
122122
<Properties>TestAssembly=%(_VSTestDLLs.FullPath);
123-
XmlPath=$(TestResultsDirectory)%(_VSTestDLLs.FileName)-NetCoreApp-XunitResults.xml;
123+
XmlPath=$(TestResultsDirectory)%(_VSTestDLLs.FileName)-$([System.String]::Copy('%(_VSTestDLLs.RecursiveDir)').Trim('\\'))-XunitResults.xml;
124124
UseVSTest=true</Properties>
125125
</_XunitProject>
126126
</ItemGroup>

azure-pipelines.yml

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -60,10 +60,16 @@ jobs:
6060
- checkout: self
6161
clean: true
6262
displayName: Checkout
63+
6364
- task: UseDotNet@2
6465
displayName: Get .NET SDK
6566
inputs:
6667
useGlobalJson: true
68+
- task: UseDotNet@2
69+
displayName: Get .NET 2.1 runtime
70+
inputs:
71+
packageType: runtime
72+
version: '2.1.x'
6773

6874
- script: .\build.cmd EnableSkipStrongNames
6975
displayName: Enable SkipStrongNames

build.cmd

Lines changed: 21 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -2,13 +2,12 @@
22
pushd %~dp0
33
setlocal
44

5-
if exist bin goto build
5+
if exist bin goto Build
66
mkdir bin
77

88
:Build
99

10-
REM Find the most recent 32bit MSBuild.exe on the system. Require v16.0 (installed with VS2019) or later.
11-
REM Use `vswhere` for the search because it can find all VS installations.
10+
REM Require VS2019 (v16.0) on the system. Use `vswhere` for the search because it can find all VS installations.
1211
set vswhere="%ProgramFiles(x86)%\Microsoft Visual Studio\Installer\vswhere.exe"
1312
if not exist %vswhere% (
1413
set vswhere="%ProgramFiles%\Microsoft Visual Studio\Installer\vswhere.exe"
@@ -24,28 +23,33 @@ if not exist %vswhere% (
2423
goto BuildFail
2524
)
2625

27-
REM We're fine w/ any .NET SDK newer than 2.1.500 but also need a 2.1.x runtime. Microsoft.Net.Core.Component.SDK.2.1
28-
REM actually checks for only the runtime these days.
2926
set InstallDir=
3027
for /f "usebackq tokens=*" %%i in (`%vswhere% -version 16 -latest -prerelease -products * ^
31-
-requires Microsoft.Component.MSBuild ^
32-
-requires Microsoft.NetCore.Component.SDK ^
33-
-requires Microsoft.Net.Core.Component.SDK.2.1 ^
28+
-requires Microsoft.Net.Component.4.5.TargetingPack ^
29+
-requires Microsoft.Net.Component.4.5.2.TargetingPack ^
30+
-requires Microsoft.Net.Component.4.6.2.TargetingPack ^
3431
-property installationPath`) do (
3532
set InstallDir="%%i"
3633
)
3734

3835
if not DEFINED InstallDir (
39-
echo "Could not find a VS2019 installation with the necessary components (MSBuild, .NET Core 2.1 Runtime, .NET SDK). Please install VS2019 or the missing components."
40-
)
41-
42-
if exist %InstallDir%\MSBuild\Current\Bin\MSBuild.exe (
43-
set MSBuild=%InstallDir%\MSBuild\Current\Bin\MSBuild.exe
44-
) else (
45-
echo Could not find MSBuild.exe. Please install the VS2019 BuildTools component or a workload that includes it.
36+
echo "Could not find a VS2019 installation with the necessary components (targeting packs for v4.5, v4.5.2, and v4.6.2)."
37+
echo Please install VS2019 or the missing components.
4638
goto BuildFail
4739
)
4840

41+
REM Find or install MSBuild. Need v17.4 due to our .NET SDK choice.
42+
set "MSBuildVersion=17.4.1"
43+
set "Command=[System.Threading.Thread]::CurrentThread.CurrentCulture = ''"
44+
set "Command=%Command%; [System.Threading.Thread]::CurrentThread.CurrentUICulture = ''"
45+
set "Command=%Command%; try { & '%~dp0eng\GetXCopyMSBuild.ps1' %MSBuildVersion%; exit $LASTEXITCODE }"
46+
set "Command=%Command% catch { write-host $_; exit 1 }"
47+
PowerShell -NoProfile -NoLogo -ExecutionPolicy Bypass -Command "%Command%"
48+
if %ERRORLEVEL% neq 0 goto BuildFail
49+
50+
REM Add MSBuild to the path.
51+
set "PATH=%CD%\.msbuild\%MSBuildVersion%\tools\MSBuild\Current\Bin\;%PATH%"
52+
4953
REM Configure NuGet operations to work w/in this repo i.e. do not pollute system packages folder.
5054
REM Note this causes two copies of packages restored using packages.config to land in this folder e.g.
5155
REM StyleCpy.5.0.0/ and stylecop/5.0.0/.
@@ -56,13 +60,13 @@ if DEFINED CI (set Desktop=false) else if DEFINED TEAMCITY_VERSION (set Desktop=
5660

5761
if "%1" == "" goto BuildDefaults
5862

59-
%MSBuild% Runtime.msbuild /m /nr:false /p:Platform="Any CPU" /p:Desktop=%Desktop% /v:M ^
63+
MSBuild Runtime.msbuild /m /nr:false /p:Platform="Any CPU" /p:Desktop=%Desktop% /v:M ^
6064
/fl /fileLoggerParameters:LogFile=bin\msbuild.log;Verbosity=Normal /consoleLoggerParameters:Summary /t:%*
6165
if %ERRORLEVEL% neq 0 goto BuildFail
6266
goto BuildSuccess
6367

6468
:BuildDefaults
65-
%MSBuild% Runtime.msbuild /m /nr:false /p:Platform="Any CPU" /p:Desktop=%Desktop% /v:M ^
69+
MSBuild Runtime.msbuild /m /nr:false /p:Platform="Any CPU" /p:Desktop=%Desktop% /v:M ^
6670
/fl /fileLoggerParameters:LogFile=bin\msbuild.log;Verbosity=Normal /consoleLoggerParameters:Summary
6771
if %ERRORLEVEL% neq 0 goto BuildFail
6872
goto BuildSuccess

eng/GetXCopyMSBuild.ps1

Lines changed: 42 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,42 @@
1+
# Lifted from https://github.com/dotnet/arcade/blob/main/eng/common/tools.ps1
2+
3+
[CmdletBinding(DefaultParameterSetName='Groups')]
4+
param(
5+
[string]$Version = '17.4.1'
6+
)
7+
8+
Set-StrictMode -Version 2
9+
$ErrorActionPreference = 'Stop'
10+
11+
function Create-Directory ([string[]] $path) {
12+
New-Item -Path $path -Force -ItemType 'Directory' | Out-Null
13+
}
14+
15+
function Unzip([string]$zipfile, [string]$outpath) {
16+
Add-Type -AssemblyName System.IO.Compression.FileSystem
17+
[System.IO.Compression.ZipFile]::ExtractToDirectory($zipfile, $outpath)
18+
}
19+
20+
function InitializeXCopyMSBuild([string]$packageVersion, [bool]$install, [string]$ToolsDir) {
21+
$packageName = 'RoslynTools.MSBuild'
22+
$packageDir = Join-Path $ToolsDir $packageVersion
23+
$packagePath = Join-Path $packageDir "$packageName.$packageVersion.nupkg"
24+
25+
if (!(Test-Path $packageDir)) {
26+
if (!$install) {
27+
return $null
28+
}
29+
30+
Create-Directory $packageDir
31+
32+
Write-Host "Downloading $packageName $packageVersion"
33+
$ProgressPreference = 'SilentlyContinue' # Don't display the console progress UI - it's a huge perf hit
34+
Invoke-WebRequest "https://pkgs.dev.azure.com/dnceng/public/_packaging/dotnet-eng/nuget/v3/flat2/$packageName/$packageVersion/$packageName.$packageVersion.nupkg" -OutFile $packagePath
35+
36+
Unzip $packagePath $packageDir
37+
}
38+
39+
return Join-Path $packageDir 'tools'
40+
}
41+
42+
InitializeXCopyMSBuild -packageVersion $Version -install $true -ToolsDir (join-path $PWD .msbuild)

global.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
{
22
"sdk": {
3-
"version": "2.1.818",
3+
"version": "6.0.405",
44
"rollForward": "major"
55
}
66
}

src/System.Net.Http.Formatting/Internal/TranscodingStream.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -119,7 +119,7 @@ protected override void Dispose(bool disposing)
119119
}
120120
}
121121

122-
#if NETCOREAPP3_1 || NET5_0_OR_GREATER || NETSTANDARD2_1
122+
#if NETCOREAPP3_1_OR_GREATER || NETSTANDARD2_1
123123
public override ValueTask DisposeAsync()
124124
{
125125
if (_innerStream is null)

test/Microsoft.TestCommon/ExceptionAssertions.cs

Lines changed: 14 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -297,7 +297,7 @@ public static async Task<ArgumentNullException> ThrowsArgumentNullAsync(Func<Tas
297297
/// <exception cref="ThrowsException">Thrown when an exception was not thrown, or when an exception of the incorrect type is thrown</exception>
298298
public static ArgumentException ThrowsArgumentNullOrEmpty(Action testCode, string paramName)
299299
{
300-
return Throws<ArgumentException>(testCode, "Value cannot be null or empty.\r\nParameter name: " + paramName, allowDerivedExceptions: false);
300+
return Throws<ArgumentException>(testCode, "Value cannot be null or empty." + GetParameterMessage(paramName), allowDerivedExceptions: false);
301301
}
302302

303303
/// <summary>
@@ -327,7 +327,7 @@ public static ArgumentOutOfRangeException ThrowsArgumentOutOfRange(Action testCo
327327
{
328328
if (exceptionMessage != null)
329329
{
330-
exceptionMessage = exceptionMessage + "\r\nParameter name: " + paramName;
330+
exceptionMessage = exceptionMessage + GetParameterMessage(paramName);
331331
if (actualValue != null)
332332
{
333333
exceptionMessage += String.Format(CultureReplacer.DefaultCulture, "\r\nActual value was {0}.", actualValue);
@@ -360,7 +360,7 @@ public static async Task<ArgumentOutOfRangeException> ThrowsArgumentOutOfRangeAs
360360
{
361361
if (exceptionMessage != null)
362362
{
363-
exceptionMessage = exceptionMessage + "\r\nParameter name: " + paramName;
363+
exceptionMessage = exceptionMessage + GetParameterMessage(paramName);
364364
if (actualValue != null)
365365
{
366366
exceptionMessage += String.Format(CultureReplacer.DefaultCulture, "\r\nActual value was {0}.", actualValue);
@@ -500,8 +500,8 @@ public static HttpException ThrowsHttpException(Action testCode, string exceptio
500500
public static ArgumentException ThrowsInvalidEnumArgument(Action testCode, string paramName, int invalidValue, Type enumType, bool allowDerivedExceptions = false)
501501
{
502502
string message = String.Format(CultureReplacer.DefaultCulture,
503-
"The value of argument '{0}' ({1}) is invalid for Enum type '{2}'.{3}Parameter name: {0}",
504-
paramName, invalidValue, enumType.Name, Environment.NewLine);
503+
"The value of argument '{0}' ({1}) is invalid for Enum type '{2}'.{3}",
504+
paramName, invalidValue, enumType.Name, GetParameterMessage(paramName));
505505

506506
#if NETFX_CORE // InvalidEnumArgumentException not available in netstandard1.3.
507507
return Throws<Error.InvalidEnumArgumentException>(testCode, message, allowDerivedExceptions);
@@ -581,6 +581,15 @@ public static async Task<TException> ThrowsAsync<TException>(
581581
return ex;
582582
}
583583

584+
private static string GetParameterMessage(string parameterName)
585+
{
586+
#if NETCOREAPP3_1_OR_GREATER
587+
return " (Parameter '" + parameterName + "')";
588+
#else
589+
return Environment.NewLine + "Parameter name: " + parameterName;
590+
#endif
591+
}
592+
584593
// We've re-implemented all the xUnit.net Throws code so that we can get this
585594
// updated implementation of RecordException which silently unwraps any instances
586595
// of AggregateException. In addition to unwrapping exceptions, this method ensures

test/Microsoft.TestCommon/Microsoft.TestCommon.csproj

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
<Project Sdk="Microsoft.NET.Sdk">
22
<Import Project="$([MSBuild]::GetDirectoryNameOfFileAbove($(MSBuildThisFileDirectory),Runtime.sln))\tools\WebStack.settings.targets" />
33
<PropertyGroup>
4-
<TargetFrameworks>net462;netcoreapp2.1</TargetFrameworks>
4+
<TargetFrameworks>net462;netcoreapp2.1;net6.0</TargetFrameworks>
55
<Configurations>$(Configurations);CodeAnalysis</Configurations>
66
<DefineConstants
77
Condition=" '$(NetFX_Core)' == 'true' ">$(DefineConstants);NETFX_CORE</DefineConstants>

test/System.Net.Http.Formatting.NetCore.Test/System.Net.Http.Formatting.NetCore.Test.csproj

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
<Project Sdk="Microsoft.NET.Sdk">
22
<Import Project="$([MSBuild]::GetDirectoryNameOfFileAbove($(MSBuildThisFileDirectory),Runtime.sln))\tools\WebStack.settings.targets" />
33
<PropertyGroup>
4-
<TargetFrameworks>netcoreapp2.1;net462</TargetFrameworks>
4+
<TargetFrameworks>net462;netcoreapp2.1;net6.0</TargetFrameworks>
55
<RootNamespace>System.Net.Http</RootNamespace>
66
<OutputPath>..\..\bin\$(Configuration)\Test\NetCore\</OutputPath>
77
<Configurations>$(Configurations);CodeAnalysis</Configurations>

test/System.Net.Http.Formatting.NetStandard.Test/System.Net.Http.Formatting.NetStandard.Test.csproj

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
<Project Sdk="Microsoft.NET.Sdk">
22
<Import Project="$([MSBuild]::GetDirectoryNameOfFileAbove($(MSBuildThisFileDirectory),Runtime.sln))\tools\WebStack.settings.targets" />
33
<PropertyGroup>
4-
<TargetFrameworks>netcoreapp2.1;net462</TargetFrameworks>
4+
<TargetFrameworks>net462;netcoreapp2.1;net6.0</TargetFrameworks>
55
<RootNamespace>System.Net.Http</RootNamespace>
66
<OutputPath>..\..\bin\$(Configuration)\Test\NetStandard\</OutputPath>
77
<Configurations>$(Configurations);CodeAnalysis</Configurations>

test/System.Net.Http.Formatting.Test/Formatting/BsonMediaTypeFormatterTests.cs

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -330,7 +330,12 @@ public async Task FormatterThrowsOnReadWithInvalidContent()
330330
// Act & Assert
331331
await Assert.ThrowsAsync<JsonReaderException>(
332332
() => formatter.ReadFromStreamAsync(variationType, stream, content, null),
333-
"Could not convert to decimal: 7.92281625142643E+28. Path 'Value'.");
333+
#if NETCOREAPP3_1_OR_GREATER
334+
"Could not convert to decimal: 7.922816251426434E+28. Path 'Value'."
335+
#else
336+
"Could not convert to decimal: 7.92281625142643E+28. Path 'Value'."
337+
#endif
338+
);
334339
}
335340

336341
[Theory]

test/System.Net.Http.Formatting.Test/Formatting/JsonMediaTypeFormatterTests.cs

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@
1111
using System.Text;
1212
using System.Threading.Tasks;
1313
using Microsoft.TestCommon;
14+
using Moq;
1415
using Newtonsoft.Json;
1516
using Newtonsoft.Json.Linq;
1617

@@ -576,6 +577,29 @@ public override Task WriteToStreamAsync_UsesCorrectCharacterEncoding(string cont
576577
formatter, content, formattedContent, mediaType, encoding, isDefaultEncoding);
577578
}
578579

580+
#if NET6_0_OR_GREATER
581+
// Cannot Mock a Stream and let JsonWriter write to it. Writer will use ReadOnlySpan in this case and such
582+
// parameters are not currently mockable. See moq/moq4#829, moq/moq4#979, and dotnet/runtime#45152.
583+
// Override here avoids the Mock<Stream> and should confirm this Stream is not closed. Also adds an
584+
// additional check of the written text.
585+
[Fact]
586+
public override async Task WriteToStreamAsync_WhenObjectIsNull_WritesDataButDoesNotCloseStream()
587+
{
588+
// Arrange
589+
JsonMediaTypeFormatter formatter = CreateFormatter();
590+
Stream stream = new MemoryStream();
591+
HttpContent content = new StringContent(String.Empty);
592+
593+
// Act
594+
await formatter.WriteToStreamAsync(typeof(SampleType), null, stream, content, null);
595+
596+
// Assert (stream will throw if it has been closed)
597+
stream.Position = 0;
598+
using var reader = new StreamReader(stream);
599+
Assert.Equal("null", reader.ReadToEnd());
600+
}
601+
#endif
602+
579603
public class TestJsonMediaTypeFormatter : JsonMediaTypeFormatter
580604
{
581605
public TestJsonMediaTypeFormatter()

test/System.Net.Http.Formatting.Test/Handlers/ProgressMessageHandlerTest.cs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -56,8 +56,10 @@ public async Task SendAsync_DoesNotInsertSendProgressWithoutEntityOrHandlerPrese
5656
}
5757

5858
[Theory]
59+
#if !NET6_0_OR_GREATER // https://github.com/aspnet/AspNetWebStack/issues/386
5960
[InlineData(false, false)]
6061
[InlineData(false, true)]
62+
#endif
6163
[InlineData(true, false)]
6264
[InlineData(true, true)]
6365
public async Task SendAsync_InsertsReceiveProgressWhenResponseEntityPresent(bool insertResponseEntity, bool addReceiveProgressHandler)

0 commit comments

Comments
 (0)