From f2d105d8b998854969da649c1b5fbdabcf2df868 Mon Sep 17 00:00:00 2001 From: Shannon Deminick Date: Thu, 21 Feb 2013 05:44:44 +0600 Subject: [PATCH] Fixed #U4-814 and got all possible unit tests that were not working for DynamicNode but were working for DynamicPublishedContent working. And fixed up the DynamicPublishedContent unit tests as these weren't working at all... but seemed to say they did on the build server. strange. --- .../DynamicDocumentTestsBase.cs | 1031 +++++++++-------- .../PublishedContent/DynamicNodeTests.cs | 21 + .../DynamicPublishedContentTests.cs | 4 + .../RazorDynamicNode/DynamicNode.cs | 626 +++++----- 4 files changed, 869 insertions(+), 813 deletions(-) diff --git a/src/Umbraco.Tests/PublishedContent/DynamicDocumentTestsBase.cs b/src/Umbraco.Tests/PublishedContent/DynamicDocumentTestsBase.cs index bb1e2e42ec..fc63ef4c39 100644 --- a/src/Umbraco.Tests/PublishedContent/DynamicDocumentTestsBase.cs +++ b/src/Umbraco.Tests/PublishedContent/DynamicDocumentTestsBase.cs @@ -10,28 +10,28 @@ using Umbraco.Tests.TestHelpers; namespace Umbraco.Tests.PublishedContent { - [TestFixture] - public abstract class DynamicDocumentTestsBase : BaseRoutingTest - { - public override void Initialize() - { - base.Initialize(); - } + [TestFixture] + public abstract class DynamicDocumentTestsBase : BaseRoutingTest + { + public override void Initialize() + { + base.Initialize(); + } - public override void TearDown() - { - base.TearDown(); - - } + public override void TearDown() + { + base.TearDown(); - protected override bool RequiresDbSetup - { - get { return false; } - } + } - protected override string GetXmlContent(int templateId) - { - return @" + protected override bool RequiresDbSetup + { + get { return false; } + } + + protected override string GetXmlContent(int templateId) + { + return @" @@ -68,578 +68,587 @@ namespace Umbraco.Tests.PublishedContent "; - } + } - /// - /// Returns the dynamic node/document to run tests against - /// - /// - /// - protected abstract dynamic GetDynamicNode(int id); + /// + /// Returns the dynamic node/document to run tests against + /// + /// + /// + protected abstract dynamic GetDynamicNode(int id); - [Test] - public void Single() - { - var doc = GetDynamicNode(4444); + [Test] + public void Single() + { + var doc = GetDynamicNode(4444); - var result = doc.Children().Single(); + var result = doc.Children().Single(); - Assert.IsNotNull(result); - Assert.AreEqual(5555, result.Id); - } + Assert.IsNotNull(result); + Assert.AreEqual(5555, result.Id); + } - [Test] - public void Single_With_Query() - { - var doc = GetDynamicNode(1046); + [Test] + public void Single_With_Query() + { + var doc = GetDynamicNode(1046); - var result = doc.Children().Single("id==1175"); + var result = doc.Children().Single("id==1175"); - Assert.IsNotNull(result); - Assert.AreEqual(1175, result.Id); - } + Assert.IsNotNull(result); + Assert.AreEqual(1175, result.Id); + } - [Test] - public void First() - { - var doc = GetDynamicNode(1173); + [Test] + public void First() + { + var doc = GetDynamicNode(1173); - var result = doc.Children().First(); + var result = doc.Children().First(); - Assert.IsNotNull(result); - Assert.AreEqual(1174, result.Id); - } + Assert.IsNotNull(result); + Assert.AreEqual(1174, result.Id); + } - [Test] - public void First_With_Query() - { - var doc = GetDynamicNode(1173); + [Test] + public void First_With_Query() + { + var doc = GetDynamicNode(1173); - var result = doc.Children().First("blah==\"some content\""); + var result = doc.Children().First("blah==\"some content\""); - Assert.IsNotNull(result); - Assert.AreEqual(1176, result.Id); - } + Assert.IsNotNull(result); + Assert.AreEqual(1176, result.Id); + } - [Test] - public void Where_User_Property_Value() - { - var doc = GetDynamicNode(1173); + [Test] + public void Where_User_Property_Value() + { + var doc = GetDynamicNode(1173); - var result = (IEnumerable)doc.Children().Where("blah==\"some content\""); + var result = (IEnumerable)doc.Children().Where("blah==\"some content\""); - Assert.IsNotNull(result); - Assert.AreEqual(1, result.Count()); - Assert.AreEqual(1176, result.Single().Id); - } + Assert.IsNotNull(result); + Assert.AreEqual(1, result.Count()); + Assert.AreEqual(1176, result.Single().Id); + } - [Test] - public void String_ContainsValue_Extension_Method() - { - var doc = GetDynamicNode(1046); + [Test] + public void String_ContainsValue_Extension_Method() + { + var doc = GetDynamicNode(1046); - var paramVals = new Dictionary { { "searchId", 1173 } }; //this is an integer value - var result = doc.Children() - .Where("selectedNodes.ContainsValue(searchId)", paramVals) //call an extension method - .FirstOrDefault(); + var paramVals = new Dictionary { { "searchId", 1173 } }; //this is an integer value + var result = doc.Children() + .Where("selectedNodes.ContainsValue(searchId)", paramVals) //call an extension method + .FirstOrDefault(); - Assert.IsNotNull(result); - Assert.AreEqual(4444, result.Id); + Assert.IsNotNull(result); + Assert.AreEqual(4444, result.Id); - //don't find! - paramVals = new Dictionary { { "searchId", 1111777 } }; - result = doc.Children() - .Where("selectedNodes.ContainsValue(searchId)", paramVals) - .FirstOrDefault(); + //don't find! + paramVals = new Dictionary { { "searchId", 1111777 } }; + result = doc.Children() + .Where("selectedNodes.ContainsValue(searchId)", paramVals) + .FirstOrDefault(); - Assert.IsNotNull(result); - Assert.IsTrue(result.GetType() == typeof(DynamicNull) || result.GetType() == typeof(umbraco.MacroEngines.DynamicNull)); - //Assert.AreEqual(typeof(DynamicNull), result.GetType()); - } + Assert.IsNotNull(result); + Assert.IsTrue(result.GetType() == typeof(DynamicNull) || result.GetType() == typeof(umbraco.MacroEngines.DynamicNull)); + //Assert.AreEqual(typeof(DynamicNull), result.GetType()); + } - [Test] - public void String_Contains_Method() - { - var doc = GetDynamicNode(1046); + [Test] + public void String_Contains_Method() + { + var doc = GetDynamicNode(1046); - var paramVals = new Dictionary { { "searchId", "1173" } }; - var result = doc.Children() - .Where("selectedNodes.Contains(searchId)", paramVals) - .FirstOrDefault(); + var paramVals = new Dictionary { { "searchId", "1173" } }; + var result = doc.Children() + .Where("selectedNodes.Contains(searchId)", paramVals) + .FirstOrDefault(); - Assert.IsNotNull(result); - Assert.AreEqual(4444, result.Id); + Assert.IsNotNull(result); + Assert.AreEqual(4444, result.Id); - //don't find! - paramVals = new Dictionary { { "searchId", "1aaa173" } }; - result = doc.Children() - .Where("selectedNodes.Contains(searchId)", paramVals) - .FirstOrDefault(); + //don't find! + paramVals = new Dictionary { { "searchId", "1aaa173" } }; + result = doc.Children() + .Where("selectedNodes.Contains(searchId)", paramVals) + .FirstOrDefault(); - Assert.IsNotNull(result); - Assert.IsTrue(result.GetType() == typeof (DynamicNull) || result.GetType() == typeof (umbraco.MacroEngines.DynamicNull)); - //Assert.AreEqual(typeof (DynamicNull), result.GetType()); - } + Assert.IsNotNull(result); + Assert.IsTrue(result.GetType() == typeof(DynamicNull) || result.GetType() == typeof(umbraco.MacroEngines.DynamicNull)); + //Assert.AreEqual(typeof (DynamicNull), result.GetType()); + } - [Test] - public void String_Split_Method() - { - var doc = GetDynamicNode(1046); + [Test] + public void String_Split_Method() + { + var doc = GetDynamicNode(1046); - var paramVals = new Dictionary + var paramVals = new Dictionary { { "splitTerm", new char[] { ',' } }, { "splitOptions", StringSplitOptions.RemoveEmptyEntries } }; - var result = doc.Children() - .Where("selectedNodes.Split(splitTerm, splitOptions).Length == 3", paramVals) - .FirstOrDefault(); - - Assert.IsNotNull(result); - Assert.AreEqual(4444, result.Id); - } - - [Ignore] - [Test] - public void Complex_Linq() - { - var doc = GetDynamicNode(1173); - - var paramVals = new Dictionary {{"splitTerm", new char[] {','}}, {"searchId", "1173"}}; - var result = doc.Ancestors().OrderBy("level") - .Single() - .Descendants() - .Where("selectedNodes != null && selectedNodes != String.Empty && selectedNodes.Split(splitTerm).Contains(searchId)", paramVals) - .FirstOrDefault(); - - Assert.IsNotNull(result); - Assert.AreEqual(4444, result.Id); - } - - [Test] - public void Index() - { - var doc = GetDynamicNode(1173); - Assert.AreEqual(0, doc.Index()); - doc = GetDynamicNode(1176); - Assert.AreEqual(1, doc.Index()); - doc = GetDynamicNode(1177); - Assert.AreEqual(2, doc.Index()); - doc = GetDynamicNode(1178); - Assert.AreEqual(3, doc.Index()); - } - - [Ignore] - [Test] - public void Is_First() - { - var doc = GetDynamicNode(1046); //test root nodes - Assert.IsTrue(doc.IsFirst()); - doc = GetDynamicNode(1172); - Assert.IsFalse(doc.IsFirst()); - doc = GetDynamicNode(1173); //test normal nodes - Assert.IsTrue(doc.IsFirst()); - doc = GetDynamicNode(1175); - Assert.IsFalse(doc.IsFirst()); - } - - [Ignore] - [Test] - public void Is_Not_First() - { - var doc = GetDynamicNode(1046); //test root nodes - Assert.IsFalse(doc.IsNotFirst()); - doc = GetDynamicNode(1172); - Assert.IsTrue(doc.IsNotFirst()); - doc = GetDynamicNode(1173); //test normal nodes - Assert.IsFalse(doc.IsNotFirst()); - doc = GetDynamicNode(1175); - Assert.IsTrue(doc.IsNotFirst()); - } - - [Ignore] - [Test] - public void Is_Position() - { - var doc = GetDynamicNode(1046); //test root nodes - Assert.IsTrue(doc.IsPosition(0)); - doc = GetDynamicNode(1172); - Assert.IsTrue(doc.IsPosition(1)); - doc = GetDynamicNode(1173); //test normal nodes - Assert.IsTrue(doc.IsPosition(0)); - doc = GetDynamicNode(1175); - Assert.IsTrue(doc.IsPosition(1)); - } - - [Test] - public void Children_GroupBy_DocumentTypeAlias() - { - var doc = GetDynamicNode(1046); - - var found1 = doc.Children.GroupBy("DocumentTypeAlias"); - - var casted = (IEnumerable>)(found1); - Assert.AreEqual(2, casted.Count()); - Assert.AreEqual(2, casted.Single(x => x.Key.ToString() == "Home").Count()); - Assert.AreEqual(1, casted.Single(x => x.Key.ToString() == "CustomDocument").Count()); - } - - [Test] - public void Children_Where_DocumentTypeAlias() - { - var doc = GetDynamicNode(1046); - - var found1 = doc.Children.Where("DocumentTypeAlias == \"CustomDocument\""); - var found2 = doc.Children.Where("DocumentTypeAlias == \"Home\""); - - Assert.AreEqual(1, found1.Count()); - Assert.AreEqual(2, found2.Count()); - } - - [Test] - public void Children_Where_NodeTypeAlias() - { - var doc = GetDynamicNode(1046); - - var found1 = doc.Children.Where("NodeTypeAlias == \"CustomDocument\""); - var found2 = doc.Children.Where("NodeTypeAlias == \"Home\""); - - Assert.AreEqual(1, found1.Count()); - Assert.AreEqual(2, found2.Count()); - } - - [Test] - public void Children_Order_By_Update_Date() - { - var asDynamic = GetDynamicNode(1173); - - var ordered = asDynamic.Children.OrderBy("UpdateDate"); - var casted = (IEnumerable)ordered; - - var correctOrder = new[] { 1178, 1177, 1174, 1176 }; - for (var i = 0; i < correctOrder.Length ;i++) - { - Assert.AreEqual(correctOrder[i], ((dynamic)casted.ElementAt(i)).Id); - } - - } - - [Test] - public void Children_Order_By_Update_Date_Descending() - { - var asDynamic = GetDynamicNode(1173); - - var ordered = asDynamic.Children.OrderBy("UpdateDate desc"); - var casted = (IEnumerable)ordered; - - var correctOrder = new[] { 1176, 1174, 1177, 1178 }; - for (var i = 0; i < correctOrder.Length; i++) - { - Assert.AreEqual(correctOrder[i], ((dynamic)casted.ElementAt(i)).Id); - } - - } - - [Test] - public void HasProperty() - { - var asDynamic = GetDynamicNode(1173); - - var hasProp = asDynamic.HasProperty("umbracoUrlAlias"); - - Assert.AreEqual(true, (bool)hasProp); - - } - - [Test] - public void Skip() - { - var asDynamic = GetDynamicNode(1173); - - var skip = asDynamic.Children.Skip(2); - var casted = (IEnumerable)skip; - - Assert.AreEqual(2, casted.Count()); - Assert.IsTrue(casted.Select(x => ((dynamic)x).Id).ContainsAll(new dynamic[]{1177, 1178})); - - } - - [Test] - public void HasValue() - { - var asDynamic = GetDynamicNode(1173); - - var hasValue = asDynamic.HasValue("umbracoUrlAlias"); - var noValue = asDynamic.HasValue("blahblahblah"); - - Assert.IsTrue(hasValue); - Assert.IsFalse(noValue); - } - - [Test] - public void Take() - { - var asDynamic = GetDynamicNode(1173); - - var take = asDynamic.Children.Take(2); - var casted = (IEnumerable)take; - - Assert.AreEqual(2, casted.Count()); - Assert.IsTrue(casted.Select(x => ((dynamic)x).Id).ContainsAll(new dynamic[] { 1174, 1176 })); - } - - [Test] - public void Ancestors_Where_Visible() - { - var asDynamic = GetDynamicNode(1174); - - var whereVisible = asDynamic.Ancestors().Where("Visible"); - var casted = (IEnumerable)whereVisible; - - Assert.AreEqual(1, casted.Count()); - - } - - [Test] - public void Visible() - { - var asDynamicHidden = GetDynamicNode(1046); - var asDynamicVisible = GetDynamicNode(1173); - - Assert.IsFalse(asDynamicHidden.Visible); - Assert.IsTrue(asDynamicVisible.Visible); - } - - [Test] - public void Ensure_TinyMCE_Converted_Type_User_Property() - { - var asDynamic = GetDynamicNode(1173); - - Assert.IsTrue(TypeHelper.IsTypeAssignableFrom(asDynamic.Content.GetType())); - Assert.AreEqual("
This is some content
", asDynamic.Content.ToString()); - } - - [Ignore] - [Test] - public void Get_Children_With_Pluralized_Alias() - { - var asDynamic = GetDynamicNode(1173); - - Action doAssert = d => - { - Assert.IsTrue(TypeHelper.IsTypeAssignableFrom(d)); - var casted = (IEnumerable)d; - Assert.AreEqual(2, casted.Count()); - }; + var result = doc.Children() + .Where("selectedNodes.Split(splitTerm, splitOptions).Length == 3", paramVals) + .FirstOrDefault(); + + Assert.IsNotNull(result); + Assert.AreEqual(4444, result.Id); + } + + [Ignore("We are ignoring this test because currently our ExpressionParser class cannot deal with this... it needs some serious TLC but it is very complex.")] + [Test] + public void Complex_Linq() + { + var doc = GetDynamicNode(1173); + + var paramVals = new Dictionary { { "splitTerm", new char[] { ',' } }, { "searchId", "1173" } }; + var result = doc.Ancestors().OrderBy("level") + .Single() + .Descendants() + .Where("selectedNodes != null && selectedNodes != String.Empty && selectedNodes.Split(splitTerm).Contains(searchId)", paramVals) + .FirstOrDefault(); + + Assert.IsNotNull(result); + Assert.AreEqual(4444, result.Id); + } + + [Test] + public void Index() + { + var doc = GetDynamicNode(1173); + Assert.AreEqual(0, doc.Index()); + doc = GetDynamicNode(1176); + Assert.AreEqual(1, doc.Index()); + doc = GetDynamicNode(1177); + Assert.AreEqual(2, doc.Index()); + doc = GetDynamicNode(1178); + Assert.AreEqual(3, doc.Index()); + } + + [Test] + public virtual void Is_First_Root_Nodes() + { + var doc = GetDynamicNode(1046); //test root nodes + Assert.IsTrue(doc.IsFirst()); + doc = GetDynamicNode(1172); + Assert.IsFalse(doc.IsFirst()); + } + + [Test] + public void Is_First() + { + var doc = GetDynamicNode(1173); //test normal nodes + Assert.IsTrue(doc.IsFirst()); + doc = GetDynamicNode(1175); + Assert.IsFalse(doc.IsFirst()); + } + + [Test] + public virtual void Is_Not_First_Root_Nodes() + { + var doc = GetDynamicNode(1046); //test root nodes + Assert.IsFalse(doc.IsNotFirst()); + doc = GetDynamicNode(1172); + Assert.IsTrue(doc.IsNotFirst()); + } + + [Test] + public void Is_Not_First() + { + var doc = GetDynamicNode(1173); //test normal nodes + Assert.IsFalse(doc.IsNotFirst()); + doc = GetDynamicNode(1175); + Assert.IsTrue(doc.IsNotFirst()); + } + + [Test] + public virtual void Is_Position_Root_Nodes() + { + var doc = GetDynamicNode(1046); //test root nodes + Assert.IsTrue(doc.IsPosition(0)); + doc = GetDynamicNode(1172); + Assert.IsTrue(doc.IsPosition(1)); + } + + [Test] + public void Is_Position() + { + var doc = GetDynamicNode(1173); //test normal nodes + Assert.IsTrue(doc.IsPosition(0)); + doc = GetDynamicNode(1175); + Assert.IsTrue(doc.IsPosition(1)); + } + + [Test] + public void Children_GroupBy_DocumentTypeAlias() + { + var doc = GetDynamicNode(1046); + + var found1 = doc.Children.GroupBy("DocumentTypeAlias"); + + var casted = (IEnumerable>)(found1); + Assert.AreEqual(2, casted.Count()); + Assert.AreEqual(2, casted.Single(x => x.Key.ToString() == "Home").Count()); + Assert.AreEqual(1, casted.Single(x => x.Key.ToString() == "CustomDocument").Count()); + } + + [Test] + public void Children_Where_DocumentTypeAlias() + { + var doc = GetDynamicNode(1046); + + var found1 = doc.Children.Where("DocumentTypeAlias == \"CustomDocument\""); + var found2 = doc.Children.Where("DocumentTypeAlias == \"Home\""); + + Assert.AreEqual(1, found1.Count()); + Assert.AreEqual(2, found2.Count()); + } + + [Test] + public void Children_Where_NodeTypeAlias() + { + var doc = GetDynamicNode(1046); + + var found1 = doc.Children.Where("NodeTypeAlias == \"CustomDocument\""); + var found2 = doc.Children.Where("NodeTypeAlias == \"Home\""); + + Assert.AreEqual(1, found1.Count()); + Assert.AreEqual(2, found2.Count()); + } + + [Test] + public void Children_Order_By_Update_Date() + { + var asDynamic = GetDynamicNode(1173); + + var ordered = asDynamic.Children.OrderBy("UpdateDate"); + var casted = (IEnumerable)ordered; + + var correctOrder = new[] { 1178, 1177, 1174, 1176 }; + for (var i = 0; i < correctOrder.Length; i++) + { + Assert.AreEqual(correctOrder[i], ((dynamic)casted.ElementAt(i)).Id); + } + + } + + [Test] + public void Children_Order_By_Update_Date_Descending() + { + var asDynamic = GetDynamicNode(1173); + + var ordered = asDynamic.Children.OrderBy("UpdateDate desc"); + var casted = (IEnumerable)ordered; + + var correctOrder = new[] { 1176, 1174, 1177, 1178 }; + for (var i = 0; i < correctOrder.Length; i++) + { + Assert.AreEqual(correctOrder[i], ((dynamic)casted.ElementAt(i)).Id); + } + + } + + [Test] + public void HasProperty() + { + var asDynamic = GetDynamicNode(1173); + + var hasProp = asDynamic.HasProperty("umbracoUrlAlias"); + + Assert.AreEqual(true, (bool)hasProp); + + } + + [Test] + public void Skip() + { + var asDynamic = GetDynamicNode(1173); + + var skip = asDynamic.Children.Skip(2); + var casted = (IEnumerable)skip; + + Assert.AreEqual(2, casted.Count()); + Assert.IsTrue(casted.Select(x => ((dynamic)x).Id).ContainsAll(new dynamic[] { 1177, 1178 })); - doAssert(asDynamic.Homes); //pluralized alias - doAssert(asDynamic.homes); //pluralized alias - doAssert(asDynamic.CustomDocuments); //pluralized alias - doAssert(asDynamic.customDocuments); //pluralized alias - } + } + + [Test] + public void HasValue() + { + var asDynamic = GetDynamicNode(1173); - [Test] - public void GetPropertyValue_Non_Reflected() - { - var asDynamic = GetDynamicNode(1174); - - Assert.AreEqual("Custom data with same property name as the member name", asDynamic.GetPropertyValue("creatorName")); - Assert.AreEqual("Custom data with same property name as the member name", asDynamic.GetPropertyValue("CreatorName")); - } + var hasValue = asDynamic.HasValue("umbracoUrlAlias"); + var noValue = asDynamic.HasValue("blahblahblah"); - [Ignore] - [Test] - public void GetPropertyValue_Reflected() - { - var asDynamic = GetDynamicNode(1174); - - Assert.AreEqual("admin", asDynamic.GetPropertyValue("@creatorName")); - Assert.AreEqual("admin", asDynamic.GetPropertyValue("@CreatorName")); - } - - [Test] - public void Get_User_Property_With_Same_Name_As_Member_Property() - { - var asDynamic = GetDynamicNode(1174); + Assert.IsTrue(hasValue); + Assert.IsFalse(noValue); + } - Assert.AreEqual("Custom data with same property name as the member name", asDynamic.creatorName); - - //because CreatorName is defined on DynamicNode, it will not return the user defined property - Assert.AreEqual("admin", asDynamic.CreatorName); - } - - [Ignore] - [Test] - public void Get_Member_Property() - { - var asDynamic = GetDynamicNode(1173); - - Assert.AreEqual((int) 2, (int) asDynamic.Level); - Assert.AreEqual((int) 2, (int) asDynamic.level); - - Assert.AreEqual((int) 1046, (int) asDynamic.ParentId); - Assert.AreEqual((int) 1046, (int) asDynamic.parentId); - } + [Test] + public void Take() + { + var asDynamic = GetDynamicNode(1173); - [Test] - public void Get_Children() - { - var asDynamic = GetDynamicNode(1173); + var take = asDynamic.Children.Take(2); + var casted = (IEnumerable)take; - var children = asDynamic.Children; - Assert.IsTrue(TypeHelper.IsTypeAssignableFrom(children)); + Assert.AreEqual(2, casted.Count()); + Assert.IsTrue(casted.Select(x => ((dynamic)x).Id).ContainsAll(new dynamic[] { 1174, 1176 })); + } - var childrenAsList = asDynamic.ChildrenAsList; //test ChildrenAsList too - Assert.IsTrue(TypeHelper.IsTypeAssignableFrom(childrenAsList)); + [Test] + public void Ancestors_Where_Visible() + { + var asDynamic = GetDynamicNode(1174); - var castChildren = (IEnumerable)children; - Assert.AreEqual(4, castChildren.Count()); + var whereVisible = asDynamic.Ancestors().Where("Visible"); + var casted = (IEnumerable)whereVisible; - var castChildrenAsList = (IEnumerable)childrenAsList; - Assert.AreEqual(4, castChildrenAsList.Count()); - } + Assert.AreEqual(1, casted.Count()); - [Test] - public void Ancestor_Or_Self() - { - var asDynamic = GetDynamicNode(1173); + } - var result = asDynamic.AncestorOrSelf(); + [Test] + public void Visible() + { + var asDynamicHidden = GetDynamicNode(1046); + var asDynamicVisible = GetDynamicNode(1173); - Assert.IsNotNull(result); + Assert.IsFalse(asDynamicHidden.Visible); + Assert.IsTrue(asDynamicVisible.Visible); + } - Assert.AreEqual((int) 1046, (int) result.Id); - } + [Test] + public void Ensure_TinyMCE_Converted_Type_User_Property() + { + var asDynamic = GetDynamicNode(1173); - [Test] - public void Ancestors_Or_Self() - { - var asDynamic = GetDynamicNode(1174); + Assert.IsTrue(TypeHelper.IsTypeAssignableFrom(asDynamic.Content.GetType())); + Assert.AreEqual("
This is some content
", asDynamic.Content.ToString()); + } - var result = asDynamic.AncestorsOrSelf(); + [Test] + public void Get_Children_With_Pluralized_Alias() + { + var asDynamic = GetDynamicNode(1173); - Assert.IsNotNull(result); + Action doAssert = d => + { + Assert.IsTrue(TypeHelper.IsTypeAssignableFrom(d)); + var casted = (IEnumerable)d; + Assert.AreEqual(2, casted.Count()); + }; - var list = (IEnumerable)result; - Assert.AreEqual(3, list.Count()); - Assert.IsTrue(list.Select(x => ((dynamic)x).Id).ContainsAll(new dynamic[] { 1174, 1173, 1046 })); - } + doAssert(asDynamic.Homes); //pluralized alias + doAssert(asDynamic.homes); //pluralized alias + doAssert(asDynamic.CustomDocuments); //pluralized alias + doAssert(asDynamic.customDocuments); //pluralized alias + } - [Test] - public void Ancestors() - { - var asDynamic = GetDynamicNode(1174); + [Test] + public void GetPropertyValue_Non_Reflected() + { + var asDynamic = GetDynamicNode(1174); - var result = asDynamic.Ancestors(); + Assert.AreEqual("Custom data with same property name as the member name", asDynamic.GetPropertyValue("creatorName")); + Assert.AreEqual("Custom data with same property name as the member name", asDynamic.GetPropertyValue("CreatorName")); + } - Assert.IsNotNull(result); + [Test] + public void GetPropertyValue_Reflected() + { + var asDynamic = GetDynamicNode(1174); - var list = (IEnumerable)result; - Assert.AreEqual(2, list.Count()); - Assert.IsTrue(list.Select(x => ((dynamic)x).Id).ContainsAll(new dynamic[] { 1173, 1046 })); - } + Assert.AreEqual("admin", asDynamic.GetPropertyValue("@creatorName")); + Assert.AreEqual("admin", asDynamic.GetPropertyValue("@CreatorName")); + } - [Test] - public void Descendants_Or_Self() - { - var asDynamic = GetDynamicNode(1046); + [Test] + public void Get_User_Property_With_Same_Name_As_Member_Property() + { + var asDynamic = GetDynamicNode(1174); - var result = asDynamic.DescendantsOrSelf(); + Assert.AreEqual("Custom data with same property name as the member name", asDynamic.creatorName); - Assert.IsNotNull(result); + //because CreatorName is defined on DynamicNode, it will not return the user defined property + Assert.AreEqual("admin", asDynamic.CreatorName); + } - var list = (IEnumerable)result; - Assert.AreEqual(9, list.Count()); - Assert.IsTrue(list.Select(x => ((dynamic)x).Id).ContainsAll(new dynamic[] { 1046, 1173, 1174, 1176, 1175, 4444 })); - } + [Test] + public void Get_Member_Property() + { + var asDynamic = GetDynamicNode(1173); - [Test] - public void Descendants() - { - var asDynamic = GetDynamicNode(1046); + Assert.AreEqual((int)2, (int)asDynamic.Level); + Assert.AreEqual((int)2, (int)asDynamic.level); - var result = asDynamic.Descendants(); + Assert.AreEqual((int)1046, (int)asDynamic.ParentId); + Assert.AreEqual((int)1046, (int)asDynamic.parentId); + } - Assert.IsNotNull(result); + [Test] + public void Get_Children() + { + var asDynamic = GetDynamicNode(1173); - var list = (IEnumerable)result; - Assert.AreEqual(8, list.Count()); - Assert.IsTrue(list.Select(x => ((dynamic)x).Id).ContainsAll(new dynamic[] { 1173, 1174, 1176, 1175, 4444 })); - } + var children = asDynamic.Children; + Assert.IsTrue(TypeHelper.IsTypeAssignableFrom(children)); - [Test] - public void Up() - { - var asDynamic = GetDynamicNode(1173); + var childrenAsList = asDynamic.ChildrenAsList; //test ChildrenAsList too + Assert.IsTrue(TypeHelper.IsTypeAssignableFrom(childrenAsList)); - var result = asDynamic.Up(); + var castChildren = (IEnumerable)children; + Assert.AreEqual(4, castChildren.Count()); - Assert.IsNotNull(result); + var castChildrenAsList = (IEnumerable)childrenAsList; + Assert.AreEqual(4, castChildrenAsList.Count()); + } - Assert.AreEqual((int) 1046, (int) result.Id); - } + [Test] + public void Ancestor_Or_Self() + { + var asDynamic = GetDynamicNode(1173); - [Test] - public void Down() - { - var asDynamic = GetDynamicNode(1173); + var result = asDynamic.AncestorOrSelf(); - var result = asDynamic.Down(); + Assert.IsNotNull(result); - Assert.IsNotNull(result); + Assert.AreEqual((int)1046, (int)result.Id); + } - Assert.AreEqual((int) 1174, (int) result.Id); - } + [Test] + public void Ancestors_Or_Self() + { + var asDynamic = GetDynamicNode(1174); - [Test] - public void Next() - { - var asDynamic = GetDynamicNode(1173); + var result = asDynamic.AncestorsOrSelf(); - var result = asDynamic.Next(); + Assert.IsNotNull(result); - Assert.IsNotNull(result); + var list = (IEnumerable)result; + Assert.AreEqual(3, list.Count()); + Assert.IsTrue(list.Select(x => ((dynamic)x).Id).ContainsAll(new dynamic[] { 1174, 1173, 1046 })); + } - Assert.AreEqual((int) 1175, (int) result.Id); - } + [Test] + public void Ancestors() + { + var asDynamic = GetDynamicNode(1174); - [Test] - public void Next_Without_Sibling() - { - var asDynamic = GetDynamicNode(1178); + var result = asDynamic.Ancestors(); - Assert.IsNull(asDynamic.Next()); - } + Assert.IsNotNull(result); - [Test] - public void Previous_Without_Sibling() - { - var asDynamic = GetDynamicNode(1173); + var list = (IEnumerable)result; + Assert.AreEqual(2, list.Count()); + Assert.IsTrue(list.Select(x => ((dynamic)x).Id).ContainsAll(new dynamic[] { 1173, 1046 })); + } - Assert.IsNull(asDynamic.Previous()); - } + [Test] + public void Descendants_Or_Self() + { + var asDynamic = GetDynamicNode(1046); - [Test] - public void Previous() - { - var asDynamic = GetDynamicNode(1176); + var result = asDynamic.DescendantsOrSelf(); - var result = asDynamic.Previous(); + Assert.IsNotNull(result); - Assert.IsNotNull(result); + var list = (IEnumerable)result; + Assert.AreEqual(9, list.Count()); + Assert.IsTrue(list.Select(x => ((dynamic)x).Id).ContainsAll(new dynamic[] { 1046, 1173, 1174, 1176, 1175, 4444 })); + } - Assert.AreEqual((int) 1174, (int) result.Id); - } - } + [Test] + public void Descendants() + { + var asDynamic = GetDynamicNode(1046); - /// - /// Extension methods used in tests - /// - public static class TestExtensionMethods - { - public static bool ContainsValue(this string s, int val) - { - return s.Contains(val.ToString()); - } - } + var result = asDynamic.Descendants(); + + Assert.IsNotNull(result); + + var list = (IEnumerable)result; + Assert.AreEqual(8, list.Count()); + Assert.IsTrue(list.Select(x => ((dynamic)x).Id).ContainsAll(new dynamic[] { 1173, 1174, 1176, 1175, 4444 })); + } + + [Test] + public void Up() + { + var asDynamic = GetDynamicNode(1173); + + var result = asDynamic.Up(); + + Assert.IsNotNull(result); + + Assert.AreEqual((int)1046, (int)result.Id); + } + + [Test] + public void Down() + { + var asDynamic = GetDynamicNode(1173); + + var result = asDynamic.Down(); + + Assert.IsNotNull(result); + + Assert.AreEqual((int)1174, (int)result.Id); + } + + [Test] + public void Next() + { + var asDynamic = GetDynamicNode(1173); + + var result = asDynamic.Next(); + + Assert.IsNotNull(result); + + Assert.AreEqual((int)1175, (int)result.Id); + } + + [Test] + public void Next_Without_Sibling() + { + var asDynamic = GetDynamicNode(1178); + + Assert.IsNull(asDynamic.Next()); + } + + [Test] + public void Previous_Without_Sibling() + { + var asDynamic = GetDynamicNode(1173); + + Assert.IsNull(asDynamic.Previous()); + } + + [Test] + public void Previous() + { + var asDynamic = GetDynamicNode(1176); + + var result = asDynamic.Previous(); + + Assert.IsNotNull(result); + + Assert.AreEqual((int)1174, (int)result.Id); + } + } + + /// + /// Extension methods used in tests + /// + public static class TestExtensionMethods + { + public static bool ContainsValue(this string s, int val) + { + return s.Contains(val.ToString()); + } + } } \ No newline at end of file diff --git a/src/Umbraco.Tests/PublishedContent/DynamicNodeTests.cs b/src/Umbraco.Tests/PublishedContent/DynamicNodeTests.cs index bd8944a027..0d85955136 100644 --- a/src/Umbraco.Tests/PublishedContent/DynamicNodeTests.cs +++ b/src/Umbraco.Tests/PublishedContent/DynamicNodeTests.cs @@ -54,6 +54,27 @@ namespace Umbraco.Tests.PublishedContent } + [Test] + [Ignore("This test will never work unless DynamicNode is refactored a lot in order to get a list of root nodes since root nodes don't have a parent to look up")] + public override void Is_First_Root_Nodes() + { + base.Is_First_Root_Nodes(); + } + + [Test] + [Ignore("This test will never work unless DynamicNode is refactored a lot in order to get a list of root nodes since root nodes don't have a parent to look up")] + public override void Is_Not_First_Root_Nodes() + { + base.Is_Not_First_Root_Nodes(); + } + + [Test] + [Ignore("This test will never work unless DynamicNode is refactored a lot in order to get a list of root nodes since root nodes don't have a parent to look up")] + public override void Is_Position_Root_Nodes() + { + base.Is_Position_Root_Nodes(); + } + public override void TearDown() { base.TearDown(); diff --git a/src/Umbraco.Tests/PublishedContent/DynamicPublishedContentTests.cs b/src/Umbraco.Tests/PublishedContent/DynamicPublishedContentTests.cs index e8bb815802..40049d8d2f 100644 --- a/src/Umbraco.Tests/PublishedContent/DynamicPublishedContentTests.cs +++ b/src/Umbraco.Tests/PublishedContent/DynamicPublishedContentTests.cs @@ -1,7 +1,9 @@ using System; +using System.IO; using System.Linq; using NUnit.Framework; using Umbraco.Core; +using Umbraco.Core.Configuration; using Umbraco.Core.Models; using Umbraco.Core.PropertyEditors; using Umbraco.Web; @@ -24,6 +26,8 @@ namespace Umbraco.Tests.PublishedContent typeof(YesNoPropertyEditorValueConverter) }); + UmbracoSettings.SettingsFilePath = Core.IO.IOHelper.MapPath(Core.IO.SystemDirectories.Config + Path.DirectorySeparatorChar, false); + //need to specify a custom callback for unit tests PublishedContentHelper.GetDataTypeCallback = (docTypeAlias, propertyAlias) => { diff --git a/src/umbraco.MacroEngines/RazorDynamicNode/DynamicNode.cs b/src/umbraco.MacroEngines/RazorDynamicNode/DynamicNode.cs index 3c92cfa223..80bef30574 100644 --- a/src/umbraco.MacroEngines/RazorDynamicNode/DynamicNode.cs +++ b/src/umbraco.MacroEngines/RazorDynamicNode/DynamicNode.cs @@ -1,4 +1,5 @@ using System; +using System.Collections.Concurrent; using System.Collections.Generic; using System.Dynamic; using System.Linq; @@ -30,11 +31,11 @@ namespace umbraco.MacroEngines { public class DynamicNode : DynamicObject, INode { - /// - /// This callback is used only so we can set it dynamically for use in unit tests - /// - internal static Func GetDataTypeCallback = (docTypeAlias, propertyAlias) => - ContentType.GetDataType(docTypeAlias, propertyAlias); + /// + /// This callback is used only so we can set it dynamically for use in unit tests + /// + internal static Func GetDataTypeCallback = (docTypeAlias, propertyAlias) => + ContentType.GetDataType(docTypeAlias, propertyAlias); #region consts // these are private readonlys as const can't be Guids @@ -45,6 +46,9 @@ namespace umbraco.MacroEngines //private readonly Guid DATATYPE_INTEGER_GUID = new Guid("1413afcb-d19a-4173-8e9a-68288d2a73b8"); #endregion + private DynamicNodeList _cachedChildren; + private readonly ConcurrentDictionary _cachedMemberOutput = new ConcurrentDictionary(); + internal readonly DynamicBackingItem n; public DynamicNodeList ownerList; @@ -154,13 +158,20 @@ namespace umbraco.MacroEngines { get { - List children = n.ChildrenAsList; - //testing - if (children.Count == 0 && n.Id == 0) + if (_cachedChildren == null) { - return new DynamicNodeList(new List { this.n }); + List children = n.ChildrenAsList; + //testing + if (children.Count == 0 && n.Id == 0) + { + _cachedChildren = new DynamicNodeList(new List { this.n }); + } + else + { + _cachedChildren = new DynamicNodeList(n.ChildrenAsList); + } } - return new DynamicNodeList(n.ChildrenAsList); + return _cachedChildren; } } public DynamicNodeList XPath(string xPath) @@ -234,12 +245,12 @@ namespace umbraco.MacroEngines throw new NullReferenceException("DynamicNode wasn't initialized with an underlying NodeFactory.Node"); } } - - + + public DynamicNodeList Search(string term, bool useWildCards = true, string searchProvider = null) { var searcher = Examine.ExamineManager.Instance.DefaultSearchProvider; - if(!string.IsNullOrEmpty(searchProvider)) + if (!string.IsNullOrEmpty(searchProvider)) searcher = Examine.ExamineManager.Instance.SearchProviderCollection[searchProvider]; var t = term.Escape().Value; @@ -279,13 +290,13 @@ namespace umbraco.MacroEngines var s = Examine.ExamineManager.Instance.DefaultSearchProvider; if (searchProvider != null) s = searchProvider; - + var results = s.Search(criteria); return ExamineSearchUtill.ConvertSearchResultToDynamicNode(results); } - + public bool HasProperty(string name) { @@ -406,125 +417,99 @@ namespace umbraco.MacroEngines } return result; } - private List GetAncestorOrSelfNodeTypeAlias(DynamicBackingItem node) - { - List list = new List(); - if (node != null) - { - if (node.Type == DynamicBackingItemType.Content) - { - //find the doctype node, so we can walk it's parent's tree- not the working.parent content tree - CMSNode working = ContentType.GetByAlias(node.NodeTypeAlias); - while (working != null) - { - //NOTE: I'm not sure if anyone has ever tested this but if you get working.Parent it will return a CMSNode and - // it will never be castable to a 'ContentType' object - // pretty sure the only reason why this method works for the one place that it is used is that it returns - // the current node's alias which is all that is actually requried, this is just added overhead for no - // reason - if ((working as ContentType) != null) - { - list.Add((working as ContentType).Alias); - } + private static Dictionary, Type> _razorDataTypeModelTypes = null; + private static readonly ReaderWriterLockSlim _locker = new ReaderWriterLockSlim(); + + internal static Dictionary, Type> RazorDataTypeModelTypes + { + get + { + using (var l = new UpgradeableReadLock(_locker)) + { + if (_razorDataTypeModelTypes == null) + { + l.UpgradeToWriteLock(); + + var foundTypes = new Dictionary, Type>(); + try { - working = working.Parent; + PluginManager.Current.ResolveRazorDataTypeModels() + .ToList() + .ConvertAll(type => + { + var razorDataTypeModelAttributes = type.GetCustomAttributes(true); + return razorDataTypeModelAttributes.ToList().ConvertAll(razorDataTypeModelAttribute => + { + var g = razorDataTypeModelAttribute.DataTypeEditorId; + var priority = razorDataTypeModelAttribute.Priority; + return new KeyValuePair, Type>(new System.Tuple(g, priority), type); + }); + }) + .SelectMany(item => item) + .ToList() + .ForEach(item => + { + System.Tuple key = item.Key; + if (!foundTypes.ContainsKey(key)) + { + foundTypes.Add(key, item.Value); + } + }); + + //there is no error, so set the collection + _razorDataTypeModelTypes = foundTypes; + } - catch (ArgumentException) + catch (Exception ex) { - break; + LogHelper.Warn("Exception occurred while populating cache, will keep RazorDataTypeModelTypes to null so that this error remains visible and you don't end up with an empty cache with silent failure." + + string.Format("The exception was {0} and the message was {1}. {2}", ex.GetType().FullName, ex.Message, ex.StackTrace)); } + } - } - else - { - return null; + return _razorDataTypeModelTypes; } } - return list; } - private static Dictionary, Type> _razorDataTypeModelTypes = null; - private static readonly ReaderWriterLockSlim _locker = new ReaderWriterLockSlim(); - - internal static Dictionary, Type> RazorDataTypeModelTypes - { - get - { - using (var l = new UpgradeableReadLock(_locker)) - { - if (_razorDataTypeModelTypes == null) - { - l.UpgradeToWriteLock(); - - var foundTypes = new Dictionary, Type>(); - - try - { - PluginManager.Current.ResolveRazorDataTypeModels() - .ToList() - .ConvertAll(type => - { - var razorDataTypeModelAttributes = type.GetCustomAttributes(true); - return razorDataTypeModelAttributes.ToList().ConvertAll(razorDataTypeModelAttribute => - { - var g = razorDataTypeModelAttribute.DataTypeEditorId; - var priority = razorDataTypeModelAttribute.Priority; - return new KeyValuePair, Type>(new System.Tuple(g, priority), type); - }); - }) - .SelectMany(item => item) - .ToList() - .ForEach(item => - { - System.Tuple key = item.Key; - if (!foundTypes.ContainsKey(key)) - { - foundTypes.Add(key, item.Value); - } - }); - - //NOTE: We really dont need to log this? - //var i = 1; - //foreach (var item in foundTypes) - //{ - // HttpContext.Current.Trace.Write(string.Format("{0}/{1}: {2}@{4} => {3}", i, foundTypes.Count, item.Key.Item1, item.Value.FullName, item.Key.Item2)); - // i++; - //} - - //there is no error, so set the collection - _razorDataTypeModelTypes = foundTypes; - - } - catch (Exception ex) - { - LogHelper.Warn("Exception occurred while populating cache, will keep RazorDataTypeModelTypes to null so that this error remains visible and you don't end up with an empty cache with silent failure." - + string.Format("The exception was {0} and the message was {1}. {2}", ex.GetType().FullName, ex.Message, ex.StackTrace)); - } - - } - return _razorDataTypeModelTypes; - } - } - } - - private static Guid GetDataType(string docTypeAlias, string propertyAlias) - { - return GetDataTypeCallback(docTypeAlias, propertyAlias); - } + private static Guid GetDataType(string docTypeAlias, string propertyAlias) + { + return GetDataTypeCallback(docTypeAlias, propertyAlias); + } public override bool TryGetMember(GetMemberBinder binder, out object result) { - var name = binder.Name; - result = null; //this will never be returned - if (name == "ChildrenAsList" || name == "Children") + //check the cache first! + if (_cachedMemberOutput.TryGetValue(name, out result)) { - result = GetChildrenAsList; return true; } + + result = null; //this will never be returned + + if (name.InvariantEquals("ChildrenAsList") || name.InvariantEquals("Children")) + { + result = GetChildrenAsList; + //cache the result so we don't have to re-process the whole thing + _cachedMemberOutput.TryAdd(name, result); + return true; + } + if (binder.Name.InvariantEquals("parentId")) + { + var parent = n.Parent; + if (parent == null) + { + throw new InvalidOperationException(string.Format("The node {0} does not have a parent", Id)); + } + result = parent.Id; + _cachedMemberOutput.TryAdd(name, result); + return true; + } + bool propertyExists = false; if (n != null) { @@ -554,8 +539,8 @@ namespace umbraco.MacroEngines //contextAlias is the node which the property data was returned from //Guid dataType = ContentType.GetDataType(data.ContextAlias, data.Alias); - var dataType = GetDataType(data.ContextAlias, data.Alias); - + var dataType = GetDataType(data.ContextAlias, data.Alias); + var staticMapping = UmbracoSettings.RazorDataTypeModelStaticMapping.FirstOrDefault(mapping => { return mapping.Applies(dataType, data.ContextAlias, data.Alias); @@ -570,19 +555,21 @@ namespace umbraco.MacroEngines if (TryCreateInstanceRazorDataTypeModel(dataType, dataTypeType, data.Value, out instance)) { result = instance; + //cache the result so we don't have to re-process the whole thing + _cachedMemberOutput.TryAdd(name, result); return true; } else { - LogHelper.Warn(string.Format("Failed to create the instance of the model binder")); + LogHelper.Warn(string.Format("Failed to create the instance of the model binder")); } } else { - LogHelper.Warn(string.Format("staticMapping type name {0} came back as null from Type.GetType; check the casing, assembly presence, assembly framework version, namespace", staticMapping.TypeName)); + LogHelper.Warn(string.Format("staticMapping type name {0} came back as null from Type.GetType; check the casing, assembly presence, assembly framework version, namespace", staticMapping.TypeName)); } } - + if (RazorDataTypeModelTypes != null && RazorDataTypeModelTypes.Any(model => model.Key.Item1 == dataType) && dataType != Guid.Empty) { var razorDataTypeModelDefinition = RazorDataTypeModelTypes.Where(model => model.Key.Item1 == dataType).OrderByDescending(model => model.Key.Item2).FirstOrDefault(); @@ -593,35 +580,26 @@ namespace umbraco.MacroEngines if (TryCreateInstanceRazorDataTypeModel(dataType, dataTypeType, data.Value, out instance)) { result = instance; + //cache the result so we don't have to re-process the whole thing + _cachedMemberOutput.TryAdd(name, result); return true; } else { - LogHelper.Warn(string.Format("Failed to create the instance of the model binder")); + LogHelper.Warn(string.Format("Failed to create the instance of the model binder")); } } else { - LogHelper.Warn(string.Format("Could not get the dataTypeType for the RazorDataTypeModel")); + LogHelper.Warn(string.Format("Could not get the dataTypeType for the RazorDataTypeModel")); } } - else - { - //NOTE: Do we really want to log this? I'm not sure. - //if (RazorDataTypeModelTypes == null) - //{ - // HttpContext.Current.Trace.Write(string.Format("RazorDataTypeModelTypes is null, probably an exception while building the cache, falling back to ConvertPropertyValueByDataType", dataType)); - //} - //else - //{ - // HttpContext.Current.Trace.Write(string.Format("GUID {0} does not have a DataTypeModel, falling back to ConvertPropertyValueByDataType", dataType)); - //} - - } //convert the string value to a known type - return ConvertPropertyValueByDataType(ref result, name, dataType); - + var returnVal = ConvertPropertyValueByDataType(ref result, name, dataType); + //cache the result so we don't have to re-process the whole thing + _cachedMemberOutput.TryAdd(name, result); + return returnVal; } //check if the alias is that of a child type @@ -629,39 +607,30 @@ namespace umbraco.MacroEngines var typeChildren = n.ChildrenAsList; if (typeChildren != null) { - var filteredTypeChildren = typeChildren.Where(x => - { - List ancestorAliases = GetAncestorOrSelfNodeTypeAlias(x); - if (ancestorAliases == null) - { - return false; - } - return ancestorAliases.Any(alias => alias == name || MakePluralName(alias) == name); - }); + + var filteredTypeChildren = typeChildren + .Where(x => x.NodeTypeAlias.InvariantEquals(name) || x.NodeTypeAlias.MakePluralName().InvariantEquals(binder.Name)) + .ToArray(); if (filteredTypeChildren.Any()) { result = new DynamicNodeList(filteredTypeChildren); + //cache the result so we don't have to re-process the whole thing + _cachedMemberOutput.TryAdd(name, result); return true; } } - try + //lookup the property using reflection + + result = GetReflectedProperty(binder.Name); + + if (result != null) { - result = n.GetType().InvokeMember(binder.Name, - System.Reflection.BindingFlags.GetProperty | - System.Reflection.BindingFlags.Instance | - System.Reflection.BindingFlags.Public, - null, - n, - null); + _cachedMemberOutput.TryAdd(name, result); return true; } - catch - { - //result = null; - //return false; - } + } //if property access, type lookup and member invoke all failed @@ -679,6 +648,42 @@ namespace umbraco.MacroEngines } return true; } + + private object GetReflectedProperty(string alias) + { + Func> getMember = + memberAlias => + { + try + { + return new Attempt(true, + n.GetType().InvokeMember(memberAlias, + System.Reflection.BindingFlags.GetProperty | + System.Reflection.BindingFlags.Instance | + System.Reflection.BindingFlags.Public, + null, + n, + null)); + } + catch (MissingMethodException ex) + { + return new Attempt(ex); + } + }; + + //try with the current casing + var attempt = getMember(alias); + if (!attempt.Success) + { + //if we cannot get with the current alias, try changing it's case + attempt = alias[0].IsUpperCase() + ? getMember(alias.ConvertCase(StringAliasCaseType.CamelCase)) + : getMember(alias.ConvertCase(StringAliasCaseType.PascalCase)); + } + + return attempt.Success ? attempt.Result : null; + } + private bool TryCreateInstanceRazorDataTypeModel(Guid dataType, Type dataTypeType, string value, out object result) { IRazorDataTypeModel razorDataTypeModel = Activator.CreateInstance(dataTypeType, false) as IRazorDataTypeModel; @@ -689,22 +694,22 @@ namespace umbraco.MacroEngines { if (instance == null) { - LogHelper.Warn("razorDataTypeModel successfully instantiated but returned null for instance"); + LogHelper.Warn("razorDataTypeModel successfully instantiated but returned null for instance"); } - result = instance; + result = instance; return true; } else { if (instance == null) { - LogHelper.Warn("razorDataTypeModel successfully instantiated but returned null for instance"); + LogHelper.Warn("razorDataTypeModel successfully instantiated but returned null for instance"); } } } else { - LogHelper.Warn(string.Format("DataTypeModel {0} failed to instantiate, perhaps it is lacking a parameterless constructor or doesn't implement IRazorDataTypeModel?", dataTypeType.FullName)); + LogHelper.Warn(string.Format("DataTypeModel {0} failed to instantiate, perhaps it is lacking a parameterless constructor or doesn't implement IRazorDataTypeModel?", dataTypeType.FullName)); } result = null; return false; @@ -1329,15 +1334,15 @@ namespace umbraco.MacroEngines { get { - return GetChildrenAsList; - //if (n == null) return null; return n.ChildrenAsList; + return GetChildrenAsList; + //if (n == null) return null; return n.ChildrenAsList; } } - public DynamicNodeList Children - { - get { return ChildrenAsList; } - } + public DynamicNodeList Children + { + get { return ChildrenAsList; } + } public IProperty GetProperty(string alias) { @@ -1368,13 +1373,25 @@ namespace umbraco.MacroEngines } public string GetPropertyValue(string alias, string fallback) { - var prop = GetProperty(alias); - if (prop != null) return prop.Value; - return fallback; + string prop; + if (alias.StartsWith("@")) + { + var p = GetReflectedProperty(alias.TrimStart('@')); + prop = p == null ? null : p.ToString(); + } + else + { + var p = GetProperty(alias); + prop = p != null ? p.Value : null; + } + return !prop.IsNullOrWhiteSpace() ? prop : fallback; } public string GetPropertyValue(string alias, bool recursive) { - return GetPropertyValue(alias, recursive, null); + var p = alias.StartsWith("@") + ? GetReflectedProperty(alias.TrimStart('@')) + : GetPropertyValue(alias, recursive, null); + return (string)p; } public string GetPropertyValue(string alias, bool recursive, string fallback) { @@ -1433,14 +1450,24 @@ namespace umbraco.MacroEngines { return this.Index(); } - public int Index() + + /// + /// Checks if the owner list is null and attempts to create it if there is a parent. + /// + /// Successful if the owners list is not null, false if the owners list could not be created and remains null + private bool EnsureOwnersList() { if (this.ownerList == null && this.Parent != null) { var list = this.Parent.ChildrenAsList.Select(n => new DynamicNode(n)); this.ownerList = new DynamicNodeList(list); } - if (this.ownerList != null) + return this.ownerList != null; + } + + public int Index() + { + if (EnsureOwnersList()) { List container = this.ownerList.Items.ToList(); int currentIndex = container.FindIndex(n => n.Id == this.Id); @@ -1448,16 +1475,11 @@ namespace umbraco.MacroEngines { return currentIndex; } - else - { - throw new IndexOutOfRangeException(string.Format("Node {0} belongs to a DynamicNodeList but could not retrieve the index for it's position in the list", this.Id)); - } - } - else - { - throw new ArgumentNullException(string.Format("Node {0} has been orphaned and doesn't belong to a DynamicNodeList", this.Id)); + throw new IndexOutOfRangeException(string.Format("Node {0} belongs to a DynamicNodeList but could not retrieve the index for it's position in the list", this.Id)); } + throw new ArgumentNullException(string.Format("Node {0} has been orphaned and doesn't belong to a DynamicNodeList", this.Id)); } + public bool IsFirst() { return IsHelper(n => n.Index() == 0); @@ -1484,7 +1506,7 @@ namespace umbraco.MacroEngines } public bool IsPosition(int index) { - if (this.ownerList == null) + if (!EnsureOwnersList()) { return false; } @@ -1492,7 +1514,7 @@ namespace umbraco.MacroEngines } public HtmlString IsPosition(int index, string valueIfTrue) { - if (this.ownerList == null) + if (!EnsureOwnersList()) { return new HtmlString(string.Empty); } @@ -1500,7 +1522,7 @@ namespace umbraco.MacroEngines } public HtmlString IsPosition(int index, string valueIfTrue, string valueIfFalse) { - if (this.ownerList == null) + if (!EnsureOwnersList()) { return new HtmlString(valueIfFalse); } @@ -1508,7 +1530,7 @@ namespace umbraco.MacroEngines } public bool IsModZero(int modulus) { - if (this.ownerList == null) + if (!EnsureOwnersList()) { return false; } @@ -1516,7 +1538,7 @@ namespace umbraco.MacroEngines } public HtmlString IsModZero(int modulus, string valueIfTrue) { - if (this.ownerList == null) + if (!EnsureOwnersList()) { return new HtmlString(string.Empty); } @@ -1524,7 +1546,7 @@ namespace umbraco.MacroEngines } public HtmlString IsModZero(int modulus, string valueIfTrue, string valueIfFalse) { - if (this.ownerList == null) + if (!EnsureOwnersList()) { return new HtmlString(valueIfFalse); } @@ -1533,7 +1555,7 @@ namespace umbraco.MacroEngines public bool IsNotModZero(int modulus) { - if (this.ownerList == null) + if (!EnsureOwnersList()) { return false; } @@ -1541,7 +1563,7 @@ namespace umbraco.MacroEngines } public HtmlString IsNotModZero(int modulus, string valueIfTrue) { - if (this.ownerList == null) + if (!EnsureOwnersList()) { return new HtmlString(string.Empty); } @@ -1549,7 +1571,7 @@ namespace umbraco.MacroEngines } public HtmlString IsNotModZero(int modulus, string valueIfTrue, string valueIfFalse) { - if (this.ownerList == null) + if (!EnsureOwnersList()) { return new HtmlString(valueIfFalse); } @@ -1557,7 +1579,7 @@ namespace umbraco.MacroEngines } public bool IsNotPosition(int index) { - if (this.ownerList == null) + if (!EnsureOwnersList()) { return false; } @@ -1565,7 +1587,7 @@ namespace umbraco.MacroEngines } public HtmlString IsNotPosition(int index, string valueIfTrue) { - if (this.ownerList == null) + if (!EnsureOwnersList()) { return new HtmlString(string.Empty); } @@ -1573,7 +1595,7 @@ namespace umbraco.MacroEngines } public HtmlString IsNotPosition(int index, string valueIfTrue, string valueIfFalse) { - if (this.ownerList == null) + if (!EnsureOwnersList()) { return new HtmlString(valueIfFalse); } @@ -1581,7 +1603,7 @@ namespace umbraco.MacroEngines } public bool IsLast() { - if (this.ownerList == null) + if (!EnsureOwnersList()) { return false; } @@ -1590,7 +1612,7 @@ namespace umbraco.MacroEngines } public HtmlString IsLast(string valueIfTrue) { - if (this.ownerList == null) + if (!EnsureOwnersList()) { return new HtmlString(string.Empty); } @@ -1599,7 +1621,7 @@ namespace umbraco.MacroEngines } public HtmlString IsLast(string valueIfTrue, string valueIfFalse) { - if (this.ownerList == null) + if (!EnsureOwnersList()) { return new HtmlString(valueIfFalse); } @@ -1608,7 +1630,7 @@ namespace umbraco.MacroEngines } public bool IsNotLast() { - if (this.ownerList == null) + if (!EnsureOwnersList()) { return false; } @@ -1617,7 +1639,7 @@ namespace umbraco.MacroEngines } public HtmlString IsNotLast(string valueIfTrue) { - if (this.ownerList == null) + if (!EnsureOwnersList()) { return new HtmlString(string.Empty); } @@ -1626,7 +1648,7 @@ namespace umbraco.MacroEngines } public HtmlString IsNotLast(string valueIfTrue, string valueIfFalse) { - if (this.ownerList == null) + if (!EnsureOwnersList()) { return new HtmlString(valueIfFalse); } @@ -1779,128 +1801,128 @@ namespace umbraco.MacroEngines return false; } - #region Explicit INode implementation - INode INode.Parent - { - get { return Parent; } - } + #region Explicit INode implementation + INode INode.Parent + { + get { return Parent; } + } - int INode.Id - { - get { return Id; } - } + int INode.Id + { + get { return Id; } + } - int INode.template - { - get { return template; } - } + int INode.template + { + get { return template; } + } - int INode.SortOrder - { - get { return SortOrder; } - } + int INode.SortOrder + { + get { return SortOrder; } + } - string INode.Name - { - get { return Name; } - } + string INode.Name + { + get { return Name; } + } - string INode.Url - { - get { return Url; } - } + string INode.Url + { + get { return Url; } + } - string INode.UrlName - { - get { return UrlName; } - } + string INode.UrlName + { + get { return UrlName; } + } - string INode.NodeTypeAlias - { - get { return NodeTypeAlias; } - } + string INode.NodeTypeAlias + { + get { return NodeTypeAlias; } + } - string INode.WriterName - { - get { return WriterName; } - } + string INode.WriterName + { + get { return WriterName; } + } - string INode.CreatorName - { - get { return CreatorName; } - } + string INode.CreatorName + { + get { return CreatorName; } + } - int INode.WriterID - { - get { return WriterID; } - } + int INode.WriterID + { + get { return WriterID; } + } - int INode.CreatorID - { - get { return CreatorID; } - } + int INode.CreatorID + { + get { return CreatorID; } + } - string INode.Path - { - get { return Path; } - } + string INode.Path + { + get { return Path; } + } - DateTime INode.CreateDate - { - get { return CreateDate; } - } + DateTime INode.CreateDate + { + get { return CreateDate; } + } - DateTime INode.UpdateDate - { - get { return UpdateDate; } - } + DateTime INode.UpdateDate + { + get { return UpdateDate; } + } - Guid INode.Version - { - get { return Version; } - } + Guid INode.Version + { + get { return Version; } + } - string INode.NiceUrl - { - get { return NiceUrl; } - } + string INode.NiceUrl + { + get { return NiceUrl; } + } - int INode.Level - { - get { return Level; } - } + int INode.Level + { + get { return Level; } + } - List INode.PropertiesAsList - { - get { return PropertiesAsList; } - } + List INode.PropertiesAsList + { + get { return PropertiesAsList; } + } - List INode.ChildrenAsList - { - get { return new List(ChildrenAsList.Select(x => x).ToList()); } - } + List INode.ChildrenAsList + { + get { return new List(ChildrenAsList.Select(x => x).ToList()); } + } - IProperty INode.GetProperty(string Alias) - { - return GetProperty(Alias); - } + IProperty INode.GetProperty(string Alias) + { + return GetProperty(Alias); + } - IProperty INode.GetProperty(string Alias, out bool propertyExists) - { - var p = GetProperty(Alias, false); - propertyExists = p != null; - return p; - } + IProperty INode.GetProperty(string Alias, out bool propertyExists) + { + var p = GetProperty(Alias, false); + propertyExists = p != null; + return p; + } - System.Data.DataTable INode.ChildrenAsTable() - { - return ChildrenAsTable(); - } + System.Data.DataTable INode.ChildrenAsTable() + { + return ChildrenAsTable(); + } - System.Data.DataTable INode.ChildrenAsTable(string nodeTypeAliasFilter) - { - return ChildrenAsTable(nodeTypeAliasFilter); - } - #endregion - } + System.Data.DataTable INode.ChildrenAsTable(string nodeTypeAliasFilter) + { + return ChildrenAsTable(nodeTypeAliasFilter); + } + #endregion + } }