mirror of
https://github.com/gui-cs/Terminal.Gui.git
synced 2025-12-26 15:57:56 +01:00
* Initial plan * Phase 1: Update IConsoleDriver.Init() to return void instead of MainLoop Co-authored-by: tig <585482+tig@users.noreply.github.com> * Phase 2: Remove legacy MainLoop infrastructure Co-authored-by: tig <585482+tig@users.noreply.github.com> * Complete Phase 1 and Phase 2 - All tests pass Co-authored-by: tig <585482+tig@users.noreply.github.com> * Update deep dive docs to reflect MainLoop removal Co-authored-by: tig <585482+tig@users.noreply.github.com> --------- Co-authored-by: copilot-swe-agent[bot] <198982749+Copilot@users.noreply.github.com> Co-authored-by: tig <585482+tig@users.noreply.github.com> Co-authored-by: Tig <tig@users.noreply.github.com>
This commit is contained in:
@@ -99,7 +99,6 @@ public class Arrangement : Scenario
|
|||||||
|
|
||||||
progressBar.Fraction += 0.01f;
|
progressBar.Fraction += 0.01f;
|
||||||
|
|
||||||
Application.Wakeup ();
|
|
||||||
|
|
||||||
progressBar.SetNeedsDraw ();
|
progressBar.SetNeedsDraw ();
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -100,7 +100,6 @@ public class Clipping : Scenario
|
|||||||
{
|
{
|
||||||
tiledProgressBar1.Pulse ();
|
tiledProgressBar1.Pulse ();
|
||||||
tiledProgressBar2.Pulse ();
|
tiledProgressBar2.Pulse ();
|
||||||
Application.Wakeup ();
|
|
||||||
};
|
};
|
||||||
|
|
||||||
progressTimer.Start ();
|
progressTimer.Start ();
|
||||||
|
|||||||
@@ -198,7 +198,6 @@ public class ProgressBarStyles : Scenario
|
|||||||
button.Enabled = true;
|
button.Enabled = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
Application.Wakeup ();
|
|
||||||
},
|
},
|
||||||
null,
|
null,
|
||||||
0,
|
0,
|
||||||
@@ -282,7 +281,6 @@ public class ProgressBarStyles : Scenario
|
|||||||
marqueesBlocksPB.Text = marqueesContinuousPB.Text = DateTime.Now.TimeOfDay.ToString ();
|
marqueesBlocksPB.Text = marqueesContinuousPB.Text = DateTime.Now.TimeOfDay.ToString ();
|
||||||
marqueesBlocksPB.Pulse ();
|
marqueesBlocksPB.Pulse ();
|
||||||
marqueesContinuousPB.Pulse ();
|
marqueesContinuousPB.Pulse ();
|
||||||
Application.Wakeup ();
|
|
||||||
},
|
},
|
||||||
null,
|
null,
|
||||||
0,
|
0,
|
||||||
|
|||||||
@@ -384,7 +384,6 @@ public class Shortcuts : Scenario
|
|||||||
|
|
||||||
pb.Fraction += 0.01f;
|
pb.Fraction += 0.01f;
|
||||||
|
|
||||||
Application.Wakeup ();
|
|
||||||
|
|
||||||
pb.SetNeedsDraw ();
|
pb.SetNeedsDraw ();
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -131,7 +131,7 @@ public static partial class Application // Lifecycle (Init/Shutdown)
|
|||||||
|
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
MainLoop = Driver!.Init ();
|
Driver!.Init ();
|
||||||
SubscribeDriverEvents ();
|
SubscribeDriverEvents ();
|
||||||
}
|
}
|
||||||
catch (InvalidOperationException ex)
|
catch (InvalidOperationException ex)
|
||||||
|
|||||||
@@ -372,12 +372,6 @@ public static partial class Application // Run (Begin -> Run -> Layout/Draw -> E
|
|||||||
/// <param name="action">the action to be invoked on the main processing thread.</param>
|
/// <param name="action">the action to be invoked on the main processing thread.</param>
|
||||||
public static void Invoke (Action action) { ApplicationImpl.Instance.Invoke (action); }
|
public static void Invoke (Action action) { ApplicationImpl.Instance.Invoke (action); }
|
||||||
|
|
||||||
// TODO: Determine if this is really needed. The only code that calls WakeUp I can find
|
|
||||||
// is ProgressBarStyles, and it's not clear it needs to.
|
|
||||||
|
|
||||||
/// <summary>Wakes up the running application that might be waiting on input.</summary>
|
|
||||||
public static void Wakeup () { MainLoop?.Wakeup (); }
|
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Causes any Toplevels that need layout to be laid out. Then draws any Toplevels that need display. Only Views that
|
/// Causes any Toplevels that need layout to be laid out. Then draws any Toplevels that need display. Only Views that
|
||||||
/// need to be laid out (see <see cref="View.NeedsLayout"/>) will be laid out.
|
/// need to be laid out (see <see cref="View.NeedsLayout"/>) will be laid out.
|
||||||
@@ -396,10 +390,6 @@ public static partial class Application // Run (Begin -> Run -> Layout/Draw -> E
|
|||||||
/// <remarks>See also <see cref="Timeout"/></remarks>
|
/// <remarks>See also <see cref="Timeout"/></remarks>
|
||||||
public static event EventHandler<IterationEventArgs>? Iteration;
|
public static event EventHandler<IterationEventArgs>? Iteration;
|
||||||
|
|
||||||
/// <summary>The <see cref="MainLoop"/> driver for the application</summary>
|
|
||||||
/// <value>The main loop.</value>
|
|
||||||
internal static MainLoop? MainLoop { get; set; }
|
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Set to true to cause <see cref="End"/> to be called after the first iteration. Set to false (the default) to
|
/// Set to true to cause <see cref="End"/> to be called after the first iteration. Set to false (the default) to
|
||||||
/// cause the application to continue running until Application.RequestStop () is called.
|
/// cause the application to continue running until Application.RequestStop () is called.
|
||||||
@@ -417,11 +407,6 @@ public static partial class Application // Run (Begin -> Run -> Layout/Draw -> E
|
|||||||
|
|
||||||
for (state.Toplevel.Running = true; state.Toplevel?.Running == true;)
|
for (state.Toplevel.Running = true; state.Toplevel?.Running == true;)
|
||||||
{
|
{
|
||||||
if (MainLoop is { })
|
|
||||||
{
|
|
||||||
MainLoop.Running = true;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (EndAfterFirstIteration && !firstIteration)
|
if (EndAfterFirstIteration && !firstIteration)
|
||||||
{
|
{
|
||||||
return;
|
return;
|
||||||
@@ -430,11 +415,6 @@ public static partial class Application // Run (Begin -> Run -> Layout/Draw -> E
|
|||||||
firstIteration = RunIteration (ref state, firstIteration);
|
firstIteration = RunIteration (ref state, firstIteration);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (MainLoop is { })
|
|
||||||
{
|
|
||||||
MainLoop.Running = false;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Run one last iteration to consume any outstanding input events from Driver
|
// Run one last iteration to consume any outstanding input events from Driver
|
||||||
// This is important for remaining OnKeyUp events.
|
// This is important for remaining OnKeyUp events.
|
||||||
RunIteration (ref state, firstIteration);
|
RunIteration (ref state, firstIteration);
|
||||||
|
|||||||
@@ -216,9 +216,6 @@ public static partial class Application
|
|||||||
Top = null;
|
Top = null;
|
||||||
_cachedRunStateToplevel = null;
|
_cachedRunStateToplevel = null;
|
||||||
|
|
||||||
// MainLoop stuff
|
|
||||||
MainLoop?.Dispose ();
|
|
||||||
MainLoop = null;
|
|
||||||
MainThreadId = -1;
|
MainThreadId = -1;
|
||||||
Iteration = null;
|
Iteration = null;
|
||||||
EndAfterFirstIteration = false;
|
EndAfterFirstIteration = false;
|
||||||
|
|||||||
@@ -1,24 +0,0 @@
|
|||||||
#nullable enable
|
|
||||||
namespace Terminal.Gui.App;
|
|
||||||
|
|
||||||
/// <summary>Interface to create a platform specific <see cref="MainLoop"/> driver.</summary>
|
|
||||||
internal interface IMainLoopDriver
|
|
||||||
{
|
|
||||||
/// <summary>Must report whether there are any events pending, or even block waiting for events.</summary>
|
|
||||||
/// <returns><see langword="true"/>, if there were pending events, <see langword="false"/> otherwise.</returns>
|
|
||||||
bool EventsPending ();
|
|
||||||
|
|
||||||
/// <summary>The iteration function.</summary>
|
|
||||||
void Iteration ();
|
|
||||||
|
|
||||||
/// <summary>Initializes the <see cref="MainLoop"/>, gets the calling main loop for the initialization.</summary>
|
|
||||||
/// <remarks>Call <see cref="TearDown"/> to release resources.</remarks>
|
|
||||||
/// <param name="mainLoop">Main loop.</param>
|
|
||||||
void Setup (MainLoop mainLoop);
|
|
||||||
|
|
||||||
/// <summary>Tears down the <see cref="MainLoop"/> driver. Releases resources created in <see cref="Setup"/>.</summary>
|
|
||||||
void TearDown ();
|
|
||||||
|
|
||||||
/// <summary>Wakes up the <see cref="MainLoop"/> that might be waiting on input, must be thread safe.</summary>
|
|
||||||
void Wakeup ();
|
|
||||||
}
|
|
||||||
@@ -1,122 +0,0 @@
|
|||||||
#nullable enable
|
|
||||||
//
|
|
||||||
// LegacyMainLoopDriver.cs: IMainLoopDriver and MainLoop for legacy v1 driver based applications
|
|
||||||
//
|
|
||||||
// Authors:
|
|
||||||
// Miguel de Icaza (miguel@gnome.org)
|
|
||||||
//
|
|
||||||
|
|
||||||
using System.Collections.ObjectModel;
|
|
||||||
|
|
||||||
namespace Terminal.Gui.App;
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// The main event loop of legacy v1 driver based applications.
|
|
||||||
/// </summary>
|
|
||||||
/// <remarks>
|
|
||||||
/// <para>
|
|
||||||
/// This class is provided for backward compatibility with the legacy FakeDriver implementation.
|
|
||||||
/// New code should use the modern <see cref="ApplicationMainLoop{T}"/> architecture instead.
|
|
||||||
/// </para>
|
|
||||||
/// <para>
|
|
||||||
/// Monitoring of file descriptors is only available on Unix, there does not seem to be a way of supporting this
|
|
||||||
/// on Windows.
|
|
||||||
/// </para>
|
|
||||||
/// </remarks>
|
|
||||||
[Obsolete ("This class is for legacy FakeDriver compatibility only. Use ApplicationMainLoop<T> for new code.")]
|
|
||||||
public class MainLoop : IDisposable
|
|
||||||
{
|
|
||||||
/// <summary>
|
|
||||||
/// Gets the class responsible for handling timeouts
|
|
||||||
/// </summary>
|
|
||||||
public ITimedEvents TimedEvents { get; } = new TimedEvents();
|
|
||||||
|
|
||||||
/// <summary>Creates a new MainLoop.</summary>
|
|
||||||
/// <remarks>Use <see cref="Dispose"/> to release resources.</remarks>
|
|
||||||
/// <param name="driver">
|
|
||||||
/// The <see cref="IConsoleDriver"/> instance (one of the implementations FakeMainLoop, UnixMainLoop,
|
|
||||||
/// NetMainLoop or WindowsMainLoop).
|
|
||||||
/// </param>
|
|
||||||
internal MainLoop (IMainLoopDriver driver)
|
|
||||||
{
|
|
||||||
MainLoopDriver = driver;
|
|
||||||
driver.Setup (this);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/// <summary>The current <see cref="IMainLoopDriver"/> in use.</summary>
|
|
||||||
/// <value>The main loop driver.</value>
|
|
||||||
internal IMainLoopDriver? MainLoopDriver { get; private set; }
|
|
||||||
|
|
||||||
/// <summary>Used for unit tests.</summary>
|
|
||||||
internal bool Running { get; set; }
|
|
||||||
|
|
||||||
|
|
||||||
/// <inheritdoc/>
|
|
||||||
public void Dispose ()
|
|
||||||
{
|
|
||||||
GC.SuppressFinalize (this);
|
|
||||||
Stop ();
|
|
||||||
Running = false;
|
|
||||||
MainLoopDriver?.TearDown ();
|
|
||||||
MainLoopDriver = null;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/// <summary>Determines whether there are pending events to be processed.</summary>
|
|
||||||
/// <remarks>
|
|
||||||
/// You can use this method if you want to probe if events are pending. Typically used if you need to flush the
|
|
||||||
/// input queue while still running some of your own code in your main thread.
|
|
||||||
/// </remarks>
|
|
||||||
internal bool EventsPending () { return MainLoopDriver!.EventsPending (); }
|
|
||||||
|
|
||||||
|
|
||||||
/// <summary>Runs the <see cref="MainLoop"/>. Used only for unit tests.</summary>
|
|
||||||
internal void Run ()
|
|
||||||
{
|
|
||||||
bool prev = Running;
|
|
||||||
Running = true;
|
|
||||||
|
|
||||||
while (Running)
|
|
||||||
{
|
|
||||||
EventsPending ();
|
|
||||||
RunIteration ();
|
|
||||||
}
|
|
||||||
|
|
||||||
Running = prev;
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>Runs one iteration of timers and file watches</summary>
|
|
||||||
/// <remarks>
|
|
||||||
/// Use this to process all pending events (timers handlers and file watches).
|
|
||||||
/// <code>
|
|
||||||
/// while (main.EventsPending ()) RunIteration ();
|
|
||||||
/// </code>
|
|
||||||
/// </remarks>
|
|
||||||
internal void RunIteration ()
|
|
||||||
{
|
|
||||||
RunAnsiScheduler ();
|
|
||||||
|
|
||||||
MainLoopDriver?.Iteration ();
|
|
||||||
|
|
||||||
TimedEvents.RunTimers ();
|
|
||||||
}
|
|
||||||
|
|
||||||
private void RunAnsiScheduler ()
|
|
||||||
{
|
|
||||||
Application.Driver?.GetRequestScheduler ().RunSchedule ();
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>Stops the main loop driver and calls <see cref="IMainLoopDriver.Wakeup"/>. Used only for unit tests.</summary>
|
|
||||||
internal void Stop ()
|
|
||||||
{
|
|
||||||
Running = false;
|
|
||||||
Wakeup ();
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/// <summary>Wakes up the <see cref="MainLoop"/> that might be waiting on input.</summary>
|
|
||||||
internal void Wakeup () { MainLoopDriver?.Wakeup (); }
|
|
||||||
|
|
||||||
|
|
||||||
}
|
|
||||||
@@ -10,23 +10,8 @@ internal sealed class MainLoopSyncContext : SynchronizationContext
|
|||||||
|
|
||||||
public override void Post (SendOrPostCallback d, object state)
|
public override void Post (SendOrPostCallback d, object state)
|
||||||
{
|
{
|
||||||
// Queue the task
|
// Queue the task using the modern architecture
|
||||||
if (ApplicationImpl.Instance.IsLegacy)
|
ApplicationImpl.Instance.Invoke (() => { d (state); });
|
||||||
{
|
|
||||||
Application.MainLoop?.TimedEvents.Add (TimeSpan.Zero,
|
|
||||||
() =>
|
|
||||||
{
|
|
||||||
d (state);
|
|
||||||
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
);
|
|
||||||
Application.MainLoop?.Wakeup ();
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
ApplicationImpl.Instance.Invoke (() => { d (state); });
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
//_mainLoop.Driver.Wakeup ();
|
//_mainLoop.Driver.Wakeup ();
|
||||||
|
|||||||
@@ -931,7 +931,7 @@ public static class EscSeqUtils
|
|||||||
_isButtonClicked = false;
|
_isButtonClicked = false;
|
||||||
_isButtonDoubleClicked = true;
|
_isButtonDoubleClicked = true;
|
||||||
|
|
||||||
Application.MainLoop?.TimedEvents.Add (TimeSpan.Zero,
|
ApplicationImpl.Instance.TimedEvents?.Add (TimeSpan.Zero,
|
||||||
() =>
|
() =>
|
||||||
{
|
{
|
||||||
Task.Run (async () => await ProcessButtonDoubleClickedAsync ());
|
Task.Run (async () => await ProcessButtonDoubleClickedAsync ());
|
||||||
@@ -970,7 +970,7 @@ public static class EscSeqUtils
|
|||||||
mouseFlags.Add (GetButtonClicked (buttonState));
|
mouseFlags.Add (GetButtonClicked (buttonState));
|
||||||
_isButtonClicked = true;
|
_isButtonClicked = true;
|
||||||
|
|
||||||
Application.MainLoop?.TimedEvents.Add (TimeSpan.Zero,
|
ApplicationImpl.Instance.TimedEvents?.Add (TimeSpan.Zero,
|
||||||
() =>
|
() =>
|
||||||
{
|
{
|
||||||
Task.Run (async () => await ProcessButtonClickedAsync ());
|
Task.Run (async () => await ProcessButtonClickedAsync ());
|
||||||
|
|||||||
@@ -550,8 +550,7 @@ public abstract class ConsoleDriver : IConsoleDriver
|
|||||||
#region Setup & Teardown
|
#region Setup & Teardown
|
||||||
|
|
||||||
/// <summary>Initializes the driver</summary>
|
/// <summary>Initializes the driver</summary>
|
||||||
/// <returns>Returns an instance of <see cref="MainLoop"/> using the <see cref="IMainLoopDriver"/> for the driver.</returns>
|
public abstract void Init ();
|
||||||
public abstract MainLoop Init ();
|
|
||||||
|
|
||||||
/// <summary>Ends the execution of the console driver.</summary>
|
/// <summary>Ends the execution of the console driver.</summary>
|
||||||
public abstract void End ();
|
public abstract void End ();
|
||||||
|
|||||||
@@ -365,7 +365,7 @@ internal class ConsoleDriverFacade<T> : IConsoleDriver, IConsoleDriverFacade
|
|||||||
|
|
||||||
/// <summary>Initializes the driver</summary>
|
/// <summary>Initializes the driver</summary>
|
||||||
/// <returns>Returns an instance of <see cref="MainLoop"/> using the <see cref="IMainLoopDriver"/> for the driver.</returns>
|
/// <returns>Returns an instance of <see cref="MainLoop"/> using the <see cref="IMainLoopDriver"/> for the driver.</returns>
|
||||||
public MainLoop Init () { throw new NotSupportedException (); }
|
public void Init () { throw new NotSupportedException (); }
|
||||||
|
|
||||||
/// <summary>Ends the execution of the console driver.</summary>
|
/// <summary>Ends the execution of the console driver.</summary>
|
||||||
public void End ()
|
public void End ()
|
||||||
|
|||||||
@@ -91,9 +91,7 @@ public class FakeDriver : ConsoleDriver
|
|||||||
FakeConsole.Clear ();
|
FakeConsole.Clear ();
|
||||||
}
|
}
|
||||||
|
|
||||||
private FakeMainLoop? _mainLoopDriver;
|
public override void Init ()
|
||||||
|
|
||||||
public override MainLoop Init ()
|
|
||||||
{
|
{
|
||||||
FakeConsole.MockKeyPresses.Clear ();
|
FakeConsole.MockKeyPresses.Clear ();
|
||||||
|
|
||||||
@@ -102,12 +100,6 @@ public class FakeDriver : ConsoleDriver
|
|||||||
FakeConsole.Clear ();
|
FakeConsole.Clear ();
|
||||||
ResizeScreen ();
|
ResizeScreen ();
|
||||||
CurrentAttribute = new Attribute (Color.White, Color.Black);
|
CurrentAttribute = new Attribute (Color.White, Color.Black);
|
||||||
//ClearContents ();
|
|
||||||
|
|
||||||
_mainLoopDriver = new FakeMainLoop (this);
|
|
||||||
_mainLoopDriver.MockKeyPressed = MockKeyPressedHandler;
|
|
||||||
|
|
||||||
return new MainLoop (_mainLoopDriver);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public override bool UpdateScreen ()
|
public override bool UpdateScreen ()
|
||||||
@@ -346,24 +338,6 @@ public class FakeDriver : ConsoleDriver
|
|||||||
|
|
||||||
private CursorVisibility _savedCursorVisibility;
|
private CursorVisibility _savedCursorVisibility;
|
||||||
|
|
||||||
private void MockKeyPressedHandler (ConsoleKeyInfo consoleKeyInfo)
|
|
||||||
{
|
|
||||||
if (consoleKeyInfo.Key == ConsoleKey.Packet)
|
|
||||||
{
|
|
||||||
consoleKeyInfo = ConsoleKeyMapping.DecodeVKPacketToKConsoleKeyInfo (consoleKeyInfo);
|
|
||||||
}
|
|
||||||
|
|
||||||
KeyCode map = MapKey (consoleKeyInfo);
|
|
||||||
|
|
||||||
if (IsValidInput (map, out map))
|
|
||||||
{
|
|
||||||
OnKeyDown (new (map));
|
|
||||||
OnKeyUp (new (map));
|
|
||||||
}
|
|
||||||
|
|
||||||
//OnKeyPressed (new KeyEventArgs (map));
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <inheritdoc/>
|
/// <inheritdoc/>
|
||||||
public override bool GetCursorVisibility (out CursorVisibility visibility)
|
public override bool GetCursorVisibility (out CursorVisibility visibility)
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -1,38 +0,0 @@
|
|||||||
|
|
||||||
namespace Terminal.Gui.Drivers;
|
|
||||||
|
|
||||||
internal class FakeMainLoop : IMainLoopDriver
|
|
||||||
{
|
|
||||||
public Action<ConsoleKeyInfo> MockKeyPressed;
|
|
||||||
|
|
||||||
public FakeMainLoop (IConsoleDriver consoleDriver = null)
|
|
||||||
{
|
|
||||||
// No implementation needed for FakeMainLoop
|
|
||||||
}
|
|
||||||
|
|
||||||
public void Setup (MainLoop mainLoop)
|
|
||||||
{
|
|
||||||
// No implementation needed for FakeMainLoop
|
|
||||||
}
|
|
||||||
|
|
||||||
public void Wakeup ()
|
|
||||||
{
|
|
||||||
// No implementation needed for FakeMainLoop
|
|
||||||
}
|
|
||||||
|
|
||||||
public bool EventsPending ()
|
|
||||||
{
|
|
||||||
// Always return true for FakeMainLoop
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void Iteration ()
|
|
||||||
{
|
|
||||||
if (FakeConsole.MockKeyPresses.Count > 0)
|
|
||||||
{
|
|
||||||
MockKeyPressed?.Invoke (FakeConsole.MockKeyPresses.Pop ());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public void TearDown () { }
|
|
||||||
}
|
|
||||||
@@ -214,8 +214,7 @@ public interface IConsoleDriver
|
|||||||
void UpdateCursor ();
|
void UpdateCursor ();
|
||||||
|
|
||||||
/// <summary>Initializes the driver</summary>
|
/// <summary>Initializes the driver</summary>
|
||||||
/// <returns>Returns an instance of <see cref="MainLoop"/> using the <see cref="IMainLoopDriver"/> for the driver.</returns>
|
void Init ();
|
||||||
MainLoop Init ();
|
|
||||||
|
|
||||||
/// <summary>Ends the execution of the console driver.</summary>
|
/// <summary>Ends the execution of the console driver.</summary>
|
||||||
void End ();
|
void End ();
|
||||||
|
|||||||
@@ -159,7 +159,6 @@ public class ApplicationTests
|
|||||||
Application.Shutdown ();
|
Application.Shutdown ();
|
||||||
|
|
||||||
Assert.Null (Application.Top);
|
Assert.Null (Application.Top);
|
||||||
Assert.Null (Application.MainLoop);
|
|
||||||
Assert.Null (Application.Driver);
|
Assert.Null (Application.Driver);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -316,7 +315,6 @@ public class ApplicationTests
|
|||||||
// Don't check Application.Force16Colors
|
// Don't check Application.Force16Colors
|
||||||
//Assert.False (Application.Force16Colors);
|
//Assert.False (Application.Force16Colors);
|
||||||
Assert.Null (Application.Driver);
|
Assert.Null (Application.Driver);
|
||||||
Assert.Null (Application.MainLoop);
|
|
||||||
Assert.False (Application.EndAfterFirstIteration);
|
Assert.False (Application.EndAfterFirstIteration);
|
||||||
|
|
||||||
// Commented out because if CM changed the defaults, those changes should
|
// Commented out because if CM changed the defaults, those changes should
|
||||||
@@ -472,7 +470,6 @@ public class ApplicationTests
|
|||||||
Application.Shutdown ();
|
Application.Shutdown ();
|
||||||
|
|
||||||
Assert.Null (Application.Top);
|
Assert.Null (Application.Top);
|
||||||
Assert.Null (Application.MainLoop);
|
|
||||||
Assert.Null (Application.Driver);
|
Assert.Null (Application.Driver);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -486,7 +483,6 @@ public class ApplicationTests
|
|||||||
Application.Shutdown ();
|
Application.Shutdown ();
|
||||||
|
|
||||||
Assert.Null (Application.Top);
|
Assert.Null (Application.Top);
|
||||||
Assert.Null (Application.MainLoop);
|
|
||||||
Assert.Null (Application.Driver);
|
Assert.Null (Application.Driver);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -522,14 +518,12 @@ public class ApplicationTests
|
|||||||
Application.End (runstate);
|
Application.End (runstate);
|
||||||
|
|
||||||
Assert.NotNull (Application.Top);
|
Assert.NotNull (Application.Top);
|
||||||
Assert.NotNull (Application.MainLoop);
|
|
||||||
Assert.NotNull (Application.Driver);
|
Assert.NotNull (Application.Driver);
|
||||||
|
|
||||||
topLevel.Dispose ();
|
topLevel.Dispose ();
|
||||||
Application.Shutdown ();
|
Application.Shutdown ();
|
||||||
|
|
||||||
Assert.Null (Application.Top);
|
Assert.Null (Application.Top);
|
||||||
Assert.Null (Application.MainLoop);
|
|
||||||
Assert.Null (Application.Driver);
|
Assert.Null (Application.Driver);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -676,7 +670,6 @@ public class ApplicationTests
|
|||||||
Application.Shutdown ();
|
Application.Shutdown ();
|
||||||
|
|
||||||
Assert.Null (Application.Top);
|
Assert.Null (Application.Top);
|
||||||
Assert.Null (Application.MainLoop);
|
|
||||||
Assert.Null (Application.Driver);
|
Assert.Null (Application.Driver);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -700,7 +693,6 @@ public class ApplicationTests
|
|||||||
Application.Shutdown ();
|
Application.Shutdown ();
|
||||||
|
|
||||||
Assert.Null (Application.Top);
|
Assert.Null (Application.Top);
|
||||||
Assert.Null (Application.MainLoop);
|
|
||||||
Assert.Null (Application.Driver);
|
Assert.Null (Application.Driver);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -734,7 +726,6 @@ public class ApplicationTests
|
|||||||
Application.Shutdown ();
|
Application.Shutdown ();
|
||||||
|
|
||||||
Assert.Null (Application.Top);
|
Assert.Null (Application.Top);
|
||||||
Assert.Null (Application.MainLoop);
|
|
||||||
Assert.Null (Application.Driver);
|
Assert.Null (Application.Driver);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -752,7 +743,6 @@ public class ApplicationTests
|
|||||||
Application.Shutdown ();
|
Application.Shutdown ();
|
||||||
|
|
||||||
Assert.Null (Application.Top);
|
Assert.Null (Application.Top);
|
||||||
Assert.Null (Application.MainLoop);
|
|
||||||
Assert.Null (Application.Driver);
|
Assert.Null (Application.Driver);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -774,7 +764,6 @@ public class ApplicationTests
|
|||||||
Application.Shutdown ();
|
Application.Shutdown ();
|
||||||
|
|
||||||
Assert.Null (Application.Top);
|
Assert.Null (Application.Top);
|
||||||
Assert.Null (Application.MainLoop);
|
|
||||||
Assert.Null (Application.Driver);
|
Assert.Null (Application.Driver);
|
||||||
|
|
||||||
a.After (null);
|
a.After (null);
|
||||||
@@ -793,7 +782,6 @@ public class ApplicationTests
|
|||||||
Application.Shutdown ();
|
Application.Shutdown ();
|
||||||
|
|
||||||
Assert.Null (Application.Top);
|
Assert.Null (Application.Top);
|
||||||
Assert.Null (Application.MainLoop);
|
|
||||||
Assert.Null (Application.Driver);
|
Assert.Null (Application.Driver);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -812,7 +800,6 @@ public class ApplicationTests
|
|||||||
Application.Shutdown ();
|
Application.Shutdown ();
|
||||||
|
|
||||||
Assert.Null (Application.Top);
|
Assert.Null (Application.Top);
|
||||||
Assert.Null (Application.MainLoop);
|
|
||||||
Assert.Null (Application.Driver);
|
Assert.Null (Application.Driver);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -829,7 +816,6 @@ public class ApplicationTests
|
|||||||
Application.Shutdown ();
|
Application.Shutdown ();
|
||||||
|
|
||||||
Assert.Null (Application.Top);
|
Assert.Null (Application.Top);
|
||||||
Assert.Null (Application.MainLoop);
|
|
||||||
Assert.Null (Application.Driver);
|
Assert.Null (Application.Driver);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -849,7 +835,6 @@ public class ApplicationTests
|
|||||||
top.Dispose ();
|
top.Dispose ();
|
||||||
Application.Shutdown ();
|
Application.Shutdown ();
|
||||||
Assert.Null (Application.Top);
|
Assert.Null (Application.Top);
|
||||||
Assert.Null (Application.MainLoop);
|
|
||||||
Assert.Null (Application.Driver);
|
Assert.Null (Application.Driver);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -872,7 +857,6 @@ public class ApplicationTests
|
|||||||
top.Dispose ();
|
top.Dispose ();
|
||||||
Application.Shutdown ();
|
Application.Shutdown ();
|
||||||
Assert.Null (Application.Top);
|
Assert.Null (Application.Top);
|
||||||
Assert.Null (Application.MainLoop);
|
|
||||||
Assert.Null (Application.Driver);
|
Assert.Null (Application.Driver);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -892,7 +876,6 @@ public class ApplicationTests
|
|||||||
top.Dispose ();
|
top.Dispose ();
|
||||||
Application.Shutdown ();
|
Application.Shutdown ();
|
||||||
Assert.Null (Application.Top);
|
Assert.Null (Application.Top);
|
||||||
Assert.Null (Application.MainLoop);
|
|
||||||
Assert.Null (Application.Driver);
|
Assert.Null (Application.Driver);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -1,940 +0,0 @@
|
|||||||
using System.Diagnostics;
|
|
||||||
using Xunit.Abstractions;
|
|
||||||
|
|
||||||
// Alias Console to MockConsole so we don't accidentally use Console
|
|
||||||
|
|
||||||
namespace UnitTests.ApplicationTests;
|
|
||||||
|
|
||||||
/// <summary>Tests MainLoop using the FakeMainLoop.</summary>
|
|
||||||
public class MainLoopTests
|
|
||||||
{
|
|
||||||
private readonly ITestOutputHelper _output;
|
|
||||||
|
|
||||||
public MainLoopTests (ITestOutputHelper output)
|
|
||||||
{
|
|
||||||
_output = output;
|
|
||||||
ConsoleDriver.RunningUnitTests = true;
|
|
||||||
}
|
|
||||||
|
|
||||||
private static Button btn;
|
|
||||||
private static string cancel;
|
|
||||||
private static string clickMe;
|
|
||||||
private static int four;
|
|
||||||
private static int one;
|
|
||||||
private static string pewPew;
|
|
||||||
private static bool taskCompleted;
|
|
||||||
|
|
||||||
// TODO: EventsPending tests
|
|
||||||
// - wait = true
|
|
||||||
// - wait = false
|
|
||||||
|
|
||||||
// TODO: Add IMainLoop tests
|
|
||||||
private static int three;
|
|
||||||
private static int total;
|
|
||||||
private static int two;
|
|
||||||
private static int zero;
|
|
||||||
|
|
||||||
// See Also ConsoleDRivers/MainLoopDriverTests.cs for tests of the MainLoopDriver
|
|
||||||
|
|
||||||
// Idle Handler tests
|
|
||||||
[Fact]
|
|
||||||
public void AddTimeout_Adds_And_Removes ()
|
|
||||||
{
|
|
||||||
var ml = new MainLoop (new FakeMainLoop ());
|
|
||||||
|
|
||||||
Func<bool> fnTrue = () => true;
|
|
||||||
Func<bool> fnFalse = () => false;
|
|
||||||
|
|
||||||
var a = ml.TimedEvents.Add (TimeSpan.Zero, fnTrue);
|
|
||||||
var b = ml.TimedEvents.Add (TimeSpan.Zero, fnFalse);
|
|
||||||
|
|
||||||
Assert.Equal (2, ml.TimedEvents.Timeouts.Count);
|
|
||||||
Assert.Equal (fnTrue, ml.TimedEvents.Timeouts.ElementAt (0).Value.Callback);
|
|
||||||
Assert.NotEqual (fnFalse, ml.TimedEvents.Timeouts.ElementAt (0).Value.Callback);
|
|
||||||
|
|
||||||
Assert.True (ml.TimedEvents.Remove (a));
|
|
||||||
Assert.Single (ml.TimedEvents.Timeouts);
|
|
||||||
|
|
||||||
// BUGBUG: This doesn't throw or indicate an error. Ideally RemoveIdle would either
|
|
||||||
// throw an exception in this case, or return an error.
|
|
||||||
// No. Only need to return a boolean.
|
|
||||||
Assert.False (ml.TimedEvents.Remove (a));
|
|
||||||
|
|
||||||
Assert.True (ml.TimedEvents.Remove (b));
|
|
||||||
|
|
||||||
// BUGBUG: This doesn't throw an exception or indicate an error. Ideally RemoveIdle would either
|
|
||||||
// throw an exception in this case, or return an error.
|
|
||||||
// No. Only need to return a boolean.
|
|
||||||
Assert.False (ml.TimedEvents.Remove(b));
|
|
||||||
}
|
|
||||||
|
|
||||||
[Fact]
|
|
||||||
public void AddTimeout_Function_GetsCalled_OnIteration ()
|
|
||||||
{
|
|
||||||
var ml = new MainLoop (new FakeMainLoop ());
|
|
||||||
|
|
||||||
var functionCalled = 0;
|
|
||||||
|
|
||||||
Func<bool> fn = () =>
|
|
||||||
{
|
|
||||||
functionCalled++;
|
|
||||||
|
|
||||||
return true;
|
|
||||||
};
|
|
||||||
|
|
||||||
ml.TimedEvents.Add (TimeSpan.Zero, fn);
|
|
||||||
ml.RunIteration ();
|
|
||||||
Assert.Equal (1, functionCalled);
|
|
||||||
}
|
|
||||||
|
|
||||||
[Fact]
|
|
||||||
public void AddTimeout_Twice_Returns_False_Called_Twice ()
|
|
||||||
{
|
|
||||||
var ml = new MainLoop (new FakeMainLoop ());
|
|
||||||
|
|
||||||
var functionCalled = 0;
|
|
||||||
|
|
||||||
Func<bool> fn1 = () =>
|
|
||||||
{
|
|
||||||
functionCalled++;
|
|
||||||
|
|
||||||
return false;
|
|
||||||
};
|
|
||||||
|
|
||||||
// Force stop if 10 iterations
|
|
||||||
var stopCount = 0;
|
|
||||||
|
|
||||||
Func<bool> fnStop = () =>
|
|
||||||
{
|
|
||||||
stopCount++;
|
|
||||||
|
|
||||||
if (stopCount == 10)
|
|
||||||
{
|
|
||||||
ml.Stop ();
|
|
||||||
}
|
|
||||||
|
|
||||||
return true;
|
|
||||||
};
|
|
||||||
|
|
||||||
var a = ml.TimedEvents.Add (TimeSpan.Zero, fnStop);
|
|
||||||
var b = ml.TimedEvents.Add (TimeSpan.Zero, fn1);
|
|
||||||
ml.Run ();
|
|
||||||
|
|
||||||
Assert.True (ml.TimedEvents.Remove(a));
|
|
||||||
Assert.False (ml.TimedEvents.Remove (a));
|
|
||||||
|
|
||||||
// Cannot remove b because it returned false i.e. auto removes itself
|
|
||||||
Assert.False (ml.TimedEvents.Remove (b));
|
|
||||||
|
|
||||||
Assert.Equal (1, functionCalled);
|
|
||||||
}
|
|
||||||
|
|
||||||
[Fact]
|
|
||||||
public void AddTimeoutTwice_Function_CalledTwice ()
|
|
||||||
{
|
|
||||||
var ml = new MainLoop (new FakeMainLoop ());
|
|
||||||
|
|
||||||
var functionCalled = 0;
|
|
||||||
|
|
||||||
Func<bool> fn = () =>
|
|
||||||
{
|
|
||||||
functionCalled++;
|
|
||||||
|
|
||||||
return true;
|
|
||||||
};
|
|
||||||
|
|
||||||
var a = ml.TimedEvents.Add (TimeSpan.Zero, fn);
|
|
||||||
var b = ml.TimedEvents.Add (TimeSpan.Zero, fn);
|
|
||||||
ml.RunIteration ();
|
|
||||||
Assert.Equal (2, functionCalled);
|
|
||||||
Assert.Equal (2, ml.TimedEvents.Timeouts.Count);
|
|
||||||
|
|
||||||
functionCalled = 0;
|
|
||||||
Assert.True (ml.TimedEvents.Remove (a));
|
|
||||||
Assert.Single (ml.TimedEvents.Timeouts);
|
|
||||||
ml.RunIteration ();
|
|
||||||
Assert.Equal (1, functionCalled);
|
|
||||||
|
|
||||||
functionCalled = 0;
|
|
||||||
Assert.True (ml.TimedEvents.Remove (b));
|
|
||||||
Assert.Empty (ml.TimedEvents.Timeouts);
|
|
||||||
ml.RunIteration ();
|
|
||||||
Assert.Equal (0, functionCalled);
|
|
||||||
Assert.False (ml.TimedEvents.Remove (b));
|
|
||||||
}
|
|
||||||
|
|
||||||
[Fact]
|
|
||||||
public void AddThenRemoveIdle_Function_NotCalled ()
|
|
||||||
{
|
|
||||||
var ml = new MainLoop (new FakeMainLoop ());
|
|
||||||
|
|
||||||
var functionCalled = 0;
|
|
||||||
|
|
||||||
Func<bool> fn = () =>
|
|
||||||
{
|
|
||||||
functionCalled++;
|
|
||||||
|
|
||||||
return true;
|
|
||||||
};
|
|
||||||
|
|
||||||
var a = ml.TimedEvents.Add (TimeSpan.Zero, fn);
|
|
||||||
Assert.True (ml.TimedEvents.Remove (a));
|
|
||||||
ml.RunIteration ();
|
|
||||||
Assert.Equal (0, functionCalled);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Timeout Handler Tests
|
|
||||||
[Fact]
|
|
||||||
public void AddTimer_Adds_Removes_NoFaults ()
|
|
||||||
{
|
|
||||||
var ml = new MainLoop (new FakeMainLoop ());
|
|
||||||
var ms = 100;
|
|
||||||
|
|
||||||
var callbackCount = 0;
|
|
||||||
|
|
||||||
Func<bool> callback = () =>
|
|
||||||
{
|
|
||||||
callbackCount++;
|
|
||||||
|
|
||||||
return true;
|
|
||||||
};
|
|
||||||
|
|
||||||
object token = ml.TimedEvents.Add (TimeSpan.FromMilliseconds (ms), callback);
|
|
||||||
|
|
||||||
Assert.True (ml.TimedEvents.Remove (token));
|
|
||||||
|
|
||||||
// BUGBUG: This should probably fault?
|
|
||||||
// Must return a boolean.
|
|
||||||
Assert.False (ml.TimedEvents.Remove (token));
|
|
||||||
}
|
|
||||||
|
|
||||||
[Fact]
|
|
||||||
public async Task AddTimer_Duplicate_Keys_Not_Allowed ()
|
|
||||||
{
|
|
||||||
var ml = new MainLoop (new FakeMainLoop ());
|
|
||||||
const int ms = 100;
|
|
||||||
object token1 = null, token2 = null;
|
|
||||||
|
|
||||||
var callbackCount = 0;
|
|
||||||
|
|
||||||
Func<bool> callback = () =>
|
|
||||||
{
|
|
||||||
callbackCount++;
|
|
||||||
|
|
||||||
if (callbackCount == 2)
|
|
||||||
{
|
|
||||||
ml.Stop ();
|
|
||||||
}
|
|
||||||
|
|
||||||
return true;
|
|
||||||
};
|
|
||||||
|
|
||||||
var task1 = new Task (() => token1 = ml.TimedEvents.Add (TimeSpan.FromMilliseconds (ms), callback));
|
|
||||||
var task2 = new Task (() => token2 = ml.TimedEvents.Add (TimeSpan.FromMilliseconds (ms), callback));
|
|
||||||
Assert.Null (token1);
|
|
||||||
Assert.Null (token2);
|
|
||||||
task1.Start ();
|
|
||||||
task2.Start ();
|
|
||||||
ml.Run ();
|
|
||||||
Assert.NotNull (token1);
|
|
||||||
Assert.NotNull (token2);
|
|
||||||
await Task.WhenAll (task1, task2);
|
|
||||||
Assert.True (ml.TimedEvents.Remove (token1));
|
|
||||||
Assert.True (ml.TimedEvents.Remove (token2));
|
|
||||||
|
|
||||||
Assert.Equal (2, callbackCount);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Timeout Handler Tests
|
|
||||||
[Fact]
|
|
||||||
public void AddTimer_EventFired ()
|
|
||||||
{
|
|
||||||
var ml = new MainLoop (new FakeMainLoop ());
|
|
||||||
var ms = 100;
|
|
||||||
|
|
||||||
// Use Stopwatch ticks since TimedEvents now uses Stopwatch.GetTimestamp internally
|
|
||||||
long originTicks = Stopwatch.GetTimestamp () * TimeSpan.TicksPerSecond / Stopwatch.Frequency;
|
|
||||||
|
|
||||||
var callbackCount = 0;
|
|
||||||
|
|
||||||
Func<bool> callback = () =>
|
|
||||||
{
|
|
||||||
callbackCount++;
|
|
||||||
|
|
||||||
return true;
|
|
||||||
};
|
|
||||||
|
|
||||||
object sender = null;
|
|
||||||
TimeoutEventArgs args = null;
|
|
||||||
|
|
||||||
ml.TimedEvents.Added += (s, e) =>
|
|
||||||
{
|
|
||||||
sender = s;
|
|
||||||
args = e;
|
|
||||||
};
|
|
||||||
|
|
||||||
object token = ml.TimedEvents.Add (TimeSpan.FromMilliseconds (ms), callback);
|
|
||||||
|
|
||||||
Assert.Same (ml.TimedEvents, sender);
|
|
||||||
Assert.NotNull (args.Timeout);
|
|
||||||
Assert.True (args.Ticks - originTicks >= 100 * TimeSpan.TicksPerMillisecond);
|
|
||||||
}
|
|
||||||
|
|
||||||
[Fact]
|
|
||||||
public void AddTimer_In_Parallel_Wont_Throw ()
|
|
||||||
{
|
|
||||||
var ml = new MainLoop (new FakeMainLoop ());
|
|
||||||
const int ms = 100;
|
|
||||||
object token1 = null, token2 = null;
|
|
||||||
|
|
||||||
var callbackCount = 0;
|
|
||||||
|
|
||||||
Func<bool> callback = () =>
|
|
||||||
{
|
|
||||||
callbackCount++;
|
|
||||||
|
|
||||||
if (callbackCount == 2)
|
|
||||||
{
|
|
||||||
ml.Stop ();
|
|
||||||
}
|
|
||||||
|
|
||||||
return true;
|
|
||||||
};
|
|
||||||
|
|
||||||
Parallel.Invoke (
|
|
||||||
() => token1 = ml.TimedEvents.Add (TimeSpan.FromMilliseconds (ms), callback),
|
|
||||||
() => token2 = ml.TimedEvents.Add (TimeSpan.FromMilliseconds (ms), callback)
|
|
||||||
);
|
|
||||||
ml.Run ();
|
|
||||||
Assert.NotNull (token1);
|
|
||||||
Assert.NotNull (token2);
|
|
||||||
Assert.True (ml.TimedEvents.Remove (token1));
|
|
||||||
Assert.True (ml.TimedEvents.Remove (token2));
|
|
||||||
|
|
||||||
Assert.Equal (2, callbackCount);
|
|
||||||
}
|
|
||||||
|
|
||||||
[Fact]
|
|
||||||
public void AddTimer_Remove_NotCalled ()
|
|
||||||
{
|
|
||||||
var ml = new MainLoop (new FakeMainLoop ());
|
|
||||||
TimeSpan ms = TimeSpan.FromMilliseconds (50);
|
|
||||||
|
|
||||||
// Force stop if 10 iterations
|
|
||||||
var stopCount = 0;
|
|
||||||
|
|
||||||
Func<bool> fnStop = () =>
|
|
||||||
{
|
|
||||||
stopCount++;
|
|
||||||
|
|
||||||
if (stopCount == 10)
|
|
||||||
{
|
|
||||||
ml.Stop ();
|
|
||||||
}
|
|
||||||
|
|
||||||
return true;
|
|
||||||
};
|
|
||||||
ml.TimedEvents.Add (TimeSpan.Zero, fnStop);
|
|
||||||
|
|
||||||
var callbackCount = 0;
|
|
||||||
|
|
||||||
Func<bool> callback = () =>
|
|
||||||
{
|
|
||||||
callbackCount++;
|
|
||||||
|
|
||||||
return true;
|
|
||||||
};
|
|
||||||
|
|
||||||
object token = ml.TimedEvents.Add (ms, callback);
|
|
||||||
Assert.True (ml.TimedEvents.Remove (token));
|
|
||||||
ml.Run ();
|
|
||||||
Assert.Equal (0, callbackCount);
|
|
||||||
}
|
|
||||||
|
|
||||||
[Fact]
|
|
||||||
public void AddTimer_ReturnFalse_StopsBeingCalled ()
|
|
||||||
{
|
|
||||||
var ml = new MainLoop (new FakeMainLoop ());
|
|
||||||
TimeSpan ms = TimeSpan.FromMilliseconds (50);
|
|
||||||
|
|
||||||
// Force stop if 10 iterations
|
|
||||||
var stopCount = 0;
|
|
||||||
|
|
||||||
Func<bool> fnStop = () =>
|
|
||||||
{
|
|
||||||
Thread.Sleep (10); // Sleep to enable timer to fire
|
|
||||||
stopCount++;
|
|
||||||
|
|
||||||
if (stopCount == 10)
|
|
||||||
{
|
|
||||||
ml.Stop ();
|
|
||||||
}
|
|
||||||
|
|
||||||
return true;
|
|
||||||
};
|
|
||||||
ml.TimedEvents.Add (TimeSpan.Zero, fnStop);
|
|
||||||
|
|
||||||
var callbackCount = 0;
|
|
||||||
|
|
||||||
Func<bool> callback = () =>
|
|
||||||
{
|
|
||||||
callbackCount++;
|
|
||||||
|
|
||||||
return false;
|
|
||||||
};
|
|
||||||
|
|
||||||
object token = ml.TimedEvents.Add (ms, callback);
|
|
||||||
ml.Run ();
|
|
||||||
Assert.Equal (1, callbackCount);
|
|
||||||
Assert.Equal (10, stopCount);
|
|
||||||
Assert.False (ml.TimedEvents.Remove (token));
|
|
||||||
}
|
|
||||||
|
|
||||||
[Fact]
|
|
||||||
public void AddTimer_Run_Called ()
|
|
||||||
{
|
|
||||||
var ml = new MainLoop (new FakeMainLoop ());
|
|
||||||
var ms = 100;
|
|
||||||
|
|
||||||
var callbackCount = 0;
|
|
||||||
|
|
||||||
Func<bool> callback = () =>
|
|
||||||
{
|
|
||||||
callbackCount++;
|
|
||||||
ml.Stop ();
|
|
||||||
|
|
||||||
return true;
|
|
||||||
};
|
|
||||||
|
|
||||||
object token = ml.TimedEvents.Add (TimeSpan.FromMilliseconds (ms), callback);
|
|
||||||
ml.Run ();
|
|
||||||
Assert.True (ml.TimedEvents.Remove (token));
|
|
||||||
|
|
||||||
Assert.Equal (1, callbackCount);
|
|
||||||
}
|
|
||||||
|
|
||||||
[Fact]
|
|
||||||
public void AddTimer_Run_CalledAtApproximatelyRightTime ()
|
|
||||||
{
|
|
||||||
var ml = new MainLoop (new FakeMainLoop ());
|
|
||||||
TimeSpan ms = TimeSpan.FromMilliseconds (50);
|
|
||||||
var watch = new Stopwatch ();
|
|
||||||
|
|
||||||
var callbackCount = 0;
|
|
||||||
|
|
||||||
Func<bool> callback = () =>
|
|
||||||
{
|
|
||||||
watch.Stop ();
|
|
||||||
callbackCount++;
|
|
||||||
ml.Stop ();
|
|
||||||
|
|
||||||
return true;
|
|
||||||
};
|
|
||||||
|
|
||||||
object token = ml.TimedEvents.Add (ms, callback);
|
|
||||||
watch.Start ();
|
|
||||||
ml.Run ();
|
|
||||||
|
|
||||||
// +/- 100ms should be good enuf
|
|
||||||
// https://github.com/xunit/assert.xunit/pull/25
|
|
||||||
Assert.Equal (ms * callbackCount, watch.Elapsed, new MillisecondTolerance (100));
|
|
||||||
|
|
||||||
Assert.True (ml.TimedEvents.Remove (token));
|
|
||||||
Assert.Equal (1, callbackCount);
|
|
||||||
}
|
|
||||||
|
|
||||||
[Fact]
|
|
||||||
public void AddTimer_Run_CalledTwiceApproximatelyRightTime ()
|
|
||||||
{
|
|
||||||
var ml = new MainLoop (new FakeMainLoop ());
|
|
||||||
TimeSpan ms = TimeSpan.FromMilliseconds (50);
|
|
||||||
var watch = new Stopwatch ();
|
|
||||||
|
|
||||||
var callbackCount = 0;
|
|
||||||
|
|
||||||
Func<bool> callback = () =>
|
|
||||||
{
|
|
||||||
callbackCount++;
|
|
||||||
|
|
||||||
if (callbackCount == 2)
|
|
||||||
{
|
|
||||||
watch.Stop ();
|
|
||||||
ml.Stop ();
|
|
||||||
}
|
|
||||||
|
|
||||||
return true;
|
|
||||||
};
|
|
||||||
|
|
||||||
object token = ml.TimedEvents.Add (ms, callback);
|
|
||||||
watch.Start ();
|
|
||||||
ml.Run ();
|
|
||||||
|
|
||||||
// +/- 100ms should be good enuf
|
|
||||||
// https://github.com/xunit/assert.xunit/pull/25
|
|
||||||
Assert.Equal (ms * callbackCount, watch.Elapsed, new MillisecondTolerance (100));
|
|
||||||
|
|
||||||
Assert.True (ml.TimedEvents.Remove (token));
|
|
||||||
Assert.Equal (2, callbackCount);
|
|
||||||
}
|
|
||||||
|
|
||||||
[Fact]
|
|
||||||
public void CheckTimersAndIdleHandlers_NoTimers_Returns_False ()
|
|
||||||
{
|
|
||||||
var ml = new MainLoop (new FakeMainLoop ());
|
|
||||||
bool retVal = ml.TimedEvents.CheckTimers(out int waitTimeOut);
|
|
||||||
Assert.False (retVal);
|
|
||||||
Assert.Equal (-1, waitTimeOut);
|
|
||||||
}
|
|
||||||
|
|
||||||
[Fact]
|
|
||||||
public void CheckTimersAndIdleHandlers_NoTimers_WithIdle_Returns_True ()
|
|
||||||
{
|
|
||||||
var ml = new MainLoop (new FakeMainLoop ());
|
|
||||||
Func<bool> fnTrue = () => true;
|
|
||||||
|
|
||||||
ml.TimedEvents.Add (TimeSpan.Zero, fnTrue);
|
|
||||||
bool retVal = ml.TimedEvents.CheckTimers(out int waitTimeOut);
|
|
||||||
Assert.True (retVal);
|
|
||||||
Assert.Equal (0, waitTimeOut);
|
|
||||||
}
|
|
||||||
|
|
||||||
[Fact]
|
|
||||||
public void CheckTimersAndIdleHandlers_With1Timer_Returns_Timer ()
|
|
||||||
{
|
|
||||||
var ml = new MainLoop (new FakeMainLoop ());
|
|
||||||
TimeSpan ms = TimeSpan.FromMilliseconds (50);
|
|
||||||
|
|
||||||
static bool Callback () { return false; }
|
|
||||||
|
|
||||||
_ = ml.TimedEvents.Add (ms, Callback);
|
|
||||||
bool retVal = ml.TimedEvents.CheckTimers (out int waitTimeOut);
|
|
||||||
|
|
||||||
Assert.True (retVal);
|
|
||||||
|
|
||||||
// It should take < 10ms to execute to here
|
|
||||||
Assert.True (ms.TotalMilliseconds <= waitTimeOut + 10);
|
|
||||||
}
|
|
||||||
|
|
||||||
[Fact]
|
|
||||||
public void CheckTimersAndIdleHandlers_With2Timers_Returns_Timer ()
|
|
||||||
{
|
|
||||||
var ml = new MainLoop (new FakeMainLoop ());
|
|
||||||
TimeSpan ms = TimeSpan.FromMilliseconds (50);
|
|
||||||
|
|
||||||
static bool Callback () { return false; }
|
|
||||||
|
|
||||||
_ = ml.TimedEvents.Add (ms, Callback);
|
|
||||||
_ = ml.TimedEvents.Add (ms, Callback);
|
|
||||||
bool retVal = ml.TimedEvents.CheckTimers (out int waitTimeOut);
|
|
||||||
|
|
||||||
Assert.True (retVal);
|
|
||||||
|
|
||||||
// It should take < 10ms to execute to here
|
|
||||||
Assert.True (ms.TotalMilliseconds <= waitTimeOut + 10);
|
|
||||||
}
|
|
||||||
|
|
||||||
[Fact]
|
|
||||||
public void False_Idle_Stops_It_Being_Called_Again ()
|
|
||||||
{
|
|
||||||
var ml = new MainLoop (new FakeMainLoop ());
|
|
||||||
|
|
||||||
var functionCalled = 0;
|
|
||||||
|
|
||||||
Func<bool> fn1 = () =>
|
|
||||||
{
|
|
||||||
functionCalled++;
|
|
||||||
|
|
||||||
if (functionCalled == 10)
|
|
||||||
{
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
return true;
|
|
||||||
};
|
|
||||||
|
|
||||||
// Force stop if 20 iterations
|
|
||||||
var stopCount = 0;
|
|
||||||
|
|
||||||
Func<bool> fnStop = () =>
|
|
||||||
{
|
|
||||||
stopCount++;
|
|
||||||
|
|
||||||
if (stopCount == 20)
|
|
||||||
{
|
|
||||||
ml.Stop ();
|
|
||||||
}
|
|
||||||
|
|
||||||
return true;
|
|
||||||
};
|
|
||||||
|
|
||||||
var a = ml.TimedEvents.Add (TimeSpan.Zero, fnStop);
|
|
||||||
var b = ml.TimedEvents.Add (TimeSpan.Zero, fn1);
|
|
||||||
ml.Run ();
|
|
||||||
Assert.True (ml.TimedEvents.Remove (a));
|
|
||||||
Assert.False (ml.TimedEvents.Remove (a));
|
|
||||||
|
|
||||||
Assert.Equal (10, functionCalled);
|
|
||||||
Assert.Equal (20, stopCount);
|
|
||||||
}
|
|
||||||
|
|
||||||
[Fact]
|
|
||||||
public void Internal_Tests ()
|
|
||||||
{
|
|
||||||
var testMainloop = new TestMainloop ();
|
|
||||||
var mainloop = new MainLoop (testMainloop);
|
|
||||||
Assert.Empty (mainloop.TimedEvents.Timeouts);
|
|
||||||
|
|
||||||
Assert.NotNull (
|
|
||||||
new Terminal.Gui.App.Timeout { Span = new (), Callback = () => true }
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
[Theory]
|
|
||||||
[MemberData (nameof (TestAddTimeout))]
|
|
||||||
public void Mainloop_Invoke_Or_AddTimeout_Can_Be_Used_For_Events_Or_Actions (
|
|
||||||
Action action,
|
|
||||||
string pclickMe,
|
|
||||||
string pcancel,
|
|
||||||
string ppewPew,
|
|
||||||
int pzero,
|
|
||||||
int pone,
|
|
||||||
int ptwo,
|
|
||||||
int pthree,
|
|
||||||
int pfour
|
|
||||||
)
|
|
||||||
{
|
|
||||||
// TODO: Expand this test to test all drivers
|
|
||||||
Application.Init (null, "fakedriver");
|
|
||||||
|
|
||||||
total = 0;
|
|
||||||
btn = null;
|
|
||||||
clickMe = pclickMe;
|
|
||||||
cancel = pcancel;
|
|
||||||
pewPew = ppewPew;
|
|
||||||
zero = pzero;
|
|
||||||
one = pone;
|
|
||||||
two = ptwo;
|
|
||||||
three = pthree;
|
|
||||||
four = pfour;
|
|
||||||
taskCompleted = false;
|
|
||||||
|
|
||||||
var btnLaunch = new Button { Text = "Open Window" };
|
|
||||||
|
|
||||||
btnLaunch.Accepting += (s, e) => action ();
|
|
||||||
|
|
||||||
var top = new Toplevel ();
|
|
||||||
top.Add (btnLaunch);
|
|
||||||
|
|
||||||
int iterations = -1;
|
|
||||||
|
|
||||||
Application.Iteration += (s, a) =>
|
|
||||||
{
|
|
||||||
iterations++;
|
|
||||||
|
|
||||||
if (iterations == 0)
|
|
||||||
{
|
|
||||||
Assert.Null (btn);
|
|
||||||
Assert.Equal (zero, total);
|
|
||||||
Assert.False (btnLaunch.NewKeyDownEvent (Key.Space));
|
|
||||||
|
|
||||||
if (btn == null)
|
|
||||||
{
|
|
||||||
Assert.Null (btn);
|
|
||||||
Assert.Equal (zero, total);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
Assert.Equal (clickMe, btn.Text);
|
|
||||||
Assert.Equal (four, total);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else if (iterations == 1)
|
|
||||||
{
|
|
||||||
Assert.Equal (clickMe, btn.Text);
|
|
||||||
Assert.Equal (zero, total);
|
|
||||||
Assert.False (btn.NewKeyDownEvent (Key.Space));
|
|
||||||
Assert.Equal (cancel, btn.Text);
|
|
||||||
Assert.Equal (one, total);
|
|
||||||
}
|
|
||||||
else if (taskCompleted)
|
|
||||||
{
|
|
||||||
Application.RequestStop ();
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
Application.Run (top);
|
|
||||||
top.Dispose ();
|
|
||||||
|
|
||||||
Assert.True (taskCompleted);
|
|
||||||
Assert.Equal (clickMe, btn.Text);
|
|
||||||
Assert.Equal (four, total);
|
|
||||||
|
|
||||||
Application.Shutdown ();
|
|
||||||
}
|
|
||||||
|
|
||||||
[Fact]
|
|
||||||
public void RemoveIdle_Function_NotCalled ()
|
|
||||||
{
|
|
||||||
var ml = new MainLoop (new FakeMainLoop ());
|
|
||||||
|
|
||||||
var functionCalled = 0;
|
|
||||||
|
|
||||||
Func<bool> fn = () =>
|
|
||||||
{
|
|
||||||
functionCalled++;
|
|
||||||
|
|
||||||
return true;
|
|
||||||
};
|
|
||||||
|
|
||||||
Assert.False (ml.TimedEvents.Remove ("flibble"));
|
|
||||||
ml.RunIteration ();
|
|
||||||
Assert.Equal (0, functionCalled);
|
|
||||||
}
|
|
||||||
|
|
||||||
[Fact]
|
|
||||||
public void Run_Runs_Idle_Stop_Stops_Idle ()
|
|
||||||
{
|
|
||||||
var ml = new MainLoop (new FakeMainLoop ());
|
|
||||||
|
|
||||||
var functionCalled = 0;
|
|
||||||
|
|
||||||
Func<bool> fn = () =>
|
|
||||||
{
|
|
||||||
functionCalled++;
|
|
||||||
|
|
||||||
if (functionCalled == 10)
|
|
||||||
{
|
|
||||||
ml.Stop ();
|
|
||||||
}
|
|
||||||
|
|
||||||
return true;
|
|
||||||
};
|
|
||||||
|
|
||||||
var a = ml.TimedEvents.Add (TimeSpan.Zero, fn);
|
|
||||||
ml.Run ();
|
|
||||||
Assert.True (ml.TimedEvents.Remove (a));
|
|
||||||
|
|
||||||
Assert.Equal (10, functionCalled);
|
|
||||||
}
|
|
||||||
|
|
||||||
[Theory]
|
|
||||||
[InlineData ("fake")]
|
|
||||||
[InlineData ("windows")]
|
|
||||||
[InlineData ("dotnet")]
|
|
||||||
[InlineData ("unix")]
|
|
||||||
public void Application_Invoke_Run_TimedEvents (string driverName)
|
|
||||||
{
|
|
||||||
// Arrange
|
|
||||||
Application.Init (driverName: driverName);
|
|
||||||
var functionCalled = 0;
|
|
||||||
var stopwatch = new Stopwatch ();
|
|
||||||
|
|
||||||
// Act
|
|
||||||
Application.Invoke (() =>
|
|
||||||
{
|
|
||||||
// Stop the stopwatch *after* the function is called.
|
|
||||||
functionCalled++;
|
|
||||||
stopwatch.Stop ();
|
|
||||||
Application.RequestStop ();
|
|
||||||
});
|
|
||||||
|
|
||||||
// Start timing just before running the application loop.
|
|
||||||
stopwatch.Start ();
|
|
||||||
Application.Run ();
|
|
||||||
|
|
||||||
// Assert
|
|
||||||
Assert.NotNull (Application.Top);
|
|
||||||
Application.Top.Dispose ();
|
|
||||||
Application.Shutdown ();
|
|
||||||
Assert.Equal (1, functionCalled);
|
|
||||||
|
|
||||||
// Output the elapsed time for this test case.
|
|
||||||
// ReSharper disable once Xunit.XunitTestWithConsoleOutput
|
|
||||||
// ReSharper disable once LocalizableElement
|
|
||||||
Console.WriteLine ($"[{driverName}] Duration: {stopwatch.Elapsed.TotalMilliseconds:F2} ms");
|
|
||||||
|
|
||||||
// Output elapsed duration to xUnit's test output
|
|
||||||
_output.WriteLine ($"[{driverName}] Duration: {stopwatch.Elapsed.TotalMilliseconds:F2} ms");
|
|
||||||
}
|
|
||||||
|
|
||||||
[Theory]
|
|
||||||
[InlineData ("fake")]
|
|
||||||
[InlineData ("windows")]
|
|
||||||
[InlineData ("dotnet")]
|
|
||||||
[InlineData ("unix")]
|
|
||||||
public void Application_AddTimeout_Run_TimedEvents (string driverName)
|
|
||||||
{
|
|
||||||
// Arrange
|
|
||||||
Application.Init (driverName: driverName);
|
|
||||||
var functionCalled = 0;
|
|
||||||
var stopwatch = new Stopwatch ();
|
|
||||||
|
|
||||||
// Act
|
|
||||||
bool Function ()
|
|
||||||
{
|
|
||||||
functionCalled++;
|
|
||||||
|
|
||||||
if (functionCalled == 10 && Application.Top is { Running: true })
|
|
||||||
{
|
|
||||||
stopwatch.Stop ();
|
|
||||||
Application.RequestStop ();
|
|
||||||
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
Application.AddTimeout (TimeSpan.FromMilliseconds (1), Function);
|
|
||||||
|
|
||||||
// Start timing just before running the application loop.
|
|
||||||
stopwatch.Start ();
|
|
||||||
Application.Run ();
|
|
||||||
|
|
||||||
// Assert
|
|
||||||
Assert.NotNull (Application.Top);
|
|
||||||
Application.Top.Dispose ();
|
|
||||||
Application.Shutdown ();
|
|
||||||
Assert.Equal (10, functionCalled);
|
|
||||||
|
|
||||||
// Output the elapsed time for this test case.
|
|
||||||
// ReSharper disable once Xunit.XunitTestWithConsoleOutput
|
|
||||||
// ReSharper disable once LocalizableElement
|
|
||||||
Console.WriteLine ($"[{driverName}] Duration: {stopwatch.Elapsed.TotalMilliseconds:F2} ms");
|
|
||||||
|
|
||||||
// Output elapsed duration to xUnit's test output
|
|
||||||
_output.WriteLine ($"[{driverName}] Duration: {stopwatch.Elapsed.TotalMilliseconds:F2} ms");
|
|
||||||
}
|
|
||||||
|
|
||||||
public static IEnumerable<object []> TestAddTimeout
|
|
||||||
{
|
|
||||||
get
|
|
||||||
{
|
|
||||||
// Goes fine
|
|
||||||
Action a1 = StartWindow;
|
|
||||||
|
|
||||||
yield return new object [] { a1, "Click Me", "Cancel", "Pew Pew", 0, 1, 2, 3, 4 };
|
|
||||||
|
|
||||||
// Also goes fine
|
|
||||||
Action a2 = () => Application.Invoke (StartWindow);
|
|
||||||
|
|
||||||
yield return new object [] { a2, "Click Me", "Cancel", "Pew Pew", 0, 1, 2, 3, 4 };
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private static async void RunAsyncTest (object sender, EventArgs e)
|
|
||||||
{
|
|
||||||
Assert.Equal (clickMe, btn.Text);
|
|
||||||
Assert.Equal (zero, total);
|
|
||||||
|
|
||||||
btn.Text = "Cancel";
|
|
||||||
Interlocked.Increment (ref total);
|
|
||||||
btn.SetNeedsDraw ();
|
|
||||||
|
|
||||||
await Task.Run (
|
|
||||||
() =>
|
|
||||||
{
|
|
||||||
try
|
|
||||||
{
|
|
||||||
Assert.Equal (cancel, btn.Text);
|
|
||||||
Assert.Equal (one, total);
|
|
||||||
|
|
||||||
RunSql ();
|
|
||||||
}
|
|
||||||
finally
|
|
||||||
{
|
|
||||||
SetReadyToRun ();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
)
|
|
||||||
.ContinueWith (
|
|
||||||
async (s, e) =>
|
|
||||||
{
|
|
||||||
await Task.Delay (1000);
|
|
||||||
Assert.Equal (clickMe, btn.Text);
|
|
||||||
Assert.Equal (three, total);
|
|
||||||
|
|
||||||
Interlocked.Increment (ref total);
|
|
||||||
|
|
||||||
Assert.Equal (clickMe, btn.Text);
|
|
||||||
Assert.Equal (four, total);
|
|
||||||
|
|
||||||
taskCompleted = true;
|
|
||||||
},
|
|
||||||
TaskScheduler.FromCurrentSynchronizationContext ()
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
private static void RunSql ()
|
|
||||||
{
|
|
||||||
Thread.Sleep (100);
|
|
||||||
Assert.Equal (cancel, btn.Text);
|
|
||||||
Assert.Equal (one, total);
|
|
||||||
|
|
||||||
Application.Invoke (
|
|
||||||
() =>
|
|
||||||
{
|
|
||||||
btn.Text = "Pew Pew";
|
|
||||||
Interlocked.Increment (ref total);
|
|
||||||
btn.SetNeedsDraw ();
|
|
||||||
}
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
private static void SetReadyToRun ()
|
|
||||||
{
|
|
||||||
Thread.Sleep (100);
|
|
||||||
Assert.Equal (pewPew, btn.Text);
|
|
||||||
Assert.Equal (two, total);
|
|
||||||
|
|
||||||
Application.Invoke (
|
|
||||||
() =>
|
|
||||||
{
|
|
||||||
btn.Text = "Click Me";
|
|
||||||
Interlocked.Increment (ref total);
|
|
||||||
btn.SetNeedsDraw ();
|
|
||||||
}
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
private static void StartWindow ()
|
|
||||||
{
|
|
||||||
var startWindow = new Window { Modal = true };
|
|
||||||
|
|
||||||
btn = new() { Text = "Click Me" };
|
|
||||||
|
|
||||||
btn.Accepting += RunAsyncTest;
|
|
||||||
|
|
||||||
var totalbtn = new Button { X = Pos.Right (btn), Text = "total" };
|
|
||||||
|
|
||||||
totalbtn.Accepting += (s, e) => { MessageBox.Query ("Count", $"Count is {total}", "Ok"); };
|
|
||||||
|
|
||||||
startWindow.Add (btn);
|
|
||||||
startWindow.Add (totalbtn);
|
|
||||||
|
|
||||||
Application.Run (startWindow);
|
|
||||||
|
|
||||||
Assert.Equal (clickMe, btn.Text);
|
|
||||||
Assert.Equal (four, total);
|
|
||||||
|
|
||||||
Application.RequestStop ();
|
|
||||||
}
|
|
||||||
|
|
||||||
private class MillisecondTolerance : IEqualityComparer<TimeSpan>
|
|
||||||
{
|
|
||||||
public MillisecondTolerance (int tolerance) { _tolerance = tolerance; }
|
|
||||||
private readonly int _tolerance;
|
|
||||||
public bool Equals (TimeSpan x, TimeSpan y) { return Math.Abs (x.Milliseconds - y.Milliseconds) <= _tolerance; }
|
|
||||||
public int GetHashCode (TimeSpan obj) { return obj.GetHashCode (); }
|
|
||||||
}
|
|
||||||
|
|
||||||
private class TestMainloop : IMainLoopDriver
|
|
||||||
{
|
|
||||||
private MainLoop mainLoop;
|
|
||||||
public bool EventsPending () { throw new NotImplementedException (); }
|
|
||||||
public void Iteration () { throw new NotImplementedException (); }
|
|
||||||
public void TearDown () { throw new NotImplementedException (); }
|
|
||||||
public void Setup (MainLoop mainLoop) { this.mainLoop = mainLoop; }
|
|
||||||
public void Wakeup () { throw new NotImplementedException (); }
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -45,7 +45,6 @@ public class RunStateTests
|
|||||||
#endif
|
#endif
|
||||||
|
|
||||||
Assert.Null (Application.Top);
|
Assert.Null (Application.Top);
|
||||||
// Assert.Null (Application.MainLoop);
|
|
||||||
Assert.Null (Application.Driver);
|
Assert.Null (Application.Driver);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -50,8 +50,8 @@ public class ConsoleDriverTests
|
|||||||
public void Init_Inits (Type driverType)
|
public void Init_Inits (Type driverType)
|
||||||
{
|
{
|
||||||
var driver = (IConsoleDriver)Activator.CreateInstance (driverType);
|
var driver = (IConsoleDriver)Activator.CreateInstance (driverType);
|
||||||
MainLoop ml = driver.Init ();
|
driver.Init ();
|
||||||
Assert.NotNull (ml);
|
// Note: MainLoop is no longer returned from Init() as part of legacy MainLoop removal
|
||||||
Assert.NotNull (driver.Clipboard);
|
Assert.NotNull (driver.Clipboard);
|
||||||
Console.ForegroundColor = ConsoleColor.Red;
|
Console.ForegroundColor = ConsoleColor.Red;
|
||||||
Assert.Equal (ConsoleColor.Red, Console.ForegroundColor);
|
Assert.Equal (ConsoleColor.Red, Console.ForegroundColor);
|
||||||
|
|||||||
@@ -12,7 +12,6 @@ public class AllViewsDrawTests (ITestOutputHelper output) : TestsAllViews
|
|||||||
{
|
{
|
||||||
Application.ResetState (true);
|
Application.ResetState (true);
|
||||||
// Required for spinner view that wants to register timeouts
|
// Required for spinner view that wants to register timeouts
|
||||||
Application.MainLoop = new MainLoop (new FakeMainLoop (Application.Driver));
|
|
||||||
|
|
||||||
var view = (View)CreateInstanceIfNotGeneric (viewType);
|
var view = (View)CreateInstanceIfNotGeneric (viewType);
|
||||||
|
|
||||||
|
|||||||
@@ -12,7 +12,6 @@ public class LayoutTests (ITestOutputHelper output) : TestsAllViews
|
|||||||
{
|
{
|
||||||
|
|
||||||
// Required for spinner view that wants to register timeouts
|
// Required for spinner view that wants to register timeouts
|
||||||
Application.MainLoop = new MainLoop (new FakeMainLoop (Application.Driver));
|
|
||||||
|
|
||||||
var view = (View)CreateInstanceIfNotGeneric (viewType);
|
var view = (View)CreateInstanceIfNotGeneric (viewType);
|
||||||
|
|
||||||
|
|||||||
@@ -14,7 +14,6 @@ public class AllViewsTests (ITestOutputHelper output) : TestsAllViews
|
|||||||
public void AllViews_Center_Properly (Type viewType)
|
public void AllViews_Center_Properly (Type viewType)
|
||||||
{
|
{
|
||||||
// Required for spinner view that wants to register timeouts
|
// Required for spinner view that wants to register timeouts
|
||||||
Application.MainLoop = new (new FakeMainLoop (Application.Driver));
|
|
||||||
|
|
||||||
var view = CreateInstanceIfNotGeneric (viewType);
|
var view = CreateInstanceIfNotGeneric (viewType);
|
||||||
|
|
||||||
|
|||||||
@@ -623,7 +623,6 @@ public class MenuBarv1Tests (ITestOutputHelper output)
|
|||||||
Application.RaiseMouseEvent (new () { ScreenPosition = new (20, 5), Flags = MouseFlags.Button1Clicked });
|
Application.RaiseMouseEvent (new () { ScreenPosition = new (20, 5), Flags = MouseFlags.Button1Clicked });
|
||||||
|
|
||||||
// Need to fool MainLoop into thinking it's running
|
// Need to fool MainLoop into thinking it's running
|
||||||
Application.MainLoop.Running = true;
|
|
||||||
AutoInitShutdownAttribute.RunIteration ();
|
AutoInitShutdownAttribute.RunIteration ();
|
||||||
Assert.Equal (items [0], menu.Menus [0].Title);
|
Assert.Equal (items [0], menu.Menus [0].Title);
|
||||||
|
|
||||||
@@ -815,7 +814,6 @@ public class MenuBarv1Tests (ITestOutputHelper output)
|
|||||||
Application.RaiseMouseEvent (new () { ScreenPosition = new (20, 5), Flags = MouseFlags.Button1Clicked });
|
Application.RaiseMouseEvent (new () { ScreenPosition = new (20, 5), Flags = MouseFlags.Button1Clicked });
|
||||||
|
|
||||||
// Need to fool MainLoop into thinking it's running
|
// Need to fool MainLoop into thinking it's running
|
||||||
Application.MainLoop.Running = true;
|
|
||||||
AutoInitShutdownAttribute.RunIteration ();
|
AutoInitShutdownAttribute.RunIteration ();
|
||||||
Assert.Equal (items [0], menu.Menus [0].Title);
|
Assert.Equal (items [0], menu.Menus [0].Title);
|
||||||
|
|
||||||
|
|||||||
@@ -1,300 +0,0 @@
|
|||||||
using Xunit.Abstractions;
|
|
||||||
|
|
||||||
// Alias Console to MockConsole so we don't accidentally use Console
|
|
||||||
|
|
||||||
namespace UnitTests_Parallelizable.DriverTests;
|
|
||||||
|
|
||||||
public class MainLoopDriverTests : UnitTests.Parallelizable.ParallelizableBase
|
|
||||||
{
|
|
||||||
public MainLoopDriverTests (ITestOutputHelper output) { ConsoleDriver.RunningUnitTests = true; }
|
|
||||||
|
|
||||||
[Theory]
|
|
||||||
[InlineData (typeof (FakeDriver), typeof (FakeMainLoop))]
|
|
||||||
//[InlineData (typeof (DotNetDriver), typeof (NetMainLoop))]
|
|
||||||
//[InlineData (typeof (UnixDriver), typeof (UnixMainLoop))]
|
|
||||||
//[InlineData (typeof (WindowsDriver), typeof (WindowsMainLoop))]
|
|
||||||
|
|
||||||
//[InlineData (typeof (ANSIDriver), typeof (AnsiMainLoopDriver))]
|
|
||||||
public void MainLoop_AddTimeout_ValidIdleHandler_ReturnsToken (Type driverType, Type mainLoopDriverType)
|
|
||||||
{
|
|
||||||
var driver = (IConsoleDriver)Activator.CreateInstance (driverType);
|
|
||||||
var mainLoopDriver = (IMainLoopDriver)Activator.CreateInstance (mainLoopDriverType, driver);
|
|
||||||
var mainLoop = new MainLoop (mainLoopDriver);
|
|
||||||
var idleHandlerInvoked = false;
|
|
||||||
|
|
||||||
bool IdleHandler ()
|
|
||||||
{
|
|
||||||
idleHandlerInvoked = true;
|
|
||||||
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
var token = mainLoop.TimedEvents.Add(TimeSpan.Zero, IdleHandler);
|
|
||||||
|
|
||||||
Assert.NotNull (token);
|
|
||||||
Assert.False (idleHandlerInvoked); // Idle handler should not be invoked immediately
|
|
||||||
mainLoop.RunIteration (); // Run an iteration to process the idle handler
|
|
||||||
Assert.True (idleHandlerInvoked); // Idle handler should be invoked after processing
|
|
||||||
mainLoop.Dispose ();
|
|
||||||
}
|
|
||||||
|
|
||||||
[Theory]
|
|
||||||
[InlineData (typeof (FakeDriver), typeof (FakeMainLoop))]
|
|
||||||
//[InlineData (typeof (DotNetDriver), typeof (NetMainLoop))]
|
|
||||||
//[InlineData (typeof (UnixDriver), typeof (UnixMainLoop))]
|
|
||||||
//[InlineData (typeof (WindowsDriver), typeof (WindowsMainLoop))]
|
|
||||||
|
|
||||||
//[InlineData (typeof (ANSIDriver), typeof (AnsiMainLoopDriver))]
|
|
||||||
public void MainLoop_AddTimeout_ValidParameters_ReturnsToken (Type driverType, Type mainLoopDriverType)
|
|
||||||
{
|
|
||||||
var driver = (IConsoleDriver)Activator.CreateInstance (driverType);
|
|
||||||
var mainLoopDriver = (IMainLoopDriver)Activator.CreateInstance (mainLoopDriverType, driver);
|
|
||||||
var mainLoop = new MainLoop (mainLoopDriver);
|
|
||||||
var callbackInvoked = false;
|
|
||||||
|
|
||||||
object token = mainLoop.TimedEvents.Add (
|
|
||||||
TimeSpan.FromMilliseconds (100),
|
|
||||||
() =>
|
|
||||||
{
|
|
||||||
callbackInvoked = true;
|
|
||||||
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
);
|
|
||||||
|
|
||||||
Assert.NotNull (token);
|
|
||||||
mainLoop.RunIteration (); // Run an iteration to process the timeout
|
|
||||||
Assert.False (callbackInvoked); // Callback should not be invoked immediately
|
|
||||||
Thread.Sleep (200); // Wait for the timeout
|
|
||||||
mainLoop.RunIteration (); // Run an iteration to process the timeout
|
|
||||||
Assert.True (callbackInvoked); // Callback should be invoked after the timeout
|
|
||||||
mainLoop.Dispose ();
|
|
||||||
}
|
|
||||||
|
|
||||||
[Theory]
|
|
||||||
[InlineData (typeof (FakeDriver), typeof (FakeMainLoop))]
|
|
||||||
//[InlineData (typeof (DotNetDriver), typeof (NetMainLoop))]
|
|
||||||
//[InlineData (typeof (UnixDriver), typeof (UnixMainLoop))]
|
|
||||||
//[InlineData (typeof (WindowsDriver), typeof (WindowsMainLoop))]
|
|
||||||
|
|
||||||
//[InlineData (typeof (ANSIDriver), typeof (AnsiMainLoopDriver))]
|
|
||||||
public void MainLoop_CheckTimersAndIdleHandlers_IdleHandlersActive_ReturnsTrue (
|
|
||||||
Type driverType,
|
|
||||||
Type mainLoopDriverType
|
|
||||||
)
|
|
||||||
{
|
|
||||||
var driver = (IConsoleDriver)Activator.CreateInstance (driverType);
|
|
||||||
var mainLoopDriver = (IMainLoopDriver)Activator.CreateInstance (mainLoopDriverType, driver);
|
|
||||||
var mainLoop = new MainLoop (mainLoopDriver);
|
|
||||||
|
|
||||||
mainLoop.TimedEvents.Add (TimeSpan.Zero, () => false);
|
|
||||||
bool result = mainLoop.TimedEvents.CheckTimers (out int waitTimeout);
|
|
||||||
|
|
||||||
Assert.True (result);
|
|
||||||
Assert.Equal (0, waitTimeout);
|
|
||||||
mainLoop.Dispose ();
|
|
||||||
}
|
|
||||||
|
|
||||||
[Theory]
|
|
||||||
[InlineData (typeof (FakeDriver), typeof (FakeMainLoop))]
|
|
||||||
//[InlineData (typeof (DotNetDriver), typeof (NetMainLoop))]
|
|
||||||
//[InlineData (typeof (UnixDriver), typeof (UnixMainLoop))]
|
|
||||||
//[InlineData (typeof (WindowsDriver), typeof (WindowsMainLoop))]
|
|
||||||
|
|
||||||
//[InlineData (typeof (ANSIDriver), typeof (AnsiMainLoopDriver))]
|
|
||||||
public void MainLoop_CheckTimers_NoTimersOrIdleHandlers_ReturnsFalse (
|
|
||||||
Type driverType,
|
|
||||||
Type mainLoopDriverType
|
|
||||||
)
|
|
||||||
{
|
|
||||||
var driver = (IConsoleDriver)Activator.CreateInstance (driverType);
|
|
||||||
var mainLoopDriver = (IMainLoopDriver)Activator.CreateInstance (mainLoopDriverType, driver);
|
|
||||||
var mainLoop = new MainLoop (mainLoopDriver);
|
|
||||||
|
|
||||||
bool result = mainLoop.TimedEvents.CheckTimers (out int waitTimeout);
|
|
||||||
|
|
||||||
Assert.False (result);
|
|
||||||
Assert.Equal (-1, waitTimeout);
|
|
||||||
mainLoop.Dispose ();
|
|
||||||
}
|
|
||||||
|
|
||||||
[Theory]
|
|
||||||
[InlineData (typeof (FakeDriver), typeof (FakeMainLoop))]
|
|
||||||
//[InlineData (typeof (DotNetDriver), typeof (NetMainLoop))]
|
|
||||||
//[InlineData (typeof (UnixDriver), typeof (UnixMainLoop))]
|
|
||||||
//[InlineData (typeof (WindowsDriver), typeof (WindowsMainLoop))]
|
|
||||||
|
|
||||||
//[InlineData (typeof (ANSIDriver), typeof (AnsiMainLoopDriver))]
|
|
||||||
public void MainLoop_CheckTimersAndIdleHandlers_TimersActive_ReturnsTrue (
|
|
||||||
Type driverType,
|
|
||||||
Type mainLoopDriverType
|
|
||||||
)
|
|
||||||
{
|
|
||||||
var driver = (IConsoleDriver)Activator.CreateInstance (driverType);
|
|
||||||
var mainLoopDriver = (IMainLoopDriver)Activator.CreateInstance (mainLoopDriverType, driver);
|
|
||||||
var mainLoop = new MainLoop (mainLoopDriver);
|
|
||||||
|
|
||||||
mainLoop.TimedEvents.Add (TimeSpan.FromMilliseconds (100), () => false);
|
|
||||||
bool result = mainLoop.TimedEvents.CheckTimers(out int waitTimeout);
|
|
||||||
|
|
||||||
Assert.True (result);
|
|
||||||
Assert.True (waitTimeout >= 0);
|
|
||||||
mainLoop.Dispose ();
|
|
||||||
}
|
|
||||||
|
|
||||||
[Theory]
|
|
||||||
[InlineData (typeof (FakeDriver), typeof (FakeMainLoop))]
|
|
||||||
//[InlineData (typeof (DotNetDriver), typeof (NetMainLoop))]
|
|
||||||
//[InlineData (typeof (UnixDriver), typeof (UnixMainLoop))]
|
|
||||||
//[InlineData (typeof (WindowsDriver), typeof (WindowsMainLoop))]
|
|
||||||
|
|
||||||
//[InlineData (typeof (ANSIDriver), typeof (AnsiMainLoopDriver))]
|
|
||||||
public void MainLoop_Constructs_Disposes (Type driverType, Type mainLoopDriverType)
|
|
||||||
{
|
|
||||||
var driver = (IConsoleDriver)Activator.CreateInstance (driverType);
|
|
||||||
var mainLoopDriver = (IMainLoopDriver)Activator.CreateInstance (mainLoopDriverType, driver);
|
|
||||||
var mainLoop = new MainLoop (mainLoopDriver);
|
|
||||||
|
|
||||||
// Check default values
|
|
||||||
Assert.NotNull (mainLoop);
|
|
||||||
Assert.Equal (mainLoopDriver, mainLoop.MainLoopDriver);
|
|
||||||
Assert.Empty (mainLoop.TimedEvents.Timeouts);
|
|
||||||
Assert.False (mainLoop.Running);
|
|
||||||
|
|
||||||
// Clean up
|
|
||||||
mainLoop.Dispose ();
|
|
||||||
|
|
||||||
// TODO: It'd be nice if we could really verify IMainLoopDriver.TearDown was called
|
|
||||||
// and that it was actually cleaned up.
|
|
||||||
Assert.Null (mainLoop.MainLoopDriver);
|
|
||||||
Assert.Empty (mainLoop.TimedEvents.Timeouts);
|
|
||||||
Assert.False (mainLoop.Running);
|
|
||||||
}
|
|
||||||
|
|
||||||
[Theory]
|
|
||||||
[InlineData (typeof (FakeDriver), typeof (FakeMainLoop))]
|
|
||||||
//[InlineData (typeof (DotNetDriver), typeof (NetMainLoop))]
|
|
||||||
//[InlineData (typeof (UnixDriver), typeof (UnixMainLoop))]
|
|
||||||
//[InlineData (typeof (WindowsDriver), typeof (WindowsMainLoop))]
|
|
||||||
|
|
||||||
//[InlineData (typeof (ANSIDriver), typeof (AnsiMainLoopDriver))]
|
|
||||||
public void MainLoop_RemoveIdle_InvalidToken_ReturnsFalse (Type driverType, Type mainLoopDriverType)
|
|
||||||
{
|
|
||||||
var driver = (IConsoleDriver)Activator.CreateInstance (driverType);
|
|
||||||
var mainLoopDriver = (IMainLoopDriver)Activator.CreateInstance (mainLoopDriverType, driver);
|
|
||||||
var mainLoop = new MainLoop (mainLoopDriver);
|
|
||||||
|
|
||||||
bool result = mainLoop.TimedEvents.Remove("flibble");
|
|
||||||
|
|
||||||
Assert.False (result);
|
|
||||||
mainLoop.Dispose ();
|
|
||||||
}
|
|
||||||
|
|
||||||
[Theory]
|
|
||||||
[InlineData (typeof (FakeDriver), typeof (FakeMainLoop))]
|
|
||||||
//[InlineData (typeof (DotNetDriver), typeof (NetMainLoop))]
|
|
||||||
//[InlineData (typeof (UnixDriver), typeof (UnixMainLoop))]
|
|
||||||
//[InlineData (typeof (WindowsDriver), typeof (WindowsMainLoop))]
|
|
||||||
|
|
||||||
//[InlineData (typeof (ANSIDriver), typeof (AnsiMainLoopDriver))]
|
|
||||||
public void MainLoop_RemoveIdle_ValidToken_ReturnsTrue (Type driverType, Type mainLoopDriverType)
|
|
||||||
{
|
|
||||||
var driver = (IConsoleDriver)Activator.CreateInstance (driverType);
|
|
||||||
var mainLoopDriver = (IMainLoopDriver)Activator.CreateInstance (mainLoopDriverType, driver);
|
|
||||||
var mainLoop = new MainLoop (mainLoopDriver);
|
|
||||||
|
|
||||||
bool IdleHandler () { return false; }
|
|
||||||
|
|
||||||
|
|
||||||
var token = mainLoop.TimedEvents.Add (TimeSpan.Zero, IdleHandler);
|
|
||||||
bool result = mainLoop.TimedEvents.Remove (token);
|
|
||||||
|
|
||||||
Assert.True (result);
|
|
||||||
mainLoop.Dispose ();
|
|
||||||
}
|
|
||||||
|
|
||||||
[Theory]
|
|
||||||
[InlineData (typeof (FakeDriver), typeof (FakeMainLoop))]
|
|
||||||
//[InlineData (typeof (DotNetDriver), typeof (NetMainLoop))]
|
|
||||||
//[InlineData (typeof (UnixDriver), typeof (UnixMainLoop))]
|
|
||||||
//[InlineData (typeof (WindowsDriver), typeof (WindowsMainLoop))]
|
|
||||||
|
|
||||||
//[InlineData (typeof (ANSIDriver), typeof (AnsiMainLoopDriver))]
|
|
||||||
public void MainLoop_RemoveTimeout_InvalidToken_ReturnsFalse (Type driverType, Type mainLoopDriverType)
|
|
||||||
{
|
|
||||||
var driver = (IConsoleDriver)Activator.CreateInstance (driverType);
|
|
||||||
var mainLoopDriver = (IMainLoopDriver)Activator.CreateInstance (mainLoopDriverType, driver);
|
|
||||||
var mainLoop = new MainLoop (mainLoopDriver);
|
|
||||||
|
|
||||||
bool result = mainLoop.TimedEvents.Remove (new object ());
|
|
||||||
|
|
||||||
Assert.False (result);
|
|
||||||
}
|
|
||||||
|
|
||||||
[Theory]
|
|
||||||
[InlineData (typeof (FakeDriver), typeof (FakeMainLoop))]
|
|
||||||
//[InlineData (typeof (DotNetDriver), typeof (NetMainLoop))]
|
|
||||||
//[InlineData (typeof (UnixDriver), typeof (UnixMainLoop))]
|
|
||||||
//[InlineData (typeof (WindowsDriver), typeof (WindowsMainLoop))]
|
|
||||||
|
|
||||||
//[InlineData (typeof (ANSIDriver), typeof (AnsiMainLoopDriver))]
|
|
||||||
public void MainLoop_RemoveTimeout_ValidToken_ReturnsTrue (Type driverType, Type mainLoopDriverType)
|
|
||||||
{
|
|
||||||
var driver = (IConsoleDriver)Activator.CreateInstance (driverType);
|
|
||||||
var mainLoopDriver = (IMainLoopDriver)Activator.CreateInstance (mainLoopDriverType, driver);
|
|
||||||
var mainLoop = new MainLoop (mainLoopDriver);
|
|
||||||
|
|
||||||
object token = mainLoop.TimedEvents.Add (TimeSpan.FromMilliseconds (100), () => false);
|
|
||||||
bool result = mainLoop.TimedEvents.Remove (token);
|
|
||||||
|
|
||||||
Assert.True (result);
|
|
||||||
mainLoop.Dispose ();
|
|
||||||
}
|
|
||||||
|
|
||||||
[Theory]
|
|
||||||
[InlineData (typeof (FakeDriver), typeof (FakeMainLoop))]
|
|
||||||
//[InlineData (typeof (DotNetDriver), typeof (NetMainLoop))]
|
|
||||||
//[InlineData (typeof (UnixDriver), typeof (UnixMainLoop))]
|
|
||||||
//[InlineData (typeof (WindowsDriver), typeof (WindowsMainLoop))]
|
|
||||||
|
|
||||||
//[InlineData (typeof (ANSIDriver), typeof (AnsiMainLoopDriver))]
|
|
||||||
public void MainLoop_RunIteration_ValidIdleHandler_CallsIdleHandler (Type driverType, Type mainLoopDriverType)
|
|
||||||
{
|
|
||||||
var driver = (IConsoleDriver)Activator.CreateInstance (driverType);
|
|
||||||
var mainLoopDriver = (IMainLoopDriver)Activator.CreateInstance (mainLoopDriverType, driver);
|
|
||||||
var mainLoop = new MainLoop (mainLoopDriver);
|
|
||||||
var idleHandlerInvoked = false;
|
|
||||||
|
|
||||||
Func<bool> idleHandler = () =>
|
|
||||||
{
|
|
||||||
idleHandlerInvoked = true;
|
|
||||||
|
|
||||||
return false;
|
|
||||||
};
|
|
||||||
|
|
||||||
mainLoop.TimedEvents.Add (TimeSpan.Zero, idleHandler);
|
|
||||||
mainLoop.RunIteration (); // Run an iteration to process the idle handler
|
|
||||||
|
|
||||||
Assert.True (idleHandlerInvoked);
|
|
||||||
mainLoop.Dispose ();
|
|
||||||
}
|
|
||||||
|
|
||||||
//[Theory]
|
|
||||||
//[InlineData (typeof (FakeDriver), typeof (FakeMainLoop))]
|
|
||||||
////[InlineData (typeof (DotNetDriver), typeof (NetMainLoop))]
|
|
||||||
////[InlineData (typeof (UnixDriver), typeof (UnixMainLoop))]
|
|
||||||
////[InlineData (typeof (WindowsDriver), typeof (WindowsMainLoop))]
|
|
||||||
//public void MainLoop_Invoke_ValidAction_RunsAction (Type driverType, Type mainLoopDriverType)
|
|
||||||
//{
|
|
||||||
// var driver = (IConsoleDriver)Activator.CreateInstance (driverType);
|
|
||||||
// var mainLoopDriver = (IMainLoopDriver)Activator.CreateInstance (mainLoopDriverType, new object [] { driver });
|
|
||||||
// var mainLoop = new MainLoop (mainLoopDriver);
|
|
||||||
// var actionInvoked = false;
|
|
||||||
|
|
||||||
// mainLoop.Invoke (() => { actionInvoked = true; });
|
|
||||||
// mainLoop.RunIteration (); // Run an iteration to process the action.
|
|
||||||
|
|
||||||
// Assert.True (actionInvoked);
|
|
||||||
// mainLoop.Dispose ();
|
|
||||||
//}
|
|
||||||
}
|
|
||||||
@@ -155,7 +155,7 @@ internal class MockConsoleDriver : IConsoleDriver
|
|||||||
public void UpdateCursor () {}
|
public void UpdateCursor () {}
|
||||||
|
|
||||||
/// <inheritdoc />
|
/// <inheritdoc />
|
||||||
public MainLoop Init () { return null!; }
|
public void Init () { }
|
||||||
|
|
||||||
/// <inheritdoc />
|
/// <inheritdoc />
|
||||||
public void End () { }
|
public void End () { }
|
||||||
|
|||||||
@@ -47,7 +47,6 @@ public class GlobalTestSetup : IDisposable
|
|||||||
// Don't check Application.Force16Colors
|
// Don't check Application.Force16Colors
|
||||||
//Assert.False (Application.Force16Colors);
|
//Assert.False (Application.Force16Colors);
|
||||||
Assert.Null (Application.Driver);
|
Assert.Null (Application.Driver);
|
||||||
Assert.Null (Application.MainLoop);
|
|
||||||
Assert.False (Application.EndAfterFirstIteration);
|
Assert.False (Application.EndAfterFirstIteration);
|
||||||
Assert.Equal (Key.Tab.WithShift, Application.PrevTabKey);
|
Assert.Equal (Key.Tab.WithShift, Application.PrevTabKey);
|
||||||
Assert.Equal (Key.Tab, Application.NextTabKey);
|
Assert.Equal (Key.Tab, Application.NextTabKey);
|
||||||
|
|||||||
@@ -291,6 +291,8 @@ Application.Init();
|
|||||||
|
|
||||||
Terminal.Gui v1 drivers that implement `IConsoleDriver` but not `IConsoleDriverFacade` are still supported through a legacy compatibility layer. However, they do not benefit from the v2 architecture improvements (multi-threading, component separation, etc.).
|
Terminal.Gui v1 drivers that implement `IConsoleDriver` but not `IConsoleDriverFacade` are still supported through a legacy compatibility layer. However, they do not benefit from the v2 architecture improvements (multi-threading, component separation, etc.).
|
||||||
|
|
||||||
|
**Note**: The legacy `MainLoop` infrastructure (including the `MainLoop` class, `IMainLoopDriver` interface, and `FakeMainLoop`) has been removed in favor of the modern architecture. All drivers now use the `MainLoopCoordinator` and `ApplicationMainLoop` system exclusively.
|
||||||
|
|
||||||
## See Also
|
## See Also
|
||||||
|
|
||||||
- @Terminal.Gui.Drivers - API Reference
|
- @Terminal.Gui.Drivers - API Reference
|
||||||
|
|||||||
@@ -456,17 +456,26 @@ Additionally, the `Toggle` event was renamed `CheckStateChanging` and made cance
|
|||||||
+cb.AdvanceCheckState ();
|
+cb.AdvanceCheckState ();
|
||||||
```
|
```
|
||||||
|
|
||||||
## `MainLoop` is no longer accessible from `Application`
|
## `MainLoop` has been removed from `Application`
|
||||||
|
|
||||||
In v1, you could add timeouts via `Application.MainLoop.AddTimeout` among other things. In v2, the `MainLoop` object is internal to `Application` and methods previously accessed via `MainLoop` can now be accessed directly via `Application`
|
In v1, you could add timeouts via `Application.MainLoop.AddTimeout` and access the `MainLoop` object directly. In v2, the legacy `MainLoop` class has been completely removed as part of the architectural modernization. Timeout functionality and other features previously accessed via `MainLoop` are now available directly through `Application` or `ApplicationImpl`.
|
||||||
|
|
||||||
### How to Fix
|
### How to Fix
|
||||||
|
|
||||||
|
Replace any `Application.MainLoop` references:
|
||||||
|
|
||||||
```diff
|
```diff
|
||||||
- Application.MainLoop.AddTimeout (TimeSpan time, Func<MainLoop, bool> callback)
|
- Application.MainLoop.AddTimeout (TimeSpan time, Func<MainLoop, bool> callback)
|
||||||
+ Application.AddTimeout (TimeSpan time, Func<bool> callback)
|
+ Application.AddTimeout (TimeSpan time, Func<bool> callback)
|
||||||
```
|
```
|
||||||
|
|
||||||
|
```diff
|
||||||
|
- Application.MainLoop.Wakeup ()
|
||||||
|
+ // No replacement needed - wakeup is handled automatically by the modern architecture
|
||||||
|
```
|
||||||
|
|
||||||
|
**Note**: The legacy `MainLoop` infrastructure (including `IMainLoopDriver` and `FakeMainLoop`) has been removed. The modern v2 architecture uses `ApplicationImpl`, `MainLoopCoordinator`, and `ApplicationMainLoop` instead.
|
||||||
|
|
||||||
## `SendSubViewXXX` renamed and corrected
|
## `SendSubViewXXX` renamed and corrected
|
||||||
|
|
||||||
In v1, the `View` methods to move SubViews within the SubViews list were poorly named and actually operated in reverse of what their names suggested.
|
In v1, the `View` methods to move SubViews within the SubViews list were poorly named and actually operated in reverse of what their names suggested.
|
||||||
|
|||||||
Binary file not shown.
Binary file not shown.
Reference in New Issue
Block a user