diff options
author | Sven Boemer <sbomer@gmail.com> | 2019-03-26 23:05:14 +0300 |
---|---|---|
committer | Marek Safar <marek.safar@gmail.com> | 2019-03-26 23:05:14 +0300 |
commit | 5175506202f74bdfaa35e08aa5d91e04b4fed7f2 (patch) | |
tree | e2fb699b8e33269633215a0bc221e2a9bdfb8146 /test/Mono.Linker.Tests | |
parent | f23fb32406f45aeb70e1b835d5c95bb4837f4da1 (diff) |
Enable unit tests on .NET Core (#489)
This enables the unit tests to run on .NET Core. CodeDom compilation doesn't exist on core, so I've added the ability to compile in-process with Roslyn APIs. This still uses NUnit, using a recent version of NUnit package references with "dotnet test". This doesn't change how tests run on mono.
Finding the right reference assemblies for compilation is a bit different on .NET Core. As described in https://github.com/dotnet/roslyn/wiki/Runtime-code-generation-using-Roslyn-compilations-in-.NET-Core-App, they can either be found using packages (what the SDK does), or we can just compile against the implementation assemblies. In this change, I'm compiling against implementation assemblies, since that's fairly similar to what the tests do on mono, where they find them in the GAC.
For mono, the common references only included mscorlib. For .NET Core, I'm getting the common references from the "Trusted Platform Assemblies" (TPA) of the test process. As a result, package references of the test project become references during testcase compilation. Explicit references specified via `ReferenceAttribute` in a testcase are looked for alongside the host process's implementations as well (since we have no way to resolve a reference from just the filename since there is no GAC).
Other changes:
- Roslyn outputs the `DebuggableAttribute` by default but mcs does not, so when running on .NET Core, we don't check for the `DebuggableAttribute`.
- Check for core types in `System.Private.CoreLib` instead of `mscorlib`.
- There are some more edge cases that I'm in the process of cleaning up and will update soon.
At the moment, I'm trying to get the tests up and running, and I'm using plenty of compile-time conditions to modify the behavior on core. It would be nice not to have to do this - I haven't given it much thought, but maybe we could provide an abstraction that contains knowledge of the platform libraries, so that we don't have to have a hard dependency on `"mscorlib.dll"` and `"System.Private.CoreLib.dll"` everywhere? @mrvoorhe please let me know if you have any thoughts. Does the approach I'm taking so far seem sane to you?
@marek-safar
Diffstat (limited to 'test/Mono.Linker.Tests')
7 files changed, 279 insertions, 13 deletions
diff --git a/test/Mono.Linker.Tests/Mono.Linker.Tests.csproj b/test/Mono.Linker.Tests/Mono.Linker.Tests.csproj index 7da7cae3d..f37575b0c 100644 --- a/test/Mono.Linker.Tests/Mono.Linker.Tests.csproj +++ b/test/Mono.Linker.Tests/Mono.Linker.Tests.csproj @@ -1,5 +1,10 @@ <Project DefaultTargets="Build" ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003"> <PropertyGroup> + <ILLinkBuild Condition=" $(Configuration.StartsWith('illink')) ">true</ILLinkBuild> + <ILLinkBuild Condition=" '$(ILLinkBuild)' == '' ">false</ILLinkBuild> + </PropertyGroup> + <Import Project="Sdk.props" Sdk="Microsoft.NET.Sdk" Condition=" $(ILLinkBuild) " /> + <PropertyGroup> <Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration> <Platform Condition=" '$(Platform)' == '' ">AnyCPU</Platform> <ProductVersion>8.0.50727</ProductVersion> @@ -9,7 +14,17 @@ <AssemblyName>Mono.Linker.Tests</AssemblyName> <StartupObject> </StartupObject> - <TargetFrameworkVersion>v4.7.1</TargetFrameworkVersion> + <TargetFramework Condition=" $(ILLinkBuild) ">netcoreapp3.0</TargetFramework> + <EnableDefaultCompileItems Condition=" $(ILLinkBuild) ">false</EnableDefaultCompileItems> + <TargetFrameworkVersion Condition=" ! $(ILLinkBuild) ">v4.7.1</TargetFrameworkVersion> + <!-- Simulate https://github.com/dotnet/sdk/pull/2073 until it ships. --> + <DefineConstants Condition=" '$(TargetFramework)' == 'netcoreapp3.0' ">$(DefineConstants);NETCOREAPP</DefineConstants> + <DefineConstants Condition=" $(ILLinkBuild) ">$(DefineConstants);ILLINK</DefineConstants> + <DefineConstants Condition=" '$(Configuration)' == 'illink_Debug' ">$(DefineConstants);DEBUG</DefineConstants> + <DefineConstants Condition=" '$(ArcadeBuild)' == 'true' ">$(DefineConstants);ARCADE</DefineConstants> + <IsTestProject Condition=" $(ILLinkBuild) ">true</IsTestProject> + <!-- Arcade's custom test imports assume that we are using xunit. --> + <DisableArcadeTestFramework Condition=" '$(ArcadeBuild)' == 'true' ">true</DisableArcadeTestFramework> <RootNamespace>Mono.Linker.Tests</RootNamespace> </PropertyGroup> <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' "> @@ -29,7 +44,7 @@ <ErrorReport>prompt</ErrorReport> <WarningLevel>4</WarningLevel> </PropertyGroup> - <Import Project="$(MSBuildBinPath)\Microsoft.CSharp.targets" /> + <Import Project="$(MSBuildBinPath)\Microsoft.CSharp.targets" Condition=" ! $(ILLinkBuild) " /> <!-- To modify your build process, add your task inside one of the targets below and uncomment it. Other similar extension points exist, see Microsoft.Common.targets. <Target Name="BeforeBuild"> @@ -37,7 +52,7 @@ <Target Name="AfterBuild"> </Target> --> - <ItemGroup> + <ItemGroup Condition=" ! $(ILLinkBuild) "> <Reference Include="System" /> <Reference Include="System.Xml" /> <Reference Include="System.Core" /> @@ -52,14 +67,20 @@ </ItemGroup> <ItemGroup> <ProjectReference Include="..\..\external\cecil\Mono.Cecil.csproj"> + <SetConfiguration Condition=" '$(Configuration)' == 'illink_Debug' ">Configuration=netstandard_Debug</SetConfiguration> + <SetConfiguration Condition=" '$(Configuration)' == 'illink_Release' ">Configuration=netstandard_Release</SetConfiguration> <Project>{D68133BD-1E63-496E-9EDE-4FBDBF77B486}</Project> <Name>Mono.Cecil</Name> </ProjectReference> <ProjectReference Include="..\..\external\cecil\symbols\mdb\Mono.Cecil.Mdb.csproj"> + <SetConfiguration Condition=" '$(Configuration)' == 'illink_Debug' ">Configuration=netstandard_Debug</SetConfiguration> + <SetConfiguration Condition=" '$(Configuration)' == 'illink_Release' ">Configuration=netstandard_Release</SetConfiguration> <Project>{8559dd7f-a16f-46d0-a05a-9139faeba8fd}</Project> <Name>Mono.Cecil.Mdb</Name> </ProjectReference> <ProjectReference Include="..\..\external\cecil\symbols\pdb\Mono.Cecil.Pdb.csproj"> + <SetConfiguration Condition=" '$(Configuration)' == 'illink_Debug' ">Configuration=netstandard_Debug</SetConfiguration> + <SetConfiguration Condition=" '$(Configuration)' == 'illink_Release' ">Configuration=netstandard_Release</SetConfiguration> <Project>{63e6915c-7ea4-4d76-ab28-0d7191eea626}</Project> <Name>Mono.Cecil.Pdb</Name> </ProjectReference> @@ -68,6 +89,8 @@ <Name>Mono.Linker</Name> </ProjectReference> <ProjectReference Include="..\Mono.Linker.Tests.Cases\Mono.Linker.Tests.Cases.csproj"> + <SetConfiguration Condition=" '$(Configuration)' == 'illink_Debug' ">Configuration=illink_Debug</SetConfiguration> + <SetConfiguration Condition=" '$(Configuration)' == 'illink_Release' ">Configuration=illink_Release</SetConfiguration> <Project>{B6BEE6AA-ADA0-4E1D-9A17-FBF2936F82B5}</Project> <Name>Mono.Linker.Tests.Cases</Name> </ProjectReference> @@ -112,4 +135,36 @@ <Compile Include="Tests\TypeNameParserTests.cs" /> <Compile Include="Tests\ParseResponseFileLinesTests.cs" /> </ItemGroup> -</Project>
\ No newline at end of file + + <ItemGroup Condition=" $(ILLinkBuild) "> + <PackageReference Include="System.CodeDom" Version="4.5.0" /> + <PackageReference Include="Microsoft.Win32.Registry" Version="4.5.0" /> + <PackageReference Include="Microsoft.CodeAnalysis.CSharp" Version="2.10.0" /> + <PackageReference Include="nunit" Version="3.10.0" /> + <PackageReference Include="NUnit3TestAdapter" Version="3.10.0" /> + <PackageReference Include="Microsoft.NET.Test.Sdk" Version="15.7.2" /> + <!-- This reference is purely so that the linker can resolve this + dependency of mscorlib. It is not actually required to build + the tests. --> + <PackageReference Include="System.Threading.AccessControl" Version="4.5.0" /> + </ItemGroup> + + <Target Name="PrepareTools" + BeforeTargets="Build" + Condition=" $(ILLinkBuild) "> + <!-- Restore ilasm using ilasm.ilproj. Restore must be done + separately from copy with a different set of input + properties, to force MSBuild to re-evaluate using new props + and targets from the restored package. --> + <PropertyGroup> + <IlasmProject>$(MSBuildThisFileDirectory)../../eng/ilasm.ilproj</IlasmProject> + <IlasmDir Condition=" '$(ArcadeBuild)' == 'true' ">$(ArtifactsDir)tools</IlasmDir> + <IlasmDir Condition=" '$(ArcadeBuild)' != 'true' ">$(MSBuildThisFileDirectory)$(BaseIntermediateOutputPath)tools</IlasmDir> + </PropertyGroup> + + <MSBuild Projects="$(IlasmProject)" Targets="Restore" Properties="BaseIntermediateOutputPath=$(IlasmDir)" /> + <MSBuild Projects="$(IlasmProject)" Targets="CopyILAsmTool" Properties="BaseIntermediateOutputPath=$(IlasmDir);__BuildPhase=Copy" /> + </Target> + + <Import Project="Sdk.targets" Sdk="Microsoft.NET.Sdk" Condition=" $(ILLinkBuild) " /> +</Project> diff --git a/test/Mono.Linker.Tests/TestCases/TestDatabase.cs b/test/Mono.Linker.Tests/TestCases/TestDatabase.cs index 62a1a0009..e5e9085f2 100644 --- a/test/Mono.Linker.Tests/TestCases/TestDatabase.cs +++ b/test/Mono.Linker.Tests/TestCases/TestDatabase.cs @@ -162,14 +162,47 @@ namespace Mono.Linker.Tests.TestCases static void GetDirectoryPaths(out string rootSourceDirectory, out string testCaseAssemblyPath, [CallerFilePath] string thisFile = null) { - var thisDirectory = Path.GetDirectoryName(thisFile); - rootSourceDirectory = Path.GetFullPath(Path.Combine(thisDirectory, "..", "..", "Mono.Linker.Tests.Cases")); + +#if ILLINK +#if DEBUG + var configDirectoryName = "illink_Debug"; +#else + var configDirectoryName = "illink_Release"; +#endif +#else #if DEBUG var configDirectoryName = "Debug"; #else var configDirectoryName = "Release"; #endif - testCaseAssemblyPath = Path.GetFullPath(Path.Combine(rootSourceDirectory, "bin", configDirectoryName, "Mono.Linker.Tests.Cases.dll")); +#endif + +#if NETCOREAPP3_0 + var tfm = "netcoreapp3.0"; +#else + var tfm = ""; +#endif + +#if ILLINK + // Deterministic builds sanitize source paths, so CallerFilePathAttribute gives an incorrect path. + // Instead, get the testcase dll based on the working directory of the test runner. +#if ARCADE + // working directory is artifacts/bin/Mono.Linker.Tests/<config>/<tfm> + var artifactsBinDir = Path.Combine (Directory.GetCurrentDirectory (), "..", "..", ".."); + rootSourceDirectory = Path.GetFullPath (Path.Combine (artifactsBinDir, "..", "..", "test", "Mono.Linker.Tests.Cases")); + testCaseAssemblyPath = Path.GetFullPath (Path.Combine (artifactsBinDir, "Mono.Linker.Tests.Cases", configDirectoryName, tfm, "Mono.Linker.Tests.Cases.dll")); +#else + // working directory is test/Mono.Linker.Tests/bin/<config>/<tfm> + var testDir = Path.Combine (Directory.GetCurrentDirectory (), "..", "..", "..", ".."); + rootSourceDirectory = Path.GetFullPath (Path.Combine (testDir, "Mono.Linker.Tests.Cases")); + testCaseAssemblyPath = Path.GetFullPath (Path.Combine (rootSourceDirectory, "bin", configDirectoryName, tfm, "Mono.Linker.Tests.Cases.dll")); +#endif // ARCADE + +#else + var thisDirectory = Path.GetDirectoryName (thisFile); + rootSourceDirectory = Path.GetFullPath (Path.Combine (thisDirectory, "..", "..", "Mono.Linker.Tests.Cases")); + testCaseAssemblyPath = Path.GetFullPath (Path.Combine (rootSourceDirectory, "bin", configDirectoryName, tfm, "Mono.Linker.Tests.Cases.dll")); +#endif // ILLINK } } } diff --git a/test/Mono.Linker.Tests/TestCasesRunner/AssemblyChecker.cs b/test/Mono.Linker.Tests/TestCasesRunner/AssemblyChecker.cs index fc8968fa5..1a992af17 100644 --- a/test/Mono.Linker.Tests/TestCasesRunner/AssemblyChecker.cs +++ b/test/Mono.Linker.Tests/TestCasesRunner/AssemblyChecker.cs @@ -80,7 +80,7 @@ namespace Mono.Linker.Tests.TestCasesRunner { ModuleDefinition linkedModule = linked?.Module; // - // Little bit complex check to allow easier test writting to match + // Little bit complex check to allow easier test writing to match // - It has [Kept] attribute or any variation of it // - It contains Main method // - It contains at least one member which has [Kept] attribute (not recursive) @@ -615,6 +615,10 @@ namespace Mono.Linker.Tests.TestCasesRunner { case "System.Diagnostics.DebuggerBrowsableAttribute": continue; + // When compiling with roslyn, assemblies get the DebuggableAttribute by default. + case "System.Diagnostics.DebuggableAttribute": + continue; + case "System.Runtime.CompilerServices.CompilationRelaxationsAttribute": if (linked is AssemblyDefinition) continue; diff --git a/test/Mono.Linker.Tests/TestCasesRunner/ILCompiler.cs b/test/Mono.Linker.Tests/TestCasesRunner/ILCompiler.cs index 517bcb273..14ec56d9e 100644 --- a/test/Mono.Linker.Tests/TestCasesRunner/ILCompiler.cs +++ b/test/Mono.Linker.Tests/TestCasesRunner/ILCompiler.cs @@ -1,7 +1,9 @@ using System; using System.Collections.Generic; using System.Diagnostics; +using System.IO; using System.Linq; +using System.Runtime.InteropServices; using System.Text; using Mono.Linker.Tests.Extensions; using NUnit.Framework; @@ -12,7 +14,7 @@ namespace Mono.Linker.Tests.TestCasesRunner { public ILCompiler () { - _ilasmExecutable = Environment.OSVersion.Platform == PlatformID.Win32NT ? LocateIlasmOnWindows ().ToString () : "ilasm"; + _ilasmExecutable = LocateIlasm ().ToString (); } public ILCompiler (string ilasmExecutable) @@ -51,18 +53,44 @@ namespace Mono.Linker.Tests.TestCasesRunner { private string BuildArguments (CompilerOptions options) { var args = new StringBuilder(); +#if ILLINK + args.Append(options.OutputPath.ExtensionWithDot == ".dll" ? "-dll" : "-exe"); + args.Append($" -out:{options.OutputPath.InQuotes ()}"); +#else args.Append(options.OutputPath.ExtensionWithDot == ".dll" ? "/dll" : "/exe"); args.Append($" /out:{options.OutputPath.InQuotes ()}"); +#endif args.Append($" {options.SourceFiles.Aggregate (string.Empty, (buff, file) => $"{buff} {file.InQuotes ()}")}"); return args.ToString (); } + public static NPath LocateIlasm () + { +#if ILLINK + var extension = RuntimeInformation.IsOSPlatform (OSPlatform.Windows) ? ".exe" : ""; +#if ARCADE + // working directory is artifacts/bin/Mono.Linker.Tests/<config>/<tfm> + var toolsDir = Path.Combine (Directory.GetCurrentDirectory (), "..", "..", "..", "..", "tools"); +#else + // working directory is test/Mono.Linker.Tests/bin/<config>/<tfm> + var toolsDir = Path.Combine (Directory.GetCurrentDirectory (), "..", "..", "..", "obj", "tools"); +#endif // ARCADE + var ilasmPath = Path.GetFullPath (Path.Combine (toolsDir, "ilasm", $"ilasm{extension}")).ToNPath (); + if (ilasmPath.FileExists ()) + return ilasmPath; + + throw new InvalidOperationException ("ilasm not found at " + ilasmPath); +#else + return Environment.OSVersion.Platform == PlatformID.Win32NT ? LocateIlasmOnWindows () : "ilasm".ToNPath (); +#endif + } + public static NPath LocateIlasmOnWindows () { if (Environment.OSVersion.Platform != PlatformID.Win32NT) throw new InvalidOperationException ("This method should only be called on windows"); - var possiblePath = System.Runtime.InteropServices.RuntimeEnvironment.GetRuntimeDirectory ().ToNPath ().Combine ("ilasm.exe"); + var possiblePath = RuntimeEnvironment.GetRuntimeDirectory ().ToNPath ().Combine ("ilasm.exe"); if (possiblePath.FileExists ()) return possiblePath; diff --git a/test/Mono.Linker.Tests/TestCasesRunner/ResultChecker.cs b/test/Mono.Linker.Tests/TestCasesRunner/ResultChecker.cs index 545e381cd..ea3eaf950 100644 --- a/test/Mono.Linker.Tests/TestCasesRunner/ResultChecker.cs +++ b/test/Mono.Linker.Tests/TestCasesRunner/ResultChecker.cs @@ -58,7 +58,10 @@ namespace Mono.Linker.Tests.TestCasesRunner { VerifyLinkingOfOtherAssemblies (original); +#if !NETCOREAPP + // the PE Verifier does not know how to resolve .NET Core assemblies. _peVerifier.Check (linkResult, original); +#endif AdditionalChecking (linkResult, original, linked); } diff --git a/test/Mono.Linker.Tests/TestCasesRunner/TestCaseCompiler.cs b/test/Mono.Linker.Tests/TestCasesRunner/TestCaseCompiler.cs index ecf8ecc1e..75eb965ce 100644 --- a/test/Mono.Linker.Tests/TestCasesRunner/TestCaseCompiler.cs +++ b/test/Mono.Linker.Tests/TestCasesRunner/TestCaseCompiler.cs @@ -7,6 +7,12 @@ using System.Linq; using System.Text; using Mono.Linker.Tests.Extensions; using NUnit.Framework; +#if NETCOREAPP +using System.Runtime.InteropServices; +using Microsoft.CodeAnalysis; +using Microsoft.CodeAnalysis.Emit; +using Microsoft.CodeAnalysis.CSharp; +#endif namespace Mono.Linker.Tests.TestCasesRunner { public class TestCaseCompiler { @@ -185,6 +191,97 @@ namespace Mono.Linker.Tests.TestCasesRunner { protected virtual NPath CompileCSharpAssemblyWithDefaultCompiler (CompilerOptions options) { +#if NETCOREAPP + return CompileCSharpAssemblyWithRoslyn (options); +#else + return CompileCSharpAssemblyWithCodeDom (options); +#endif + } + +#if NETCOREAPP + protected virtual NPath CompileCSharpAssemblyWithRoslyn (CompilerOptions options) + { + var parseOptions = new CSharpParseOptions (preprocessorSymbols: options.Defines); + var compilationOptions = new CSharpCompilationOptions ( + outputKind: options.OutputPath.FileName.EndsWith (".exe") ? OutputKind.ConsoleApplication : OutputKind.DynamicallyLinkedLibrary + ); + // Default debug info format for the current platform. + DebugInformationFormat debugType = RuntimeInformation.IsOSPlatform (OSPlatform.Windows) ? DebugInformationFormat.Pdb : DebugInformationFormat.PortablePdb; + bool emitPdb = false; + if (options.AdditionalArguments != null) { + foreach (var option in options.AdditionalArguments) { + switch (option) { + case "/unsafe": + compilationOptions = compilationOptions.WithAllowUnsafe(true); + break; + case "/optimize+": + compilationOptions = compilationOptions.WithOptimizationLevel(OptimizationLevel.Release); + break; + case "/debug:full": + case "/debug:pdbonly": + // Use platform's default debug info. This behavior is the same as csc. + emitPdb = true; + break; + case "/debug:portable": + emitPdb = true; + debugType = DebugInformationFormat.PortablePdb; + break; + case "/debug:embedded": + emitPdb = true; + debugType = DebugInformationFormat.Embedded; + break; + } + } + } + var emitOptions = new EmitOptions (debugInformationFormat: debugType); + var pdbPath = (!emitPdb || debugType == DebugInformationFormat.Embedded) ? null : options.OutputPath.ChangeExtension (".pdb").ToString (); + + var syntaxTrees = options.SourceFiles.Select (p => + CSharpSyntaxTree.ParseText ( + text: p.ReadAllText (), + options: parseOptions + ) + ); + + var compilation = CSharpCompilation.Create ( + assemblyName: options.OutputPath.FileNameWithoutExtension, + syntaxTrees: syntaxTrees, + references: options.References.Select (r => MetadataReference.CreateFromFile (r)), + options: compilationOptions + ); + + var manifestResources = options.Resources.Select (r => { + var fullPath = r.ToString (); + return new ResourceDescription ( + resourceName: Path.GetFileName (fullPath), + dataProvider: () => new FileStream (fullPath, FileMode.Open, FileAccess.Read, FileShare.ReadWrite), + isPublic: true + ); + }); + + EmitResult result; + using (var outputStream = File.Create (options.OutputPath.ToString ())) + using (var pdbStream = (pdbPath == null ? null : File.Create (pdbPath))) { + result = compilation.Emit( + peStream: outputStream, + pdbStream: pdbStream, + manifestResources: manifestResources, + options: emitOptions + ); + } + + var errors = new StringBuilder (); + if (result.Success) + return options.OutputPath; + + foreach (var diagnostic in result.Diagnostics) + errors.AppendLine (diagnostic.ToString ()); + throw new Exception ("Roslyn compilation errors: " + errors); + } +#endif + + protected virtual NPath CompileCSharpAssemblyWithCodeDom (CompilerOptions options) + { var compilerOptions = CreateCodeDomCompilerOptions (options); var provider = CodeDomProvider.CreateProvider ("C#"); var result = provider.CompileAssemblyFromFile (compilerOptions, options.SourceFiles.Select (p => p.ToString ()).ToArray ()); @@ -199,7 +296,11 @@ namespace Mono.Linker.Tests.TestCasesRunner { protected virtual NPath CompileCSharpAssemblyWithCsc (CompilerOptions options) { +#if NETCOREAPP + return CompileCSharpAssemblyWithRoslyn (options); +#else return CompileCSharpAssemblyWithExternalCompiler (LocateCscExecutable (), options); +#endif } protected virtual NPath CompileCSharpAssemblyWithMcs(CompilerOptions options) diff --git a/test/Mono.Linker.Tests/TestCasesRunner/TestCaseMetadaProvider.cs b/test/Mono.Linker.Tests/TestCasesRunner/TestCaseMetadaProvider.cs index a41b398ff..24416984c 100644 --- a/test/Mono.Linker.Tests/TestCasesRunner/TestCaseMetadaProvider.cs +++ b/test/Mono.Linker.Tests/TestCasesRunner/TestCaseMetadaProvider.cs @@ -55,23 +55,55 @@ namespace Mono.Linker.Tests.TestCasesRunner { return tclo; } +#if NETCOREAPP + public static IEnumerable<string> GetTrustedPlatformAssemblies () + { + if (AppContext.GetData ("TRUSTED_PLATFORM_ASSEMBLIES") is string tpaPaths) { + foreach (var path in tpaPaths.Split(Path.PathSeparator)) { + if (Path.GetExtension (path) == ".dll") + yield return path; + } + } + } +#endif + public virtual IEnumerable<string> GetCommonReferencedAssemblies (NPath workingDirectory) { yield return workingDirectory.Combine ("Mono.Linker.Tests.Cases.Expectations.dll").ToString (); +#if NETCOREAPP + foreach (var path in GetTrustedPlatformAssemblies ()) { + // Don't reference testcases dll, as these will be compiled dynamically. + if (Path.GetFileName (path) != "Mono.Linker.Tests.Cases.dll") + yield return path; + } +#else yield return "mscorlib.dll"; +#endif } public virtual IEnumerable<string> GetReferencedAssemblies (NPath workingDirectory) { foreach (var fileName in GetReferenceValues ()) { - if (fileName.StartsWith ("System.", StringComparison.Ordinal) || fileName.StartsWith ("Mono.", StringComparison.Ordinal) || fileName.StartsWith ("Microsoft.", StringComparison.Ordinal)) + if (fileName.StartsWith ("System.", StringComparison.Ordinal) || fileName.StartsWith ("Mono.", StringComparison.Ordinal) || fileName.StartsWith ("Microsoft.", StringComparison.Ordinal)) { +#if NETCOREAPP + // Try to find the assembly alongside the host's framework dependencies + var frameworkDir = Path.GetDirectoryName (typeof (object).Assembly.Location); + var filePath = Path.Combine (frameworkDir, fileName); + if (File.Exists (filePath)) { + yield return filePath; + } else { + yield return fileName; + } +#else yield return fileName; - else +#endif + } else { // Drop any relative path information. Sandboxing will have taken care of copying the reference to the directory yield return workingDirectory.Combine (Path.GetFileName (fileName)); + } } } - + public virtual IEnumerable<string> GetReferenceDependencies () { return _testCaseTypeDefinition.CustomAttributes @@ -101,7 +133,13 @@ namespace Mono.Linker.Tests.TestCasesRunner { public virtual IEnumerable<NPath> GetExtraLinkerSearchDirectories () { +#if NETCOREAPP + var tpaDirs = GetTrustedPlatformAssemblies ().Select (p => Path.GetDirectoryName (p)).Distinct (); + foreach (var dir in tpaDirs) + yield return dir.ToNPath (); +#else yield break; +#endif } public virtual bool IsIgnored (out string reason) @@ -144,6 +182,10 @@ namespace Mono.Linker.Tests.TestCasesRunner { if (Environment.OSVersion.Platform == PlatformID.Win32NT) yield return "WIN32"; +#if NETCOREAPP + yield return "NETCOREAPP"; +#endif + foreach (var attr in _testCaseTypeDefinition.CustomAttributes.Where (attr => attr.AttributeType.Name == nameof (DefineAttribute))) yield return (string) attr.ConstructorArguments.First ().Value; } |