Files
Umbraco-CMS/src/Umbraco.Tests/Published/NestedContentTests.cs

310 lines
13 KiB
C#
Raw Normal View History

2017-09-26 14:57:50 +02:00
using System;
2017-10-17 17:43:15 +02:00
using System.Collections;
2017-09-26 14:57:50 +02:00
using System.Collections.Generic;
using System.Linq;
using Moq;
using NUnit.Framework;
using Umbraco.Core;
using Umbraco.Core.Composing;
using Umbraco.Core.Exceptions;
using Umbraco.Core.Logging;
using Umbraco.Core.Models;
using Umbraco.Core.Models.PublishedContent;
using Umbraco.Core.PropertyEditors;
using Umbraco.Tests.TestHelpers;
2017-09-26 14:57:50 +02:00
using Umbraco.Web;
using Umbraco.Web.Models;
2017-10-17 17:43:15 +02:00
using Umbraco.Web.PropertyEditors;
2017-09-26 14:57:50 +02:00
using Umbraco.Web.PropertyEditors.ValueConverters;
using Umbraco.Web.PublishedCache;
2017-10-31 12:48:24 +01:00
namespace Umbraco.Tests.Published
2017-09-26 14:57:50 +02:00
{
[TestFixture]
public class NestedContentTests
{
2019-04-15 13:04:14 +02:00
private (IPublishedContentType, IPublishedContentType) CreateContentTypes()
2017-09-26 14:57:50 +02:00
{
Current.Reset();
var logger = Mock.Of<ILogger>();
var profiler = Mock.Of<IProfiler>();
var proflog = new ProfilingLogger(logger, profiler);
2018-02-07 13:35:59 +01:00
PropertyEditorCollection editors = null;
var editor = new NestedContentPropertyEditor(logger, new Lazy<PropertyEditorCollection>(() => editors));
2018-02-25 10:43:16 +01:00
editors = new PropertyEditorCollection(new DataEditorCollection(new DataEditor[] { editor }));
2018-02-07 13:35:59 +01:00
var dataType1 = new DataType(editor)
2018-01-26 17:55:20 +01:00
{
2018-02-07 13:35:59 +01:00
Id = 1,
2018-01-26 17:55:20 +01:00
Configuration = new NestedContentConfiguration
{
MinItems = 1,
MaxItems = 1,
2018-01-26 17:55:20 +01:00
ContentTypes = new[]
{
new NestedContentConfiguration.ContentType { Alias = "contentN1" }
}
}
};
2018-02-07 13:35:59 +01:00
var dataType2 = new DataType(editor)
2018-01-26 17:55:20 +01:00
{
2018-02-07 13:35:59 +01:00
Id = 2,
2018-01-26 17:55:20 +01:00
Configuration = new NestedContentConfiguration
{
MinItems = 1,
MaxItems = 99,
ContentTypes = new[]
{
new NestedContentConfiguration.ContentType { Alias = "contentN1" }
}
}
};
2017-09-26 14:57:50 +02:00
var dataType3 = new DataType(new TextboxPropertyEditor(logger))
{
Id = 3
};
2018-01-26 17:55:20 +01:00
// mocked dataservice returns nested content preValues
var dataTypeService = new TestObjects.TestDataTypeService(dataType1, dataType2, dataType3);
2017-09-26 14:57:50 +02:00
var publishedModelFactory = new Mock<IPublishedModelFactory>();
// mocked model factory returns model type
var modelTypes = new Dictionary<string, Type>
{
{ "contentN1", typeof(TestElementModel) }
};
2017-09-26 14:57:50 +02:00
publishedModelFactory
.Setup(x => x.MapModelType(It.IsAny<Type>()))
.Returns((Type type) => ModelType.Map(type, modelTypes));
2017-09-26 14:57:50 +02:00
// mocked model factory creates models
publishedModelFactory
.Setup(x => x.CreateModel(It.IsAny<IPublishedElement>()))
.Returns((IPublishedElement element) =>
{
if (element.ContentType.Alias.InvariantEquals("contentN1"))
2017-09-29 15:51:33 +02:00
return new TestElementModel(element);
2017-09-26 14:57:50 +02:00
return element;
});
2017-10-17 17:43:15 +02:00
// mocked model factory creates model lists
publishedModelFactory
.Setup(x => x.CreateModelList(It.IsAny<string>()))
.Returns((string alias) =>
{
return alias == "contentN1"
? (IList) new List<TestElementModel>()
: (IList) new List<IPublishedElement>();
});
2017-09-26 14:57:50 +02:00
var contentCache = new Mock<IPublishedContentCache>();
2018-04-27 11:38:50 +10:00
var publishedSnapshot = new Mock<IPublishedSnapshot>();
2017-09-26 14:57:50 +02:00
2017-10-31 12:48:24 +01:00
// mocked published snapshot returns a content cache
publishedSnapshot
2017-10-31 12:50:30 +01:00
.Setup(x => x.Content)
2017-09-26 14:57:50 +02:00
.Returns(contentCache.Object);
2017-10-31 12:48:24 +01:00
var publishedSnapshotAccessor = new Mock<IPublishedSnapshotAccessor>();
2017-09-26 14:57:50 +02:00
2017-10-31 12:48:24 +01:00
// mocked published snapshot accessor returns a facade
publishedSnapshotAccessor
.Setup(x => x.PublishedSnapshot)
.Returns(publishedSnapshot.Object);
2017-09-26 14:57:50 +02:00
var converters = new PropertyValueConverterCollection(new IPropertyValueConverter[]
{
2017-10-31 12:48:24 +01:00
new NestedContentSingleValueConverter(publishedSnapshotAccessor.Object, publishedModelFactory.Object, proflog),
new NestedContentManyValueConverter(publishedSnapshotAccessor.Object, publishedModelFactory.Object, proflog),
2017-09-26 14:57:50 +02:00
});
var factory = new PublishedContentTypeFactory(publishedModelFactory.Object, converters, dataTypeService);
2017-10-17 17:43:15 +02:00
2019-04-15 17:14:45 +02:00
IEnumerable<IPublishedPropertyType> CreatePropertyTypes1(IPublishedContentType contentType)
{
yield return factory.CreatePropertyType(contentType, "property1", 1);
}
IEnumerable<IPublishedPropertyType> CreatePropertyTypes2(IPublishedContentType contentType)
{
yield return factory.CreatePropertyType(contentType, "property2", 2);
}
IEnumerable<IPublishedPropertyType> CreatePropertyTypesN1(IPublishedContentType contentType)
{
yield return factory.CreatePropertyType(contentType, "propertyN1", 3);
}
2017-09-26 14:57:50 +02:00
2019-04-15 17:14:45 +02:00
var contentType1 = factory.CreateContentType(1, "content1", CreatePropertyTypes1);
var contentType2 = factory.CreateContentType(2, "content2", CreatePropertyTypes2);
var contentTypeN1 = factory.CreateContentType(2, "contentN1", CreatePropertyTypesN1, isElement: true);
2017-09-26 14:57:50 +02:00
// mocked content cache returns content types
contentCache
.Setup(x => x.GetContentType(It.IsAny<string>()))
.Returns((string alias) =>
{
if (alias.InvariantEquals("contentN1")) return contentTypeN1;
return null;
});
return (contentType1, contentType2);
}
[Test]
public void SingleNestedTest()
{
(var contentType1, _) = CreateContentTypes();
// nested single converter returns the proper value clr type TestModel, and cache level
2017-09-29 15:51:33 +02:00
Assert.AreEqual(typeof (TestElementModel), contentType1.GetPropertyType("property1").ClrType);
2017-10-31 12:48:24 +01:00
Assert.AreEqual(PropertyCacheLevel.Element, contentType1.GetPropertyType("property1").CacheLevel);
2017-09-26 14:57:50 +02:00
var key = Guid.NewGuid();
var keyA = Guid.NewGuid();
var content = new TestPublishedContent(contentType1, key, new[]
{
new TestPublishedProperty(contentType1.GetPropertyType("property1"), $@"[
{{ ""key"": ""{keyA}"", ""propertyN1"": ""foo"", ""ncContentTypeAlias"": ""contentN1"" }}
]")
}, Mock.Of<IUmbracoContextAccessor>());
2017-09-26 14:57:50 +02:00
var value = content.Value("property1");
// nested single converter returns proper TestModel value
2017-09-29 15:51:33 +02:00
Assert.IsInstanceOf<TestElementModel>(value);
var valueM = (TestElementModel) value;
2017-09-26 14:57:50 +02:00
Assert.AreEqual("foo", valueM.PropValue);
Assert.AreEqual(keyA, valueM.Key);
}
[Test]
public void ManyNestedTest()
{
(_, var contentType2) = CreateContentTypes();
// nested many converter returns the proper value clr type IEnumerable<TestModel>, and cache level
2017-09-29 15:51:33 +02:00
Assert.AreEqual(typeof (IEnumerable<TestElementModel>), contentType2.GetPropertyType("property2").ClrType);
2017-10-31 12:48:24 +01:00
Assert.AreEqual(PropertyCacheLevel.Element, contentType2.GetPropertyType("property2").CacheLevel);
2017-09-26 14:57:50 +02:00
var key = Guid.NewGuid();
var keyA = Guid.NewGuid();
var keyB = Guid.NewGuid();
var content = new TestPublishedContent(contentType2, key, new[]
{
new TestPublishedProperty(contentType2.GetPropertyType("property2"), $@"[
{{ ""key"": ""{keyA}"", ""propertyN1"": ""foo"", ""ncContentTypeAlias"": ""contentN1"" }},
{{ ""key"": ""{keyB}"", ""propertyN1"": ""bar"", ""ncContentTypeAlias"": ""contentN1"" }}
]")
},
Mock.Of<IUmbracoContextAccessor>());
2017-09-26 14:57:50 +02:00
var value = content.Value("property2");
// nested many converter returns proper IEnumerable<TestModel> value
Assert.IsInstanceOf<IEnumerable<IPublishedElement>>(value);
2017-09-29 15:51:33 +02:00
Assert.IsInstanceOf<IEnumerable<TestElementModel>>(value);
var valueM = ((IEnumerable<TestElementModel>) value).ToArray();
2017-09-26 14:57:50 +02:00
Assert.AreEqual("foo", valueM[0].PropValue);
Assert.AreEqual(keyA, valueM[0].Key);
Assert.AreEqual("bar", valueM[1].PropValue);
Assert.AreEqual(keyB, valueM[1].Key);
}
2017-09-29 15:51:33 +02:00
public class TestElementModel : PublishedElementModel
2017-09-26 14:57:50 +02:00
{
2017-09-29 15:51:33 +02:00
public TestElementModel(IPublishedElement content)
2017-09-26 14:57:50 +02:00
: base(content)
{ }
public string PropValue => this.Value<string>("propertyN1");
}
class TestPublishedProperty : PublishedPropertyBase
{
private readonly bool _preview;
2017-12-06 11:51:35 +01:00
private readonly object _sourceValue;
private readonly bool _hasValue;
2017-09-26 14:57:50 +02:00
private IPublishedElement _owner;
2019-04-15 17:14:45 +02:00
public TestPublishedProperty(IPublishedPropertyType propertyType, object source)
2017-10-31 12:48:24 +01:00
: base(propertyType, PropertyCacheLevel.Element) // initial reference cache level always is .Content
2017-09-26 14:57:50 +02:00
{
2017-12-06 11:51:35 +01:00
_sourceValue = source;
_hasValue = source != null && (!(source is string ssource) || !string.IsNullOrWhiteSpace(ssource));
2017-09-26 14:57:50 +02:00
}
2019-04-15 17:14:45 +02:00
public TestPublishedProperty(IPublishedPropertyType propertyType, IPublishedElement element, bool preview, PropertyCacheLevel referenceCacheLevel, object source)
2017-09-26 14:57:50 +02:00
: base(propertyType, referenceCacheLevel)
{
2017-12-06 11:51:35 +01:00
_sourceValue = source;
_hasValue = source != null && (!(source is string ssource) || !string.IsNullOrWhiteSpace(ssource));
2017-09-26 14:57:50 +02:00
_owner = element;
_preview = preview;
}
2017-12-06 11:51:35 +01:00
private object InterValue => PropertyType.ConvertSourceToInter(null, _sourceValue, false);
2017-09-26 14:57:50 +02:00
internal void SetOwner(IPublishedElement owner)
{
_owner = owner;
}
public override bool HasValue(string culture = null, string segment = null) => _hasValue;
public override object GetSourceValue(string culture = null, string segment = null) => _sourceValue;
public override object GetValue(string culture = null, string segment = null) => PropertyType.ConvertInterToObject(_owner, ReferenceCacheLevel, InterValue, _preview);
public override object GetXPathValue(string culture = null, string segment = null) => throw new WontImplementException();
2017-09-26 14:57:50 +02:00
}
class TestPublishedContent : PublishedContentBase
{
2019-04-15 13:04:14 +02:00
public TestPublishedContent(IPublishedContentType contentType, Guid key, IEnumerable<TestPublishedProperty> properties, IUmbracoContextAccessor umbracoContextAccessor): base(umbracoContextAccessor)
2017-09-26 14:57:50 +02:00
{
ContentType = contentType;
Key = key;
var propertiesA = properties.ToArray();
Properties = propertiesA;
foreach (var property in propertiesA)
property.SetOwner(this);
}
// ReSharper disable UnassignedGetOnlyAutoProperty
public override PublishedItemType ItemType { get; }
public override bool IsDraft(string culture = null) => false;
public override bool IsPublished(string culture = null) => true;
2017-09-26 14:57:50 +02:00
public override IPublishedContent Parent { get; }
public override IEnumerable<IPublishedContent> Children { get; }
2019-04-15 13:04:14 +02:00
public override IPublishedContentType ContentType { get; }
2017-09-26 14:57:50 +02:00
// ReSharper restore UnassignedGetOnlyAutoProperty
// ReSharper disable UnassignedGetOnlyAutoProperty
public override int Id { get; }
public override int? TemplateId { get; }
2017-09-26 14:57:50 +02:00
public override int SortOrder { get; }
public override string Name { get; }
public override PublishedCultureInfo GetCulture(string culture = ".") => throw new NotSupportedException();
public override IReadOnlyDictionary<string, PublishedCultureInfo> Cultures => throw new NotSupportedException();
2018-04-28 16:35:33 +02:00
public override string UrlSegment { get; }
2017-09-26 14:57:50 +02:00
public override string WriterName { get; }
public override string CreatorName { get; }
public override int WriterId { get; }
public override int CreatorId { get; }
public override string Path { get; }
public override DateTime CreateDate { get; }
public override DateTime UpdateDate { get; }
public override int Level { get; }
public override Guid Key { get; }
// ReSharper restore UnassignedGetOnlyAutoProperty
public override IEnumerable<IPublishedProperty> Properties { get; }
public override IPublishedProperty GetProperty(string alias)
{
return Properties.FirstOrDefault(x => x.Alias.InvariantEquals(alias));
2017-09-26 14:57:50 +02:00
}
}
}
}