// 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 System.Linq; using Avalonia.Controls.Presenters; using Avalonia.Controls.Templates; using Avalonia.LogicalTree; using Avalonia.UnitTests; using Avalonia.VisualTree; using Moq; using Xunit; namespace Avalonia.Controls.UnitTests.Presenters { /// /// Tests for ContentControls that are hosted in a control template. /// public class ContentPresenterTests_InTemplate { [Fact] public void Should_Register_With_Host_When_TemplatedParent_Set() { var host = new Mock(); var target = new ContentPresenter(); target.SetValue(Control.TemplatedParentProperty, host.Object); host.Verify(x => x.RegisterContentPresenter(target)); } [Fact] public void Setting_Content_To_Control_Should_Set_Child() { var (target, _) = CreateTarget(); var child = new Border(); target.Content = child; Assert.Equal(child, target.Child); } [Fact] public void Setting_Content_To_Control_Should_Update_Logical_Tree() { var (target, parent) = CreateTarget(); var child = new Border(); target.Content = child; Assert.Equal(parent, child.GetLogicalParent()); Assert.Equal(new[] { child }, parent.GetLogicalChildren()); } [Fact] public void Setting_Content_To_Control_Should_Update_Visual_Tree() { var (target, _) = CreateTarget(); var child = new Border(); target.Content = child; Assert.Equal(target, child.GetVisualParent()); Assert.Equal(new[] { child }, target.GetVisualChildren()); } [Fact] public void Setting_Content_To_String_Should_Create_TextBlock() { var (target, _) = CreateTarget(); target.Content = "Foo"; Assert.IsType(target.Child); Assert.Equal("Foo", ((TextBlock)target.Child).Text); } [Fact] public void Setting_Content_To_String_Should_Update_Logical_Tree() { var (target, parent) = CreateTarget(); target.Content = "Foo"; var child = target.Child; Assert.Equal(parent, child.GetLogicalParent()); Assert.Equal(new[] { child }, parent.GetLogicalChildren()); } [Fact] public void Setting_Content_To_String_Should_Update_Visual_Tree() { var (target, _) = CreateTarget(); target.Content = "Foo"; var child = target.Child; Assert.Equal(target, child.GetVisualParent()); Assert.Equal(new[] { child }, target.GetVisualChildren()); } [Fact] public void Clearing_Control_Content_Should_Update_Logical_Tree() { var (target, _) = CreateTarget(); var child = new Border(); target.Content = child; target.Content = null; Assert.Equal(null, child.GetLogicalParent()); Assert.Empty(target.GetLogicalChildren()); } [Fact] public void Clearing_Control_Content_Should_Update_Visual_Tree() { var (target, _) = CreateTarget(); var child = new Border(); target.Content = child; target.Content = null; Assert.Equal(null, child.GetVisualParent()); Assert.Empty(target.GetVisualChildren()); } [Fact] public void Control_Content_Should_Not_Be_NameScope() { var (target, _) = CreateTarget(); target.Content = new TextBlock(); Assert.IsType(target.Child); Assert.Null(NameScope.GetNameScope((Control)target.Child)); } [Fact] public void DataTemplate_Created_Control_Should_Be_NameScope() { var (target, _) = CreateTarget(); target.Content = "Foo"; Assert.IsType(target.Child); Assert.NotNull(NameScope.GetNameScope((Control)target.Child)); } [Fact] public void Assigning_Control_To_Content_Should_Not_Set_DataContext() { var (target, _) = CreateTarget(); target.Content = new Border(); Assert.False(target.IsSet(Control.DataContextProperty)); } [Fact] public void Assigning_NonControl_To_Content_Should_Set_DataContext_On_UpdateChild() { var (target, _) = CreateTarget(); target.Content = "foo"; Assert.Equal("foo", target.DataContext); } [Fact] public void Should_Use_ContentTemplate_If_Specified() { var (target, _) = CreateTarget(); target.ContentTemplate = new FuncDataTemplate(_ => new Canvas()); target.Content = "Foo"; Assert.IsType(target.Child); } [Fact] public void Should_Update_If_ContentTemplate_Changed() { var (target, _) = CreateTarget(); target.Content = "Foo"; Assert.IsType(target.Child); target.ContentTemplate = new FuncDataTemplate(_ => new Canvas()); Assert.IsType(target.Child); target.ContentTemplate = null; Assert.IsType(target.Child); } [Fact] public void Assigning_Control_To_Content_After_NonControl_Should_Clear_DataContext() { var (target, _) = CreateTarget(); target.Content = "foo"; Assert.True(target.IsSet(Control.DataContextProperty)); target.Content = new Border(); Assert.False(target.IsSet(Control.DataContextProperty)); } [Fact] public void Recycles_DataTemplate() { var (target, _) = CreateTarget(); target.DataTemplates.Add(new FuncDataTemplate(_ => new Border(), true)); target.Content = "foo"; var control = target.Child; Assert.IsType(control); target.Content = "bar"; Assert.Same(control, target.Child); } [Fact] public void Detects_DataTemplate_Doesnt_Match_And_Doesnt_Recycle() { var (target, _) = CreateTarget(); target.DataTemplates.Add(new FuncDataTemplate(x => x == "foo", _ => new Border(), true)); target.Content = "foo"; var control = target.Child; Assert.IsType(control); target.Content = "bar"; Assert.IsType(target.Child); } [Fact] public void Detects_DataTemplate_Doesnt_Support_Recycling() { var (target, _) = CreateTarget(); target.DataTemplates.Add(new FuncDataTemplate(_ => new Border(), false)); target.Content = "foo"; var control = target.Child; Assert.IsType(control); target.Content = "bar"; Assert.NotSame(control, target.Child); } [Fact] public void Reevaluates_DataTemplates_When_Recycling() { var (target, _) = CreateTarget(); target.DataTemplates.Add(new FuncDataTemplate(x => x == "bar", _ => new Canvas(), true)); target.DataTemplates.Add(new FuncDataTemplate(_ => new Border(), true)); target.Content = "foo"; var control = target.Child; Assert.IsType(control); target.Content = "bar"; Assert.IsType(target.Child); } (ContentPresenter presenter, ContentControl templatedParent) CreateTarget() { var templatedParent = new ContentControl { Template = new FuncControlTemplate(x => new ContentPresenter { Name = "PART_ContentPresenter", }), }; var root = new TestRoot { Child = templatedParent }; templatedParent.ApplyTemplate(); return ((ContentPresenter)templatedParent.Presenter, templatedParent); } private class TestContentControl : ContentControl { public IControl Child { get; set; } } } }