diff options
author | vnugent <public@vaughnnugent.com> | 2024-02-14 14:10:27 -0500 |
---|---|---|
committer | vnugent <public@vaughnnugent.com> | 2024-02-14 14:10:27 -0500 |
commit | 2b1314c1475e7e1831c691cf349cb89c66fa320c (patch) | |
tree | 091fc132a2bee2e79a68d8c6d5eb20f1d989a3d2 /third-party/DotNetCorePlugins/test | |
parent | f4e4db7c5320976406feb252ae8f8bdbe9b3e351 (diff) |
Squashed commit of the following:
commit ddd8a651b6eb43cfdd49d84056f8b9c34b543992
Author: vnugent <public@vaughnnugent.com>
Date: Wed Feb 14 00:15:50 2024 -0500
ci: reduce output noise and update Argon2 build
commit cf942959ff2feea03d3eda2ff2a263bdac4d6bc6
Author: vnugent <public@vaughnnugent.com>
Date: Mon Feb 12 18:39:18 2024 -0500
chore: update packages and minor fixes
commit ab506af9e2de2876b11bb45b3c7e787616c80155
Author: vnugent <public@vaughnnugent.com>
Date: Fri Feb 9 21:27:24 2024 -0500
fix: patch and update core runtime service injection
commit 7ed5e8b19164c28d3a238bd56878d2161fbea2e4
Author: vnugent <public@vaughnnugent.com>
Date: Thu Feb 8 18:26:11 2024 -0500
fork dotnetplugins and make some intial updates/upgrades
commit f4cab88d67be5da0953b14bd46fc972d4acc8606
Author: vnugent <public@vaughnnugent.com>
Date: Thu Feb 8 12:16:13 2024 -0500
update some heap api functions
commit 6035bf7ed8412f1da361cc5feddd860abfaf4fc1
Author: vnugent <public@vaughnnugent.com>
Date: Wed Feb 7 22:09:11 2024 -0500
working file-watcher notifications/rework
commit 698f8edf694ad9700ee2ce2220e692b496448ff9
Author: vnugent <public@vaughnnugent.com>
Date: Wed Feb 7 20:37:28 2024 -0500
remove mem-template and add file-watcher utility
commit b17591e0fb363222fcd7d93c2bad4ab1b102385f
Author: vnugent <public@vaughnnugent.com>
Date: Wed Feb 7 18:28:21 2024 -0500
add small memmove support for known small blocks
commit 631be4d4b27fdbcd4b0526e17a128bb0d86911eb
Author: vnugent <public@vaughnnugent.com>
Date: Wed Feb 7 18:08:02 2024 -0500
setup some readonly ref arguments and convert copy apis to readonly refs
commit 2ba8dec68d5cb192e61ad0141d4b460076d3f90a
Author: vnugent <public@vaughnnugent.com>
Date: Mon Feb 5 18:30:38 2024 -0500
restructure internal memmove strategies
commit 25cf02872da980893ad7fb51d4eccc932380582b
Author: vnugent <public@vaughnnugent.com>
Date: Sun Feb 4 01:29:18 2024 -0500
add http stream interface, profiling -> file read updates
commit 757668c44e78864dc69d5713a2cfba6db2ed9a2a
Author: vnugent <public@vaughnnugent.com>
Date: Fri Feb 2 14:27:04 2024 -0500
streamline data-copy api with proper large block support and net8 feature updates
commit f22c1765fd72ab40a10d8ec92a8cb6d9ec1b1a04
Author: vnugent <public@vaughnnugent.com>
Date: Mon Jan 29 16:16:23 2024 -0500
check for compression lib updates to close #2 and fix some ci build stuff
commit f974bfdef6a795b4a1c04602502ef506ef2587a9
Author: vnugent <public@vaughnnugent.com>
Date: Tue Jan 23 17:36:17 2024 -0500
switch allocator libs to lgpl2.1
commit 1fe5e01b329cd27b675000f1a557b784d3c88b56
Author: vnugent <public@vaughnnugent.com>
Date: Tue Jan 23 17:05:59 2024 -0500
consolidate allocator packages and close #1
commit 74e1107e522f00b670526193396217f40a6bade7
Author: vnugent <public@vaughnnugent.com>
Date: Tue Jan 23 15:43:40 2024 -0500
cache extension api tweaks
commit 96ca2b0388a6326b9bb74f3ab2f62eaede6681e0
Author: vnugent <public@vaughnnugent.com>
Date: Mon Jan 22 17:54:23 2024 -0500
explicit tcp server args reuse
Diffstat (limited to 'third-party/DotNetCorePlugins/test')
64 files changed, 1381 insertions, 0 deletions
diff --git a/third-party/DotNetCorePlugins/test/Plugins.Tests/BasicAssemblyLoaderTests.cs b/third-party/DotNetCorePlugins/test/Plugins.Tests/BasicAssemblyLoaderTests.cs new file mode 100644 index 0000000..c094951 --- /dev/null +++ b/third-party/DotNetCorePlugins/test/Plugins.Tests/BasicAssemblyLoaderTests.cs @@ -0,0 +1,160 @@ +// 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.Reflection; +using System.Runtime.CompilerServices; +using McMaster.Extensions.Xunit; +using Test.Referenced.Library; +using Xunit; + +namespace McMaster.NETCore.Plugins.Tests +{ + public class BasicAssemblyLoaderTests + { +#if !NETCOREAPP2_1 + [Fact] + public void PluginLoaderCanUnload() + { + var path = TestResources.GetTestProjectAssembly("NetCoreApp2App"); + + // See https://github.com/dotnet/coreclr/pull/22221 + + ExecuteAndUnload(path, out var weakRef); + + // Force a GC collect to ensure unloaded has completed + for (var i = 0; weakRef.IsAlive && (i < 10); i++) + { + GC.Collect(); + GC.WaitForPendingFinalizers(); + } + + Assert.False(weakRef.IsAlive); + } + + [MethodImpl(MethodImplOptions.NoInlining)] // ensure no local vars are create + private void ExecuteAndUnload(string path, out WeakReference weakRef) + { + var loader = PluginLoader.CreateFromAssemblyFile(path, c => { c.IsUnloadable = true; }); + var assembly = loader.LoadDefaultAssembly(); + + var method = assembly + .GetType("NetCoreApp2App.Program", throwOnError: true)! + .GetMethod("GetGreeting", BindingFlags.Static | BindingFlags.Public); + + Assert.True(loader.IsUnloadable); + Assert.NotNull(method); + Assert.Equal("Hello world!", method!.Invoke(null, Array.Empty<object>())); + loader.Dispose(); + Assert.Throws<ObjectDisposedException>(() => loader.LoadDefaultAssembly()); + + weakRef = new WeakReference(loader.LoadContext, trackResurrection: true); + } +#endif + + [Fact] + public void LoadsNetCoreProjectWithNativeDeps() + { + var path = TestResources.GetTestProjectAssembly("PowerShellPlugin"); + var loader = PluginLoader.CreateFromAssemblyFile(path); + var assembly = loader.LoadDefaultAssembly(); + + var method = assembly + .GetType("PowerShellPlugin.Program", throwOnError: true)! + .GetMethod("GetGreeting", BindingFlags.Static | BindingFlags.Public); + Assert.NotNull(method); + Assert.Equal("hello", method!.Invoke(null, Array.Empty<object>())); + } + + [SkippableFact] + [SkipOnOS(OS.Linux | OS.MacOS)] + public void LoadsNativeDependenciesWhenDllImportUsesFilename() + { + // SqlClient has P/invoke that calls "sni.dll" on Windows. This test checks + // that native libraries can still be resolved in this case. + var path = TestResources.GetTestProjectAssembly("SqlClientApp"); + var loader = PluginLoader.CreateFromAssemblyFile(path); + var assembly = loader.LoadDefaultAssembly(); + + var method = assembly + .GetType("SqlClientApp.Program", throwOnError: true)! + .GetMethod("Run", BindingFlags.Static | BindingFlags.Public); + Assert.NotNull(method); + Assert.Equal(true, method!.Invoke(null, Array.Empty<object>())); + } + + [Fact] + public void LoadsNetCoreApp2Project() + { + var path = TestResources.GetTestProjectAssembly("NetCoreApp2App"); + var loader = PluginLoader.CreateFromAssemblyFile(path); + var assembly = loader.LoadDefaultAssembly(); + + var method = assembly + .GetType("NetCoreApp2App.Program", throwOnError: true)! + .GetMethod("GetGreeting", BindingFlags.Static | BindingFlags.Public); + Assert.NotNull(method); + Assert.Equal("Hello world!", method!.Invoke(null, Array.Empty<object>())); + } + + [Fact] + public void LoadsNetStandard20Project() + { + var path = TestResources.GetTestProjectAssembly("NetStandardClassLib"); + var loader = PluginLoader.CreateFromAssemblyFile(path); + var assembly = loader.LoadDefaultAssembly(); + + var type = assembly.GetType("NetStandardClassLib.Class1", throwOnError: true); + var method = type!.GetMethod("GetColor", BindingFlags.Instance | BindingFlags.Public); + Assert.NotNull(method); + Assert.Equal("Red", method!.Invoke(Activator.CreateInstance(type), Array.Empty<object>())); + } + + [Fact] + public void ItPrefersRuntimeSpecificManagedAssetsOverRidlessOnes() + { + // System.Drawing.Common is an example of a package which has both rid-specific and ridless versions + // The package has lib/netstandard2.0/System.Drawing.Common.dll, but also has runtimes/{win,unix}/lib/netcoreapp2.0/System.Drawing.Common.dll + // In this case, the host will pick the rid-specific version + + var path = TestResources.GetTestProjectAssembly("DrawingApp"); + var loader = PluginLoader.CreateFromAssemblyFile(path); + var assembly = loader.LoadDefaultAssembly(); + + var type = assembly.GetType("Finder", throwOnError: true)!; + var method = type.GetMethod("FindDrawingAssembly", BindingFlags.Static | BindingFlags.Public); + Assert.NotNull(method); + Assert.Contains("runtimes", (string?)method!.Invoke(null, Array.Empty<object>())); + } + + [Fact] + [UseCulture("es")] + public void ItLoadsSatelliteAssemblies() + { + var fruit = GetPlátano(); + Assert.Equal("Plátano", fruit.GetFlavor()); + } + + [Fact] + [UseCulture("en")] + public void ItLoadsDefaultCultureAssemblies() + { + var fruit = GetPlátano(); + Assert.Equal("Banana", fruit.GetFlavor()); + } + + private IFruit GetPlátano() + { + var path = TestResources.GetTestProjectAssembly("Plátano"); + var loader = PluginLoader.CreateFromAssemblyFile(path, +#if !NETCOREAPP2_1 + isUnloadable: true, +#endif + sharedTypes: new[] { typeof(IFruit) }); + + var assembly = loader.LoadDefaultAssembly(); + var type = Assert.Single(assembly.GetTypes(), t => typeof(IFruit).IsAssignableFrom(t)); + return (IFruit)Activator.CreateInstance(type)!; + } + } +} diff --git a/third-party/DotNetCorePlugins/test/Plugins.Tests/DebouncerTests.cs b/third-party/DotNetCorePlugins/test/Plugins.Tests/DebouncerTests.cs new file mode 100644 index 0000000..67994f6 --- /dev/null +++ b/third-party/DotNetCorePlugins/test/Plugins.Tests/DebouncerTests.cs @@ -0,0 +1,60 @@ +// 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.Threading.Tasks; +using McMaster.NETCore.Plugins.Internal; +using Xunit; + +namespace McMaster.NETCore.Plugins.Tests +{ + public class DebouncerTests + { + [Fact] + public async Task InvocationIsDelayed() + { + var executionCounter = 0; + + var debouncer = new Debouncer(TimeSpan.FromSeconds(.1)); + debouncer.Execute(() => executionCounter++); + + Assert.Equal(0, executionCounter); + + await Task.Delay(TimeSpan.FromSeconds(.5)); + + Assert.Equal(1, executionCounter); + } + + [Fact] + public async Task ActionsAreDebounced() + { + var executionCounter = 0; + + var debouncer = new Debouncer(TimeSpan.FromSeconds(.1)); + debouncer.Execute(() => executionCounter++); + debouncer.Execute(() => executionCounter++); + debouncer.Execute(() => executionCounter++); + + await Task.Delay(TimeSpan.FromSeconds(.5)); + + Assert.Equal(1, executionCounter); + } + + [Fact] + public async Task OnlyLastActionIsInvoked() + { + string? invokedAction = null; + + var debouncer = new Debouncer(TimeSpan.FromSeconds(.1)); + foreach (var action in new[] { "a", "b", "c" }) + { + debouncer.Execute(() => invokedAction = action); + } + + await Task.Delay(TimeSpan.FromSeconds(.5)); + + Assert.NotNull(invokedAction); + Assert.Equal("c", invokedAction); + } + } +} diff --git a/third-party/DotNetCorePlugins/test/Plugins.Tests/ManageLoadContextTests.cs b/third-party/DotNetCorePlugins/test/Plugins.Tests/ManageLoadContextTests.cs new file mode 100644 index 0000000..bd40aae --- /dev/null +++ b/third-party/DotNetCorePlugins/test/Plugins.Tests/ManageLoadContextTests.cs @@ -0,0 +1,69 @@ +// 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.IO; +using System.Reflection; +using System.Runtime.Loader; +using McMaster.NETCore.Plugins.Loader; +using Xunit; + +namespace McMaster.NETCore.Plugins.Tests +{ + public class ManagedLoadContextTests + { + [Fact] + public void ItUpgradesTypesInContext() + { + var samplePath = TestResources.GetTestProjectAssembly("XunitSample"); + var context = new AssemblyLoadContextBuilder() + .SetMainAssemblyPath(samplePath) + .AddProbingPath(samplePath) + .AddDependencyContext(Path.Combine(Path.GetDirectoryName(samplePath)!, "XunitSample.deps.json")) + .PreferDefaultLoadContext(true) + .Build(); + + Assert.Same(typeof(TheoryData).Assembly, LoadAssembly(context, "xunit.core")); + } + + [Fact] + public void ContextsHavePrivateVersionsByDefault() + { + var samplePath = TestResources.GetTestProjectAssembly("XunitSample"); + + var context = new AssemblyLoadContextBuilder() + .SetMainAssemblyPath(samplePath) + .AddProbingPath(samplePath) + .AddDependencyContext(Path.Combine(Path.GetDirectoryName(samplePath)!, "XunitSample.deps.json")) + .Build(); + + Assert.NotSame(typeof(TheoryData).Assembly, LoadAssembly(context, "xunit.core")); + } + + [Fact] + public void ItCanDowngradeUnifiedTypes() + { + var samplePath = TestResources.GetTestProjectAssembly("NetCoreApp2App"); + + var defaultLoader = new AssemblyLoadContextBuilder() + .SetMainAssemblyPath(samplePath) + .AddProbingPath(samplePath) + .PreferDefaultLoadContext(false) + .AddDependencyContext(Path.Combine(Path.GetDirectoryName(samplePath)!, "NetCoreApp2App.deps.json")) + .Build(); + + var unifedLoader = new AssemblyLoadContextBuilder() + .SetMainAssemblyPath(samplePath) + .AddProbingPath(samplePath) + .PreferDefaultLoadContext(true) + .AddDependencyContext(Path.Combine(Path.GetDirectoryName(samplePath)!, "NetCoreApp2App.deps.json")) + .Build(); + + Assert.Equal(new Version("2.0.0.0"), LoadAssembly(defaultLoader, "Test.Referenced.Library").GetName().Version); + Assert.Equal(new Version("1.0.0.0"), LoadAssembly(unifedLoader, "Test.Referenced.Library").GetName().Version); + } + + private Assembly LoadAssembly(AssemblyLoadContext context, string name) + => context.LoadFromAssemblyName(new AssemblyName(name)); + } +} diff --git a/third-party/DotNetCorePlugins/test/Plugins.Tests/McMaster.NETCore.Plugins.Tests.csproj b/third-party/DotNetCorePlugins/test/Plugins.Tests/McMaster.NETCore.Plugins.Tests.csproj new file mode 100644 index 0000000..5a0a5f5 --- /dev/null +++ b/third-party/DotNetCorePlugins/test/Plugins.Tests/McMaster.NETCore.Plugins.Tests.csproj @@ -0,0 +1,41 @@ +<Project Sdk="Microsoft.NET.Sdk"> + + <PropertyGroup> + <TargetFrameworks>net5.0;netcoreapp3.1;netcoreapp2.1</TargetFrameworks> + <DefaultItemExcludes>$(DefaultItemExcludes);TestResults\**</DefaultItemExcludes> + </PropertyGroup> + + <ItemGroup> + <PackageReference Include="McMaster.Extensions.Xunit" Version="0.1.0" /> + <PackageReference Include="coverlet.collector" Version="3.0.3" /> + <PackageReference Include="Microsoft.NET.Test.Sdk" Version="16.9.1" /> + <PackageReference Include="xunit" Version="2.4.1" /> + <PackageReference Include="xunit.runner.visualstudio" Version="2.4.3" /> + </ItemGroup> + + <ItemGroup> + <ProjectReference Include="..\..\src\Plugins\McMaster.NETCore.Plugins.csproj" /> + <ProjectReference Include="..\TestProjects\WithOwnPluginsContract\WithOwnPluginsContract.csproj" /> + <ProjectReference Include="..\TestProjects\ReferencedLibv1\ReferencedLibv1.csproj" /> + <ProjectReference Include="..\TestProjects\SharedAbstraction.v2\SharedAbstraction.v2.csproj" /> + <TestProject Include="..\TestProjects\ReferencedLibv2\ReferencedLibv2.csproj" /> + <TestProject Include="..\TestProjects\DrawingApp\DrawingApp.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" /> + <TestProject Include="..\TestProjects\JsonNet11\JsonNet11.csproj" /> + <TestProject Include="..\TestProjects\Strawberry\Strawberry.csproj" /> + <TestProject Include="..\TestProjects\Banana\Banana.csproj" /> + <TestProject Include="..\TestProjects\Plátano\Plátano.csproj" /> + <TestProject Include="..\TestProjects\XunitSample\XunitSample.csproj" /> + <TestProject Include="..\TestProjects\SqlClientApp\SqlClientApp.csproj" /> + <TestProject Include="..\TestProjects\TransitivePlugin\TransitivePlugin.csproj" /> + <TestProject Include="..\TestProjects\NativeDependency\NativeDependency.csproj" Condition=" '$(TargetFramework)' != 'netcoreapp2.1' " /> + <PublishedTestProject Include="..\TestProjects\PowerShellPlugin\PowerShellPlugin.csproj" /> + <MultitargetTestProject Include="..\TestProjects\WithOwnPlugins\WithOwnPlugins.csproj" /> + </ItemGroup> + + <Import Project="TestProjectRefs.targets" /> + +</Project> diff --git a/third-party/DotNetCorePlugins/test/Plugins.Tests/PrivateDependencyTests.cs b/third-party/DotNetCorePlugins/test/Plugins.Tests/PrivateDependencyTests.cs new file mode 100644 index 0000000..c9c56f5 --- /dev/null +++ b/third-party/DotNetCorePlugins/test/Plugins.Tests/PrivateDependencyTests.cs @@ -0,0 +1,40 @@ +// 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.Reflection; +using Xunit; + +namespace McMaster.NETCore.Plugins.Tests +{ + public class PrivateDependencyTests + { + [Fact] + public void EachContextHasPrivateVersions() + { + var json9context = PluginLoader.CreateFromAssemblyFile(TestResources.GetTestProjectAssembly("JsonNet9")); + var json10context = PluginLoader.CreateFromAssemblyFile(TestResources.GetTestProjectAssembly("JsonNet10")); + var json11context = PluginLoader.CreateFromAssemblyFile(TestResources.GetTestProjectAssembly("JsonNet11")); + + // Load newest first to prove we can load older assemblies later into the same process + var json11 = GetJson(json11context); + var json10 = GetJson(json10context); + var json9 = GetJson(json9context); + + Assert.Equal(new Version("9.0.0.0"), json9.GetName().Version); + Assert.Equal(new Version("10.0.0.0"), json10.GetName().Version); + Assert.Equal(new Version("11.0.0.0"), json11.GetName().Version); + + // types from each context have unique identities + Assert.NotEqual( + json11.GetType("Newtonsoft.Json.JsonConvert", throwOnError: true), + json10.GetType("Newtonsoft.Json.JsonConvert", throwOnError: true)); + Assert.NotEqual( + json10.GetType("Newtonsoft.Json.JsonConvert", throwOnError: true), + json9.GetType("Newtonsoft.Json.JsonConvert", throwOnError: true)); + } + + private Assembly GetJson(PluginLoader loader) + => loader.LoadAssembly(new AssemblyName("Newtonsoft.Json")); + } +} diff --git a/third-party/DotNetCorePlugins/test/Plugins.Tests/ShadowCopyTests.cs b/third-party/DotNetCorePlugins/test/Plugins.Tests/ShadowCopyTests.cs new file mode 100644 index 0000000..07e7afb --- /dev/null +++ b/third-party/DotNetCorePlugins/test/Plugins.Tests/ShadowCopyTests.cs @@ -0,0 +1,31 @@ +// Copyright (c) Nate McMaster. +// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. + +#if !NETCOREAPP2_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 nativeDependencyLoadMethod = loader.LoadDefaultAssembly() + ?.GetType("NativeDependency.NativeDependencyLoader") + ?.GetMethod("Load"); + + var exception = Record.Exception(() => nativeDependencyLoadMethod?.Invoke(null, null)); + + Assert.Null(exception); + } + } +} + +#endif diff --git a/third-party/DotNetCorePlugins/test/Plugins.Tests/SharedTypesTests.cs b/third-party/DotNetCorePlugins/test/Plugins.Tests/SharedTypesTests.cs new file mode 100644 index 0000000..f03f42c --- /dev/null +++ b/third-party/DotNetCorePlugins/test/Plugins.Tests/SharedTypesTests.cs @@ -0,0 +1,107 @@ +// 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.Linq; +using System.Reflection; +using System.Runtime.Loader; +using Test.Referenced.Library; +using Test.Shared.Abstraction; +using WithOwnPluginsContract; +using Xunit; + +namespace McMaster.NETCore.Plugins.Tests +{ + public class SharedTypesTests + { + [Fact] + public void PluginsCanForceSharedTypes() + { + var pluginsNames = new[] { "Banana", "Strawberry" }; + var loaders = new List<PluginLoader>(); + foreach (var name in pluginsNames) + { + var loader = PluginLoader.CreateFromAssemblyFile( + TestResources.GetTestProjectAssembly(name), + sharedTypes: new[] { typeof(IFruit) }); + loaders.Add(loader); + } + + foreach (var plugin in loaders.Select(l => l.LoadDefaultAssembly())) + { + var fruitType = Assert.Single(plugin.GetTypes(), t => typeof(IFruit).IsAssignableFrom(t)); + var fruit = (IFruit)Activator.CreateInstance(fruitType)!; + Assert.NotNull(fruit.GetFlavor()); + } + } + + /// <summary> + /// This is a carefully crafted example which tests + /// that the assembly dependencies of shared types are + /// accounted for. Without this, the order in which code loads + /// could cause different assembly versions to be loaded. + /// </summary> + [Theory] + [InlineData(true)] + [InlineData(false)] + public void TransitiveAssembliesOfSharedTypesAreResolved(bool isLazyLoaded) + { + using var loader = PluginLoader.CreateFromAssemblyFile(TestResources.GetTestProjectAssembly("TransitivePlugin"), sharedTypes: new[] { typeof(SharedType) }, config => config.IsLazyLoaded = isLazyLoaded); + var assembly = loader.LoadDefaultAssembly(); + var configType = assembly.GetType("TransitivePlugin.PluginConfig", throwOnError: true)!; + var config = Activator.CreateInstance(configType); + var transitiveInstance = configType.GetMethod("GetTransitiveType")?.Invoke(config, null); + Assert.IsType<Test.Transitive.TransitiveSharedType>(transitiveInstance); + } + + /// <summary> + /// This is a carefully crafted example which tests + /// whether the library can be used outside of the default load context + /// (<see cref="AssemblyLoadContext.Default"/>). + /// + /// It works by loading a plugin (that gets loaded into another ALC) + /// which in turn loads its own plugins using the library. If said plugin + /// can successfully share its own types, the test should work. + /// </summary> + [Fact] + public void NonDefaultLoadContextsAreSupported() + { + /* The loaded plugin here will be in its own ALC. + * It will load its own plugins, which are not known to this ALC. + * Then this ALC will ask that ALC if it managed to successfully its own plugins. + */ + + using var loader = PluginLoader.CreateFromAssemblyFile(TestResources.GetTestProjectAssembly("WithOwnPlugins"), new[] { typeof(IWithOwnPlugins) }); + var assembly = loader.LoadDefaultAssembly(); + var configType = assembly.GetType("WithOwnPlugins.WithOwnPlugins", throwOnError: true)!; + var config = (IWithOwnPlugins?)Activator.CreateInstance(configType); + + /* + * Here, we have made sure that neither WithOwnPlugins or its own plugins have any way to be + * accidentally unified with the default (current for our tests) ALC. We did this by ensuring they are + * not loaded in the default ALC in the first place, hence the use of the `IWithOwnPlugins` interface. + * + * We are simulating a real use case scenario where the plugin host is 100% unaware of the + * plugin's own plugins. + * + * An important additional note: + * - Although the assembly of WithOurPlugins is not directly referenced thanks to the + * ReferenceOutputAssembly = false property, its contents will still be copied to the output. + * - This is problematic because the test runner seems to load all of the Assemblies present in the same + * directory as the test assembly, regardless of whether referenced or not. + * - Therefore we store the plugins of `WithOwnPlugins` are output in a `Plugins` directory. + * (see csproj of WithOwnPlugins, Link property) + * + * You can ensure that WithOwnPlugins or its plugins are not loaded by inspecting the following: + * AssemblyLoadContext.Default.Assemblies + * + * Even if it was loaded, there's an extra check on the other side to ensure no unification could happen. + * Nothing wrong with being extra careful ;). + */ + + var callingContext = AssemblyLoadContext.GetLoadContext(Assembly.GetExecutingAssembly()); + Assert.True(config?.TryLoadPluginsInCustomContext(callingContext)); + } + } +} diff --git a/third-party/DotNetCorePlugins/test/Plugins.Tests/TestProjectRefs.targets b/third-party/DotNetCorePlugins/test/Plugins.Tests/TestProjectRefs.targets new file mode 100644 index 0000000..17e1b82 --- /dev/null +++ b/third-party/DotNetCorePlugins/test/Plugins.Tests/TestProjectRefs.targets @@ -0,0 +1,50 @@ +<Project> + + <ItemDefinitionGroup> + <MultitargetTestProject> + <ReferenceOutputAssembly>false</ReferenceOutputAssembly> + <SkipGetTargetFrameworkProperties>true</SkipGetTargetFrameworkProperties> + <OutputItemType>_ResolvedTestProjectReference</OutputItemType> + </MultitargetTestProject> + <TestProject> + <ReferenceOutputAssembly>false</ReferenceOutputAssembly> + <SkipGetTargetFrameworkProperties>true</SkipGetTargetFrameworkProperties> + <OutputItemType>_ResolvedTestProjectReference</OutputItemType> + <UndefineProperties>TargetFramework;TargetFrameworks</UndefineProperties> + </TestProject> + <PublishedTestProject> + <ReferenceOutputAssembly>false</ReferenceOutputAssembly> + <SkipGetTargetFrameworkProperties>true</SkipGetTargetFrameworkProperties> + <OutputItemType>_ResolvedPublishedTestProjectReference</OutputItemType> + <UndefineProperties>TargetFramework;TargetFrameworks</UndefineProperties> + </PublishedTestProject> + </ItemDefinitionGroup> + + <ItemGroup> + <ProjectReference Include="@(TestProject);@(MultitargetTestProject);@(PublishedTestProject)" /> + </ItemGroup> + + <Target Name="GeneratePathToTestProjects" + BeforeTargets="CoreCompile;GetAssemblyAttributes" + DependsOnTargets="ResolveProjectReferences"> + <ItemGroup> + <AssemblyAttribute Include="McMaster.NETCore.Plugins.Tests.TestProjectReferenceAttribute"> + <_Parameter1>%(_ResolvedTestProjectReference.FileName)</_Parameter1> + <_Parameter2>%(_ResolvedTestProjectReference.RootDir)%(_ResolvedTestProjectReference.Directory)%(_ResolvedTestProjectReference.FileName).dll</_Parameter2> + </AssemblyAttribute> + </ItemGroup> + + <MSBuild Projects="@(PublishedTestProject)" + Targets="Publish" + Properties="NoBuild=true;PublishDir=$(TargetDir)%(PublishedTestProject.FileName)/" + RemoveProperties="TargetFramework;TargetFrameworks" /> + + <ItemGroup> + <AssemblyAttribute Include="McMaster.NETCore.Plugins.Tests.TestProjectReferenceAttribute"> + <_Parameter1>%(PublishedTestProject.FileName)</_Parameter1> + <_Parameter2>$(TargetDir)%(PublishedTestProject.FileName)/%(PublishedTestProject.FileName).dll</_Parameter2> + </AssemblyAttribute> + </ItemGroup> + </Target> + +</Project> diff --git a/third-party/DotNetCorePlugins/test/Plugins.Tests/Utilities/TestProjectReferenceAttribute.cs b/third-party/DotNetCorePlugins/test/Plugins.Tests/Utilities/TestProjectReferenceAttribute.cs new file mode 100644 index 0000000..4246596 --- /dev/null +++ b/third-party/DotNetCorePlugins/test/Plugins.Tests/Utilities/TestProjectReferenceAttribute.cs @@ -0,0 +1,20 @@ +// 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 McMaster.NETCore.Plugins.Tests +{ + [AttributeUsage(AttributeTargets.Assembly, AllowMultiple = true)] + public class TestProjectReferenceAttribute : Attribute + { + public TestProjectReferenceAttribute(string name, string path) + { + Name = name; + Path = path; + } + + public string Name { get; } + public string Path { get; } + } +} diff --git a/third-party/DotNetCorePlugins/test/Plugins.Tests/Utilities/TestResources.cs b/third-party/DotNetCorePlugins/test/Plugins.Tests/Utilities/TestResources.cs new file mode 100644 index 0000000..43f17d4 --- /dev/null +++ b/third-party/DotNetCorePlugins/test/Plugins.Tests/Utilities/TestResources.cs @@ -0,0 +1,20 @@ +// Copyright (c) Nate McMaster. +// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. + +using System.Linq; +using System.Reflection; + +namespace McMaster.NETCore.Plugins.Tests +{ + public class TestResources + { + public static string GetTestProjectAssembly(string name) + { + return typeof(TestResources) + .Assembly + .GetCustomAttributes<TestProjectReferenceAttribute>() + .First(a => a.Name == name) + .Path; + } + } +} diff --git a/third-party/DotNetCorePlugins/test/TestProjects/Banana/Banana.cs b/third-party/DotNetCorePlugins/test/TestProjects/Banana/Banana.cs new file mode 100644 index 0000000..3f670b7 --- /dev/null +++ b/third-party/DotNetCorePlugins/test/TestProjects/Banana/Banana.cs @@ -0,0 +1,12 @@ +// Copyright (c) Nate McMaster. +// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. + +using Test.Referenced.Library; + +namespace Test +{ + internal class Banana : IFruit + { + public string GetFlavor() => nameof(Banana); + } +} diff --git a/third-party/DotNetCorePlugins/test/TestProjects/Banana/Banana.csproj b/third-party/DotNetCorePlugins/test/TestProjects/Banana/Banana.csproj new file mode 100644 index 0000000..d6377b4 --- /dev/null +++ b/third-party/DotNetCorePlugins/test/TestProjects/Banana/Banana.csproj @@ -0,0 +1,11 @@ +<Project Sdk="Microsoft.NET.Sdk"> + + <ItemGroup> + <ProjectReference Include="..\ReferencedLibv1\ReferencedLibv1.csproj" /> + </ItemGroup> + + <PropertyGroup> + <TargetFramework>netcoreapp2.1</TargetFramework> + </PropertyGroup> + +</Project> diff --git a/third-party/DotNetCorePlugins/test/TestProjects/Directory.Build.props b/third-party/DotNetCorePlugins/test/TestProjects/Directory.Build.props new file mode 100644 index 0000000..e4594cb --- /dev/null +++ b/third-party/DotNetCorePlugins/test/TestProjects/Directory.Build.props @@ -0,0 +1,7 @@ +<Project> + <Import Project="..\..\Directory.Build.props" /> + + <PropertyGroup> + <CopyLocalLockFileAssemblies>true</CopyLocalLockFileAssemblies> + </PropertyGroup> +</Project> diff --git a/third-party/DotNetCorePlugins/test/TestProjects/DrawingApp/DrawingApp.csproj b/third-party/DotNetCorePlugins/test/TestProjects/DrawingApp/DrawingApp.csproj new file mode 100644 index 0000000..d5a260a --- /dev/null +++ b/third-party/DotNetCorePlugins/test/TestProjects/DrawingApp/DrawingApp.csproj @@ -0,0 +1,11 @@ +<Project Sdk="Microsoft.NET.Sdk"> + + <PropertyGroup> + <TargetFramework>netcoreapp2.1</TargetFramework> + </PropertyGroup> + + <ItemGroup> + <PackageReference Include="System.Drawing.Common" Version="5.0.1" /> + </ItemGroup> + +</Project> diff --git a/third-party/DotNetCorePlugins/test/TestProjects/DrawingApp/Finder.cs b/third-party/DotNetCorePlugins/test/TestProjects/DrawingApp/Finder.cs new file mode 100644 index 0000000..727f7ef --- /dev/null +++ b/third-party/DotNetCorePlugins/test/TestProjects/DrawingApp/Finder.cs @@ -0,0 +1,14 @@ +// Copyright (c) Nate McMaster. +// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. + +using System.Drawing.Printing; + +public class Finder +{ + public static string FindDrawingAssembly() + { + _ = new PrintDocument(); + return typeof(PrintDocument).Assembly.CodeBase; + } +} + diff --git a/third-party/DotNetCorePlugins/test/TestProjects/JsonNet10/Class1.cs b/third-party/DotNetCorePlugins/test/TestProjects/JsonNet10/Class1.cs new file mode 100644 index 0000000..a2133d3 --- /dev/null +++ b/third-party/DotNetCorePlugins/test/TestProjects/JsonNet10/Class1.cs @@ -0,0 +1,9 @@ +// Copyright (c) Nate McMaster. +// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. + +namespace JsonNet10 +{ + public class Class1 + { + } +} diff --git a/third-party/DotNetCorePlugins/test/TestProjects/JsonNet10/JsonNet10.csproj b/third-party/DotNetCorePlugins/test/TestProjects/JsonNet10/JsonNet10.csproj new file mode 100644 index 0000000..636432f --- /dev/null +++ b/third-party/DotNetCorePlugins/test/TestProjects/JsonNet10/JsonNet10.csproj @@ -0,0 +1,12 @@ +<Project Sdk="Microsoft.NET.Sdk"> + + <PropertyGroup> + <TargetFramework>netstandard2.0</TargetFramework> + </PropertyGroup> + + <ItemGroup> + <PackageReference Include="Newtonsoft.Json" Version="10.0.1" /> + <PrivateDependency Include="Newtonsoft.Json, Version=10.0.0.0" /> + </ItemGroup> + +</Project> diff --git a/third-party/DotNetCorePlugins/test/TestProjects/JsonNet11/Class1.cs b/third-party/DotNetCorePlugins/test/TestProjects/JsonNet11/Class1.cs new file mode 100644 index 0000000..889ca1f --- /dev/null +++ b/third-party/DotNetCorePlugins/test/TestProjects/JsonNet11/Class1.cs @@ -0,0 +1,9 @@ +// Copyright (c) Nate McMaster. +// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. + +namespace JsonNet11 +{ + public class Class1 + { + } +} diff --git a/third-party/DotNetCorePlugins/test/TestProjects/JsonNet11/JsonNet11.csproj b/third-party/DotNetCorePlugins/test/TestProjects/JsonNet11/JsonNet11.csproj new file mode 100644 index 0000000..a38d36d --- /dev/null +++ b/third-party/DotNetCorePlugins/test/TestProjects/JsonNet11/JsonNet11.csproj @@ -0,0 +1,13 @@ +<Project Sdk="Microsoft.NET.Sdk"> + + <PropertyGroup> + <TargetFramework>netstandard2.0</TargetFramework> + </PropertyGroup> + + <ItemGroup> + <PackageReference Include="Newtonsoft.Json" Version="11.0.2" /> + <PrivateDependency Include="Newtonsoft.Json, Version=11.0.0.0" /> + + </ItemGroup> + +</Project> diff --git a/third-party/DotNetCorePlugins/test/TestProjects/JsonNet9/Class1.cs b/third-party/DotNetCorePlugins/test/TestProjects/JsonNet9/Class1.cs new file mode 100644 index 0000000..345849f --- /dev/null +++ b/third-party/DotNetCorePlugins/test/TestProjects/JsonNet9/Class1.cs @@ -0,0 +1,9 @@ +// Copyright (c) Nate McMaster. +// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. + +namespace JsonNet9 +{ + public class Class1 + { + } +} diff --git a/third-party/DotNetCorePlugins/test/TestProjects/JsonNet9/JsonNet9.csproj b/third-party/DotNetCorePlugins/test/TestProjects/JsonNet9/JsonNet9.csproj new file mode 100644 index 0000000..8ac8da1 --- /dev/null +++ b/third-party/DotNetCorePlugins/test/TestProjects/JsonNet9/JsonNet9.csproj @@ -0,0 +1,12 @@ +<Project Sdk="Microsoft.NET.Sdk"> + + <PropertyGroup> + <TargetFramework>netstandard2.0</TargetFramework> + </PropertyGroup> + + <ItemGroup> + <PackageReference Include="Newtonsoft.Json" Version="9.0.1" /> + <PrivateDependency Include="Newtonsoft.Json, Version=9.0.0.0" /> + </ItemGroup> + +</Project> diff --git a/third-party/DotNetCorePlugins/test/TestProjects/NativeDependency/NativeDependency.csproj b/third-party/DotNetCorePlugins/test/TestProjects/NativeDependency/NativeDependency.csproj new file mode 100644 index 0000000..d9867d8 --- /dev/null +++ b/third-party/DotNetCorePlugins/test/TestProjects/NativeDependency/NativeDependency.csproj @@ -0,0 +1,11 @@ +<Project Sdk="Microsoft.NET.Sdk"> + + <PropertyGroup> + <TargetFramework>net5.0</TargetFramework> + </PropertyGroup> + + <ItemGroup> + <PackageReference Include="System.Data.SQLite" Version="1.0.114.3" /> + </ItemGroup> + +</Project> diff --git a/third-party/DotNetCorePlugins/test/TestProjects/NativeDependency/NativeDependencyLoader.cs b/third-party/DotNetCorePlugins/test/TestProjects/NativeDependency/NativeDependencyLoader.cs new file mode 100644 index 0000000..5473bb1 --- /dev/null +++ b/third-party/DotNetCorePlugins/test/TestProjects/NativeDependency/NativeDependencyLoader.cs @@ -0,0 +1,40 @@ +// 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.Data.SQLite; +using System.IO; + +namespace NativeDependency +{ + public static class NativeDependencyLoader + { + public static void Load() + { + using var tempFile = new TempFile("db.sqlite"); + using var dbConnection = new SQLiteConnection($"Data Source={tempFile.FilePath}"); + + dbConnection.Open(); + } + } + + public class TempFile : IDisposable + { + public TempFile(string fileName) + { + FilePath = Path.Combine(Path.GetTempPath(), fileName); + } + + public string FilePath { get; } + + public void Dispose() + { + if (!File.Exists(FilePath)) + { + return; + } + + File.Delete(FilePath); + } + } +} diff --git a/third-party/DotNetCorePlugins/test/TestProjects/NetCoreApp2App/NetCoreApp2App.csproj b/third-party/DotNetCorePlugins/test/TestProjects/NetCoreApp2App/NetCoreApp2App.csproj new file mode 100644 index 0000000..0403b15 --- /dev/null +++ b/third-party/DotNetCorePlugins/test/TestProjects/NetCoreApp2App/NetCoreApp2App.csproj @@ -0,0 +1,12 @@ +<Project Sdk="Microsoft.NET.Sdk"> + + <PropertyGroup> + <OutputType>Exe</OutputType> + <TargetFramework>netcoreapp2.1</TargetFramework> + </PropertyGroup> + + <ItemGroup> + <ProjectReference Include="..\ReferencedLibv2\ReferencedLibv2.csproj" /> + </ItemGroup> + +</Project> diff --git a/third-party/DotNetCorePlugins/test/TestProjects/NetCoreApp2App/Program.cs b/third-party/DotNetCorePlugins/test/TestProjects/NetCoreApp2App/Program.cs new file mode 100644 index 0000000..c818479 --- /dev/null +++ b/third-party/DotNetCorePlugins/test/TestProjects/NetCoreApp2App/Program.cs @@ -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!"; + } +} diff --git a/third-party/DotNetCorePlugins/test/TestProjects/NetStandardClassLib/Class1.cs b/third-party/DotNetCorePlugins/test/TestProjects/NetStandardClassLib/Class1.cs new file mode 100644 index 0000000..24bd016 --- /dev/null +++ b/third-party/DotNetCorePlugins/test/TestProjects/NetStandardClassLib/Class1.cs @@ -0,0 +1,10 @@ +// Copyright (c) Nate McMaster. +// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. + +namespace NetStandardClassLib +{ + public class Class1 + { + public string GetColor() => "Red"; + } +} diff --git a/third-party/DotNetCorePlugins/test/TestProjects/NetStandardClassLib/NetStandardClassLib.csproj b/third-party/DotNetCorePlugins/test/TestProjects/NetStandardClassLib/NetStandardClassLib.csproj new file mode 100644 index 0000000..9f5c4f4 --- /dev/null +++ b/third-party/DotNetCorePlugins/test/TestProjects/NetStandardClassLib/NetStandardClassLib.csproj @@ -0,0 +1,7 @@ +<Project Sdk="Microsoft.NET.Sdk"> + + <PropertyGroup> + <TargetFramework>netstandard2.0</TargetFramework> + </PropertyGroup> + +</Project> diff --git a/third-party/DotNetCorePlugins/test/TestProjects/Plátano/Plátano.cs b/third-party/DotNetCorePlugins/test/TestProjects/Plátano/Plátano.cs new file mode 100644 index 0000000..c655f44 --- /dev/null +++ b/third-party/DotNetCorePlugins/test/TestProjects/Plátano/Plátano.cs @@ -0,0 +1,13 @@ +// Copyright (c) Nate McMaster. +// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. + +using Plátano; +using Test.Referenced.Library; + +namespace Test +{ + internal class Plátano : IFruit + { + public string GetFlavor() => Strings.Flavor; + } +} diff --git a/third-party/DotNetCorePlugins/test/TestProjects/Plátano/Plátano.csproj b/third-party/DotNetCorePlugins/test/TestProjects/Plátano/Plátano.csproj new file mode 100644 index 0000000..d6377b4 --- /dev/null +++ b/third-party/DotNetCorePlugins/test/TestProjects/Plátano/Plátano.csproj @@ -0,0 +1,11 @@ +<Project Sdk="Microsoft.NET.Sdk"> + + <ItemGroup> + <ProjectReference Include="..\ReferencedLibv1\ReferencedLibv1.csproj" /> + </ItemGroup> + + <PropertyGroup> + <TargetFramework>netcoreapp2.1</TargetFramework> + </PropertyGroup> + +</Project> diff --git a/third-party/DotNetCorePlugins/test/TestProjects/Plátano/Strings.Designer.cs b/third-party/DotNetCorePlugins/test/TestProjects/Plátano/Strings.Designer.cs new file mode 100644 index 0000000..460c16b --- /dev/null +++ b/third-party/DotNetCorePlugins/test/TestProjects/Plátano/Strings.Designer.cs @@ -0,0 +1,55 @@ +//------------------------------------------------------------------------------ +// <auto-generated> +// This code was generated by a tool. +// Runtime Version:4.0.30319.42000 +// +// Changes to this file may cause incorrect behavior and will be lost if +// the code is regenerated. +// </auto-generated> +//------------------------------------------------------------------------------ + +namespace Plátano { + using System; + + + [System.CodeDom.Compiler.GeneratedCodeAttribute("System.Resources.Tools.StronglyTypedResourceBuilder", "4.0.0.0")] + [System.Diagnostics.DebuggerNonUserCodeAttribute()] + [System.Runtime.CompilerServices.CompilerGeneratedAttribute()] + public class Strings { + + private static System.Resources.ResourceManager resourceMan; + + private static System.Globalization.CultureInfo resourceCulture; + + [System.Diagnostics.CodeAnalysis.SuppressMessageAttribute("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")] + internal Strings() { + } + + [System.ComponentModel.EditorBrowsableAttribute(System.ComponentModel.EditorBrowsableState.Advanced)] + public static System.Resources.ResourceManager ResourceManager { + get { + if (object.Equals(null, resourceMan)) { + System.Resources.ResourceManager temp = new System.Resources.ResourceManager("Plátano.Strings", typeof(Strings).Assembly); + resourceMan = temp; + } + return resourceMan; + } + } + + [System.ComponentModel.EditorBrowsableAttribute(System.ComponentModel.EditorBrowsableState.Advanced)] + public static System.Globalization.CultureInfo Culture { + get { + return resourceCulture; + } + set { + resourceCulture = value; + } + } + + public static string Flavor { + get { + return ResourceManager.GetString("Flavor", resourceCulture); + } + } + } +} diff --git a/third-party/DotNetCorePlugins/test/TestProjects/Plátano/Strings.es.Designer.cs b/third-party/DotNetCorePlugins/test/TestProjects/Plátano/Strings.es.Designer.cs new file mode 100644 index 0000000..8b13789 --- /dev/null +++ b/third-party/DotNetCorePlugins/test/TestProjects/Plátano/Strings.es.Designer.cs @@ -0,0 +1 @@ + diff --git a/third-party/DotNetCorePlugins/test/TestProjects/Plátano/Strings.es.resx b/third-party/DotNetCorePlugins/test/TestProjects/Plátano/Strings.es.resx new file mode 100644 index 0000000..532a76d --- /dev/null +++ b/third-party/DotNetCorePlugins/test/TestProjects/Plátano/Strings.es.resx @@ -0,0 +1,24 @@ +<?xml version="1.0" encoding="utf-8"?> + +<root> + <xsd:schema id="root" xmlns="" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:msdata="urn:schemas-microsoft-com:xml-msdata"> + <xsd:element name="root" msdata:IsDataSet="true"> + + </xsd:element> + </xsd:schema> + <resheader name="resmimetype"> + <value>text/microsoft-resx</value> + </resheader> + <resheader name="version"> + <value>1.3</value> + </resheader> + <resheader name="reader"> + <value>System.Resources.ResXResourceReader, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value> + </resheader> + <resheader name="writer"> + <value>System.Resources.ResXResourceWriter, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value> + </resheader> + <data name="Flavor"> + <value>Plátano</value> + </data> +</root> diff --git a/third-party/DotNetCorePlugins/test/TestProjects/Plátano/Strings.resx b/third-party/DotNetCorePlugins/test/TestProjects/Plátano/Strings.resx new file mode 100644 index 0000000..1ee8873 --- /dev/null +++ b/third-party/DotNetCorePlugins/test/TestProjects/Plátano/Strings.resx @@ -0,0 +1,24 @@ +<?xml version="1.0" encoding="utf-8"?> + +<root> + <xsd:schema id="root" xmlns="" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:msdata="urn:schemas-microsoft-com:xml-msdata"> + <xsd:element name="root" msdata:IsDataSet="true"> + + </xsd:element> + </xsd:schema> + <resheader name="resmimetype"> + <value>text/microsoft-resx</value> + </resheader> + <resheader name="version"> + <value>1.3</value> + </resheader> + <resheader name="reader"> + <value>System.Resources.ResXResourceReader, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value> + </resheader> + <resheader name="writer"> + <value>System.Resources.ResXResourceWriter, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value> + </resheader> + <data name="Flavor"> + <value>Banana</value> + </data> +</root> diff --git a/third-party/DotNetCorePlugins/test/TestProjects/PowerShellPlugin/PowerShellPlugin.csproj b/third-party/DotNetCorePlugins/test/TestProjects/PowerShellPlugin/PowerShellPlugin.csproj new file mode 100644 index 0000000..80924db --- /dev/null +++ b/third-party/DotNetCorePlugins/test/TestProjects/PowerShellPlugin/PowerShellPlugin.csproj @@ -0,0 +1,12 @@ +<Project Sdk="Microsoft.NET.Sdk"> + + <PropertyGroup> + <OutputType>Exe</OutputType> + <TargetFramework>netcoreapp2.1</TargetFramework> + </PropertyGroup> + + <ItemGroup> + <PackageReference Include="Microsoft.PowerShell.SDK" Version="6.0.4" /> + </ItemGroup> + +</Project> diff --git a/third-party/DotNetCorePlugins/test/TestProjects/PowerShellPlugin/Program.cs b/third-party/DotNetCorePlugins/test/TestProjects/PowerShellPlugin/Program.cs new file mode 100644 index 0000000..eec7c42 --- /dev/null +++ b/third-party/DotNetCorePlugins/test/TestProjects/PowerShellPlugin/Program.cs @@ -0,0 +1,25 @@ +// 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.Management.Automation; + +namespace PowerShellPlugin +{ + internal class Program + { + public static void Main(string[] args) + { + Console.WriteLine(GetGreeting()); + } + + public static string GetGreeting() + { + using var ps = PowerShell.Create(); + var type = typeof(AliasAttribute); + // Console.WriteLine(type.Assembly.Location); + var results = ps.AddScript("Write-Output hello").Invoke(); + return results[0].ToString(); + } + } +} diff --git a/third-party/DotNetCorePlugins/test/TestProjects/ReferencedLibv1/Class1.cs b/third-party/DotNetCorePlugins/test/TestProjects/ReferencedLibv1/Class1.cs new file mode 100644 index 0000000..3ad31b6 --- /dev/null +++ b/third-party/DotNetCorePlugins/test/TestProjects/ReferencedLibv1/Class1.cs @@ -0,0 +1,10 @@ +// Copyright (c) Nate McMaster. +// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. + +namespace Test.Referenced.Library +{ + public class Class1 + { + public static string GetVersion() => "v1"; + } +} diff --git a/third-party/DotNetCorePlugins/test/TestProjects/ReferencedLibv1/IFruit.cs b/third-party/DotNetCorePlugins/test/TestProjects/ReferencedLibv1/IFruit.cs new file mode 100644 index 0000000..5aee614 --- /dev/null +++ b/third-party/DotNetCorePlugins/test/TestProjects/ReferencedLibv1/IFruit.cs @@ -0,0 +1,10 @@ +// Copyright (c) Nate McMaster. +// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. + +namespace Test.Referenced.Library +{ + public interface IFruit + { + string GetFlavor(); + } +} diff --git a/third-party/DotNetCorePlugins/test/TestProjects/ReferencedLibv1/ReferencedLibv1.csproj b/third-party/DotNetCorePlugins/test/TestProjects/ReferencedLibv1/ReferencedLibv1.csproj new file mode 100644 index 0000000..e6fb2b2 --- /dev/null +++ b/third-party/DotNetCorePlugins/test/TestProjects/ReferencedLibv1/ReferencedLibv1.csproj @@ -0,0 +1,9 @@ +<Project Sdk="Microsoft.NET.Sdk"> + + <PropertyGroup> + <TargetFramework>netstandard2.0</TargetFramework> + <AssemblyName>Test.Referenced.Library</AssemblyName> + <AssemblyVersion>1.0.0.0</AssemblyVersion> + </PropertyGroup> + +</Project> diff --git a/third-party/DotNetCorePlugins/test/TestProjects/ReferencedLibv2/Class1.cs b/third-party/DotNetCorePlugins/test/TestProjects/ReferencedLibv2/Class1.cs new file mode 100644 index 0000000..af12c3e --- /dev/null +++ b/third-party/DotNetCorePlugins/test/TestProjects/ReferencedLibv2/Class1.cs @@ -0,0 +1,10 @@ +// Copyright (c) Nate McMaster. +// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. + +namespace Test.Referenced.Library +{ + public class Class1 + { + public static string GetVersion() => "v2"; + } +} diff --git a/third-party/DotNetCorePlugins/test/TestProjects/ReferencedLibv2/ReferencedLibv2.csproj b/third-party/DotNetCorePlugins/test/TestProjects/ReferencedLibv2/ReferencedLibv2.csproj new file mode 100644 index 0000000..5622b28 --- /dev/null +++ b/third-party/DotNetCorePlugins/test/TestProjects/ReferencedLibv2/ReferencedLibv2.csproj @@ -0,0 +1,13 @@ +<Project Sdk="Microsoft.NET.Sdk"> + + <PropertyGroup> + <TargetFramework>netstandard2.0</TargetFramework> + <AssemblyName>Test.Referenced.Library</AssemblyName> + <AssemblyVersion>2.0.0.0</AssemblyVersion> + </PropertyGroup> + + <ItemGroup> + <Compile Include="..\ReferencedLibv1\IFruit.cs" /> + </ItemGroup> + +</Project> diff --git a/third-party/DotNetCorePlugins/test/TestProjects/SharedAbstraction.v1/SharedAbstraction.v1.csproj b/third-party/DotNetCorePlugins/test/TestProjects/SharedAbstraction.v1/SharedAbstraction.v1.csproj new file mode 100644 index 0000000..1b9b58e --- /dev/null +++ b/third-party/DotNetCorePlugins/test/TestProjects/SharedAbstraction.v1/SharedAbstraction.v1.csproj @@ -0,0 +1,13 @@ +<Project Sdk="Microsoft.NET.Sdk"> + + <PropertyGroup> + <TargetFramework>netstandard2.0</TargetFramework> + <AssemblyName>Test.Shared.Abstraction</AssemblyName> + <AssemblyVersion>1.0.0.0</AssemblyVersion> + </PropertyGroup> + + <ItemGroup> + <ProjectReference Include="..\TransitiveDep.v1\TransitiveDep.v1.csproj" /> + </ItemGroup> + +</Project> diff --git a/third-party/DotNetCorePlugins/test/TestProjects/SharedAbstraction.v1/SharedType.cs b/third-party/DotNetCorePlugins/test/TestProjects/SharedAbstraction.v1/SharedType.cs new file mode 100644 index 0000000..869345d --- /dev/null +++ b/third-party/DotNetCorePlugins/test/TestProjects/SharedAbstraction.v1/SharedType.cs @@ -0,0 +1,13 @@ +// 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 Test.Transitive; + +namespace Test.Shared.Abstraction +{ + public class SharedType + { + public Type GetTransitive() => typeof(TransitiveSharedType); + } +} diff --git a/third-party/DotNetCorePlugins/test/TestProjects/SharedAbstraction.v2/SharedAbstraction.v2.csproj b/third-party/DotNetCorePlugins/test/TestProjects/SharedAbstraction.v2/SharedAbstraction.v2.csproj new file mode 100644 index 0000000..1eddcc9 --- /dev/null +++ b/third-party/DotNetCorePlugins/test/TestProjects/SharedAbstraction.v2/SharedAbstraction.v2.csproj @@ -0,0 +1,14 @@ +<Project Sdk="Microsoft.NET.Sdk"> + + <PropertyGroup> + <TargetFramework>netstandard2.0</TargetFramework> + <AssemblyName>Test.Shared.Abstraction</AssemblyName> + <AssemblyVersion>2.0.0.0</AssemblyVersion> + </PropertyGroup> + + <ItemGroup> + <Compile Include="..\SharedAbstraction.v1\SharedType.cs" /> + <ProjectReference Include="..\TransitiveDep.v2\TransitiveDep.v2.csproj" /> + </ItemGroup> + +</Project> diff --git a/third-party/DotNetCorePlugins/test/TestProjects/SqlClientApp/Program.cs b/third-party/DotNetCorePlugins/test/TestProjects/SqlClientApp/Program.cs new file mode 100644 index 0000000..79fc076 --- /dev/null +++ b/third-party/DotNetCorePlugins/test/TestProjects/SqlClientApp/Program.cs @@ -0,0 +1,31 @@ +// Copyright (c) Nate McMaster. +// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. + +using System.Data.SqlClient; + +namespace SqlClientApp +{ + public class Program + { + // required to make the C# compiler happy + public static void Main(string[] args) + { + } + + public static bool Run() + { + try + { + using var client = new SqlConnection(@"Data Source=(localdb)\mssqllocaldb;Integrated Security=True"); + client.Open(); + return !string.IsNullOrEmpty(client.ServerVersion); + } + catch (SqlException ex) when (ex.Number == -2) // -2 means SQL timeout + { + // When running the test in Azure DevOps build pipeline, we'll get a SqlException with "Connection Timeout Expired". + // We can ignore this safely in unit tests. + return true; + } + } + } +} diff --git a/third-party/DotNetCorePlugins/test/TestProjects/SqlClientApp/SqlClientApp.csproj b/third-party/DotNetCorePlugins/test/TestProjects/SqlClientApp/SqlClientApp.csproj new file mode 100644 index 0000000..c8a711c --- /dev/null +++ b/third-party/DotNetCorePlugins/test/TestProjects/SqlClientApp/SqlClientApp.csproj @@ -0,0 +1,12 @@ +<Project Sdk="Microsoft.NET.Sdk"> + + <PropertyGroup> + <TargetFramework>netcoreapp2.1</TargetFramework> + <OutputType>Exe</OutputType> + </PropertyGroup> + + <ItemGroup> + <PackageReference Include="System.Data.SqlClient" Version="4.6.0" /> + </ItemGroup> + +</Project> diff --git a/third-party/DotNetCorePlugins/test/TestProjects/Strawberry/Strawberry.cs b/third-party/DotNetCorePlugins/test/TestProjects/Strawberry/Strawberry.cs new file mode 100644 index 0000000..47a3c87 --- /dev/null +++ b/third-party/DotNetCorePlugins/test/TestProjects/Strawberry/Strawberry.cs @@ -0,0 +1,12 @@ +// Copyright (c) Nate McMaster. +// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. + +using Test.Referenced.Library; + +namespace Test +{ + internal class Strawberry : IFruit + { + public string GetFlavor() => nameof(Strawberry); + } +} diff --git a/third-party/DotNetCorePlugins/test/TestProjects/Strawberry/Strawberry.csproj b/third-party/DotNetCorePlugins/test/TestProjects/Strawberry/Strawberry.csproj new file mode 100644 index 0000000..cbbb6d6 --- /dev/null +++ b/third-party/DotNetCorePlugins/test/TestProjects/Strawberry/Strawberry.csproj @@ -0,0 +1,11 @@ +<Project Sdk="Microsoft.NET.Sdk"> + + <ItemGroup> + <ProjectReference Include="..\ReferencedLibv1\ReferencedLibv1.csproj" /> + </ItemGroup> + + <PropertyGroup> + <TargetFramework>netstandard2.0</TargetFramework> + </PropertyGroup> + +</Project> diff --git a/third-party/DotNetCorePlugins/test/TestProjects/TransitiveDep.v1/TransitiveDep.v1.csproj b/third-party/DotNetCorePlugins/test/TestProjects/TransitiveDep.v1/TransitiveDep.v1.csproj new file mode 100644 index 0000000..a133a0c --- /dev/null +++ b/third-party/DotNetCorePlugins/test/TestProjects/TransitiveDep.v1/TransitiveDep.v1.csproj @@ -0,0 +1,9 @@ +<Project Sdk="Microsoft.NET.Sdk"> + + <PropertyGroup> + <TargetFramework>netstandard2.0</TargetFramework> + <AssemblyName>Test.Transitive</AssemblyName> + <AssemblyVersion>1.0.0.0</AssemblyVersion> + </PropertyGroup> + +</Project> diff --git a/third-party/DotNetCorePlugins/test/TestProjects/TransitiveDep.v1/TransitiveSharedType.cs b/third-party/DotNetCorePlugins/test/TestProjects/TransitiveDep.v1/TransitiveSharedType.cs new file mode 100644 index 0000000..5f4ca47 --- /dev/null +++ b/third-party/DotNetCorePlugins/test/TestProjects/TransitiveDep.v1/TransitiveSharedType.cs @@ -0,0 +1,7 @@ +// Copyright (c) Nate McMaster. +// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. + +namespace Test.Transitive +{ + public class TransitiveSharedType { } +} diff --git a/third-party/DotNetCorePlugins/test/TestProjects/TransitiveDep.v2/TransitiveDep.v2.csproj b/third-party/DotNetCorePlugins/test/TestProjects/TransitiveDep.v2/TransitiveDep.v2.csproj new file mode 100644 index 0000000..ff98f18 --- /dev/null +++ b/third-party/DotNetCorePlugins/test/TestProjects/TransitiveDep.v2/TransitiveDep.v2.csproj @@ -0,0 +1,13 @@ +<Project Sdk="Microsoft.NET.Sdk"> + + <PropertyGroup> + <TargetFramework>netstandard2.0</TargetFramework> + <AssemblyName>Test.Transitive</AssemblyName> + <AssemblyVersion>2.0.0.0</AssemblyVersion> + </PropertyGroup> + + <ItemGroup> + <Compile Include="..\TransitiveDep.v1\*.cs" /> + </ItemGroup> + +</Project> diff --git a/third-party/DotNetCorePlugins/test/TestProjects/TransitivePlugin/PluginConfig.cs b/third-party/DotNetCorePlugins/test/TestProjects/TransitivePlugin/PluginConfig.cs new file mode 100644 index 0000000..7e4b420 --- /dev/null +++ b/third-party/DotNetCorePlugins/test/TestProjects/TransitivePlugin/PluginConfig.cs @@ -0,0 +1,12 @@ +// Copyright (c) Nate McMaster. +// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. + +using Test.Transitive; + +namespace TransitivePlugin +{ + public class PluginConfig + { + public TransitiveSharedType GetTransitiveType() => new(); + } +} diff --git a/third-party/DotNetCorePlugins/test/TestProjects/TransitivePlugin/TransitivePlugin.csproj b/third-party/DotNetCorePlugins/test/TestProjects/TransitivePlugin/TransitivePlugin.csproj new file mode 100644 index 0000000..4a917c2 --- /dev/null +++ b/third-party/DotNetCorePlugins/test/TestProjects/TransitivePlugin/TransitivePlugin.csproj @@ -0,0 +1,11 @@ +<Project Sdk="Microsoft.NET.Sdk"> + + <PropertyGroup> + <TargetFramework>netstandard2.0</TargetFramework> + </PropertyGroup> + + <ItemGroup> + <ProjectReference Include="..\SharedAbstraction.v1\SharedAbstraction.v1.csproj" /> + </ItemGroup> + +</Project> diff --git a/third-party/DotNetCorePlugins/test/TestProjects/WithOurPluginsPluginA/Class1.cs b/third-party/DotNetCorePlugins/test/TestProjects/WithOurPluginsPluginA/Class1.cs new file mode 100644 index 0000000..cf15f88 --- /dev/null +++ b/third-party/DotNetCorePlugins/test/TestProjects/WithOurPluginsPluginA/Class1.cs @@ -0,0 +1,12 @@ +// Copyright (c) Nate McMaster. +// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. + +using WithOurPluginsPluginContract; + +namespace WithOurPluginsPluginA +{ + public class Class1 : ISayHello + { + public string SayHello() => $"Hello from {nameof(WithOurPluginsPluginA)}"; + } +} diff --git a/third-party/DotNetCorePlugins/test/TestProjects/WithOurPluginsPluginA/WithOurPluginsPluginA.csproj b/third-party/DotNetCorePlugins/test/TestProjects/WithOurPluginsPluginA/WithOurPluginsPluginA.csproj new file mode 100644 index 0000000..d20507a --- /dev/null +++ b/third-party/DotNetCorePlugins/test/TestProjects/WithOurPluginsPluginA/WithOurPluginsPluginA.csproj @@ -0,0 +1,12 @@ +<Project Sdk="Microsoft.NET.Sdk"> + + <PropertyGroup> + <TargetFramework>netstandard2.0</TargetFramework> + <AppendTargetFrameworkToOutputPath>false</AppendTargetFrameworkToOutputPath> + </PropertyGroup> + + <ItemGroup> + <ProjectReference Include="..\WithOurPluginsPluginContract\WithOurPluginsPluginContract.csproj" /> + </ItemGroup> + +</Project> diff --git a/third-party/DotNetCorePlugins/test/TestProjects/WithOurPluginsPluginB/Class1.cs b/third-party/DotNetCorePlugins/test/TestProjects/WithOurPluginsPluginB/Class1.cs new file mode 100644 index 0000000..837f0e7 --- /dev/null +++ b/third-party/DotNetCorePlugins/test/TestProjects/WithOurPluginsPluginB/Class1.cs @@ -0,0 +1,12 @@ +// Copyright (c) Nate McMaster. +// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. + +using WithOurPluginsPluginContract; + +namespace WithOurPluginsPluginB +{ + public class Class1 : ISayHello + { + public string SayHello() => $"Hello from {nameof(WithOurPluginsPluginB)}"; + } +} diff --git a/third-party/DotNetCorePlugins/test/TestProjects/WithOurPluginsPluginB/WithOurPluginsPluginB.csproj b/third-party/DotNetCorePlugins/test/TestProjects/WithOurPluginsPluginB/WithOurPluginsPluginB.csproj new file mode 100644 index 0000000..d20507a --- /dev/null +++ b/third-party/DotNetCorePlugins/test/TestProjects/WithOurPluginsPluginB/WithOurPluginsPluginB.csproj @@ -0,0 +1,12 @@ +<Project Sdk="Microsoft.NET.Sdk"> + + <PropertyGroup> + <TargetFramework>netstandard2.0</TargetFramework> + <AppendTargetFrameworkToOutputPath>false</AppendTargetFrameworkToOutputPath> + </PropertyGroup> + + <ItemGroup> + <ProjectReference Include="..\WithOurPluginsPluginContract\WithOurPluginsPluginContract.csproj" /> + </ItemGroup> + +</Project> diff --git a/third-party/DotNetCorePlugins/test/TestProjects/WithOurPluginsPluginContract/ISayHello.cs b/third-party/DotNetCorePlugins/test/TestProjects/WithOurPluginsPluginContract/ISayHello.cs new file mode 100644 index 0000000..cc52587 --- /dev/null +++ b/third-party/DotNetCorePlugins/test/TestProjects/WithOurPluginsPluginContract/ISayHello.cs @@ -0,0 +1,10 @@ +// Copyright (c) Nate McMaster. +// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. + +namespace WithOurPluginsPluginContract +{ + public interface ISayHello + { + string SayHello(); + } +} diff --git a/third-party/DotNetCorePlugins/test/TestProjects/WithOurPluginsPluginContract/WithOurPluginsPluginContract.csproj b/third-party/DotNetCorePlugins/test/TestProjects/WithOurPluginsPluginContract/WithOurPluginsPluginContract.csproj new file mode 100644 index 0000000..9f5c4f4 --- /dev/null +++ b/third-party/DotNetCorePlugins/test/TestProjects/WithOurPluginsPluginContract/WithOurPluginsPluginContract.csproj @@ -0,0 +1,7 @@ +<Project Sdk="Microsoft.NET.Sdk"> + + <PropertyGroup> + <TargetFramework>netstandard2.0</TargetFramework> + </PropertyGroup> + +</Project> diff --git a/third-party/DotNetCorePlugins/test/TestProjects/WithOwnPlugins/WithOwnPlugins.cs b/third-party/DotNetCorePlugins/test/TestProjects/WithOwnPlugins/WithOwnPlugins.cs new file mode 100644 index 0000000..47cff6f --- /dev/null +++ b/third-party/DotNetCorePlugins/test/TestProjects/WithOwnPlugins/WithOwnPlugins.cs @@ -0,0 +1,72 @@ +// 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 !NETCOREAPP2_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; + } + } +} diff --git a/third-party/DotNetCorePlugins/test/TestProjects/WithOwnPlugins/WithOwnPlugins.csproj b/third-party/DotNetCorePlugins/test/TestProjects/WithOwnPlugins/WithOwnPlugins.csproj new file mode 100644 index 0000000..4218eda --- /dev/null +++ b/third-party/DotNetCorePlugins/test/TestProjects/WithOwnPlugins/WithOwnPlugins.csproj @@ -0,0 +1,15 @@ +<Project Sdk="Microsoft.NET.Sdk"> + + <PropertyGroup> + <TargetFrameworks>net5.0;netcoreapp3.1;netcoreapp2.1</TargetFrameworks> + </PropertyGroup> + + <ItemGroup> + <ProjectReference Include="..\..\..\src\Plugins\McMaster.NETCore.Plugins.csproj" /> + <ProjectReference Include="..\WithOurPluginsPluginA\WithOurPluginsPluginA.csproj" PrivateAssets="All" ReferenceOutputAssembly="false" OutputItemType="Content" CopyToOutputDirectory="Always" Link="Plugins/%(RecursiveDir)%(Filename).dll" /> + <ProjectReference Include="..\WithOurPluginsPluginB\WithOurPluginsPluginB.csproj" PrivateAssets="All" ReferenceOutputAssembly="false" OutputItemType="Content" CopyToOutputDirectory="Always" Link="Plugins/%(RecursiveDir)%(Filename).dll" /> + <ProjectReference Include="..\WithOurPluginsPluginContract\WithOurPluginsPluginContract.csproj" /> + <ProjectReference Include="..\WithOwnPluginsContract\WithOwnPluginsContract.csproj" /> + </ItemGroup> + +</Project> diff --git a/third-party/DotNetCorePlugins/test/TestProjects/WithOwnPluginsContract/IWithOwnPlugins.cs b/third-party/DotNetCorePlugins/test/TestProjects/WithOwnPluginsContract/IWithOwnPlugins.cs new file mode 100644 index 0000000..ae7563f --- /dev/null +++ b/third-party/DotNetCorePlugins/test/TestProjects/WithOwnPluginsContract/IWithOwnPlugins.cs @@ -0,0 +1,12 @@ +// Copyright (c) Nate McMaster. +// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. + +using System.Runtime.Loader; + +namespace WithOwnPluginsContract +{ + public interface IWithOwnPlugins + { + bool TryLoadPluginsInCustomContext(AssemblyLoadContext? callingContext); + } +} diff --git a/third-party/DotNetCorePlugins/test/TestProjects/WithOwnPluginsContract/WithOwnPluginsContract.csproj b/third-party/DotNetCorePlugins/test/TestProjects/WithOwnPluginsContract/WithOwnPluginsContract.csproj new file mode 100644 index 0000000..65d6641 --- /dev/null +++ b/third-party/DotNetCorePlugins/test/TestProjects/WithOwnPluginsContract/WithOwnPluginsContract.csproj @@ -0,0 +1,7 @@ +<Project Sdk="Microsoft.NET.Sdk"> + + <PropertyGroup> + <TargetFrameworks>netcoreapp3.1;netcoreapp2.1</TargetFrameworks> + </PropertyGroup> + +</Project> diff --git a/third-party/DotNetCorePlugins/test/TestProjects/XunitSample/Class1.cs b/third-party/DotNetCorePlugins/test/TestProjects/XunitSample/Class1.cs new file mode 100644 index 0000000..b124389 --- /dev/null +++ b/third-party/DotNetCorePlugins/test/TestProjects/XunitSample/Class1.cs @@ -0,0 +1,9 @@ +// Copyright (c) Nate McMaster. +// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. + +namespace XunitSample +{ + public class Class1 + { + } +} diff --git a/third-party/DotNetCorePlugins/test/TestProjects/XunitSample/XunitSample.csproj b/third-party/DotNetCorePlugins/test/TestProjects/XunitSample/XunitSample.csproj new file mode 100644 index 0000000..4620f3d --- /dev/null +++ b/third-party/DotNetCorePlugins/test/TestProjects/XunitSample/XunitSample.csproj @@ -0,0 +1,12 @@ +<Project Sdk="Microsoft.NET.Sdk"> + + <PropertyGroup> + <TargetFramework>netstandard2.0</TargetFramework> + <CopyLocalLockFileAssemblies>true</CopyLocalLockFileAssemblies> + </PropertyGroup> + + <ItemGroup> + <PackageReference Include="xunit.extensibility.execution" Version="2.2.0" /> + </ItemGroup> + +</Project> |