This commit is contained in:
Tig
2025-11-25 07:13:28 -08:00
163 changed files with 4892 additions and 2983 deletions

View File

@@ -0,0 +1,367 @@
#nullable enable
using System.Globalization;
using System.Runtime.InteropServices;
namespace UnitTests_Parallelizable.ViewsTests;
public class DateFieldTests
{
[Fact]
[TestDate]
public void Constructors_Defaults ()
{
var df = new DateField ();
df.Layout ();
Assert.Equal (DateTime.MinValue, df.Date);
Assert.Equal (1, df.CursorPosition);
Assert.Equal (new (0, 0, 12, 1), df.Frame);
Assert.Equal (" 01/01/0001", df.Text);
DateTime date = DateTime.Now;
df = new (date);
df.Layout ();
Assert.Equal (date, df.Date);
Assert.Equal (1, df.CursorPosition);
Assert.Equal (new (0, 0, 12, 1), df.Frame);
Assert.Equal ($" {date.ToString (CultureInfo.InvariantCulture.DateTimeFormat.ShortDatePattern)}", df.Text);
df = new (date) { X = 1, Y = 2 };
df.Layout ();
Assert.Equal (date, df.Date);
Assert.Equal (1, df.CursorPosition);
Assert.Equal (new (1, 2, 12, 1), df.Frame);
Assert.Equal ($" {date.ToString (CultureInfo.InvariantCulture.DateTimeFormat.ShortDatePattern)}", df.Text);
}
[Fact]
[TestDate]
public void Copy_Paste ()
{
IApplication app = Application.Create();
app.Init("fake");
try
{
var df1 = new DateField (DateTime.Parse ("12/12/1971")) { App = app };
var df2 = new DateField (DateTime.Parse ("12/31/2023")) { App = app };
// Select all text
Assert.True (df2.NewKeyDownEvent (Key.End.WithShift));
Assert.Equal (1, df2.SelectedStart);
Assert.Equal (10, df2.SelectedLength);
Assert.Equal (11, df2.CursorPosition);
// Copy from df2
Assert.True (df2.NewKeyDownEvent (Key.C.WithCtrl));
// Paste into df1
Assert.True (df1.NewKeyDownEvent (Key.V.WithCtrl));
Assert.Equal (" 12/31/2023", df1.Text);
Assert.Equal (11, df1.CursorPosition);
}
finally
{
app.Shutdown();
}
}
[Fact]
[TestDate]
public void CursorPosition_Min_Is_Always_One_Max_Is_Always_Max_Format ()
{
var df = new DateField ();
Assert.Equal (1, df.CursorPosition);
df.CursorPosition = 0;
Assert.Equal (1, df.CursorPosition);
df.CursorPosition = 11;
Assert.Equal (10, df.CursorPosition);
}
[Fact]
[TestDate]
public void CursorPosition_Min_Is_Always_One_Max_Is_Always_Max_Format_After_Selection ()
{
var df = new DateField ();
// Start selection
Assert.True (df.NewKeyDownEvent (Key.CursorLeft.WithShift));
Assert.Equal (1, df.SelectedStart);
Assert.Equal (1, df.SelectedLength);
Assert.Equal (0, df.CursorPosition);
// Without selection
Assert.True (df.NewKeyDownEvent (Key.CursorLeft));
Assert.Equal (-1, df.SelectedStart);
Assert.Equal (0, df.SelectedLength);
Assert.Equal (1, df.CursorPosition);
df.CursorPosition = 10;
Assert.True (df.NewKeyDownEvent (Key.CursorRight.WithShift));
Assert.Equal (10, df.SelectedStart);
Assert.Equal (1, df.SelectedLength);
Assert.Equal (11, df.CursorPosition);
Assert.True (df.NewKeyDownEvent (Key.CursorRight));
Assert.Equal (-1, df.SelectedStart);
Assert.Equal (0, df.SelectedLength);
Assert.Equal (10, df.CursorPosition);
}
[Fact]
[TestDate]
public void Date_Start_From_01_01_0001_And_End_At_12_31_9999 ()
{
var df = new DateField (DateTime.Parse ("01/01/0001"));
Assert.Equal (" 01/01/0001", df.Text);
df.Date = DateTime.Parse ("12/31/9999");
Assert.Equal (" 12/31/9999", df.Text);
}
[Fact]
[TestDate]
public void KeyBindings_Command ()
{
var df = new DateField (DateTime.Parse ("12/12/1971")) { ReadOnly = true };
Assert.True (df.NewKeyDownEvent (Key.Delete));
Assert.Equal (" 12/12/1971", df.Text);
df.ReadOnly = false;
Assert.True (df.NewKeyDownEvent (Key.D.WithCtrl));
Assert.Equal (" 02/12/1971", df.Text);
df.CursorPosition = 4;
df.ReadOnly = true;
Assert.True (df.NewKeyDownEvent (Key.Delete));
Assert.Equal (" 02/12/1971", df.Text);
df.ReadOnly = false;
Assert.True (df.NewKeyDownEvent (Key.Backspace));
Assert.Equal (" 02/02/1971", df.Text);
Assert.True (df.NewKeyDownEvent (Key.Home));
Assert.Equal (1, df.CursorPosition);
Assert.True (df.NewKeyDownEvent (Key.End));
Assert.Equal (10, df.CursorPosition);
Assert.True (df.NewKeyDownEvent (Key.E.WithCtrl));
Assert.Equal (10, df.CursorPosition);
Assert.True (df.NewKeyDownEvent (Key.CursorLeft));
Assert.Equal (9, df.CursorPosition);
Assert.True (df.NewKeyDownEvent (Key.CursorRight));
Assert.Equal (10, df.CursorPosition);
// Non-numerics are ignored
Assert.False (df.NewKeyDownEvent (Key.A));
df.ReadOnly = true;
df.CursorPosition = 1;
Assert.True (df.NewKeyDownEvent (Key.D1));
Assert.Equal (" 02/02/1971", df.Text);
df.ReadOnly = false;
Assert.True (df.NewKeyDownEvent (Key.D1));
Assert.Equal (" 12/02/1971", df.Text);
Assert.Equal (2, df.CursorPosition);
#if UNIX_KEY_BINDINGS
Assert.True (df.NewKeyDownEvent (Key.D.WithAlt));
Assert.Equal (" 10/02/1971", df.Text);
#endif
}
[Fact]
[TestDate]
public void Typing_With_Selection_Normalize_Format ()
{
var df = new DateField (DateTime.Parse ("12/12/1971"))
{
// Start selection at before the first separator /
CursorPosition = 2
};
// Now select the separator /
Assert.True (df.NewKeyDownEvent (Key.CursorRight.WithShift));
Assert.Equal (2, df.SelectedStart);
Assert.Equal (1, df.SelectedLength);
Assert.Equal (3, df.CursorPosition);
// Type 3 over the separator
Assert.True (df.NewKeyDownEvent (Key.D3));
// The format was normalized and replaced again with /
Assert.Equal (" 12/12/1971", df.Text);
Assert.Equal (4, df.CursorPosition);
}
[Fact]
[TestDate]
public void Culture_Pt_Portuguese ()
{
CultureInfo cultureBackup = CultureInfo.CurrentCulture;
try
{
CultureInfo.CurrentCulture = new ("pt-PT");
var df = new DateField (DateTime.Parse ("12/12/1971"))
{
// Move to the first 2
CursorPosition = 2
};
// Type 3 over the separator
Assert.True (df.NewKeyDownEvent (Key.D3));
// If InvariantCulture was used this will fail but not with PT culture
Assert.Equal (" 13/12/1971", df.Text);
Assert.Equal ("13/12/1971", df.Date!.Value.ToString (CultureInfo.CurrentCulture.DateTimeFormat.ShortDatePattern));
Assert.Equal (4, df.CursorPosition);
}
finally
{
CultureInfo.CurrentCulture = cultureBackup;
}
}
/// <summary>
/// Tests specific culture date formatting edge cases.
/// Split from the monolithic culture test for better isolation and maintainability.
/// </summary>
[Theory]
[TestDate]
[InlineData ("en-US", "01/01/1971", '/')]
[InlineData ("en-GB", "01/01/1971", '/')]
[InlineData ("de-DE", "01.01.1971", '.')]
[InlineData ("fr-FR", "01/01/1971", '/')]
[InlineData ("es-ES", "01/01/1971", '/')]
[InlineData ("it-IT", "01/01/1971", '/')]
[InlineData ("ja-JP", "1971/01/01", '/')]
[InlineData ("zh-CN", "1971/01/01", '/')]
[InlineData ("ko-KR", "1971.01.01", '.')]
[InlineData ("pt-PT", "01/01/1971", '/')]
[InlineData ("pt-BR", "01/01/1971", '/')]
[InlineData ("ru-RU", "01.01.1971", '.')]
[InlineData ("nl-NL", "01-01-1971", '-')]
[InlineData ("sv-SE", "1971-01-01", '-')]
[InlineData ("pl-PL", "01.01.1971", '.')]
[InlineData ("tr-TR", "01.01.1971", '.')]
public void Culture_SpecificCultures_ProducesExpectedFormat (string cultureName, string expectedDate, char expectedSeparator)
{
// Skip cultures that may have platform-specific issues
if (RuntimeInformation.IsOSPlatform (OSPlatform.OSX))
{
// macOS has known issues with certain cultures - see #3592
string [] problematicOnMac = { "ar-SA", "en-SA", "en-TH", "th", "th-TH" };
if (problematicOnMac.Contains (cultureName))
{
return;
}
}
CultureInfo cultureBackup = CultureInfo.CurrentCulture;
try
{
var culture = new CultureInfo (cultureName);
// Parse date using InvariantCulture BEFORE changing CurrentCulture
DateTime date = DateTime.Parse ("1/1/1971", CultureInfo.InvariantCulture);
CultureInfo.CurrentCulture = culture;
var df = new DateField (date);
// Verify the text contains the expected separator
Assert.Contains (expectedSeparator, df.Text);
// Verify the date is formatted correctly (accounting for leading space)
Assert.Equal ($" {expectedDate}", df.Text);
}
catch (CultureNotFoundException)
{
// Skip cultures not available on this system
}
finally
{
CultureInfo.CurrentCulture = cultureBackup;
}
}
/// <summary>
/// Tests right-to-left cultures separately due to their complexity.
/// </summary>
[Theory]
[TestDate]
[InlineData ("ar-SA")] // Arabic (Saudi Arabia)
[InlineData ("he-IL")] // Hebrew (Israel)
[InlineData ("fa-IR")] // Persian (Iran)
public void Culture_RightToLeft_HandlesFormatting (string cultureName)
{
if (RuntimeInformation.IsOSPlatform (OSPlatform.OSX))
{
// macOS has known issues with RTL cultures - see #3592
return;
}
CultureInfo cultureBackup = CultureInfo.CurrentCulture;
try
{
var culture = new CultureInfo (cultureName);
// Parse date using InvariantCulture BEFORE changing CurrentCulture
// This is critical because RTL cultures may use different calendars
DateTime date = DateTime.Parse ("1/1/1971", CultureInfo.InvariantCulture);
CultureInfo.CurrentCulture = culture;
var df = new DateField (date);
// Just verify DateField doesn't crash with RTL cultures
// and produces some text
Assert.NotEmpty (df.Text);
Assert.NotNull (df.Date);
}
catch (CultureNotFoundException)
{
// Skip cultures not available on this system
}
finally
{
CultureInfo.CurrentCulture = cultureBackup;
}
}
/// <summary>
/// Tests that DateField handles calendar systems that differ from Gregorian.
/// </summary>
[Theory]
[TestDate]
[InlineData ("th-TH")] // Thai Buddhist calendar
public void Culture_NonGregorianCalendar_HandlesFormatting (string cultureName)
{
if (RuntimeInformation.IsOSPlatform (OSPlatform.OSX))
{
// macOS has known issues with certain calendars - see #3592
return;
}
CultureInfo cultureBackup = CultureInfo.CurrentCulture;
try
{
var culture = new CultureInfo (cultureName);
// Parse date using InvariantCulture BEFORE changing CurrentCulture
DateTime date = DateTime.Parse ("1/1/1971", CultureInfo.InvariantCulture);
CultureInfo.CurrentCulture = culture;
var df = new DateField (date);
// Buddhist calendar is 543 years ahead (1971 + 543 = 2514)
// Just verify it doesn't crash and produces valid output
Assert.NotEmpty (df.Text);
Assert.NotNull (df.Date);
}
catch (CultureNotFoundException)
{
// Skip cultures not available on this system
}
finally
{
CultureInfo.CurrentCulture = cultureBackup;
}
}
}

View File

@@ -0,0 +1,625 @@
#nullable enable
using System.Text;
using UICatalog;
using UnitTests;
using Xunit.Abstractions;
namespace UnitTests_Parallelizable.ViewsTests;
public class MessageBoxTests (ITestOutputHelper output)
{
[Fact]
public void KeyBindings_Enter_Causes_Focused_Button_Click_No_Accept ()
{
IApplication app = Application.Create ();
app.Init ("fake");
try
{
int? result = null;
var iteration = 0;
var btnAcceptCount = 0;
app.Iteration += OnApplicationOnIteration;
app.Run<Toplevel> ().Dispose ();
app.Iteration -= OnApplicationOnIteration;
Assert.Equal (1, result);
Assert.Equal (1, btnAcceptCount);
void OnApplicationOnIteration (object? s, EventArgs<IApplication?> a)
{
iteration++;
switch (iteration)
{
case 1:
result = MessageBox.Query (app, string.Empty, string.Empty, 0, false, "btn0", "btn1");
app.RequestStop ();
break;
case 2:
// Tab to btn2
app.Keyboard.RaiseKeyDownEvent (Key.Tab);
var btn = app.Navigation!.GetFocused () as Button;
btn!.Accepting += (sender, e) => { btnAcceptCount++; };
// Click
app.Keyboard.RaiseKeyDownEvent (Key.Enter);
break;
default:
Assert.Fail ();
break;
}
}
}
finally
{
app.Shutdown ();
}
}
[Fact]
public void KeyBindings_Esc_Closes ()
{
IApplication app = Application.Create ();
app.Init ("fake");
try
{
int? result = 999;
var iteration = 0;
app.Iteration += OnApplicationOnIteration;
app.Run<Toplevel> ().Dispose ();
app.Iteration -= OnApplicationOnIteration;
Assert.Null (result);
void OnApplicationOnIteration (object? s, EventArgs<IApplication?> a)
{
iteration++;
switch (iteration)
{
case 1:
result = MessageBox.Query (app, string.Empty, string.Empty, 0, false, "btn0", "btn1");
app.RequestStop ();
break;
case 2:
app.Keyboard.RaiseKeyDownEvent (Key.Esc);
break;
default:
Assert.Fail ();
break;
}
}
}
finally
{
app.Shutdown ();
}
}
[Fact]
public void KeyBindings_Space_Causes_Focused_Button_Click_No_Accept ()
{
IApplication app = Application.Create ();
app.Init ("fake");
try
{
int? result = null;
var iteration = 0;
var btnAcceptCount = 0;
app.Iteration += OnApplicationOnIteration;
app.Run<Toplevel> ().Dispose ();
app.Iteration -= OnApplicationOnIteration;
Assert.Equal (1, result);
Assert.Equal (1, btnAcceptCount);
void OnApplicationOnIteration (object? s, EventArgs<IApplication?> a)
{
iteration++;
switch (iteration)
{
case 1:
result = MessageBox.Query (app, string.Empty, string.Empty, 0, false, "btn0", "btn1");
app.RequestStop ();
break;
case 2:
// Tab to btn2
app.Keyboard.RaiseKeyDownEvent (Key.Tab);
var btn = app.Navigation!.GetFocused () as Button;
btn!.Accepting += (sender, e) => { btnAcceptCount++; };
app.Keyboard.RaiseKeyDownEvent (Key.Space);
break;
default:
Assert.Fail ();
break;
}
}
}
finally
{
app.Shutdown ();
}
}
[Theory]
[InlineData (@"", false, false, 6, 6, 2, 2)]
[InlineData (@"", false, true, 3, 6, 9, 3)]
[InlineData (@"01234\n-----\n01234", false, false, 1, 6, 13, 3)]
[InlineData (@"01234\n-----\n01234", true, false, 1, 5, 13, 4)]
[InlineData (@"0123456789", false, false, 1, 6, 12, 3)]
[InlineData (@"0123456789", false, true, 1, 5, 12, 4)]
[InlineData (@"01234567890123456789", false, true, 1, 5, 13, 4)]
[InlineData (@"01234567890123456789", true, true, 1, 5, 13, 5)]
[InlineData (@"01234567890123456789\n01234567890123456789", false, true, 1, 5, 13, 4)]
[InlineData (@"01234567890123456789\n01234567890123456789", true, true, 1, 4, 13, 7)]
public void Location_And_Size_Correct (string message, bool wrapMessage, bool hasButton, int expectedX, int expectedY, int expectedW, int expectedH)
{
IApplication app = Application.Create ();
app.Init ("fake");
try
{
int iterations = -1;
app.Driver!.SetScreenSize (15, 15); // 15 x 15 gives us enough room for a button with one char (9x1)
Dialog.DefaultShadow = ShadowStyle.None;
Button.DefaultShadow = ShadowStyle.None;
var mbFrame = Rectangle.Empty;
app.Iteration += OnApplicationOnIteration;
app.Run<Toplevel> ().Dispose ();
app.Iteration -= OnApplicationOnIteration;
Assert.Equal (new (expectedX, expectedY, expectedW, expectedH), mbFrame);
void OnApplicationOnIteration (object? s, EventArgs<IApplication?> a)
{
iterations++;
if (iterations == 0)
{
MessageBox.Query (app, string.Empty, message, 0, wrapMessage, hasButton ? ["0"] : []);
app.RequestStop ();
}
else if (iterations == 1)
{
mbFrame = app.TopRunnable!.Frame;
app.RequestStop ();
}
}
}
finally
{
app.Shutdown ();
}
}
[Fact]
public void Message_With_Spaces_WrapMessage_False ()
{
IApplication app = Application.Create ();
app.Init ("fake");
try
{
int iterations = -1;
var top = new Toplevel ();
top.BorderStyle = LineStyle.None;
app.Driver!.SetScreenSize (20, 10);
var btn =
$"{Glyphs.LeftBracket}{Glyphs.LeftDefaultIndicator} btn {Glyphs.RightDefaultIndicator}{Glyphs.RightBracket}";
// Override CM
MessageBox.DefaultButtonAlignment = Alignment.End;
MessageBox.DefaultBorderStyle = LineStyle.Double;
Dialog.DefaultShadow = ShadowStyle.None;
Button.DefaultShadow = ShadowStyle.None;
app.Iteration += OnApplicationOnIteration;
try
{
app.Run (top);
}
finally
{
app.Iteration -= OnApplicationOnIteration;
top.Dispose ();
}
void OnApplicationOnIteration (object? s, EventArgs<IApplication?> a)
{
iterations++;
if (iterations == 0)
{
var sb = new StringBuilder ();
for (var i = 0; i < 17; i++)
{
sb.Append ("ff ");
}
MessageBox.Query (app, string.Empty, sb.ToString (), 0, false, "btn");
app.RequestStop ();
}
else if (iterations == 2)
{
DriverAssert.AssertDriverContentsWithFrameAre (
@"
╔════════════════╗
║ ff ff ff ff ff ║
║ ⟦► btn ◄⟧║
╚════════════════╝",
output,
app.Driver);
app.RequestStop ();
// Really long text
MessageBox.Query (app, string.Empty, new ('f', 500), 0, false, "btn");
}
else if (iterations == 4)
{
DriverAssert.AssertDriverContentsWithFrameAre (
@"
╔════════════════╗
║ffffffffffffffff║
║ ⟦► btn ◄⟧║
╚════════════════╝",
output,
app.Driver);
app.RequestStop ();
}
}
}
finally
{
app.Shutdown ();
}
}
[Fact]
public void Message_With_Spaces_WrapMessage_True ()
{
IApplication app = Application.Create ();
app.Init ("fake");
try
{
int iterations = -1;
var top = new Toplevel ();
top.BorderStyle = LineStyle.None;
app.Driver!.SetScreenSize (20, 10);
var btn =
$"{Glyphs.LeftBracket}{Glyphs.LeftDefaultIndicator} btn {Glyphs.RightDefaultIndicator}{Glyphs.RightBracket}";
// Override CM
MessageBox.DefaultButtonAlignment = Alignment.End;
MessageBox.DefaultBorderStyle = LineStyle.Double;
Dialog.DefaultShadow = ShadowStyle.None;
Button.DefaultShadow = ShadowStyle.None;
app.Iteration += OnApplicationOnIteration;
try
{
app.Run (top);
}
finally
{
app.Iteration -= OnApplicationOnIteration;
top.Dispose ();
}
void OnApplicationOnIteration (object? s, EventArgs<IApplication?> a)
{
iterations++;
if (iterations == 0)
{
var sb = new StringBuilder ();
for (var i = 0; i < 17; i++)
{
sb.Append ("ff ");
}
MessageBox.Query (app, string.Empty, sb.ToString (), 0, true, "btn");
app.RequestStop ();
}
else if (iterations == 2)
{
DriverAssert.AssertDriverContentsWithFrameAre (
@"
╔══════════════╗
║ff ff ff ff ff║
║ff ff ff ff ff║
║ff ff ff ff ff║
║ ff ff ║
║ ⟦► btn ◄⟧║
╚══════════════╝",
output,
app.Driver);
app.RequestStop ();
// Really long text
MessageBox.Query (app, string.Empty, new ('f', 500), 0, true, "btn");
}
else if (iterations == 4)
{
DriverAssert.AssertDriverContentsWithFrameAre (
@"
╔════════════════╗
║ffffffffffffffff║
║ffffffffffffffff║
║ffffffffffffffff║
║ffffffffffffffff║
║ffffffffffffffff║
║ffffffffffffffff║
║fffffff⟦► btn ◄⟧║
╚════════════════╝",
output,
app.Driver);
app.RequestStop ();
}
}
}
finally
{
app.Shutdown ();
}
}
[Theory (Skip = "Bogus test: Never does anything")]
[InlineData (0, 0, "1")]
[InlineData (1, 1, "1")]
[InlineData (7, 5, "1")]
[InlineData (50, 50, "1")]
[InlineData (0, 0, "message")]
[InlineData (1, 1, "message")]
[InlineData (7, 5, "message")]
[InlineData (50, 50, "message")]
public void Size_Not_Default_Message (int height, int width, string message)
{
IApplication app = Application.Create ();
app.Init ("fake");
try
{
int iterations = -1;
app.Driver!.SetScreenSize (100, 100);
app.Iteration += (s, a) =>
{
iterations++;
if (iterations == 0)
{
MessageBox.Query (app, height, width, string.Empty, message);
app.RequestStop ();
}
else if (iterations == 1)
{
Assert.IsType<Dialog> (app.TopRunnable);
Assert.Equal (new (height, width), app.TopRunnable.Frame.Size);
app.RequestStop ();
}
};
}
finally
{
app.Shutdown ();
}
}
[Theory (Skip = "Bogus test: Never does anything")]
[InlineData (0, 0, "1")]
[InlineData (1, 1, "1")]
[InlineData (7, 5, "1")]
[InlineData (50, 50, "1")]
[InlineData (0, 0, "message")]
[InlineData (1, 1, "message")]
[InlineData (7, 5, "message")]
[InlineData (50, 50, "message")]
public void Size_Not_Default_Message_Button (int height, int width, string message)
{
IApplication app = Application.Create ();
app.Init ("fake");
try
{
int iterations = -1;
app.Iteration += (s, a) =>
{
iterations++;
if (iterations == 0)
{
MessageBox.Query (app, height, width, string.Empty, message, "_Ok");
app.RequestStop ();
}
else if (iterations == 1)
{
Assert.IsType<Dialog> (app.TopRunnable);
Assert.Equal (new (height, width), app.TopRunnable.Frame.Size);
app.RequestStop ();
}
};
}
finally
{
app.Shutdown ();
}
}
[Theory (Skip = "Bogus test: Never does anything")]
[InlineData (0, 0)]
[InlineData (1, 1)]
[InlineData (7, 5)]
[InlineData (50, 50)]
public void Size_Not_Default_No_Message (int height, int width)
{
IApplication app = Application.Create ();
app.Init ("fake");
try
{
int iterations = -1;
app.Iteration += (s, a) =>
{
iterations++;
if (iterations == 0)
{
MessageBox.Query (app, height, width, string.Empty, string.Empty);
app.RequestStop ();
}
else if (iterations == 1)
{
Assert.IsType<Dialog> (app.TopRunnable);
Assert.Equal (new (height, width), app.TopRunnable.Frame.Size);
app.RequestStop ();
}
};
}
finally
{
app.Shutdown ();
}
}
[Fact]
public void UICatalog_AboutBox ()
{
IApplication app = Application.Create ();
app.Init ("fake");
try
{
int iterations = -1;
app.Driver!.SetScreenSize (70, 15);
// Override CM
MessageBox.DefaultButtonAlignment = Alignment.End;
MessageBox.DefaultBorderStyle = LineStyle.Double;
Dialog.DefaultShadow = ShadowStyle.None;
Button.DefaultShadow = ShadowStyle.None;
app.Iteration += OnApplicationOnIteration;
var top = new Toplevel ();
top.BorderStyle = LineStyle.Single;
try
{
app.Run (top);
}
finally
{
app.Iteration -= OnApplicationOnIteration;
top.Dispose ();
}
void OnApplicationOnIteration (object? s, EventArgs<IApplication?> a)
{
iterations++;
if (iterations == 0)
{
MessageBox.Query (
app,
"",
UICatalogTop.GetAboutBoxMessage (),
wrapMessage: false,
buttons: "_Ok");
app.RequestStop ();
}
else if (iterations == 2)
{
var expectedText = """
UI Catalog: A comprehensive sample library and test app for
_______ _ _ _____ _
|__ __| (_) | | / ____| (_)
| | ___ _ __ _ __ ___ _ _ __ __ _| || | __ _ _ _
| |/ _ \ '__| '_ ` _ \| | '_ \ / _` | || | |_ | | | | |
| | __/ | | | | | | | | | | | (_| | || |__| | |_| | |
|_|\___|_| |_| |_| |_|_|_| |_|\__,_|_(_)_____|\__,_|_|
v2 - Pre-Alpha
Ok
""";
DriverAssert.AssertDriverContentsAre (expectedText, output, app.Driver);
app.RequestStop ();
}
}
}
finally
{
app.Shutdown ();
}
}
[Theory]
[MemberData (nameof (AcceptingKeys))]
public void Button_IsDefault_True_Return_His_Index_On_Accepting (Key key)
{
IApplication app = Application.Create ();
app.Init ("fake");
try
{
app.Iteration += OnApplicationOnIteration;
int? res = MessageBox.Query (app, "hey", "IsDefault", "Yes", "No");
app.Iteration -= OnApplicationOnIteration;
Assert.Equal (0, res);
void OnApplicationOnIteration (object? o, EventArgs<IApplication?> iterationEventArgs) { Assert.True (app.Keyboard.RaiseKeyDownEvent (key)); }
}
finally
{
app.Shutdown ();
}
}
public static IEnumerable<object []> AcceptingKeys ()
{
yield return [Key.Enter];
yield return [Key.Space];
}
}

View File

@@ -679,7 +679,6 @@ public class ScrollSliderTests (ITestOutputHelper output) : FakeDriverBase
[Theory]
[SetupFakeApplication]
[InlineData (
3,
10,

View File

@@ -0,0 +1,205 @@
namespace UnitTests_Parallelizable.ViewsTests;
public class TimeFieldTests
{
[Fact]
public void Constructors_Defaults ()
{
var tf = new TimeField ();
tf.Layout ();
Assert.False (tf.IsShortFormat);
Assert.Equal (TimeSpan.MinValue, tf.Time);
Assert.Equal (1, tf.CursorPosition);
Assert.Equal (new Rectangle (0, 0, 10, 1), tf.Frame);
TimeSpan time = DateTime.Now.TimeOfDay;
tf = new TimeField { Time = time };
tf.Layout ();
Assert.False (tf.IsShortFormat);
Assert.Equal (time, tf.Time);
Assert.Equal (1, tf.CursorPosition);
Assert.Equal (new Rectangle (0, 0, 10, 1), tf.Frame);
tf = new TimeField { X = 1, Y = 2, Time = time };
tf.Layout ();
Assert.False (tf.IsShortFormat);
Assert.Equal (time, tf.Time);
Assert.Equal (1, tf.CursorPosition);
Assert.Equal (new Rectangle (1, 2, 10, 1), tf.Frame);
tf = new TimeField { X = 3, Y = 4, Time = time, IsShortFormat = true };
tf.Layout ();
Assert.True (tf.IsShortFormat);
Assert.Equal (time, tf.Time);
Assert.Equal (1, tf.CursorPosition);
Assert.Equal (new Rectangle (3, 4, 7, 1), tf.Frame);
tf.IsShortFormat = false;
tf.Layout ();
Assert.Equal (new Rectangle (3, 4, 10, 1), tf.Frame);
Assert.Equal (10, tf.Width);
}
[Fact]
public void Copy_Paste ()
{
IApplication app = Application.Create();
app.Init("fake");
try
{
var tf1 = new TimeField { Time = TimeSpan.Parse ("12:12:19"), App = app };
var tf2 = new TimeField { Time = TimeSpan.Parse ("12:59:01"), App = app };
// Select all text
Assert.True (tf2.NewKeyDownEvent (Key.End.WithShift));
Assert.Equal (1, tf2.SelectedStart);
Assert.Equal (8, tf2.SelectedLength);
Assert.Equal (9, tf2.CursorPosition);
// Copy from tf2
Assert.True (tf2.NewKeyDownEvent (Key.C.WithCtrl));
// Paste into tf1
Assert.True (tf1.NewKeyDownEvent (Key.V.WithCtrl));
Assert.Equal (" 12:59:01", tf1.Text);
Assert.Equal (9, tf1.CursorPosition);
}
finally
{
app.Shutdown();
}
}
[Fact]
public void CursorPosition_Min_Is_Always_One_Max_Is_Always_Max_Format ()
{
var tf = new TimeField ();
Assert.Equal (1, tf.CursorPosition);
tf.CursorPosition = 0;
Assert.Equal (1, tf.CursorPosition);
tf.CursorPosition = 9;
Assert.Equal (8, tf.CursorPosition);
tf.IsShortFormat = true;
tf.CursorPosition = 0;
Assert.Equal (1, tf.CursorPosition);
tf.CursorPosition = 6;
Assert.Equal (5, tf.CursorPosition);
}
[Fact]
public void CursorPosition_Min_Is_Always_One_Max_Is_Always_Max_Format_After_Selection ()
{
var tf = new TimeField ();
// Start selection
Assert.True (tf.NewKeyDownEvent (Key.CursorLeft.WithShift));
Assert.Equal (1, tf.SelectedStart);
Assert.Equal (1, tf.SelectedLength);
Assert.Equal (0, tf.CursorPosition);
// Without selection
Assert.True (tf.NewKeyDownEvent (Key.CursorLeft));
Assert.Equal (-1, tf.SelectedStart);
Assert.Equal (0, tf.SelectedLength);
Assert.Equal (1, tf.CursorPosition);
tf.CursorPosition = 8;
Assert.True (tf.NewKeyDownEvent (Key.CursorRight.WithShift));
Assert.Equal (8, tf.SelectedStart);
Assert.Equal (1, tf.SelectedLength);
Assert.Equal (9, tf.CursorPosition);
Assert.True (tf.NewKeyDownEvent (Key.CursorRight));
Assert.Equal (-1, tf.SelectedStart);
Assert.Equal (0, tf.SelectedLength);
Assert.Equal (8, tf.CursorPosition);
Assert.False (tf.IsShortFormat);
Assert.False (tf.IsInitialized);
tf.BeginInit ();
tf.EndInit ();
tf.IsShortFormat = true;
Assert.Equal (5, tf.CursorPosition);
// Start selection
Assert.True (tf.NewKeyDownEvent (Key.CursorRight.WithShift));
Assert.Equal (5, tf.SelectedStart);
Assert.Equal (1, tf.SelectedLength);
Assert.Equal (6, tf.CursorPosition);
Assert.True (tf.NewKeyDownEvent (Key.CursorRight));
Assert.Equal (-1, tf.SelectedStart);
Assert.Equal (0, tf.SelectedLength);
Assert.Equal (5, tf.CursorPosition);
}
[Fact]
public void KeyBindings_Command ()
{
var tf = new TimeField { Time = TimeSpan.Parse ("12:12:19") };
tf.BeginInit ();
tf.EndInit ();
Assert.Equal (9, tf.CursorPosition);
tf.CursorPosition = 1;
tf.ReadOnly = true;
Assert.True (tf.NewKeyDownEvent (Key.Delete));
Assert.Equal (" 12:12:19", tf.Text);
tf.ReadOnly = false;
Assert.True (tf.NewKeyDownEvent (Key.D.WithCtrl));
Assert.Equal (" 02:12:19", tf.Text);
tf.CursorPosition = 4;
tf.ReadOnly = true;
Assert.True (tf.NewKeyDownEvent (Key.Delete));
Assert.Equal (" 02:12:19", tf.Text);
tf.ReadOnly = false;
Assert.True (tf.NewKeyDownEvent (Key.Backspace));
Assert.Equal (" 02:02:19", tf.Text);
Assert.True (tf.NewKeyDownEvent (Key.Home));
Assert.Equal (1, tf.CursorPosition);
Assert.True (tf.NewKeyDownEvent (Key.End));
Assert.Equal (8, tf.CursorPosition);
Assert.True (tf.NewKeyDownEvent (Key.A.WithCtrl));
Assert.Equal (1, tf.CursorPosition);
Assert.Equal (9, tf.Text.Length);
Assert.True (tf.NewKeyDownEvent (Key.E.WithCtrl));
Assert.Equal (8, tf.CursorPosition);
Assert.True (tf.NewKeyDownEvent (Key.CursorLeft));
Assert.Equal (7, tf.CursorPosition);
Assert.True (tf.NewKeyDownEvent (Key.CursorRight));
Assert.Equal (8, tf.CursorPosition);
// Non-numerics are ignored
Assert.False (tf.NewKeyDownEvent (Key.A));
tf.ReadOnly = true;
tf.CursorPosition = 1;
Assert.True (tf.NewKeyDownEvent (Key.D1));
Assert.Equal (" 02:02:19", tf.Text);
tf.ReadOnly = false;
Assert.True (tf.NewKeyDownEvent (Key.D1));
Assert.Equal (" 12:02:19", tf.Text);
Assert.Equal (2, tf.CursorPosition);
#if UNIX_KEY_BINDINGS
Assert.True (tf.NewKeyDownEvent (Key.D.WithAlt));
Assert.Equal (" 10:02:19", tf.Text);
#endif
}
[Fact]
public void Typing_With_Selection_Normalize_Format ()
{
var tf = new TimeField { Time = TimeSpan.Parse ("12:12:19") };
// Start selection at before the first separator :
tf.CursorPosition = 2;
// Now select the separator :
Assert.True (tf.NewKeyDownEvent (Key.CursorRight.WithShift));
Assert.Equal (2, tf.SelectedStart);
Assert.Equal (1, tf.SelectedLength);
Assert.Equal (3, tf.CursorPosition);
// Type 3 over the separator
Assert.True (tf.NewKeyDownEvent (Key.D3));
// The format was normalized and replaced again with :
Assert.Equal (" 12:12:19", tf.Text);
Assert.Equal (4, tf.CursorPosition);
}
}