using Microsoft.VisualStudio.TestTools.UnitTesting; using Moq; using Prise.AssemblyLoading; using Prise.Tests.Plugins; using System; using System.Collections.Generic; using System.IO; using System.Linq; using System.Reflection; using System.Runtime.Loader; using System.Threading.Tasks; namespace Prise.Tests.AssemblyLoading { [TestClass] public class DefaultAssemblyLoadStrategyTests : TestBase { [TestMethod] public async Task Ctor_Works() { Assert.IsNotNull(new DefaultAssemblyLoadStrategy()); } [TestMethod] public async Task LoadAssembly_Returns_Null_For_Empty_AssemblyName() { var sut = new DefaultAssemblyLoadStrategy(); var emptyAssemblyname = new AssemblyName(); var initialPluginLoadDirectory = GetPathToAssemblies(); Assert.IsNull(sut.LoadAssembly(initialPluginLoadDirectory, emptyAssemblyname, null, null, null, null)?.Assembly); } [TestMethod] public async Task LoadAssembly_Returns_Null_When_AssemblyName_NotFound() { var sut = new DefaultAssemblyLoadStrategy(); var assemblyname = new AssemblyName("Newtonsoft.Json.dll"); var pluginDependencyContext = this.mockRepository.Create(); var loadFromDependencyContext = CreateLookupFunction((c, a) => ValueOrProceed.Proceed()); var loadFromRemote = CreateLookupFunction((c, a) => ValueOrProceed.Proceed()); var loadFromAppDomain = CreateLookupFunction((c, a) => ValueOrProceed.Proceed()); var initialPluginLoadDirectory = GetPathToAssemblies(); pluginDependencyContext .Setup(p => p.HostDependencies).Returns(Enumerable.Empty()); pluginDependencyContext .Setup(p => p.RemoteDependencies).Returns(Enumerable.Empty()); Assert.IsNull(sut.LoadAssembly(initialPluginLoadDirectory, assemblyname, pluginDependencyContext.Object, loadFromDependencyContext, loadFromRemote, loadFromAppDomain)?.Assembly); } [TestMethod] public async Task LoadAssembly_Returns_Null_From_AppDomain_When_IsHostAssembly_And_Not_RemoteAssembly() { var sut = new DefaultAssemblyLoadStrategy(); var pluginDependencyContext = this.mockRepository.Create(); var initialPluginLoadDirectory = GetPathToAssemblies(); var someAssembly = Assembly.LoadFile(Path.Combine(initialPluginLoadDirectory, "Newtonsoft.Json.dll")); var someAssemblyName = someAssembly.GetName(); var loadFromDependencyContext = CreateLookupFunction((c, a) => ValueOrProceed.Proceed()); var loadFromRemote = CreateLookupFunction((c, a) => ValueOrProceed.Proceed()); var loadFromAppDomain = CreateLookupFunction((c, a) => ValueOrProceed.FromValue(new RuntimeAssemblyShim(someAssembly, RuntimeLoadFlag.FromRequestedVersion), false)); // Mock the fact that it was setup as a host assembly that should be loaded from the host. pluginDependencyContext .Setup(p => p.HostDependencies).Returns(new List { new HostDependency { DependencyName = someAssemblyName } }); pluginDependencyContext .Setup(p => p.RemoteDependencies).Returns(Enumerable.Empty()); Assert.IsNull(sut.LoadAssembly(initialPluginLoadDirectory, someAssemblyName, pluginDependencyContext.Object, loadFromDependencyContext, loadFromRemote, loadFromAppDomain)?.Assembly); } [TestMethod] public async Task LoadAssembly_Returns_NotNull_From_AppDomain_When_IsHostAssembly_And_Not_RemoteAssembly_FromRuntimeVersion() { var sut = new DefaultAssemblyLoadStrategy(); var pluginDependencyContext = this.mockRepository.Create(); var initialPluginLoadDirectory = GetPathToAssemblies(); var someAssembly = Assembly.LoadFile(Path.Combine(initialPluginLoadDirectory, "Newtonsoft.Json.dll")); var someAssemblyName = someAssembly.GetName(); var loadFromDependencyContext = CreateLookupFunction((c, a) => ValueOrProceed.Proceed()); var loadFromRemote = CreateLookupFunction((c, a) => ValueOrProceed.Proceed()); var loadFromAppDomain = CreateLookupFunction((c, a) => ValueOrProceed.FromValue(new RuntimeAssemblyShim(someAssembly, RuntimeLoadFlag.FromRuntimeVersion), false)); // Mock the fact that it was setup as a host assembly that should be loaded from the host. pluginDependencyContext .Setup(p => p.HostDependencies).Returns(new List { new HostDependency { DependencyName = someAssemblyName } }); pluginDependencyContext .Setup(p => p.RemoteDependencies).Returns(Enumerable.Empty()); Assert.AreEqual(someAssembly, sut.LoadAssembly(initialPluginLoadDirectory, someAssemblyName, pluginDependencyContext.Object, loadFromDependencyContext, loadFromRemote, loadFromAppDomain)?.Assembly); } [TestMethod] public async Task LoadAssembly_Returns_Null_From_AppDomain_When_NOT_IsHostAssembly_And_RemoteAssembly() { var sut = new DefaultAssemblyLoadStrategy(); var pluginDependencyContext = this.mockRepository.Create(); var initialPluginLoadDirectory = GetPathToAssemblies(); var someAssembly = Assembly.LoadFile(Path.Combine(initialPluginLoadDirectory, "Newtonsoft.Json.dll")); var someAssemblyName = someAssembly.GetName(); var loadFromDependencyContext = CreateLookupFunction((c, a) => ValueOrProceed.Proceed()); var loadFromRemote = CreateLookupFunction((c, a) => ValueOrProceed.Proceed()); var loadFromAppDomain = CreateLookupFunction((c, a) => ValueOrProceed.Proceed()); // Mock the fact that it was setup as a host assembly that should be loaded from the host. pluginDependencyContext .Setup(p => p.HostDependencies).Returns(new List { new HostDependency { DependencyName = someAssemblyName } }); // Mock the fact that it was ALSO setup as a remote assembly that should be loaded from the plugin. pluginDependencyContext .Setup(p => p.RemoteDependencies).Returns(new List { new RemoteDependency { DependencyName = someAssemblyName } }); Assert.IsNull(sut.LoadAssembly(initialPluginLoadDirectory, someAssemblyName, pluginDependencyContext.Object, loadFromDependencyContext, loadFromRemote, loadFromAppDomain)?.Assembly); } [TestMethod] public async Task LoadAssembly_Returns_Assembly_From_DependencyContext() { var sut = new DefaultAssemblyLoadStrategy(); var pluginDependencyContext = this.mockRepository.Create(); var initialPluginLoadDirectory = GetPathToAssemblies(); var someAssembly = Assembly.LoadFile(Path.Combine(initialPluginLoadDirectory, "Newtonsoft.Json.dll")); var someAssemblyName = someAssembly.GetName(); var loadFromDependencyContext = CreateLookupFunction((c, a) => ValueOrProceed.FromValue(AssemblyFromStrategy.Releasable(someAssembly), false)); var loadFromRemote = CreateLookupFunction((c, a) => ValueOrProceed.Proceed()); var loadFromAppDomain = CreateLookupFunction((c, a) => ValueOrProceed.Proceed()); pluginDependencyContext .Setup(p => p.HostDependencies).Returns(Enumerable.Empty()); pluginDependencyContext .Setup(p => p.RemoteDependencies).Returns(Enumerable.Empty()); Assert.AreEqual(someAssembly, sut.LoadAssembly(initialPluginLoadDirectory, someAssemblyName, pluginDependencyContext.Object, loadFromDependencyContext, loadFromRemote, loadFromAppDomain)?.Assembly); } [TestMethod] public async Task LoadAssembly_Returns_Assembly_From_Remote() { var sut = new DefaultAssemblyLoadStrategy(); var pluginDependencyContext = this.mockRepository.Create(); var initialPluginLoadDirectory = GetPathToAssemblies(); var someAssembly = Assembly.LoadFile(Path.Combine(initialPluginLoadDirectory, "Newtonsoft.Json.dll")); var someAssemblyName = someAssembly.GetName(); var loadFromDependencyContext = CreateLookupFunction((c, a) => ValueOrProceed.Proceed()); var loadFromRemote = CreateLookupFunction((c, a) => ValueOrProceed.FromValue(AssemblyFromStrategy.Releasable(someAssembly), false)); var loadFromAppDomain = CreateLookupFunction((c, a) => ValueOrProceed.Proceed()); pluginDependencyContext .Setup(p => p.HostDependencies).Returns(Enumerable.Empty()); pluginDependencyContext .Setup(p => p.RemoteDependencies).Returns(Enumerable.Empty()); Assert.AreEqual(someAssembly, sut.LoadAssembly(initialPluginLoadDirectory, someAssemblyName, pluginDependencyContext.Object, loadFromDependencyContext, loadFromRemote, loadFromAppDomain)?.Assembly); } [TestMethod] public async Task LoadUnmanagedDll_Returns_AssemblyPath_FromDependencyContext() { var sut = new DefaultAssemblyLoadStrategy(); var pluginDependencyContext = this.mockRepository.Create(); var initialPluginLoadDirectory = GetPathToAssemblies(); var someAssembly = Assembly.LoadFile(Path.Combine(initialPluginLoadDirectory, "Newtonsoft.Json.dll")); var someAssemblyName = someAssembly.GetName(); var loadFromDependencyContext = CreateLookupFunction((c, a) => ValueOrProceed.FromValue(someAssemblyName.Name, false)); var loadFromRemote = CreateLookupFunction((c, a) => ValueOrProceed.Proceed()); var loadFromAppDomain = CreateLookupFunction((c, a) => ValueOrProceed.FromValue(IntPtr.Zero, false)); var result = sut.LoadUnmanagedDll(initialPluginLoadDirectory, someAssemblyName.Name, pluginDependencyContext.Object, loadFromDependencyContext, loadFromRemote, loadFromAppDomain); Assert.AreEqual(someAssemblyName.Name, result.Path); Assert.AreEqual(IntPtr.Zero, result.Pointer); } [TestMethod] public async Task LoadUnmanagedDll_Returns_AssemblyPointer_FromAppDomain() { var sut = new DefaultAssemblyLoadStrategy(); var pluginDependencyContext = this.mockRepository.Create(); var initialPluginLoadDirectory = GetPathToAssemblies(); var someAssembly = Assembly.LoadFile(Path.Combine(initialPluginLoadDirectory, "Newtonsoft.Json.dll")); var someAssemblyName = someAssembly.GetName(); var loadFromDependencyContext = CreateLookupFunction((c, a) => ValueOrProceed.Proceed()); var loadFromRemote = CreateLookupFunction((c, a) => ValueOrProceed.Proceed()); var loadFromAppDomain = CreateLookupFunction((c, a) => ValueOrProceed.FromValue(new IntPtr(100), false)); var result = sut.LoadUnmanagedDll(initialPluginLoadDirectory, someAssemblyName.Name, pluginDependencyContext.Object, loadFromDependencyContext, loadFromRemote, loadFromAppDomain); Assert.IsNull(result.Path); Assert.AreEqual(new IntPtr(100), result.Pointer); } [TestMethod] public async Task LoadUnmanagedDll_Returns_AssemblyPath_FromRemote() { var sut = new DefaultAssemblyLoadStrategy(); var pluginDependencyContext = this.mockRepository.Create(); var initialPluginLoadDirectory = GetPathToAssemblies(); var someAssembly = Assembly.LoadFile(Path.Combine(initialPluginLoadDirectory, "Newtonsoft.Json.dll")); var someAssemblyName = someAssembly.GetName(); var loadFromDependencyContext = CreateLookupFunction((c, a) => ValueOrProceed.Proceed()); var loadFromRemote = CreateLookupFunction((c, a) => ValueOrProceed.FromValue(someAssemblyName.Name, false)); var loadFromAppDomain = CreateLookupFunction((c, a) => ValueOrProceed.Proceed()); var result = sut.LoadUnmanagedDll(initialPluginLoadDirectory, someAssemblyName.Name, pluginDependencyContext.Object, loadFromDependencyContext, loadFromRemote, loadFromAppDomain); Assert.AreEqual(someAssemblyName.Name, result.Path); Assert.AreEqual(IntPtr.Zero, result.Pointer); } protected Func> CreateLookupFunction(Func> func) => func; protected Func> CreateLookupFunction(Func> func) => func; protected Func> CreateLookupFunction(Func> func) => func; } }