diff --git a/app/Umbraco/Archetype.Tests/Archetype.Tests.csproj b/app/Umbraco/Archetype.Tests/Archetype.Tests.csproj index f0dc847..a9cd9c2 100644 --- a/app/Umbraco/Archetype.Tests/Archetype.Tests.csproj +++ b/app/Umbraco/Archetype.Tests/Archetype.Tests.csproj @@ -1,251 +1,271 @@ - - - - - Debug - AnyCPU - {21F3E6CF-B76F-4059-9474-1AF1CE63CD6B} - Library - Properties - Archetype.Tests - Archetype.Tests - v4.5 - 512 - ..\ - - - true - full - false - bin\Debug\ - DEBUG;TRACE - prompt - 4 - - - pdbonly - true - bin\Release\ - TRACE - prompt - 4 - - - - ..\packages\AutoMapper.3.0.0\lib\net40\AutoMapper.dll - - - ..\packages\AutoMapper.3.0.0\lib\net40\AutoMapper.Net4.dll - - - False - ..\packages\UmbracoCms.Core.7.1.2\lib\businesslogic.dll - - - ..\packages\ClientDependency.1.7.1.2\lib\ClientDependency.Core.dll - - - ..\packages\ClientDependency-Mvc.1.7.0.4\lib\ClientDependency.Core.Mvc.dll - - - False - ..\packages\UmbracoCms.Core.7.1.2\lib\cms.dll - - - False - ..\packages\UmbracoCms.Core.7.1.2\lib\controls.dll - - - ..\packages\xmlrpcnet.2.5.0\lib\net20\CookComputing.XmlRpcV2.dll - - - False - ..\packages\UmbracoCms.Core.7.1.2\lib\Examine.dll - - - ..\packages\HtmlAgilityPack.1.4.6\lib\Net45\HtmlAgilityPack.dll - - - ..\packages\SharpZipLib.0.86.0\lib\20\ICSharpCode.SharpZipLib.dll - - - False - ..\packages\ImageProcessor.1.9.0.0\lib\ImageProcessor.dll - - - False - ..\packages\ImageProcessor.Web.3.2.3.0\lib\net45\ImageProcessor.Web.dll - - - False - ..\packages\UmbracoCms.Core.7.1.2\lib\interfaces.dll - - - False - ..\packages\UmbracoCms.Core.7.1.2\lib\log4net.dll - - - ..\packages\Lucene.Net.2.9.4.1\lib\net40\Lucene.Net.dll - - - False - ..\packages\UmbracoCms.Core.7.1.2\lib\Microsoft.ApplicationBlocks.Data.dll - - - False - ..\packages\UmbracoCms.Core.7.1.2\lib\Microsoft.Web.Helpers.dll - - - True - ..\packages\Microsoft.Web.Infrastructure.1.0.0.0\lib\net40\Microsoft.Web.Infrastructure.dll - - - ..\packages\Microsoft.AspNet.Mvc.FixedDisplayModes.1.0.1\lib\net40\Microsoft.Web.Mvc.FixedDisplayModes.dll - - - ..\packages\MiniProfiler.2.1.0\lib\net40\MiniProfiler.dll - - - ..\packages\Moq.4.2.1312.1622\lib\net40\Moq.dll - - - ..\packages\MySql.Data.6.6.5\lib\net40\MySql.Data.dll - - - False - ..\packages\Newtonsoft.Json.6.0.2\lib\net45\Newtonsoft.Json.dll - - - ..\packages\NUnit.2.6.3\lib\nunit.framework.dll - - - False - ..\packages\UmbracoCms.Core.7.1.2\lib\SQLCE4Umbraco.dll - - - - - True - ..\packages\UmbracoCms.Core.7.1.2\lib\System.Data.SqlServerCe.dll - - - True - ..\packages\UmbracoCms.Core.7.1.2\lib\System.Data.SqlServerCe.Entity.dll - - - - ..\packages\Microsoft.AspNet.WebApi.Client.4.0.30506.0\lib\net40\System.Net.Http.Formatting.dll - - - - True - ..\packages\Microsoft.AspNet.WebPages.2.0.30506.0\lib\net40\System.Web.Helpers.dll - - - ..\packages\Microsoft.AspNet.WebApi.Core.4.0.30506.0\lib\net40\System.Web.Http.dll - - - ..\packages\Microsoft.AspNet.WebApi.WebHost.4.0.30506.0\lib\net40\System.Web.Http.WebHost.dll - - - True - ..\packages\Microsoft.AspNet.Mvc.4.0.30506.0\lib\net40\System.Web.Mvc.dll - - - False - ..\packages\Microsoft.AspNet.Razor.2.0.30506.0\lib\net40\System.Web.Razor.dll - True - - - True - ..\packages\Microsoft.AspNet.WebPages.2.0.30506.0\lib\net40\System.Web.WebPages.dll - - - True - ..\packages\Microsoft.AspNet.WebPages.2.0.30506.0\lib\net40\System.Web.WebPages.Deployment.dll - - - True - ..\packages\Microsoft.AspNet.WebPages.2.0.30506.0\lib\net40\System.Web.WebPages.Razor.dll - - - - - - - - False - ..\packages\UmbracoCms.Core.7.1.2\lib\TidyNet.dll - - - False - ..\packages\UmbracoCms.Core.7.1.2\lib\umbraco.dll - - - False - ..\packages\UmbracoCms.Core.7.1.2\lib\Umbraco.Core.dll - - - False - ..\packages\UmbracoCms.Core.7.1.2\lib\umbraco.DataLayer.dll - - - False - ..\packages\UmbracoCms.Core.7.1.2\lib\umbraco.editorControls.dll - - - False - ..\packages\UmbracoCms.Core.7.1.2\lib\umbraco.MacroEngines.dll - - - False - ..\packages\UmbracoCms.Core.7.1.2\lib\umbraco.providers.dll - - - False - ..\packages\UmbracoCms.Core.7.1.2\lib\Umbraco.Web.UI.dll - - - False - ..\packages\UmbracoCms.Core.7.1.2\lib\umbraco.XmlSerializers.dll - - - False - ..\packages\UmbracoCms.Core.7.1.2\lib\UmbracoExamine.dll - - - False - ..\packages\UmbracoCms.Core.7.1.2\lib\UrlRewritingNet.UrlRewriter.dll - - - - - - - - - - - - - - - - - - - {7D185D41-4228-4978-ACB8-83F9A48AD94F} - Archetype.Umbraco - - - - - - + + + + + Debug + AnyCPU + {21F3E6CF-B76F-4059-9474-1AF1CE63CD6B} + Library + Properties + Archetype.Tests + Archetype.Tests + v4.5 + 512 + ..\ + + + true + full + false + bin\Debug\ + DEBUG;TRACE + prompt + 4 + + + pdbonly + true + bin\Release\ + TRACE + prompt + 4 + + + + ..\packages\AutoMapper.3.0.0\lib\net40\AutoMapper.dll + + + ..\packages\AutoMapper.3.0.0\lib\net40\AutoMapper.Net4.dll + + + False + ..\packages\UmbracoCms.Core.7.1.2\lib\businesslogic.dll + + + ..\packages\ClientDependency.1.7.1.2\lib\ClientDependency.Core.dll + + + ..\packages\ClientDependency-Mvc.1.7.0.4\lib\ClientDependency.Core.Mvc.dll + + + False + ..\packages\UmbracoCms.Core.7.1.2\lib\cms.dll + + + False + ..\packages\UmbracoCms.Core.7.1.2\lib\controls.dll + + + ..\packages\xmlrpcnet.2.5.0\lib\net20\CookComputing.XmlRpcV2.dll + + + False + ..\packages\UmbracoCms.Core.7.1.2\lib\Examine.dll + + + ..\packages\HtmlAgilityPack.1.4.6\lib\Net45\HtmlAgilityPack.dll + + + ..\packages\SharpZipLib.0.86.0\lib\20\ICSharpCode.SharpZipLib.dll + + + False + ..\packages\ImageProcessor.1.9.0.0\lib\ImageProcessor.dll + + + False + ..\packages\ImageProcessor.Web.3.2.3.0\lib\net45\ImageProcessor.Web.dll + + + False + ..\packages\UmbracoCms.Core.7.1.2\lib\interfaces.dll + + + False + ..\packages\UmbracoCms.Core.7.1.2\lib\log4net.dll + + + ..\packages\Lucene.Net.2.9.4.1\lib\net40\Lucene.Net.dll + + + False + ..\packages\UmbracoCms.Core.7.1.2\lib\Microsoft.ApplicationBlocks.Data.dll + + + False + ..\packages\UmbracoCms.Core.7.1.2\lib\Microsoft.Web.Helpers.dll + + + True + ..\packages\Microsoft.Web.Infrastructure.1.0.0.0\lib\net40\Microsoft.Web.Infrastructure.dll + + + ..\packages\Microsoft.AspNet.Mvc.FixedDisplayModes.1.0.1\lib\net40\Microsoft.Web.Mvc.FixedDisplayModes.dll + + + ..\packages\MiniProfiler.2.1.0\lib\net40\MiniProfiler.dll + + + ..\packages\Moq.4.2.1312.1622\lib\net40\Moq.dll + + + ..\packages\MySql.Data.6.6.5\lib\net40\MySql.Data.dll + + + False + ..\packages\Newtonsoft.Json.6.0.2\lib\net45\Newtonsoft.Json.dll + + + ..\packages\NUnit.2.6.3\lib\nunit.framework.dll + + + False + ..\packages\UmbracoCms.Core.7.1.2\lib\SQLCE4Umbraco.dll + + + + + True + ..\packages\UmbracoCms.Core.7.1.2\lib\System.Data.SqlServerCe.dll + + + True + ..\packages\UmbracoCms.Core.7.1.2\lib\System.Data.SqlServerCe.Entity.dll + + + + ..\packages\Microsoft.AspNet.WebApi.Client.4.0.30506.0\lib\net40\System.Net.Http.Formatting.dll + + + + True + ..\packages\Microsoft.AspNet.WebPages.2.0.30506.0\lib\net40\System.Web.Helpers.dll + + + ..\packages\Microsoft.AspNet.WebApi.Core.4.0.30506.0\lib\net40\System.Web.Http.dll + + + ..\packages\Microsoft.AspNet.WebApi.WebHost.4.0.30506.0\lib\net40\System.Web.Http.WebHost.dll + + + True + ..\packages\Microsoft.AspNet.Mvc.4.0.30506.0\lib\net40\System.Web.Mvc.dll + + + False + ..\packages\Microsoft.AspNet.Razor.2.0.30506.0\lib\net40\System.Web.Razor.dll + True + + + True + ..\packages\Microsoft.AspNet.WebPages.2.0.30506.0\lib\net40\System.Web.WebPages.dll + + + True + ..\packages\Microsoft.AspNet.WebPages.2.0.30506.0\lib\net40\System.Web.WebPages.Deployment.dll + + + True + ..\packages\Microsoft.AspNet.WebPages.2.0.30506.0\lib\net40\System.Web.WebPages.Razor.dll + + + + + + + + False + ..\packages\UmbracoCms.Core.7.1.2\lib\TidyNet.dll + + + False + ..\packages\UmbracoCms.Core.7.1.2\lib\umbraco.dll + + + False + ..\packages\UmbracoCms.Core.7.1.2\lib\Umbraco.Core.dll + + + False + ..\packages\UmbracoCms.Core.7.1.2\lib\umbraco.DataLayer.dll + + + False + ..\packages\UmbracoCms.Core.7.1.2\lib\umbraco.editorControls.dll + + + False + ..\packages\UmbracoCms.Core.7.1.2\lib\umbraco.MacroEngines.dll + + + False + ..\packages\UmbracoCms.Core.7.1.2\lib\umbraco.providers.dll + + + False + ..\packages\UmbracoCms.Core.7.1.2\lib\Umbraco.Web.UI.dll + + + False + ..\packages\UmbracoCms.Core.7.1.2\lib\umbraco.XmlSerializers.dll + + + False + ..\packages\UmbracoCms.Core.7.1.2\lib\UmbracoExamine.dll + + + False + ..\packages\UmbracoCms.Core.7.1.2\lib\UrlRewritingNet.UrlRewriter.dll + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + {7D185D41-4228-4978-ACB8-83F9A48AD94F} + Archetype.Umbraco + + + + + + + + + + + xcopy $(ProjectDir)SupportingFiles\config\* $(TargetDir)config /I /O /X /E /K /D /Y + + \ No newline at end of file diff --git a/app/Umbraco/Archetype.Tests/Serialization/Base/ArchetypeJsonConverterTestBase.cs b/app/Umbraco/Archetype.Tests/Serialization/Base/ArchetypeJsonConverterTestBase.cs new file mode 100644 index 0000000..d8b0d08 --- /dev/null +++ b/app/Umbraco/Archetype.Tests/Serialization/Base/ArchetypeJsonConverterTestBase.cs @@ -0,0 +1,33 @@ +using Archetype.PropertyConverters; +using at = Archetype.Models; +using Newtonsoft.Json; + +namespace Archetype.Tests.Serialization.Base +{ + public abstract class ArchetypeJsonConverterTestBase + { + public at.ArchetypeModel ConvertModelToArchetype(T model) + { + var converter = new ArchetypeValueConverter(); + var json = JsonConvert.SerializeObject(model); + var archetype = (at.ArchetypeModel)converter.ConvertDataToSource(null, json, false); + return archetype; + } + + public string ConvertModelToArchetypeJson(T model, Formatting formatting = Formatting.None) + { + return JsonConvert.SerializeObject(model, formatting); + } + + public T ConvertArchetypeJsonToModel(string json) + { + return JsonConvert.DeserializeObject(json); + } + + public T ConvertModelToArchetypeAndBack(T model) + { + var json = ConvertModelToArchetypeJson(model); + return ConvertArchetypeJsonToModel(json); + } + } +} diff --git a/app/Umbraco/Archetype.Tests/Serialization/Base/RegressionTestBase.cs b/app/Umbraco/Archetype.Tests/Serialization/Base/RegressionTestBase.cs new file mode 100644 index 0000000..db9b84b --- /dev/null +++ b/app/Umbraco/Archetype.Tests/Serialization/Base/RegressionTestBase.cs @@ -0,0 +1,166 @@ +using System.Collections; +using System.Linq; +using System.Reflection; +using Archetype.Serialization; +using Moq; +using Newtonsoft.Json; +using NUnit.Framework; +using Umbraco.Core; +using Umbraco.Core.Persistence; +using Umbraco.Core.Services; + +namespace Archetype.Tests.Serialization.Base +{ + public abstract class RegressionTestBase : ArchetypeJsonConverterTestBase + { + protected void SimpleModel_Regression_Battery(T model) + { + var archetype = ConvertModelToArchetype(model); + Assert.IsNotNull(archetype); + + var archetypeJson = archetype.SerializeForPersistence(); + var modelJson = ConvertModelToArchetypeJson(model, Formatting.Indented); + + Assert.IsNotNullOrEmpty(modelJson); + + var result = ConvertModelToArchetypeAndBack(model); + var resultfromArchetypeJson = ConvertArchetypeJsonToModel(archetypeJson); + + Assert.IsInstanceOf(result); + Assert.IsInstanceOf(resultfromArchetypeJson); + AssertAreEqual(model, result); + AssertAreEqual(model, resultfromArchetypeJson); + } + + protected void SimpleModels_Regression_Battery(T model) + where T : IList + { + var archetype = ConvertModelToArchetype(model); + Assert.IsNotNull(archetype); + + var archetypeJson = archetype.SerializeForPersistence(); + var modelJson = ConvertModelToArchetypeJson(model, Formatting.Indented); + + Assert.IsNotNullOrEmpty(modelJson); + + var result = ConvertModelToArchetypeAndBack(model); + var resultfromArchetypeJson = ConvertArchetypeJsonToModel(archetypeJson); + + Assert.IsInstanceOf(result); + Assert.IsInstanceOf(resultfromArchetypeJson); + + Assert.AreEqual(model.Count, result.Count); + Assert.AreEqual(model.Count, resultfromArchetypeJson.Count); + + foreach (var resultItem in result) + { + var index = result.IndexOf(resultItem); + AssertAreEqual(model[index], resultItem); + } + + foreach (var resultItem in resultfromArchetypeJson) + { + var index = resultfromArchetypeJson.IndexOf(resultItem); + AssertAreEqual(model[index], resultItem); + } + } + + protected void CompoundModel_Regression_Battery(T model) + { + var archetype = ConvertModelToArchetype(model); + Assert.IsNotNull(archetype); + + var archetypeJson = archetype.SerializeForPersistence(); + var modelJson = ConvertModelToArchetypeJson(model, Formatting.Indented); + + Assert.IsNotNullOrEmpty(modelJson); + + var result = ConvertModelToArchetypeAndBack(model); + var resultfromArchetypeJson = ConvertArchetypeJsonToModel(archetypeJson); + + Assert.IsInstanceOf(result); + AssertAreEqual(model, result); + + Assert.IsInstanceOf(resultfromArchetypeJson); + AssertAreEqual(model, resultfromArchetypeJson); + } + + protected void NestedModel_Regression_Battery(T model) + { + CompoundModel_Regression_Battery(model); + } + + protected void ComplexModel_Regression_Battery(T model) + { + CompoundModel_Regression_Battery(model); + } + + protected void AssertAreEqual(T model, T result) + { + foreach (var propInfo in model.GetSerialiazableProperties()) + { + var expected = GetExpectedValue(model, propInfo); + var actual = GetActualValue(result, propInfo); + + if (propInfo.PropertyType.Namespace.Equals("System")) + { + Assert.AreEqual(expected, actual); + continue; + } + + var list = expected as IList; + if (list != null) + { + foreach (var expectedItem in list) + { + var index = list.IndexOf(expectedItem); + AssertAreEqual(expectedItem, ((IList)actual)[index]); + } + continue; + } + + AssertAreEqual(expected, actual); + } + } + + protected void EnsureUmbracoContext(Mock dataTypeService) + { + var cacheHelper = CacheHelper.CreateDisabledCacheHelper(); + var serviceContext = new ServiceContext( + Mock.Of(), + Mock.Of(), + Mock.Of(), + dataTypeService.Object, + Mock.Of(), + Mock.Of(), + Mock.Of(), + Mock.Of(), + Mock.Of(), + Mock.Of(), + Mock.Of(), + Mock.Of(), + Mock.Of(), + Mock.Of(), + Mock.Of(), + Mock.Of(), + Mock.Of() + ); + + ApplicationContext.EnsureContext( + new DatabaseContext(Mock.Of()), serviceContext, cacheHelper, true); + } + + private object GetExpectedValue(T expected, PropertyInfo propInfo) + { + return propInfo.GetValue(expected, null); + } + + private object GetActualValue(T actual, PropertyInfo propInfo) + { + var actualProp = actual.GetSerialiazableProperties().SingleOrDefault(pinfo => pinfo.Name.Equals(propInfo.Name)); + return actualProp != null + ? actualProp.GetValue(actual, null) + : null; + } + } +} diff --git a/app/Umbraco/Archetype.Tests/Serialization/Delinter/ArchetypeJsonDelinterTest.cs b/app/Umbraco/Archetype.Tests/Serialization/Delinter/ArchetypeJsonDelinterTest.cs new file mode 100644 index 0000000..dcb02a4 --- /dev/null +++ b/app/Umbraco/Archetype.Tests/Serialization/Delinter/ArchetypeJsonDelinterTest.cs @@ -0,0 +1,253 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using Archetype.PropertyEditors; +using Archetype.Serialization; +using Archetype.Tests.Serialization.Base; +using Moq; +using Newtonsoft.Json; +using Newtonsoft.Json.Linq; +using NUnit.Framework; +using Umbraco.Core.Models; +using Umbraco.Core.Models.Editors; +using Umbraco.Core.PropertyEditors; +using Umbraco.Core.Services; + +namespace Archetype.Tests.Serialization.Delinter +{ + [TestFixture] + public class ArchetypeJsonDelinterTest : RegressionTestBase + { + private const string _ESCAPED_JSON = @"{""fieldsets"":[{""properties"":[{""alias"":""slides"",""value"":""2680""}],""alias"":""slides""},{""properties"":[{""alias"":""captions"",""value"":""{\""fieldsets\"":[{\""properties\"":[{\""alias\"":\""textstring\"",\""value\"":\""test1 test1\""}],\""alias\"":\""textstringArray\""},{\""properties\"":[{\""alias\"":\""textstring\"",\""value\"":\""test2 test2\""}],\""alias\"":\""textstringArray\""},{\""properties\"":[{\""alias\"":\""textstring\"",\""value\"":\""test3b test3b\""}],\""alias\"":\""textstringArray\""}]}""}],""alias"":""captions""}]}"; + private const string _JSON = @"{""fieldsets"":[{""properties"":[{""alias"":""slides"",""value"":""2680""}],""alias"":""slides""},{""properties"":[{""alias"":""captions"",""value"":{""fieldsets"":[{""properties"":[{""alias"":""textstring"",""value"":""test1 test1""}],""alias"":""textstringArray""},{""properties"":[{""alias"":""textstring"",""value"":""test2 test2""}],""alias"":""textstringArray""},{""properties"":[{""alias"":""textstring"",""value"":""test3b test3b""}],""alias"":""textstringArray""}]}}],""alias"":""captions""}]}"; + private const string _ESCAPED_JSON_DEEP_NESTED = @"{""fieldsets"":[{""properties"":[{""alias"":""pages"",""value"":""""},{""alias"":""captions"",""value"":""{\""fieldsets\"":[{\""properties\"":[{\""alias\"":\""captions\"",\""value\"":\""{\\\""fieldsets\\\"":[{\\\""properties\\\"":[{\\\""alias\\\"":\\\""textString\\\"",\\\""value\\\"":\\\""{\\\\\\\""fieldsets\\\\\\\"":[{\\\\\\\""properties\\\\\\\"":[{\\\\\\\""alias\\\\\\\"":\\\\\\\""textString\\\\\\\"",\\\\\\\""value\\\\\\\"":\\\\\\\""\\\\\\\""}],\\\\\\\""alias\\\\\\\"":\\\\\\\""textItem\\\\\\\""}]}\\\""}],\\\""alias\\\"":\\\""textList\\\""}]}\""}],\""alias\"":\""captions\""}]}""}],""alias"":""pages""}]}"; + private const string _ESCAPED_JSON_FROM_APP = @"{ + ""alias"": ""captions"", + ""value"": ""{\""fieldsets\"":[{\""properties\"":[{\""alias\"":\""textstring\"",\""value\"":\""test1 test1\""}],\""alias\"":\""textstringArray\""},{\""properties\"":[{\""alias\"":\""textstring\"",\""value\"":\""test2 test2\""}],\""alias\"":\""textstringArray\""},{\""properties\"":[{\""alias\"":\""textstring\"",\""value\"":\""test3b test3b\""}],\""alias\"":\""textstringArray\""}]}"" +}"; + + private SlideShow _referenceModel; + private NestedClass _nestedClass; + + [SetUp] + public void SetUp() + { + _referenceModel = new SlideShow() + { + Slides = "2680", + Captions = new Captions() + { + new TextString(){Text = "test1 test1"}, + new TextString(){Text = "test2 test2"}, + new TextString(){Text = "test3b test3b"} + } + }; + + _nestedClass = GetNestedClass(); + _nestedClass.SlideShow = _referenceModel; + _nestedClass.Nested = GetNestedClass(); + _nestedClass.Nested.SlideShow = _referenceModel; + _nestedClass.Nested.Nested = GetNestedClass(); + + } + + [Test] + public void Delinter_RemoveNewLine_ByPasses_Values() + { + const string _JSON_WITH_RESERVED_CHARS = @"{ + ""alias"": ""captions"", + ""value"": ""{ \""fieldsets\"": [ +{ + \""properties\"": + [ +{ \""alias\"": \""textstring\"" , \""value\"":\""test1 \r\n test1\r\n\""}], \""alias\"":\""textstringArray\"" },{\""properties\"": [ { \""alias\"":\""textstring\"",\""value\"":\""test2\r\ntest2\""}],\""alias\"":\""textstringArray\""},{\""properties\"":[{\""alias\"":\""textstring\"",\""value\"":\""test3b \""quote\"" \\r\\r\\rtest3\""}],\""alias\"":\""textstringArray\"" } ] }"" +}"; + + var referenceModel = new Captions() + { + new TextString() {Text = @"test1 + test1 +"}, + new TextString() {Text = @"test2 +test2"}, + new TextString() {Text = @"test3b ""quote"" \r\r\rtest3"} + }; + + var delintedJson = _JSON_WITH_RESERVED_CHARS.DelintArchetypeJson(); + var actualModel = ConvertArchetypeJsonToModel(delintedJson); + + var t = JToken.Parse(delintedJson).ToString(Formatting.None); + + Assert.IsInstanceOf(actualModel); + Assert.IsNotNull(actualModel); + + Assert.AreEqual(3, actualModel.Count); + + foreach (var refItem in referenceModel) + { + var index = referenceModel.IndexOf(refItem); + AssertAreEqual(refItem, actualModel.ElementAt(index)); + } + } + + [Test] + public void ReferenceJsonAndModel_Equal_ExpectedJsonAndModel() + { + const string expectedJson = _JSON; + + var expectedModel = ConvertArchetypeJsonToModel(expectedJson); + var referenceModel = ConvertModelToArchetypeAndBack(_referenceModel); + + Assert.IsInstanceOf(expectedModel); + Assert.IsInstanceOf(referenceModel); + + Assert.AreEqual(3, expectedModel.Captions.Count); + Assert.AreEqual(3, referenceModel.Captions.Count); + + AssertAreEqual(expectedModel, referenceModel); + } + + [Test] + public void UnescapedJsonAndModel_Equal_ExpectedJsonAndModel() + { + const string expectedJson = _JSON; + var unescapedJson = _ESCAPED_JSON.DelintArchetypeJson(); + + var expectedModel = ConvertArchetypeJsonToModel(expectedJson); + var actualModel = ConvertArchetypeJsonToModel(unescapedJson); + + Assert.IsInstanceOf(expectedModel); + Assert.IsInstanceOf(actualModel); + + Assert.AreEqual(3, expectedModel.Captions.Count); + Assert.AreEqual(3, actualModel.Captions.Count); + + AssertAreEqual(expectedModel, actualModel); + } + + [Test] + public void EscapedJson_FromApp_SerializesToModel() + { + var delintedJson = _ESCAPED_JSON_FROM_APP.DelintArchetypeJson(); + + var referenceModel = new Captions() + { + new TextString() {Text = "test1 test1"}, + new TextString() {Text = "test2 test2"}, + new TextString() {Text = "test3b test3b"} + }; + + var actualModel = ConvertArchetypeJsonToModel(delintedJson); + + Assert.IsInstanceOf(actualModel); + Assert.AreEqual(3, actualModel.Count); + + foreach (var refItem in referenceModel) + { + var index = referenceModel.IndexOf(refItem); + AssertAreEqual(refItem, actualModel.ElementAt(index)); + } + } + + [Test] + public void DeepNestedJson_Escapes_Correctly() + { + var propGuid = new Guid(); + var dtd = new DataTypeDefinition(-1, String.Empty) { Id = 0 }; + + var dataTypeService = new Mock(); + dataTypeService.Setup(dts => dts.GetDataTypeDefinitionById(Guid.Parse(propGuid.ToString()))).Returns(dtd); + dataTypeService.Setup(dts => dts.GetPreValuesCollectionByDataTypeId(dtd.Id)).Returns(new PreValueCollection(new Dictionary())); + + var propValueEditor = new Mock(new PropertyValueEditor()); + propValueEditor.Setup(pe => pe.GetPropertyEditor(dtd)).Returns(new ArchetypePropertyEditor()); + + var archetype = ConvertModelToArchetype(_nestedClass); + + foreach (var prop in archetype.Fieldsets.SelectMany(fs => fs.Properties)) + { + prop.DataTypeGuid = propGuid.ToString(); + if (prop.Value.ToString().Contains("fieldsets")) + prop.PropertyEditorAlias = Constants.PropertyEditorAlias; + } + + var archetypeJson = JsonConvert.SerializeObject(archetype); + Assert.IsNotNullOrEmpty(archetypeJson); + + EnsureUmbracoContext(dataTypeService); + + var propEditor = new ArchetypePropertyEditor.ArchetypePropertyValueEditor(new PropertyValueEditor()); + var convertedJson = propEditor.ConvertEditorToDb(new ContentPropertyData(JObject.FromObject(archetype), + new PreValueCollection(new Dictionary()), new Dictionary()), + archetypeJson); + + Assert.IsNotNull(convertedJson); + + var delintedJson = convertedJson.ToString().DelintArchetypeJson(); + Assert.IsNotNullOrEmpty(delintedJson); + + var modelfromArchetypeJson = ConvertArchetypeJsonToModel(archetypeJson); + var modelfromConvertedJson = ConvertArchetypeJsonToModel(delintedJson); + + Assert.IsInstanceOf(modelfromArchetypeJson); + Assert.IsInstanceOf(modelfromConvertedJson); + + Assert.AreEqual(3, modelfromArchetypeJson.SlideShow.Captions.Count); + Assert.AreEqual(3, modelfromConvertedJson.SlideShow.Captions.Count); + + Assert.AreEqual(3, modelfromArchetypeJson.Nested.SlideShow.Captions.Count); + Assert.AreEqual(3, modelfromConvertedJson.Nested.SlideShow.Captions.Count); + + AssertAreEqual(modelfromArchetypeJson, modelfromConvertedJson); + + } + + #region private methods + + private NestedClass GetNestedClass() + { + return new NestedClass(); + } + + #endregion + + #region classes + + [AsArchetype("slides")] + [JsonConverter(typeof(ArchetypeJsonConverter))] + public class SlideShow + { + [JsonProperty("slides")] + public string Slides { get; set; } + [AsFieldset] + [JsonProperty("captions")] + public Captions Captions { get; set; } + } + + [AsArchetype("textstringArray")] /* Note: when inheriting from a list, archetype alias is not used */ + [JsonConverter(typeof(ArchetypeJsonConverter))] + public class Captions : List + { + } + + [AsArchetype("textstringArray")] /* due to hard coded string calues above, must have same archetype alias as list class */ + [JsonConverter(typeof(ArchetypeJsonConverter))] + public class TextString + { + [JsonProperty("textstring")] + public String Text { get; set; } + } + + [AsArchetype("nestedClass")] + [JsonConverter(typeof(ArchetypeJsonConverter))] + public class NestedClass + { + [JsonProperty("nestedClass")] + public NestedClass Nested { get; set; } + [JsonProperty("slides")] + public SlideShow SlideShow { get; set; } + } + + #endregion + } +} diff --git a/app/Umbraco/Archetype.Tests/Serialization/Regression/ArchetypeJsonConverterTest.cs b/app/Umbraco/Archetype.Tests/Serialization/Regression/ArchetypeJsonConverterTest.cs new file mode 100644 index 0000000..daf5241 --- /dev/null +++ b/app/Umbraco/Archetype.Tests/Serialization/Regression/ArchetypeJsonConverterTest.cs @@ -0,0 +1,150 @@ +using Archetype.Tests.Serialization.Base; +using Newtonsoft.Json; +using NUnit.Framework; + +namespace Archetype.Tests.Serialization.Regression +{ + [TestFixture] + public class ArchetypeJsonConverterTest : RegressionTestBase + { + private SerializationTestHelper _testHelper; + + [SetUp] + public void SetUp() + { + _testHelper = new SerializationTestHelper(); + } + + [Test] + public void EmptyArray_Returns_Null() + { + var archetypeJson = @"{""fieldsets"": []}"; + var result = ConvertArchetypeJsonToModel(archetypeJson); + + Assert.IsNull(result); + } + + [Test] + public void SimpleModel_Regression_Battery() + { + var simpleModel = _testHelper.GetModel(); + SimpleModel_Regression_Battery(simpleModel); + + var json = ConvertModelToArchetypeJson(simpleModel, Formatting.Indented); + Assert.AreEqual(JsonTestStrings._SIMPLE_JSON, json); + } + + [Test] + public void SimpleModelWithFieldsets_Regression_Battery() + { + var simpleModel = _testHelper.GetModel(); + SimpleModel_Regression_Battery(simpleModel); + } + + [Test] + public void SimpleModelWithMixedFieldsets_Regression_Battery() + { + var simpleModel = _testHelper.GetModel(); + SimpleModel_Regression_Battery(simpleModel); + } + + [Test] + public void SimpleModels_Regression_Battery() + { + var simpleModels = _testHelper.GetModel(); + SimpleModels_Regression_Battery(simpleModels); + } + + [Test] + public void SimpleModelsWithFieldsets_Regression_Battery() + { + var simpleModels = _testHelper.GetModel(); + SimpleModels_Regression_Battery(simpleModels); + } + + [Test] + public void SimpleModelsWithMixedFieldsets_Regression_Battery() + { + var simpleModels = _testHelper.GetModel(); + SimpleModels_Regression_Battery(simpleModels); + } + + [Test] + public void CompoundModel_Regression_Battery() + { + var compoundModel = _testHelper.GetModel(); + CompoundModel_Regression_Battery(compoundModel); + } + + [Test] + public void CompoundModelWithMixedFieldsetVariant1_Regression_Battery() + { + var compoundModel = _testHelper.GetModel(); + CompoundModel_Regression_Battery(compoundModel); + } + + [Test] + public void CompoundModelWithMixedFieldsetVariant2_Regression_Battery() + { + var compoundModel = _testHelper.GetModel(); + CompoundModel_Regression_Battery(compoundModel); + } + + [Test] + public void CompoundModelWithFieldset_Regression_Battery() + { + var compoundModel = _testHelper.GetModel(); + CompoundModel_Regression_Battery(compoundModel); + } + + [Test] + public void CompoundModelWithList_Regression_Battery() + { + var compoundModelWithList = _testHelper.GetModel(); + CompoundModel_Regression_Battery(compoundModelWithList); + } + + [Test] + public void CompoundModelWithMixedFieldsetWithList_Regression_Battery() + { + var compoundModelWithList = _testHelper.GetModel(); + CompoundModel_Regression_Battery(compoundModelWithList); + } + + [Test] + public void CompoundModelWithFieldsetWithList_Regression_Battery() + { + var compoundModelWithList = _testHelper.GetModel(); + CompoundModel_Regression_Battery(compoundModelWithList); + } + + [Test] + public void NestedModel_Regression_Battery() + { + var nestedModel = _testHelper.GetModel(); + NestedModel_Regression_Battery(nestedModel); + } + + [Test] + public void NestedModelWithMixedFieldset_Regression_Battery() + { + var nestedModel = _testHelper.GetModel(); + NestedModel_Regression_Battery(nestedModel); + } + + [Test] + public void NestedModelWithFieldset_Regression_Battery() + { + var nestedModel = _testHelper.GetModel(); + NestedModel_Regression_Battery(nestedModel); + } + + [Test] + public void ComplexModel_Regression_Battery() + { + var complexModel = _testHelper.GetModel(); + NestedModel_Regression_Battery(complexModel); + } + + } +} diff --git a/app/Umbraco/Archetype.Tests/Serialization/Regression/JsonTestModels.cs b/app/Umbraco/Archetype.Tests/Serialization/Regression/JsonTestModels.cs new file mode 100644 index 0000000..8ff3be5 --- /dev/null +++ b/app/Umbraco/Archetype.Tests/Serialization/Regression/JsonTestModels.cs @@ -0,0 +1,257 @@ +using System; +using System.Collections.Generic; +using Archetype.Serialization; +using Newtonsoft.Json; + +namespace Archetype.Tests.Serialization.Regression +{ + [AsArchetype("simpleModel")] + [JsonConverter(typeof(ArchetypeJsonConverter))] + public class SimpleModel + { + [JsonProperty("text")] + public String Text { get; set; } + [JsonProperty("integer")] + public int Id { get; set; } + [JsonProperty("nullableInteger")] + public int? NullableId { get; set; } + [JsonProperty("double")] + public double Amount { get; set; } + [JsonProperty("nullableDouble")] + public double? NullableAmount { get; set; } + [JsonProperty("dateTime")] + public DateTime DateOne { get; set; } + [JsonProperty("nullableDateTime")] + public DateTime? DateTwo { get; set; } + } + + [AsArchetype("simpleModel")] + [JsonConverter(typeof(ArchetypeJsonConverter))] + public class SimpleModelWithFieldsets + { + [AsFieldset] + [JsonProperty("text")] + public string Text { get; set; } + [AsFieldset] + [JsonProperty("integer")] + public int Id { get; set; } + [AsFieldset] + [JsonProperty("nullableInteger")] + public int? NullableId { get; set; } + [AsFieldset] + [JsonProperty("double")] + public double Amount { get; set; } + [AsFieldset] + [JsonProperty("nullableDouble")] + public double? NullableAmount { get; set; } + [AsFieldset] + [JsonProperty("dateTime")] + public DateTime DateOne { get; set; } + [AsFieldset] + [JsonProperty("nullableDateTime")] + public DateTime? DateTwo { get; set; } + } + + [AsArchetype("simpleModel")] + [JsonConverter(typeof(ArchetypeJsonConverter))] + public class SimpleModelWithMixedFieldsets + { + [AsFieldset] + [JsonProperty("text")] + public string Text { get; set; } + [JsonProperty("integer")] + public int Id { get; set; } + [AsFieldset] + [JsonProperty("nullableInteger")] + public int? NullableId { get; set; } + [JsonProperty("double")] + public double Amount { get; set; } + [AsFieldset] + [JsonProperty("nullableDouble")] + public double? NullableAmount { get; set; } + [AsFieldset] + [JsonProperty("dateTime")] + public DateTime DateOne { get; set; } + public DateTime? DateTwo { get; set; } + } + + [AsArchetype("simpleModels")] + [JsonConverter(typeof(ArchetypeJsonConverter))] + public class SimpleModels : List + { + } + + [AsArchetype("simpleModels")] + [JsonConverter(typeof(ArchetypeJsonConverter))] + public class SimpleModelsWithFieldsets : List + { + } + + [AsArchetype("simpleModels")] + [JsonConverter(typeof(ArchetypeJsonConverter))] + public class SimpleModelsWithMixedFieldsets : List + { + } + + [AsArchetype("compoundModel")] + [JsonConverter(typeof(ArchetypeJsonConverter))] + public class CompoundModel + { + [JsonProperty("simpleModel")] + public SimpleModel SimpleModel { get; set; } + [JsonProperty("text")] + public String Text { get; set; } + [JsonProperty("integer")] + public int Id { get; set; } + } + + [AsArchetype("compoundModelWithMixedFieldset")] + [JsonConverter(typeof(ArchetypeJsonConverter))] + public class CompoundModelWithMixedFieldsetVariant1 + { + [AsFieldset] + [JsonProperty("simpleModel")] + public SimpleModel SimpleModel { get; set; } + [JsonProperty("text")] + public String Text { get; set; } + [JsonProperty("integer")] + public int Id { get; set; } + } + + [AsArchetype("compoundModelWithMixedFieldset")] + [JsonConverter(typeof(ArchetypeJsonConverter))] + public class CompoundModelWithMixedFieldsetVariant2 + { + [JsonProperty("simpleModel")] + public SimpleModel SimpleModel { get; set; } + [AsFieldset] + [JsonProperty("text")] + public String Text { get; set; } + [AsFieldset] + [JsonProperty("integer")] + public int Id { get; set; } + } + + [AsArchetype("compoundModel")] + [JsonConverter(typeof(ArchetypeJsonConverter))] + public class CompoundModelWithFieldset + { + [AsFieldset] + [JsonProperty("simpleModel")] + public SimpleModel SimpleModel { get; set; } + [AsFieldset] + [JsonProperty("text")] + public String Text { get; set; } + [AsFieldset] + [JsonProperty("integer")] + public int Id { get; set; } + } + + [AsArchetype("compoundModelWithList")] + [JsonConverter(typeof(ArchetypeJsonConverter))] + public class CompoundModelWithList + { + [JsonProperty("simpleModelList")] + public List SimpleModelList { get; set; } + [JsonProperty("text")] + public String Text { get; set; } + [JsonProperty("integer")] + public int Id { get; set; } + } + + [AsArchetype("compoundModelWithList")] + [JsonConverter(typeof(ArchetypeJsonConverter))] + public class CompoundModelWithMixedFieldsetWithList + { + [JsonProperty("simpleModelList")] + public List SimpleModelList { get; set; } + [AsFieldset] + [JsonProperty("text")] + public String Text { get; set; } + [JsonProperty("integer")] + public int Id { get; set; } + } + + [AsArchetype("compoundModelWithList")] + [JsonConverter(typeof(ArchetypeJsonConverter))] + public class CompoundModelWithFieldsetWithList + { + [AsFieldset] + [JsonProperty("simpleModelList")] + public List SimpleModelList { get; set; } + [AsFieldset] + [JsonProperty("text")] + public String Text { get; set; } + [AsFieldset] + [JsonProperty("integer")] + public int Id { get; set; } + } + + [AsArchetype("nestedModel")] + [JsonConverter(typeof(ArchetypeJsonConverter))] + public class NestedModel + { + [JsonProperty("compoundModel")] + public CompoundModel CompoundModel { get; set; } + [JsonProperty("simpleModel")] + public SimpleModel SimpleModel { get; set; } + [JsonProperty("text")] + public String Text { get; set; } + [JsonProperty("integer")] + public int Id { get; set; } + } + + [AsArchetype("nestedModel")] + [JsonConverter(typeof(ArchetypeJsonConverter))] + public class NestedModelWithMixedFieldset + { + [JsonProperty("compoundModel")] + public CompoundModel CompoundModel { get; set; } + [AsFieldset] + [JsonProperty("simpleModel")] + public SimpleModel SimpleModel { get; set; } + [JsonProperty("text")] + public String Text { get; set; } + [AsFieldset] + [JsonProperty("integer")] + public int Id { get; set; } + } + + [AsArchetype("nestedModel")] + [JsonConverter(typeof(ArchetypeJsonConverter))] + public class NestedModelWithFieldset + { + [AsFieldset] + [JsonProperty("compoundModel")] + public CompoundModel CompoundModel { get; set; } + [AsFieldset] + [JsonProperty("simpleModel")] + public SimpleModel SimpleModel { get; set; } + [AsFieldset] + [JsonProperty("text")] + public String Text { get; set; } + [AsFieldset] + [JsonProperty("integer")] + public int Id { get; set; } + } + + [AsArchetype("complexModel")] + [JsonConverter(typeof(ArchetypeJsonConverter))] + public class ComplexModel + { + [JsonProperty("compoundModels")] + public CompoundModelWrapper CompoundModelWrapper { get; set; } + [JsonProperty("text")] + public String Text { get; set; } + } + + [AsArchetype("compoundModelWrapper")] + [JsonConverter(typeof(ArchetypeJsonConverter))] + public class CompoundModelWrapper + { + [JsonProperty("compoundModels")] + public List CompoundModels { get; set; } + [JsonProperty("text")] + public String Text { get; set; } + } +} diff --git a/app/Umbraco/Archetype.Tests/Serialization/Regression/JsonTestStrings.cs b/app/Umbraco/Archetype.Tests/Serialization/Regression/JsonTestStrings.cs new file mode 100644 index 0000000..df58e5d --- /dev/null +++ b/app/Umbraco/Archetype.Tests/Serialization/Regression/JsonTestStrings.cs @@ -0,0 +1,61 @@ +namespace Archetype.Tests.Serialization.Regression +{ + public class JsonTestStrings + { + public const string _SIMPLE_JSON = @"{ + ""fieldsets"": [ + { + ""alias"": ""simpleModel"", + ""properties"": [ + { + ""alias"": ""text"", + ""value"": ""Test \r\nText \""quote\"" \r\n"" + }, + { + ""alias"": ""integer"", + ""value"": ""123"" + }, + { + ""alias"": ""nullableInteger"", + ""value"": """" + }, + { + ""alias"": ""double"", + ""value"": ""5.67"" + }, + { + ""alias"": ""nullableDouble"", + ""value"": """" + }, + { + ""alias"": ""dateTime"", + ""value"": ""01/01/2000 00:00:00"" + }, + { + ""alias"": ""nullableDateTime"", + ""value"": """" + } + ] + } + ] +}"; + public const string _ESCAPED_JSON = +@"{ + ""fieldsets"":[ + { + ""properties"":[ + { + ""alias"":""pages"", + ""value"":""2439,2440,2441,2442,2443,2444,2445,2446,2447,2448,2449,2450,2451,2452,2453"" + }, + { + ""alias"":""captions"", + ""value"":""{\""fieldsets\"":[{\""properties\"":[{\""alias\"":\""captions\"",\""value\"":\""{\\\""fieldsets\\\"":[{\\\""properties\\\"":[{\\\""alias\\\"":\\\""textString\\\"",\\\""value\\\"":\\\""{\\\\\\\""fieldsets\\\\\\\"":[{\\\\\\\""properties\\\\\\\"":[{\\\\\\\""alias\\\\\\\"":\\\\\\\""textString\\\\\\\"",\\\\\\\""value\\\\\\\"":\\\\\\\""First Page\\\\\\\"",\\\\\\\""propertyEditorAlias\\\\\\\"":\\\\\\\""Umbraco.Textbox\\\\\\\"",\\\\\\\""dataTypeId\\\\\\\"":-88,\\\\\\\""dataTypeGuid\\\\\\\"":\\\\\\\""0cc0eba1-9960-42c9-bf9b-60e150b429ae\\\\\\\""}],\\\\\\\""alias\\\\\\\"":\\\\\\\""textItem\\\\\\\""}]}\\\"",\\\""propertyEditorAlias\\\"":\\\""Imulus.Archetype\\\"",\\\""dataTypeId\\\"":3764,\\\""dataTypeGuid\\\"":\\\""496cfe35-448f-4b59-9c75-050798afdce4\\\""}],\\\""alias\\\"":\\\""textList\\\""},{\\\""properties\\\"":[{\\\""alias\\\"":\\\""textString\\\"",\\\""value\\\"":\\\""{\\\\\\\""fieldsets\\\\\\\"":[{\\\\\\\""properties\\\\\\\"":[{\\\\\\\""alias\\\\\\\"":\\\\\\\""textString\\\\\\\"",\\\\\\\""value\\\\\\\"":\\\\\\\""Second Page\\\\\\\"",\\\\\\\""propertyEditorAlias\\\\\\\"":\\\\\\\""Umbraco.Textbox\\\\\\\"",\\\\\\\""dataTypeId\\\\\\\"":-88,\\\\\\\""dataTypeGuid\\\\\\\"":\\\\\\\""0cc0eba1-9960-42c9-bf9b-60e150b429ae\\\\\\\""}],\\\\\\\""alias\\\\\\\"":\\\\\\\""textItem\\\\\\\""}]}\\\"",\\\""propertyEditorAlias\\\"":\\\""Imulus.Archetype\\\"",\\\""dataTypeId\\\"":3764,\\\""dataTypeGuid\\\"":\\\""496cfe35-448f-4b59-9c75-050798afdce4\\\""}],\\\""alias\\\"":\\\""textList\\\""},{\\\""properties\\\"":[{\\\""alias\\\"":\\\""textString\\\"",\\\""value\\\"":\\\""{\\\\\\\""fieldsets\\\\\\\"":[{\\\\\\\""properties\\\\\\\"":[{\\\\\\\""alias\\\\\\\"":\\\\\\\""textString\\\\\\\"",\\\\\\\""value\\\\\\\"":\\\\\\\""Third Page\\\\\\\"",\\\\\\\""propertyEditorAlias\\\\\\\"":\\\\\\\""Umbraco.Textbox\\\\\\\"",\\\\\\\""dataTypeId\\\\\\\"":-88,\\\\\\\""dataTypeGuid\\\\\\\"":\\\\\\\""0cc0eba1-9960-42c9-bf9b-60e150b429ae\\\\\\\""}],\\\\\\\""alias\\\\\\\"":\\\\\\\""textItem\\\\\\\""}]}\\\"",\\\""propertyEditorAlias\\\"":\\\""Imulus.Archetype\\\"",\\\""dataTypeId\\\"":3764,\\\""dataTypeGuid\\\"":\\\""496cfe35-448f-4b59-9c75-050798afdce4\\\""}],\\\""alias\\\"":\\\""textList\\\""},{\\\""properties\\\"":[{\\\""alias\\\"":\\\""textString\\\"",\\\""value\\\"":\\\""{\\\\\\\""fieldsets\\\\\\\"":[{\\\\\\\""properties\\\\\\\"":[{\\\\\\\""alias\\\\\\\"":\\\\\\\""textString\\\\\\\"",\\\\\\\""value\\\\\\\"":\\\\\\\""Fourth Page\\\\\\\"",\\\\\\\""propertyEditorAlias\\\\\\\"":\\\\\\\""Umbraco.Textbox\\\\\\\"",\\\\\\\""dataTypeId\\\\\\\"":-88,\\\\\\\""dataTypeGuid\\\\\\\"":\\\\\\\""0cc0eba1-9960-42c9-bf9b-60e150b429ae\\\\\\\""}],\\\\\\\""alias\\\\\\\"":\\\\\\\""textItem\\\\\\\""}]}\\\"",\\\""propertyEditorAlias\\\"":\\\""Imulus.Archetype\\\"",\\\""dataTypeId\\\"":3764,\\\""dataTypeGuid\\\"":\\\""496cfe35-448f-4b59-9c75-050798afdce4\\\""}],\\\""alias\\\"":\\\""textList\\\""}]}\"",\""propertyEditorAlias\"":\""Imulus.Archetype\"",\""dataTypeId\"":3765,\""dataTypeGuid\"":\""4ed439b3-0ee7-447a-a64e-b2b486b86379\""}],\""alias\"":\""captions\""}]}"" + } + ], + ""alias"":""pages"" + } + ] +}"; + } +} diff --git a/app/Umbraco/Archetype.Tests/Serialization/Regression/SerializationTestHelper.cs b/app/Umbraco/Archetype.Tests/Serialization/Regression/SerializationTestHelper.cs new file mode 100644 index 0000000..d8e8a54 --- /dev/null +++ b/app/Umbraco/Archetype.Tests/Serialization/Regression/SerializationTestHelper.cs @@ -0,0 +1,220 @@ +using System; +using System.Collections.Generic; + +namespace Archetype.Tests.Serialization.Regression +{ + public class SerializationTestHelper + { + public T GetModel() + { + try + { + return (T)GetType().GetMethod("Get" + typeof(T).Name).Invoke(this, null); + } + catch + { + return default(T); + } + } + + public SimpleModel GetSimpleModel() + { + return new SimpleModel + { + Amount = 5.67, + NullableAmount = null, + DateOne = new DateTime(2000, 1, 1), + DateTwo = null, + Id = 123, + NullableId = null, + Text = @"Test +Text ""quote"" +" + }; + } + + public SimpleModelWithFieldsets GetSimpleModelWithFieldsets() + { + return new SimpleModelWithFieldsets + { + Amount = 5.67, + NullableAmount = null, + DateOne = new DateTime(2000, 1, 1), + DateTwo = null, + Id = 123, + NullableId = null, + Text = "Test Text" + }; + } + + public SimpleModelWithMixedFieldsets GetSimpleModelWithMixedFieldsets() + { + return new SimpleModelWithMixedFieldsets + { + Amount = 5.67, + NullableAmount = null, + DateOne = new DateTime(2000, 1, 1), + DateTwo = null, + Id = 123, + NullableId = null, + Text = "Test Text" + }; + } + + public SimpleModels GetSimpleModels() + { + return new SimpleModels + { + GetSimpleModel(), + GetSimpleModel(), + GetSimpleModel() + }; + } + + public SimpleModelsWithFieldsets GetSimpleModelsWithFieldsets() + { + return new SimpleModelsWithFieldsets + { + GetSimpleModelWithFieldsets(), + GetSimpleModelWithFieldsets(), + GetSimpleModelWithFieldsets() + }; + } + + public SimpleModelsWithMixedFieldsets GetSimpleModelsWithMixedFieldsets() + { + return new SimpleModelsWithMixedFieldsets + { + GetSimpleModelWithMixedFieldsets(), + GetSimpleModelWithMixedFieldsets(), + GetSimpleModelWithMixedFieldsets() + }; + } + + public CompoundModel GetCompoundModel() + { + return new CompoundModel + { + Id = -1, + SimpleModel = GetModel(), + Text = typeof(CompoundModel).Name + }; + } + + public CompoundModelWithMixedFieldsetVariant1 GetCompoundModelWithMixedFieldsetVariant1() + { + return new CompoundModelWithMixedFieldsetVariant1 + { + Id = -1, + SimpleModel = GetModel(), + Text = typeof(CompoundModelWithMixedFieldsetVariant1).Name + }; + } + + public CompoundModelWithMixedFieldsetVariant2 GetCompoundModelWithMixedFieldsetVariant2() + { + return new CompoundModelWithMixedFieldsetVariant2 + { + Id = -1, + SimpleModel = GetModel(), + Text = typeof(CompoundModelWithMixedFieldsetVariant2).Name + }; + } + + public CompoundModelWithFieldset GetCompoundModelWithFieldset() + { + return new CompoundModelWithFieldset + { + Id = -1, + SimpleModel = GetModel(), + Text = typeof(CompoundModelWithFieldset).Name + }; + } + + public CompoundModelWithList GetCompoundModelWithList() + { + return new CompoundModelWithList + { + Id = 10, + SimpleModelList = GetModel(), + Text = typeof(CompoundModelWithList).Name + }; + } + + public CompoundModelWithMixedFieldsetWithList GetCompoundModelWithMixedFieldsetWithList() + { + return new CompoundModelWithMixedFieldsetWithList + { + Id = 11, + SimpleModelList = GetModel(), + Text = typeof(CompoundModelWithMixedFieldsetWithList).Name + }; + } + + public CompoundModelWithFieldsetWithList GetCompoundModelWithFieldsetWithList() + { + return new CompoundModelWithFieldsetWithList + { + Id = 12, + SimpleModelList = GetModel(), + Text = typeof(CompoundModelWithFieldsetWithList).Name + }; + } + + public NestedModel GetNestedModel() + { + return new NestedModel + { + CompoundModel = GetModel(), + Id = 53, + SimpleModel = GetModel(), + Text = typeof(NestedModel).Name + }; + } + + public NestedModelWithMixedFieldset GetNestedModelWithMixedFieldset() + { + return new NestedModelWithMixedFieldset + { + CompoundModel = GetModel(), + Id = 54, + SimpleModel = GetModel(), + Text = typeof(NestedModelWithMixedFieldset).Name + }; + } + + public NestedModelWithFieldset GetNestedModelWithFieldset() + { + return new NestedModelWithFieldset + { + CompoundModel = GetModel(), + Id = 55, + SimpleModel = GetModel(), + Text = typeof(NestedModelWithFieldset).Name + }; + } + + public CompoundModelWrapper GetCompoundModelWrapper() + { + return new CompoundModelWrapper + { + CompoundModels = new List + { + GetModel(), + GetModel(), + GetModel() + }, + Text = typeof(CompoundModelWrapper).Name + }; + } + + public ComplexModel GetComplexModel() + { + return new ComplexModel + { + CompoundModelWrapper = GetModel(), + Text = typeof(ComplexModel).Name + }; + } + } +} diff --git a/app/Umbraco/Archetype.Tests/Serialization/ArchetypeJsonConverterTest.cs b/app/Umbraco/Archetype.Tests/Serialization/UseCases/ArchetypeJsonConverterTest.cs similarity index 70% rename from app/Umbraco/Archetype.Tests/Serialization/ArchetypeJsonConverterTest.cs rename to app/Umbraco/Archetype.Tests/Serialization/UseCases/ArchetypeJsonConverterTest.cs index 23c7062..4709736 100644 --- a/app/Umbraco/Archetype.Tests/Serialization/ArchetypeJsonConverterTest.cs +++ b/app/Umbraco/Archetype.Tests/Serialization/UseCases/ArchetypeJsonConverterTest.cs @@ -1,12 +1,13 @@ using System; using Archetype.PropertyConverters; +using Archetype.Tests.Serialization.Base; using Newtonsoft.Json; using NUnit.Framework; -namespace Archetype.Tests.Serialization +namespace Archetype.Tests.Serialization.UseCases { [TestFixture] - public class ArchetypeJsonConverterTest + public class ArchetypeJsonConverterTest : ArchetypeJsonConverterTestBase { private ContactDetails _contactDetails; private CompanyDetails _companyDetails; @@ -60,32 +61,32 @@ namespace Archetype.Tests.Serialization #region serialization tests [Test] - public void MergerDetailsModel_Serializes_To_Archetype_Property() + public void Convert_MergerDetailsModel_To_ArchetypeJson() { - var result = JsonConvert.SerializeObject(_mergerDetails, Formatting.Indented); + var result = ConvertModelToArchetypeJson(_mergerDetails, Formatting.Indented); Assert.AreEqual(JsonTestStrings._MERGER_DETAILS_JSON, result); } [Test] - public void ContactDetailsModel_Serializes_To_Archetype_Property() + public void Convert_ContactDetailsModel_To_ArchetypeJson() { - var result = JsonConvert.SerializeObject(_contactDetails, Formatting.Indented); + var result = ConvertModelToArchetypeJson(_contactDetails, Formatting.Indented); Assert.AreEqual(JsonTestStrings._CONTACT_DETAILS_JSON, result); } [Test] - public void CompanyDetailsModel_Fieldset_Serializes_As_Expected() + public void Convert_CompanyDetailsModel_To_ArchetypeJson() { - var result = JsonConvert.SerializeObject(_companyDetails, Formatting.Indented); + var result = ConvertModelToArchetypeJson(_companyDetails, Formatting.Indented); Assert.AreEqual(JsonTestStrings._COMPANY_DETAILS_JSON, result); } [Test] - public void AnnualStatementModel_Fieldset_Serializes_As_Expected() + public void Convert_AnnualStatementModel_To_ArchetypeJson() { - var result = JsonConvert.SerializeObject(_annualStatement, Formatting.Indented); + var result = ConvertModelToArchetypeJson(_annualStatement, Formatting.Indented); Assert.AreEqual(JsonTestStrings._ANNUAL_STATEMENT_JSON, result); @@ -94,14 +95,14 @@ namespace Archetype.Tests.Serialization [Test] public void NullValues_Serialize_To_Empty_String() { - var result = JsonConvert.SerializeObject(new ContactDetails()); + var result = ConvertModelToArchetypeJson(new ContactDetails()); Assert.AreEqual(JsonTestStrings._NULL_VALUES_JSON, result); } [Test] - public void ConvertModelToArchetype() + public void Convert_ContactDetailsModel_To_Archetype() { var model = new ContactDetails { @@ -109,25 +110,17 @@ namespace Archetype.Tests.Serialization Email = "email" }; - var converter = new ArchetypeValueConverter(); - var json = JsonConvert.SerializeObject(model); - var archetype = (Archetype.Models.ArchetypeModel)converter.ConvertDataToSource(null, json, false); - - Assert.NotNull(archetype); + Assert.NotNull(ConvertModelToArchetype(model)); } [Test] - public void ConvertNumericAndDateModelToArchetype() + public void Convert_AnnualStatementModel_To_Archetype() { - var converter = new ArchetypeValueConverter(); - var json = JsonConvert.SerializeObject(_annualStatement); - var archetype = (Archetype.Models.ArchetypeModel)converter.ConvertDataToSource(null, json, false); - - Assert.NotNull(archetype); + Assert.NotNull(ConvertModelToArchetype(_annualStatement)); } [Test] - public void ConvertCompoundModelToArchetype() + public void Convert_AllContactDetailsModel_To_Archetype() { var item1 = new ContactDetails { @@ -147,15 +140,11 @@ namespace Archetype.Tests.Serialization AdminDetails = item2 }; - var converter = new ArchetypeValueConverter(); - var json = JsonConvert.SerializeObject(model, Formatting.Indented); - var archetype = (Archetype.Models.ArchetypeModel)converter.ConvertDataToSource(null, json, false); - - Assert.NotNull(archetype); + Assert.NotNull(ConvertModelToArchetype(model)); } [Test] - public void ConvertEnumerableModelToArchetype() + public void Convert_ContactDetailsListModel_To_Archetype() { var item1 = new ContactDetails { @@ -175,15 +164,11 @@ namespace Archetype.Tests.Serialization item2 }; - var converter = new ArchetypeValueConverter(); - var json = JsonConvert.SerializeObject(model, Formatting.Indented); - var archetype = (Archetype.Models.ArchetypeModel)converter.ConvertDataToSource(null, json, false); - - Assert.NotNull(archetype); + Assert.NotNull(ConvertModelToArchetype(model)); } [Test] - public void ConvertNestedModelToArchetype() + public void Convert_CompanyDetailsModel_To_Archetype() { var model = new CompanyDetails { @@ -195,11 +180,7 @@ namespace Archetype.Tests.Serialization } }; - var converter = new ArchetypeValueConverter(); - var json = JsonConvert.SerializeObject(model, Formatting.Indented); - var archetype = (Archetype.Models.ArchetypeModel)converter.ConvertDataToSource(null, json, false); - - Assert.NotNull(archetype); + Assert.NotNull(ConvertModelToArchetype(model)); } #endregion @@ -207,9 +188,9 @@ namespace Archetype.Tests.Serialization #region deserialization tests [Test] - public void DeserializeModelFromArchetype() + public void Convert_ArchetypeJson_To_ContactDetailsModel() { - var result = JsonConvert.DeserializeObject(JsonTestStrings._CONTACT_DETAILS_JSON); + var result = ConvertArchetypeJsonToModel(JsonTestStrings._CONTACT_DETAILS_JSON); Assert.NotNull(result); Assert.IsInstanceOf(result); @@ -228,9 +209,9 @@ namespace Archetype.Tests.Serialization } [Test] - public void DeserializeNumericAndDateModelFromArchetype() + public void Convert_ArchetypeJson_To_AnnualStatementModel() { - var result = JsonConvert.DeserializeObject(JsonTestStrings._ANNUAL_STATEMENT_JSON); + var result = ConvertArchetypeJsonToModel(JsonTestStrings._ANNUAL_STATEMENT_JSON); Assert.NotNull(result); Assert.IsInstanceOf(result); @@ -244,7 +225,7 @@ namespace Archetype.Tests.Serialization } [Test] - public void DeserializeNumericAndDateModel_NullableDate_HasValue_FromArchetype() + public void Convert_ArchetypeJson_To_AnnualStatementModel_NullableDate_HasValue() { var annualStatement = new AnnualStatement { @@ -256,8 +237,7 @@ namespace Archetype.Tests.Serialization Profit = 1123456.78m }; - var json = JsonConvert.SerializeObject(annualStatement); - var result = JsonConvert.DeserializeObject(json); + var result = ConvertModelToArchetypeAndBack(annualStatement); Assert.NotNull(result); Assert.IsInstanceOf(result); @@ -271,7 +251,7 @@ namespace Archetype.Tests.Serialization } [Test] - public void DeserializeCompoundModelFromArchetype() + public void Convert_ArchetypeJson_To_AllContactDetailsModel() { var item1 = new ContactDetails { @@ -291,8 +271,7 @@ namespace Archetype.Tests.Serialization AdminDetails = item2 }; - var json = JsonConvert.SerializeObject(model, Formatting.Indented); - var result = JsonConvert.DeserializeObject(json); + var result = ConvertModelToArchetypeAndBack(model); Assert.NotNull(result); Assert.IsInstanceOf(result); @@ -304,7 +283,7 @@ namespace Archetype.Tests.Serialization } [Test] - public void DeserializeEnumerableModelFromArchetype() + public void Convert_ArchetypeJson_To_ContactDetailsListModel() { var item1 = new ContactDetails { @@ -324,8 +303,7 @@ namespace Archetype.Tests.Serialization item2 }; - var json = JsonConvert.SerializeObject(model, Formatting.Indented); - var result = JsonConvert.DeserializeObject(json); + var result = ConvertModelToArchetypeAndBack(model); Assert.NotNull(result); Assert.IsInstanceOf(result); @@ -338,7 +316,7 @@ namespace Archetype.Tests.Serialization } [Test] - public void DeserializeNestedModelFromArchetype() + public void Convert_ArchetypeJson_To_CompanyDetailsModel() { var model = new CompanyDetails { @@ -350,8 +328,7 @@ namespace Archetype.Tests.Serialization } }; - var json = JsonConvert.SerializeObject(model, Formatting.Indented); - var result = JsonConvert.DeserializeObject(json); + var result = ConvertModelToArchetypeAndBack(model); Assert.NotNull(result); Assert.IsInstanceOf(result); diff --git a/app/Umbraco/Archetype.Tests/Serialization/ArchetypeJsonConverterComplexModelTest.cs b/app/Umbraco/Archetype.Tests/Serialization/UseCases/Complex/ArchetypeJsonConverterTest.cs similarity index 80% rename from app/Umbraco/Archetype.Tests/Serialization/ArchetypeJsonConverterComplexModelTest.cs rename to app/Umbraco/Archetype.Tests/Serialization/UseCases/Complex/ArchetypeJsonConverterTest.cs index 06f3ccd..e6bacd9 100644 --- a/app/Umbraco/Archetype.Tests/Serialization/ArchetypeJsonConverterComplexModelTest.cs +++ b/app/Umbraco/Archetype.Tests/Serialization/UseCases/Complex/ArchetypeJsonConverterTest.cs @@ -1,12 +1,13 @@ using System.Linq; using Archetype.PropertyConverters; +using Archetype.Tests.Serialization.Base; using Newtonsoft.Json; using NUnit.Framework; -namespace Archetype.Tests.Serialization +namespace Archetype.Tests.Serialization.UseCases.Complex { [TestFixture] - public class ArchetypeJsonConverterComplexModelTest + public class ArchetypeJsonConverterTest : ArchetypeJsonConverterTestBase { private TextList _textList; private Captions _captions; @@ -27,26 +28,22 @@ namespace Archetype.Tests.Serialization #region complex nested model tests [Test] - public void PageDetailsModel_Serializes_To_Archetype_Property() + public void Convert_PageDetailsModel_To_ArchetypeJson() { - var result = JsonConvert.SerializeObject(_pageDetails, Formatting.Indented); + var result = ConvertModelToArchetypeJson(_pageDetails, Formatting.Indented); Assert.AreEqual(JsonTestStrings._PAGE_DETAILS_JSON, result); } [Test] - public void ConvertComplexModelToArchetype() + public void Convert_PageDetailsModel_To_Archetype() { - var converter = new ArchetypeValueConverter(); - var json = JsonConvert.SerializeObject(_pageDetails, Formatting.Indented); - var archetype = (Archetype.Models.ArchetypeModel)converter.ConvertDataToSource(null, json, false); - - Assert.NotNull(archetype); + Assert.NotNull(ConvertModelToArchetype(_pageDetails)); } [Test] - public void DeserializeComplexModelFromArchetype() + public void Convert_ArchetypeJson_To_PageDetailsModel() { - var result = JsonConvert.DeserializeObject(JsonTestStrings._PAGE_DETAILS_JSON); + var result = ConvertArchetypeJsonToModel(JsonTestStrings._PAGE_DETAILS_JSON); Assert.NotNull(result); Assert.IsInstanceOf(result); @@ -59,10 +56,9 @@ namespace Archetype.Tests.Serialization } [Test] - public void SerializeThenDeserializeComplexModelFromArchetype() + public void Convert_PageDetailsModel_To_Archetype_AndBack() { - var json = JsonConvert.SerializeObject(_pageDetails); - var result = JsonConvert.DeserializeObject(json); + var result = ConvertModelToArchetypeAndBack(_pageDetails); Assert.NotNull(result); Assert.IsInstanceOf(result); @@ -78,26 +74,22 @@ namespace Archetype.Tests.Serialization #region complex nested tree model tests [Test] - public void ConvertComplexNestedModelToArchetype() + public void Convert_PagesModel_To_Archetype() { - var converter = new ArchetypeValueConverter(); - var json = JsonConvert.SerializeObject(_pages, Formatting.Indented); - var archetype = (Archetype.Models.ArchetypeModel)converter.ConvertDataToSource(null, json, false); - - Assert.NotNull(archetype); + Assert.NotNull(ConvertModelToArchetype(_pages)); } [Test] - public void PagesModel_Serializes_To_Archetype_Property() + public void Convert_PagesModel_To_ArchetypeJson() { - var result = JsonConvert.SerializeObject(_pages, Formatting.Indented); + var result = ConvertModelToArchetypeJson(_pages, Formatting.Indented); Assert.AreEqual(JsonTestStrings._PAGES_JSON, result); } [Test] - public void DeserializeComplexTreeModelFromArchetype() + public void Convert_ArchetypeJson_To_PagesModel() { - var result = JsonConvert.DeserializeObject(JsonTestStrings._PAGES_JSON); + var result = ConvertArchetypeJsonToModel(JsonTestStrings._PAGES_JSON); Assert.NotNull(result); Assert.IsInstanceOf(result); @@ -124,10 +116,9 @@ namespace Archetype.Tests.Serialization } [Test] - public void SerializeThenDeserializeComplexTreeModelFromArchetype() + public void Convert_PagesModel_To_Archetype_AndBack() { - var json = JsonConvert.SerializeObject(_pages); - var result = JsonConvert.DeserializeObject(json); + var result = ConvertModelToArchetypeAndBack(_pages); Assert.NotNull(result); Assert.IsInstanceOf(result); diff --git a/app/Umbraco/Archetype.Tests/Serialization/UseCases/Complex/JsonTestModels.cs b/app/Umbraco/Archetype.Tests/Serialization/UseCases/Complex/JsonTestModels.cs new file mode 100644 index 0000000..14f999a --- /dev/null +++ b/app/Umbraco/Archetype.Tests/Serialization/UseCases/Complex/JsonTestModels.cs @@ -0,0 +1,92 @@ +using System.Collections.Generic; +using Archetype.Serialization; +using Newtonsoft.Json; + +namespace Archetype.Tests.Serialization.UseCases.Complex +{ + #region complex nested model + + [AsArchetype("pages")] + [JsonConverter(typeof(ArchetypeJsonConverter))] + public class PageDetails + { + [JsonProperty("pages")] + public string Pages { get; set; } + [AsFieldset] + [JsonProperty("captions")] + public Captions Captions { get; set; } + } + + [AsArchetype("captions")] + [JsonConverter(typeof(ArchetypeJsonConverter))] + public class Captions + { + [JsonProperty("captions")] + public TextList TextStringArray { get; set; } + } + + [AsArchetype("textstringArray")] + [JsonConverter(typeof(ArchetypeJsonConverter))] + public class TextList : List + { + } + + [AsArchetype("textstringArray")] + [JsonConverter(typeof(ArchetypeJsonConverter))] + public class TextItem + { + [JsonProperty("textstring")] + public string TextString { get; set; } + } + + #endregion + + #region complex nested tree model + + public abstract class PageBase + { + public string PageTitle { get; set; } + public string BodyText { get; set; } + } + + [AsArchetype("slideShow")] + [JsonConverter(typeof(ArchetypeJsonConverter))] + public class SlideShow + { + public string Slides { get; set; } + } + + [AsArchetype("seo")] + [JsonConverter(typeof(ArchetypeJsonConverter))] + public class Seo + { + public string MetaTitle { get; set; } + public string MetaDescription { get; set; } + } + + [AsArchetype("TextPage")] + [JsonConverter(typeof(ArchetypeJsonConverter))] + public class TextPage : PageBase + { + [AsFieldset] + public SlideShow Media { get; set; } + + [AsFieldset] + public Seo Seo { get; set; } + } + + [AsArchetype("TextPageList")] + [JsonConverter(typeof(ArchetypeJsonConverter))] + public class TextPageList : List + { + } + + [AsArchetype("Pages")] + [JsonConverter(typeof(ArchetypeJsonConverter))] + public class PageList + { + public TextPageList Pages { get; set; } + } + + #endregion +} diff --git a/app/Umbraco/Archetype.Tests/Serialization/JsonTestStrings.cs b/app/Umbraco/Archetype.Tests/Serialization/UseCases/Complex/JsonTestStrings.cs similarity index 51% rename from app/Umbraco/Archetype.Tests/Serialization/JsonTestStrings.cs rename to app/Umbraco/Archetype.Tests/Serialization/UseCases/Complex/JsonTestStrings.cs index 5061e8c..ba5f66f 100644 --- a/app/Umbraco/Archetype.Tests/Serialization/JsonTestStrings.cs +++ b/app/Umbraco/Archetype.Tests/Serialization/UseCases/Complex/JsonTestStrings.cs @@ -1,435 +1,245 @@ -namespace Archetype.Tests.Serialization -{ - public class JsonTestStrings - { - public const string _MERGER_DETAILS_JSON = - @"{ - ""fieldsets"": [ - { - ""alias"": ""mergerDetails"", - ""properties"": [ - { - ""alias"": ""MergerDate"", - ""value"": ""07/06/2014 08:09:10"" - } - ] - } - ] -}"; - - public const string _ANNUAL_STATEMENT_JSON = - @"{ - ""fieldsets"": [ - { - ""alias"": ""annualStatement"", - ""properties"": [ - { - ""alias"": ""FiscalYearStart"", - ""value"": ""01/09/2013 00:00:00"" - }, - { - ""alias"": ""FiscalYearEnd"", - ""value"": ""31/08/2014 00:00:00"" - }, - { - ""alias"": ""DividendPaymentDate"", - ""value"": """" - }, - { - ""alias"": ""TotalShares"", - ""value"": ""345678"" - }, - { - ""alias"": ""Sales"", - ""value"": ""123456700.89"" - }, - { - ""alias"": ""Profit"", - ""value"": ""1123456.78"" - } - ] - } - ] -}"; - - public const string _CONTACT_DETAILS_JSON = - @"{ - ""fieldsets"": [ - { - ""alias"": ""contactDetails"", - ""properties"": [ - { - ""alias"": ""name"", - ""value"": ""Test"" - }, - { - ""alias"": ""address"", - ""value"": ""Test Address"" - }, - { - ""alias"": ""telephone"", - ""value"": ""111"" - }, - { - ""alias"": ""mobile"", - ""value"": ""000"" - }, - { - ""alias"": ""fax"", - ""value"": ""000"" - }, - { - ""alias"": ""email"", - ""value"": ""test@test.com"" - }, - { - ""alias"": ""webSite"", - ""value"": { - ""fieldsets"": [ - { - ""alias"": ""urlPicker"", - ""properties"": [ - { - ""alias"": ""title"", - ""value"": ""The Test Company"" - }, - { - ""alias"": ""url"", - ""value"": ""http://test.com"" - }, - { - ""alias"": ""content"", - ""value"": """" - }, - { - ""alias"": ""media"", - ""value"": """" - }, - { - ""alias"": ""openInNewWindow"", - ""value"": ""1"" - } - ] - } - ] - } - } - ] - } - ] -}"; - - public const string _COMPANY_DETAILS_JSON = - @"{ - ""fieldsets"": [ - { - ""alias"": ""companyDetails"", - ""properties"": [ - { - ""alias"": ""region"", - ""value"": ""Test Region"" - }, - { - ""alias"": ""contactDetails"", - ""value"": { - ""fieldsets"": [ - { - ""alias"": ""contactDetails"", - ""properties"": [ - { - ""alias"": ""name"", - ""value"": ""Test"" - }, - { - ""alias"": ""address"", - ""value"": ""Test Address"" - }, - { - ""alias"": ""telephone"", - ""value"": ""111"" - }, - { - ""alias"": ""mobile"", - ""value"": ""000"" - }, - { - ""alias"": ""fax"", - ""value"": ""000"" - }, - { - ""alias"": ""email"", - ""value"": ""test@test.com"" - }, - { - ""alias"": ""webSite"", - ""value"": { - ""fieldsets"": [ - { - ""alias"": ""urlPicker"", - ""properties"": [ - { - ""alias"": ""title"", - ""value"": ""The Test Company"" - }, - { - ""alias"": ""url"", - ""value"": ""http://test.com"" - }, - { - ""alias"": ""content"", - ""value"": """" - }, - { - ""alias"": ""media"", - ""value"": """" - }, - { - ""alias"": ""openInNewWindow"", - ""value"": ""1"" - } - ] - } - ] - } - } - ] - } - ] - } - } - ] - } - ] -}"; - - public const string _PAGE_DETAILS_JSON = - @"{ - ""fieldsets"": [ - { - ""alias"": ""pages"", - ""properties"": [ - { - ""alias"": ""pages"", - ""value"": ""2439,2440,2441,2442,2443,2444,2445,2446,2447,2448,2449,2450,2451,2452,2453"" - } - ] - }, - { - ""alias"": ""captions"", - ""properties"": [ - { - ""alias"": ""captions"", - ""value"": { - ""fieldsets"": [ - { - ""alias"": ""textstringArray"", - ""properties"": [ - { - ""alias"": ""textstring"", - ""value"": ""First Page"" - } - ] - }, - { - ""alias"": ""textstringArray"", - ""properties"": [ - { - ""alias"": ""textstring"", - ""value"": ""Second Page"" - } - ] - }, - { - ""alias"": ""textstringArray"", - ""properties"": [ - { - ""alias"": ""textstring"", - ""value"": ""Third Page"" - } - ] - }, - { - ""alias"": ""textstringArray"", - ""properties"": [ - { - ""alias"": ""textstring"", - ""value"": ""Fourth Page"" - } - ] - } - ] - } - } - ] - } - ] -}"; - - public const string _PAGES_JSON = - @"{ - ""fieldsets"": [ - { - ""alias"": ""Pages"", - ""properties"": [ - { - ""alias"": ""Pages"", - ""value"": { - ""fieldsets"": [ - { - ""alias"": ""TextPage"", - ""properties"": [ - { - ""alias"": ""Media"", - ""value"": { - ""fieldsets"": [ - { - ""alias"": ""slideShow"", - ""properties"": [ - { - ""alias"": ""Slides"", - ""value"": ""1,2,3,4,5,6,7,8"" - } - ] - } - ] - } - }, - { - ""alias"": ""Seo"", - ""value"": { - ""fieldsets"": [ - { - ""alias"": ""seo"", - ""properties"": [ - { - ""alias"": ""MetaTitle"", - ""value"": ""Test Meta Title"" - }, - { - ""alias"": ""MetaDescription"", - ""value"": ""Test Meta Description"" - } - ] - } - ] - } - }, - { - ""alias"": ""PageTitle"", - ""value"": ""Home Page"" - }, - { - ""alias"": ""BodyText"", - ""value"": ""Home Page Body"" - } - ] - }, - { - ""alias"": ""TextPage"", - ""properties"": [ - { - ""alias"": ""Media"", - ""value"": { - ""fieldsets"": [ - { - ""alias"": ""slideShow"", - ""properties"": [ - { - ""alias"": ""Slides"", - ""value"": ""1,2,3,4,5,6,7,8"" - } - ] - } - ] - } - }, - { - ""alias"": ""Seo"", - ""value"": { - ""fieldsets"": [ - { - ""alias"": ""seo"", - ""properties"": [ - { - ""alias"": ""MetaTitle"", - ""value"": ""Test Meta Title"" - }, - { - ""alias"": ""MetaDescription"", - ""value"": ""Test Meta Description"" - } - ] - } - ] - } - }, - { - ""alias"": ""PageTitle"", - ""value"": ""About us Page"" - }, - { - ""alias"": ""BodyText"", - ""value"": ""About us Page Body"" - } - ] - }, - { - ""alias"": ""TextPage"", - ""properties"": [ - { - ""alias"": ""Media"", - ""value"": { - ""fieldsets"": [ - { - ""alias"": ""slideShow"", - ""properties"": [ - { - ""alias"": ""Slides"", - ""value"": ""1,2,3,4,5,6,7,8"" - } - ] - } - ] - } - }, - { - ""alias"": ""Seo"", - ""value"": { - ""fieldsets"": [ - { - ""alias"": ""seo"", - ""properties"": [ - { - ""alias"": ""MetaTitle"", - ""value"": ""Test Meta Title"" - }, - { - ""alias"": ""MetaDescription"", - ""value"": ""Test Meta Description"" - } - ] - } - ] - } - }, - { - ""alias"": ""PageTitle"", - ""value"": ""Contact us Page"" - }, - { - ""alias"": ""BodyText"", - ""value"": ""Contact us Page Body"" - } - ] - } - ] - } - } - ] - } - ] -}"; - - public const string _NULL_VALUES_JSON = @"{""fieldsets"":[{""alias"":""contactDetails"",""properties"":[{""alias"":""name"",""value"":""""},{""alias"":""address"",""value"":""""},{""alias"":""telephone"",""value"":""""},{""alias"":""mobile"",""value"":""""},{""alias"":""fax"",""value"":""""},{""alias"":""email"",""value"":""""},{""alias"":""webSite"",""value"":""""}]}]}"; - } -} +namespace Archetype.Tests.Serialization.UseCases.Complex +{ + public class JsonTestStrings + { + public const string _PAGE_DETAILS_JSON = + @"{ + ""fieldsets"": [ + { + ""alias"": ""captions"", + ""properties"": [ + { + ""alias"": ""captions"", + ""value"": { + ""fieldsets"": [ + { + ""alias"": ""captions"", + ""properties"": [ + { + ""alias"": ""captions"", + ""value"": { + ""fieldsets"": [ + { + ""alias"": ""textstringArray"", + ""properties"": [ + { + ""alias"": ""textstring"", + ""value"": ""First Page"" + } + ] + }, + { + ""alias"": ""textstringArray"", + ""properties"": [ + { + ""alias"": ""textstring"", + ""value"": ""Second Page"" + } + ] + }, + { + ""alias"": ""textstringArray"", + ""properties"": [ + { + ""alias"": ""textstring"", + ""value"": ""Third Page"" + } + ] + }, + { + ""alias"": ""textstringArray"", + ""properties"": [ + { + ""alias"": ""textstring"", + ""value"": ""Fourth Page"" + } + ] + } + ] + } + } + ] + } + ] + } + } + ] + }, + { + ""alias"": ""pages"", + ""properties"": [ + { + ""alias"": ""pages"", + ""value"": ""2439,2440,2441,2442,2443,2444,2445,2446,2447,2448,2449,2450,2451,2452,2453"" + } + ] + } + ] +}"; + + public const string _PAGES_JSON = + @"{ + ""fieldsets"": [ + { + ""alias"": ""Pages"", + ""properties"": [ + { + ""alias"": ""Pages"", + ""value"": { + ""fieldsets"": [ + { + ""alias"": ""TextPage"", + ""properties"": [ + { + ""alias"": ""Media"", + ""value"": { + ""fieldsets"": [ + { + ""alias"": ""slideShow"", + ""properties"": [ + { + ""alias"": ""Slides"", + ""value"": ""1,2,3,4,5,6,7,8"" + } + ] + } + ] + } + }, + { + ""alias"": ""Seo"", + ""value"": { + ""fieldsets"": [ + { + ""alias"": ""seo"", + ""properties"": [ + { + ""alias"": ""MetaTitle"", + ""value"": ""Test Meta Title"" + }, + { + ""alias"": ""MetaDescription"", + ""value"": ""Test Meta Description"" + } + ] + } + ] + } + }, + { + ""alias"": ""PageTitle"", + ""value"": ""Home Page"" + }, + { + ""alias"": ""BodyText"", + ""value"": ""Home Page Body"" + } + ] + }, + { + ""alias"": ""TextPage"", + ""properties"": [ + { + ""alias"": ""Media"", + ""value"": { + ""fieldsets"": [ + { + ""alias"": ""slideShow"", + ""properties"": [ + { + ""alias"": ""Slides"", + ""value"": ""1,2,3,4,5,6,7,8"" + } + ] + } + ] + } + }, + { + ""alias"": ""Seo"", + ""value"": { + ""fieldsets"": [ + { + ""alias"": ""seo"", + ""properties"": [ + { + ""alias"": ""MetaTitle"", + ""value"": ""Test Meta Title"" + }, + { + ""alias"": ""MetaDescription"", + ""value"": ""Test Meta Description"" + } + ] + } + ] + } + }, + { + ""alias"": ""PageTitle"", + ""value"": ""About us Page"" + }, + { + ""alias"": ""BodyText"", + ""value"": ""About us Page Body"" + } + ] + }, + { + ""alias"": ""TextPage"", + ""properties"": [ + { + ""alias"": ""Media"", + ""value"": { + ""fieldsets"": [ + { + ""alias"": ""slideShow"", + ""properties"": [ + { + ""alias"": ""Slides"", + ""value"": ""1,2,3,4,5,6,7,8"" + } + ] + } + ] + } + }, + { + ""alias"": ""Seo"", + ""value"": { + ""fieldsets"": [ + { + ""alias"": ""seo"", + ""properties"": [ + { + ""alias"": ""MetaTitle"", + ""value"": ""Test Meta Title"" + }, + { + ""alias"": ""MetaDescription"", + ""value"": ""Test Meta Description"" + } + ] + } + ] + } + }, + { + ""alias"": ""PageTitle"", + ""value"": ""Contact us Page"" + }, + { + ""alias"": ""BodyText"", + ""value"": ""Contact us Page Body"" + } + ] + } + ] + } + } + ] + } + ] +}"; + } +} diff --git a/app/Umbraco/Archetype.Tests/Serialization/UseCases/Enumerable/ArchetypeJsonConverterTest.cs b/app/Umbraco/Archetype.Tests/Serialization/UseCases/Enumerable/ArchetypeJsonConverterTest.cs new file mode 100644 index 0000000..51b4ae5 --- /dev/null +++ b/app/Umbraco/Archetype.Tests/Serialization/UseCases/Enumerable/ArchetypeJsonConverterTest.cs @@ -0,0 +1,143 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using Archetype.Models; +using Archetype.PropertyConverters; +using Archetype.Tests.Serialization.Base; +using Newtonsoft.Json; +using NUnit.Framework; + +namespace Archetype.Tests.Serialization.UseCases.Enumerable +{ + [TestFixture] + public class ArchetypeJsonConverterTest : ArchetypeJsonConverterTestBase + { + private Feedbacks _feedbacks; + private Captions _captions; + + + [SetUp] + public void SetUp() + { + _feedbacks = new Feedbacks + { + new Feedback{Testimonial = "Testimonial 1"}, + new Feedback{Testimonial = "Testimonial 2"}, + new Feedback{Testimonial = "Testimonial 3"} + }; + + _captions = new Captions() + { + TextArray = new List + { + new Text{TextString = "Caption 1"}, + new Text{TextString = "Caption 2"}, + new Text{TextString = "Caption 3"} + } + }; + } + + #region Feedback - single fieldset with multiple items + + [Test] + public void Convert_FeedbackModel_To_Archetype() + { + var converter = new ArchetypeValueConverter(); + var json = JsonConvert.SerializeObject(_feedbacks); + var archetype = (ArchetypeModel)converter.ConvertDataToSource(null, json, false); + + Assert.NotNull(archetype); + } + + [Test] + public void Convert_FeedbackModel_To_ArchetypeJson() + { + var json = ConvertModelToArchetypeJson(_feedbacks, Formatting.Indented); + Assert.AreEqual(JsonTestStrings._FEEDBACK_JSON, json); + } + + [Test] + public void Convert_ArchetypeJson_To_FeedbackModel() + { + var result = ConvertArchetypeJsonToModel(JsonTestStrings._FEEDBACK_JSON); + Assert.NotNull(result); + Assert.AreEqual(3, result.Count); + + foreach (var feedback in result) + { + Assert.AreEqual(String.Format("Testimonial {0}", result.IndexOf(feedback) + 1), + feedback.Testimonial); + } + } + + [Test] + public void Convert_FeedbackModel_To_Archetype_AndBack() + { + var result = ConvertModelToArchetypeAndBack(_feedbacks); + Assert.NotNull(result); + + Assert.AreEqual(3, result.Count); + + foreach (var feedback in result) + { + var index = result.IndexOf(feedback); + Assert.AreEqual(_feedbacks.ElementAt(index).Testimonial, feedback.Testimonial); + } + } + + #endregion + + #region Captions - a root fieldset which contains another fieldset list + + [Test] + public void Convert_CaptionsModel_To_Archetype() + { + var converter = new ArchetypeValueConverter(); + var json = JsonConvert.SerializeObject(_captions); + var archetype = (ArchetypeModel)converter.ConvertDataToSource(null, json, false); + + Assert.NotNull(archetype); + } + + [Test] + public void Convert_CaptionsModel_To_ArchetypeJson() + { + var json = ConvertModelToArchetypeJson(_captions, Formatting.Indented); + Assert.AreEqual(JsonTestStrings._CAPTIONS_JSON, json); + } + + [Test] + public void Convert_ArchetypeJson_To_CaptionsModel() + { + var result = ConvertArchetypeJsonToModel(JsonTestStrings._CAPTIONS_JSON); + Assert.NotNull(result); + Assert.NotNull(result.TextArray); + + Assert.AreEqual(3, result.TextArray.Count); + + foreach (var caption in result.TextArray) + { + Assert.AreEqual(String.Format("Caption {0}", result.TextArray.IndexOf(caption) + 1), + caption.TextString); + } + } + + [Test] + public void Convert_CaptionsModel_To_Archetype_AndBack() + { + var result = ConvertModelToArchetypeAndBack(_captions); + Assert.NotNull(result); + Assert.NotNull(result.TextArray); + + Assert.AreEqual(3, result.TextArray.Count); + + foreach (var caption in result.TextArray) + { + var index = result.TextArray.IndexOf(caption); + Assert.AreEqual(_captions.TextArray.ElementAt(index).TextString, caption.TextString); + } + } + + #endregion + } +} diff --git a/app/Umbraco/Archetype.Tests/Serialization/UseCases/Enumerable/JsonTestModels.cs b/app/Umbraco/Archetype.Tests/Serialization/UseCases/Enumerable/JsonTestModels.cs new file mode 100644 index 0000000..7e7fdf4 --- /dev/null +++ b/app/Umbraco/Archetype.Tests/Serialization/UseCases/Enumerable/JsonTestModels.cs @@ -0,0 +1,58 @@ +using System; +using System.Collections.Generic; +using Archetype.Serialization; +using Newtonsoft.Json; + +namespace Archetype.Tests.Serialization.UseCases.Enumerable +{ + #region Feedback - single fieldset with multiple items + + [AsArchetype("feedbacks")] /* Note: when inheriting from a list, archetype alias is not used */ + [JsonConverter(typeof(ArchetypeJsonConverter))] + public class Feedbacks : List + { + } + + [AsArchetype("feedback")] /* Must have same archetype alias as list class */ + [JsonConverter(typeof(ArchetypeJsonConverter))] + public class Feedback + { + [JsonProperty("testimonial")] + public String Testimonial { get; set; } + } + + #endregion + + #region Captions - a root fieldset which contains another fieldset list + + [AsArchetype("captions")] + [JsonConverter(typeof(ArchetypeJsonConverter))] + public class Captions + { + [JsonProperty("captions")] + public List TextArray { get; set; } + } + + [AsArchetype("textArray")] + [JsonConverter(typeof(ArchetypeJsonConverter))] + public class Text + { + [JsonProperty("textstring")] + public String TextString { get; set; } + } + + #endregion + + + [AsArchetype("aboutUs")] + [JsonConverter(typeof(ArchetypeJsonConverter))] + public class AboutUs + { + [AsFieldset] + [JsonProperty("contacts")] + public IEnumerable Contacts { get; set; } + [AsFieldset] + [JsonProperty("testimonials")] + public IEnumerable Testimonials { get; set; } + } +} diff --git a/app/Umbraco/Archetype.Tests/Serialization/UseCases/Enumerable/JsonTestStrings.cs b/app/Umbraco/Archetype.Tests/Serialization/UseCases/Enumerable/JsonTestStrings.cs new file mode 100644 index 0000000..1dd8132 --- /dev/null +++ b/app/Umbraco/Archetype.Tests/Serialization/UseCases/Enumerable/JsonTestStrings.cs @@ -0,0 +1,86 @@ +namespace Archetype.Tests.Serialization.UseCases.Enumerable +{ + public class JsonTestStrings + { + public const string _ABOUT_US_JSON = + @""; + + public const string _FEEDBACK_JSON = + @"{ + ""fieldsets"": [ + { + ""alias"": ""feedback"", + ""properties"": [ + { + ""alias"": ""testimonial"", + ""value"": ""Testimonial 1"" + } + ] + }, + { + ""alias"": ""feedback"", + ""properties"": [ + { + ""alias"": ""testimonial"", + ""value"": ""Testimonial 2"" + } + ] + }, + { + ""alias"": ""feedback"", + ""properties"": [ + { + ""alias"": ""testimonial"", + ""value"": ""Testimonial 3"" + } + ] + } + ] +}"; + + public const string _CAPTIONS_JSON = + @"{ + ""fieldsets"": [ + { + ""alias"": ""captions"", + ""properties"": [ + { + ""alias"": ""captions"", + ""value"": { + ""fieldsets"": [ + { + ""alias"": ""textArray"", + ""properties"": [ + { + ""alias"": ""textstring"", + ""value"": ""Caption 1"" + } + ] + }, + { + ""alias"": ""textArray"", + ""properties"": [ + { + ""alias"": ""textstring"", + ""value"": ""Caption 2"" + } + ] + }, + { + ""alias"": ""textArray"", + ""properties"": [ + { + ""alias"": ""textstring"", + ""value"": ""Caption 3"" + } + ] + } + ] + } + } + ] + } + ] +}"; + } +} diff --git a/app/Umbraco/Archetype.Tests/Serialization/JsonTestModels.cs b/app/Umbraco/Archetype.Tests/Serialization/UseCases/JsonTestModels.cs similarity index 56% rename from app/Umbraco/Archetype.Tests/Serialization/JsonTestModels.cs rename to app/Umbraco/Archetype.Tests/Serialization/UseCases/JsonTestModels.cs index c9a5129..e2ce96f 100644 --- a/app/Umbraco/Archetype.Tests/Serialization/JsonTestModels.cs +++ b/app/Umbraco/Archetype.Tests/Serialization/UseCases/JsonTestModels.cs @@ -3,7 +3,7 @@ using System.Collections.Generic; using Archetype.Serialization; using Newtonsoft.Json; -namespace Archetype.Tests.Serialization +namespace Archetype.Tests.Serialization.UseCases { #region json test Models @@ -89,91 +89,5 @@ namespace Archetype.Tests.Serialization public decimal MergerValue { get; set; } } - #endregion - - #region complex nested model - - [AsArchetype("pages")] - [JsonConverter(typeof(ArchetypeJsonConverter))] - public class PageDetails - { - [JsonProperty("pages")] - public string Pages { get; set; } - [AsFieldset] - [JsonProperty("captions")] - public Captions Captions { get; set; } - } - - [AsArchetype("captions")] - [JsonConverter(typeof(ArchetypeJsonConverter))] - public class Captions - { - [JsonProperty("captions")] - public TextList TextStringArray { get; set; } - } - - [AsArchetype("textstringArray")] - [JsonConverter(typeof(ArchetypeJsonConverter))] - public class TextList : List - { - } - - [AsArchetype("textstringArray")] - [JsonConverter(typeof(ArchetypeJsonConverter))] - public class TextItem - { - [JsonProperty("textstring")] - public string TextString { get; set; } - } - - #endregion - - #region complex nested tree model - - public abstract class PageBase - { - public string PageTitle { get; set; } - public string BodyText { get; set; } - } - - [AsArchetype("slideShow")] - [JsonConverter(typeof(ArchetypeJsonConverter))] - public class SlideShow - { - public string Slides { get; set; } - } - - [AsArchetype("seo")] - [JsonConverter(typeof(ArchetypeJsonConverter))] - public class Seo - { - public string MetaTitle { get; set; } - public string MetaDescription { get; set; } - } - - [AsArchetype("TextPage")] - [JsonConverter(typeof(ArchetypeJsonConverter))] - public class TextPage : PageBase - { - [AsFieldset] - public SlideShow Media { get; set; } - - [AsFieldset] - public Seo Seo { get; set; } - } - - [AsArchetype("TextPageList")] - [JsonConverter(typeof(ArchetypeJsonConverter))] - public class TextPageList : List - { - } - - [AsArchetype("Pages")] - [JsonConverter(typeof(ArchetypeJsonConverter))] - public class PageList - { - public TextPageList Pages { get; set; } - } - - #endregion + #endregion } diff --git a/app/Umbraco/Archetype.Tests/Serialization/UseCases/JsonTestStrings.cs b/app/Umbraco/Archetype.Tests/Serialization/UseCases/JsonTestStrings.cs new file mode 100644 index 0000000..6d0a506 --- /dev/null +++ b/app/Umbraco/Archetype.Tests/Serialization/UseCases/JsonTestStrings.cs @@ -0,0 +1,207 @@ +namespace Archetype.Tests.Serialization.UseCases +{ + public class JsonTestStrings + { + public const string _MERGER_DETAILS_JSON = + @"{ + ""fieldsets"": [ + { + ""alias"": ""mergerDetails"", + ""properties"": [ + { + ""alias"": ""MergerDate"", + ""value"": ""07/06/2014 08:09:10"" + } + ] + } + ] +}"; + + public const string _ANNUAL_STATEMENT_JSON = + @"{ + ""fieldsets"": [ + { + ""alias"": ""annualStatement"", + ""properties"": [ + { + ""alias"": ""FiscalYearStart"", + ""value"": ""01/09/2013 00:00:00"" + }, + { + ""alias"": ""FiscalYearEnd"", + ""value"": ""31/08/2014 00:00:00"" + }, + { + ""alias"": ""DividendPaymentDate"", + ""value"": """" + }, + { + ""alias"": ""TotalShares"", + ""value"": ""345678"" + }, + { + ""alias"": ""Sales"", + ""value"": ""123456700.89"" + }, + { + ""alias"": ""Profit"", + ""value"": ""1123456.78"" + } + ] + } + ] +}"; + + public const string _CONTACT_DETAILS_JSON = + @"{ + ""fieldsets"": [ + { + ""alias"": ""contactDetails"", + ""properties"": [ + { + ""alias"": ""name"", + ""value"": ""Test"" + }, + { + ""alias"": ""address"", + ""value"": ""Test Address"" + }, + { + ""alias"": ""telephone"", + ""value"": ""111"" + }, + { + ""alias"": ""mobile"", + ""value"": ""000"" + }, + { + ""alias"": ""fax"", + ""value"": ""000"" + }, + { + ""alias"": ""email"", + ""value"": ""test@test.com"" + }, + { + ""alias"": ""webSite"", + ""value"": { + ""fieldsets"": [ + { + ""alias"": ""urlPicker"", + ""properties"": [ + { + ""alias"": ""title"", + ""value"": ""The Test Company"" + }, + { + ""alias"": ""url"", + ""value"": ""http://test.com"" + }, + { + ""alias"": ""content"", + ""value"": """" + }, + { + ""alias"": ""media"", + ""value"": """" + }, + { + ""alias"": ""openInNewWindow"", + ""value"": ""1"" + } + ] + } + ] + } + } + ] + } + ] +}"; + + public const string _COMPANY_DETAILS_JSON = + @"{ + ""fieldsets"": [ + { + ""alias"": ""companyDetails"", + ""properties"": [ + { + ""alias"": ""region"", + ""value"": ""Test Region"" + }, + { + ""alias"": ""contactDetails"", + ""value"": { + ""fieldsets"": [ + { + ""alias"": ""contactDetails"", + ""properties"": [ + { + ""alias"": ""name"", + ""value"": ""Test"" + }, + { + ""alias"": ""address"", + ""value"": ""Test Address"" + }, + { + ""alias"": ""telephone"", + ""value"": ""111"" + }, + { + ""alias"": ""mobile"", + ""value"": ""000"" + }, + { + ""alias"": ""fax"", + ""value"": ""000"" + }, + { + ""alias"": ""email"", + ""value"": ""test@test.com"" + }, + { + ""alias"": ""webSite"", + ""value"": { + ""fieldsets"": [ + { + ""alias"": ""urlPicker"", + ""properties"": [ + { + ""alias"": ""title"", + ""value"": ""The Test Company"" + }, + { + ""alias"": ""url"", + ""value"": ""http://test.com"" + }, + { + ""alias"": ""content"", + ""value"": """" + }, + { + ""alias"": ""media"", + ""value"": """" + }, + { + ""alias"": ""openInNewWindow"", + ""value"": ""1"" + } + ] + } + ] + } + } + ] + } + ] + } + } + ] + } + ] +}"; + + public const string _NULL_VALUES_JSON = @"{""fieldsets"":[{""alias"":""contactDetails"",""properties"":[{""alias"":""name"",""value"":""""},{""alias"":""address"",""value"":""""},{""alias"":""telephone"",""value"":""""},{""alias"":""mobile"",""value"":""""},{""alias"":""fax"",""value"":""""},{""alias"":""email"",""value"":""""},{""alias"":""webSite"",""value"":""""}]}]}"; + } +} diff --git a/app/Umbraco/Archetype.Tests/SupportingFiles/config/umbracoSettings.config b/app/Umbraco/Archetype.Tests/SupportingFiles/config/umbracoSettings.config new file mode 100644 index 0000000..2ccc8a5 --- /dev/null +++ b/app/Umbraco/Archetype.Tests/SupportingFiles/config/umbracoSettings.config @@ -0,0 +1,109 @@ + + + + + + + + + 1 + + + + + + your@email.here + + + + text + + + In Preview Mode - click to end]]> + + + + 1800 + + + inline + + + ashx,aspx,ascx,config,cshtml,vbhtml,asmx,air,axd + + + Textstring + + + + + false + + false + + + + + false + + true + + + + + Mvc + + + + + + + + + + + + 0 + + + + + + + + + + + + + diff --git a/app/Umbraco/Archetype.Tests/app.config b/app/Umbraco/Archetype.Tests/app.config index 72cac16..786460d 100644 --- a/app/Umbraco/Archetype.Tests/app.config +++ b/app/Umbraco/Archetype.Tests/app.config @@ -1,6 +1,14 @@  - + + +
+ + + + + + diff --git a/app/Umbraco/Umbraco.Archetype.sln b/app/Umbraco/Umbraco.Archetype.sln index bb5fa55..03c1b73 100644 --- a/app/Umbraco/Umbraco.Archetype.sln +++ b/app/Umbraco/Umbraco.Archetype.sln @@ -1,39 +1,39 @@ - -Microsoft Visual Studio Solution File, Format Version 12.00 -# Visual Studio 2012 -Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Archetype.Umbraco", "Umbraco.Archetype\Archetype.Umbraco.csproj", "{7D185D41-4228-4978-ACB8-83F9A48AD94F}" -EndProject -Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = ".nuget", ".nuget", "{D84AA4ED-85A6-484F-9E72-BE7AC9835821}" - ProjectSection(SolutionItems) = preProject - .nuget\NuGet.Config = .nuget\NuGet.Config - .nuget\NuGet.exe = .nuget\NuGet.exe - .nuget\NuGet.targets = .nuget\NuGet.targets - EndProjectSection -EndProject -Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Archetype.Tests", "Archetype.Tests\Archetype.Tests.csproj", "{21F3E6CF-B76F-4059-9474-1AF1CE63CD6B}" -EndProject -Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "DatabaseSizer", "DatabaseSizer\DatabaseSizer.csproj", "{0114C963-C514-49C1-B7AB-DCB1825F498C}" -EndProject -Global - GlobalSection(SolutionConfigurationPlatforms) = preSolution - Debug|Any CPU = Debug|Any CPU - Release|Any CPU = Release|Any CPU - EndGlobalSection - GlobalSection(ProjectConfigurationPlatforms) = postSolution - {7D185D41-4228-4978-ACB8-83F9A48AD94F}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {7D185D41-4228-4978-ACB8-83F9A48AD94F}.Debug|Any CPU.Build.0 = Debug|Any CPU - {7D185D41-4228-4978-ACB8-83F9A48AD94F}.Release|Any CPU.ActiveCfg = Release|Any CPU - {7D185D41-4228-4978-ACB8-83F9A48AD94F}.Release|Any CPU.Build.0 = Release|Any CPU - {21F3E6CF-B76F-4059-9474-1AF1CE63CD6B}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {21F3E6CF-B76F-4059-9474-1AF1CE63CD6B}.Debug|Any CPU.Build.0 = Debug|Any CPU - {21F3E6CF-B76F-4059-9474-1AF1CE63CD6B}.Release|Any CPU.ActiveCfg = Release|Any CPU - {21F3E6CF-B76F-4059-9474-1AF1CE63CD6B}.Release|Any CPU.Build.0 = Release|Any CPU - {0114C963-C514-49C1-B7AB-DCB1825F498C}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {0114C963-C514-49C1-B7AB-DCB1825F498C}.Debug|Any CPU.Build.0 = Debug|Any CPU - {0114C963-C514-49C1-B7AB-DCB1825F498C}.Release|Any CPU.ActiveCfg = Release|Any CPU - {0114C963-C514-49C1-B7AB-DCB1825F498C}.Release|Any CPU.Build.0 = Release|Any CPU - EndGlobalSection - GlobalSection(SolutionProperties) = preSolution - HideSolutionNode = FALSE - EndGlobalSection -EndGlobal + +Microsoft Visual Studio Solution File, Format Version 12.00 +# Visual Studio 2012 +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Archetype.Umbraco", "Umbraco.Archetype\Archetype.Umbraco.csproj", "{7D185D41-4228-4978-ACB8-83F9A48AD94F}" +EndProject +Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = ".nuget", ".nuget", "{D84AA4ED-85A6-484F-9E72-BE7AC9835821}" + ProjectSection(SolutionItems) = preProject + .nuget\NuGet.Config = .nuget\NuGet.Config + .nuget\NuGet.exe = .nuget\NuGet.exe + .nuget\NuGet.targets = .nuget\NuGet.targets + EndProjectSection +EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Archetype.Tests", "Archetype.Tests\Archetype.Tests.csproj", "{21F3E6CF-B76F-4059-9474-1AF1CE63CD6B}" +EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "DatabaseSizer", "DatabaseSizer\DatabaseSizer.csproj", "{0114C963-C514-49C1-B7AB-DCB1825F498C}" +EndProject +Global + GlobalSection(SolutionConfigurationPlatforms) = preSolution + Debug|Any CPU = Debug|Any CPU + Release|Any CPU = Release|Any CPU + EndGlobalSection + GlobalSection(ProjectConfigurationPlatforms) = postSolution + {7D185D41-4228-4978-ACB8-83F9A48AD94F}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {7D185D41-4228-4978-ACB8-83F9A48AD94F}.Debug|Any CPU.Build.0 = Debug|Any CPU + {7D185D41-4228-4978-ACB8-83F9A48AD94F}.Release|Any CPU.ActiveCfg = Release|Any CPU + {7D185D41-4228-4978-ACB8-83F9A48AD94F}.Release|Any CPU.Build.0 = Release|Any CPU + {21F3E6CF-B76F-4059-9474-1AF1CE63CD6B}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {21F3E6CF-B76F-4059-9474-1AF1CE63CD6B}.Debug|Any CPU.Build.0 = Debug|Any CPU + {21F3E6CF-B76F-4059-9474-1AF1CE63CD6B}.Release|Any CPU.ActiveCfg = Release|Any CPU + {21F3E6CF-B76F-4059-9474-1AF1CE63CD6B}.Release|Any CPU.Build.0 = Release|Any CPU + {0114C963-C514-49C1-B7AB-DCB1825F498C}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {0114C963-C514-49C1-B7AB-DCB1825F498C}.Debug|Any CPU.Build.0 = Debug|Any CPU + {0114C963-C514-49C1-B7AB-DCB1825F498C}.Release|Any CPU.ActiveCfg = Release|Any CPU + {0114C963-C514-49C1-B7AB-DCB1825F498C}.Release|Any CPU.Build.0 = Release|Any CPU + EndGlobalSection + GlobalSection(SolutionProperties) = preSolution + HideSolutionNode = FALSE + EndGlobalSection +EndGlobal diff --git a/app/Umbraco/Umbraco.Archetype/Archetype.Umbraco.csproj b/app/Umbraco/Umbraco.Archetype/Archetype.Umbraco.csproj index 678f3dd..a038f86 100644 --- a/app/Umbraco/Umbraco.Archetype/Archetype.Umbraco.csproj +++ b/app/Umbraco/Umbraco.Archetype/Archetype.Umbraco.csproj @@ -1,265 +1,266 @@ - - - - - Debug - AnyCPU - {7D185D41-4228-4978-ACB8-83F9A48AD94F} - Library - Properties - Archetype - Archetype - v4.5 - 512 - ..\ - true - - - true - full - false - bin\Debug\ - DEBUG;TRACE - prompt - 4 - - - pdbonly - true - bin\Release\ - TRACE - prompt - 4 - - - - ..\packages\AutoMapper.3.0.0\lib\net40\AutoMapper.dll - False - - - ..\packages\AutoMapper.3.0.0\lib\net40\AutoMapper.Net4.dll - False - - - ..\packages\UmbracoCms.Core.7.1.2\lib\businesslogic.dll - False - - - ..\packages\ClientDependency.1.7.1.2\lib\ClientDependency.Core.dll - False - - - ..\packages\ClientDependency-Mvc.1.7.0.4\lib\ClientDependency.Core.Mvc.dll - False - - - ..\packages\UmbracoCms.Core.7.1.2\lib\cms.dll - False - - - ..\packages\UmbracoCms.Core.7.1.2\lib\controls.dll - False - - - ..\packages\xmlrpcnet.2.5.0\lib\net20\CookComputing.XmlRpcV2.dll - False - - - ..\packages\UmbracoCms.Core.7.1.2\lib\Examine.dll - False - - - ..\packages\HtmlAgilityPack.1.4.6\lib\Net45\HtmlAgilityPack.dll - False - - - ..\packages\SharpZipLib.0.86.0\lib\20\ICSharpCode.SharpZipLib.dll - False - - - ..\packages\ImageProcessor.1.9.0.0\lib\ImageProcessor.dll - False - - - ..\packages\ImageProcessor.Web.3.2.3.0\lib\net45\ImageProcessor.Web.dll - False - - - ..\packages\UmbracoCms.Core.7.1.2\lib\interfaces.dll - False - - - ..\packages\UmbracoCms.Core.7.1.2\lib\log4net.dll - False - - - ..\packages\Lucene.Net.2.9.4.1\lib\net40\Lucene.Net.dll - False - - - ..\packages\UmbracoCms.Core.7.1.2\lib\Microsoft.ApplicationBlocks.Data.dll - False - - - ..\packages\UmbracoCms.Core.7.1.2\lib\Microsoft.Web.Helpers.dll - False - - - False - ..\packages\Microsoft.Web.Infrastructure.1.0.0.0\lib\net40\Microsoft.Web.Infrastructure.dll - - - ..\packages\Microsoft.AspNet.Mvc.FixedDisplayModes.1.0.1\lib\net40\Microsoft.Web.Mvc.FixedDisplayModes.dll - False - - - ..\packages\MiniProfiler.2.1.0\lib\net40\MiniProfiler.dll - False - - - ..\packages\MySql.Data.6.6.5\lib\net40\MySql.Data.dll - False - - - ..\packages\Newtonsoft.Json.6.0.2\lib\net45\Newtonsoft.Json.dll - False - - - ..\packages\UmbracoCms.Core.7.1.2\lib\SQLCE4Umbraco.dll - False - - - - - False - ..\packages\UmbracoCms.Core.7.1.2\lib\System.Data.SqlServerCe.dll - - - False - ..\packages\UmbracoCms.Core.7.1.2\lib\System.Data.SqlServerCe.Entity.dll - - - - ..\packages\Microsoft.AspNet.WebApi.Client.4.0.30506.0\lib\net40\System.Net.Http.Formatting.dll - False - - - - - False - ..\packages\Microsoft.AspNet.WebPages.2.0.30506.0\lib\net40\System.Web.Helpers.dll - - - ..\packages\Microsoft.AspNet.WebApi.Core.4.0.30506.0\lib\net40\System.Web.Http.dll - False - - - ..\packages\Microsoft.AspNet.WebApi.WebHost.4.0.30506.0\lib\net40\System.Web.Http.WebHost.dll - False - - - False - ..\packages\Microsoft.AspNet.Mvc.4.0.30506.0\lib\net40\System.Web.Mvc.dll - - - False - ..\packages\Microsoft.AspNet.Razor.2.0.30506.0\lib\net40\System.Web.Razor.dll - - - False - ..\packages\Microsoft.AspNet.WebPages.2.0.30506.0\lib\net40\System.Web.WebPages.dll - - - False - ..\packages\Microsoft.AspNet.WebPages.2.0.30506.0\lib\net40\System.Web.WebPages.Deployment.dll - - - False - ..\packages\Microsoft.AspNet.WebPages.2.0.30506.0\lib\net40\System.Web.WebPages.Razor.dll - - - - - - - - ..\packages\UmbracoCms.Core.7.1.2\lib\TidyNet.dll - False - - - ..\packages\UmbracoCms.Core.7.1.2\lib\umbraco.dll - False - - - ..\packages\UmbracoCms.Core.7.1.2\lib\Umbraco.Core.dll - False - - - ..\packages\UmbracoCms.Core.7.1.2\lib\umbraco.DataLayer.dll - False - - - ..\packages\UmbracoCms.Core.7.1.2\lib\umbraco.editorControls.dll - False - - - ..\packages\UmbracoCms.Core.7.1.2\lib\umbraco.MacroEngines.dll - False - - - ..\packages\UmbracoCms.Core.7.1.2\lib\umbraco.providers.dll - False - - - ..\packages\UmbracoCms.Core.7.1.2\lib\Umbraco.Web.UI.dll - False - - - ..\packages\UmbracoCms.Core.7.1.2\lib\umbraco.XmlSerializers.dll - False - - - ..\packages\UmbracoCms.Core.7.1.2\lib\UmbracoExamine.dll - False - - - ..\packages\UmbracoCms.Core.7.1.2\lib\UrlRewritingNet.UrlRewriter.dll - False - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + Debug + AnyCPU + {7D185D41-4228-4978-ACB8-83F9A48AD94F} + Library + Properties + Archetype + Archetype + v4.5 + 512 + ..\ + true + + + true + full + false + bin\Debug\ + DEBUG;TRACE + prompt + 4 + + + pdbonly + true + bin\Release\ + TRACE + prompt + 4 + + + + ..\packages\AutoMapper.3.0.0\lib\net40\AutoMapper.dll + False + + + ..\packages\AutoMapper.3.0.0\lib\net40\AutoMapper.Net4.dll + False + + + ..\packages\UmbracoCms.Core.7.1.2\lib\businesslogic.dll + False + + + ..\packages\ClientDependency.1.7.1.2\lib\ClientDependency.Core.dll + False + + + ..\packages\ClientDependency-Mvc.1.7.0.4\lib\ClientDependency.Core.Mvc.dll + False + + + ..\packages\UmbracoCms.Core.7.1.2\lib\cms.dll + False + + + ..\packages\UmbracoCms.Core.7.1.2\lib\controls.dll + False + + + ..\packages\xmlrpcnet.2.5.0\lib\net20\CookComputing.XmlRpcV2.dll + False + + + ..\packages\UmbracoCms.Core.7.1.2\lib\Examine.dll + False + + + ..\packages\HtmlAgilityPack.1.4.6\lib\Net45\HtmlAgilityPack.dll + False + + + ..\packages\SharpZipLib.0.86.0\lib\20\ICSharpCode.SharpZipLib.dll + False + + + ..\packages\ImageProcessor.1.9.0.0\lib\ImageProcessor.dll + False + + + ..\packages\ImageProcessor.Web.3.2.3.0\lib\net45\ImageProcessor.Web.dll + False + + + ..\packages\UmbracoCms.Core.7.1.2\lib\interfaces.dll + False + + + ..\packages\UmbracoCms.Core.7.1.2\lib\log4net.dll + False + + + ..\packages\Lucene.Net.2.9.4.1\lib\net40\Lucene.Net.dll + False + + + ..\packages\UmbracoCms.Core.7.1.2\lib\Microsoft.ApplicationBlocks.Data.dll + False + + + ..\packages\UmbracoCms.Core.7.1.2\lib\Microsoft.Web.Helpers.dll + False + + + False + ..\packages\Microsoft.Web.Infrastructure.1.0.0.0\lib\net40\Microsoft.Web.Infrastructure.dll + + + ..\packages\Microsoft.AspNet.Mvc.FixedDisplayModes.1.0.1\lib\net40\Microsoft.Web.Mvc.FixedDisplayModes.dll + False + + + ..\packages\MiniProfiler.2.1.0\lib\net40\MiniProfiler.dll + False + + + ..\packages\MySql.Data.6.6.5\lib\net40\MySql.Data.dll + False + + + ..\packages\Newtonsoft.Json.6.0.2\lib\net45\Newtonsoft.Json.dll + False + + + ..\packages\UmbracoCms.Core.7.1.2\lib\SQLCE4Umbraco.dll + False + + + + + False + ..\packages\UmbracoCms.Core.7.1.2\lib\System.Data.SqlServerCe.dll + + + False + ..\packages\UmbracoCms.Core.7.1.2\lib\System.Data.SqlServerCe.Entity.dll + + + + ..\packages\Microsoft.AspNet.WebApi.Client.4.0.30506.0\lib\net40\System.Net.Http.Formatting.dll + False + + + + + False + ..\packages\Microsoft.AspNet.WebPages.2.0.30506.0\lib\net40\System.Web.Helpers.dll + + + ..\packages\Microsoft.AspNet.WebApi.Core.4.0.30506.0\lib\net40\System.Web.Http.dll + False + + + ..\packages\Microsoft.AspNet.WebApi.WebHost.4.0.30506.0\lib\net40\System.Web.Http.WebHost.dll + False + + + False + ..\packages\Microsoft.AspNet.Mvc.4.0.30506.0\lib\net40\System.Web.Mvc.dll + + + False + ..\packages\Microsoft.AspNet.Razor.2.0.30506.0\lib\net40\System.Web.Razor.dll + + + False + ..\packages\Microsoft.AspNet.WebPages.2.0.30506.0\lib\net40\System.Web.WebPages.dll + + + False + ..\packages\Microsoft.AspNet.WebPages.2.0.30506.0\lib\net40\System.Web.WebPages.Deployment.dll + + + False + ..\packages\Microsoft.AspNet.WebPages.2.0.30506.0\lib\net40\System.Web.WebPages.Razor.dll + + + + + + + + ..\packages\UmbracoCms.Core.7.1.2\lib\TidyNet.dll + False + + + ..\packages\UmbracoCms.Core.7.1.2\lib\umbraco.dll + False + + + ..\packages\UmbracoCms.Core.7.1.2\lib\Umbraco.Core.dll + False + + + ..\packages\UmbracoCms.Core.7.1.2\lib\umbraco.DataLayer.dll + False + + + ..\packages\UmbracoCms.Core.7.1.2\lib\umbraco.editorControls.dll + False + + + ..\packages\UmbracoCms.Core.7.1.2\lib\umbraco.MacroEngines.dll + False + + + ..\packages\UmbracoCms.Core.7.1.2\lib\umbraco.providers.dll + False + + + ..\packages\UmbracoCms.Core.7.1.2\lib\Umbraco.Web.UI.dll + False + + + ..\packages\UmbracoCms.Core.7.1.2\lib\umbraco.XmlSerializers.dll + False + + + ..\packages\UmbracoCms.Core.7.1.2\lib\UmbracoExamine.dll + False + + + ..\packages\UmbracoCms.Core.7.1.2\lib\UrlRewritingNet.UrlRewriter.dll + False + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/app/Umbraco/Umbraco.Archetype/Extensions/Extensions.cs b/app/Umbraco/Umbraco.Archetype/Extensions/Extensions.cs index 7206088..5bcaae2 100644 --- a/app/Umbraco/Umbraco.Archetype/Extensions/Extensions.cs +++ b/app/Umbraco/Umbraco.Archetype/Extensions/Extensions.cs @@ -1,84 +1,82 @@ -using System; -using System.Web; -using System.Web.Mvc; -using System.Web.Mvc.Html; -using System.Text; -using System.Text.RegularExpressions; -using System.Collections.Generic; -using Umbraco.Core; -using Umbraco.Core.Logging; -using Umbraco.Web; -using Archetype.Models; - -namespace Archetype.Extensions -{ - public static class Extensions - { - //lifted from the core as it is marked 'internal' - public static bool DetectIsJson(this string input) - { - input = input.Trim(); - return input.StartsWith("{") && input.EndsWith("}") - || input.StartsWith("[") && input.EndsWith("]"); - } - - public static bool IsArchetype(this ArchetypePropertyModel prop) - { - return prop.PropertyEditorAlias.InvariantEquals(Constants.PropertyEditorAlias); - } - - public static IHtmlString RenderArchetypePartials(this HtmlHelper htmlHelper, ArchetypeModel archetypeModel) - { - return RenderPartials(htmlHelper, archetypeModel, null, null); - } - - public static IHtmlString RenderArchetypePartials(this HtmlHelper htmlHelper, ArchetypeModel archetypeModel, string partialPath) - { - return RenderPartials(htmlHelper, archetypeModel, partialPath, null); - } - - public static IHtmlString RenderArchetypePartials(this HtmlHelper htmlHelper, ArchetypeModel archetypeModel, ViewDataDictionary viewDataDictionary) - { - return RenderPartials(htmlHelper, archetypeModel, null, viewDataDictionary); - } - - public static IHtmlString RenderArchetypePartials(this HtmlHelper htmlHelper, ArchetypeModel archetypeModel, string partialPath, ViewDataDictionary viewDataDictionary) - { - return RenderPartials(htmlHelper, archetypeModel, partialPath, viewDataDictionary); - } - - private static IHtmlString RenderPartials(HtmlHelper htmlHelper, ArchetypeModel archetypeModel, string partialPath, ViewDataDictionary viewDataDictionary) - { - var context = HttpContext.Current; - - if (archetypeModel == null || context == null) - { - return new HtmlString(""); - } - - var sb = new StringBuilder(); - - var pathToPartials = "~/Views/Partials/Archetype/"; - if (!string.IsNullOrEmpty(partialPath)) - { - pathToPartials = partialPath; - } - - foreach (var fieldsetModel in archetypeModel) - { - var partial = pathToPartials + fieldsetModel.Alias + ".cshtml"; - - if (System.IO.File.Exists(context.Server.MapPath(partial))) - { - sb.AppendLine(htmlHelper.Partial(partial, fieldsetModel, viewDataDictionary).ToString()); - } - else - { - LogHelper.Info(string.Format("The partial for {0} could not be found. Please create a partial with that name or rename your alias.", context.Server.MapPath(partial))); - } - } - - return new HtmlString(sb.ToString()); - } - } -} +using System; +using System.Linq; +using System.Web.Mvc; +using System.Web.Mvc.Html; +using System.Text.RegularExpressions; +using System.Collections.Generic; +using Umbraco.Core; +using Umbraco.Core.Logging; +using Archetype.Models; + +namespace Archetype.Extensions +{ + public static class Extensions + { + //lifted from the core as it is marked 'internal' + public static bool DetectIsJson(this string input) + { + input = input.Trim(); + return input.StartsWith("{") && input.EndsWith("}") + || input.StartsWith("[") && input.EndsWith("]"); + } + + public static bool IsArchetype(this ArchetypePropertyModel prop) + { + return prop.PropertyEditorAlias.InvariantEquals(Constants.PropertyEditorAlias); + } + + public static IHtmlString RenderArchetypePartials(this HtmlHelper htmlHelper, ArchetypeModel archetypeModel) + { + return RenderPartials(htmlHelper, archetypeModel, null, null); + } + + public static IHtmlString RenderArchetypePartials(this HtmlHelper htmlHelper, ArchetypeModel archetypeModel, string partialPath) + { + return RenderPartials(htmlHelper, archetypeModel, partialPath, null); + } + + public static IHtmlString RenderArchetypePartials(this HtmlHelper htmlHelper, ArchetypeModel archetypeModel, ViewDataDictionary viewDataDictionary) + { + return RenderPartials(htmlHelper, archetypeModel, null, viewDataDictionary); + } + + public static IHtmlString RenderArchetypePartials(this HtmlHelper htmlHelper, ArchetypeModel archetypeModel, string partialPath, ViewDataDictionary viewDataDictionary) + { + return RenderPartials(htmlHelper, archetypeModel, partialPath, viewDataDictionary); + } + + private static IHtmlString RenderPartials(HtmlHelper htmlHelper, ArchetypeModel archetypeModel, string partialPath, ViewDataDictionary viewDataDictionary) + { + var context = HttpContext.Current; + + if (archetypeModel == null || context == null) + { + return new HtmlString(""); + } + + var sb = new StringBuilder(); + + var pathToPartials = "~/Views/Partials/Archetype/"; + if (!string.IsNullOrEmpty(partialPath)) + { + pathToPartials = partialPath; + } + + foreach (var fieldsetModel in archetypeModel) + { + var partial = pathToPartials + fieldsetModel.Alias + ".cshtml"; + + if (System.IO.File.Exists(context.Server.MapPath(partial))) + { + sb.AppendLine(htmlHelper.Partial(partial, fieldsetModel, viewDataDictionary).ToString()); + } + else + { + LogHelper.Info(string.Format("The partial for {0} could not be found. Please create a partial with that name or rename your alias.", context.Server.MapPath(partial))); + } + } + + return new HtmlString(sb.ToString()); + } + } +} diff --git a/app/Umbraco/Umbraco.Archetype/Models/ArchetypeModel.cs b/app/Umbraco/Umbraco.Archetype/Models/ArchetypeModel.cs index b057aee..d009fab 100644 --- a/app/Umbraco/Umbraco.Archetype/Models/ArchetypeModel.cs +++ b/app/Umbraco/Umbraco.Archetype/Models/ArchetypeModel.cs @@ -1,7 +1,8 @@ using System; using System.Collections; using System.Collections.Generic; -using System.Linq; +using System.Linq; +using Archetype.Serialization; using Newtonsoft.Json; using Newtonsoft.Json.Linq; @@ -38,7 +39,7 @@ namespace Archetype.Models .ToList() .ForEach(x => x.Remove()); - return json.ToString(Formatting.None); + return json.ToString(Formatting.None).DelintArchetypeJson(); } } } diff --git a/app/Umbraco/Umbraco.Archetype/Properties/VersionInfo.cs b/app/Umbraco/Umbraco.Archetype/Properties/VersionInfo.cs index 9164a1f..80f0895 100644 --- a/app/Umbraco/Umbraco.Archetype/Properties/VersionInfo.cs +++ b/app/Umbraco/Umbraco.Archetype/Properties/VersionInfo.cs @@ -1,4 +1,4 @@ using System.Reflection; [assembly: AssemblyVersion("1.2.1")] -[assembly: AssemblyFileVersion("1.2.1-beta")] +[assembly: AssemblyFileVersion("1.2.1-beta")] \ No newline at end of file diff --git a/app/Umbraco/Umbraco.Archetype/PropertyConverters/ArchetypeValueConverter.cs b/app/Umbraco/Umbraco.Archetype/PropertyConverters/ArchetypeValueConverter.cs index ad99f1c..d70b96c 100644 --- a/app/Umbraco/Umbraco.Archetype/PropertyConverters/ArchetypeValueConverter.cs +++ b/app/Umbraco/Umbraco.Archetype/PropertyConverters/ArchetypeValueConverter.cs @@ -19,7 +19,8 @@ namespace Archetype.PropertyConverters public override bool IsConverter(PublishedPropertyType propertyType) { - return propertyType.PropertyEditorAlias.Equals(Constants.PropertyEditorAlias); + return !String.IsNullOrEmpty(propertyType.PropertyEditorAlias) + && propertyType.PropertyEditorAlias.Equals(Constants.PropertyEditorAlias); } public override object ConvertDataToSource(PublishedPropertyType propertyType, object source, bool preview) diff --git a/app/Umbraco/Umbraco.Archetype/PropertyEditors/ArcheTypePropertyEditor.cs b/app/Umbraco/Umbraco.Archetype/PropertyEditors/ArcheTypePropertyEditor.cs index 6c733b3..eda4715 100644 --- a/app/Umbraco/Umbraco.Archetype/PropertyEditors/ArcheTypePropertyEditor.cs +++ b/app/Umbraco/Umbraco.Archetype/PropertyEditors/ArcheTypePropertyEditor.cs @@ -123,8 +123,8 @@ namespace Archetype.PropertyEditors { var dtd = ApplicationContext.Current.Services.DataTypeService.GetDataTypeDefinitionById(Guid.Parse(propDef.DataTypeGuid)); var preValues = ApplicationContext.Current.Services.DataTypeService.GetPreValuesCollectionByDataTypeId(dtd.Id); - var propData = new ContentPropertyData(propDef.Value, preValues, new Dictionary()); - var propEditor = PropertyEditorResolver.Current.GetByAlias(dtd.PropertyEditorAlias); + var propData = new ContentPropertyData(propDef.Value, preValues, new Dictionary()); + var propEditor = PropertyEditorResolver.Current.GetByAlias(dtd.PropertyEditorAlias); propDef.Value = propEditor.ValueEditor.ConvertEditorToDb(propData, propDef.Value); } catch (Exception ex) @@ -135,7 +135,17 @@ namespace Archetype.PropertyEditors } return archetype.SerializeForPersistence(); - } + } + + internal virtual PropertyEditor GetPropertyEditor(IDataTypeDefinition dtd) + { + if (dtd.Id != 0) + return PropertyEditorResolver.Current.GetByAlias(dtd.PropertyEditorAlias); + + return dtd.PropertyEditorAlias.Equals(Constants.PropertyEditorAlias) + ? new ArchetypePropertyEditor() + : (PropertyEditor)new TextboxPropertyEditor(); + } } #endregion diff --git a/app/Umbraco/Umbraco.Archetype/Serialization/ArchetypeJsonConverter.cs b/app/Umbraco/Umbraco.Archetype/Serialization/ArchetypeJsonConverter.cs index e31c89d..51a8fb7 100644 --- a/app/Umbraco/Umbraco.Archetype/Serialization/ArchetypeJsonConverter.cs +++ b/app/Umbraco/Umbraco.Archetype/Serialization/ArchetypeJsonConverter.cs @@ -6,6 +6,7 @@ using System.IO; using System.Linq; using System.Reflection; using System.Text; +using Archetype.Models; using Newtonsoft.Json; using Newtonsoft.Json.Linq; @@ -13,6 +14,10 @@ namespace Archetype.Serialization { public class ArchetypeJsonConverter : JsonConverter { + private const string _ROOT_FS_ALIAS = "rootFs"; + + #region public methods + public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer) { var models = GenerateModels(value); @@ -23,13 +28,7 @@ namespace Archetype.Serialization if (models.Count == 1 && models[0] == null) return; - var jObj = new JObject - { - { - "fieldsets", - new JArray( new JRaw(SerializeModels(models))) - } - }; + var jObj = SerializeModelToFieldset(models); writer.WriteRaw(ApplyFormatting(jObj.ToString(), writer.Formatting)); } @@ -41,25 +40,265 @@ namespace Archetype.Serialization if (jToken == null) return null; - var obj = Activator.CreateInstance(objectType); - - if (null != obj as IEnumerable - && jToken["fieldsets"] != null && jToken["fieldsets"].Any()) - { - return DeserializeEnumerableObject(obj, jToken); - } - - return null == jToken as JArray - ? DeserializeObject(obj, jToken) - : PopulateProperties(obj, jToken); + return DeserializeJson(objectType, GetDelintedJToken(jToken)); } public override bool CanConvert(Type objectType) { - return IsValueArchetypeDatatype(objectType); + return IsTypeArchetypeDatatype(objectType); } - #region private methods + #endregion + + #region private methods - deserialization + + private JToken GetDelintedJToken(JToken jToken) + { + return JToken.Parse(jToken.ToString(Formatting.None).DelintArchetypeJson()); + } + + private object DeserializeJson(Type objectType, JToken jToken) + { + + var obj = Activator.CreateInstance(objectType); + + if (null != obj as IEnumerable) + { + JToken enumerableToken; + + if (TryParseJTokenAsEnumerable(jToken, out enumerableToken) + || (jToken.SelectToken("value") != null && TryParseJTokenAsEnumerable(jToken["value"], out enumerableToken))) + return DeserializeEnumerableObject(obj, enumerableToken); + } + + return null == jToken as JArray + ? DeserializeObject(obj, jToken) + : PopulateProperties(obj, jToken); + } + + private object DeserializeEnumerableObject(object obj, JToken jToken) + { + var model = obj as IEnumerable; + var fsToken = jToken; + + var itemType = model.GetType().GetGenericArguments().FirstOrDefault(); + + if (itemType == null) + { + itemType = model.GetType().BaseType.GetGenericArguments().First(); + fsToken = fsToken["fieldsets"]; + } + + foreach (var fs in fsToken.Where(fs => fs["alias"].ToString().Equals(GetFieldsetName(itemType)))) + { + var item = DeserializeJson(itemType, fs["properties"]); + + obj.GetType().GetMethod("Add").Invoke(obj, new[] { item }); + } + + return obj; + } + + private object DeserializeObject(object obj, JToken jToken) + { + if (jToken.SelectToken("value") != null + && String.IsNullOrEmpty(jToken.SelectToken("value").ToString())) + return obj; + + var properties = GetSerialiazableProperties(obj).ToList(); + var asFieldset = properties.Where(HasAsFieldsetAttribute).ToList(); + + foreach (var propInfo in asFieldset) + { + var propAlias = GetJsonPropertyName(propInfo); + var fsJToken = propInfo.PropertyType.Namespace.Equals("System") + ? GetFieldsetJTokenFromAlias(propAlias, jToken) + : GetFieldsetJTokenFromPropertyAlias(propInfo, jToken); + + var propJToken = GetPropertyJToken(fsJToken, propAlias); + + if (propJToken == null) + continue; + + var propValue = GetPropertyValue(propInfo, propJToken); + + propInfo.SetValue(obj, propValue); + } + + if (properties.All(HasAsFieldsetAttribute)) + return obj; + + var objToken = GetFieldsetJTokenFromTypeAlias(obj.GetType(), jToken); + + if (objToken == null) + return obj; + + if (objToken.SelectToken("properties") != null) + return PopulateProperties(obj, objToken["properties"]); + + if (!(objToken is JArray) || (objToken as JArray).Count <= 0) + return null; + + var defaultFsProperties = properties.Where(pInfo => !HasAsFieldsetAttribute(pInfo)).ToList(); + + foreach (var property in defaultFsProperties) + { + var propJToken = ParseJTokenFromItems(objToken, GetJsonPropertyName(property)); + PopulateProperty(obj, propJToken["properties"], property); + } + + return PopulateProperties(obj, new JArray(objToken)); + } + + private JToken GetPropertyJToken(JToken fsJToken, string propAlias) + { + if (fsJToken == null) + return null; + + //make recursive + if (fsJToken.SelectToken("properties") != null) + return GetPropertyAliasJToken(propAlias, fsJToken["properties"]); + + var nestedPropJToken = fsJToken + .SingleOrDefault(p => p.SelectToken("alias").ToString().Equals(propAlias)); + + return nestedPropJToken != null ? GetPropertyAliasJToken(propAlias, nestedPropJToken["properties"]) : null; + } + + private JToken GetFieldsetJTokenFromTypeAlias(Type objType, JToken jToken) + { + var objAlias = GetFieldsetName(objType); + return GetFieldsetJTokenFromAlias(objAlias, jToken); + } + + private JToken GetFieldsetJTokenFromPropertyAlias(PropertyInfo propInfo, JToken jToken) + { + var objAlias = GetJsonPropertyName(propInfo); + return GetFieldsetJTokenFromAlias(objAlias, jToken); + } + + private JToken GetFieldsetJTokenFromAlias(string objAlias, JToken jToken) + { + JToken propJToken; + + if (TryParseJTokenFromNamedFieldset(jToken, objAlias, out propJToken)) + return propJToken; + + if (TryParseJTokenFromNestedFieldset(jToken, objAlias, out propJToken)) + return propJToken; + + if (TryParseJTokenFromDefaultFieldset(jToken, out propJToken)) + return propJToken; + + return propJToken + ?? ParseJTokenFromItem(jToken, objAlias); + } + + private object PopulateProperties(object obj, JToken jToken) + { + var properties = GetSerialiazableProperties(obj); + + foreach (var propertyInfo in properties) + { + PopulateProperty(obj, jToken, propertyInfo); + } + + return obj; + } + + private void PopulateProperty(object obj, JToken jToken, PropertyInfo propertyInfo) + { + var propAlias = GetJsonPropertyName(propertyInfo); + var propJToken = GetPropertyAliasJToken(propAlias, jToken); + + if (propJToken == null) + return; + + var propValue = GetPropertyValue(propertyInfo, propJToken); + propertyInfo.SetValue(obj, propValue); + } + + private JToken GetPropertyAliasJToken(string propAlias, JToken jToken) + { + return jToken.SingleOrDefault(p => p.SelectToken("alias").ToString().Equals(propAlias)); + } + + private object GetPropertyValue(PropertyInfo propertyInfo, JToken propJToken) + { + return IsTypeArchetypeDatatype(propertyInfo.PropertyType) + ? DeserializeJson(propertyInfo.PropertyType, propJToken) + : IsTypeIEnumerableArchetypeDatatype(propertyInfo.PropertyType) + ? DeserializeJson(propertyInfo.PropertyType, propJToken["value"].SelectToken("fieldsets")) + : GetDeserializedPropertyValue(propJToken, propertyInfo.PropertyType); + } + + private JToken ParseJTokenFromItem(JToken jToken, string itemAlias) + { + return (jToken.SelectToken("alias") != null && jToken["alias"].ToString().Equals(itemAlias)) + ? jToken + : null; + } + + private JToken ParseJTokenFromItems(JToken jToken, string itemAlias) + { + return jToken.SingleOrDefault(jT => ParseJTokenFromItem(jT, itemAlias) != null); + } + + private bool TryParseJTokenFromNamedFieldset(JToken jToken, string objAlias, out JToken resultToken) + { + resultToken = null; + + if (jToken.SelectToken("fieldsets") == null) + return false; + + resultToken = jToken["fieldsets"].SingleOrDefault(p => p.SelectToken("alias").ToString().Equals(objAlias)); + + return resultToken != null; + } + + private bool TryParseJTokenFromNestedFieldset(JToken jToken, string objAlias, out JToken resultToken) + { + resultToken = null; + + if (jToken.SelectToken("value") == null || !jToken["value"].HasValues + || jToken["value"]["fieldsets"] == null) + return false; + + resultToken = jToken["value"]["fieldsets"].SingleOrDefault(p => p.SelectToken("alias").ToString().Equals(objAlias)); + + return resultToken != null; + } + + private bool TryParseJTokenFromDefaultFieldset(JToken jToken, out JToken resultToken) + { + resultToken = jToken.SelectToken("fieldsets"); + + return resultToken != null; + } + + private bool TryParseJTokenAsEnumerable(JToken jToken, out JToken resultToken) + { + resultToken = null; + + //To Do: Strange newtonsoft behaviour + var fsToken = jToken.Parent != null + ? jToken.Parent.Children().First() is JArray + ? jToken.Parent.Children().First() + : jToken.Parent.Children().First()["fieldsets"] + : jToken.SelectToken("fieldsets"); + + var jTokenEnumerable = jToken != null + && fsToken != null && fsToken is JArray; + + if (jTokenEnumerable) + resultToken = jToken; + + return jTokenEnumerable; + } + + #endregion + + #region private methods - serialization private string ApplyFormatting(string json, Formatting formatting) { @@ -78,113 +317,52 @@ namespace Archetype.Serialization if (!PropertyLayoutHasFieldsets(properties)) return new List() { value }; - var dynamicModel = new ExpandoObject() as IDictionary; + models = new List(); + + var fieldsetModels = properties.Where(HasAsFieldsetAttribute) + .Select(pInfo => + { + var fsModel = GetDynamicModel(GetJsonPropertyName(pInfo)); + fsModel.Add(GetJsonPropertyName(pInfo), pInfo.GetValue(value)); + return fsModel; + }); + + models = ((IEnumerable)models).Concat(fieldsetModels).ToList(); + + var remainingProps = properties.Where(pInfo => !HasAsFieldsetAttribute(pInfo)).ToList(); + + if (!remainingProps.Any()) + return models; + + var dynamicModel = GetDynamicModel(GetFieldsetName(value.GetType())); foreach (var pInfo in properties.Where(pInfo => !HasAsFieldsetAttribute(pInfo))) { dynamicModel.Add(GetJsonPropertyName(pInfo), pInfo.GetValue(value)); } - var fieldsetModels = properties.Where(HasAsFieldsetAttribute) - .Select(pInfo => pInfo.GetValue(value)); - - models = new List - { - dynamicModel, - }; - - models = ((IEnumerable)models).Concat(fieldsetModels).ToList(); + models.Add(dynamicModel); return models; } - private object DeserializeEnumerableObject(object obj, JToken jToken) + private IDictionary GetDynamicModel(string rootFsAlias) { - var model = obj as IEnumerable; + var dynamicModel = new ExpandoObject() as IDictionary; + dynamicModel.Add(_ROOT_FS_ALIAS, rootFsAlias); + return dynamicModel; + } - var itemType = model.GetType().BaseType.GetGenericArguments().First(); - foreach (var fs in jToken["fieldsets"].Where(fs => fs["alias"].ToString().Equals(GetFieldsetName(itemType)))) + private JObject SerializeModelToFieldset(IEnumerable models) + { + var jObj = new JObject { - var item = JsonConvert.DeserializeObject( - fs["properties"].ToString(), itemType, GetArchetypeDatatypeConverter()); - - obj.GetType().GetMethod("Add").Invoke(obj, new[] { item }); - } - - return obj; - } - - private object DeserializeObject(object obj, JToken jToken) - { - var properties = GetSerialiazableProperties(obj).ToList(); - var asFieldset = properties.Where(HasAsFieldsetAttribute).ToList(); - - foreach (var propInfo in asFieldset) - { - var propAlias = GetJsonPropertyName(propInfo); - var fsJToken = GetFieldsetProperties(propInfo.PropertyType, jToken); - var propJToken = - fsJToken.Single(p => p.SelectToken("alias").ToString().Equals(propAlias)); - - if (propJToken == null) - continue; - - var propValue = IsValueArchetypeDatatype(propInfo.PropertyType) - ? JsonConvert.DeserializeObject(fsJToken.ToString(), propInfo.PropertyType, - GetArchetypeDatatypeConverter()) - : GetDeserializedPropertyValue(fsJToken, propInfo.PropertyType); ; - - propInfo.SetValue(obj, propValue); - } - - return PopulateProperties(obj, GetFieldsetProperties(obj.GetType(), jToken)); - } - - private JToken GetFieldsetProperties(Type objType, JToken jToken) - { - var objAlias = GetFieldsetName(objType); - return - jToken["fieldsets"].Single(p => p.SelectToken("alias").ToString().Equals(objAlias)).SelectToken("properties"); - } - - private object PopulateProperties(object obj, JToken jToken) - { - var properties = GetSerialiazableProperties(obj); - - foreach (var propertyInfo in properties) - { - var propAlias = GetJsonPropertyName(propertyInfo); - - var propJToken = jToken.SingleOrDefault(p => p.SelectToken("alias").ToString().Equals(propAlias)); - - if (propJToken == null) - continue; - - var propValue = GetPropertyValue(propertyInfo, propJToken); - - propertyInfo.SetValue(obj, propValue); - } - - return obj; - } - - private object GetPropertyValue(PropertyInfo propertyInfo, JToken propJToken) - { - return IsValueArchetypeDatatype(propertyInfo.PropertyType) - ? JsonConvert.DeserializeObject(propJToken["value"].ToString(), propertyInfo.PropertyType, - GetArchetypeDatatypeConverter()) - : GetDeserializedPropertyValue(propJToken["value"], propertyInfo.PropertyType); - } - - private bool PropertyLayoutHasFieldsets(IEnumerable properties) - { - return properties.Any(HasAsFieldsetAttribute); - } - - private static bool HasAsFieldsetAttribute(PropertyInfo pInfo) - { - return pInfo - .GetCustomAttributes(typeof(AsFieldsetAttribute), true).Length > 0; + { + "fieldsets", + new JArray(new JRaw(SerializeModels(models))) + } + }; + return jObj; } private IEnumerable SerializeModels(IEnumerable models) @@ -200,7 +378,7 @@ namespace Archetype.Serialization return null; var jObj = IsExpandoObject(value) - ? GetJObjectFromExpandoObject(value as IDictionary) + ? GetJObjectFromExpandoObject(value as IDictionary) : GetJObject(value); var fieldsetJson = new StringBuilder(); @@ -214,31 +392,48 @@ namespace Archetype.Serialization return fieldsetJson.ToString(); } + private bool PropertyLayoutHasFieldsets(IEnumerable properties) + { + return properties.Any(HasAsFieldsetAttribute); + } + + private static bool HasAsFieldsetAttribute(PropertyInfo pInfo) + { + return pInfo + .GetCustomAttributes(typeof(AsFieldsetAttribute), true).Length > 0; + } + private bool IsExpandoObject(object value) { return value.GetType().Name.Equals(typeof (ExpandoObject).Name); } - private JObject GetJObjectFromExpandoObject(IEnumerable> obj) + private JObject GetJObjectFromExpandoObject(IDictionary expandoObj) { - var property = obj.ElementAt(0); - var alias = property.Key; - var value = property.Value; - var jObj = new JObject - { - { - "alias", - new JValue(alias) - } - }; - - var fsProperties = new List { - new JObject {new JProperty("alias", alias), new JProperty("value", value)} + { + "alias", + new JValue(expandoObj[_ROOT_FS_ALIAS]) + } }; - jObj.Add("properties", new JRaw(JsonConvert.SerializeObject(fsProperties))); + var fsProperties = new List(); + + foreach (var item in expandoObj.SkipWhile(i => i.Key.Equals(_ROOT_FS_ALIAS))) + { + var property = item; + var alias = property.Key; + var value = property.Value; + + fsProperties.Add(new JObject + { + new JProperty("alias", alias), + new JProperty("value", value != null ? JToken.FromObject(value) : value) + }); + } + + jObj.Add("properties", new JRaw(JsonConvert.SerializeObject(fsProperties))); return jObj; } @@ -252,7 +447,7 @@ namespace Archetype.Serialization } }; - var properties = GetSerialiazableProperties(obj); + var properties = GetProperties(obj); var fsProperties = new List(); @@ -262,14 +457,12 @@ namespace Archetype.Serialization var jProperty = new JProperty("alias", GetJsonPropertyName(propertyInfo)); fsProperty.Add(jProperty); - var propValue = propertyInfo.GetValue(obj, null); + var propValue = propertyInfo.GetIndexParameters().Length == 0 + ? propertyInfo.GetValue(obj, null) + : obj as string; fsProperty.Add( - new JProperty("value", - IsValueArchetypeDatatype(propValue) - ? new JRaw(JsonConvert.SerializeObject(propValue, - GetArchetypeDatatypeConverter())) - : new JValue(GetSerializedPropertyValue(propValue)))); + new JProperty("value", GetJPropertyValue(propValue))); fsProperties.Add(fsProperty); } @@ -279,11 +472,29 @@ namespace Archetype.Serialization return jObj; } + private object GetJPropertyValue(object value) + { + return IsValueArchetypeDatatype(value) + ? new JRaw(JsonConvert.SerializeObject(value)) + : IsValueIEnumerableArchetypeDatatype(value) + ? new JRaw(SerializeModelToFieldset(value as IEnumerable)) + : new JValue(GetSerializedPropertyValue(value)); + } + + private IEnumerable GetProperties(object obj) + { + if (obj.GetType() != typeof(string)) + return GetSerialiazableProperties(obj); + + var indexer = ((DefaultMemberAttribute)obj.GetType() + .GetCustomAttributes(typeof(DefaultMemberAttribute), true)[0]).MemberName; + + return new List { obj.GetType().GetProperty(indexer) }; + } + private IEnumerable GetSerialiazableProperties(object obj) { - return obj.GetType() - .GetProperties(BindingFlags.Instance | BindingFlags.Public) - .Where(prop => !Attribute.IsDefined(prop, typeof(JsonIgnoreAttribute))); + return obj.GetSerialiazableProperties(); } private string GetJsonPropertyName(PropertyInfo property) @@ -302,22 +513,6 @@ namespace Archetype.Serialization return archetypeDatatypeAttribute != null ? archetypeDatatypeAttribute.FieldsetName : type.Name; } - private bool IsValueArchetypeDatatype(object value) - { - return value != null && - IsValueArchetypeDatatype(value.GetType()); - } - - private bool IsValueArchetypeDatatype(Type type) - { - return type.GetCustomAttributes(typeof(AsArchetypeAttribute), true).Length > 0; - } - - private JsonConverter GetArchetypeDatatypeConverter() - { - return (JsonConverter)Activator.CreateInstance(GetType()); - } - private string GetSerializedPropertyValue(object propValue) { if (propValue == null) @@ -330,18 +525,20 @@ namespace Archetype.Serialization } private object GetDeserializedPropertyValue(JToken jToken, Type type) - { - if (String.IsNullOrEmpty(jToken.ToString())) - return GetDefault(type); + { + return String.IsNullOrEmpty(jToken.ToString()) + ? GetDefault(type) + : GetTypedValue(jToken, type); + } - var localType = Nullable.GetUnderlyingType(type) ?? type; + private object GetTypedValue(JToken jToken, Type type) + { + var property = JsonConvert.DeserializeObject(jToken.ToString()); - if (localType == typeof(bool)) - return jToken.ToString() == "1"; + var method = typeof(ArchetypePropertyModel).GetMethod("GetValue"); + var getValue = method.MakeGenericMethod(type); - return localType == typeof(DateTime) - ? Convert.ToDateTime(jToken.ToString()) - : jToken.ToObject(localType); + return getValue.Invoke(property, null); } private object GetDefault(Type type) @@ -350,5 +547,36 @@ namespace Archetype.Serialization } #endregion + + #region private methods - common + + private bool IsValueIEnumerableArchetypeDatatype(object value) + { + if (value as IEnumerable != null && value.GetType().IsGenericType) + return IsTypeArchetypeDatatype(value.GetType().GetGenericArguments()[0]); + + return false; + } + + private bool IsTypeIEnumerableArchetypeDatatype(Type type) + { + if (typeof(IEnumerable).IsAssignableFrom(type) && type.IsGenericType) + return IsTypeArchetypeDatatype(type.GetGenericArguments()[0]); + + return false; + } + + private bool IsValueArchetypeDatatype(object value) + { + return value != null && + IsTypeArchetypeDatatype(value.GetType()); + } + + private bool IsTypeArchetypeDatatype(Type type) + { + return type.GetCustomAttributes(typeof(AsArchetypeAttribute), true).Length > 0; + } + + #endregion } } \ No newline at end of file diff --git a/app/Umbraco/Umbraco.Archetype/Serialization/ArchetypeJsonDelinter.cs b/app/Umbraco/Umbraco.Archetype/Serialization/ArchetypeJsonDelinter.cs new file mode 100644 index 0000000..ea2c55c --- /dev/null +++ b/app/Umbraco/Umbraco.Archetype/Serialization/ArchetypeJsonDelinter.cs @@ -0,0 +1,105 @@ +using System; +using System.Linq; +using System.Collections.Generic; +using System.Text.RegularExpressions; + +namespace Archetype.Serialization +{ + public enum DelinterStep + { + RemoveNewLine = 0, + RemoveWhiteSpace, + UnescapeLabels, + UnescapeAlias, + UnescapeValues, + FixNestedFieldsets + } + + public enum DelinterAction + { + Remove = 0, + RemoveWhiteSpace, + UnescapeLabels, + UnescapeValues, + FixNestedFieldsets + } + + public class ArchetypeJsonDelinter + { + public IDictionary Pipeline { get; private set; } + public IDictionary Tokens { get; private set; } + public IDictionary> Actions { get; private set; } + + public ArchetypeJsonDelinter() + { + Init(); + } + + public string Execute(string input) + { + var buffer = input; + + foreach (var step in Pipeline.Keys) + { + var action = Pipeline[step]; + buffer = Actions[action](buffer, Tokens[step]); + } + + return buffer; + } + + private void Init() + { + Tokens = new Dictionary + { + {DelinterStep.RemoveNewLine, new Regex(@"(?<=\,){0,1}(\\+r\\+n)(?=\\*?""(alias|value|properties|fieldsets)\\*?"":\{*?(\\*|""|\[))|(\r|\n)+|(\\+r\\+n)(?=\s*?(\{|\}|\]))|(\\+r\\n+)(?=\s+\\*?""(alias|value|properties|fieldsets))")}, + {DelinterStep.RemoveWhiteSpace, new Regex(@"(""\S+?"":)(\s+?)("")|([\{\[\}\],]|(?> + { + {DelinterAction.Remove, (input, pattern) => + RecursiveReplace(input, pattern, match => String.Empty) + }, + {DelinterAction.RemoveWhiteSpace, (input, pattern) => + RecursiveReplace(input.Trim(), pattern, match => + String.Format("{0}{1}{2}{3}", match.Groups[1].Value, + match.Groups[3].Value, match.Groups[4].Value, match.Groups[6].Value)) + }, + {DelinterAction.UnescapeLabels, (input, pattern) => + RecursiveReplace(input, pattern, match => String.Format(@"""{0}"":", match.Groups[1].Value)) + }, + {DelinterAction.UnescapeValues, (input, pattern) => + RecursiveReplace(input, pattern, match => String.Format(@"""{0}"":""{1}""", match.Groups[1].Value, match.Groups[2].Value)) + }, + {DelinterAction.FixNestedFieldsets, (input, pattern) => + RecursiveReplace(input, pattern, match => String.Format(@"""{0}"":{{{1}}}", match.Groups[1].Value, match.Groups[2].Value)) + } + }; + + Pipeline = new Dictionary + { + {DelinterStep.RemoveNewLine, DelinterAction.Remove}, + {DelinterStep.UnescapeLabels, DelinterAction.UnescapeLabels}, + {DelinterStep.UnescapeAlias, DelinterAction.UnescapeValues}, + {DelinterStep.UnescapeValues, DelinterAction.UnescapeValues}, + {DelinterStep.FixNestedFieldsets, DelinterAction.FixNestedFieldsets}, + {DelinterStep.RemoveWhiteSpace, DelinterAction.RemoveWhiteSpace}, + }; + } + + private string RecursiveReplace(string input, Regex pattern, Func matchFunc) + { + var buffer = input; + while (pattern.IsMatch(buffer)) + { + buffer = pattern.Replace(buffer, match => matchFunc(match)); + } + return buffer; + } + } +} diff --git a/app/Umbraco/Umbraco.Archetype/Serialization/SerializationExtensions.cs b/app/Umbraco/Umbraco.Archetype/Serialization/SerializationExtensions.cs index 31bab75..9a08778 100644 --- a/app/Umbraco/Umbraco.Archetype/Serialization/SerializationExtensions.cs +++ b/app/Umbraco/Umbraco.Archetype/Serialization/SerializationExtensions.cs @@ -1,8 +1,8 @@ using System; using System.Collections.Generic; using System.Linq; -using System.Text; -using System.Threading.Tasks; +using System.Reflection; +using Archetype.Extensions; using Newtonsoft.Json; using Umbraco.Core.Models; using Umbraco.Web; @@ -20,6 +20,16 @@ namespace Archetype.Serialization return (string)contentPage.Properties.Single(p => p.PropertyTypeAlias == propertyAlias).DataValue; } + public static IEnumerable GetSerialiazableProperties(this object obj) + { + if (obj == null) + return new List(); + + return obj.GetType() + .GetProperties(BindingFlags.Instance | BindingFlags.Public) + .Where(prop => !Attribute.IsDefined(prop, typeof(JsonIgnoreAttribute))); + } + public static T GetModelFromArchetype(this IPublishedContent content, string cmsFieldAlias, bool returnInstanceIfNull = false) where T : class, new() @@ -28,5 +38,14 @@ namespace Archetype.Serialization return JsonConvert.DeserializeObject(archetypeJson) ?? (returnInstanceIfNull ? Activator.CreateInstance() : default(T)); } + + public static string DelintArchetypeJson(this string input) + { + if (!input.DetectIsJson()) + return String.Empty; + + var delinter = new ArchetypeJsonDelinter(); + return delinter.Execute(input); + } } }