Working with unit tests and making a few corrections around ContentTypes.
This commit is contained in:
@@ -13,112 +13,112 @@ namespace Umbraco.Core.Models
|
||||
[DataContract(IsReference = true)]
|
||||
public abstract class ContentTypeCompositionBase : ContentTypeBase, IContentTypeComposition
|
||||
{
|
||||
private List<IContentTypeComposition> _contentTypeComposition;
|
||||
private List<IContentTypeComposition> _contentTypeComposition = new List<IContentTypeComposition>();
|
||||
|
||||
protected ContentTypeCompositionBase(int parentId) : base(parentId)
|
||||
{
|
||||
_contentTypeComposition = new List<IContentTypeComposition>();
|
||||
}
|
||||
|
||||
private static readonly PropertyInfo ContentTypeCompositionSelector = ExpressionHelper.GetPropertyInfo<ContentTypeCompositionBase, List<IContentTypeComposition>>(x => x.ContentTypeComposition);
|
||||
private static readonly PropertyInfo ContentTypeCompositionSelector =
|
||||
ExpressionHelper.GetPropertyInfo<ContentTypeCompositionBase, IEnumerable<IContentTypeComposition>>(
|
||||
x => x.ContentTypeComposition);
|
||||
|
||||
/// <summary>
|
||||
/// List of ContentTypes that make up a composition of PropertyGroups and PropertyTypes for the current ContentType
|
||||
/// </summary>
|
||||
[DataMember]
|
||||
public List<IContentTypeComposition> ContentTypeComposition
|
||||
{
|
||||
get { return _contentTypeComposition; }
|
||||
set
|
||||
{
|
||||
_contentTypeComposition = value;
|
||||
OnPropertyChanged(ContentTypeCompositionSelector);
|
||||
}
|
||||
}
|
||||
/// <summary>
|
||||
/// List of ContentTypes that make up a composition of PropertyGroups and PropertyTypes for the current ContentType
|
||||
/// </summary>
|
||||
[DataMember]
|
||||
public IEnumerable<IContentTypeComposition> ContentTypeComposition
|
||||
{
|
||||
get { return _contentTypeComposition; }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Returns a list of <see cref="PropertyGroup"/> objects from the composition
|
||||
/// </summary>
|
||||
[IgnoreDataMember]
|
||||
public IEnumerable<PropertyGroup> CompositionPropertyGroups
|
||||
{
|
||||
get
|
||||
{
|
||||
var groups = PropertyGroups.Union(ContentTypeComposition.SelectMany(x => x.CompositionPropertyGroups));
|
||||
return groups;
|
||||
}
|
||||
}
|
||||
/// <summary>
|
||||
/// Returns a list of <see cref="PropertyGroup"/> objects from the composition
|
||||
/// </summary>
|
||||
[IgnoreDataMember]
|
||||
public IEnumerable<PropertyGroup> CompositionPropertyGroups
|
||||
{
|
||||
get
|
||||
{
|
||||
var groups = PropertyGroups.Union(ContentTypeComposition.SelectMany(x => x.CompositionPropertyGroups));
|
||||
return groups;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Returns a list of <see cref="PropertyType"/> objects from the composition
|
||||
/// </summary>
|
||||
[IgnoreDataMember]
|
||||
public IEnumerable<PropertyType> CompositionPropertyTypes
|
||||
{
|
||||
get
|
||||
{
|
||||
var propertyTypes = PropertyTypes.Union(ContentTypeComposition.SelectMany(x => x.CompositionPropertyTypes));
|
||||
return propertyTypes;
|
||||
}
|
||||
}
|
||||
/// <summary>
|
||||
/// Returns a list of <see cref="PropertyType"/> objects from the composition
|
||||
/// </summary>
|
||||
[IgnoreDataMember]
|
||||
public IEnumerable<PropertyType> CompositionPropertyTypes
|
||||
{
|
||||
get
|
||||
{
|
||||
var propertyTypes =
|
||||
PropertyTypes.Union(ContentTypeComposition.SelectMany(x => x.CompositionPropertyTypes));
|
||||
return propertyTypes;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Adds a new ContentType to the list of composite ContentTypes
|
||||
/// </summary>
|
||||
/// <param name="contentType"><see cref="ContentType"/> to add</param>
|
||||
/// <returns>True if ContentType was added, otherwise returns False</returns>
|
||||
public bool AddContentType(IContentTypeComposition contentType)
|
||||
{
|
||||
if (contentType.ContentTypeComposition.Any(x => x.CompositionAliases().Any(ContentTypeCompositionExists)))
|
||||
return false;
|
||||
/// <summary>
|
||||
/// Adds a new ContentType to the list of composite ContentTypes
|
||||
/// </summary>
|
||||
/// <param name="contentType"><see cref="ContentType"/> to add</param>
|
||||
/// <returns>True if ContentType was added, otherwise returns False</returns>
|
||||
public bool AddContentType(IContentTypeComposition contentType)
|
||||
{
|
||||
if (contentType.ContentTypeComposition.Any(x => x.CompositionAliases().Any(ContentTypeCompositionExists)))
|
||||
return false;
|
||||
|
||||
if (!ContentTypeCompositionExists(contentType.Alias))
|
||||
{
|
||||
ContentTypeComposition.Add(contentType);
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
if (!ContentTypeCompositionExists(contentType.Alias))
|
||||
{
|
||||
_contentTypeComposition.Add(contentType);
|
||||
OnPropertyChanged(ContentTypeCompositionSelector);
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Removes a ContentType with the supplied alias from the the list of composite ContentTypes
|
||||
/// </summary>
|
||||
/// <param name="alias">Alias of a <see cref="ContentType"/></param>
|
||||
/// <returns>True if ContentType was removed, otherwise returns False</returns>
|
||||
public bool RemoveContentType(string alias)
|
||||
{
|
||||
if (!ContentTypeCompositionExists(alias))
|
||||
{
|
||||
var contentTypeComposition = ContentTypeComposition.First(x => x.Alias == alias);
|
||||
return ContentTypeComposition.Remove(contentTypeComposition);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
/// <summary>
|
||||
/// Removes a ContentType with the supplied alias from the the list of composite ContentTypes
|
||||
/// </summary>
|
||||
/// <param name="alias">Alias of a <see cref="ContentType"/></param>
|
||||
/// <returns>True if ContentType was removed, otherwise returns False</returns>
|
||||
public bool RemoveContentType(string alias)
|
||||
{
|
||||
if (!ContentTypeCompositionExists(alias))
|
||||
{
|
||||
var contentTypeComposition = ContentTypeComposition.First(x => x.Alias == alias);
|
||||
return _contentTypeComposition.Remove(contentTypeComposition);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Checks if a ContentType with the supplied alias exists in the list of composite ContentTypes
|
||||
/// </summary>
|
||||
/// <param name="alias">Alias of a <see cref="ContentType"/></param>
|
||||
/// <returns>True if ContentType with alias exists, otherwise returns False</returns>
|
||||
public bool ContentTypeCompositionExists(string alias)
|
||||
{
|
||||
if (ContentTypeComposition.Any(x => x.Alias.Equals(alias)))
|
||||
return true;
|
||||
/// <summary>
|
||||
/// Checks if a ContentType with the supplied alias exists in the list of composite ContentTypes
|
||||
/// </summary>
|
||||
/// <param name="alias">Alias of a <see cref="ContentType"/></param>
|
||||
/// <returns>True if ContentType with alias exists, otherwise returns False</returns>
|
||||
public bool ContentTypeCompositionExists(string alias)
|
||||
{
|
||||
if (ContentTypeComposition.Any(x => x.Alias.Equals(alias)))
|
||||
return true;
|
||||
|
||||
if (ContentTypeComposition.Any(x => x.ContentTypeCompositionExists(alias)))
|
||||
return true;
|
||||
if (ContentTypeComposition.Any(x => x.ContentTypeCompositionExists(alias)))
|
||||
return true;
|
||||
|
||||
return false;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets a list of ContentType aliases from the current composition
|
||||
/// </summary>
|
||||
/// <returns></returns>
|
||||
/// <remarks>Does not contain the alias of the Current ContentType</remarks>
|
||||
public IEnumerable<string> CompositionAliases()
|
||||
{
|
||||
return ContentTypeComposition.Select(x => x.Alias).Union(ContentTypeComposition.SelectMany(x => x.CompositionAliases()));
|
||||
}
|
||||
/// <summary>
|
||||
/// Gets a list of ContentType aliases from the current composition
|
||||
/// </summary>
|
||||
/// <returns></returns>
|
||||
/// <remarks>Does not contain the alias of the Current ContentType</remarks>
|
||||
public IEnumerable<string> CompositionAliases()
|
||||
{
|
||||
return ContentTypeComposition
|
||||
.Select(x => x.Alias)
|
||||
.Union(ContentTypeComposition.SelectMany(x => x.CompositionAliases()));
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -10,7 +10,7 @@ namespace Umbraco.Core.Models
|
||||
/// <summary>
|
||||
/// Gets a list of ContentTypes that make up a composition of PropertyGroups and PropertyTypes for the current ContentType
|
||||
/// </summary>
|
||||
List<IContentTypeComposition> ContentTypeComposition { get; }
|
||||
IEnumerable<IContentTypeComposition> ContentTypeComposition { get; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets a list of <see cref="PropertyGroup"/> objects from the composition
|
||||
|
||||
@@ -9,9 +9,11 @@ namespace Umbraco.Core.Models.Rdbms
|
||||
{
|
||||
[Column("parentContentTypeId")]
|
||||
[PrimaryKeyColumn(AutoIncrement = false, Clustered = true, Name = "PK_cmsContentType2ContentType", OnColumns = "parentContentTypeId, childContentTypeId")]
|
||||
[ForeignKey(typeof(NodeDto), Name = "FK_cmsContentType2ContentType_umbracoNode_parent")]
|
||||
public int ParentId { get; set; }
|
||||
|
||||
[Column("childContentTypeId")]
|
||||
[ForeignKey(typeof(NodeDto), Name = "FK_cmsContentType2ContentType_umbracoNode_child")]
|
||||
public int ChildId { get; set; }
|
||||
}
|
||||
}
|
||||
@@ -13,7 +13,7 @@ namespace Umbraco.Core.Models.Rdbms
|
||||
public int Id { get; set; }
|
||||
|
||||
[Column("datatypeNodeId")]
|
||||
[ForeignKey(typeof(DataTypeDto))]
|
||||
[ForeignKey(typeof(DataTypeDto), Column = "nodeId")]
|
||||
public int DataTypeNodeId { get; set; }
|
||||
|
||||
[Column("value")]
|
||||
|
||||
@@ -84,7 +84,19 @@ namespace Umbraco.Core.Persistence.Repositories
|
||||
{
|
||||
if (composition.Id == entity.Id) continue;//Just to ensure that we aren't creating a reference to ourself.
|
||||
|
||||
Database.Insert(new ContentType2ContentTypeDto { ParentId = composition.Id, ChildId = entity.Id });
|
||||
if (composition.HasIdentity)
|
||||
{
|
||||
Database.Insert(new ContentType2ContentTypeDto { ParentId = composition.Id, ChildId = entity.Id });
|
||||
}
|
||||
else
|
||||
{
|
||||
//Fallback for ContentTypes with no identity
|
||||
var contentTypeDto = Database.FirstOrDefault<ContentTypeDto>("WHERE alias = @Alias", new {Alias = composition.Alias});
|
||||
if (contentTypeDto != null)
|
||||
{
|
||||
Database.Insert(new ContentType2ContentTypeDto { ParentId = contentTypeDto.NodeId, ChildId = entity.Id });
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//Insert collection of allowed content types
|
||||
|
||||
@@ -3,6 +3,7 @@ using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using Umbraco.Core.Configuration;
|
||||
using Umbraco.Core.Logging;
|
||||
using Umbraco.Core.Models;
|
||||
using Umbraco.Core.Persistence;
|
||||
using Umbraco.Core.Persistence.Querying;
|
||||
@@ -126,6 +127,8 @@ namespace Umbraco.Core.Services
|
||||
content.Value.CreatorId = 0;
|
||||
repository.AddOrUpdate(content.Value);
|
||||
_unitOfWork.Commit();
|
||||
|
||||
LogHelper.Info<ContentTypeService>(string.Format("Saved ContentType with Alias '{0}' and Id '{1}'", content.Value.Alias, content.Value.Id));
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
18
src/Umbraco.Tests/CodeFirst/Attributes/MixinAttribute.cs
Normal file
18
src/Umbraco.Tests/CodeFirst/Attributes/MixinAttribute.cs
Normal file
@@ -0,0 +1,18 @@
|
||||
using System;
|
||||
|
||||
namespace Umbraco.Tests.CodeFirst.Attributes
|
||||
{
|
||||
[AttributeUsage(AttributeTargets.Interface, AllowMultiple = false, Inherited = true)]
|
||||
public class MixinAttribute : Attribute
|
||||
{
|
||||
public MixinAttribute(Type type)
|
||||
{
|
||||
Type = type;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the Type of the implementing class
|
||||
/// </summary>
|
||||
public Type Type { get; private set; }
|
||||
}
|
||||
}
|
||||
@@ -30,8 +30,8 @@ namespace Umbraco.Tests.CodeFirst.Attributes
|
||||
|
||||
if(string.IsNullOrEmpty(PreValue) == false)
|
||||
{
|
||||
Conventions.CreatePrevalueForDataTypeDefinition(definition.DataTypeDefinition.Id, PreValue, 0,
|
||||
string.Empty);
|
||||
//TODO - test inserting a prevalue when a DataTypeDefinition has been created, as its currently throwing a foreignkey constraint error.
|
||||
Conventions.CreatePrevalueForDataTypeDefinition(definition.DataTypeDefinition.Id, PreValue, 0, string.Empty);
|
||||
}
|
||||
|
||||
return definition;
|
||||
|
||||
@@ -1,5 +1,4 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using NUnit.Framework;
|
||||
@@ -10,6 +9,7 @@ using Umbraco.Core.ObjectResolution;
|
||||
using Umbraco.Core.Serialization;
|
||||
using Umbraco.Tests.CodeFirst.Definitions;
|
||||
using Umbraco.Tests.CodeFirst.TestModels;
|
||||
using Umbraco.Tests.CodeFirst.TestModels.Composition;
|
||||
using Umbraco.Tests.TestHelpers;
|
||||
using Umbraco.Tests.TestHelpers.Entities;
|
||||
using umbraco.editorControls.tinyMCE3;
|
||||
@@ -32,7 +32,8 @@ namespace Umbraco.Tests.CodeFirst
|
||||
PluginManager.Current.AssembliesToScan = new[]
|
||||
{
|
||||
typeof(IDataType).Assembly,
|
||||
typeof(tinyMCE3dataType).Assembly
|
||||
typeof(tinyMCE3dataType).Assembly,
|
||||
typeof (ContentTypeBase).Assembly
|
||||
};
|
||||
|
||||
DataTypesResolver.Current = new DataTypesResolver(
|
||||
@@ -187,37 +188,43 @@ namespace Umbraco.Tests.CodeFirst
|
||||
|
||||
}
|
||||
|
||||
private SerializationService SerializationService { get; set; }
|
||||
|
||||
private static int[] GetTopologicalSortOrder(IList<DependencyField> fields)
|
||||
[Test]
|
||||
public void Can_Resolve_ContentType_Composition_And_Save_To_Database()
|
||||
{
|
||||
var g = new TopologicalSorter(fields.Count());
|
||||
var _indexes = new Dictionary<string, int>();
|
||||
ContentTypeDefinitionFactory.ClearContentTypeCache();
|
||||
|
||||
//add vertices
|
||||
for (int i = 0; i < fields.Count(); i++)
|
||||
{
|
||||
_indexes[fields[i].Alias.ToLower()] = g.AddVertex(i);
|
||||
}
|
||||
var metaSeoModel = typeof(MetaSeo);
|
||||
var seoContentType = ContentTypeDefinitionFactory.GetContentTypeDefinition(metaSeoModel);
|
||||
var metaModel = typeof(Meta);
|
||||
var metaContentType = ContentTypeDefinitionFactory.GetContentTypeDefinition(metaModel);
|
||||
var baseModel = typeof(Base);
|
||||
var baseContentType = ContentTypeDefinitionFactory.GetContentTypeDefinition(baseModel);
|
||||
var newsModel = typeof(News);
|
||||
var newsContentType = ContentTypeDefinitionFactory.GetContentTypeDefinition(newsModel);
|
||||
|
||||
//add edges
|
||||
for (int i = 0; i < fields.Count; i++)
|
||||
{
|
||||
if (fields[i].DependsOn != null)
|
||||
{
|
||||
for (int j = 0; j < fields[i].DependsOn.Length; j++)
|
||||
{
|
||||
g.AddEdge(i,
|
||||
_indexes[fields[i].DependsOn[j].ToLower()]);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
int[] result = g.Sort();
|
||||
return result;
|
||||
var mappedContentTypes = ContentTypeDefinitionFactory.RetrieveMappedContentTypes().ToList();
|
||||
ServiceContext.ContentTypeService.Save(mappedContentTypes);
|
||||
|
||||
Assert.That(mappedContentTypes.Count(), Is.EqualTo(4));
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void Can_Resolve_Full_List_Of_Models_Implementing_ContentTypeBase()
|
||||
{
|
||||
ContentTypeDefinitionFactory.ClearContentTypeCache();
|
||||
|
||||
var foundTypes = PluginManager.Current.ResolveContentTypeBaseTypes();
|
||||
var contentTypeList = foundTypes.Select(ContentTypeDefinitionFactory.GetContentTypeDefinition).ToList();
|
||||
|
||||
var mappedContentTypes = ContentTypeDefinitionFactory.RetrieveMappedContentTypes();
|
||||
|
||||
Assert.That(contentTypeList.Count(), Is.EqualTo(mappedContentTypes.Count()));
|
||||
|
||||
ServiceContext.ContentTypeService.Save(mappedContentTypes);//Save to db
|
||||
}
|
||||
|
||||
private SerializationService SerializationService { get; set; }
|
||||
|
||||
[TearDown]
|
||||
public override void TearDown()
|
||||
{
|
||||
|
||||
@@ -37,6 +37,9 @@ namespace Umbraco.Tests.CodeFirst.Definitions
|
||||
? PlainPocoConvention(modelType, existing)
|
||||
: ContentTypeConvention(contentTypeAttribute, modelType, existing);
|
||||
|
||||
//Check for interfaces that'll be used for ContentTypeComposition
|
||||
var mixins = GetAliasesFromTypeInterfaces(modelType);
|
||||
|
||||
var definitions = new List<PropertyDefinition>();
|
||||
int order = 0;
|
||||
var objProperties = modelType.GetProperties(BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance | BindingFlags.DeclaredOnly).ToList();
|
||||
@@ -126,17 +129,48 @@ namespace Umbraco.Tests.CodeFirst.Definitions
|
||||
//Add the resolved ContentType to the internal cache
|
||||
var field = new DependencyField {ContentType = contentType, Alias = contentType.Value.Alias};
|
||||
var dependencies = new List<string>();
|
||||
//If current type has a parent (inherited model) we add the alias of that type as a dependency
|
||||
if(hasParent)
|
||||
{
|
||||
dependencies.Add(parent.Value.Alias);
|
||||
}
|
||||
//Check ContentType for existing 'Allowed ContentTypes'
|
||||
if(contentType.Value.AllowedContentTypes.Any())
|
||||
{
|
||||
dependencies.AddRange(contentType.Value.AllowedContentTypes.Select(allowed => allowed.Alias));
|
||||
}
|
||||
//Check for interfaces with AliasAttribute and add those as dependencies
|
||||
//NOTE: might also be an idea to check if ContentType has already been created/added to cache that implements the interface.
|
||||
if(mixins.Any())
|
||||
{
|
||||
foreach (var mixin in mixins)
|
||||
{
|
||||
if(dependencies.Contains(mixin.Item1)) continue;
|
||||
|
||||
dependencies.Add(mixin.Item1);
|
||||
var isMixinResolved = _contentTypeCache.ContainsKey(mixin.Item2);
|
||||
|
||||
Lazy<IContentType> compositionType = null;
|
||||
|
||||
if (isMixinResolved)
|
||||
{
|
||||
compositionType = _contentTypeCache[mixin.Item2].ContentType;
|
||||
}
|
||||
else
|
||||
{
|
||||
GetContentTypeDefinition(mixin.Item3);
|
||||
compositionType = _contentTypeCache[mixin.Item2].ContentType;
|
||||
}
|
||||
|
||||
contentType.Value.AddContentType(compositionType.Value);
|
||||
}
|
||||
}
|
||||
field.DependsOn = dependencies.ToArray();
|
||||
_contentTypeCache.AddOrUpdate(modelType.FullName, field, (x, y) => field);
|
||||
return contentType;
|
||||
}
|
||||
|
||||
|
||||
private static int[] GetTopologicalSortOrder(IList<DependencyField> fields)
|
||||
{
|
||||
var g = new TopologicalSorter(fields.Count());
|
||||
@@ -191,6 +225,37 @@ namespace Umbraco.Tests.CodeFirst.Definitions
|
||||
_contentTypeCache.Clear();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Retrieves a list of aliases that correspond to the interfaces on the passed in type,
|
||||
/// which are attributed with the AliasAttribute.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// The modelType is also used to ensure that the implementing class doesn't reference
|
||||
/// itself via its interface.
|
||||
/// </remarks>
|
||||
/// <param name="modelType">Type of the model to retrieve interface aliases from</param>
|
||||
/// <returns>An enumerable list of strings with aliases</returns>
|
||||
private static IEnumerable<Tuple<string, string, Type>> GetAliasesFromTypeInterfaces(Type modelType)
|
||||
{
|
||||
var interfaces = modelType.GetInterfaces().ToList().Distinct();
|
||||
var list = new List<Tuple<string, string, Type>>();
|
||||
|
||||
foreach (var interfaceType in interfaces)
|
||||
{
|
||||
var mixinAttribute = interfaceType.FirstAttribute<MixinAttribute>();
|
||||
if (mixinAttribute != null)
|
||||
{
|
||||
if(mixinAttribute.Type == modelType) continue;
|
||||
var contentTypeAttribute = mixinAttribute.Type.FirstAttribute<ContentTypeAttribute>();
|
||||
var contentTypeAlias = contentTypeAttribute == null ? mixinAttribute.Type.Name.ToUmbracoAlias() : contentTypeAttribute.Alias;
|
||||
var tuple = new Tuple<string, string, Type>(contentTypeAlias, mixinAttribute.Type.FullName, mixinAttribute.Type);
|
||||
list.Add(tuple);
|
||||
}
|
||||
}
|
||||
|
||||
return list;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Convention that converts a class decorated with the ContentTypeAttribute to an initial ContentType
|
||||
/// </summary>
|
||||
|
||||
17
src/Umbraco.Tests/CodeFirst/PluginManagerExtensions.cs
Normal file
17
src/Umbraco.Tests/CodeFirst/PluginManagerExtensions.cs
Normal file
@@ -0,0 +1,17 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using Umbraco.Core;
|
||||
|
||||
namespace Umbraco.Tests.CodeFirst
|
||||
{
|
||||
/// <summary>
|
||||
/// Used for PluginTypeResolverTests
|
||||
/// </summary>
|
||||
internal static class PluginManagerExtensions
|
||||
{
|
||||
public static IEnumerable<Type> ResolveContentTypeBaseTypes(this PluginManager resolver)
|
||||
{
|
||||
return resolver.ResolveTypes<ContentTypeBase>();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,10 +1,14 @@
|
||||
namespace Umbraco.Tests.CodeFirst.TestModels.Composition
|
||||
using Umbraco.Tests.CodeFirst.Attributes;
|
||||
|
||||
namespace Umbraco.Tests.CodeFirst.TestModels.Composition
|
||||
{
|
||||
public class Base : IBase
|
||||
public class Base : ContentTypeBase, IBase
|
||||
{
|
||||
|
||||
[Richtext(PropertyGroup = "Content")]
|
||||
public string BodyContent { get; set; }
|
||||
}
|
||||
|
||||
[Mixin(typeof(Base))]
|
||||
public interface IBase
|
||||
{
|
||||
|
||||
|
||||
@@ -1,13 +1,19 @@
|
||||
using Umbraco.Tests.CodeFirst.Attributes;
|
||||
using umbraco.editorControls.textfield;
|
||||
using umbraco.editorControls.textfieldmultiple;
|
||||
|
||||
namespace Umbraco.Tests.CodeFirst.TestModels.Composition
|
||||
{
|
||||
public class Meta : IMeta
|
||||
public class Meta : ContentTypeBase, IMeta
|
||||
{
|
||||
|
||||
[PropertyType(typeof(TextFieldDataType), PropertyGroup = "Content")]
|
||||
public string MetaKeywords { get; set; }
|
||||
|
||||
[PropertyType(typeof(textfieldMultipleDataType))]
|
||||
public string MetaDescription { get; set; }
|
||||
}
|
||||
|
||||
[Alias("meta", Name = "Meta")]
|
||||
[Mixin(typeof(Meta))]
|
||||
public interface IMeta
|
||||
{}
|
||||
}
|
||||
@@ -0,0 +1,15 @@
|
||||
using Umbraco.Tests.CodeFirst.Attributes;
|
||||
using umbraco.editorControls.textfieldmultiple;
|
||||
|
||||
namespace Umbraco.Tests.CodeFirst.TestModels.Composition
|
||||
{
|
||||
public class MetaSeo : ContentTypeBase, IMetaSeo
|
||||
{
|
||||
[PropertyType(typeof(textfieldMultipleDataType))]
|
||||
public string FriendlySeoStuff { get; set; }
|
||||
}
|
||||
|
||||
[Mixin(typeof(MetaSeo))]
|
||||
public interface IMetaSeo
|
||||
{}
|
||||
}
|
||||
@@ -1,10 +1,14 @@
|
||||
namespace Umbraco.Tests.CodeFirst.TestModels.Composition
|
||||
using Umbraco.Tests.CodeFirst.Attributes;
|
||||
using umbraco.editorControls.textfield;
|
||||
|
||||
namespace Umbraco.Tests.CodeFirst.TestModels.Composition
|
||||
{
|
||||
/// <summary>
|
||||
/// Deriving class is parent, interfaces are compositions
|
||||
/// </summary>
|
||||
public class News : Base, IMeta, ISeo
|
||||
public class News : Base, IMetaSeo, IMeta
|
||||
{
|
||||
|
||||
[PropertyType(typeof(TextFieldDataType), PropertyGroup = "Content")]
|
||||
public string Author { get; set; }
|
||||
}
|
||||
}
|
||||
@@ -1,13 +0,0 @@
|
||||
using Umbraco.Tests.CodeFirst.Attributes;
|
||||
|
||||
namespace Umbraco.Tests.CodeFirst.TestModels.Composition
|
||||
{
|
||||
public class Seo : ISeo
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
[Alias("seo", Name = "Seo")]
|
||||
public interface ISeo : IBase
|
||||
{}
|
||||
}
|
||||
@@ -7,7 +7,7 @@ namespace Umbraco.Tests.CodeFirst.TestModels
|
||||
[ContentType("modelPage",
|
||||
AllowedChildContentTypes = new[] { typeof(ContentPage) },
|
||||
AllowedTemplates = new[]{"umbMaster"})]
|
||||
public class DecoratedModelPage
|
||||
public class DecoratedModelPage : ContentTypeBase
|
||||
{
|
||||
[PropertyType(typeof(TextFieldDataType), PropertyGroup = "Content")]
|
||||
public string Author { get; set; }
|
||||
|
||||
@@ -5,7 +5,7 @@ using umbraco.editorControls.textfieldmultiple;
|
||||
namespace Umbraco.Tests.CodeFirst.TestModels
|
||||
{
|
||||
[ContentType("home", AllowedChildContentTypes = new[] { typeof(ContentPage) })]
|
||||
public class Home
|
||||
public class Home : ContentTypeBase
|
||||
{
|
||||
[PropertyType(typeof(TextFieldDataType))]
|
||||
public string SiteName { get; set; }
|
||||
|
||||
@@ -4,7 +4,7 @@ using umbraco.editorControls.tinymce;
|
||||
|
||||
namespace Umbraco.Tests.CodeFirst.TestModels
|
||||
{
|
||||
public class ModelWithNewDataType
|
||||
public class ModelWithNewDataType : ContentTypeBase
|
||||
{
|
||||
[PropertyType(typeof(TextFieldDataType), PropertyGroup = "Content")]
|
||||
public string Title { get; set; }
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
|
||||
namespace Umbraco.Tests.CodeFirst.TestModels
|
||||
{
|
||||
public class NumericModel
|
||||
public class NumericModel : ContentTypeBase
|
||||
{
|
||||
[Numeric("Number DataType", PreValue = "5", PropertyGroup = "Content")]
|
||||
public int Number { get; set; }
|
||||
|
||||
@@ -2,17 +2,22 @@
|
||||
|
||||
namespace Umbraco.Tests.CodeFirst.TestModels
|
||||
{
|
||||
//Plain Poco Type - plainPocoType
|
||||
public class PlainPocoType
|
||||
//Name: Plain Poco Type - Alias: plainPocoType
|
||||
public class PlainPocoType : ContentTypeBase
|
||||
{
|
||||
//Name: Title, Alias: title, DataType: Text Field
|
||||
public string Title { get; set; }
|
||||
|
||||
//Name: Author, Alias: author, DataType: Text Field
|
||||
public string Author { get; set; }
|
||||
|
||||
//Name: Is Finished, Alias: isFinished, DataType: Yes/No
|
||||
public bool IsFinished { get; set; }
|
||||
|
||||
//Name: Weight, Alias: weight, DataType: Number
|
||||
public int Weight { get; set; }
|
||||
|
||||
//Name: Publish Date, Alias: publishDate, DataType: Datepicker
|
||||
public DateTime PublishDate { get; set; }
|
||||
}
|
||||
}
|
||||
@@ -3,7 +3,7 @@ using umbraco.editorControls.textfield;
|
||||
|
||||
namespace Umbraco.Tests.CodeFirst.TestModels
|
||||
{
|
||||
public class SimpleContentPage
|
||||
public class SimpleContentPage : ContentTypeBase
|
||||
{
|
||||
[PropertyType(typeof(TextFieldDataType), PropertyGroup = "Content")]
|
||||
public string Title { get; set; }
|
||||
|
||||
@@ -3,7 +3,7 @@ using umbraco.editorControls.textfield;
|
||||
|
||||
namespace Umbraco.Tests.CodeFirst.TestModels
|
||||
{
|
||||
public class TextPage
|
||||
public class TextPage : ContentTypeBase
|
||||
{
|
||||
[PropertyType(typeof(TextFieldDataType), PropertyGroup = "Content")]
|
||||
public string Author { get; set; }
|
||||
|
||||
@@ -1,24 +1,82 @@
|
||||
using System.Linq;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using NUnit.Framework;
|
||||
using Umbraco.Core;
|
||||
using Umbraco.Core.Models;
|
||||
using Umbraco.Tests.CodeFirst.Attributes;
|
||||
using Umbraco.Tests.CodeFirst.Definitions;
|
||||
using Umbraco.Tests.CodeFirst.TestModels.Composition;
|
||||
using Umbraco.Tests.TestHelpers;
|
||||
|
||||
namespace Umbraco.Tests.CodeFirst
|
||||
{
|
||||
[TestFixture]
|
||||
public class TypeInheritanceTest
|
||||
{
|
||||
[SetUp]
|
||||
public void Initialize()
|
||||
{
|
||||
TestHelper.SetupLog4NetForTests();
|
||||
|
||||
//this ensures its reset
|
||||
PluginManager.Current = new PluginManager(false);
|
||||
|
||||
//for testing, we'll specify which assemblies are scanned for the PluginTypeResolver
|
||||
PluginManager.Current.AssembliesToScan = new[]
|
||||
{
|
||||
typeof (ContentTypeBase).Assembly
|
||||
};
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void Can_Get_Interfaces_From_Type()
|
||||
{
|
||||
var type = typeof (News);
|
||||
var interfaces = type.GetInterfaces().ToList();
|
||||
|
||||
bool hasSeo = interfaces.Any(x => x.Name == typeof(ISeo).Name);
|
||||
bool hasSeo = interfaces.Any(x => x.Name == typeof(IMetaSeo).Name);
|
||||
bool hasMeta = interfaces.Any(x => x.Name == typeof(IMeta).Name);
|
||||
|
||||
Assert.That(hasSeo, Is.True);
|
||||
Assert.That(hasMeta, Is.True);
|
||||
Assert.That(interfaces.Count, Is.EqualTo(3));
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void Can_Get_MixinAttribute_From_Types()
|
||||
{
|
||||
var type = typeof(News);
|
||||
var interfaces = type.GetInterfaces().ToList();
|
||||
|
||||
var list = new List<string>();
|
||||
|
||||
foreach (var interfaceType in interfaces)
|
||||
{
|
||||
var mixinAttribute = interfaceType.FirstAttribute<MixinAttribute>();
|
||||
if(mixinAttribute != null)
|
||||
{
|
||||
var modelType = mixinAttribute.Type;
|
||||
var contentTypeAttribute = modelType.FirstAttribute<ContentTypeAttribute>();
|
||||
var contentTypeAlias = contentTypeAttribute == null ? modelType.Name.ToUmbracoAlias() : contentTypeAttribute.Alias;
|
||||
list.Add(contentTypeAlias);
|
||||
}
|
||||
}
|
||||
|
||||
Assert.That(list.Count, Is.EqualTo(2));
|
||||
Assert.That(list.Any(x => x == "meta"), Is.True);
|
||||
Assert.That(list.Any(x => x == "seo"), Is.True);
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void Ensure_Only_One_Type_List_Created()
|
||||
{
|
||||
var foundTypes = PluginManager.Current.ResolveContentTypeBaseTypes();
|
||||
|
||||
Assert.That(foundTypes.Count(), Is.EqualTo(13));
|
||||
Assert.AreEqual(1,
|
||||
PluginManager.Current.GetTypeLists()
|
||||
.Count(x => x.IsTypeList<ContentTypeBase>(PluginManager.TypeResolutionKind.FindAllTypes)));
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -101,6 +101,7 @@
|
||||
<Compile Include="CodeFirst\Attributes\AliasAttribute.cs" />
|
||||
<Compile Include="CodeFirst\Attributes\ContentTypeAttribute.cs" />
|
||||
<Compile Include="CodeFirst\Attributes\DescriptionAttribute.cs" />
|
||||
<Compile Include="CodeFirst\Attributes\MixinAttribute.cs" />
|
||||
<Compile Include="CodeFirst\Attributes\Numeric.cs" />
|
||||
<Compile Include="CodeFirst\Attributes\PropertyTypeAttribute.cs" />
|
||||
<Compile Include="CodeFirst\Attributes\PropertyTypeConventionAttribute.cs" />
|
||||
@@ -113,11 +114,12 @@
|
||||
<Compile Include="CodeFirst\Definitions\DependencyField.cs" />
|
||||
<Compile Include="CodeFirst\Definitions\PropertyDefinition.cs" />
|
||||
<Compile Include="CodeFirst\Mvc\UmbracoTemplatePage`T.cs" />
|
||||
<Compile Include="CodeFirst\PluginManagerExtensions.cs" />
|
||||
<Compile Include="CodeFirst\TestModels\AdvancedContentPage.cs" />
|
||||
<Compile Include="CodeFirst\TestModels\Composition\Base.cs" />
|
||||
<Compile Include="CodeFirst\TestModels\Composition\Meta.cs" />
|
||||
<Compile Include="CodeFirst\TestModels\Composition\News.cs" />
|
||||
<Compile Include="CodeFirst\TestModels\Composition\Seo.cs" />
|
||||
<Compile Include="CodeFirst\TestModels\Composition\MetaSeo.cs" />
|
||||
<Compile Include="CodeFirst\TestModels\ContentPage.cs" />
|
||||
<Compile Include="CodeFirst\TestModels\DecoratedModelPage.cs" />
|
||||
<Compile Include="CodeFirst\TestModels\Home.cs" />
|
||||
|
||||
Reference in New Issue
Block a user