mirror of
https://github.com/gui-cs/Terminal.Gui.git
synced 2025-12-26 15:57:56 +01:00
* Initial plan * Add comprehensive analysis of InvokeLeakTest debugger failure Co-authored-by: tig <585482+tig@users.noreply.github.com> * Add XML documentation to InvokeLeakTest about debugger issues Co-authored-by: tig <585482+tig@users.noreply.github.com> * Add visual timing diagrams for InvokeLeakTest analysis Co-authored-by: tig <585482+tig@users.noreply.github.com> * Add executive summary of InvokeLeakTest investigation Co-authored-by: tig <585482+tig@users.noreply.github.com> * Update analysis with x64 vs ARM confirmation from @tig Co-authored-by: tig <585482+tig@users.noreply.github.com> * Implement Stopwatch-based timing in TimedEvents to fix x64 race condition Co-authored-by: tig <585482+tig@users.noreply.github.com> * Update documentation to reflect fix implementation Co-authored-by: tig <585482+tig@users.noreply.github.com> * Fix test issues and increase TimeSpan.Zero buffer for debugger safety Co-authored-by: tig <585482+tig@users.noreply.github.com> * Add MainLoop.Wakeup() call in Invoke and remove problematic test Co-authored-by: tig <585482+tig@users.noreply.github.com> * Auto-detect debugger and increase test timeout to 500ms Co-authored-by: tig <585482+tig@users.noreply.github.com> * Remove unnecessary MainLoop.Wakeup() call for v2 drivers Co-authored-by: tig <585482+tig@users.noreply.github.com> * Move analysis documents to Tests/StressTests folder Co-authored-by: tig <585482+tig@users.noreply.github.com> * Add test coverage for multiple drivers per @BDisp's suggestion Co-authored-by: tig <585482+tig@users.noreply.github.com> * Revert multi-driver test coverage changes per @tig request 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>
123 lines
3.5 KiB
C#
123 lines
3.5 KiB
C#
using System.Diagnostics;
|
|
|
|
namespace UnitTests.ApplicationTests;
|
|
|
|
/// <summary>
|
|
/// Tests for TimedEvents class, focusing on high-resolution timing with Stopwatch.
|
|
/// </summary>
|
|
public class TimedEventsTests
|
|
{
|
|
[Fact]
|
|
public void HighFrequency_Concurrent_Invocations_No_Lost_Timeouts ()
|
|
{
|
|
var timedEvents = new Terminal.Gui.App.TimedEvents ();
|
|
var counter = 0;
|
|
var expected = 1000;
|
|
var completed = new ManualResetEventSlim (false);
|
|
|
|
// Add many timeouts with TimeSpan.Zero concurrently
|
|
Parallel.For (0, expected, i =>
|
|
{
|
|
timedEvents.Add (TimeSpan.Zero, () =>
|
|
{
|
|
var current = Interlocked.Increment (ref counter);
|
|
if (current == expected)
|
|
{
|
|
completed.Set ();
|
|
}
|
|
return false; // One-shot
|
|
});
|
|
});
|
|
|
|
// Run timers multiple times to ensure all are processed
|
|
for (int i = 0; i < 10; i++)
|
|
{
|
|
timedEvents.RunTimers ();
|
|
if (completed.IsSet)
|
|
{
|
|
break;
|
|
}
|
|
Thread.Sleep (10);
|
|
}
|
|
|
|
Assert.Equal (expected, counter);
|
|
}
|
|
|
|
[Fact]
|
|
public void GetTimestampTicks_Provides_High_Resolution ()
|
|
{
|
|
var timedEvents = new Terminal.Gui.App.TimedEvents ();
|
|
|
|
// Add multiple timeouts with TimeSpan.Zero rapidly
|
|
var timestamps = new List<long> ();
|
|
|
|
// Single event handler to capture all timestamps
|
|
EventHandler<Terminal.Gui.App.TimeoutEventArgs>? handler = null;
|
|
handler = (s, e) =>
|
|
{
|
|
timestamps.Add (e.Ticks);
|
|
};
|
|
|
|
timedEvents.Added += handler;
|
|
|
|
for (int i = 0; i < 100; i++)
|
|
{
|
|
timedEvents.Add (TimeSpan.Zero, () => false);
|
|
}
|
|
|
|
timedEvents.Added -= handler;
|
|
|
|
// Verify that we got timestamps
|
|
Assert.True (timestamps.Count > 0, $"Should have captured timestamps. Got {timestamps.Count}");
|
|
|
|
// Verify that we got unique timestamps (or very close)
|
|
// With Stopwatch, we should have much better resolution than DateTime.UtcNow
|
|
var uniqueTimestamps = timestamps.Distinct ().Count ();
|
|
|
|
// We should have mostly unique timestamps
|
|
// Allow some duplicates due to extreme speed, but should be > 50% unique
|
|
Assert.True (uniqueTimestamps > timestamps.Count / 2,
|
|
$"Expected more unique timestamps. Got {uniqueTimestamps} unique out of {timestamps.Count} total");
|
|
}
|
|
|
|
[Fact]
|
|
public void TimeSpan_Zero_Executes_Immediately ()
|
|
{
|
|
var timedEvents = new Terminal.Gui.App.TimedEvents ();
|
|
var executed = false;
|
|
|
|
timedEvents.Add (TimeSpan.Zero, () =>
|
|
{
|
|
executed = true;
|
|
return false;
|
|
});
|
|
|
|
// Should execute on first RunTimers call
|
|
timedEvents.RunTimers ();
|
|
|
|
Assert.True (executed);
|
|
}
|
|
|
|
[Fact]
|
|
public void Multiple_TimeSpan_Zero_Timeouts_All_Execute ()
|
|
{
|
|
var timedEvents = new Terminal.Gui.App.TimedEvents ();
|
|
var executeCount = 0;
|
|
var expected = 100;
|
|
|
|
for (int i = 0; i < expected; i++)
|
|
{
|
|
timedEvents.Add (TimeSpan.Zero, () =>
|
|
{
|
|
Interlocked.Increment (ref executeCount);
|
|
return false;
|
|
});
|
|
}
|
|
|
|
// Run timers once
|
|
timedEvents.RunTimers ();
|
|
|
|
Assert.Equal (expected, executeCount);
|
|
}
|
|
}
|