Skip to content
This repository has been archived by the owner on Jul 15, 2023. It is now read-only.

Adding support for running tests cross-platform #746

Merged
merged 21 commits into from
Jan 23, 2019
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
21 commits
Select commit Hold shift + click to select a range
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 1 addition & 4 deletions build.ps1
Original file line number Diff line number Diff line change
Expand Up @@ -39,12 +39,9 @@ function Invoke-Tests() {
foreach ($test in $(Get-ChildItem $testFolder | ? { $_.PsIsContainer })) {
$csprojs = Get-ChildItem $test.FullName -Recurse | ? { $_.Extension -eq ".csproj" }
foreach ($proj in $csprojs) {
$trx = "$($proj.BaseName).$(Get-Date -Format "yyyy-MM-dd.hh_mm_ss").trx"
$fullpath = Join-Path $testResults $trx

Write-Host "Testing $($proj.Name). Output: $trx"

dotnet test "$($proj.FullName)" --configuration $Configuration --logger "trx;LogFileName=$fullpath" --no-build
dotnet test "$($proj.FullName)" --configuration $Configuration --logger "trx" --no-build
}
}
}
Expand Down
76 changes: 58 additions & 18 deletions build.sh
Original file line number Diff line number Diff line change
Expand Up @@ -12,10 +12,11 @@ RootDir="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
DotNetSDKPath=$RootDir"/.tools/dotnet/"$DotNetSDKVersion
DotNetExe=$DotNetSDKPath"/dotnet"

TestResults=$RootDir"/TestResults"
BuildApps=true
RunTests=false

usage() {
echo "Usage: build.sh [-c|--configuration <Debug|Release>] [--downloadCatalog]"
echo "Usage: build.sh [-c|--configuration <Debug|Release>] [--downloadCatalog] [--runTests] [--no-build]"
}

downloadCatalog() {
Expand All @@ -39,6 +40,14 @@ downloadCatalog() {
}

installSDK() {
local dotnetPath=$(command -v dotnet)

if [[ $dotnetPath != "" ]]; then
echo "dotnet is found on PATH. using that."
DotNetExe=$dotnetPath
return 0
fi

if [[ -e $DotNetExe ]]; then
echo $DotNetExe" exists. Skipping install..."
return 0
Expand All @@ -53,33 +62,51 @@ installSDK() {
curl -sSL https://dot.net/v1/dotnet-install.sh | bash /dev/stdin --channel Current --install-dir $DotNetSDKPath
}

tryGetTargetFramework() {
local file=$1
local targetFramework=$(awk -F: '/<TargetFramework(s)?>.*netcoreapp[1-9]\.[0-9].*<\/TargetFramework(s)?>/ { print $0 }' $file | sed 's/.*\(netcoreapp[1-9]\.[0-9]\).*/\1/')
echo $targetFramework
}

build() {
echo "Building ApiPort... Configuration: ["$Configuration"]"

pushd src/ApiPort/ApiPort >/dev/null
$DotNetExe build ApiPort.csproj -f netcoreapp2.1 -c $Configuration
$DotNetExe build ApiPort.Offline.csproj -f netcoreapp2.1 -c $Configuration

local targetFramework=$(tryGetTargetFramework ApiPort.props)
echo "Building for: $targetFramework"

$DotNetExe build ApiPort.csproj -f $targetFramework -c $Configuration
$DotNetExe build ApiPort.Offline.csproj -f $targetFramework -c $Configuration
popd >/dev/null
}

runTest() {
ls $1/*.csproj | while read file; do
if awk -F: '/<TargetFramework>netcoreapp[1-9]\.[0-9]<\/TargetFramework>/ { found = 1 } END { if (found == 1) { exit 0 } else { exit 1 } }' $file; then
echo "Testing "$file
$DotNetExe test $file -c $Configuration --logger trx
else
# Can remove this when: https://github.com/dotnet/sdk/issues/335 is resolved
local targetFramework=$(tryGetTargetFramework $file)

if [[ $targetFramework == "" ]]; then
echo "Skipping "$file
echo "--- Desktop .NET Framework testing is not currently supported on Unix."
else
echo "Testing "$file
$DotNetExe test $file -c $Configuration --logger trx --framework $targetFramework --results-directory $2
fi
done
}

if [ ! -d $TestResults ]; then
mkdir $TestResults
findAndRunTests() {
local testResultsDirectory=$COMMON_TESTRESULTSDIRECTORY

if [[ $testResultsDirectory == "" ]]; then
testResultsDirectory=$RootDir/TestResults
echo "Results directory not specified, using $testResultsDirectory."
else
echo "Using common one set by build agent."
fi

find $RootDir/tests/ -type f -name "*.trx" | while read line; do
mv $line $TestResults/
find tests/ -type d -name "*\.Tests" | while read file; do
runTest $file $testResultsDirectory
done
}

Expand All @@ -94,6 +121,14 @@ while [[ $# -gt 0 ]]; do
Configuration="$2"
shift 2
;;
"--runtests")
RunTests=true
shift
;;
"--no-build")
BuildApps=false
shift
;;
"--downloadcatalog")
downloadCatalog "true"
exit 0
Expand Down Expand Up @@ -124,12 +159,17 @@ if [[ ! -e $DotNetExe ]]; then
exit 2
fi

downloadCatalog
if [[ $BuildApps == "true" ]]; then
downloadCatalog
build
fi

build
if [[ $RunTests == "true" ]]; then
if [[$BuildApps != "true" ]]; then
echo "WARNING: Not building applications because --no-build is set."
fi

find tests/ -type d -name "*\.Tests" | while read file; do
runTest $file
done
findAndRunTests
fi

echo "Finished!"
2 changes: 1 addition & 1 deletion src/ApiPort/ApiPort/ApiPort.props
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@
</PropertyGroup>

<PropertyGroup Condition="'$(TargetFramework)' == 'net461'">
<RuntimeIdentifier>win7-x64</RuntimeIdentifier>
<RuntimeIdentifiers>win7-x64;win7-x86</RuntimeIdentifiers>
<DefineConstants>$(DefineConstants);FEATURE_SYSTEM_PROXY;FEATURE_NETWORK_CREDENTIAL</DefineConstants>
</PropertyGroup>

Expand Down
12 changes: 11 additions & 1 deletion src/lib/Microsoft.Fx.Portability/AssemblyFileComparer.cs
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@

using System;
using System.Collections.Generic;
using System.Runtime.InteropServices;

namespace Microsoft.Fx.Portability
{
Expand All @@ -21,7 +22,16 @@ public int Compare(IAssemblyFile x, IAssemblyFile y)
return y == null ? 0 : -1;
}

return string.Compare(x.Name, y?.Name, StringComparison.Ordinal);
// Filenames are case insensitive on Windows.
var comparison = StringComparison.OrdinalIgnoreCase;

#if !NET461
if (!RuntimeInformation.IsOSPlatform(OSPlatform.Windows))
{
comparison = StringComparison.Ordinal;
}
#endif
return string.Compare(x.Name, y?.Name, comparison);
}
}
}
13 changes: 10 additions & 3 deletions tests/ApiPort/ApiPort.Tests/AnalyzeOptionsTests.cs
Original file line number Diff line number Diff line change
Expand Up @@ -115,15 +115,22 @@ public static void TestAssemblyFlag_DirectoryAndFileName()
{
var directoryPath = Directory.GetCurrentDirectory();
var currentAssemblyPath = typeof(AnalyzeOptionsTests).GetTypeInfo().Assembly.Location;
var currentAssemblyDirectory = Path.GetDirectoryName(currentAssemblyPath);

// The scenario tested is when an assembly is passed in twice, once explicitly and once as part of the folder
// Assert that we test this scenario.
if (!string.Equals(currentAssemblyDirectory, directoryPath, StringComparison.OrdinalIgnoreCase))
{
Directory.SetCurrentDirectory(currentAssemblyDirectory);
directoryPath = Directory.GetCurrentDirectory();
}

var options = GetOptions($"analyze -f {directoryPath} -f {currentAssemblyPath}");

Assert.Equal(AppCommand.AnalyzeAssemblies, options.Command);
Assert.NotEmpty(options.InputAssemblies);

// The scenario tested is when an assembly is passed in twice, once explicitly and once as part of the folder
// Assert that we test this scenario.
Assert.Equal(Path.GetDirectoryName(currentAssemblyPath), directoryPath, StringComparer.OrdinalIgnoreCase);
Assert.Equal(currentAssemblyDirectory, Directory.GetCurrentDirectory(), StringComparer.OrdinalIgnoreCase);

foreach (var element in options.InputAssemblies)
{
Expand Down
2 changes: 1 addition & 1 deletion tests/ApiPort/ApiPort.Tests/ApiPort.Tests.csproj
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
<Project Sdk="Microsoft.NET.Sdk">

<PropertyGroup>
<TargetFramework>netcoreapp2.1</TargetFramework>
<TargetFrameworks>netcoreapp2.1;net461</TargetFrameworks>
</PropertyGroup>

<PropertyGroup>
Expand Down
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
<Project Sdk="Microsoft.NET.Sdk">

<PropertyGroup>
<TargetFramework>net46</TargetFramework>
<TargetFrameworks>netcoreapp2.1;net461</TargetFrameworks>
<AutoGenerateBindingRedirects>true</AutoGenerateBindingRedirects>
<GenerateBindingRedirectsOutputType>true</GenerateBindingRedirectsOutputType>
<NonShipping>true</NonShipping>
Expand Down
21 changes: 15 additions & 6 deletions tests/lib/Microsoft.Fx.Portability.Cci.Tests/TestAssembly.cs
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,15 @@ namespace Microsoft.Fx.Portability.Cci.Tests
internal class TestAssembly
{
private const string TFM = @"[assembly: global::System.Runtime.Versioning.TargetFrameworkAttribute("".NETFramework,Version=v4.5.1"", FrameworkDisplayName = "".NET Framework 4.5.1"")]";
private static readonly string Mscorlib = typeof(object).GetTypeInfo().Assembly.Location;
private static readonly IEnumerable<string> DefaultReferences = new[]
{
typeof(object).Assembly.Location,
typeof(Console).Assembly.Location,

// Reference to System.Runtime.dll rather than System.Private.CoreLib on .NET Core
typeof(RuntimeReflectionExtensions).Assembly.Location
}.Distinct();

private readonly string _path;

private TestAssembly(string assemblyName, string text, IEnumerable<string> referencePaths)
Expand Down Expand Up @@ -56,7 +64,7 @@ public static string EmptyProject
get
{
var text = GetText("EmptyProject.cs");
return new TestAssembly("EmptyProject", text, new[] { Mscorlib }).Path;
return new TestAssembly("EmptyProject", text, DefaultReferences).Path;
}
}

Expand All @@ -65,7 +73,8 @@ public static string WithGenericsAndReference
get
{
var text = GetText("WithGenericsAndReference.cs");
return new TestAssembly("WithGenericsAndReference", text, new[] { Mscorlib, EmptyProject }).Path;
var references = DefaultReferences.Concat(new[] { EmptyProject });
return new TestAssembly("WithGenericsAndReference", text, references).Path;
}
}

Expand All @@ -76,9 +85,9 @@ private static string GetText(string fileName)
using (var stream = typeof(TestAssembly).GetTypeInfo().Assembly.GetManifestResourceStream(name))
{
using (var reader = new StreamReader(stream))
{
return reader.ReadToEnd();
}
{
return reader.ReadToEnd();
}
}
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -31,12 +31,10 @@ public ManagedMetadataReaderTests(ITestOutputHelper output)
[InlineData("OpImplicitMethod2Parameter.cs", "M:Microsoft.Fx.Portability.MetadataReader.Tests.OpImplicit_Method_2Parameter`1.op_Implicit(`0,`0)")]
[InlineData("OpExplicit.cs", "M:Microsoft.Fx.Portability.MetadataReader.Tests.Class2_OpExplicit`1.op_Explicit(Microsoft.Fx.Portability.MetadataReader.Tests.Class2_OpExplicit{`0})~Microsoft.Fx.Portability.MetadataReader.Tests.Class1_OpExplicit{`0}")]
[InlineData("NestedGenericTypesWithInvalidNames.cs", "M:Microsoft.Fx.Portability.MetadataReader.Tests.OtherClass.<GetValues>d__0`1.System#Collections#Generic#IEnumerable{System#Tuple{T@System#Int32}}#GetEnumerator")]
[InlineData("modopt.il", "M:TestClass.Foo(System.Int32 optmod System.Runtime.CompilerServices.IsConst)")]
[InlineData("modopt.il", "M:TestClass.Bar(System.SByte optmod System.Runtime.CompilerServices.IsConst reqmod System.Runtime.CompilerServices.IsSignUnspecifiedByte*)")]
[InlineData("NestedGenericTypes.cs", "M:OuterClass`2.InnerClass`2.InnerInnerClass.InnerInnerMethod(OuterClass{`3,`2}.InnerClass{System.Int32,`0}.InnerInnerClass)")]
[InlineData("NestedGenericTypes.cs", "M:OuterClass`2.InnerClass`2.InnerMethod(OuterClass{`2,`2}.InnerClass{`1,`1})")]
[InlineData("NestedGenericTypes.cs", "M:OuterClass`2.OuterMethod(`0,OuterClass{`1,`0}.InnerClass{`1,`0})")]

#if FEATURE_ILASM
// IL can, bizarrely, define non-generic types that take generic paratmers
[InlineData("NonGenericTypesWithGenericParameters.il", "M:OuterClass.InnerClass.InnerMethod(OuterClass.InnerClass{`2,`2})")]
[InlineData("NonGenericTypesWithGenericParameters.il", "M:OuterClass.OuterMethod(`0,OuterClass.InnerClass{`1,`0,System.Object,`0})")]
Expand All @@ -45,7 +43,9 @@ public ManagedMetadataReaderTests(ITestOutputHelper output)
// This is not possible to construct in C#, but was being encoded incorrectly by the metadata reader parser.
[InlineData("NestedGenericTypes.il", "M:OuterClass`2.InnerClass`2.InnerMethod(OuterClass{`2,`2}.InnerClass`2)")]
[InlineData("NestedGenericTypes.il", "M:OuterClass`2.OuterMethod(`0,OuterClass{`1,`0}.InnerClass{`1,`0})")]

[InlineData("modopt.il", "M:TestClass.Foo(System.Int32 optmod System.Runtime.CompilerServices.IsConst)")]
[InlineData("modopt.il", "M:TestClass.Bar(System.SByte optmod System.Runtime.CompilerServices.IsConst reqmod System.Runtime.CompilerServices.IsSignUnspecifiedByte*)")]
#endif
[Theory]
public void TestForDocId(string source, string docid)
{
Expand Down Expand Up @@ -140,7 +140,9 @@ public void VerifyFilter()
.OrderBy(x => x, StringComparer.Ordinal);

var assemblyName = "FilterApis";
var filter = new AssemblyNameFilter(assemblyName);

// We want to recognize System.Console but not System.Uri.
var filter = new AssemblyNameFilter(assemblyName, new[] { "System.Console" });
var dependencyFinder = new ReflectionMetadataDependencyFinder(filter, new SystemObjectFinder(filter));
var assemblyToTest = TestAssembly.Create($"{assemblyName}.cs", _output);
var progressReporter = Substitute.For<IProgressReporter>();
Expand Down Expand Up @@ -240,6 +242,7 @@ public void ThrowsSystemObjectNotFoundException()
Assert.IsType<SystemObjectNotFoundException>(exception.InnerException);
}

#if FEATURE_ILASM
[Fact]
public void AssemblyWithNoReferencesIsSkipped()
{
Expand All @@ -257,6 +260,7 @@ public void AssemblyWithNoReferencesIsSkipped()

Assert.Equal("NoReferences, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null", assembly.AssemblyIdentity);
}
#endif

private static IEnumerable<Tuple<string, int>> EmptyProjectMemberDocId()
{
Expand Down Expand Up @@ -296,21 +300,37 @@ private static IEnumerable<Tuple<string, int>> EmptyProjectMemberDocId()

private class AssemblyNameFilter : IDependencyFilter
{
private static readonly HashSet<string> SystemObjectAssemblies = new HashSet<string>(StringComparer.Ordinal)
{
"mscorlib",
"netstandard",
"System.Private.CoreLib",
"System.Runtime"
};

private readonly string _assemblyName;
private readonly HashSet<string> _frameworkAssemblies;

public AssemblyNameFilter(string assemblyName)
public AssemblyNameFilter(string assemblyName, IEnumerable<string> frameworkAssemblies)
{
_assemblyName = assemblyName;
_assemblyName = assemblyName ?? throw new ArgumentNullException(nameof(assemblyName));
_frameworkAssemblies = new HashSet<string>(
frameworkAssemblies ?? Enumerable.Empty<string>(),
StringComparer.Ordinal);
}

public bool IsFrameworkAssembly(AssemblyReferenceInformation assembly)
{
var comparison = StringComparison.Ordinal;
var name = assembly?.Name;

var result = string.Equals(_assemblyName, name, comparison)
|| string.Equals("mscorlib", name, comparison)
|| string.Equals("System.Runtime", name, comparison);
if (string.IsNullOrEmpty(name))
{
return false;
}

var result = string.Equals(_assemblyName, name, StringComparison.Ordinal)
|| SystemObjectAssemblies.Contains(name)
|| _frameworkAssemblies.Contains(name);

return result;
}
Expand Down
Original file line number Diff line number Diff line change
@@ -1,11 +1,21 @@
<Project Sdk="Microsoft.NET.Sdk">

<PropertyGroup>
<TargetFramework>net46</TargetFramework>
<TargetFrameworks>net461;netcoreapp2.1</TargetFrameworks>
<AutoGenerateBindingRedirects>true</AutoGenerateBindingRedirects>
<GenerateBindingRedirectsOutputType>true</GenerateBindingRedirectsOutputType>
<NonShipping>true</NonShipping>
<RuntimeIdentifier>win-x86</RuntimeIdentifier>
</PropertyGroup>

<PropertyGroup Condition="$(TargetFramework) == 'net461'">
<!-- Need to specify RuntimeIdentifier in here because using
RuntimeIdentifiers will not copy native assets (ildasm) to the output.
folder.
TODO: ilasm exists on Linux but for some reason the assets are not copied
during dotnet test even when using RuntimeIdentifier. See:
https://github.com/dotnet/sdk/issues/2765 -->
<RuntimeIdentifier>win7-x86</RuntimeIdentifier>
<DefineConstants>$(DefineConstants);FEATURE_ILASM</DefineConstants>
</PropertyGroup>

<ItemGroup>
Expand Down
Loading