Files
OpenNest/OpenNest.WinForms.Tests/ArchUnitsTests.cs
T
aj a15c54fbaf test(desktop): fail WinForms tests on UI-callback exceptions per STA thread
TestAssemblySetup set the unhandled-exception mode and a ThreadException
handler from a module initializer. WinForms stores both per thread
(ThreadContext/NativeWindow thread statics), so they applied only to the
runner thread that loaded the assembly, never to the STA threads the
tests run on. There, an exception escaping a window message or a
BeginInvoke/SynchronizationContext callback still opened a modal
ThreadExceptionDialog in an interactive session, or was silently ignored
otherwise; the handler would also have logged and swallowed it.

Replace the fifteen copied RunSta helpers with StaTestThread.Run, which
selects UnhandledExceptionMode.ThrowException on each STA thread before
it creates a window, so the exception propagates to the test body and
fails the test. Each class keeps its own timeout and message; all
threads are now background threads. Remove TestAssemblySetup.

StaTestThreadTests covers a throwing BeginInvoke callback through
StaTestThread (fails with the original exception) and, as a control,
the default mode on a plain STA thread (the exception goes to the
thread's handler and never reaches the test body). Cross-compiled on
Linux; Windows execution is the windows-desktop CI job.
2026-10-04 18:40:48 -04:00

53 lines
1.9 KiB
C#

using System.Drawing;
using System.Globalization;
using System.Reflection;
using System.Text.RegularExpressions;
using System.Windows.Forms;
namespace OpenNest.WinForms.Tests;
public class ArchUnitsTests
{
[Fact]
public void ArchitecturalRegexHasExplicitTimeout()
{
var regex = Assert.IsType<Regex>(typeof(ArchUnits)
.GetField("UnitRegex", BindingFlags.Static | BindingFlags.NonPublic)!.GetValue(null));
Assert.Equal(TimeSpan.FromMilliseconds(250), regex.MatchTimeout);
Assert.Equal(RegexOptions.None, regex.Options);
}
[Theory]
[InlineData("5' 6.5\"", 66.5)]
[InlineData("2 feet 3 1/2 inches", 27.5)]
[InlineData("1-1/2\"", 1.5)]
[InlineData("48", 48)]
[InlineData("", 0)]
public void OrdinaryArchitecturalInputsKeepTheirMeaning(string input, double expected)
{
var original = CultureInfo.CurrentCulture;
try
{
CultureInfo.CurrentCulture = CultureInfo.InvariantCulture;
Assert.Equal(expected, ArchUnits.ParseToInches(input));
}
finally { CultureInfo.CurrentCulture = original; }
}
[Fact]
public void InvalidFieldIsRedAndNaNAndCorrectionRestoresIt() => RunSta(() =>
{
using var field = new TextBox { Text = "invalid dimension" };
Assert.True(double.IsNaN(ArchUnits.GetLengthInches(field)));
Assert.Equal(Color.Red, field.ForeColor);
field.Text = "12\"";
Assert.Equal(12, ArchUnits.GetLengthInches(field));
Assert.Equal(SystemColors.WindowText, field.ForeColor);
});
// Actual timeout execution is covered by the shared Regex mechanism in FractionTests;
// these desktop tests deliberately avoid timing-sensitive oversized-input fixtures.
internal static void RunSta(Action action) =>
StaTestThread.Run(action, TimeSpan.FromSeconds(15), "The STA test did not complete.");
}