cleanup: upgrade test and samples to supported .NET Core versions

This commit is contained in:
Nate McMaster 2021-01-30 15:26:18 -08:00
parent 716a21b49e
commit 7d673f3378
No known key found for this signature in database
GPG Key ID: 157F9066DEF38BD0
14 changed files with 199 additions and 127 deletions

View File

@ -23,7 +23,7 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "JsonNet11", "test\TestProje
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "JsonNet9", "test\TestProjects\JsonNet9\JsonNet9.csproj", "{D71D858B-35AF-452F-926F-873DDD990B27}"
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "NetCoreApp20App", "test\TestProjects\NetCoreApp20App\NetCoreApp20App.csproj", "{B9C61145-C010-4FAA-B9EA-4D1AEE20305F}"
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "NetCoreApp2App", "test\TestProjects\NetCoreApp2App\NetCoreApp2App.csproj", "{B9C61145-C010-4FAA-B9EA-4D1AEE20305F}"
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "NetStandardClassLib", "test\TestProjects\NetStandardClassLib\NetStandardClassLib.csproj", "{4FDB7710-F4CA-45FB-9514-A4D288EDA44A}"
EndProject
@ -126,6 +126,16 @@ Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "WithOurPluginsPluginB", "te
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "NativeDependency", "test\TestProjects\NativeDependency\NativeDependency.csproj", "{2837A894-11D6-4DBF-B140-84C97C385A15}"
EndProject
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "dynamic-implementation", "dynamic-implementation", "{10109B62-DACC-42BA-AD8C-73DE4B93841B}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Contracts", "samples\dynamic-implementation\Contracts\Contracts.csproj", "{39B9F0B5-3C53-4140-B158-96C67C03E876}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Host", "samples\dynamic-implementation\Host\Host.csproj", "{703ECD55-EF0E-4734-A28E-371EDD213EEF}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Mixer", "samples\dynamic-implementation\Mixer\Mixer.csproj", "{9E2178A0-5915-4308-B6C3-5C8758A47788}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "ServiceImplementation", "samples\dynamic-implementation\ServiceImplementation\ServiceImplementation.csproj", "{39BCFE6F-50C4-45AE-8D13-38FB423AB619}"
EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|Any CPU = Debug|Any CPU
@ -652,6 +662,54 @@ Global
{2837A894-11D6-4DBF-B140-84C97C385A15}.Release|x64.Build.0 = Release|Any CPU
{2837A894-11D6-4DBF-B140-84C97C385A15}.Release|x86.ActiveCfg = Release|Any CPU
{2837A894-11D6-4DBF-B140-84C97C385A15}.Release|x86.Build.0 = Release|Any CPU
{39B9F0B5-3C53-4140-B158-96C67C03E876}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{39B9F0B5-3C53-4140-B158-96C67C03E876}.Debug|Any CPU.Build.0 = Debug|Any CPU
{39B9F0B5-3C53-4140-B158-96C67C03E876}.Debug|x64.ActiveCfg = Debug|Any CPU
{39B9F0B5-3C53-4140-B158-96C67C03E876}.Debug|x64.Build.0 = Debug|Any CPU
{39B9F0B5-3C53-4140-B158-96C67C03E876}.Debug|x86.ActiveCfg = Debug|Any CPU
{39B9F0B5-3C53-4140-B158-96C67C03E876}.Debug|x86.Build.0 = Debug|Any CPU
{39B9F0B5-3C53-4140-B158-96C67C03E876}.Release|Any CPU.ActiveCfg = Release|Any CPU
{39B9F0B5-3C53-4140-B158-96C67C03E876}.Release|Any CPU.Build.0 = Release|Any CPU
{39B9F0B5-3C53-4140-B158-96C67C03E876}.Release|x64.ActiveCfg = Release|Any CPU
{39B9F0B5-3C53-4140-B158-96C67C03E876}.Release|x64.Build.0 = Release|Any CPU
{39B9F0B5-3C53-4140-B158-96C67C03E876}.Release|x86.ActiveCfg = Release|Any CPU
{39B9F0B5-3C53-4140-B158-96C67C03E876}.Release|x86.Build.0 = Release|Any CPU
{703ECD55-EF0E-4734-A28E-371EDD213EEF}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{703ECD55-EF0E-4734-A28E-371EDD213EEF}.Debug|Any CPU.Build.0 = Debug|Any CPU
{703ECD55-EF0E-4734-A28E-371EDD213EEF}.Debug|x64.ActiveCfg = Debug|Any CPU
{703ECD55-EF0E-4734-A28E-371EDD213EEF}.Debug|x64.Build.0 = Debug|Any CPU
{703ECD55-EF0E-4734-A28E-371EDD213EEF}.Debug|x86.ActiveCfg = Debug|Any CPU
{703ECD55-EF0E-4734-A28E-371EDD213EEF}.Debug|x86.Build.0 = Debug|Any CPU
{703ECD55-EF0E-4734-A28E-371EDD213EEF}.Release|Any CPU.ActiveCfg = Release|Any CPU
{703ECD55-EF0E-4734-A28E-371EDD213EEF}.Release|Any CPU.Build.0 = Release|Any CPU
{703ECD55-EF0E-4734-A28E-371EDD213EEF}.Release|x64.ActiveCfg = Release|Any CPU
{703ECD55-EF0E-4734-A28E-371EDD213EEF}.Release|x64.Build.0 = Release|Any CPU
{703ECD55-EF0E-4734-A28E-371EDD213EEF}.Release|x86.ActiveCfg = Release|Any CPU
{703ECD55-EF0E-4734-A28E-371EDD213EEF}.Release|x86.Build.0 = Release|Any CPU
{9E2178A0-5915-4308-B6C3-5C8758A47788}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{9E2178A0-5915-4308-B6C3-5C8758A47788}.Debug|Any CPU.Build.0 = Debug|Any CPU
{9E2178A0-5915-4308-B6C3-5C8758A47788}.Debug|x64.ActiveCfg = Debug|Any CPU
{9E2178A0-5915-4308-B6C3-5C8758A47788}.Debug|x64.Build.0 = Debug|Any CPU
{9E2178A0-5915-4308-B6C3-5C8758A47788}.Debug|x86.ActiveCfg = Debug|Any CPU
{9E2178A0-5915-4308-B6C3-5C8758A47788}.Debug|x86.Build.0 = Debug|Any CPU
{9E2178A0-5915-4308-B6C3-5C8758A47788}.Release|Any CPU.ActiveCfg = Release|Any CPU
{9E2178A0-5915-4308-B6C3-5C8758A47788}.Release|Any CPU.Build.0 = Release|Any CPU
{9E2178A0-5915-4308-B6C3-5C8758A47788}.Release|x64.ActiveCfg = Release|Any CPU
{9E2178A0-5915-4308-B6C3-5C8758A47788}.Release|x64.Build.0 = Release|Any CPU
{9E2178A0-5915-4308-B6C3-5C8758A47788}.Release|x86.ActiveCfg = Release|Any CPU
{9E2178A0-5915-4308-B6C3-5C8758A47788}.Release|x86.Build.0 = Release|Any CPU
{39BCFE6F-50C4-45AE-8D13-38FB423AB619}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{39BCFE6F-50C4-45AE-8D13-38FB423AB619}.Debug|Any CPU.Build.0 = Debug|Any CPU
{39BCFE6F-50C4-45AE-8D13-38FB423AB619}.Debug|x64.ActiveCfg = Debug|Any CPU
{39BCFE6F-50C4-45AE-8D13-38FB423AB619}.Debug|x64.Build.0 = Debug|Any CPU
{39BCFE6F-50C4-45AE-8D13-38FB423AB619}.Debug|x86.ActiveCfg = Debug|Any CPU
{39BCFE6F-50C4-45AE-8D13-38FB423AB619}.Debug|x86.Build.0 = Debug|Any CPU
{39BCFE6F-50C4-45AE-8D13-38FB423AB619}.Release|Any CPU.ActiveCfg = Release|Any CPU
{39BCFE6F-50C4-45AE-8D13-38FB423AB619}.Release|Any CPU.Build.0 = Release|Any CPU
{39BCFE6F-50C4-45AE-8D13-38FB423AB619}.Release|x64.ActiveCfg = Release|Any CPU
{39BCFE6F-50C4-45AE-8D13-38FB423AB619}.Release|x64.Build.0 = Release|Any CPU
{39BCFE6F-50C4-45AE-8D13-38FB423AB619}.Release|x86.ActiveCfg = Release|Any CPU
{39BCFE6F-50C4-45AE-8D13-38FB423AB619}.Release|x86.Build.0 = Release|Any CPU
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE
@ -706,6 +764,11 @@ Global
{3A7712FC-9A91-4322-AF7E-4FEC6EB0D845} = {98E964A2-55DA-4740-9F2E-B64FDF6715DB}
{D5B3DA06-E60D-4C85-8835-6A26003365AA} = {98E964A2-55DA-4740-9F2E-B64FDF6715DB}
{2837A894-11D6-4DBF-B140-84C97C385A15} = {98E964A2-55DA-4740-9F2E-B64FDF6715DB}
{10109B62-DACC-42BA-AD8C-73DE4B93841B} = {F49FFE3B-E1AE-483E-951F-D498F6ABA08E}
{39B9F0B5-3C53-4140-B158-96C67C03E876} = {10109B62-DACC-42BA-AD8C-73DE4B93841B}
{703ECD55-EF0E-4734-A28E-371EDD213EEF} = {10109B62-DACC-42BA-AD8C-73DE4B93841B}
{9E2178A0-5915-4308-B6C3-5C8758A47788} = {10109B62-DACC-42BA-AD8C-73DE4B93841B}
{39BCFE6F-50C4-45AE-8D13-38FB423AB619} = {10109B62-DACC-42BA-AD8C-73DE4B93841B}
EndGlobalSection
GlobalSection(ExtensibilityGlobals) = postSolution
SolutionGuid = {B1AF41DC-A03E-47B1-BBDB-3DC27ABD9F74}

View File

@ -1,7 +1,7 @@
<Project Sdk="Microsoft.NET.Sdk.Web">
<PropertyGroup>
<TargetFramework>netcoreapp3.0</TargetFramework>
<TargetFramework>netcoreapp3.1</TargetFramework>
</PropertyGroup>
<ItemGroup>

View File

@ -1,7 +1,7 @@
<Project Sdk="Microsoft.NET.Sdk.Razor">
<PropertyGroup>
<TargetFramework>netcoreapp3.0</TargetFramework>
<TargetFramework>netcoreapp3.1</TargetFramework>
<AddRazorSupportForMvc>true</AddRazorSupportForMvc>
</PropertyGroup>

View File

@ -2,7 +2,7 @@
<PropertyGroup>
<OutputType>Exe</OutputType>
<TargetFramework>netcoreapp3.0</TargetFramework>
<TargetFramework>netcoreapp3.1</TargetFramework>
</PropertyGroup>
<ItemGroup>

View File

@ -2,7 +2,7 @@
<PropertyGroup>
<OutputType>Exe</OutputType>
<TargetFramework>netcoreapp3.0</TargetFramework>
<TargetFramework>netcoreapp3.1</TargetFramework>
</PropertyGroup>
<ItemGroup>

View File

@ -2,7 +2,7 @@
<PropertyGroup>
<OutputType>Exe</OutputType>
<TargetFramework>netcoreapp3.0</TargetFramework>
<TargetFramework>netcoreapp3.1</TargetFramework>
</PropertyGroup>
<ItemGroup>

View File

@ -1,7 +1,7 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<TargetFramework>netcoreapp3.0</TargetFramework>
<TargetFramework>netcoreapp3.1</TargetFramework>
</PropertyGroup>
<ItemGroup>

View File

@ -9,11 +9,11 @@ namespace McMaster.NETCore.Plugins.Tests
{
public class BasicAssemblyLoaderTests
{
#if NETCOREAPP3_0
#if NETCOREAPP3_1
[Fact]
public void PluginLoaderCanUnload()
{
var path = TestResources.GetTestProjectAssembly("NetCoreApp20App");
var path = TestResources.GetTestProjectAssembly("NetCoreApp2App");
// See https://github.com/dotnet/coreclr/pull/22221
@ -36,7 +36,7 @@ namespace McMaster.NETCore.Plugins.Tests
var assembly = loader.LoadDefaultAssembly();
var method = assembly
.GetType("NetCoreApp20App.Program", throwOnError: true)!
.GetType("NetCoreApp2App.Program", throwOnError: true)!
.GetMethod("GetGreeting", BindingFlags.Static | BindingFlags.Public);
Assert.True(loader.IsUnloadable);
@ -81,14 +81,14 @@ namespace McMaster.NETCore.Plugins.Tests
}
[Fact]
public void LoadsNetCoreApp20Project()
public void LoadsNetCoreApp2Project()
{
var path = TestResources.GetTestProjectAssembly("NetCoreApp20App");
var path = TestResources.GetTestProjectAssembly("NetCoreApp2App");
var loader = PluginLoader.CreateFromAssemblyFile(path);
var assembly = loader.LoadDefaultAssembly();
var method = assembly
.GetType("NetCoreApp20App.Program", throwOnError: true)!
.GetType("NetCoreApp2App.Program", throwOnError: true)!
.GetMethod("GetGreeting", BindingFlags.Static | BindingFlags.Public);
Assert.NotNull(method);
Assert.Equal("Hello world!", method!.Invoke(null, Array.Empty<object>()));
@ -144,7 +144,7 @@ namespace McMaster.NETCore.Plugins.Tests
{
var path = TestResources.GetTestProjectAssembly("Plátano");
var loader = PluginLoader.CreateFromAssemblyFile(path,
#if NETCOREAPP3_0
#if NETCOREAPP3_1
isUnloadable: true,
#endif
sharedTypes: new[] { typeof(IFruit) });

View File

@ -20,7 +20,7 @@
<ProjectReference Include="..\TestProjects\SharedAbstraction.v2\SharedAbstraction.v2.csproj" />
<TestProject Include="..\TestProjects\ReferencedLibv2\ReferencedLibv2.csproj" />
<TestProject Include="..\TestProjects\DrawingApp\DrawingApp.csproj" />
<TestProject Include="..\TestProjects\NetCoreApp20App\NetCoreApp20App.csproj" />
<TestProject Include="..\TestProjects\NetCoreApp2App\NetCoreApp2App.csproj" />
<TestProject Include="..\TestProjects\NetStandardClassLib\NetStandardClassLib.csproj" />
<TestProject Include="..\TestProjects\JsonNet9\JsonNet9.csproj" />
<TestProject Include="..\TestProjects\JsonNet10\JsonNet10.csproj" />

View File

@ -1,28 +1,31 @@
#if NETCOREAPP3_1
using Xunit;
namespace McMaster.NETCore.Plugins.Tests
{
public class ShadowCopyTests
{
[Fact]
public void DoesNotThrowWhenLoadingSameNativeDependecyMoreThanOnce()
{
var samplePath = TestResources.GetTestProjectAssembly("NativeDependency");
using var loader = PluginLoader
.CreateFromAssemblyFile(samplePath, config => config.EnableHotReload = true);
var nativeDependecyLoadMethod = loader.LoadDefaultAssembly()
.GetType("NativeDependency.NativeDependencyLoader")
.GetMethod("Load");
var exception = Record.Exception(() => nativeDependecyLoadMethod.Invoke(null, null));
Assert.Null(exception);
}
}
}
#endif
// Copyright (c) Nate McMaster.
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
#if NETCOREAPP3_1
using Xunit;
namespace McMaster.NETCore.Plugins.Tests
{
public class ShadowCopyTests
{
[Fact]
public void DoesNotThrowWhenLoadingSameNativeDependecyMoreThanOnce()
{
var samplePath = TestResources.GetTestProjectAssembly("NativeDependency");
using var loader = PluginLoader
.CreateFromAssemblyFile(samplePath, config => config.EnableHotReload = true);
var nativeDependecyLoadMethod = loader.LoadDefaultAssembly()
?.GetType("NativeDependency.NativeDependencyLoader")
?.GetMethod("Load");
var exception = Record.Exception(() => nativeDependecyLoadMethod?.Invoke(null, null));
Assert.Null(exception);
}
}
}
#endif

View File

@ -1,14 +0,0 @@
using System;
namespace NetCoreApp20App
{
class Program
{
static void Main(string[] args)
{
Console.WriteLine(GetGreeting());
}
public static string GetGreeting() => "Hello world!";
}
}

View File

@ -2,7 +2,7 @@
<PropertyGroup>
<OutputType>Exe</OutputType>
<TargetFramework>netcoreapp2.0</TargetFramework>
<TargetFramework>netcoreapp2.1</TargetFramework>
</PropertyGroup>
<ItemGroup>

View File

@ -0,0 +1,17 @@
// Copyright (c) Nate McMaster.
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
using System;
namespace NetCoreApp2App
{
internal class Program
{
public static void Main(string[] args)
{
Console.WriteLine(GetGreeting());
}
public static string GetGreeting() => "Hello world!";
}
}

View File

@ -1,69 +1,72 @@
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Reflection;
using System.Runtime.Loader;
using McMaster.NETCore.Plugins;
using WithOurPluginsPluginContract;
using WithOwnPluginsContract;
namespace WithOwnPlugins
{
public class WithOwnPlugins : IWithOwnPlugins
{
public bool TryLoadPluginsInCustomContext(AssemblyLoadContext? callingContext)
{
var currentContext = AssemblyLoadContext.GetLoadContext(Assembly.GetExecutingAssembly());
if (currentContext == callingContext)
{
throw new ArgumentException("The context of the caller is the context of this assembly. This invalidates the test.");
}
#if NETCOREAPP3_0
/*
Ensure the source calling context does not have our plugin's interfaces loaded.
This guarantees that the Assembly cannot possibly unify with the default load context.
Note:
The code below this check would fail anyway if the assembly would unify with the default context.
This is more of a safety check to ensure "correctness" as opposed to anything else.
*/
var sayHelloAssembly = typeof(ISayHello).Assembly;
if (callingContext?.Assemblies.Contains(sayHelloAssembly) == true) // .Assemblies API not available in Core 2.X
{
throw new ArgumentException("The context of the caller has this plugin's interface to interact with its own plugins loaded. Test is void.");
}
#endif
// Load our own plugins: Remember, we are in an isolated, non-default ALC.
var plugins = new List<ISayHello?>();
string[] assemblyNames = { "Plugins/WithOurPluginsPluginA.dll", "Plugins/WithOurPluginsPluginB.dll" };
foreach (var assemblyName in assemblyNames)
{
var currentAssemblyFolderPath = Path.GetDirectoryName(Assembly.GetExecutingAssembly().Location) ?? throw new Exception("Unable to get folder path for currently executing assembly.");
var pluginPath = Path.Combine(currentAssemblyFolderPath, assemblyName);
using var loader = PluginLoader.CreateFromAssemblyFile(pluginPath, new[] { typeof(ISayHello) });
var assembly = loader.LoadDefaultAssembly();
var configType = assembly.GetTypes().First(x => typeof(ISayHello).IsAssignableFrom(x) && !x.IsAbstract);
var plugin = (ISayHello?)Activator.CreateInstance(configType);
if (plugin == null)
{
throw new Exception($"Failed to load instance of {nameof(ISayHello)} from plugin.");
}
plugins.Add(plugin);
}
// Shouldn't need to check for this but just in case to absolutely make sure.
if (plugins.Any(plugin => String.IsNullOrEmpty(plugin?.SayHello())))
{
throw new Exception("No value returned from plugin.");
}
return true;
}
}
}
// Copyright (c) Nate McMaster.
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Reflection;
using System.Runtime.Loader;
using McMaster.NETCore.Plugins;
using WithOurPluginsPluginContract;
using WithOwnPluginsContract;
namespace WithOwnPlugins
{
public class WithOwnPlugins : IWithOwnPlugins
{
public bool TryLoadPluginsInCustomContext(AssemblyLoadContext? callingContext)
{
var currentContext = AssemblyLoadContext.GetLoadContext(Assembly.GetExecutingAssembly());
if (currentContext == callingContext)
{
throw new ArgumentException("The context of the caller is the context of this assembly. This invalidates the test.");
}
#if NETCOREAPP3_1
/*
Ensure the source calling context does not have our plugin's interfaces loaded.
This guarantees that the Assembly cannot possibly unify with the default load context.
Note:
The code below this check would fail anyway if the assembly would unify with the default context.
This is more of a safety check to ensure "correctness" as opposed to anything else.
*/
var sayHelloAssembly = typeof(ISayHello).Assembly;
if (callingContext?.Assemblies.Contains(sayHelloAssembly) == true) // .Assemblies API not available in Core 2.X
{
throw new ArgumentException("The context of the caller has this plugin's interface to interact with its own plugins loaded. Test is void.");
}
#endif
// Load our own plugins: Remember, we are in an isolated, non-default ALC.
var plugins = new List<ISayHello?>();
string[] assemblyNames = { "Plugins/WithOurPluginsPluginA.dll", "Plugins/WithOurPluginsPluginB.dll" };
foreach (var assemblyName in assemblyNames)
{
var currentAssemblyFolderPath = Path.GetDirectoryName(Assembly.GetExecutingAssembly().Location) ?? throw new Exception("Unable to get folder path for currently executing assembly.");
var pluginPath = Path.Combine(currentAssemblyFolderPath, assemblyName);
using var loader = PluginLoader.CreateFromAssemblyFile(pluginPath, new[] { typeof(ISayHello) });
var assembly = loader.LoadDefaultAssembly();
var configType = assembly.GetTypes().First(x => typeof(ISayHello).IsAssignableFrom(x) && !x.IsAbstract);
var plugin = (ISayHello?)Activator.CreateInstance(configType);
if (plugin == null)
{
throw new Exception($"Failed to load instance of {nameof(ISayHello)} from plugin.");
}
plugins.Add(plugin);
}
// Shouldn't need to check for this but just in case to absolutely make sure.
if (plugins.Any(plugin => String.IsNullOrEmpty(plugin?.SayHello())))
{
throw new Exception("No value returned from plugin.");
}
return true;
}
}
}