// Copyright (c) The Perspex Project. All rights reserved. // Licensed under the MIT license. See licence.md file in the project root for full license information. using System; using System.Collections.Specialized; using System.Linq; using Moq; using Perspex.Controls.Presenters; using Perspex.Controls.Templates; using Perspex.LogicalTree; using Perspex.Platform; using Perspex.Styling; using Perspex.VisualTree; using Ploeh.AutoFixture; using Ploeh.AutoFixture.AutoMoq; using Xunit; namespace Perspex.Controls.UnitTests { public class ContentControlTests { [Fact] public void Template_Should_Be_Instantiated() { using (var ctx = RegisterServices()) { var target = new ContentControl(); target.Content = "Foo"; target.Template = GetTemplate(); target.Measure(new Size(100, 100)); var child = ((IVisual)target).VisualChildren.Single(); Assert.IsType(child); child = child.VisualChildren.Single(); Assert.IsType(child); child = child.VisualChildren.Single(); Assert.IsType(child); } } [Fact] public void Templated_Children_Should_Be_Styled() { using (var ctx = RegisterServices()) { var root = new TestRoot(); var target = new ContentControl(); var styler = new Mock(); PerspexLocator.CurrentMutable.Bind().ToConstant(styler.Object); target.Content = "Foo"; target.Template = GetTemplate(); root.Child = target; target.ApplyTemplate(); styler.Verify(x => x.ApplyStyles(It.IsAny()), Times.Once()); styler.Verify(x => x.ApplyStyles(It.IsAny()), Times.Once()); styler.Verify(x => x.ApplyStyles(It.IsAny()), Times.Once()); styler.Verify(x => x.ApplyStyles(It.IsAny()), Times.Once()); } } [Fact] public void ContentPresenter_Should_Have_TemplatedParent_Set() { var target = new ContentControl(); var child = new Border(); target.Template = GetTemplate(); target.Content = child; target.ApplyTemplate(); var contentPresenter = child.GetVisualParent(); Assert.Equal(target, contentPresenter.TemplatedParent); } [Fact] public void Content_Should_Have_TemplatedParent_Set_To_Null() { var target = new ContentControl(); var child = new Border(); target.Template = GetTemplate(); target.Content = child; target.ApplyTemplate(); Assert.Null(child.TemplatedParent); } [Fact] public void Setting_Content_To_Control_Should_Set_Child_Controls_Parent() { var target = new ContentControl { Template = GetTemplate(), }; var child = new Control(); target.Content = child; target.ApplyTemplate(); Assert.Equal(child.Parent, target); Assert.Equal(((ILogical)child).LogicalParent, target); } [Fact] public void Setting_Content_To_String_Should_Set_Child_Controls_Parent() { var target = new ContentControl { Template = GetTemplate(), }; target.Content = "Foo"; target.ApplyTemplate(); var child = target.Presenter.Child; Assert.Equal(child.Parent, target); Assert.Equal(((ILogical)child).LogicalParent, target); } [Fact] public void Clearing_Content_Should_Clear_Child_Controls_Parent() { var target = new ContentControl(); var child = new Control(); target.Content = child; target.Content = null; Assert.Null(child.Parent); Assert.Null(((ILogical)child).LogicalParent); } [Fact] public void Setting_Content_To_Control_Should_Make_Control_Appear_In_LogicalChildren() { var target = new ContentControl(); var child = new Control(); target.Template = GetTemplate(); target.Content = child; target.ApplyTemplate(); Assert.Equal(new[] { child }, ((ILogical)target).LogicalChildren.ToList()); } [Fact] public void Setting_Content_To_String_Should_Make_TextBlock_Appear_In_LogicalChildren() { var target = new ContentControl(); var child = new Control(); target.Template = GetTemplate(); target.Content = "Foo"; target.ApplyTemplate(); var logical = (ILogical)target; Assert.Equal(1, logical.LogicalChildren.Count); Assert.IsType(logical.LogicalChildren[0]); } [Fact] public void Clearing_Content_Should_Remove_From_LogicalChildren() { var target = new ContentControl(); var child = new Control(); target.Template = GetTemplate(); target.Content = child; target.ApplyTemplate(); target.Content = null; // Need to call ApplyTemplate on presenter for LogicalChildren to be updated. target.Presenter.ApplyTemplate(); Assert.Empty(target.GetLogicalChildren()); } [Fact] public void Setting_Content_Should_Fire_LogicalChildren_CollectionChanged() { var target = new ContentControl(); var child = new Control(); var called = false; ((ILogical)target).LogicalChildren.CollectionChanged += (s, e) => called = e.Action == NotifyCollectionChangedAction.Add; target.Template = GetTemplate(); target.Content = child; target.ApplyTemplate(); // Need to call ApplyTemplate on presenter for LogicalChildren to be updated. target.Presenter.ApplyTemplate(); Assert.True(called); } [Fact] public void Clearing_Content_Should_Fire_LogicalChildren_CollectionChanged() { var target = new ContentControl(); var child = new Control(); var called = false; target.Template = GetTemplate(); target.Content = child; target.ApplyTemplate(); ((ILogical)target).LogicalChildren.CollectionChanged += (s, e) => called = true; target.Content = null; // Need to call ApplyTemplate on presenter for CollectionChanged to be called. var presenter = target.GetTemplateChildren().Single(x => x.Name == "contentPresenter"); presenter.ApplyTemplate(); Assert.True(called); } [Fact] public void Changing_Content_Should_Fire_LogicalChildren_CollectionChanged() { var contentControl = new ContentControl(); var child1 = new Control(); var child2 = new Control(); var called = false; contentControl.Template = GetTemplate(); contentControl.Content = child1; contentControl.ApplyTemplate(); ((ILogical)contentControl).LogicalChildren.CollectionChanged += (s, e) => called = true; contentControl.Content = child2; // Need to call ApplyTemplate on presenter for CollectionChanged to be called. var presenter = contentControl.GetTemplateChildren().Single(x => x.Name == "contentPresenter"); presenter.ApplyTemplate(); Assert.True(called); } [Fact] public void Changing_Content_Should_Update_Presenter() { var target = new ContentControl(); target.Template = GetTemplate(); target.ApplyTemplate(); target.Content = "Foo"; target.Presenter.ApplyTemplate(); Assert.Equal("Foo", ((TextBlock)target.Presenter.Child).Text); target.Content = "Bar"; target.Presenter.ApplyTemplate(); Assert.Equal("Bar", ((TextBlock)target.Presenter.Child).Text); } [Fact] public void DataContext_Should_Be_Set_For_Templated_Data() { var target = new ContentControl(); target.Template = GetTemplate(); target.Content = "Foo"; target.ApplyTemplate(); Assert.Equal("Foo", target.Presenter.Child.DataContext); } [Fact] public void DataContext_Should_Not_Be_Set_For_Control_Data() { var target = new ContentControl(); target.Template = GetTemplate(); target.Content = new TextBlock(); target.ApplyTemplate(); Assert.Null(target.Presenter.Child.DataContext); } private FuncControlTemplate GetTemplate() { return new FuncControlTemplate(parent => { return new Border { Background = new Media.SolidColorBrush(0xffffffff), Child = new ContentPresenter { Name = "contentPresenter", [~ContentPresenter.ContentProperty] = parent[~ContentControl.ContentProperty], } }; }); } private IDisposable RegisterServices() { var result = PerspexLocator.EnterScope(); var fixture = new Fixture().Customize(new AutoMoqCustomization()); var renderInterface = fixture.Create(); PerspexLocator.CurrentMutable .Bind().ToConstant(renderInterface); return result; } } }