ShadowStyletests.cs 5.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157
  1. using UnitTests;
  2. using Xunit.Abstractions;
  3. namespace ViewBaseTests.Adornments;
  4. [Collection ("Global Test Setup")]
  5. public class ShadowStyleTests (ITestOutputHelper output)
  6. {
  7. private readonly ITestOutputHelper _output = output;
  8. [Fact]
  9. public void Default_None ()
  10. {
  11. var view = new View ();
  12. Assert.Equal (ShadowStyle.None, view.ShadowStyle);
  13. Assert.Equal (ShadowStyle.None, view.Margin!.ShadowStyle);
  14. view.Dispose ();
  15. }
  16. [Theory]
  17. [InlineData (ShadowStyle.None)]
  18. [InlineData (ShadowStyle.Opaque)]
  19. [InlineData (ShadowStyle.Transparent)]
  20. public void Set_View_Sets_Margin (ShadowStyle style)
  21. {
  22. var view = new View ();
  23. view.ShadowStyle = style;
  24. Assert.Equal (style, view.ShadowStyle);
  25. Assert.Equal (style, view.Margin!.ShadowStyle);
  26. view.Dispose ();
  27. }
  28. [Theory]
  29. [InlineData (ShadowStyle.None, 0, 0, 0, 0)]
  30. [InlineData (ShadowStyle.Opaque, 0, 0, 1, 1)]
  31. [InlineData (ShadowStyle.Transparent, 0, 0, 1, 1)]
  32. public void ShadowStyle_Margin_Thickness (ShadowStyle style, int expectedLeft, int expectedTop, int expectedRight, int expectedBottom)
  33. {
  34. var superView = new View
  35. {
  36. Height = 10, Width = 10
  37. };
  38. View view = new ()
  39. {
  40. Width = Dim.Auto (),
  41. Height = Dim.Auto (),
  42. Text = "0123",
  43. HighlightStates = MouseState.Pressed,
  44. ShadowStyle = style,
  45. CanFocus = true
  46. };
  47. superView.Add (view);
  48. superView.BeginInit ();
  49. superView.EndInit ();
  50. Assert.Equal (new (expectedLeft, expectedTop, expectedRight, expectedBottom), view.Margin!.Thickness);
  51. }
  52. [Theory]
  53. [InlineData (ShadowStyle.None, 3)]
  54. [InlineData (ShadowStyle.Opaque, 4)]
  55. [InlineData (ShadowStyle.Transparent, 4)]
  56. public void Style_Changes_Margin_Thickness (ShadowStyle style, int expected)
  57. {
  58. var view = new View ();
  59. view.Margin!.Thickness = new (3);
  60. view.ShadowStyle = style;
  61. Assert.Equal (new (3, 3, expected, expected), view.Margin.Thickness);
  62. view.ShadowStyle = ShadowStyle.None;
  63. Assert.Equal (new (3), view.Margin.Thickness);
  64. view.Dispose ();
  65. }
  66. [Fact]
  67. public void TransparentShadow_Draws_Transparent_At_Driver_Output ()
  68. {
  69. // Arrange
  70. IApplication app = Application.Create ();
  71. app.Init ("fake");
  72. app.Driver!.SetScreenSize (5, 3);
  73. // Force 16-bit colors off to get predictable RGB output
  74. app.Driver.Force16Colors = false;
  75. var superView = new Runnable
  76. {
  77. Width = Dim.Fill (),
  78. Height = Dim.Fill (),
  79. Text = "ABC".Repeat (40)!
  80. };
  81. superView.SetScheme (new (new Attribute (Color.White, Color.Blue)));
  82. superView.TextFormatter.WordWrap = true;
  83. // Create an overlapped view with transparent shadow
  84. var overlappedView = new View
  85. {
  86. Width = 4,
  87. Height = 2,
  88. Text = "123",
  89. Arrangement = ViewArrangement.Overlapped,
  90. ShadowStyle = ShadowStyle.Transparent
  91. };
  92. overlappedView.SetScheme (new (new Attribute (Color.Black, Color.Green)));
  93. superView.Add (overlappedView);
  94. // Act
  95. SessionToken? token = app.Begin (superView);
  96. app.LayoutAndDraw ();
  97. app.Driver.Refresh ();
  98. // Assert
  99. _output.WriteLine ("Actual driver contents:");
  100. _output.WriteLine (app.Driver.ToString ());
  101. _output.WriteLine ("\nActual driver output:");
  102. string? output = app.Driver.GetOutput ().GetLastOutput ();
  103. _output.WriteLine (output);
  104. DriverAssert.AssertDriverOutputIs ("""
  105. \x1b[38;2;0;0;0m\x1b[48;2;0;128;0m123\x1b[38;2;0;0;0m\x1b[48;2;189;189;189mA\x1b[38;2;0;0;255m\x1b[48;2;255;255;255mBC\x1b[38;2;0;0;0m\x1b[48;2;189;189;189mABC\x1b[38;2;0;0;255m\x1b[48;2;255;255;255mABCABC
  106. """, _output, app.Driver);
  107. // The output should contain ANSI color codes for the transparent shadow
  108. // which will have dimmed colors compared to the original
  109. Assert.Contains ("\x1b[38;2;", output); // Should have RGB foreground color codes
  110. Assert.Contains ("\x1b[48;2;", output); // Should have RGB background color codes
  111. // Verify driver contents show the background text in shadow areas
  112. int shadowX = overlappedView.Frame.X + overlappedView.Frame.Width;
  113. int shadowY = overlappedView.Frame.Y + overlappedView.Frame.Height;
  114. Cell shadowCell = app.Driver.Contents! [shadowY, shadowX];
  115. _output.WriteLine ($"\nShadow cell at [{shadowY},{shadowX}]: Grapheme='{shadowCell.Grapheme}', Attr={shadowCell.Attribute}");
  116. // The grapheme should be from background text
  117. Assert.NotEqual (string.Empty, shadowCell.Grapheme);
  118. Assert.Contains (shadowCell.Grapheme, "ABC"); // Should be one of the background characters
  119. // Cleanup
  120. if (token is { })
  121. {
  122. app.End (token);
  123. }
  124. superView.Dispose ();
  125. app.Dispose ();
  126. }
  127. }