From 90098411c68b3f87c7c792783ce8359cae6caa29 Mon Sep 17 00:00:00 2001 From: Ajay Bhargav Baaskaran Date: Fri, 14 Nov 2014 15:18:31 -0800 Subject: [PATCH] [Fixes issue #1528] default reference assemblies made extensible - Made ReferenceAssemblies and GetCandidateLibraries virtual - Added relevant tests --- .../DefaultAssemblyProvider.cs | 36 ++++-- .../DefaultAssemblyProviderTests.cs | 105 +++++++++++++++++- 2 files changed, 127 insertions(+), 14 deletions(-) diff --git a/src/Microsoft.AspNet.Mvc.Core/DefaultAssemblyProvider.cs b/src/Microsoft.AspNet.Mvc.Core/DefaultAssemblyProvider.cs index 675eb87b37..1a42fccba1 100644 --- a/src/Microsoft.AspNet.Mvc.Core/DefaultAssemblyProvider.cs +++ b/src/Microsoft.AspNet.Mvc.Core/DefaultAssemblyProvider.cs @@ -3,6 +3,7 @@ using System; using System.Collections.Generic; +using System.Diagnostics; using System.Linq; using System.Reflection; using Microsoft.Framework.Runtime; @@ -11,8 +12,11 @@ namespace Microsoft.AspNet.Mvc { public class DefaultAssemblyProvider : IAssemblyProvider { - // List of Mvc assemblies that we'll use as roots for controller discovery. - private static readonly HashSet _mvcAssemblyList = new HashSet(StringComparer.Ordinal) + /// + /// Gets the set of assembly names that are used as root for discovery of + /// MVC controllers, view components and views. + /// + protected virtual HashSet ReferenceAssemblies { get; } = new HashSet(StringComparer.Ordinal) { "Microsoft.AspNet.Mvc", "Microsoft.AspNet.Mvc.Core", @@ -29,6 +33,7 @@ namespace Microsoft.AspNet.Mvc _libraryManager = libraryManager; } + /// public IEnumerable CandidateAssemblies { get @@ -37,14 +42,24 @@ namespace Microsoft.AspNet.Mvc } } - internal IEnumerable GetCandidateLibraries() + /// + /// Returns a list of libraries that references the assemblies in . + /// By default it returns all assemblies that reference any of the primary MVC assemblies + /// while ignoring MVC assemblies. + /// + /// A set of . + protected virtual IEnumerable GetCandidateLibraries() { + if (ReferenceAssemblies == null) + { + return Enumerable.Empty(); + } + // GetReferencingLibraries returns the transitive closure of referencing assemblies - // for a given assembly. In our case, we'll gather all assemblies that reference - // any of the primary Mvc assemblies while ignoring Mvc assemblies. - return _mvcAssemblyList.SelectMany(_libraryManager.GetReferencingLibraries) - .Distinct() - .Where(IsCandidateLibrary); + // for a given assembly. + return ReferenceAssemblies.SelectMany(_libraryManager.GetReferencingLibraries) + .Distinct() + .Where(IsCandidateLibrary); } private static Assembly Load(AssemblyName assemblyName) @@ -52,9 +67,10 @@ namespace Microsoft.AspNet.Mvc return Assembly.Load(assemblyName); } - private static bool IsCandidateLibrary(ILibraryInformation library) + private bool IsCandidateLibrary(ILibraryInformation library) { - return !_mvcAssemblyList.Contains(library.Name); + Debug.Assert(ReferenceAssemblies != null); + return !ReferenceAssemblies.Contains(library.Name); } } } diff --git a/test/Microsoft.AspNet.Mvc.Core.Test/DefaultAssemblyProviderTests.cs b/test/Microsoft.AspNet.Mvc.Core.Test/DefaultAssemblyProviderTests.cs index d04c9f82e0..7260a1aec8 100644 --- a/test/Microsoft.AspNet.Mvc.Core.Test/DefaultAssemblyProviderTests.cs +++ b/test/Microsoft.AspNet.Mvc.Core.Test/DefaultAssemblyProviderTests.cs @@ -1,10 +1,8 @@ // Copyright (c) Microsoft Open Technologies, Inc. All rights reserved. // 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 Microsoft.Framework.Runtime; using Moq; using Xunit; @@ -27,7 +25,7 @@ namespace Microsoft.AspNet.Mvc.Core CreateLibraryInfo("SomeRandomAssembly"), }) .Verifiable(); - var provider = new DefaultAssemblyProvider(manager.Object); + var provider = new TestAssemblyProvider(manager.Object); // Act var candidates = provider.GetCandidateLibraries(); @@ -49,7 +47,7 @@ namespace Microsoft.AspNet.Mvc.Core .Returns(new[] { CreateLibraryInfo("Bar") }); manager.Setup(f => f.GetReferencingLibraries("Microsoft.AspNet.Mvc")) .Returns(new[] { CreateLibraryInfo("Baz") }); - var provider = new DefaultAssemblyProvider(manager.Object); + var provider = new TestAssemblyProvider(manager.Object); // Act var candidates = provider.GetCandidateLibraries(); @@ -58,11 +56,110 @@ namespace Microsoft.AspNet.Mvc.Core Assert.Equal(new[] { "Baz", "Foo", "Bar" }, candidates.Select(a => a.Name)); } + [Fact] + public void CandidateAssemblies_ReturnsLibrariesReferencingDefaultAssemblies() + { + // Arrange + var defaultProvider = new TestAssemblyProvider(CreateLibraryManager()); + + // Act + var defaultProviderCandidates = defaultProvider.GetCandidateLibraries(); + + // Assert + Assert.Equal(new[] { "Baz" }, defaultProviderCandidates.Select(a => a.Name)); + } + + [Fact] + public void CandidateAssemblies_ReturnsLibrariesReferencingOverriddenAssemblies() + { + // Arrange + var overriddenProvider = new OverriddenAssemblyProvider(CreateLibraryManager()); + + // Act + var overriddenProviderCandidates = overriddenProvider.GetCandidateLibraries(); + + // Assert + Assert.Equal(new[] { "Foo", "Bar" }, overriddenProviderCandidates.Select(a => a.Name)); + } + + [Fact] + public void CandidateAssemblies_ReturnsEmptySequenceWhenReferenceAssembliesIsNull() + { + // Arrange + var nullProvider = new NullAssemblyProvider(CreateLibraryManager()); + + // Act + var nullProviderCandidates = nullProvider.GetCandidateLibraries(); + + // Assert + Assert.Empty(nullProviderCandidates.Select(a => a.Name)); + } + private static ILibraryInformation CreateLibraryInfo(string name) { var info = new Mock(); info.SetupGet(b => b.Name).Returns(name); return info.Object; } + + private static ILibraryManager CreateLibraryManager() + { + var manager = new Mock(); + manager.Setup(f => f.GetReferencingLibraries(It.IsAny())) + .Returns(Enumerable.Empty()); + manager.Setup(f => f.GetReferencingLibraries("Microsoft.AspNet.Mvc.Core")) + .Returns(new[] { CreateLibraryInfo("Baz") }); + manager.Setup(f => f.GetReferencingLibraries("MyAssembly")) + .Returns(new[] { CreateLibraryInfo("Foo") }); + manager.Setup(f => f.GetReferencingLibraries("AnotherAssembly")) + .Returns(new[] { CreateLibraryInfo("Bar") }); + return manager.Object; + } + + private class TestAssemblyProvider : DefaultAssemblyProvider + { + public new IEnumerable GetCandidateLibraries() + { + return base.GetCandidateLibraries(); + } + + public TestAssemblyProvider(ILibraryManager libraryManager) : base(libraryManager) + { + } + } + + private class OverriddenAssemblyProvider : TestAssemblyProvider + { + protected override HashSet ReferenceAssemblies + { + get + { + return new HashSet + { + "MyAssembly", + "AnotherAssembly" + }; + } + } + + public OverriddenAssemblyProvider(ILibraryManager libraryManager) : base(libraryManager) + { + } + } + + private class NullAssemblyProvider : TestAssemblyProvider + { + protected override HashSet ReferenceAssemblies + { + get + { + return null; + } + } + + public NullAssemblyProvider(ILibraryManager libraryManager) : base(libraryManager) + { + } + } } } \ No newline at end of file