Files

210 lines
6.9 KiB
C#

using System.Reflection;
using AtomUI.Controls.Data;
using Avalonia.Controls;
using Avalonia.Threading;
using Avalonia.VisualTree;
using Shouldly;
using Xunit;
using AtomUIWindow = AtomUI.Desktop.Controls.Window;
namespace AtomUI.Desktop.Controls.Tests.Transfer;
public class TransferPinnedOpenTests
{
static TransferPinnedOpenTests()
{
AvaloniaTestApp.EnsureInitialized();
}
[Fact]
public void Pinned_Transfer_Opens_One_Source_Dropdown_And_Rejects_Normal_Hide()
{
var transfer = CreateTransfer();
var window = CreateWindow(transfer);
try
{
window.Show();
Dispatcher.UIThread.RunJobs();
var dropdowns = GetDropdowns(transfer);
var source = dropdowns.Single(dropdown => dropdown.ViewType == TransferViewType.Source);
var target = dropdowns.Single(dropdown => dropdown.ViewType == TransferViewType.Target);
SetPopupPinnedOpen(transfer, true);
Dispatcher.UIThread.RunJobs();
GetPopupPinnedOpen(source).ShouldBeTrue();
GetPopupPinnedOpen(target).ShouldBeFalse();
var flyout = source.Flyout.ShouldBeOfType<MenuFlyout>();
flyout.IsPopupPinnedOpen.ShouldBeTrue();
flyout.IsOpen.ShouldBeTrue();
flyout.Popup.ShouldBeOfType<Popup>().IsPopupPinnedOpen.ShouldBeTrue();
flyout.Hide();
Dispatcher.UIThread.RunJobs();
flyout.IsOpen.ShouldBeTrue();
flyout.Popup.IsOpen.ShouldBeTrue();
}
finally
{
SetPopupPinnedOpenIfAvailable(transfer, false);
window.Close();
Dispatcher.UIThread.RunJobs();
}
}
[Fact]
public void Pinned_Transfer_Detach_Closes_Old_And_Reattach_Reopens_Source_Dropdown()
{
var transfer = CreateTransfer();
var window = CreateWindow(transfer);
try
{
window.Show();
Dispatcher.UIThread.RunJobs();
var source = GetSourceDropdown(transfer);
SetPopupPinnedOpen(transfer, true);
Dispatcher.UIThread.RunJobs();
var oldFlyout = source.Flyout.ShouldBeOfType<MenuFlyout>();
oldFlyout.IsOpen.ShouldBeTrue();
window.Content = new Border();
Dispatcher.UIThread.RunJobs();
GetPopupPinnedOpen(source).ShouldBeFalse();
oldFlyout.IsPopupPinnedOpen.ShouldBeFalse();
oldFlyout.IsOpen.ShouldBeFalse();
oldFlyout.Popup.IsOpen.ShouldBeFalse();
window.Content = transfer;
Dispatcher.UIThread.RunJobs();
var reattachedSource = GetSourceDropdown(transfer);
GetPopupPinnedOpen(reattachedSource).ShouldBeTrue();
var newFlyout = reattachedSource.Flyout.ShouldBeOfType<MenuFlyout>();
newFlyout.ShouldNotBeSameAs(oldFlyout);
newFlyout.IsOpen.ShouldBeTrue();
}
finally
{
SetPopupPinnedOpenIfAvailable(transfer, false);
window.Close();
Dispatcher.UIThread.RunJobs();
}
}
[Fact]
public void Transfer_Registers_A_Dropdown_Only_While_A_Pin_Request_Is_Active()
{
var transfer = CreateTransfer();
var window = CreateWindow(transfer);
try
{
window.Show();
Dispatcher.UIThread.RunJobs();
GetPrivateField<TransferSelectDropdown?>(transfer, "_pinnedOpenDropdown").ShouldBeNull();
SetPopupPinnedOpen(transfer, true);
Dispatcher.UIThread.RunJobs();
var source = GetSourceDropdown(transfer);
GetPrivateField<TransferSelectDropdown?>(transfer, "_pinnedOpenDropdown").ShouldBeSameAs(source);
var flyout = source.Flyout.ShouldBeOfType<MenuFlyout>();
flyout.IsOpen.ShouldBeTrue();
SetPopupPinnedOpen(transfer, false);
Dispatcher.UIThread.RunJobs();
GetPrivateField<TransferSelectDropdown?>(transfer, "_pinnedOpenDropdown").ShouldBeNull();
flyout.IsPopupPinnedOpen.ShouldBeFalse();
flyout.IsOpen.ShouldBeTrue();
}
finally
{
SetPopupPinnedOpenIfAvailable(transfer, false);
window.Close();
Dispatcher.UIThread.RunJobs();
}
}
private static ListTransfer CreateTransfer()
{
return new ListTransfer
{
Width = 520,
Height = 260,
IsMotionEnabled = false,
ItemsSource =
[
new ListItemData { ItemKey = "first", Content = "First" },
new ListItemData { ItemKey = "second", Content = "Second" }
]
};
}
private static AtomUIWindow CreateWindow(Control content)
{
return new AtomUIWindow
{
Width = 640,
Height = 360,
Content = content
};
}
private static TransferSelectDropdown[] GetDropdowns(AbstractTransfer transfer)
{
return transfer.GetVisualDescendants()
.OfType<TransferSelectDropdown>()
.ToArray();
}
private static TransferSelectDropdown GetSourceDropdown(AbstractTransfer transfer)
{
return GetDropdowns(transfer)
.Single(dropdown => dropdown.ViewType == TransferViewType.Source);
}
private static void SetPopupPinnedOpen(object target, bool value)
{
var property = target.GetType().GetProperty(
"IsPopupPinnedOpen",
BindingFlags.Instance | BindingFlags.NonPublic);
property.ShouldNotBeNull($"{target.GetType().Name} must own the internal popup pin contract.")
.SetValue(target, value);
}
private static void SetPopupPinnedOpenIfAvailable(object target, bool value)
{
target.GetType()
.GetProperty("IsPopupPinnedOpen", BindingFlags.Instance | BindingFlags.NonPublic)?
.SetValue(target, value);
}
private static bool GetPopupPinnedOpen(object target)
{
var property = target.GetType().GetProperty(
"IsPopupPinnedOpen",
BindingFlags.Instance | BindingFlags.NonPublic);
return property.ShouldNotBeNull($"{target.GetType().Name} must expose the internal popup pin adapter.")
.GetValue(target)
.ShouldBeOfType<bool>();
}
private static T GetPrivateField<T>(object target, string fieldName)
{
for (var type = target.GetType(); type != null; type = type.BaseType)
{
var field = type.GetField(fieldName, BindingFlags.Instance | BindingFlags.NonPublic | BindingFlags.DeclaredOnly);
if (field != null)
{
return (T)field.GetValue(target)!;
}
}
throw new MissingFieldException(target.GetType().FullName, fieldName);
}
}