Files
Terminal.Gui/Tests/UnitTestsParallelizable/ViewBase/Draw/ViewDrawTextAndLineCanvasTests.cs

468 lines
12 KiB
C#

using System.Text;
using UnitTests;
using Xunit.Abstractions;
namespace ViewBaseTests.Drawing;
public class ViewDrawTextAndLineCanvasTests () : FakeDriverBase
{
#region DrawText Tests
[Fact]
public void DrawText_EmptyText_DoesNotThrow ()
{
IDriver driver = CreateFakeDriver (80, 25);
driver.Clip = new Region (driver.Screen);
var view = new View
{
X = 10,
Y = 10,
Width = 20,
Height = 20,
Driver = driver,
Text = ""
};
view.BeginInit ();
view.EndInit ();
view.LayoutSubViews ();
var exception = Record.Exception (() => view.Draw ());
Assert.Null (exception);
}
[Fact]
public void DrawText_NullText_DoesNotThrow ()
{
IDriver driver = CreateFakeDriver (80, 25);
driver.Clip = new Region (driver.Screen);
var view = new View
{
X = 10,
Y = 10,
Width = 20,
Height = 20,
Driver = driver,
Text = null!
};
view.BeginInit ();
view.EndInit ();
view.LayoutSubViews ();
var exception = Record.Exception (() => view.Draw ());
Assert.Null (exception);
}
[Fact]
public void DrawText_DrawsTextToDriver ()
{
IDriver driver = CreateFakeDriver (80, 25);
driver.Clip = new Region (driver.Screen);
var view = new View
{
X = 1,
Y = 1,
Width = 20,
Height = 20,
Driver = driver,
Text = "Test"
};
view.BeginInit ();
view.EndInit ();
view.LayoutSubViews ();
view.Draw ();
// Text should appear at the content location
Point screenPos = view.ContentToScreen (Point.Empty);
Assert.Equal ("T", driver.Contents! [screenPos.Y, screenPos.X].Grapheme);
Assert.Equal ("e", driver.Contents [screenPos.Y, screenPos.X + 1].Grapheme);
Assert.Equal ("s", driver.Contents [screenPos.Y, screenPos.X + 2].Grapheme);
Assert.Equal ("t", driver.Contents [screenPos.Y, screenPos.X + 3].Grapheme);
}
[Fact]
public void DrawText_WithFocus_UsesFocusAttribute ()
{
IDriver driver = CreateFakeDriver (80, 25);
driver.Clip = new Region (driver.Screen);
var view = new View
{
X = 10,
Y = 10,
Width = 20,
Height = 20,
Driver = driver,
Text = "Test",
CanFocus = true
};
view.BeginInit ();
view.EndInit ();
view.LayoutSubViews ();
view.SetFocus ();
view.Draw ();
// Text should use focus attribute
Point screenPos = view.ContentToScreen (Point.Empty);
Attribute expectedAttr = view.GetAttributeForRole (VisualRole.Focus);
Assert.Equal (expectedAttr, driver.Contents! [screenPos.Y, screenPos.X].Attribute);
}
[Fact]
public void DrawText_WithoutFocus_UsesNormalAttribute ()
{
IDriver driver = CreateFakeDriver (80, 25);
driver.Clip = new Region (driver.Screen);
var view = new View
{
X = 10,
Y = 10,
Width = 20,
Height = 20,
Driver = driver,
Text = "Test",
CanFocus = true
};
view.BeginInit ();
view.EndInit ();
view.LayoutSubViews ();
view.Draw ();
// Text should use normal attribute
Point screenPos = view.ContentToScreen (Point.Empty);
Attribute expectedAttr = view.GetAttributeForRole (VisualRole.Normal);
Assert.Equal (expectedAttr, driver.Contents! [screenPos.Y, screenPos.X].Attribute);
}
[Fact]
public void DrawText_SetsSubViewNeedsDraw ()
{
IDriver driver = CreateFakeDriver (80, 25);
driver.Clip = new Region (driver.Screen);
var view = new View
{
X = 10,
Y = 10,
Width = 20,
Height = 20,
Driver = driver,
Text = "Test"
};
var child = new View { X = 0, Y = 0, Width = 10, Height = 10 };
view.Add (child);
view.BeginInit ();
view.EndInit ();
view.LayoutSubViews ();
// Clear SubViewNeedsDraw
view.Draw ();
Assert.False (view.SubViewNeedsDraw);
// Call DrawText directly which should set SubViewNeedsDraw
view.DrawText ();
// SubViews need to be redrawn since text was drawn over them
Assert.True (view.SubViewNeedsDraw);
}
[Fact]
public void DrawingText_Event_Raised ()
{
IDriver driver = CreateFakeDriver (80, 25);
driver.Clip = new Region (driver.Screen);
bool eventRaised = false;
var view = new View
{
X = 10,
Y = 10,
Width = 20,
Height = 20,
Driver = driver,
Text = "Test"
};
view.BeginInit ();
view.EndInit ();
view.LayoutSubViews ();
view.DrawingText += (s, e) => eventRaised = true;
view.Draw ();
Assert.True (eventRaised);
}
#endregion
#region LineCanvas Tests
[Fact]
public void LineCanvas_InitiallyEmpty ()
{
var view = new View ();
Assert.NotNull (view.LineCanvas);
Assert.Equal (Rectangle.Empty, view.LineCanvas.Bounds);
}
[Fact]
public void RenderLineCanvas_DrawsLines ()
{
IDriver driver = CreateFakeDriver (80, 25);
driver.Clip = new Region (driver.Screen);
var view = new View
{
X = 10,
Y = 10,
Width = 20,
Height = 20,
Driver = driver
};
view.BeginInit ();
view.EndInit ();
view.LayoutSubViews ();
// Add a line to the canvas
Point screenPos = new Point (15, 15);
view.LineCanvas.AddLine (screenPos, 5, Orientation.Horizontal, LineStyle.Single);
view.RenderLineCanvas (null);
// Verify the line was drawn (check for horizontal line character)
for (int i = 0; i < 5; i++)
{
Assert.NotEqual (" ", driver.Contents! [screenPos.Y, screenPos.X + i].Grapheme);
}
}
[Fact]
public void RenderLineCanvas_ClearsAfterRendering ()
{
IDriver driver = CreateFakeDriver (80, 25);
driver.Clip = new Region (driver.Screen);
var view = new View
{
X = 10,
Y = 10,
Width = 20,
Height = 20,
Driver = driver
};
view.BeginInit ();
view.EndInit ();
view.LayoutSubViews ();
// Add a line to the canvas
view.LineCanvas.AddLine (new Point (15, 15), 5, Orientation.Horizontal, LineStyle.Single);
Assert.NotEqual (Rectangle.Empty, view.LineCanvas.Bounds);
view.RenderLineCanvas (null);
// LineCanvas should be cleared after rendering
Assert.Equal (Rectangle.Empty, view.LineCanvas.Bounds);
}
[Fact]
public void RenderLineCanvas_WithSuperViewRendersLineCanvas_DoesNotClear ()
{
IDriver driver = CreateFakeDriver (80, 25);
driver.Clip = new Region (driver.Screen);
var view = new View
{
X = 10,
Y = 10,
Width = 20,
Height = 20,
Driver = driver,
SuperViewRendersLineCanvas = true
};
view.BeginInit ();
view.EndInit ();
view.LayoutSubViews ();
// Add a line to the canvas
view.LineCanvas.AddLine (new Point (15, 15), 5, Orientation.Horizontal, LineStyle.Single);
Rectangle boundsBefore = view.LineCanvas.Bounds;
view.RenderLineCanvas (null);
// LineCanvas should NOT be cleared when SuperViewRendersLineCanvas is true
Assert.Equal (boundsBefore, view.LineCanvas.Bounds);
}
[Fact]
public void SuperViewRendersLineCanvas_MergesWithParentCanvas ()
{
IDriver driver = CreateFakeDriver (80, 25);
driver.Clip = new Region (driver.Screen);
var parent = new View
{
X = 10,
Y = 10,
Width = 50,
Height = 50,
Driver = driver
};
var child = new View
{
X = 5,
Y = 5,
Width = 30,
Height = 30,
SuperViewRendersLineCanvas = true
};
parent.Add (child);
parent.BeginInit ();
parent.EndInit ();
parent.LayoutSubViews ();
// Add a line to child's canvas
child.LineCanvas.AddLine (new Point (20, 20), 5, Orientation.Horizontal, LineStyle.Single);
Assert.NotEqual (Rectangle.Empty, child.LineCanvas.Bounds);
Assert.Equal (Rectangle.Empty, parent.LineCanvas.Bounds);
parent.Draw ();
// Child's canvas should have been merged into parent's
// and child's canvas should be cleared
Assert.Equal (Rectangle.Empty, child.LineCanvas.Bounds);
}
[Fact]
public void OnRenderingLineCanvas_CanPreventRendering ()
{
IDriver driver = CreateFakeDriver (80, 25);
driver.Clip = new Region (driver.Screen);
var view = new TestView
{
X = 10,
Y = 10,
Width = 20,
Height = 20,
Driver = driver,
PreventRenderLineCanvas = true
};
view.BeginInit ();
view.EndInit ();
view.LayoutSubViews ();
// Add a line to the canvas
Point screenPos = new Point (15, 15);
view.LineCanvas.AddLine (screenPos, 5, Orientation.Horizontal, LineStyle.Single);
view.Draw ();
// When OnRenderingLineCanvas returns true, RenderLineCanvas is not called
// So the LineCanvas should still have lines (not cleared)
// BUT because SuperViewRendersLineCanvas is false (default), the LineCanvas
// gets cleared during the draw cycle anyway. We need to check that the
// line was NOT actually rendered to the driver.
bool lineRendered = true;
for (int i = 0; i < 5; i++)
{
if (driver.Contents! [screenPos.Y, screenPos.X + i].Grapheme == " ")
{
lineRendered = false;
break;
}
}
Assert.False (lineRendered);
}
#endregion
#region SuperViewRendersLineCanvas Tests
[Fact]
public void SuperViewRendersLineCanvas_DefaultFalse ()
{
var view = new View ();
Assert.False (view.SuperViewRendersLineCanvas);
}
[Fact]
public void SuperViewRendersLineCanvas_CanBeSet ()
{
var view = new View { SuperViewRendersLineCanvas = true };
Assert.True (view.SuperViewRendersLineCanvas);
}
[Fact]
public void Draw_WithSuperViewRendersLineCanvas_SetsNeedsDraw ()
{
IDriver driver = CreateFakeDriver (80, 25);
driver.Clip = new Region (driver.Screen);
var parent = new View
{
X = 10,
Y = 10,
Width = 50,
Height = 50,
Driver = driver
};
var child = new View
{
X = 5,
Y = 5,
Width = 30,
Height = 30,
SuperViewRendersLineCanvas = true
};
parent.Add (child);
parent.BeginInit ();
parent.EndInit ();
parent.LayoutSubViews ();
// Draw once to clear NeedsDraw
parent.Draw ();
Assert.False (child.NeedsDraw);
// Draw again - child with SuperViewRendersLineCanvas should be redrawn
parent.Draw ();
// The child should have been set to NeedsDraw during DrawSubViews
// This is verified by the fact that it was drawn (we can't check NeedsDraw after Draw)
}
#endregion
#region Helper Test View
private class TestView : View
{
public bool PreventRenderLineCanvas { get; set; }
protected override bool OnRenderingLineCanvas ()
{
return PreventRenderLineCanvas || base.OnRenderingLineCanvas ();
}
}
#endregion
}