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 + } }