diff --git a/src/System.Windows.Forms.Design/src/AssemblyRef.cs b/src/System.Windows.Forms.Design/src/AssemblyRef.cs index 926015f15c1..0884fe345a4 100644 --- a/src/System.Windows.Forms.Design/src/AssemblyRef.cs +++ b/src/System.Windows.Forms.Design/src/AssemblyRef.cs @@ -1,5 +1,8 @@ // Licensed to the .NET Foundation under one or more agreements. // The .NET Foundation licenses this file to you under the MIT license. +using System.Runtime.CompilerServices; + +[assembly: InternalsVisibleTo("DynamicProxyGenAssembly2, PublicKey=0024000004800000940000000602000000240000525341310004000001000100c547cac37abd99c8db225ef2f6c8a3602f3b3606cc9891605d02baa56104f4cfc0734aa39b93bf7852f7d9266654753cc297e7d2edfe0bac1cdcf9f717241550e0a7b191195b7667bb4f64bcb8e2121380fd1d9d46ad2d92d2d15605093924cceaf74c4861eff62abf69b9291ed0a340e113be11e6a7d3113e92484cf7045cc7")] internal static class FXAssembly { diff --git a/src/System.Windows.Forms.Design/tests/UnitTests/ControlDesignerTests.cs b/src/System.Windows.Forms.Design/tests/UnitTests/ControlDesignerTests.cs index 8360bfb0d7c..d20c5373ec7 100644 --- a/src/System.Windows.Forms.Design/tests/UnitTests/ControlDesignerTests.cs +++ b/src/System.Windows.Forms.Design/tests/UnitTests/ControlDesignerTests.cs @@ -1,15 +1,34 @@ // Licensed to the .NET Foundation under one or more agreements. // The .NET Foundation licenses this file to you under the MIT license. +#nullable enable + +using System.ComponentModel; using System.ComponentModel.Design; +using System.Reflection; +using System.Windows.Forms.Design.Behavior; using System.Windows.Forms.Design.Tests.Mocks; using Moq; using Windows.Win32; namespace System.Windows.Forms.Design.Tests; -public class ControlDesignerTests +public class ControlDesignerTests : IDisposable { + private readonly ControlDesigner _designer = new(); + private readonly Control _control = new(); + + public ControlDesignerTests() + { + _designer.Initialize(_control); + } + + public void Dispose() + { + _designer.Dispose(); + _control.Dispose(); + } + [WinFormsFact] public void ControlDesigner_Ctor_Default() { @@ -226,53 +245,335 @@ public void ControlDesigner_WndProc_InvokePaint_Success() using ControlDesigner designer = new(); using Button button = new(); designer.Initialize(button); - Message m = new Message - { - Msg = (int)PInvokeCore.WM_PAINT - }; + Message m = new Message { Msg = (int)PInvokeCore.WM_PAINT }; designer.TestAccessor().Dynamic.WndProc(ref m); } [Fact] public void ControlDesigner_AssociatedComponents_NullSite_Test() { - using ControlDesigner controlDesigner = new(); - using Control control = new(); - using Control childControl = new(); - controlDesigner.Initialize(control); - Assert.Empty(controlDesigner.AssociatedComponents); + Assert.Empty(_designer.AssociatedComponents); - control.Controls.Add(childControl); + _control.Controls.Add(childControl); - Assert.Empty(controlDesigner.AssociatedComponents); + Assert.Empty(_designer.AssociatedComponents); } [WinFormsFact] public void ControlDesigner_AssociatedComponentsTest() { - using Control control = new(); - using ControlDesigner controlDesigner = new(); - Mock mockDesignerHost = new(MockBehavior.Strict); mockDesignerHost .Setup(h => h.RootComponent) - .Returns(control); + .Returns(_control); mockDesignerHost .Setup(s => s.GetDesigner(It.IsAny())) .Returns(() => null); var mockSite = MockSite.CreateMockSiteWithDesignerHost(mockDesignerHost.Object); - control.Site = mockSite.Object; + _control.Site = mockSite.Object; - controlDesigner.Initialize(control); - - Assert.Empty(controlDesigner.AssociatedComponents); + Assert.Empty(_designer.AssociatedComponents); using Control childControl = new(); childControl.Site = mockSite.Object; - control.Controls.Add(childControl); + _control.Controls.Add(childControl); + + Assert.Equal(1, _designer.AssociatedComponents.Count); + } + + [Fact] + public void GetGlyphs_Locked_ReturnsLockedGlyphs() + { + Mock mockServiceProvider = new(); + Mock mockSite = new(); + mockServiceProvider.Setup(s => s.GetService(It.IsAny())).Returns(null); + mockSite.Setup(s => s.GetService(typeof(IServiceProvider))).Returns(mockServiceProvider.Object); + + Mock mockDesignerFrame = new(mockSite.Object) { CallBase = true }; + BehaviorService behaviorService = new(mockServiceProvider.Object, mockDesignerFrame.Object); + + FieldInfo? behaviorServiceField = typeof(ControlDesigner).GetField("_behaviorService", BindingFlags.NonPublic | BindingFlags.Instance); + behaviorServiceField?.SetValue(_designer, behaviorService); + _designer.TestAccessor().Dynamic.Locked = true; + _designer.TestAccessor().Dynamic._host = new Mock().Object; + + GlyphCollection glyphs = _designer.GetGlyphs(GlyphSelectionType.SelectedPrimary); + + glyphs.Count.Should().BeGreaterThan(0); + glyphs.Should().BeOfType(); + glyphs[0].Should().BeOfType(); + } + + [Fact] + public void GetGlyphs_GlyphSelectionTypeNotSelected_ReturnsEmptyCollection() + { + GlyphCollection glyphs = _designer.GetGlyphs(GlyphSelectionType.NotSelected); + + glyphs.Count.Should().Be(0); + } + + [Fact] + public void GetGlyphs_WithNullBehaviorService_ThrowsException() + { + _designer.TestAccessor().Dynamic._behaviorService = null; + + Action action = () => _designer.GetGlyphs(GlyphSelectionType.SelectedPrimary); + action.Should().Throw(); + } + + [Fact] + public void GetGlyphs_NonSizeableControl_ReturnsNoResizeHandleGlyphs() + { + using Control control = new(); + control.Dock = DockStyle.Fill; + control.AutoSize = false; + using ControlDesigner designer = new(); + Mock mockDesignerHost = new(); + mockDesignerHost + .Setup(h => h.RootComponent) + .Returns(control); + mockDesignerHost + .Setup(s => s.GetDesigner(It.IsAny())) + .Returns(designer); + Mock mockComponentChangeService = new(); + mockDesignerHost + .Setup(s => s.GetService(typeof(IComponentChangeService))) + .Returns(mockComponentChangeService.Object); + + Mock mockSite = CreateMockSiteWithDesignerHost(mockDesignerHost.Object); + control.Site = mockSite.Object; + + using Component component = new() + { + Site = mockSite.Object + }; + + designer.Initialize(control); + + Mock mockDesignerFrame = new(mockSite.Object) { CallBase = true }; + + Mock mockServiceProvider = new(); + mockServiceProvider.Setup(s => s.GetService(It.IsAny())).Returns(mockServiceProvider); + mockSite.Setup(s => s.GetService(typeof(IServiceProvider))).Returns(mockServiceProvider.Object); + BehaviorService behaviorService = new(mockServiceProvider.Object, mockDesignerFrame.Object); + + FieldInfo? behaviorServiceField = typeof(ControlDesigner).GetField("_behaviorService", BindingFlags.NonPublic | BindingFlags.Instance); + behaviorServiceField?.SetValue(designer, behaviorService); + mockSite.Setup(s => s.GetService(typeof(BehaviorService))).Returns(behaviorService); + + GlyphCollection glyphs = designer.GetGlyphs(GlyphSelectionType.SelectedPrimary); + + glyphs[0].Should().BeOfType(); + ((SelectionRules)glyphs[0].TestAccessor().Dynamic.rules).Should().Be(SelectionRules.None); + glyphs[1].Should().BeOfType(); + ((SelectionRules)glyphs[1].TestAccessor().Dynamic.rules).Should().Be(SelectionRules.None); + glyphs[2].Should().BeOfType(); + ((SelectionRules)glyphs[2].TestAccessor().Dynamic.rules).Should().Be(SelectionRules.None); + glyphs[3].Should().BeOfType(); + ((SelectionRules)glyphs[3].TestAccessor().Dynamic.rules).Should().Be(SelectionRules.None); + glyphs[4].Should().BeOfType(); + ((SelectionRules)glyphs[4].TestAccessor().Dynamic.rules).Should().Be(SelectionRules.None); + } + + [Fact] + public void GetGlyphs_ResizableGlyphs_ReturnsExpected() + { + _control.Dock = DockStyle.None; + _control.AutoSize = false; + + Mock mockServiceProvider = new(); + Mock mockSite = new(); + mockServiceProvider.Setup(s => s.GetService(It.IsAny())).Returns(null); + mockSite.Setup(s => s.GetService(typeof(IServiceProvider))).Returns(mockServiceProvider.Object); + + Mock mockDesignerFrame = new(mockSite.Object) { CallBase = true }; + BehaviorService behaviorService = new(mockServiceProvider.Object, mockDesignerFrame.Object); + + FieldInfo? behaviorServiceField = typeof(ControlDesigner).GetField("_behaviorService", BindingFlags.NonPublic | BindingFlags.Instance); + behaviorServiceField?.SetValue(_designer, behaviorService); + _designer.TestAccessor().Dynamic._host = new Mock().Object; + + GlyphCollection glyphs = _designer.GetGlyphs(GlyphSelectionType.SelectedPrimary); + + glyphs[0].Should().BeOfType(); + ((SelectionRules)glyphs[0].TestAccessor().Dynamic.rules).Should().Be(SelectionRules.None); + glyphs[1].Should().BeOfType(); + ((SelectionRules)glyphs[1].TestAccessor().Dynamic.rules).Should().Be(SelectionRules.TopSizeable | SelectionRules.LeftSizeable); + glyphs[2].Should().BeOfType(); + ((SelectionRules)glyphs[2].TestAccessor().Dynamic.rules).Should().Be(SelectionRules.TopSizeable | SelectionRules.RightSizeable); + glyphs[3].Should().BeOfType(); + ((SelectionRules)glyphs[3].TestAccessor().Dynamic.rules).Should().Be(SelectionRules.None); + glyphs[4].Should().BeOfType(); + ((SelectionRules)glyphs[4].TestAccessor().Dynamic.rules).Should().Be(SelectionRules.BottomSizeable | SelectionRules.LeftSizeable); + glyphs[5].Should().BeOfType(); + ((SelectionRules)glyphs[5].TestAccessor().Dynamic.rules).Should().Be(SelectionRules.BottomSizeable | SelectionRules.RightSizeable); + glyphs[6].Should().BeOfType(); + ((SelectionRules)glyphs[6].TestAccessor().Dynamic.rules).Should().Be(SelectionRules.None); + glyphs[7].Should().BeOfType(); + ((SelectionRules)glyphs[7].TestAccessor().Dynamic.rules).Should().Be(SelectionRules.None); + glyphs[8].Should().BeOfType(); + ((SelectionRules)glyphs[8].TestAccessor().Dynamic.rules).Should().Be(SelectionRules.TopSizeable); + glyphs[9].Should().BeOfType(); + ((SelectionRules)glyphs[9].TestAccessor().Dynamic.rules).Should().Be(SelectionRules.BottomSizeable); + glyphs[10].Should().BeOfType(); + ((SelectionRules)glyphs[10].TestAccessor().Dynamic.rules).Should().Be(SelectionRules.LeftSizeable); + glyphs[11].Should().BeOfType(); + ((SelectionRules)glyphs[11].TestAccessor().Dynamic.rules).Should().Be(SelectionRules.RightSizeable); + } + + [Theory] + [InlineData(DockingBehavior.Never, DockStyle.None)] + [InlineData(DockingBehavior.AutoDock, DockStyle.Fill)] + public void InitializeNewComponent_DockingBehavior_DefinesDockStyle(DockingBehavior dockingBehavior, DockStyle dockStyle) + { + using Control control = new(); + using ControlDesigner designer = new(); + + Mock mockDesignerHost = new(); + mockDesignerHost + .Setup(h => h.RootComponent) + .Returns(control); + mockDesignerHost + .Setup(s => s.GetDesigner(It.IsAny())) + .Returns(designer); + Mock mockComponentChangeService = new(); + mockDesignerHost + .Setup(s => s.GetService(typeof(IComponentChangeService))) + .Returns(mockComponentChangeService.Object); + + TypeDescriptor.AddAttributes(control, new DockingAttribute(dockingBehavior)); + + using Component component = new() + { + Site = MockSite.CreateMockSiteWithDesignerHost(mockDesignerHost.Object).Object + }; + control.Site = component.Site; + + designer.Initialize(control); + + Mock mockParentDesigner = new(); + mockDesignerHost.Setup(h => h.GetDesigner(It.IsAny())).Returns(mockParentDesigner.Object); + + Dictionary defaultValues = new() + { + { "Parent", new Control() } + }; + + designer.InitializeNewComponent(defaultValues); - Assert.Equal(1, controlDesigner.AssociatedComponents.Count); + PropertyDescriptor? dockPropDescriptor = TypeDescriptor.GetProperties(control)["Dock"]; + dockPropDescriptor.Should().NotBeNull(); + dockPropDescriptor.Should().BeAssignableTo(); + dockPropDescriptor?.GetValue(control).Should().Be(dockStyle); + } + + [Fact] + public void InitializeExistingComponent_DockingBehavior_DefinesDockStyle() + { + using Control control = new(); + using ControlDesigner designer = new(); + Mock mockDesignerHost = new(); + mockDesignerHost + .Setup(h => h.RootComponent) + .Returns(control); + mockDesignerHost + .Setup(s => s.GetDesigner(It.IsAny())) + .Returns(designer); + Mock mockComponentChangeService = new(); + mockDesignerHost + .Setup(s => s.GetService(typeof(IComponentChangeService))) + .Returns(mockComponentChangeService.Object); + + TypeDescriptor.AddAttributes(control, new DockingAttribute(DockingBehavior.AutoDock)); + + using Component component = new() + { + Site = MockSite.CreateMockSiteWithDesignerHost(mockDesignerHost.Object).Object + }; + control.Site = component.Site; + designer.Initialize(control); + Mock mockParentDesigner = new(); + mockDesignerHost.Setup(h => h.GetDesigner(It.IsAny())).Returns(mockParentDesigner.Object); + Dictionary defaultValues = new() + { + { "Parent", new Control() } + }; + Action action = () => designer.InitializeExistingComponent(defaultValues); + action.Should().Throw(SR.NotImplementedByDesign); + } + + public static Mock CreateMockSiteWithDesignerHost(object designerHost) + { + Mock mockSite = new(); + mockSite + .Setup(s => s.GetService(typeof(IDesignerHost))) + .Returns(designerHost); + mockSite + .Setup(s => s.GetService(typeof(IInheritanceService))) + .Returns(null); + mockSite + .Setup(s => s.GetService(typeof(IDictionaryService))) + .Returns(null); + mockSite + .Setup(s => s.GetService(typeof(IExtenderListService))) + .Returns(null); + mockSite + .Setup(s => s.GetService(typeof(ITypeDescriptorFilterService))) + .Returns(null); + mockSite + .Setup(s => s.GetService(typeof(AmbientProperties))) + .Returns(null); + mockSite + .Setup(s => s.GetService(typeof(DesignerActionService))) + .Returns(null); + mockSite + .Setup(s => s.GetService(typeof(IComponentChangeService))) + .Returns(null); + mockSite + .Setup(s => s.GetService(typeof(ToolStripKeyboardHandlingService))) + .Returns(null); + mockSite + .Setup(s => s.GetService(typeof(ISupportInSituService))) + .Returns(null); + mockSite + .Setup(s => s.GetService(typeof(INestedContainer))) + .Returns(null); + mockSite + .Setup(s => s.GetService(typeof(ToolStripMenuItem))) + .Returns(null); + + Mock mockServiceProvider = new(); + + mockSite + .Setup(s => s.GetService(typeof(IServiceProvider))) + .Returns(mockServiceProvider.Object); + mockSite + .Setup(s => s.GetService(typeof(ToolStripAdornerWindowService))) + .Returns(null); + mockSite + .Setup(s => s.GetService(typeof(DesignerOptionService))) + .Returns(mockServiceProvider.Object); + + Mock mockSelectionService = new(); + + mockSite + .Setup(s => s.GetService(typeof(ISelectionService))) + .Returns(mockSelectionService.Object); + mockSite + .Setup(s => s.Container) + .Returns((IContainer)null); + mockSite + .Setup(s => s.Name) + .Returns("Site"); + mockSite + .Setup(s => s.DesignMode) + .Returns(true); + mockSite + .Setup(s => s.GetService(typeof(UndoEngine))) + .Returns(null); + + return mockSite; } }