From 4c0a0269496dc1ee592a1033f7b49d8fb53e54ac Mon Sep 17 00:00:00 2001 From: donandren Date: Thu, 19 May 2016 20:13:20 +0300 Subject: [PATCH] MemberSelector UnitTests --- .../Templates/MemberSelector.cs | 19 +- .../Avalonia.Markup.Xaml.UnitTests.csproj | 3 +- .../Templates/MemberSelectorTests.cs | 168 ++++++++++++++++++ 3 files changed, 188 insertions(+), 2 deletions(-) create mode 100644 tests/Avalonia.Markup.Xaml.UnitTests/Templates/MemberSelectorTests.cs diff --git a/src/Markup/Avalonia.Markup.Xaml/Templates/MemberSelector.cs b/src/Markup/Avalonia.Markup.Xaml/Templates/MemberSelector.cs index c04bc5ece9..bc07da8b14 100644 --- a/src/Markup/Avalonia.Markup.Xaml/Templates/MemberSelector.cs +++ b/src/Markup/Avalonia.Markup.Xaml/Templates/MemberSelector.cs @@ -2,6 +2,7 @@ // Licensed under the MIT license. See licence.md file in the project root for full license information. using Avalonia.Controls.Templates; +using Avalonia.Data; using Avalonia.Markup.Data; using System; @@ -25,6 +26,11 @@ namespace Avalonia.Markup.Xaml.Templates public object Select(object o) { + if (string.IsNullOrEmpty(MemberName)) + { + return o; + } + if (_expressionNode == null) { _expressionNode = ExpressionNodeBuilder.Build(MemberName); @@ -37,7 +43,18 @@ namespace Avalonia.Markup.Xaml.Templates _expressionNode.Target = new WeakReference(o); - return _memberValueNode.CurrentValue.Target; + object result = _memberValueNode.CurrentValue.Target; + + if (result == AvaloniaProperty.UnsetValue) + { + return null; + } + else if (result is BindingError) + { + return null; + } + + return result; } private ExpressionNode _expressionNode; diff --git a/tests/Avalonia.Markup.Xaml.UnitTests/Avalonia.Markup.Xaml.UnitTests.csproj b/tests/Avalonia.Markup.Xaml.UnitTests/Avalonia.Markup.Xaml.UnitTests.csproj index a2f2d3db56..7f8c790492 100644 --- a/tests/Avalonia.Markup.Xaml.UnitTests/Avalonia.Markup.Xaml.UnitTests.csproj +++ b/tests/Avalonia.Markup.Xaml.UnitTests/Avalonia.Markup.Xaml.UnitTests.csproj @@ -1,4 +1,4 @@ - + @@ -103,6 +103,7 @@ + diff --git a/tests/Avalonia.Markup.Xaml.UnitTests/Templates/MemberSelectorTests.cs b/tests/Avalonia.Markup.Xaml.UnitTests/Templates/MemberSelectorTests.cs new file mode 100644 index 0000000000..4903ca7b35 --- /dev/null +++ b/tests/Avalonia.Markup.Xaml.UnitTests/Templates/MemberSelectorTests.cs @@ -0,0 +1,168 @@ +// Copyright (c) The Avalonia Project. All rights reserved. +// Licensed under the MIT license. See licence.md file in the project root for full license information. + +using Avalonia.Markup.Xaml.Templates; +using System; +using Xunit; + +namespace Avalonia.Markup.Xaml.UnitTests.Templates +{ + public class MemberSelectorTests + { + [Fact] + public void Should_Not_Hold_Reference_To_Object() + { + WeakReference dataRef = null; + + var selector = new MemberSelector() { MemberName = "Child.StringValue" }; + + Action run = () => + { + var data = new Item() + { + Child = new Item() { StringValue = "Value1" } + }; + + Assert.Same("Value1", selector.Select(data)); + + dataRef = new WeakReference(data); + }; + + run(); + + GC.Collect(); + + Assert.False(dataRef.IsAlive); + } + + [Fact] + public void Should_Select_Child_Property_Value() + { + var selector = new MemberSelector() { MemberName = "Child.StringValue" }; + + var data = new Item() + { + Child = new Item() { StringValue = "Value1" } + }; + + Assert.Same("Value1", selector.Select(data)); + } + + [Fact] + public void Should_Select_Child_Property_Value_In_Multiple_Items() + { + var selector = new MemberSelector() { MemberName = "Child.StringValue" }; + + var data = new Item[] + { + new Item() { Child = new Item() { StringValue = "Value1" } }, + new Item() { Child = new Item() { StringValue = "Value2" } }, + new Item() { Child = new Item() { StringValue = "Value3" } } + }; + + Assert.Same("Value1", selector.Select(data[0])); + Assert.Same("Value2", selector.Select(data[1])); + Assert.Same("Value3", selector.Select(data[2])); + } + + [Fact] + public void Should_Select_MoreComplex_Property_Value() + { + var selector = new MemberSelector() { MemberName = "Child.Child.Child.StringValue" }; + + var data = new Item() + { + Child = new Item() + { + Child = new Item() + { + Child = new Item() { StringValue = "Value1" } + } + } + }; + + Assert.Same("Value1", selector.Select(data)); + } + + [Fact] + public void Should_Select_Null_Value_On_Null_Object() + { + var selector = new MemberSelector() { MemberName = "StringValue" }; + + Assert.Equal(null, selector.Select(null)); + } + + [Fact] + public void Should_Select_Null_Value_On_Wrong_MemberName() + { + var selector = new MemberSelector() { MemberName = "WrongProperty" }; + + var data = new Item() { StringValue = "Value1" }; + + Assert.Same(null, selector.Select(data)); + } + + [Fact] + public void Should_Select_Simple_Property_Value() + { + var selector = new MemberSelector() { MemberName = "StringValue" }; + + var data = new Item() { StringValue = "Value1" }; + + Assert.Same("Value1", selector.Select(data)); + } + + [Fact] + public void Should_Select_Simple_Property_Value_In_Multiple_Items() + { + var selector = new MemberSelector() { MemberName = "StringValue" }; + + var data = new Item[] + { + new Item() { StringValue = "Value1" }, + new Item() { StringValue = "Value2" }, + new Item() { StringValue = "Value3" } + }; + + Assert.Same("Value1", selector.Select(data[0])); + Assert.Same("Value2", selector.Select(data[1])); + Assert.Same("Value3", selector.Select(data[2])); + } + + [Fact] + public void Should_Select_Target_On_Empty_MemberName() + { + var selector = new MemberSelector(); + + var data = new Item() { StringValue = "Value1" }; + + Assert.Same(data, selector.Select(data)); + } + + [Fact] + public void Should_Support_Change_Of_MemberName() + { + var selector = new MemberSelector() { MemberName = "StringValue" }; + + var data = new Item() + { + StringValue = "Value1", + IntValue = 1 + }; + + Assert.Same("Value1", selector.Select(data)); + + selector.MemberName = "IntValue"; + + Assert.Equal(1, selector.Select(data)); + } + + private class Item + { + public Item Child { get; set; } + public int IntValue { get; set; } + + public string StringValue { get; set; } + } + } +} \ No newline at end of file