--HG--
branch : dev
This commit is contained in:
Louis DeJardin
2010-04-14 14:45:34 -07:00
9 changed files with 181 additions and 15 deletions

View File

@@ -77,7 +77,10 @@ namespace Orchard.Tests.Environment {
return Enumerable.Empty<ExtensionEntry>();
}
public ShellTopology_Obsolete GetExtensionsTopology() {
public IEnumerable<Type> LoadFeature(string featureName) {
throw new NotImplementedException();
}
throw new NotImplementedException();
}

View File

@@ -1,8 +1,11 @@
using System.Collections.Generic;
using System;
using System.Collections.Generic;
using System.Linq;
using Autofac;
using NUnit.Framework;
using Orchard.Extensions;
using Orchard.Extensions.Loaders;
using Orchard.Tests.Extensions.ExtensionTypes;
using Yaml.Grammar;
namespace Orchard.Tests.Extensions {
@@ -48,6 +51,20 @@ namespace Orchard.Tests.Extensions {
}
}
public class StubLoaders : IExtensionLoader {
#region Implementation of IExtensionLoader
public int Order {
get { return 1; }
}
public ExtensionEntry Load(ExtensionDescriptor descriptor) {
return new ExtensionEntry { Descriptor = descriptor, ExportedTypes = new[] { typeof(Alpha), typeof(Beta), typeof(Phi) } };
}
#endregion
}
[Test]
public void AvailableExtensionsShouldFollowCatalogLocations() {
@@ -190,5 +207,78 @@ features:
Assert.That(!type.IsAbstract);
}
}
[Test]
public void ExtensionManagerShouldThrowIfFeatureDoesNotExist() {
Assert.Throws<ArgumentException>(() => _manager.LoadFeature("NoSuchFeature"));
}
[Test]
public void ExtensionManagerTestFeatureAttribute() {
var extensionManager = new Moq.Mock<IExtensionManager>();
extensionManager.Setup(x => x.ActiveExtensions()).Returns(new[] {
new ExtensionEntry {
Descriptor = new ExtensionDescriptor {
Name = "Module",
Features = new[] {
new FeatureDescriptor { Name = "Module", ExtensionName = "Module" },
new FeatureDescriptor { Name = "TestFeature", ExtensionName = "Module" }
}},
ExportedTypes = new[] { typeof(Alpha), typeof(Beta), typeof(Phi) }
}});
foreach (var type in extensionManager.Object.ActiveExtensions().SelectMany(x => x.ExportedTypes)) {
foreach (OrchardFeatureAttribute featureAttribute in type.GetCustomAttributes(typeof(OrchardFeatureAttribute), false)) {
Assert.That(featureAttribute.FeatureName, Is.EqualTo("TestFeature"));
}
}
}
[Test]
public void ExtensionManagerLoadFeatureReturnsTypesFromSpecificFeaturesWithFeatureAttribute() {
var extensionLoader = new StubLoaders();
var extensionFolder = new StubFolders();
extensionFolder.Manifests.Add("TestModule", @"
name: TestModule
version: 1.0.3
orchardversion: 1
features:
TestModule:
Description: My test module for Orchard.
TestFeature:
Description: Contains the Phi type.
");
ExtensionManager extensionManager = new ExtensionManager(new []{extensionFolder}, new [] {extensionLoader});
foreach (var type in extensionManager.LoadFeature("TestFeature")) {
Assert.That(type == typeof(Phi));
}
}
[Test]
public void ExtensionManagerLoadFeatureDoesNotReturnTypesFromNonMatchingFeatures() {
var extensionLoader = new StubLoaders();
var extensionFolder = new StubFolders();
extensionFolder.Manifests.Add("TestModule", @"
name: TestModule
version: 1.0.3
orchardversion: 1
features:
TestModule:
Description: My test module for Orchard.
TestFeature:
Description: Contains the Phi type.
");
ExtensionManager extensionManager = new ExtensionManager(new[] { extensionFolder }, new[] { extensionLoader });
foreach (var type in extensionManager.LoadFeature("TestModule")) {
Assert.That(type != typeof(Phi));
Assert.That((type == typeof(Alpha) || (type == typeof(Beta))));
}
}
}
}

View File

@@ -0,0 +1,13 @@
using Orchard.Extensions;
namespace Orchard.Tests.Extensions.ExtensionTypes {
public class Alpha {
}
public class Beta {
}
[OrchardFeature("TestFeature")]
public class Phi {
}
}

View File

@@ -54,7 +54,10 @@ namespace Orchard.Tests.Mvc.Routes {
};
}
public ShellTopology_Obsolete GetExtensionsTopology() {
public IEnumerable<Type> LoadFeature(string featureName) {
throw new NotImplementedException();
}
throw new NotImplementedException();
}

View File

@@ -165,6 +165,7 @@
<Compile Include="EventsTests.cs" />
<Compile Include="Extensions\ExtensionFoldersTests.cs" />
<Compile Include="Extensions\ExtensionManagerTests.cs" />
<Compile Include="Extensions\ExtensionTypes\StubTypes.cs" />
<Compile Include="Localization\NullLocalizerTests.cs" />
<Compile Include="Logging\LoggingModuleTests.cs" />
<Compile Include="Mvc\ModelBinders\KeyedListModelBinderTests.cs" />

View File

@@ -33,7 +33,8 @@ namespace Orchard.Extensions {
Logger = NullLogger.Instance;
}
// This method does not load extension types, simply parses extension manifests from
// the filesystem.
public IEnumerable<ExtensionDescriptor> AvailableExtensions() {
var availableExtensions = new List<ExtensionDescriptor>();
foreach (var folder in _folders) {
@@ -44,6 +45,14 @@ namespace Orchard.Extensions {
return availableExtensions;
}
// This method loads types from extensions into the ExtensionEntry array.
public IEnumerable<ExtensionEntry> ActiveExtensions() {
if (_activeExtensions == null) {
_activeExtensions = BuildActiveExtensions().ToList();
}
return _activeExtensions;
}
private static ExtensionDescriptor GetDescriptorForExtension(string name, IExtensionFolders folder) {
string extensionType = folder is ThemeFolders ? "Theme" : "Module";
var parseResult = folder.ParseManifest(name);
@@ -94,17 +103,50 @@ namespace Orchard.Extensions {
return featureDescriptors;
}
public IEnumerable<ExtensionEntry> ActiveExtensions() {
if (_activeExtensions == null) {
_activeExtensions = BuildActiveExtensions().ToList();
}
return _activeExtensions;
}
public ShellTopology_Obsolete GetExtensionsTopology() {
public ShellTopology GetExtensionsTopology() {
var types = ActiveExtensions().SelectMany(x => x.ExportedTypes);
types = types.Concat(typeof(IOrchardHost).Assembly.GetExportedTypes());
return new ShellTopology_Obsolete { Types = types.Where(t => t.IsClass && !t.IsAbstract) };
return new ShellTopology { Types = types.Where(t => t.IsClass && !t.IsAbstract) };
}
public IEnumerable<Type> LoadFeature(string featureName) {
string extensionName = GetExtensionForFeature(featureName);
if (extensionName == null) throw new ArgumentException(T("Feature ") + featureName + T(" was not found in any of the installed extensions"));
var extension = ActiveExtensions().Where(x => x.Descriptor.Name == extensionName).FirstOrDefault();
if (extension == null) throw new InvalidOperationException(T("Extension ") + extensionName + T(" is not active"));
var extensionTypes = extension.ExportedTypes.Where(t => t.IsClass && !t.IsAbstract);
var featureTypes = new List<Type>();
foreach (var type in extensionTypes) {
string sourceFeature = GetSourceFeatureNameForType(type, extensionName);
if (String.Equals(sourceFeature, featureName, StringComparison.OrdinalIgnoreCase)) {
featureTypes.Add(type);
}
}
return featureTypes;
}
private static string GetSourceFeatureNameForType(Type type, string extensionName) {
foreach (OrchardFeatureAttribute featureAttribute in type.GetCustomAttributes(typeof(OrchardFeatureAttribute), false)) {
return featureAttribute.FeatureName;
}
return extensionName;
}
private string GetExtensionForFeature(string featureName) {
foreach (var extensionDescriptor in AvailableExtensions()) {
if (String.Equals(extensionDescriptor.Name, featureName, StringComparison.OrdinalIgnoreCase)) {
return extensionDescriptor.Name;
}
foreach (var feature in extensionDescriptor.Features) {
if (String.Equals(feature.Name, featureName, StringComparison.OrdinalIgnoreCase)) {
return extensionDescriptor.Name;
}
}
}
return null;
}
public void InstallExtension(string extensionType, HttpPostedFileBase extensionBundle) {

View File

@@ -1,11 +1,12 @@
using System.Collections.Generic;
using System;
using System.Collections.Generic;
using System.Web;
namespace Orchard.Extensions {
public interface IExtensionManager {
IEnumerable<ExtensionDescriptor> AvailableExtensions();
IEnumerable<ExtensionEntry> ActiveExtensions();
ShellTopology_Obsolete GetExtensionsTopology();
IEnumerable<Type> LoadFeature(string featureName);
void InstallExtension(string extensionType, HttpPostedFileBase extensionBundle);
void UninstallExtension(string extensionType, string extensionName);
}

View File

@@ -0,0 +1,12 @@
using System;
namespace Orchard.Extensions {
[AttributeUsage(AttributeTargets.Class)]
public class OrchardFeatureAttribute : Attribute {
public OrchardFeatureAttribute(string text) {
FeatureName = text;
}
public string FeatureName { get; set; }
}
}

View File

@@ -181,6 +181,7 @@
<Compile Include="Extensions\ExtensionFolders.cs" />
<Compile Include="Extensions\FeatureDescriptor.cs" />
<Compile Include="Extensions\Loaders\AreaExtensionLoader.cs" />
<Compile Include="Extensions\OrchardFeatureAttribute.cs" />
<Compile Include="Extensions\Records\ExtensionRecord.cs" />
<Compile Include="Extensions\ShellTopology.cs" />
<Compile Include="Mvc\AntiForgery\ValidateAntiForgeryTokenOrchardAttribute.cs" />