aboutsummaryrefslogtreecommitdiff
path: root/third-party/DotNetCorePlugins/test
diff options
context:
space:
mode:
authorLibravatar vnugent <public@vaughnnugent.com>2024-02-14 14:10:27 -0500
committerLibravatar vnugent <public@vaughnnugent.com>2024-02-14 14:10:27 -0500
commit2b1314c1475e7e1831c691cf349cb89c66fa320c (patch)
tree091fc132a2bee2e79a68d8c6d5eb20f1d989a3d2 /third-party/DotNetCorePlugins/test
parentf4e4db7c5320976406feb252ae8f8bdbe9b3e351 (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')
-rw-r--r--third-party/DotNetCorePlugins/test/Plugins.Tests/BasicAssemblyLoaderTests.cs160
-rw-r--r--third-party/DotNetCorePlugins/test/Plugins.Tests/DebouncerTests.cs60
-rw-r--r--third-party/DotNetCorePlugins/test/Plugins.Tests/ManageLoadContextTests.cs69
-rw-r--r--third-party/DotNetCorePlugins/test/Plugins.Tests/McMaster.NETCore.Plugins.Tests.csproj41
-rw-r--r--third-party/DotNetCorePlugins/test/Plugins.Tests/PrivateDependencyTests.cs40
-rw-r--r--third-party/DotNetCorePlugins/test/Plugins.Tests/ShadowCopyTests.cs31
-rw-r--r--third-party/DotNetCorePlugins/test/Plugins.Tests/SharedTypesTests.cs107
-rw-r--r--third-party/DotNetCorePlugins/test/Plugins.Tests/TestProjectRefs.targets50
-rw-r--r--third-party/DotNetCorePlugins/test/Plugins.Tests/Utilities/TestProjectReferenceAttribute.cs20
-rw-r--r--third-party/DotNetCorePlugins/test/Plugins.Tests/Utilities/TestResources.cs20
-rw-r--r--third-party/DotNetCorePlugins/test/TestProjects/Banana/Banana.cs12
-rw-r--r--third-party/DotNetCorePlugins/test/TestProjects/Banana/Banana.csproj11
-rw-r--r--third-party/DotNetCorePlugins/test/TestProjects/Directory.Build.props7
-rw-r--r--third-party/DotNetCorePlugins/test/TestProjects/DrawingApp/DrawingApp.csproj11
-rw-r--r--third-party/DotNetCorePlugins/test/TestProjects/DrawingApp/Finder.cs14
-rw-r--r--third-party/DotNetCorePlugins/test/TestProjects/JsonNet10/Class1.cs9
-rw-r--r--third-party/DotNetCorePlugins/test/TestProjects/JsonNet10/JsonNet10.csproj12
-rw-r--r--third-party/DotNetCorePlugins/test/TestProjects/JsonNet11/Class1.cs9
-rw-r--r--third-party/DotNetCorePlugins/test/TestProjects/JsonNet11/JsonNet11.csproj13
-rw-r--r--third-party/DotNetCorePlugins/test/TestProjects/JsonNet9/Class1.cs9
-rw-r--r--third-party/DotNetCorePlugins/test/TestProjects/JsonNet9/JsonNet9.csproj12
-rw-r--r--third-party/DotNetCorePlugins/test/TestProjects/NativeDependency/NativeDependency.csproj11
-rw-r--r--third-party/DotNetCorePlugins/test/TestProjects/NativeDependency/NativeDependencyLoader.cs40
-rw-r--r--third-party/DotNetCorePlugins/test/TestProjects/NetCoreApp2App/NetCoreApp2App.csproj12
-rw-r--r--third-party/DotNetCorePlugins/test/TestProjects/NetCoreApp2App/Program.cs17
-rw-r--r--third-party/DotNetCorePlugins/test/TestProjects/NetStandardClassLib/Class1.cs10
-rw-r--r--third-party/DotNetCorePlugins/test/TestProjects/NetStandardClassLib/NetStandardClassLib.csproj7
-rw-r--r--third-party/DotNetCorePlugins/test/TestProjects/Plátano/Plátano.cs13
-rw-r--r--third-party/DotNetCorePlugins/test/TestProjects/Plátano/Plátano.csproj11
-rw-r--r--third-party/DotNetCorePlugins/test/TestProjects/Plátano/Strings.Designer.cs55
-rw-r--r--third-party/DotNetCorePlugins/test/TestProjects/Plátano/Strings.es.Designer.cs1
-rw-r--r--third-party/DotNetCorePlugins/test/TestProjects/Plátano/Strings.es.resx24
-rw-r--r--third-party/DotNetCorePlugins/test/TestProjects/Plátano/Strings.resx24
-rw-r--r--third-party/DotNetCorePlugins/test/TestProjects/PowerShellPlugin/PowerShellPlugin.csproj12
-rw-r--r--third-party/DotNetCorePlugins/test/TestProjects/PowerShellPlugin/Program.cs25
-rw-r--r--third-party/DotNetCorePlugins/test/TestProjects/ReferencedLibv1/Class1.cs10
-rw-r--r--third-party/DotNetCorePlugins/test/TestProjects/ReferencedLibv1/IFruit.cs10
-rw-r--r--third-party/DotNetCorePlugins/test/TestProjects/ReferencedLibv1/ReferencedLibv1.csproj9
-rw-r--r--third-party/DotNetCorePlugins/test/TestProjects/ReferencedLibv2/Class1.cs10
-rw-r--r--third-party/DotNetCorePlugins/test/TestProjects/ReferencedLibv2/ReferencedLibv2.csproj13
-rw-r--r--third-party/DotNetCorePlugins/test/TestProjects/SharedAbstraction.v1/SharedAbstraction.v1.csproj13
-rw-r--r--third-party/DotNetCorePlugins/test/TestProjects/SharedAbstraction.v1/SharedType.cs13
-rw-r--r--third-party/DotNetCorePlugins/test/TestProjects/SharedAbstraction.v2/SharedAbstraction.v2.csproj14
-rw-r--r--third-party/DotNetCorePlugins/test/TestProjects/SqlClientApp/Program.cs31
-rw-r--r--third-party/DotNetCorePlugins/test/TestProjects/SqlClientApp/SqlClientApp.csproj12
-rw-r--r--third-party/DotNetCorePlugins/test/TestProjects/Strawberry/Strawberry.cs12
-rw-r--r--third-party/DotNetCorePlugins/test/TestProjects/Strawberry/Strawberry.csproj11
-rw-r--r--third-party/DotNetCorePlugins/test/TestProjects/TransitiveDep.v1/TransitiveDep.v1.csproj9
-rw-r--r--third-party/DotNetCorePlugins/test/TestProjects/TransitiveDep.v1/TransitiveSharedType.cs7
-rw-r--r--third-party/DotNetCorePlugins/test/TestProjects/TransitiveDep.v2/TransitiveDep.v2.csproj13
-rw-r--r--third-party/DotNetCorePlugins/test/TestProjects/TransitivePlugin/PluginConfig.cs12
-rw-r--r--third-party/DotNetCorePlugins/test/TestProjects/TransitivePlugin/TransitivePlugin.csproj11
-rw-r--r--third-party/DotNetCorePlugins/test/TestProjects/WithOurPluginsPluginA/Class1.cs12
-rw-r--r--third-party/DotNetCorePlugins/test/TestProjects/WithOurPluginsPluginA/WithOurPluginsPluginA.csproj12
-rw-r--r--third-party/DotNetCorePlugins/test/TestProjects/WithOurPluginsPluginB/Class1.cs12
-rw-r--r--third-party/DotNetCorePlugins/test/TestProjects/WithOurPluginsPluginB/WithOurPluginsPluginB.csproj12
-rw-r--r--third-party/DotNetCorePlugins/test/TestProjects/WithOurPluginsPluginContract/ISayHello.cs10
-rw-r--r--third-party/DotNetCorePlugins/test/TestProjects/WithOurPluginsPluginContract/WithOurPluginsPluginContract.csproj7
-rw-r--r--third-party/DotNetCorePlugins/test/TestProjects/WithOwnPlugins/WithOwnPlugins.cs72
-rw-r--r--third-party/DotNetCorePlugins/test/TestProjects/WithOwnPlugins/WithOwnPlugins.csproj15
-rw-r--r--third-party/DotNetCorePlugins/test/TestProjects/WithOwnPluginsContract/IWithOwnPlugins.cs12
-rw-r--r--third-party/DotNetCorePlugins/test/TestProjects/WithOwnPluginsContract/WithOwnPluginsContract.csproj7
-rw-r--r--third-party/DotNetCorePlugins/test/TestProjects/XunitSample/Class1.cs9
-rw-r--r--third-party/DotNetCorePlugins/test/TestProjects/XunitSample/XunitSample.csproj12
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>