From 840e198e856a97d3558ec1bc80fff4444bd7f010 Mon Sep 17 00:00:00 2001 From: Tig Date: Mon, 22 Jul 2024 12:25:49 -0600 Subject: [PATCH] Beefed up unit tests --- Terminal.Gui/View/Orientation/IOrientation.cs | 98 +------------------ .../View/Orientation/OrientationHelper.cs | 87 ++++++++-------- Terminal.Gui/Views/RadioGroup.cs | 51 +++------- .../View/Orientation/OrientationTests.cs | 46 +++++++++ 4 files changed, 110 insertions(+), 172 deletions(-) diff --git a/Terminal.Gui/View/Orientation/IOrientation.cs b/Terminal.Gui/View/Orientation/IOrientation.cs index 25bdf7fcc..52bf2f49f 100644 --- a/Terminal.Gui/View/Orientation/IOrientation.cs +++ b/Terminal.Gui/View/Orientation/IOrientation.cs @@ -37,100 +37,4 @@ public interface IOrientation /// /// public void OnOrientationChanged (Orientation oldOrientation, Orientation newOrientation) { return; } -} - - -/// -/// Helper class for implementing . -/// -public class OrientationHelper -{ - private Orientation _orientation = Orientation.Vertical; - private readonly IOrientation _owner; - - /// - /// Initializes a new instance of the class. - /// - /// - public OrientationHelper (IOrientation owner) - { - _owner = owner; - } - - /// - /// Gets or sets the orientation of the View. - /// - public Orientation Orientation - { - get => _orientation; - set - { - if (_orientation == value) - { - return; - } - - var args = new CancelEventArgs (in _orientation, ref value); - OrientationChanging?.Invoke (_owner, args); - if (args.Cancel) - { - return; - } - - if (_owner?.OnOrientationChanging (value, _orientation) ?? false) - { - return; - } - - Orientation old = _orientation; - if (_orientation != value) - { - _orientation = value; - - if (_owner is { }) - { - _owner.Orientation = value; - } - } - - args = new CancelEventArgs (in old, ref _orientation); - OrientationChanged?.Invoke (_owner, args); - - _owner?.OnOrientationChanged (old, _orientation); - } - } - - /// - /// - /// - public event EventHandler> OrientationChanging; - - /// - /// - /// - /// - /// - /// - protected bool OnOrientationChanging (Orientation currentOrientation, Orientation newOrientation) - { - return _owner?.OnOrientationChanging (currentOrientation, newOrientation) ?? false; - } - - /// - /// - /// - public event EventHandler> OrientationChanged; - - /// - /// - /// - /// - /// - /// - protected void OnOrientationChanged (Orientation oldOrientation, Orientation newOrientation) - { - _owner?.OnOrientationChanged (oldOrientation, newOrientation); - } -} - - +} \ No newline at end of file diff --git a/Terminal.Gui/View/Orientation/OrientationHelper.cs b/Terminal.Gui/View/Orientation/OrientationHelper.cs index f2278ed98..613557e10 100644 --- a/Terminal.Gui/View/Orientation/OrientationHelper.cs +++ b/Terminal.Gui/View/Orientation/OrientationHelper.cs @@ -3,6 +3,14 @@ /// /// Helper class for implementing . /// +/// +/// +/// Implements the standard pattern for changing/changed events. +/// +/// +/// Views that implement should add a OrientationHelper property. See as an example. +/// +/// public class OrientationHelper { private Orientation _orientation = Orientation.Vertical; @@ -11,11 +19,8 @@ public class OrientationHelper /// /// Initializes a new instance of the class. /// - /// - public OrientationHelper (IOrientation owner) - { - _owner = owner; - } + /// Specifies the object that owns this helper instance. + public OrientationHelper (IOrientation owner) { _owner = owner; } /// /// Gets or sets the orientation of the View. @@ -30,19 +35,25 @@ public class OrientationHelper return; } - var args = new CancelEventArgs (in _orientation, ref value); - OrientationChanging?.Invoke (_owner, args); - if (args.Cancel) - { - return; - } - + // Best practice is to invoke the virtual method first. + // This allows derived classes to handle the event and potentially cancel it. if (_owner?.OnOrientationChanging (value, _orientation) ?? false) { return; } + // If the event is not canceled by the virtual method, raise the event to notify any external subscribers. + CancelEventArgs args = new (in _orientation, ref value); + OrientationChanging?.Invoke (_owner, args); + + if (args.Cancel) + { + return; + } + + // If the event is not canceled, update the value. Orientation old = _orientation; + if (_orientation != value) { _orientation = value; @@ -53,42 +64,40 @@ public class OrientationHelper } } - args = new CancelEventArgs (in old, ref _orientation); - OrientationChanged?.Invoke (_owner, args); - + // Best practice is to invoke the virtual method first. _owner?.OnOrientationChanged (old, _orientation); + + // Even though Changed is not cancelable, it is still a good practice to raise the event after. + args = new (in old, ref _orientation); + OrientationChanged?.Invoke (_owner, args); } } /// - /// + /// Raised when the orientation is changing. This is cancelable. /// + /// + /// + /// Views that implement should raise after the orientation has changed + /// (_orientationHelper.OrientationChanging += (sender, e) => OrientationChanging?.Invoke (this, e);). + /// + /// + /// This event will be raised after the method is called (assuming it was not canceled). + /// + /// public event EventHandler> OrientationChanging; /// - /// - /// - /// - /// - /// - protected bool OnOrientationChanging (Orientation currentOrientation, Orientation newOrientation) - { - return _owner?.OnOrientationChanging (currentOrientation, newOrientation) ?? false; - } - - /// - /// + /// Raised when the orientation has changed. /// + /// + /// + /// Views that implement should raise after the orientation has changed + /// (_orientationHelper.OrientationChanged += (sender, e) => OrientationChanged?.Invoke (this, e);). + /// + /// + /// This event will be raised after the method is called. + /// + /// public event EventHandler> OrientationChanged; - - /// - /// - /// - /// - /// - /// - protected void OnOrientationChanged (Orientation oldOrientation, Orientation newOrientation) - { - _owner?.OnOrientationChanged (oldOrientation, newOrientation); - } } diff --git a/Terminal.Gui/Views/RadioGroup.cs b/Terminal.Gui/Views/RadioGroup.cs index 49e821772..1113cf9de 100644 --- a/Terminal.Gui/Views/RadioGroup.cs +++ b/Terminal.Gui/Views/RadioGroup.cs @@ -44,6 +44,7 @@ public class RadioGroup : View, IDesignable, IOrientation { return false; } + MoveDownRight (); return true; @@ -58,6 +59,7 @@ public class RadioGroup : View, IDesignable, IOrientation { return false; } + MoveHome (); return true; @@ -72,6 +74,7 @@ public class RadioGroup : View, IDesignable, IOrientation { return false; } + MoveEnd (); return true; @@ -93,6 +96,7 @@ public class RadioGroup : View, IDesignable, IOrientation ctx => { SetFocus (); + if (ctx.KeyBinding?.Context is { } && (int)ctx.KeyBinding?.Context! < _radioLabels.Count) { SelectedItem = (int)ctx.KeyBinding?.Context!; @@ -103,13 +107,10 @@ public class RadioGroup : View, IDesignable, IOrientation return true; }); - _orientationHelper = new OrientationHelper (this); + _orientationHelper = new (this); _orientationHelper.OrientationChanging += (sender, e) => OrientationChanging?.Invoke (this, e); _orientationHelper.OrientationChanged += (sender, e) => OrientationChanged?.Invoke (this, e); - //OrientationChanging += (sender, e) => OnOrientationChanging (e.CurrentValue, e.NewValue); - //OrientationChanged += (sender, e) => OnOrientationChanged (e.CurrentValue, e.NewValue); - SetupKeyBindings (); LayoutStarted += RadioGroup_LayoutStarted; @@ -331,16 +332,14 @@ public class RadioGroup : View, IDesignable, IOrientation } #region IOrientation - /// + + /// public event EventHandler> OrientationChanging; - /// - public bool OnOrientationChanging (Orientation currentOrientation, Orientation newOrientation) - { - return false; - } + /// + public bool OnOrientationChanging (Orientation currentOrientation, Orientation newOrientation) { return false; } - /// + /// public event EventHandler> OrientationChanged; /// Called when has changed. @@ -351,6 +350,7 @@ public class RadioGroup : View, IDesignable, IOrientation SetupKeyBindings (); SetContentSize (); } + #endregion IOrientation // TODO: This should be cancelable @@ -363,6 +363,7 @@ public class RadioGroup : View, IDesignable, IOrientation { return; } + _selected = selectedItem; SelectedItemChanged?.Invoke (this, new (selectedItem, previousSelectedItem)); } @@ -384,6 +385,7 @@ public class RadioGroup : View, IDesignable, IOrientation { x = _horizontal [_cursor].pos; } + break; default: @@ -470,34 +472,11 @@ public class RadioGroup : View, IDesignable, IOrientation } } - /// + /// public bool EnableForDesign () { RadioLabels = new [] { "Option _1", "Option _2", "Option _3" }; + return true; } } - -public class RadioGroupHorizontal : RadioGroup, IOrientation -{ - private bool _preventOrientationChange = false; - public RadioGroupHorizontal () : base () - { - Orientation = Orientation.Horizontal; - _preventOrientationChange = true; - - OrientationChanging += RadioGroupHorizontal_OrientationChanging; - } - - private void RadioGroupHorizontal_OrientationChanging (object sender, CancelEventArgs e) - { - //e.Cancel = _preventOrientationChange; - } - - /// - bool IOrientation.OnOrientationChanging (Orientation currrentOrientation, Orientation newOrientation) - { - return _preventOrientationChange; - } - -} \ No newline at end of file diff --git a/UnitTests/View/Orientation/OrientationTests.cs b/UnitTests/View/Orientation/OrientationTests.cs index 3e5734be0..01eeda71f 100644 --- a/UnitTests/View/Orientation/OrientationTests.cs +++ b/UnitTests/View/Orientation/OrientationTests.cs @@ -25,14 +25,19 @@ public class OrientationTests public bool CancelOnOrientationChanging { get; set; } + public bool OnOrientationChangingCalled { get; private set; } + public bool OnOrientationChangedCalled { get; private set; } + public bool OnOrientationChanging (Orientation currentOrientation, Orientation newOrientation) { + OnOrientationChangingCalled = true; // Custom logic before orientation changes return CancelOnOrientationChanging; // Return true to cancel the change } public void OnOrientationChanged (Orientation oldOrientation, Orientation newOrientation) { + OnOrientationChangedCalled = true; // Custom logic after orientation has changed } } @@ -87,4 +92,45 @@ public class OrientationTests Assert.False (orientationChanged, "OrientationChanged event was invoked despite cancellation."); Assert.Equal (Orientation.Vertical, customView.Orientation); // Assuming Vertical is the default orientation } + + + [Fact] + public void OrientationChanging_VirtualMethodCalledBeforeEvent () + { + // Arrange + var radioGroup = new CustomView (); + bool eventCalled = false; + + radioGroup.OrientationChanging += (sender, e) => + { + eventCalled = true; + Assert.True (radioGroup.OnOrientationChangingCalled, "OnOrientationChanging was not called before the event."); + }; + + // Act + radioGroup.Orientation = Orientation.Horizontal; + + // Assert + Assert.True (eventCalled, "OrientationChanging event was not called."); + } + + [Fact] + public void OrientationChanged_VirtualMethodCalledBeforeEvent () + { + // Arrange + var radioGroup = new CustomView (); + bool eventCalled = false; + + radioGroup.OrientationChanged += (sender, e) => + { + eventCalled = true; + Assert.True (radioGroup.OnOrientationChangedCalled, "OnOrientationChanged was not called before the event."); + }; + + // Act + radioGroup.Orientation = Orientation.Horizontal; + + // Assert + Assert.True (eventCalled, "OrientationChanged event was not called."); + } }