OutputBaseTests.cs 7.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218
  1. #nullable enable
  2. namespace DriverTests;
  3. public class OutputBaseTests
  4. {
  5. [Fact]
  6. public void ToAnsi_SingleCell_NoAttribute_ReturnsGraphemeAndNewline ()
  7. {
  8. // Arrange
  9. var output = new FakeOutput ();
  10. IOutputBuffer buffer = output.LastBuffer!;
  11. buffer.SetSize (1, 1);
  12. // Act
  13. buffer.AddStr ("A");
  14. string ansi = output.ToAnsi (buffer);
  15. // Assert: single grapheme plus newline (BuildAnsiForRegion appends a newline per row)
  16. Assert.Contains ("A" + Environment.NewLine, ansi);
  17. }
  18. [Theory]
  19. [InlineData (true, false)]
  20. [InlineData (true, true)]
  21. [InlineData (false, false)]
  22. [InlineData (false, true)]
  23. public void ToAnsi_WithAttribute_AppendsCorrectColorSequence_BasedOnIsLegacyConsole_And_Force16Colors (bool isLegacyConsole, bool force16Colors)
  24. {
  25. // Arrange
  26. var output = new FakeOutput { IsLegacyConsole = isLegacyConsole };
  27. // Create DriverImpl and associate it with the FakeOutput to test Sixel output
  28. IDriver driver = new DriverImpl (
  29. new FakeInputProcessor (null!),
  30. new OutputBufferImpl (),
  31. output,
  32. new (new AnsiResponseParser ()),
  33. new SizeMonitorImpl (output));
  34. driver.Force16Colors = force16Colors;
  35. IOutputBuffer buffer = output.LastBuffer!;
  36. buffer.SetSize (1, 1);
  37. // Use a known RGB color and attribute
  38. var fg = new Color (1, 2, 3);
  39. var bg = new Color (4, 5, 6);
  40. buffer.CurrentAttribute = new Attribute (fg, bg);
  41. buffer.AddStr ("X");
  42. // Act
  43. string ansi = output.ToAnsi (buffer);
  44. // Assert: when true color expected, we should see the RGB CSI; otherwise we should see the 16-color CSI
  45. if (!isLegacyConsole && !force16Colors)
  46. {
  47. Assert.Contains ("\u001b[38;2;1;2;3m", ansi);
  48. }
  49. else if (!isLegacyConsole && force16Colors)
  50. {
  51. var expected16 = EscSeqUtils.CSI_SetForegroundColor (fg.GetAnsiColorCode ());
  52. Assert.Contains (expected16, ansi);
  53. }
  54. else
  55. {
  56. var expected16 = (ConsoleColor)fg.GetClosestNamedColor16 ();
  57. Assert.Equal (ConsoleColor.Black, expected16);
  58. Assert.DoesNotContain ('\u001b', ansi);
  59. }
  60. // Grapheme and newline should always be present
  61. Assert.Contains ("X" + Environment.NewLine, ansi);
  62. }
  63. [Fact]
  64. public void Write_WritesDirtyCellsAndClearsDirtyFlags ()
  65. {
  66. // Arrange
  67. var output = new FakeOutput ();
  68. IOutputBuffer buffer = output.LastBuffer!;
  69. buffer.SetSize (2, 1);
  70. // Mark two characters as dirty by writing them into the buffer
  71. buffer.AddStr ("AB");
  72. // Sanity: ensure cells are dirty before calling Write
  73. Assert.True (buffer.Contents! [0, 0].IsDirty);
  74. Assert.True (buffer.Contents! [0, 1].IsDirty);
  75. // Act
  76. output.Write (buffer); // calls OutputBase.Write via FakeOutput
  77. // Assert: content was written to the fake output and dirty flags cleared
  78. Assert.Contains ("AB", output.Output);
  79. Assert.False (buffer.Contents! [0, 0].IsDirty);
  80. Assert.False (buffer.Contents! [0, 1].IsDirty);
  81. }
  82. [Theory]
  83. [InlineData (true)]
  84. [InlineData (false)]
  85. public void Write_Virtual_Or_NonVirtual_Uses_WriteToConsole_And_Clears_Dirty_Flags (bool isLegacyConsole)
  86. {
  87. // Arrange
  88. // FakeOutput exposes this because it's in test scope
  89. var output = new FakeOutput { IsLegacyConsole = isLegacyConsole };
  90. IOutputBuffer buffer = output.LastBuffer!;
  91. buffer.SetSize (3, 1);
  92. // Write 'A' at col 0 and 'C' at col 2; leave col 1 untouched (not dirty)
  93. buffer.Move (0, 0);
  94. buffer.AddStr ("A");
  95. buffer.Move (2, 0);
  96. buffer.AddStr ("C");
  97. // Confirm some dirtiness before to write
  98. Assert.True (buffer.Contents! [0, 0].IsDirty);
  99. Assert.True (buffer.Contents! [0, 2].IsDirty);
  100. // Act
  101. output.Write (buffer);
  102. // Assert: both characters were written (use Contains to avoid CI side effects)
  103. Assert.Contains ("A", output.Output);
  104. Assert.Contains ("C", output.Output);
  105. // Dirty flags cleared for the written cells
  106. Assert.False (buffer.Contents! [0, 0].IsDirty);
  107. Assert.False (buffer.Contents! [0, 2].IsDirty);
  108. // Verify SetCursorPositionImpl was invoked by WriteToConsole (cursor set to a written column)
  109. Assert.Equal (new Point (0, 0), output.GetCursorPosition ());
  110. // Now write 'X' at col 0 to verify subsequent writes also work
  111. buffer.Move (0, 0);
  112. buffer.AddStr ("X");
  113. // Confirm dirtiness state before to write
  114. Assert.True (buffer.Contents! [0, 0].IsDirty);
  115. Assert.False (buffer.Contents! [0, 2].IsDirty);
  116. output.Write (buffer);
  117. // Assert: both characters were written (use Contains to avoid CI side effects)
  118. Assert.Contains ("A", output.Output);
  119. Assert.Contains ("C", output.Output);
  120. // Dirty flags cleared for the written cells
  121. Assert.False (buffer.Contents! [0, 0].IsDirty);
  122. Assert.False (buffer.Contents! [0, 2].IsDirty);
  123. // Verify SetCursorPositionImpl was invoked by WriteToConsole (cursor set to a written column)
  124. Assert.Equal (new Point (2, 0), output.GetCursorPosition ());
  125. }
  126. [Theory]
  127. [InlineData (true)]
  128. [InlineData (false)]
  129. public void Write_EmitsSixelDataAndPositionsCursor (bool isLegacyConsole)
  130. {
  131. // Arrange
  132. var output = new FakeOutput ();
  133. IOutputBuffer buffer = output.LastBuffer!;
  134. buffer.SetSize (1, 1);
  135. // Ensure the buffer has some content so Write traverses rows
  136. buffer.AddStr (".");
  137. // Create a Sixel to render
  138. var s = new SixelToRender
  139. {
  140. SixelData = "SIXEL-DATA",
  141. ScreenPosition = new Point (4, 2)
  142. };
  143. // Create DriverImpl and associate it with the FakeOutput to test Sixel output
  144. IDriver driver = new DriverImpl (
  145. new FakeInputProcessor (null!),
  146. new OutputBufferImpl (),
  147. output,
  148. new (new AnsiResponseParser ()),
  149. new SizeMonitorImpl (output));
  150. // Add the Sixel to the driver
  151. driver.GetSixels ().Enqueue (s);
  152. // FakeOutput exposes this because it's in test scope
  153. output.IsLegacyConsole = isLegacyConsole;
  154. // Act
  155. output.Write (buffer);
  156. if (!isLegacyConsole)
  157. {
  158. // Assert: Sixel data was emitted (use Contains to avoid equality/side-effects)
  159. Assert.Contains ("SIXEL-DATA", output.Output);
  160. // Cursor was moved to Sixel position
  161. Assert.Equal (s.ScreenPosition, output.GetCursorPosition ());
  162. }
  163. else
  164. {
  165. // Assert: Sixel data was NOT emitted
  166. Assert.DoesNotContain ("SIXEL-DATA", output.Output);
  167. // Cursor was NOT moved to Sixel position
  168. Assert.NotEqual (s.ScreenPosition, output.GetCursorPosition ());
  169. }
  170. IApplication app = Application.Create ();
  171. app.Driver = driver;
  172. Assert.Equal (driver.GetSixels (), app.Driver.GetSixels ());
  173. app.Dispose ();
  174. }
  175. }