Skip to content

Commit

Permalink
Fixes #3097. Now that View is IDisposable, it should expose a Disposi…
Browse files Browse the repository at this point in the history
…ng event. (#3104)
  • Loading branch information
BDisp committed Jan 4, 2024
1 parent 3d829d7 commit 0b7ca7b
Show file tree
Hide file tree
Showing 2 changed files with 131 additions and 9 deletions.
6 changes: 6 additions & 0 deletions Terminal.Gui/Input/Responder.cs
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,11 @@ public Responder ()
}
#endif

/// <summary>
/// Event raised when <see cref="Dispose()"/> has been called to signal that this object is being disposed.
/// </summary>
public event EventHandler Disposing;

/// <summary>
/// Gets or sets a value indicating whether this <see cref="Responder"/> can focus.
/// </summary>
Expand Down Expand Up @@ -186,6 +191,7 @@ protected virtual void Dispose (bool disposing)
public void Dispose ()
{
// Do not change this code. Put cleanup code in 'Dispose(bool disposing)' method
Disposing?.Invoke (this, EventArgs.Empty);
Dispose (disposing: true);
GC.SuppressFinalize (this);
#if DEBUG_IDISPOSABLE
Expand Down
134 changes: 125 additions & 9 deletions UnitTests/Input/ResponderTests.cs
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
using System.Collections.Generic;
using Xunit;

// Alias Console to MockConsole so we don't accidentally use Console
Expand All @@ -6,7 +7,8 @@
namespace Terminal.Gui.InputTests;

public class ResponderTests {
[Fact] [TestRespondersDisposed]
[Fact]
[TestRespondersDisposed]
public void New_Initializes ()
{
var r = new Responder ();
Expand All @@ -19,7 +21,8 @@ public void New_Initializes ()
r.Dispose ();
}

[Fact] [TestRespondersDisposed]
[Fact]
[TestRespondersDisposed]
public void New_Methods_Return_False ()
{
var r = new View ();
Expand Down Expand Up @@ -59,7 +62,8 @@ public void KeyPressed_Handled_True_Cancels_KeyPress ()
}

// Generic lifetime (IDisposable) tests
[Fact] [TestRespondersDisposed]
[Fact]
[TestRespondersDisposed]
public void Dispose_Works ()
{

Expand All @@ -83,7 +87,8 @@ public override bool OnKeyDown (Key keyEvent)
}
}

[Fact] [TestRespondersDisposed]
[Fact]
[TestRespondersDisposed]
public void IsOverridden_False_IfNotOverridden ()
{
// MouseEvent IS defined on Responder but NOT overridden
Expand All @@ -106,17 +111,18 @@ public void IsOverridden_False_IfNotOverridden ()
#endif
}

[Fact] [TestRespondersDisposed]
[Fact]
[TestRespondersDisposed]
public void IsOverridden_True_IfOverridden ()
{
// MouseEvent is defined on Responder IS overriden on ScrollBarView (but not View)
Assert.True (Responder.IsOverridden (new ScrollBarView () { Text = "ScrollBarView overrides MouseEvent" }, "MouseEvent"));

//// OnKeyDown is defined on View
//Assert.True (Responder.IsOverridden (new View () { Text = "View overrides OnKeyDown" }, "OnKeyDown"));
// OnKeyDown is defined on View
Assert.False (Responder.IsOverridden (new View () { Text = "View overrides OnKeyDown" }, "OnKeyDown"));

//// OnKeyDown is defined on DerivedView
//Assert.True (Responder.IsOverridden (new DerivedView () { Text = "DerivedView overrides OnKeyDown" }, "OnKeyDown"));
// OnKeyDown is defined on DerivedView
Assert.True (Responder.IsOverridden (new DerivedView () { Text = "DerivedView overrides OnKeyDown" }, "OnKeyDown"));

// ScrollBarView overrides both MouseEvent (from Responder) and Redraw (from View)
Assert.True (Responder.IsOverridden (new ScrollBarView () { Text = "ScrollBarView overrides MouseEvent" }, "MouseEvent"));
Expand All @@ -129,4 +135,114 @@ public void IsOverridden_True_IfOverridden ()
Assert.Empty (Responder.Instances);
#endif
}

[Fact]
public void Responder_Not_Notifying_Dispose ()
{
var container1 = new View () { Id = "Container1" };

var view = new View () { Id = "View" };
container1.Add (view);
Assert.Equal (container1, view.SuperView);

Assert.Single (container1.Subviews);

var container2 = new View () { Id = "Container2" };

container2.Add (view);
Assert.Equal (container2, view.SuperView);
Assert.Equal (container1.Subviews.Count, container2.Subviews.Count);
container1.Dispose ();

Assert.Empty (container1.Subviews);
Assert.NotEmpty (container2.Subviews);
Assert.Single (container2.Subviews);
Assert.Null (view.SuperView);

// Trying access disposed properties
Assert.True (container2.Subviews [0].WasDisposed);

Check failure on line 163 in UnitTests/Input/ResponderTests.cs

View workflow job for this annotation

GitHub Actions / Build and Publish to Nuget.org

'View' does not contain a definition for 'WasDisposed' and no accessible extension method 'WasDisposed' accepting a first argument of type 'View' could be found (are you missing a using directive or an assembly reference?)

Check failure on line 163 in UnitTests/Input/ResponderTests.cs

View workflow job for this annotation

GitHub Actions / Build and Publish to Nuget.org

'View' does not contain a definition for 'WasDisposed' and no accessible extension method 'WasDisposed' accepting a first argument of type 'View' could be found (are you missing a using directive or an assembly reference?)
Assert.False (container2.Subviews [0].CanFocus);
Assert.Null (container2.Subviews [0].Margin);
Assert.Null (container2.Subviews [0].Border);
Assert.Null (container2.Subviews [0].Padding);
Assert.Null (view.SuperView);

container2.Dispose ();

Assert.Empty (Responder.Instances);

Check failure on line 172 in UnitTests/Input/ResponderTests.cs

View workflow job for this annotation

GitHub Actions / Build and Publish to Nuget.org

'Responder' does not contain a definition for 'Instances'

Check failure on line 172 in UnitTests/Input/ResponderTests.cs

View workflow job for this annotation

GitHub Actions / Build and Publish to Nuget.org

'Responder' does not contain a definition for 'Instances'
}

[Fact]
public void Disposing_Event_Notify_All_Subscribers_On_The_Second_Container ()
{
var container1 = new View () { Id = "Container1" };

var view = new View () { Id = "View" };
container1.Add (view);
Assert.Equal (container1, view.SuperView);
Assert.Single (container1.Subviews);

var container2 = new View () { Id = "Container2" };
var count = 0;

view.Disposing += View_Disposing;
container2.Add (view);
Assert.Equal (container2, view.SuperView);

void View_Disposing (object sender, System.EventArgs e)
{
count++;
Assert.Equal (view, sender);
container2.Remove ((View)sender);
}

Assert.Equal (container1.Subviews.Count, container2.Subviews.Count);
container1.Dispose ();

Assert.Empty (container1.Subviews);
Assert.Empty (container2.Subviews);
Assert.Equal (1, count);
Assert.Null (view.SuperView);

container2.Dispose ();

Assert.Empty (Responder.Instances);

Check failure on line 209 in UnitTests/Input/ResponderTests.cs

View workflow job for this annotation

GitHub Actions / Build and Publish to Nuget.org

'Responder' does not contain a definition for 'Instances'

Check failure on line 209 in UnitTests/Input/ResponderTests.cs

View workflow job for this annotation

GitHub Actions / Build and Publish to Nuget.org

'Responder' does not contain a definition for 'Instances'
}

[Fact]
public void Disposing_Event_Notify_All_Subscribers_On_The_First_Container ()
{
var container1 = new View () { Id = "Container1" };
var count = 0;

var view = new View () { Id = "View" };
view.Disposing += View_Disposing;
container1.Add (view);
Assert.Equal (container1, view.SuperView);

void View_Disposing (object sender, System.EventArgs e)
{
count++;
Assert.Equal (view, sender);
container1.Remove ((View)sender);
}

Assert.Single (container1.Subviews);

var container2 = new View () { Id = "Container2" };

container2.Add (view);
Assert.Equal (container2, view.SuperView);
Assert.Equal (container1.Subviews.Count, container2.Subviews.Count);
container2.Dispose ();

Assert.Empty (container1.Subviews);
Assert.Empty (container2.Subviews);
Assert.Equal (1, count);
Assert.Null (view.SuperView);

container1.Dispose ();

Assert.Empty (Responder.Instances);

Check failure on line 246 in UnitTests/Input/ResponderTests.cs

View workflow job for this annotation

GitHub Actions / Build and Publish to Nuget.org

'Responder' does not contain a definition for 'Instances'

Check failure on line 246 in UnitTests/Input/ResponderTests.cs

View workflow job for this annotation

GitHub Actions / Build and Publish to Nuget.org

'Responder' does not contain a definition for 'Instances'
}
}

0 comments on commit 0b7ca7b

Please sign in to comment.