using System; using System.Collections.Generic; using System.Collections.Specialized; using System.Linq; using Avalonia.Controls; using Avalonia.Controls.Presenters; using Avalonia.Controls.Primitives; using Avalonia.Controls.Templates; using Avalonia.Input; using Avalonia.LogicalTree; using Avalonia.Media; using Avalonia.Styling; using Avalonia.Themes.Simple; using Avalonia.Threading; using Avalonia.UnitTests; using Avalonia.VisualTree; using Xunit; namespace Avalonia.Controls.UnitTests; public class CommandBarButtonTests : ScopedTestBase { [Fact] public void Label_DefaultIsNull() => Assert.Null(new CommandBarButton().Label); [Fact] public void Label_RoundTrip() { var btn = new CommandBarButton { Label = "Save" }; Assert.Equal("Save", btn.Label); } [Fact] public void Icon_DefaultIsNull() => Assert.Null(new CommandBarButton().Icon); [Fact] public void Icon_RoundTrip() { var btn = new CommandBarButton(); var icon = new object(); btn.Icon = icon; Assert.Same(icon, btn.Icon); } [Fact] public void IsCompact_DefaultIsFalse() => Assert.False(new CommandBarButton().IsCompact); [Fact] public void IsCompact_RoundTrip() { var btn = new CommandBarButton { IsCompact = true }; Assert.True(btn.IsCompact); } [Fact] public void DynamicOverflowOrder_DefaultIsZero() => Assert.Equal(0, new CommandBarButton().DynamicOverflowOrder); [Fact] public void DynamicOverflowOrder_RoundTrip() { var btn = new CommandBarButton { DynamicOverflowOrder = 3 }; Assert.Equal(3, btn.DynamicOverflowOrder); } [Fact] public void LabelPosition_DefaultIsBottom() => Assert.Equal(CommandBarDefaultLabelPosition.Bottom, new CommandBarButton().LabelPosition); [Fact] public void LabelPosition_RoundTrip() { var btn = new CommandBarButton { LabelPosition = CommandBarDefaultLabelPosition.Right }; Assert.Equal(CommandBarDefaultLabelPosition.Right, btn.LabelPosition); } [Fact] public void IsInOverflow_DefaultIsFalse() => Assert.False(new CommandBarButton().IsInOverflow); [Fact] public void IsInOverflow_RoundTrip() { var btn = new CommandBarButton { IsInOverflow = true }; Assert.True(btn.IsInOverflow); } [Fact] public void ImplementsICommandBarElement() => Assert.IsAssignableFrom(new CommandBarButton()); [Fact] public void ICommandBarElement_IsCompact_ReadWrite() { ICommandBarElement elem = new CommandBarButton(); elem.IsCompact = true; Assert.True(elem.IsCompact); } [Fact] public void Command_DefaultIsNull() => Assert.Null(new CommandBarButton().Command); [Fact] public void CommandParameter_DefaultIsNull() => Assert.Null(new CommandBarButton().CommandParameter); [Fact] public void Command_RoundTrip() { var btn = new CommandBarButton(); var cmd = new DelegateCommand(_ => { }); btn.Command = cmd; Assert.Same(cmd, btn.Command); } [Fact] public void CommandParameter_RoundTrip() { var btn = new CommandBarButton { CommandParameter = "param" }; Assert.Equal("param", btn.CommandParameter); } [Fact] public void Foreground_DoesNotSetOrOverwriteIconElementForeground() { var icon = new PathIcon(); var btn = new CommandBarButton { Icon = icon, Foreground = Brushes.Red }; Assert.False(icon.IsSet(TemplatedControl.ForegroundProperty)); btn.Foreground = Brushes.Blue; Assert.False(icon.IsSet(TemplatedControl.ForegroundProperty)); icon.Foreground = Brushes.Green; btn.Foreground = Brushes.Red; Assert.Same(Brushes.Green, icon.Foreground); } } public class CommandBarToggleButtonTests : ScopedTestBase { [Fact] public void Label_DefaultIsNull() => Assert.Null(new CommandBarToggleButton().Label); [Fact] public void Label_RoundTrip() { var btn = new CommandBarToggleButton { Label = "Bold" }; Assert.Equal("Bold", btn.Label); } [Fact] public void Icon_DefaultIsNull() => Assert.Null(new CommandBarToggleButton().Icon); [Fact] public void IsCompact_DefaultIsFalse() => Assert.False(new CommandBarToggleButton().IsCompact); [Fact] public void IsCompact_RoundTrip() { var btn = new CommandBarToggleButton { IsCompact = true }; Assert.True(btn.IsCompact); } [Fact] public void DynamicOverflowOrder_DefaultIsZero() => Assert.Equal(0, new CommandBarToggleButton().DynamicOverflowOrder); [Fact] public void DynamicOverflowOrder_RoundTrip() { var btn = new CommandBarToggleButton { DynamicOverflowOrder = 5 }; Assert.Equal(5, btn.DynamicOverflowOrder); } [Fact] public void LabelPosition_DefaultIsBottom() => Assert.Equal(CommandBarDefaultLabelPosition.Bottom, new CommandBarToggleButton().LabelPosition); [Fact] public void LabelPosition_RoundTrip() { var btn = new CommandBarToggleButton { LabelPosition = CommandBarDefaultLabelPosition.Collapsed }; Assert.Equal(CommandBarDefaultLabelPosition.Collapsed, btn.LabelPosition); } [Fact] public void IsInOverflow_DefaultIsFalse() => Assert.False(new CommandBarToggleButton().IsInOverflow); [Fact] public void ImplementsICommandBarElement() => Assert.IsAssignableFrom(new CommandBarToggleButton()); [Fact] public void ICommandBarElement_IsCompact_ReadWrite() { ICommandBarElement elem = new CommandBarToggleButton(); elem.IsCompact = true; Assert.True(elem.IsCompact); } [Fact] public void Command_DefaultIsNull() => Assert.Null(new CommandBarToggleButton().Command); [Fact] public void Command_RoundTrip() { var btn = new CommandBarToggleButton(); var cmd = new DelegateCommand(_ => { }); btn.Command = cmd; Assert.Same(cmd, btn.Command); } [Fact] public void CommandParameter_RoundTrip() { var btn = new CommandBarToggleButton { CommandParameter = 42 }; Assert.Equal(42, btn.CommandParameter); } [Fact] public void Foreground_DoesNotSetOrOverwriteIconElementForeground() { var icon = new PathIcon(); var btn = new CommandBarToggleButton { Icon = icon, Foreground = Brushes.Red }; Assert.False(icon.IsSet(TemplatedControl.ForegroundProperty)); btn.Foreground = Brushes.Blue; Assert.False(icon.IsSet(TemplatedControl.ForegroundProperty)); icon.Foreground = Brushes.Green; btn.Foreground = Brushes.Red; Assert.Same(Brushes.Green, icon.Foreground); } } public class CommandBarSeparatorTests : ScopedTestBase { [Fact] public void IsCompact_DefaultIsFalse() => Assert.False(new CommandBarSeparator().IsCompact); [Fact] public void IsCompact_RoundTrip() { var sep = new CommandBarSeparator { IsCompact = true }; Assert.True(sep.IsCompact); } [Fact] public void IsInOverflow_DefaultIsFalse() => Assert.False(new CommandBarSeparator().IsInOverflow); [Fact] public void IsInOverflow_RoundTrip() { var sep = new CommandBarSeparator { IsInOverflow = true }; Assert.True(sep.IsInOverflow); } [Fact] public void ImplementsICommandBarElement() => Assert.IsAssignableFrom(new CommandBarSeparator()); [Fact] public void DerivesFromSeparator() => Assert.IsAssignableFrom(new CommandBarSeparator()); [Fact] public void ICommandBarElement_IsCompact_ReadWrite() { ICommandBarElement elem = new CommandBarSeparator(); elem.IsCompact = true; Assert.True(elem.IsCompact); } } public class CommandBarEnumTests : ScopedTestBase { [Fact] public void LabelPosition_Bottom_IsZero() => Assert.Equal(0, (int)CommandBarDefaultLabelPosition.Bottom); [Fact] public void LabelPosition_Right_IsOne() => Assert.Equal(1, (int)CommandBarDefaultLabelPosition.Right); [Fact] public void LabelPosition_Collapsed_IsTwo() => Assert.Equal(2, (int)CommandBarDefaultLabelPosition.Collapsed); [Fact] public void OverflowButtonVisibility_Auto_IsZero() => Assert.Equal(0, (int)CommandBarOverflowButtonVisibility.Auto); [Fact] public void OverflowButtonVisibility_Visible_IsOne() => Assert.Equal(1, (int)CommandBarOverflowButtonVisibility.Visible); [Fact] public void OverflowButtonVisibility_Collapsed_IsTwo() => Assert.Equal(2, (int)CommandBarOverflowButtonVisibility.Collapsed); } public class CommandBarDefaultsTests : ScopedTestBase { [Fact] public void DefaultLabelPosition_IsBottom() => Assert.Equal(CommandBarDefaultLabelPosition.Bottom, new CommandBar().DefaultLabelPosition); [Fact] public void OverflowButtonVisibility_DefaultIsAuto() => Assert.Equal(CommandBarOverflowButtonVisibility.Auto, new CommandBar().OverflowButtonVisibility); [Fact] public void IsOpen_DefaultIsFalse() => Assert.False(new CommandBar().IsOpen); [Fact] public void IsSticky_DefaultIsFalse() => Assert.False(new CommandBar().IsSticky); [Fact] public void IsDynamicOverflowEnabled_DefaultIsFalse() => Assert.False(new CommandBar().IsDynamicOverflowEnabled); [Fact] public void HasSecondaryCommands_DefaultIsFalse() => Assert.False(new CommandBar().HasSecondaryCommands); [Fact] public void IsOverflowButtonVisible_DefaultIsFalse() => Assert.False(new CommandBar().IsOverflowButtonVisible); [Fact] public void Content_DefaultIsNull() => Assert.Null(new CommandBar().Content); [Fact] public void Foreground_IsInheritedByCommandBarButtonPathIconThroughThemeTemplate() { using var app = UnitTestApplication.Start(TestServices.StyledWindow); var icon = new PathIcon(); var btn = new CommandBarButton { Icon = icon }; var commandBar = new CommandBar { Foreground = Brushes.Red }; commandBar.PrimaryCommands.Add(btn); Assert.Same(icon, ApplySimpleThemeAndGetPresentedPathIcon(commandBar, btn)); Assert.Same(Brushes.Red, icon.Foreground); commandBar.Foreground = Brushes.Blue; Assert.Same(Brushes.Blue, icon.Foreground); } [Fact] public void Foreground_IsInheritedByCommandBarToggleButtonPathIconThroughThemeTemplate() { using var app = UnitTestApplication.Start(TestServices.StyledWindow); var icon = new PathIcon(); var btn = new CommandBarToggleButton { Icon = icon }; var commandBar = new CommandBar { Foreground = Brushes.Red }; commandBar.PrimaryCommands.Add(btn); Assert.Same(icon, ApplySimpleThemeAndGetPresentedPathIcon(commandBar, btn)); Assert.Same(Brushes.Red, icon.Foreground); commandBar.Foreground = Brushes.Blue; Assert.Same(Brushes.Blue, icon.Foreground); } [Fact] public void PrimaryCommands_NotNull() => Assert.NotNull(new CommandBar().PrimaryCommands); [Fact] public void SecondaryCommands_NotNull() => Assert.NotNull(new CommandBar().SecondaryCommands); [Fact] public void VisiblePrimaryCommands_NotNull() => Assert.NotNull(new CommandBar().VisiblePrimaryCommands); [Fact] public void OverflowItems_NotNull() => Assert.NotNull(new CommandBar().OverflowItems); [Fact] public void PrimaryCommands_StartsEmpty() => Assert.Empty(new CommandBar().PrimaryCommands); [Fact] public void SecondaryCommands_StartsEmpty() => Assert.Empty(new CommandBar().SecondaryCommands); [Fact] public void PrimaryCommands_ReturnsNewListWhenNull() { var cb = new CommandBar(); cb.ClearValue(CommandBar.PrimaryCommandsProperty); Assert.NotNull(cb.PrimaryCommands); Assert.Empty(cb.PrimaryCommands); } [Fact] public void SecondaryCommands_ReturnsNewListWhenNull() { var cb = new CommandBar(); cb.ClearValue(CommandBar.SecondaryCommandsProperty); Assert.NotNull(cb.SecondaryCommands); Assert.Empty(cb.SecondaryCommands); } [Fact] public void VisiblePrimaryCommands_StartsEmpty() => Assert.Empty(new CommandBar().VisiblePrimaryCommands); [Fact] public void OverflowItems_StartsEmpty() => Assert.Empty(new CommandBar().OverflowItems); [Fact] public void ItemWidthBottom_DefaultIs70() => Assert.Equal(70d, new CommandBar().ItemWidthBottom); [Fact] public void ItemWidthRight_DefaultIs102() => Assert.Equal(102d, new CommandBar().ItemWidthRight); [Fact] public void ItemWidthCollapsed_DefaultIs42() => Assert.Equal(42d, new CommandBar().ItemWidthCollapsed); private static PathIcon ApplySimpleThemeAndGetPresentedPathIcon(CommandBar commandBar, TemplatedControl command) { var simpleTheme = new SimpleTheme(); Assert.True(simpleTheme.TryGetResource(typeof(CommandBar), ThemeVariant.Default, out var commandBarTheme)); Assert.True(simpleTheme.TryGetResource(command.GetType(), ThemeVariant.Default, out var commandTheme)); commandBar.Theme = Assert.IsType(commandBarTheme); command.Theme = Assert.IsType(commandTheme); var root = new TestRoot { Width = 500, Height = 200, Child = commandBar, Styles = { simpleTheme } }; root.ApplyStyling(); commandBar.ApplyStyling(); commandBar.ApplyTemplate(); root.LayoutManager.ExecuteInitialLayoutPass(); command.ApplyStyling(); command.ApplyTemplate(); var presenter = command.GetTemplateDescendants() .OfType() .Single(x => x.Name == "PART_IconPresenter"); presenter.ApplyStyling(); presenter.UpdateChild(); var pathIcon = Assert.IsType(presenter.Child); pathIcon.ApplyStyling(); return pathIcon; } } public class CommandBarPropertyRoundTripTests : ScopedTestBase { [Fact] public void Content_RoundTrip() { var cb = new CommandBar(); var content = new object(); cb.Content = content; Assert.Same(content, cb.Content); } [Fact] public void DefaultLabelPosition_RoundTrip() { var cb = new CommandBar { DefaultLabelPosition = CommandBarDefaultLabelPosition.Right }; Assert.Equal(CommandBarDefaultLabelPosition.Right, cb.DefaultLabelPosition); } [Fact] public void IsOpen_RoundTrip() { var cb = new CommandBar { IsOpen = true }; Assert.True(cb.IsOpen); cb.IsOpen = false; Assert.False(cb.IsOpen); } [Fact] public void IsSticky_RoundTrip() { var cb = new CommandBar { IsSticky = true }; Assert.True(cb.IsSticky); } [Fact] public void IsDynamicOverflowEnabled_RoundTrip() { var cb = new CommandBar { IsDynamicOverflowEnabled = true }; Assert.True(cb.IsDynamicOverflowEnabled); } [Fact] public void OverflowButtonVisibility_RoundTrip() { var cb = new CommandBar { OverflowButtonVisibility = CommandBarOverflowButtonVisibility.Visible }; Assert.Equal(CommandBarOverflowButtonVisibility.Visible, cb.OverflowButtonVisibility); } [Fact] public void ItemWidthBottom_RoundTrip() { var cb = new CommandBar { ItemWidthBottom = 80d }; Assert.Equal(80d, cb.ItemWidthBottom); } [Fact] public void ItemWidthRight_RoundTrip() { var cb = new CommandBar { ItemWidthRight = 120d }; Assert.Equal(120d, cb.ItemWidthRight); } [Fact] public void ItemWidthCollapsed_RoundTrip() { var cb = new CommandBar { ItemWidthCollapsed = 50d }; Assert.Equal(50d, cb.ItemWidthCollapsed); } } public class CommandBarIsOpenTests : ScopedTestBase { [Fact] public void Opening_FiredWhenIsOpenBecomesTrue() { var cb = new CommandBar(); bool fired = false; cb.Opening += (_, _) => fired = true; cb.IsOpen = true; Assert.True(fired); } [Fact] public void Opened_FiredWhenIsOpenBecomesTrue() { var cb = new CommandBar(); bool fired = false; cb.Opened += (_, _) => fired = true; cb.IsOpen = true; Assert.True(fired); } [Fact] public void Closing_FiredWhenIsOpenBecomesFalse() { var cb = new CommandBar { IsOpen = true }; bool fired = false; cb.Closing += (_, _) => fired = true; cb.IsOpen = false; Assert.True(fired); } [Fact] public void Closed_FiredWhenIsOpenBecomesFalse() { var cb = new CommandBar { IsOpen = true }; bool fired = false; cb.Closed += (_, _) => fired = true; cb.IsOpen = false; Assert.True(fired); } [Fact] public void Opening_NotFiredWhenAlreadyOpen() { var cb = new CommandBar(); cb.IsOpen = true; int count = 0; cb.Opening += (_, _) => count++; cb.IsOpen = true; Assert.Equal(0, count); } [Fact] public void Closing_NotFiredWhenAlreadyClosed() { var cb = new CommandBar(); int count = 0; cb.Closing += (_, _) => count++; cb.IsOpen = false; Assert.Equal(0, count); } [Fact] public void Events_FiredInOrder_OpenThenClose() { var cb = new CommandBar(); var events = new List(); cb.Opening += (_, _) => events.Add("Opening"); cb.Opened += (_, _) => events.Add("Opened"); cb.Closing += (_, _) => events.Add("Closing"); cb.Closed += (_, _) => events.Add("Closed"); cb.IsOpen = true; cb.IsOpen = false; Assert.Equal(new[] { "Opening", "Opened", "Closing", "Closed" }, events); } } public class CommandBarCollectionTests : ScopedTestBase { [Fact] public void PrimaryCommands_Added_AppearInVisiblePrimary_WhenDynamicOverflowDisabled() { var cb = new CommandBar(); var btn = new CommandBarButton { Label = "Save" }; cb.PrimaryCommands!.Add(btn); Assert.Contains(btn, cb.VisiblePrimaryCommands); } [Fact] public void PrimaryCommands_DefaultCollection_DoesNotDuplicateVisiblePrimaryNotifications() { var cb = new CommandBar(); var notifications = 0; ((INotifyCollectionChanged)cb.VisiblePrimaryCommands).CollectionChanged += (_, _) => notifications++; cb.PrimaryCommands!.Add(new CommandBarButton { Label = "Save" }); Assert.Equal(2, notifications); } [Fact] public void PrimaryCommands_Removed_DisappearsFromVisiblePrimary() { var cb = new CommandBar(); var btn = new CommandBarButton { Label = "Save" }; cb.PrimaryCommands!.Add(btn); cb.PrimaryCommands!.Remove(btn); Assert.DoesNotContain(btn, cb.VisiblePrimaryCommands); } [Fact] public void SecondaryCommands_Added_AppearInOverflowItems() { var cb = new CommandBar(); var btn = new CommandBarButton { Label = "Settings" }; cb.SecondaryCommands!.Add(btn); Assert.Contains(btn, cb.OverflowItems); } [Fact] public void SecondaryCommands_DefaultCollection_DoesNotDuplicateOverflowNotifications() { var cb = new CommandBar(); var notifications = 0; ((INotifyCollectionChanged)cb.OverflowItems).CollectionChanged += (_, _) => notifications++; cb.SecondaryCommands!.Add(new CommandBarButton { Label = "Settings" }); Assert.Equal(2, notifications); } [Fact] public void SecondaryCommands_Removed_DisappearsFromOverflowItems() { var cb = new CommandBar(); var btn = new CommandBarButton { Label = "Settings" }; cb.SecondaryCommands!.Add(btn); cb.SecondaryCommands!.Remove(btn); Assert.DoesNotContain(btn, cb.OverflowItems); } [Fact] public void HasSecondaryCommands_TrueWhenSecondaryAdded() { var cb = new CommandBar(); cb.SecondaryCommands!.Add(new CommandBarButton { Label = "Options" }); Assert.True(cb.HasSecondaryCommands); } [Fact] public void HasSecondaryCommands_FalseAfterSecondaryCleared() { var cb = new CommandBar(); var btn = new CommandBarButton { Label = "Options" }; cb.SecondaryCommands!.Add(btn); cb.SecondaryCommands!.Remove(btn); Assert.False(cb.HasSecondaryCommands); } [Fact] public void OverflowItems_CountMatchesSecondaryCommandCount() { var cb = new CommandBar(); cb.SecondaryCommands!.Add(new CommandBarButton()); cb.SecondaryCommands!.Add(new CommandBarButton()); Assert.Equal(2, cb.OverflowItems.Count); } [Fact] public void VisiblePrimaryCommands_CountMatchesPrimary_WhenDynamicOverflowDisabled() { var cb = new CommandBar(); cb.PrimaryCommands!.Add(new CommandBarButton()); cb.PrimaryCommands!.Add(new CommandBarButton()); Assert.Equal(2, cb.VisiblePrimaryCommands.Count); } [Fact] public void MultiplePrimaryCommands_AllVisibleInOrder() { var cb = new CommandBar(); var btn1 = new CommandBarButton { Label = "A" }; var btn2 = new CommandBarButton { Label = "B" }; var btn3 = new CommandBarButton { Label = "C" }; cb.PrimaryCommands!.Add(btn1); cb.PrimaryCommands!.Add(btn2); cb.PrimaryCommands!.Add(btn3); Assert.Equal(new ICommandBarElement[] { btn1, btn2, btn3 }, cb.VisiblePrimaryCommands); } [Fact] public void CommandBarSeparator_CanBeAddedToPrimaryCommands() { var cb = new CommandBar(); var sep = new CommandBarSeparator(); cb.PrimaryCommands!.Add(sep); Assert.Contains(sep, cb.VisiblePrimaryCommands); } [Fact] public void CommandBarToggleButton_CanBeAddedToPrimaryCommands() { var cb = new CommandBar(); var toggle = new CommandBarToggleButton { Label = "Bold" }; cb.PrimaryCommands!.Add(toggle); Assert.Contains(toggle, cb.VisiblePrimaryCommands); } } public class CommandBarLabelPositionTests : ScopedTestBase { [Fact] public void DefaultLabelPosition_Collapsed_SetsIsCompactOnExistingPrimaryButton() { var cb = new CommandBar(); var btn = new CommandBarButton(); cb.PrimaryCommands!.Add(btn); cb.DefaultLabelPosition = CommandBarDefaultLabelPosition.Collapsed; Assert.True(btn.IsCompact); } [Fact] public void DefaultLabelPosition_Bottom_ClearsIsCompactOnPrimaryButton() { var cb = new CommandBar(); var btn = new CommandBarButton(); cb.PrimaryCommands!.Add(btn); cb.DefaultLabelPosition = CommandBarDefaultLabelPosition.Collapsed; cb.DefaultLabelPosition = CommandBarDefaultLabelPosition.Bottom; Assert.False(btn.IsCompact); } [Fact] public void DefaultLabelPosition_Right_SetsLabelPositionOnPrimaryButton() { var cb = new CommandBar(); var btn = new CommandBarButton(); cb.PrimaryCommands!.Add(btn); cb.DefaultLabelPosition = CommandBarDefaultLabelPosition.Right; Assert.Equal(CommandBarDefaultLabelPosition.Right, btn.LabelPosition); } [Fact] public void DefaultLabelPosition_Collapsed_SetsLabelPositionOnPrimaryButton() { var cb = new CommandBar(); var btn = new CommandBarButton(); cb.PrimaryCommands!.Add(btn); cb.DefaultLabelPosition = CommandBarDefaultLabelPosition.Collapsed; Assert.Equal(CommandBarDefaultLabelPosition.Collapsed, btn.LabelPosition); } [Fact] public void DefaultLabelPosition_Collapsed_PropagatesIsCompactToToggleButton() { var cb = new CommandBar(); var toggle = new CommandBarToggleButton(); cb.PrimaryCommands!.Add(toggle); cb.DefaultLabelPosition = CommandBarDefaultLabelPosition.Collapsed; Assert.True(toggle.IsCompact); Assert.Equal(CommandBarDefaultLabelPosition.Collapsed, toggle.LabelPosition); } [Fact] public void DefaultLabelPosition_Right_PropagatesLabelPositionToToggleButton() { var cb = new CommandBar(); var toggle = new CommandBarToggleButton(); cb.PrimaryCommands!.Add(toggle); cb.DefaultLabelPosition = CommandBarDefaultLabelPosition.Right; Assert.Equal(CommandBarDefaultLabelPosition.Right, toggle.LabelPosition); } [Fact] public void DefaultLabelPosition_Collapsed_SetsIsCompactOnSeparator() { var cb = new CommandBar(); var sep = new CommandBarSeparator(); cb.PrimaryCommands!.Add(sep); cb.DefaultLabelPosition = CommandBarDefaultLabelPosition.Collapsed; Assert.True(sep.IsCompact); } [Fact] public void NewPrimaryCommand_GetsCurrentLabelPosition_WhenAlreadyCollapsed() { var cb = new CommandBar { DefaultLabelPosition = CommandBarDefaultLabelPosition.Collapsed }; var btn = new CommandBarButton(); cb.PrimaryCommands!.Add(btn); Assert.True(btn.IsCompact); Assert.Equal(CommandBarDefaultLabelPosition.Collapsed, btn.LabelPosition); } [Fact] public void NewPrimaryCommand_GetsCurrentLabelPosition_WhenRight() { var cb = new CommandBar { DefaultLabelPosition = CommandBarDefaultLabelPosition.Right }; var btn = new CommandBarButton(); cb.PrimaryCommands!.Add(btn); Assert.Equal(CommandBarDefaultLabelPosition.Right, btn.LabelPosition); } [Fact] public void DefaultLabelPosition_Collapsed_AppliesToSecondaryCommands() { var cb = new CommandBar(); var btn = new CommandBarButton(); cb.SecondaryCommands!.Add(btn); cb.DefaultLabelPosition = CommandBarDefaultLabelPosition.Collapsed; Assert.True(btn.IsCompact); } [Fact] public void DefaultLabelPosition_DoesNotClearLabelText() { var cb = new CommandBar(); var btn = new CommandBarButton { Label = "Save" }; cb.PrimaryCommands!.Add(btn); cb.DefaultLabelPosition = CommandBarDefaultLabelPosition.Collapsed; Assert.Equal("Save", btn.Label); } } public class CommandBarOverflowButtonTests : ScopedTestBase { [Fact] public void OverflowButtonVisibility_Visible_SetsIsOverflowButtonVisibleTrue() { var cb = new CommandBar { OverflowButtonVisibility = CommandBarOverflowButtonVisibility.Visible }; Assert.True(cb.IsOverflowButtonVisible); } [Fact] public void OverflowButtonVisibility_Collapsed_SetsIsOverflowButtonVisibleFalse() { var cb = new CommandBar { OverflowButtonVisibility = CommandBarOverflowButtonVisibility.Collapsed }; Assert.False(cb.IsOverflowButtonVisible); } [Fact] public void OverflowButtonVisibility_Auto_TrueWhenHasSecondaryCommands() { var cb = new CommandBar(); cb.SecondaryCommands!.Add(new CommandBarButton()); Assert.True(cb.IsOverflowButtonVisible); } [Fact] public void OverflowButtonVisibility_Auto_FalseWhenNoSecondaryCommands() { var cb = new CommandBar(); Assert.False(cb.IsOverflowButtonVisible); } [Fact] public void OverflowButtonVisibility_Visible_RemainsTrueWithoutSecondary() { var cb = new CommandBar { OverflowButtonVisibility = CommandBarOverflowButtonVisibility.Visible }; Assert.True(cb.IsOverflowButtonVisible); } [Fact] public void OverflowButtonVisibility_Collapsed_RemainsFalseEvenWithSecondary() { var cb = new CommandBar { OverflowButtonVisibility = CommandBarOverflowButtonVisibility.Collapsed }; cb.SecondaryCommands!.Add(new CommandBarButton()); Assert.False(cb.IsOverflowButtonVisible); } [Fact] public void OverflowButtonVisibility_Auto_FalseAfterSecondaryRemoved() { var cb = new CommandBar(); var btn = new CommandBarButton(); cb.SecondaryCommands!.Add(btn); Assert.True(cb.IsOverflowButtonVisible); cb.SecondaryCommands!.Remove(btn); Assert.False(cb.IsOverflowButtonVisible); } [Fact] public void OverflowButtonVisibility_SwitchFromAutoToVisible_ShowsButtonImmediately() { var cb = new CommandBar(); Assert.False(cb.IsOverflowButtonVisible); cb.OverflowButtonVisibility = CommandBarOverflowButtonVisibility.Visible; Assert.True(cb.IsOverflowButtonVisible); } } public class CommandBarItemWidthTests : ScopedTestBase { private static CommandBar CreateWithWidth(double width) { var cb = new CommandBar(); cb.Measure(new Size(width, double.PositiveInfinity)); return cb; } [Fact] public void ItemWidthBottom_Controls_HowManyButtonsFit() { var cb = CreateWithWidth(300); var secondary = new CommandBarButton(); cb.SecondaryCommands!.Add(secondary); // forces overflow button for (int i = 0; i < 4; i++) cb.PrimaryCommands!.Add(new CommandBarButton()); cb.IsDynamicOverflowEnabled = true; Assert.Equal(3, cb.VisiblePrimaryCommands.Count); Assert.Equal(3, cb.OverflowItems.Count); Assert.IsType(cb.OverflowItems[0]); Assert.IsType(cb.OverflowItems[1]); Assert.Same(secondary, cb.OverflowItems[2]); } [Fact] public void ItemWidthBottom_Reduced_AllowsMoreItemsToFit() { var cb = CreateWithWidth(300); cb.ItemWidthBottom = 35; cb.SecondaryCommands!.Add(new CommandBarButton()); for (int i = 0; i < 4; i++) cb.PrimaryCommands!.Add(new CommandBarButton()); cb.IsDynamicOverflowEnabled = true; Assert.Equal(4, cb.VisiblePrimaryCommands.Count); } [Fact] public void ItemWidthBottom_Large_ReducesToMinimumOneVisible() { var cb = CreateWithWidth(300); cb.ItemWidthBottom = 260; cb.SecondaryCommands!.Add(new CommandBarButton()); for (int i = 0; i < 3; i++) cb.PrimaryCommands!.Add(new CommandBarButton()); cb.IsDynamicOverflowEnabled = true; Assert.Equal(1, cb.VisiblePrimaryCommands.Count); } [Fact] public void ItemWidthRight_UsedWhenLabelPositionIsRight() { var cb = CreateWithWidth(300); cb.DefaultLabelPosition = CommandBarDefaultLabelPosition.Right; cb.SecondaryCommands!.Add(new CommandBarButton()); for (int i = 0; i < 4; i++) cb.PrimaryCommands!.Add(new CommandBarButton()); cb.IsDynamicOverflowEnabled = true; Assert.Equal(2, cb.VisiblePrimaryCommands.Count); } [Fact] public void ItemWidthRight_Increased_FewerItemsFit() { var cb = CreateWithWidth(300); cb.DefaultLabelPosition = CommandBarDefaultLabelPosition.Right; cb.ItemWidthRight = 252; // exactly 1 fits: 252/252=1 cb.SecondaryCommands!.Add(new CommandBarButton()); for (int i = 0; i < 3; i++) cb.PrimaryCommands!.Add(new CommandBarButton()); cb.IsDynamicOverflowEnabled = true; Assert.Equal(1, cb.VisiblePrimaryCommands.Count); } [Fact] public void ItemWidthCollapsed_UsedWhenLabelPositionIsCollapsed() { var cb = CreateWithWidth(300); cb.DefaultLabelPosition = CommandBarDefaultLabelPosition.Collapsed; cb.SecondaryCommands!.Add(new CommandBarButton()); for (int i = 0; i < 4; i++) cb.PrimaryCommands!.Add(new CommandBarButton()); cb.IsDynamicOverflowEnabled = true; Assert.Equal(4, cb.VisiblePrimaryCommands.Count); } [Fact] public void ItemWidths_AreIndependent_PerLabelPosition() { var cb = CreateWithWidth(300); cb.ItemWidthBottom = 70; cb.ItemWidthRight = 102; cb.ItemWidthCollapsed = 42; cb.SecondaryCommands!.Add(new CommandBarButton()); for (int i = 0; i < 4; i++) cb.PrimaryCommands!.Add(new CommandBarButton()); cb.DefaultLabelPosition = CommandBarDefaultLabelPosition.Bottom; cb.IsDynamicOverflowEnabled = true; int visibleBottom = cb.VisiblePrimaryCommands.Count; // 252/70 = 3 cb.IsDynamicOverflowEnabled = false; cb.DefaultLabelPosition = CommandBarDefaultLabelPosition.Right; cb.IsDynamicOverflowEnabled = true; int visibleRight = cb.VisiblePrimaryCommands.Count; // 252/102 = 2 cb.IsDynamicOverflowEnabled = false; cb.DefaultLabelPosition = CommandBarDefaultLabelPosition.Collapsed; cb.IsDynamicOverflowEnabled = true; int visibleCollapsed = cb.VisiblePrimaryCommands.Count; // 252/42 = 6 → capped at 4 Assert.Equal(3, visibleBottom); Assert.Equal(2, visibleRight); Assert.Equal(4, visibleCollapsed); } } public class CommandBarOverflowKeyboardTests : ScopedTestBase { private readonly IDisposable _app; public CommandBarOverflowKeyboardTests() { _app = UnitTestApplication.Start(TestServices.FocusableWindow); } public override void Dispose() { _app.Dispose(); base.Dispose(); } [Fact] public void Escape_WhenOverflowOpen_ClosesOverflow() { var cb = new CommandBar(); cb.SecondaryCommands.Add(new CommandBarButton { Label = "Action" }); var root = new TestRoot(useGlobalStyles: true, child: cb); root.LayoutManager.ExecuteInitialLayoutPass(); cb.IsOpen = true; RaiseKeyOnOverflowPresenter(cb, Key.Escape); Assert.False(cb.IsOpen); } [Fact] public void Escape_WhenOverflowClosed_DoesNothing() { var cb = new CommandBar(); cb.SecondaryCommands.Add(new CommandBarButton { Label = "Action" }); var root = new TestRoot(useGlobalStyles: true, child: cb); root.LayoutManager.ExecuteInitialLayoutPass(); RaiseKeyOnOverflowPresenter(cb, Key.Escape); Assert.False(cb.IsOpen); } [Theory] [InlineData(Key.Down)] [InlineData(Key.Up)] [InlineData(Key.Home)] [InlineData(Key.End)] public void NavigationKeys_AreHandled_WhenOverflowHasItems(Key key) { var cb = new CommandBar(); cb.SecondaryCommands.Add(new CommandBarButton { Label = "A" }); cb.SecondaryCommands.Add(new CommandBarButton { Label = "B" }); var root = new TestRoot(useGlobalStyles: true, child: cb); root.LayoutManager.ExecuteInitialLayoutPass(); cb.IsOpen = true; var e = new KeyEventArgs { RoutedEvent = InputElement.KeyDownEvent, Key = key }; GetOverflowPresenter(cb).RaiseEvent(e); Assert.True(e.Handled); } [Fact] public void NavigationKeys_AreHandled_WhenAllItemsAreSeparators() { var cb = new CommandBar(); cb.SecondaryCommands.Add(new CommandBarSeparator()); var root = new TestRoot(useGlobalStyles: true, child: cb); root.LayoutManager.ExecuteInitialLayoutPass(); cb.IsOpen = true; var e = new KeyEventArgs { RoutedEvent = InputElement.KeyDownEvent, Key = Key.Down }; GetOverflowPresenter(cb).RaiseEvent(e); Assert.True(e.Handled); } [Fact] public void NavigationKeys_AreHandled_WhenAllItemsAreDisabled() { var cb = new CommandBar(); cb.SecondaryCommands.Add(new CommandBarButton { Label = "A", IsEnabled = false }); var root = new TestRoot(useGlobalStyles: true, child: cb); root.LayoutManager.ExecuteInitialLayoutPass(); cb.IsOpen = true; var e = new KeyEventArgs { RoutedEvent = InputElement.KeyDownEvent, Key = Key.Down }; GetOverflowPresenter(cb).RaiseEvent(e); Assert.True(e.Handled); } [Fact] public void NavigationKeys_AreHandled_WhenAllItemsAreNonFocusable() { var cb = new CommandBar(); cb.SecondaryCommands.Add(new CommandBarButton { Label = "A", Focusable = false }); var root = new TestRoot(useGlobalStyles: true, child: cb); root.LayoutManager.ExecuteInitialLayoutPass(); cb.IsOpen = true; var e = new KeyEventArgs { RoutedEvent = InputElement.KeyDownEvent, Key = Key.Down }; GetOverflowPresenter(cb).RaiseEvent(e); Assert.True(e.Handled); } [Fact] public void KeyboardOpen_FocusesFirstOverflowItem_AsFocusVisible() { var first = new CommandBarButton { Label = "A" }; var cb = new CommandBar(); cb.SecondaryCommands.Add(first); var window = CreateWindow(cb); Assert.True(GetOverflowButton(cb).Focus(NavigationMethod.Tab)); cb.IsOpen = true; Dispatcher.UIThread.RunJobs(DispatcherPriority.Loaded, TestContext.Current.CancellationToken); Assert.True(first.IsFocused); Assert.True(first.Classes.Contains(":focus-visible")); } [Fact] public void PointerOpen_AfterKeyboardFocus_DoesNotMakeFirstOverflowItemFocusVisible() { var first = new CommandBarButton { Label = "A" }; var cb = new CommandBar(); cb.SecondaryCommands.Add(first); var window = CreateWindow(cb); var overflowButton = GetOverflowButton(cb); Assert.True(overflowButton.Focus(NavigationMethod.Tab)); RaisePointerPressed(overflowButton); cb.IsOpen = true; Dispatcher.UIThread.RunJobs(DispatcherPriority.Loaded, TestContext.Current.CancellationToken); Assert.True(first.IsFocused); Assert.False(first.Classes.Contains(":focus-visible")); } [Fact] public void KeyboardOpen_AfterPointerFocus_MakesFirstOverflowItemFocusVisible() { var first = new CommandBarButton { Label = "A" }; var cb = new CommandBar(); cb.SecondaryCommands.Add(first); var window = CreateWindow(cb); var overflowButton = GetOverflowButton(cb); Assert.True(overflowButton.Focus(NavigationMethod.Pointer)); overflowButton.RaiseEvent(new KeyEventArgs { RoutedEvent = InputElement.KeyDownEvent, Key = Key.Space, }); cb.IsOpen = true; Dispatcher.UIThread.RunJobs(DispatcherPriority.Loaded, TestContext.Current.CancellationToken); Assert.True(first.IsFocused); Assert.True(first.Classes.Contains(":focus-visible")); } private static ItemsControl GetOverflowPresenter(CommandBar cb) { var popup = cb.GetVisualDescendants() .OfType() .First(p => p.Name == "PART_OverflowPopup"); return popup.GetLogicalDescendants() .OfType() .First(x => x.Name == "PART_OverflowPresenter"); } private static void RaiseKeyOnOverflowPresenter(CommandBar cb, Key key) { GetOverflowPresenter(cb).RaiseEvent(new KeyEventArgs { RoutedEvent = InputElement.KeyDownEvent, Key = key, }); } private static Button GetOverflowButton(CommandBar cb) { return cb.GetVisualDescendants() .OfType