diff --git a/src/test/unit/System.Windows.Forms/System/Windows/Forms/CheckBoxBaseAdapterTests.cs b/src/test/unit/System.Windows.Forms/System/Windows/Forms/CheckBoxBaseAdapterTests.cs new file mode 100644 index 00000000000..94cb5ee8710 --- /dev/null +++ b/src/test/unit/System.Windows.Forms/System/Windows/Forms/CheckBoxBaseAdapterTests.cs @@ -0,0 +1,301 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. + +using System.Drawing; +using System.Windows.Forms.ButtonInternal; + +namespace System.Windows.Forms.Tests; + +public class CheckBoxBaseAdapterTests : IDisposable +{ + private TestCheckBox? _checkBox; + + private (TestCheckBoxBaseAdapter, TestCheckBox) CreateAdapter(CheckState checkState) + { + _checkBox = new TestCheckBox + { + CheckState = checkState + }; + + TestCheckBoxBaseAdapter adapter = new(_checkBox); + + return (adapter, _checkBox); + } + + public void Dispose() => _checkBox?.Dispose(); + + private class TestCheckBox : CheckBox + { + public new bool Enabled + { + get => base.Enabled; + set => base.Enabled = value; + } + + public new CheckState CheckState + { + get => base.CheckState; + set => base.CheckState = value; + } + } + + private class TestCheckBoxBaseAdapter : CheckBoxBaseAdapter + { + public TestCheckBoxBaseAdapter(ButtonBase control) : base(control) { } + + public void CallDrawCheckFlat( + PaintEventArgs e, + LayoutData layout, + Color checkColor, + Color checkBackground, + Color checkBorder, + ColorData colors) + => DrawCheckFlat(e, layout, checkColor, checkBackground, checkBorder, colors); + + protected override LayoutOptions Layout(PaintEventArgs e) + => new LayoutOptions(); + + protected override ButtonBaseAdapter CreateButtonAdapter() + => new StubButtonBaseAdapter(Control); + + private class StubButtonBaseAdapter : ButtonBaseAdapter + { + public StubButtonBaseAdapter(ButtonBase control) : base(control) { } + internal override void PaintUp(PaintEventArgs e, CheckState state) { } + internal override void PaintDown(PaintEventArgs e, CheckState state) { } + internal override void PaintOver(PaintEventArgs e, CheckState state) { } + protected override LayoutOptions Layout(PaintEventArgs e) => new LayoutOptions(); + } + + internal override void PaintOver(PaintEventArgs e, CheckState state) + { + } + + internal override void PaintDown(PaintEventArgs e, CheckState state) + { + } + + internal override void PaintUp(PaintEventArgs e, CheckState state) + { + } + } + + private static ButtonBaseAdapter.LayoutData CreateLayoutData(bool dotNetOneButtonCompat = false) + { + ButtonBaseAdapter.LayoutData layout = new( + new ButtonBaseAdapter.LayoutOptions + { + DotNetOneButtonCompat = dotNetOneButtonCompat + }) + { + CheckBounds = new Rectangle(2, 2, 11, 11) + }; + + return layout; + } + + private static ButtonBaseAdapter.ColorData CreateColorData(Graphics graphics) + { + ButtonBaseAdapter.ColorOptions options = new( + graphics, + Color.Black, + Color.White + ); + + ButtonBaseAdapter.ColorData colorData = new(options) + { + ButtonFace = Color.LightGray, + ButtonShadow = Color.Gray, + Highlight = Color.Yellow + }; + + return colorData; + } + + [WinFormsTheory] + [InlineData(CheckState.Unchecked, false)] + [InlineData(CheckState.Checked, false)] + [InlineData(CheckState.Indeterminate, false)] + [InlineData(CheckState.Unchecked, true)] + [InlineData(CheckState.Checked, true)] + [InlineData(CheckState.Indeterminate, true)] + public void DrawCheckFlat_DoesNotThrow(CheckState checkState, bool dotNetOneButtonCompat) + { + (TestCheckBoxBaseAdapter adapter, TestCheckBox checkBox) = CreateAdapter(checkState); + using Bitmap bitmap = new(20, 20); + using Graphics graphics = Graphics.FromImage(bitmap); + using PaintEventArgs e = new(graphics, new Rectangle(0, 0, 20, 20)); + ButtonBaseAdapter.LayoutData layout = CreateLayoutData(dotNetOneButtonCompat); + Color checkColor = Color.Black; + Color checkBackground = Color.White; + Color checkBorder = Color.Blue; + ButtonBaseAdapter.ColorData colors = CreateColorData(graphics); + + Exception? ex = Record.Exception(() => + adapter.CallDrawCheckFlat(e, layout, checkColor, checkBackground, checkBorder, colors)); + + ex.Should().BeNull(); + } + + [WinFormsTheory] + [InlineData(false, CheckState.Unchecked, false, 0)] + [InlineData(false, CheckState.Unchecked, true, 1)] + [InlineData(true, CheckState.Indeterminate, true, 2)] + public void DrawCheckBackground_CoversAllBranches( + bool controlEnabled, + CheckState checkState, + bool disabledColors, + int expectedBranch) + { + Rectangle bounds = new(1, 2, 3, 4); + using Bitmap bitmap = new(10, 10); + using Graphics graphics = Graphics.FromImage(bitmap); + Color checkBackground = expectedBranch == 2 ? SystemColors.Window : Color.Red; + + Exception? ex = Record.Exception(() => + CheckBoxBaseAdapter.DrawCheckBackground( + controlEnabled, + checkState, + graphics, + bounds, + checkBackground, + disabledColors)); + + ex.Should().BeNull(); + } + + [WinFormsTheory] + [InlineData(CheckState.Checked, true, true)] + [InlineData(CheckState.Checked, false, true)] + [InlineData(CheckState.Indeterminate, true, true)] + [InlineData(CheckState.Indeterminate, false, true)] + [InlineData(CheckState.Unchecked, true, false)] + public void DrawCheckOnly_Protected_DoesNotThrow( + CheckState checkState, + bool enabled, + bool isChecked) + { + (TestCheckBoxBaseAdapter adapter, TestCheckBox checkBox) = CreateAdapter(checkState); + checkBox.Enabled = enabled; + checkBox.Checked = isChecked; + + using Bitmap bitmap = new(20, 20); + using Graphics graphics = Graphics.FromImage(bitmap); + using PaintEventArgs e = new(graphics, new Rectangle(0, 0, 20, 20)); + ButtonBaseAdapter.LayoutData layout = CreateLayoutData(); + ButtonBaseAdapter.ColorData colors = CreateColorData(graphics); + Color checkColor = Color.Black; + + Exception? ex = Record.Exception(() => + adapter.TestAccessor().Dynamic.DrawCheckOnly( + e, + layout, + colors, + checkColor)); + + ex.Should().BeNull(); + } + + [WinFormsFact] + public void DrawPopupBorder_DoesNotThrow_AndInflatesRectangle() + { + using Bitmap bitmap = new(20, 20); + using Graphics graphics = Graphics.FromImage(bitmap); + Rectangle original = new(2, 2, 10, 10); + + ButtonBaseAdapter.ColorData colors = CreateColorData(graphics); + + Rectangle result = CheckBoxBaseAdapter.DrawPopupBorder(graphics, original, colors); + + Rectangle expected = original; + expected.Inflate(-1, -1); + + result.Should().Be(expected); + } + + [WinFormsFact] + public void DrawPopupBorder_PaintEventArgs_DoesNotThrow_AndInflatesRectangle() + { + using Bitmap bitmap = new(20, 20); + using Graphics graphics = Graphics.FromImage(bitmap); + Rectangle original = new(3, 3, 8, 8); + + ButtonBaseAdapter.ColorData colors = CreateColorData(graphics); + + using PaintEventArgs e = new(graphics, new Rectangle(0, 0, 20, 20)); + Rectangle result = CheckBoxBaseAdapter.DrawPopupBorder(e, original, colors); + + Rectangle expected = original; + expected.Inflate(-1, -1); + + result.Should().Be(expected); + } + + [WinFormsFact] + public void DrawPopupBorder_HDC_DoesNotThrow_AndInflatesRectangle() + { + using Bitmap bitmap = new(20, 20); + using Graphics graphics = Graphics.FromImage(bitmap); + Rectangle original = new(4, 4, 6, 6); + + ButtonBaseAdapter.ColorData colors = CreateColorData(graphics); + + IntPtr hdcPtr = graphics.GetHdc(); + try + { + Rectangle result = CheckBoxBaseAdapter.DrawPopupBorder( + new HDC(hdcPtr), + original, + colors); + + Rectangle expected = original; + expected.Inflate(-1, -1); + + result.Should().Be(expected); + } + finally + { + graphics.ReleaseHdc(hdcPtr); + } + } + + [Theory] + [InlineData(null, true, 2, 2, 10, 10)] + [InlineData("", true, 2, 2, 10, 10)] + [InlineData(null, false, 2, 2, 10, 10)] + [InlineData("", false, 2, 2, 10, 10)] + public void AdjustFocusRectangle_SetsFocusAsExpected( + string? text, + bool autoSize, + int checkX, int checkY, int checkW, int checkH) + { + (TestCheckBoxBaseAdapter adapter, TestCheckBox checkBox) = CreateAdapter(CheckState.Unchecked); + checkBox.Text = text; + checkBox.AutoSize = autoSize; + + ButtonBaseAdapter.LayoutData layout = new(new ButtonBaseAdapter.LayoutOptions()) + { + CheckBounds = new Rectangle(checkX, checkY, checkW, checkH), + Field = new Rectangle(5, 5, 20, 20) + }; + + adapter.TestAccessor().Dynamic.AdjustFocusRectangle(layout); + + if (string.IsNullOrEmpty(text)) + { + if (autoSize) + { + Rectangle expected = Rectangle.Inflate(layout.CheckBounds, -2, -2); + layout.Focus.Should().Be(expected); + } + else + { + layout.Focus.Should().Be(new Rectangle(5, 5, 20, 20)); + } + } + else + { + layout.Focus.Should().Be(default); + } + } +}