Relocating extensions to environment namespace

--HG--
branch : dev
This commit is contained in:
Louis DeJardin
2010-04-17 16:09:53 -07:00
parent 00d235c717
commit 6fb6ef0033
60 changed files with 390 additions and 270 deletions

View File

@@ -0,0 +1,71 @@
using System.IO;
using System.Linq;
using NUnit.Framework;
using Orchard.Environment.Extensions.Folders;
using Yaml.Grammar;
namespace Orchard.Tests.Environment.Extensions {
[TestFixture]
public class ExtensionFoldersTests {
private const string DataPrefix = "Orchard.Tests.Environment.Extensions.FoldersData.";
private string _tempFolderName;
[SetUp]
public void Init() {
_tempFolderName = Path.GetTempFileName();
File.Delete(_tempFolderName);
var assembly = GetType().Assembly;
foreach (var name in assembly.GetManifestResourceNames()) {
if (name.StartsWith(DataPrefix)) {
var text = "";
using (var stream = assembly.GetManifestResourceStream(name)) {
using (var reader = new StreamReader(stream))
text = reader.ReadToEnd();
}
var relativePath = name
.Substring(DataPrefix.Length)
.Replace(".txt", ":txt")
.Replace('.', Path.DirectorySeparatorChar)
.Replace(":txt", ".txt");
var targetPath = Path.Combine(_tempFolderName, relativePath);
Directory.CreateDirectory(Path.GetDirectoryName(targetPath));
using (var stream = new FileStream(targetPath, FileMode.Create)) {
using (var writer = new StreamWriter(stream)) {
writer.Write(text);
}
}
}
}
}
[TearDown]
public void Term() {
Directory.Delete(_tempFolderName, true);
}
[Test]
public void NamesFromFoldersWithModuleTxtShouldBeListed() {
var folders = new ModuleFolders(new[] { _tempFolderName });
var names = folders.ListNames();
Assert.That(names.Count(), Is.EqualTo(2));
Assert.That(names, Has.Some.EqualTo("Sample1"));
Assert.That(names, Has.Some.EqualTo("Sample3"));
}
[Test]
public void ModuleTxtShouldBeParsedAndReturnedAsYamlDocument() {
var folders = new ModuleFolders(new[] { _tempFolderName });
var sample1 = folders.ParseManifest("Sample1");
var mapping = (Mapping)sample1.YamlDocument.Root;
var entities = mapping.Entities
.Where(x => x.Key is Scalar)
.ToDictionary(x => ((Scalar)x.Key).Text, x => x.Value);
Assert.That(entities.Keys, Has.Some.EqualTo("name"));
Assert.That(entities.Keys, Has.Some.EqualTo("author"));
}
}
}

View File

@@ -0,0 +1,297 @@
using System;
using System.Collections.Generic;
using System.Linq;
using Autofac;
using NUnit.Framework;
using Orchard.Environment.Extensions;
using Orchard.Environment.Extensions.Folders;
using Orchard.Environment.Extensions.Loaders;
using Orchard.Environment.Extensions.Models;
using Orchard.Tests.Extensions.ExtensionTypes;
using Yaml.Grammar;
namespace Orchard.Tests.Environment.Extensions {
[TestFixture]
public class ExtensionManagerTests {
private IContainer _container;
private IExtensionManager _manager;
private StubFolders _folders;
[SetUp]
public void Init() {
var builder = new ContainerBuilder();
_folders = new StubFolders();
builder.RegisterInstance(_folders).As<IExtensionFolders>();
builder.RegisterType<ExtensionManager>().As<IExtensionManager>();
_container = builder.Build();
_manager = _container.Resolve<IExtensionManager>();
}
public class StubFolders : IExtensionFolders {
public StubFolders() {
Manifests = new Dictionary<string, string>();
}
public IDictionary<string, string> Manifests { get; set; }
public IEnumerable<string> ListNames() {
return Manifests.Keys;
}
public ParseResult ParseManifest(string name) {
var parser = new YamlParser();
bool success;
var stream = parser.ParseYamlStream(new TextInput(Manifests[name]), out success);
if (success) {
return new ParseResult {
Location = "~/InMemory",
Name = name,
YamlDocument = stream.Documents.Single()
};
}
return null;
}
}
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() {
_folders.Manifests.Add("foo", "name: Foo");
_folders.Manifests.Add("bar", "name: Bar");
_folders.Manifests.Add("frap", "name: Frap");
_folders.Manifests.Add("quad", "name: Quad");
var available = _manager.AvailableExtensions();
Assert.That(available.Count(), Is.EqualTo(4));
Assert.That(available, Has.Some.Property("Name").EqualTo("foo"));
}
[Test]
public void ExtensionDescriptorsShouldHaveNameAndVersion() {
_folders.Manifests.Add("Sample", @"
name: Sample Extension
version: 2.x
");
var descriptor = _manager.AvailableExtensions().Single();
Assert.That(descriptor.Name, Is.EqualTo("Sample"));
Assert.That(descriptor.DisplayName, Is.EqualTo("Sample Extension"));
Assert.That(descriptor.Version, Is.EqualTo("2.x"));
}
[Test]
public void ExtensionDescriptorsShouldBeParsedForMinimalModuleTxt() {
_folders.Manifests.Add("SuperWiki", @"
name: SuperWiki
version: 1.0.3
orchardversion: 1
features:
SuperWiki:
Description: My super wiki module for Orchard.
");
var descriptor = _manager.AvailableExtensions().Single();
Assert.That(descriptor.Name, Is.EqualTo("SuperWiki"));
Assert.That(descriptor.Version, Is.EqualTo("1.0.3"));
Assert.That(descriptor.OrchardVersion, Is.EqualTo("1"));
Assert.That(descriptor.Features.Count(), Is.EqualTo(1));
Assert.That(descriptor.Features.First().Name, Is.EqualTo("SuperWiki"));
Assert.That(descriptor.Features.First().ExtensionName, Is.EqualTo("SuperWiki"));
Assert.That(descriptor.Features.First().Description, Is.EqualTo("My super wiki module for Orchard."));
}
[Test]
public void ExtensionDescriptorsShouldBeParsedForCompleteModuleTxt() {
_folders.Manifests.Add("AnotherWiki", @"
name: AnotherWiki
author: Coder Notaprogrammer
website: http://anotherwiki.codeplex.com
version: 1.2.3
orchardversion: 1
features:
AnotherWiki:
Description: My super wiki module for Orchard.
Dependencies: Versioning, Search
Category: Content types
AnotherWiki Editor:
Description: A rich editor for wiki contents.
Dependencies: TinyMCE, AnotherWiki
Category: Input methods
AnotherWiki DistributionList:
Description: Sends e-mail alerts when wiki contents gets published.
Dependencies: AnotherWiki, Email Subscriptions
Category: Email
AnotherWiki Captcha:
Description: Kills spam. Or makes it zombie-like.
Dependencies: AnotherWiki, reCaptcha
Category: Spam
");
var descriptor = _manager.AvailableExtensions().Single();
Assert.That(descriptor.Name, Is.EqualTo("AnotherWiki"));
Assert.That(descriptor.Author, Is.EqualTo("Coder Notaprogrammer"));
Assert.That(descriptor.WebSite, Is.EqualTo("http://anotherwiki.codeplex.com"));
Assert.That(descriptor.Version, Is.EqualTo("1.2.3"));
Assert.That(descriptor.OrchardVersion, Is.EqualTo("1"));
Assert.That(descriptor.Features.Count(), Is.EqualTo(4));
foreach (var featureDescriptor in descriptor.Features) {
switch (featureDescriptor.Name) {
case "AnotherWiki":
Assert.That(featureDescriptor.ExtensionName, Is.EqualTo("AnotherWiki"));
Assert.That(featureDescriptor.Description, Is.EqualTo("My super wiki module for Orchard."));
Assert.That(featureDescriptor.Category, Is.EqualTo("Content types"));
Assert.That(featureDescriptor.Dependencies.Count(), Is.EqualTo(2));
Assert.That(featureDescriptor.Dependencies.Contains("Versioning"));
Assert.That(featureDescriptor.Dependencies.Contains("Search"));
break;
case "AnotherWiki Editor":
Assert.That(featureDescriptor.ExtensionName, Is.EqualTo("AnotherWiki"));
Assert.That(featureDescriptor.Description, Is.EqualTo("A rich editor for wiki contents."));
Assert.That(featureDescriptor.Category, Is.EqualTo("Input methods"));
Assert.That(featureDescriptor.Dependencies.Count(), Is.EqualTo(2));
Assert.That(featureDescriptor.Dependencies.Contains("TinyMCE"));
Assert.That(featureDescriptor.Dependencies.Contains("AnotherWiki"));
break;
case "AnotherWiki DistributionList":
Assert.That(featureDescriptor.ExtensionName, Is.EqualTo("AnotherWiki"));
Assert.That(featureDescriptor.Description, Is.EqualTo("Sends e-mail alerts when wiki contents gets published."));
Assert.That(featureDescriptor.Category, Is.EqualTo("Email"));
Assert.That(featureDescriptor.Dependencies.Count(), Is.EqualTo(2));
Assert.That(featureDescriptor.Dependencies.Contains("AnotherWiki"));
Assert.That(featureDescriptor.Dependencies.Contains("Email Subscriptions"));
break;
case "AnotherWiki Captcha":
Assert.That(featureDescriptor.ExtensionName, Is.EqualTo("AnotherWiki"));
Assert.That(featureDescriptor.Description, Is.EqualTo("Kills spam. Or makes it zombie-like."));
Assert.That(featureDescriptor.Category, Is.EqualTo("Spam"));
Assert.That(featureDescriptor.Dependencies.Count(), Is.EqualTo(2));
Assert.That(featureDescriptor.Dependencies.Contains("AnotherWiki"));
Assert.That(featureDescriptor.Dependencies.Contains("reCaptcha"));
break;
default:
Assert.Fail("Features not parsed correctly");
break;
}
}
}
[Test]
public void ExtensionManagerShouldLoadFeatures() {
var descriptors = _manager.AvailableExtensions().SelectMany(x => x.Features);
var features = _manager.LoadFeatures(descriptors);
var types = features.SelectMany(x => x.ExportedTypes);
Assert.That(types.Count(), Is.Not.EqualTo(0));
}
[Test]
public void ExtensionManagerFeaturesContainNonAbstractClasses() {
var descriptors = _manager.AvailableExtensions().SelectMany(x => x.Features);
var features = _manager.LoadFeatures(descriptors);
var types = features.SelectMany(x => x.ExportedTypes);
foreach (var type in types) {
Assert.That(type.IsClass);
Assert.That(!type.IsAbstract);
}
}
[Test]
public void ExtensionManagerShouldThrowIfFeatureDoesNotExist() {
var featureDescriptor = new FeatureDescriptor { Name = "NoSuchFeature" };
Assert.Throws<ArgumentException>(() => _manager.LoadFeature(featureDescriptor));
}
[Test]
public void ExtensionManagerTestFeatureAttribute() {
var extensionManager = new Moq.Mock<IExtensionManager>();
extensionManager.Setup(x => x.ActiveExtensions_Obsolete()).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_Obsolete().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 });
var testFeature = extensionManager.AvailableExtensions()
.SelectMany(x => x.Features)
.Single(x => x.Name == "TestFeature");
foreach (var type in extensionManager.LoadFeature(testFeature).ExportedTypes) {
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 });
var testModule = extensionManager.AvailableExtensions()
.SelectMany(x => x.Features)
.Single(x => x.Name == "TestModule");
foreach (var type in extensionManager.LoadFeature(testModule).ExportedTypes) {
Assert.That(type != typeof(Phi));
Assert.That((type == typeof(Alpha) || (type == typeof(Beta))));
}
}
}
}

View File

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

View File

@@ -0,0 +1,8 @@
name: Le plug-in français
author: Bertrand Le Roy
description:
This plug-in replaces
'the' with 'le'
version: 1.0
tags: plug-in, français, the, le
homepage: http://weblogs.asp.net/bleroy

View File

@@ -0,0 +1 @@
This is another test.txt

View File

@@ -0,0 +1 @@
This is another test.txt