csharpc-sharpdotnetxamlavaloniauicross-platformcross-platform-xamlavaloniaguimulti-platformuser-interfacedotnetcore
You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
341 lines
11 KiB
341 lines
11 KiB
using System;
|
|
using Avalonia.Controls.Presenters;
|
|
using Avalonia.Controls.Templates;
|
|
using Avalonia.Input;
|
|
using Avalonia.Input.Platform;
|
|
using Avalonia.Input.Raw;
|
|
using Avalonia.Layout;
|
|
using Avalonia.LogicalTree;
|
|
using Avalonia.Platform;
|
|
using Avalonia.Rendering;
|
|
using Avalonia.Rendering.Composition;
|
|
using Avalonia.Styling;
|
|
using Avalonia.UnitTests;
|
|
using Moq;
|
|
using Xunit;
|
|
using static Avalonia.Controls.UnitTests.MaskedTextBoxTests;
|
|
|
|
namespace Avalonia.Controls.UnitTests
|
|
{
|
|
public class TopLevelTests
|
|
{
|
|
[Fact]
|
|
public void IsAttachedToLogicalTree_Is_True()
|
|
{
|
|
using (UnitTestApplication.Start(TestServices.StyledWindow))
|
|
{
|
|
var impl = CreateMockTopLevelImpl();
|
|
var target = new TestTopLevel(impl.Object);
|
|
|
|
Assert.True(((ILogical)target).IsAttachedToLogicalTree);
|
|
}
|
|
}
|
|
|
|
[Fact]
|
|
public void ClientSize_Should_Be_Set_On_Construction()
|
|
{
|
|
using (UnitTestApplication.Start(TestServices.StyledWindow))
|
|
{
|
|
var impl = CreateMockTopLevelImpl();
|
|
impl.Setup(x => x.ClientSize).Returns(new Size(123, 456));
|
|
|
|
var target = new TestTopLevel(impl.Object);
|
|
|
|
Assert.Equal(new Size(123, 456), target.ClientSize);
|
|
}
|
|
}
|
|
|
|
[Fact]
|
|
public void Width_Should_Not_Be_Set_On_Construction()
|
|
{
|
|
using (UnitTestApplication.Start(TestServices.StyledWindow))
|
|
{
|
|
var impl = CreateMockTopLevelImpl();
|
|
impl.Setup(x => x.ClientSize).Returns(new Size(123, 456));
|
|
|
|
var target = new TestTopLevel(impl.Object);
|
|
|
|
Assert.Equal(double.NaN, target.Width);
|
|
}
|
|
}
|
|
|
|
[Fact]
|
|
public void Height_Should_Not_Be_Set_On_Construction()
|
|
{
|
|
using (UnitTestApplication.Start(TestServices.StyledWindow))
|
|
{
|
|
var impl = CreateMockTopLevelImpl();
|
|
impl.Setup(x => x.ClientSize).Returns(new Size(123, 456));
|
|
|
|
var target = new TestTopLevel(impl.Object);
|
|
|
|
Assert.Equal(double.NaN, target.Height);
|
|
}
|
|
}
|
|
|
|
[Fact]
|
|
public void Layout_Pass_Should_Not_Be_Automatically_Scheduled()
|
|
{
|
|
var services = TestServices.StyledWindow;
|
|
|
|
using (UnitTestApplication.Start(services))
|
|
{
|
|
var impl = CreateMockTopLevelImpl();
|
|
|
|
var target = new TestTopLevel(impl.Object, Mock.Of<ILayoutManager>());
|
|
|
|
// The layout pass should be scheduled by the derived class.
|
|
var layoutManagerMock = Mock.Get(target.LayoutManager);
|
|
layoutManagerMock.Verify(x => x.ExecuteLayoutPass(), Times.Never);
|
|
}
|
|
}
|
|
|
|
[Fact]
|
|
public void Bounds_Should_Be_Set_After_Layout_Pass()
|
|
{
|
|
using (UnitTestApplication.Start(TestServices.StyledWindow))
|
|
{
|
|
var impl = CreateMockTopLevelImpl();
|
|
impl.SetupProperty(x => x.Resized);
|
|
impl.SetupGet(x => x.RenderScaling).Returns(1);
|
|
|
|
var target = new TestTopLevel(impl.Object)
|
|
{
|
|
IsVisible = true,
|
|
Template = CreateTemplate(),
|
|
Content = new TextBlock
|
|
{
|
|
Width = 321,
|
|
Height = 432,
|
|
}
|
|
};
|
|
|
|
target.LayoutManager.ExecuteInitialLayoutPass();
|
|
|
|
Assert.Equal(new Rect(0, 0, 321, 432), target.Bounds);
|
|
}
|
|
}
|
|
|
|
[Fact]
|
|
public void Width_And_Height_Should_Not_Be_Set_After_Layout_Pass()
|
|
{
|
|
using (UnitTestApplication.Start(TestServices.StyledWindow))
|
|
{
|
|
var impl = CreateMockTopLevelImpl();
|
|
impl.Setup(x => x.ClientSize).Returns(new Size(123, 456));
|
|
|
|
var target = new TestTopLevel(impl.Object);
|
|
target.LayoutManager.ExecuteLayoutPass();
|
|
|
|
Assert.Equal(double.NaN, target.Width);
|
|
Assert.Equal(double.NaN, target.Height);
|
|
}
|
|
}
|
|
|
|
[Fact]
|
|
public void Width_And_Height_Should_Be_Set_After_Window_Resize_Notification()
|
|
{
|
|
using (UnitTestApplication.Start(TestServices.StyledWindow))
|
|
{
|
|
var impl = CreateMockTopLevelImpl(true);
|
|
impl.Setup(x => x.ClientSize).Returns(new Size(123, 456));
|
|
|
|
// The user has resized the window, so we can no longer auto-size.
|
|
var target = new TestTopLevel(impl.Object);
|
|
impl.Object.Resized(new Size(100, 200), WindowResizeReason.Unspecified);
|
|
|
|
Assert.Equal(100, target.Width);
|
|
Assert.Equal(200, target.Height);
|
|
}
|
|
}
|
|
|
|
[Fact]
|
|
public void Impl_Close_Should_Call_Raise_Closed_Event()
|
|
{
|
|
using (UnitTestApplication.Start(TestServices.StyledWindow))
|
|
{
|
|
var impl = CreateMockTopLevelImpl(true);
|
|
|
|
bool raised = false;
|
|
var target = new TestTopLevel(impl.Object);
|
|
target.Closed += (s, e) => raised = true;
|
|
|
|
impl.Object.Closed();
|
|
|
|
Assert.True(raised);
|
|
}
|
|
}
|
|
|
|
[Fact]
|
|
public void Impl_Close_Should_Raise_DetachedFromLogicalTree_Event()
|
|
{
|
|
using (UnitTestApplication.Start(TestServices.StyledWindow))
|
|
{
|
|
var impl = CreateMockTopLevelImpl(true);
|
|
|
|
var target = new TestTopLevel(impl.Object);
|
|
var raised = 0;
|
|
|
|
target.DetachedFromLogicalTree += (s, e) =>
|
|
{
|
|
Assert.Same(target, e.Root);
|
|
Assert.Same(target, e.Source);
|
|
Assert.Null(e.Parent);
|
|
++raised;
|
|
};
|
|
|
|
impl.Object.Closed();
|
|
|
|
Assert.Equal(1, raised);
|
|
}
|
|
}
|
|
|
|
[Fact]
|
|
public void Impl_Input_Should_Pass_Input_To_InputManager()
|
|
{
|
|
var inputManagerMock = new Mock<IInputManager>();
|
|
inputManagerMock.DefaultValue = DefaultValue.Mock;
|
|
inputManagerMock.SetupAllProperties();
|
|
|
|
var services = TestServices.StyledWindow.With(inputManager: inputManagerMock.Object);
|
|
|
|
using (UnitTestApplication.Start(services))
|
|
{
|
|
var impl = CreateMockTopLevelImpl(true);
|
|
|
|
var target = new TestTopLevel(impl.Object);
|
|
|
|
var input = new RawKeyEventArgs(
|
|
new Mock<IKeyboardDevice>().Object,
|
|
0,
|
|
target,
|
|
RawKeyEventType.KeyDown,
|
|
Key.A, RawInputModifiers.None);
|
|
impl.Object.Input(input);
|
|
|
|
inputManagerMock.Verify(x => x.ProcessInput(input));
|
|
}
|
|
}
|
|
|
|
[Fact]
|
|
public void Adding_Top_Level_As_Child_Should_Throw_Exception()
|
|
{
|
|
using (UnitTestApplication.Start(TestServices.StyledWindow))
|
|
{
|
|
var impl = CreateMockTopLevelImpl(true);
|
|
var target = new TestTopLevel(impl.Object);
|
|
var child = new TestTopLevel(impl.Object);
|
|
|
|
target.Template = CreateTemplate();
|
|
target.Content = child;
|
|
target.ApplyTemplate();
|
|
|
|
Assert.Throws<InvalidOperationException>(() => target.Presenter.ApplyTemplate());
|
|
}
|
|
}
|
|
|
|
[Fact]
|
|
public void Adding_Resource_To_Application_Should_Raise_ResourcesChanged()
|
|
{
|
|
using (UnitTestApplication.Start(TestServices.StyledWindow))
|
|
{
|
|
var impl = CreateMockTopLevelImpl(true);
|
|
var target = new TestTopLevel(impl.Object);
|
|
var raised = false;
|
|
|
|
target.ResourcesChanged += (_, __) => raised = true;
|
|
Application.Current.Resources.Add("foo", "bar");
|
|
|
|
Assert.True(raised);
|
|
}
|
|
}
|
|
|
|
[Fact]
|
|
public void Close_Should_Dispose_LayoutManager()
|
|
{
|
|
using (UnitTestApplication.Start(TestServices.StyledWindow))
|
|
{
|
|
var impl = CreateMockTopLevelImpl(true);
|
|
|
|
var layoutManager = new Mock<ILayoutManager>();
|
|
var target = new TestTopLevel(impl.Object, layoutManager.Object);
|
|
|
|
impl.Object.Closed();
|
|
|
|
layoutManager.Verify(x => x.Dispose());
|
|
}
|
|
}
|
|
|
|
[Fact]
|
|
public void Reacts_To_Changes_In_Global_Styles()
|
|
{
|
|
using (UnitTestApplication.Start(TestServices.StyledWindow))
|
|
{
|
|
var impl = CreateMockTopLevelImpl();
|
|
impl.SetupGet(x => x.RenderScaling).Returns(1);
|
|
|
|
var child = new Border { Classes = { "foo" } };
|
|
var target = new TestTopLevel(impl.Object)
|
|
{
|
|
Template = CreateTemplate(),
|
|
Content = child,
|
|
};
|
|
|
|
target.LayoutManager.ExecuteInitialLayoutPass();
|
|
|
|
Assert.Equal(new Thickness(0), child.BorderThickness);
|
|
|
|
var style = new Style(x => x.OfType<Border>().Class("foo"))
|
|
{
|
|
Setters =
|
|
{
|
|
new Setter(Border.BorderThicknessProperty, new Thickness(2))
|
|
}
|
|
};
|
|
|
|
Application.Current.Styles.Add(style);
|
|
target.LayoutManager.ExecuteInitialLayoutPass();
|
|
|
|
Assert.Equal(new Thickness(2), child.BorderThickness);
|
|
|
|
Application.Current.Styles.Remove(style);
|
|
|
|
Assert.Equal(new Thickness(0), child.BorderThickness);
|
|
}
|
|
}
|
|
|
|
private static FuncControlTemplate<TestTopLevel> CreateTemplate()
|
|
{
|
|
return new FuncControlTemplate<TestTopLevel>((x, scope) =>
|
|
new ContentPresenter
|
|
{
|
|
Name = "PART_ContentPresenter",
|
|
[!ContentPresenter.ContentProperty] = x[!ContentControl.ContentProperty],
|
|
}.RegisterInNameScope(scope));
|
|
}
|
|
|
|
private static Mock<ITopLevelImpl> CreateMockTopLevelImpl(bool setupProperties = false)
|
|
{
|
|
var topLevel = new Mock<ITopLevelImpl>();
|
|
if (setupProperties)
|
|
topLevel.SetupAllProperties();
|
|
topLevel.Setup(x => x.RenderScaling).Returns(1);
|
|
topLevel.Setup(x => x.Compositor).Returns(RendererMocks.CreateDummyCompositor());
|
|
return topLevel;
|
|
}
|
|
|
|
private class TestTopLevel : TopLevel
|
|
{
|
|
private readonly ILayoutManager _layoutManager;
|
|
public bool IsClosed { get; private set; }
|
|
|
|
public TestTopLevel(ITopLevelImpl impl, ILayoutManager layoutManager = null)
|
|
: base(impl)
|
|
{
|
|
_layoutManager = layoutManager ?? new LayoutManager(this);
|
|
}
|
|
|
|
private protected override ILayoutManager CreateLayoutManager() => _layoutManager;
|
|
}
|
|
}
|
|
}
|
|
|