SubtractRectangleTests.cs 10 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264
  1. namespace Terminal.Gui.DrawingTests;
  2. using Xunit;
  3. public class SubtractRectangleTests
  4. {
  5. [Fact]
  6. public void SubtractRectangle_NoOverlap_ReturnsOriginalRectangle ()
  7. {
  8. // Arrange: Non-overlapping rectangles
  9. Rectangle original = new (0, 0, 10, 10);
  10. Rectangle subtract = new (15, 15, 5, 5);
  11. // Act: Subtract non-overlapping rectangle
  12. var result = Region.SubtractRectangle (original, subtract).ToList ();
  13. // Assert: Original rectangle unchanged
  14. Assert.Single (result);
  15. Assert.Equal (new Rectangle (0, 0, 10, 10), result [0]);
  16. }
  17. [Fact]
  18. public void SubtractRectangle_CompleteOverlap_ReturnsEmpty ()
  19. {
  20. // Arrange: Subtract rectangle completely overlaps original
  21. Rectangle original = new (0, 0, 5, 5);
  22. Rectangle subtract = new (0, 0, 5, 5);
  23. // Act: Subtract overlapping rectangle
  24. var result = Region.SubtractRectangle (original, subtract).ToList ();
  25. // Assert: No rectangles returned (empty result)
  26. Assert.Empty (result);
  27. }
  28. [Fact]
  29. public void SubtractRectangle_PartialOverlap_TopAndBottom ()
  30. {
  31. // Arrange: Original rectangle with subtract overlapping top and bottom
  32. Rectangle original = new (0, 0, 10, 10);
  33. Rectangle subtract = new (0, 4, 10, 2); // Overlaps y=4 to y=5
  34. // Act: Subtract overlapping rectangle
  35. var result = Region.SubtractRectangle (original, subtract).ToList ();
  36. // Assert: Expect top (0,0,10,4) and bottom (0,6,10,4)
  37. Assert.Equal (2, result.Count);
  38. Assert.Contains (new Rectangle (0, 0, 10, 4), result); // Top part
  39. Assert.Contains (new Rectangle (0, 6, 10, 4), result); // Bottom part
  40. }
  41. [Fact]
  42. public void SubtractRectangle_PartialOverlap_LeftAndRight ()
  43. {
  44. // Arrange: Original rectangle with subtract overlapping left and right
  45. Rectangle original = new (0, 0, 10, 10);
  46. Rectangle subtract = new (4, 0, 2, 10); // Overlaps x=4 to x=5
  47. // Act: Subtract overlapping rectangle
  48. var result = Region.SubtractRectangle (original, subtract).ToList ();
  49. // Assert: Expect left (0,0,4,10) and right (6,0,4,10)
  50. Assert.Equal (2, result.Count);
  51. Assert.Contains (new Rectangle (0, 0, 4, 10), result); // Left part
  52. Assert.Contains (new Rectangle (6, 0, 4, 10), result); // Right part
  53. }
  54. [Fact]
  55. public void SubtractRectangle_EmptyOriginal_ReturnsEmpty ()
  56. {
  57. // Arrange: Empty original rectangle
  58. Rectangle original = Rectangle.Empty;
  59. Rectangle subtract = new (0, 0, 5, 5);
  60. // Act: Subtract from empty rectangle
  61. var result = Region.SubtractRectangle (original, subtract).ToList ();
  62. // Assert: No rectangles returned (empty result)
  63. Assert.Empty (result);
  64. }
  65. [Fact]
  66. public void SubtractRectangle_EmptySubtract_ReturnsOriginal ()
  67. {
  68. // Arrange: Empty subtract rectangle
  69. Rectangle original = new (0, 0, 5, 5);
  70. Rectangle subtract = Rectangle.Empty;
  71. // Act: Subtract empty rectangle
  72. var result = Region.SubtractRectangle (original, subtract).ToList ();
  73. // Assert: Original rectangle unchanged
  74. Assert.Single (result);
  75. Assert.Equal (new Rectangle (0, 0, 5, 5), result [0]);
  76. }
  77. [Fact]
  78. public void SubtractRectangle_ZeroWidthOrHeight_HandlesCorrectly ()
  79. {
  80. // Arrange: Rectangle with zero width or height
  81. Rectangle original = new (0, 0, 5, 5);
  82. Rectangle subtract = new (0, 0, 0, 5); // Zero width
  83. // Act: Subtract zero-width rectangle
  84. var result = Region.SubtractRectangle (original, subtract).ToList ();
  85. // Assert: Original rectangle unchanged
  86. Assert.Single (result);
  87. Assert.Equal (new Rectangle (0, 0, 5, 5), result [0]);
  88. }
  89. [Fact]
  90. public void SubtractRectangle_NegativeCoordinates_HandlesCorrectly ()
  91. {
  92. // Arrange:
  93. // Original rectangle: (-5,-5) with width 10 and height 10.
  94. // Subtract rectangle: (-3,-3) with width 2 and height 2.
  95. Rectangle original = new (-5, -5, 10, 10);
  96. Rectangle subtract = new (-3, -3, 2, 2);
  97. // Act:
  98. var results = Region.SubtractRectangle (original, subtract).ToList ();
  99. // Expected fragments based on our algorithm:
  100. // Top: (-5,-5,10,2)
  101. // Bottom: (-5,-1,10,6)
  102. // Left: (-5,-3,2,2)
  103. // Right: (-1,-3,6,2)
  104. var expectedTop = new Rectangle (-5, -5, 10, 2);
  105. var expectedBottom = new Rectangle (-5, -1, 10, 6);
  106. var expectedLeft = new Rectangle (-5, -3, 2, 2);
  107. var expectedRight = new Rectangle (-1, -3, 6, 2);
  108. // Assert:
  109. Assert.Contains (expectedTop, results);
  110. Assert.Contains (expectedBottom, results);
  111. Assert.Contains (expectedLeft, results);
  112. Assert.Contains (expectedRight, results);
  113. Assert.Equal (4, results.Count);
  114. }
  115. [Fact]
  116. public void SubtractRectangle_EdgeOverlap_TopLeftCorner ()
  117. {
  118. // Arrange: Subtract overlaps only the top-left corner.
  119. // Original: (0,0,5,5); Subtract: (0,0,1,1)
  120. Rectangle original = new (0, 0, 5, 5);
  121. Rectangle subtract = new (0, 0, 1, 1);
  122. // Act:
  123. var result = Region.SubtractRectangle (original, subtract).ToList ();
  124. // The algorithm produces two fragments:
  125. // 1. Bottom: (0,1,5,4)
  126. // 2. Right: (1,0,4,1)
  127. Assert.Equal (2, result.Count);
  128. Assert.Contains (new Rectangle (0, 1, 5, 4), result);
  129. Assert.Contains (new Rectangle (1, 0, 4, 1), result);
  130. }
  131. // Updated L-shaped test: The algorithm produces 6 fragments, not 5.
  132. [Fact]
  133. public void SubtractRectangle_LShapedSubtract_MultipleFragments ()
  134. {
  135. // Arrange:
  136. // Original: (0,0,6,6)
  137. // subtract1: (2,2,2,1) creates a horizontal gap.
  138. // subtract2: (2,3,1,1) removes an additional piece from the bottom fragment.
  139. Rectangle original = new (0, 0, 6, 6);
  140. Rectangle subtract1 = new (2, 2, 2, 1);
  141. Rectangle subtract2 = new (2, 3, 1, 1);
  142. // Act:
  143. var intermediateResult = Region.SubtractRectangle (original, subtract1).ToList ();
  144. var finalResult = intermediateResult.SelectMany (r => Region.SubtractRectangle (r, subtract2)).ToList ();
  145. // Explanation:
  146. // After subtracting subtract1, we expect these 4 fragments:
  147. // - Top: (0,0,6,2)
  148. // - Bottom: (0,3,6,3)
  149. // - Left: (0,2,2,1)
  150. // - Right: (4,2,2,1)
  151. // Then subtracting subtract2 from the bottom fragment (0,3,6,3) produces 3 fragments:
  152. // - Bottom part: (0,4,6,2)
  153. // - Left part: (0,3,2,1)
  154. // - Right part: (3,3,3,1)
  155. // Total fragments = 1 (top) + 3 (modified bottom) + 1 (left) + 1 (right) = 6.
  156. Assert.Equal (6, finalResult.Count);
  157. Assert.Contains (new Rectangle (0, 0, 6, 2), finalResult); // Top fragment remains unchanged.
  158. Assert.Contains (new Rectangle (0, 4, 6, 2), finalResult); // Bottom part from modified bottom.
  159. Assert.Contains (new Rectangle (0, 3, 2, 1), finalResult); // Left part from modified bottom.
  160. Assert.Contains (new Rectangle (3, 3, 3, 1), finalResult); // Right part from modified bottom.
  161. Assert.Contains (new Rectangle (0, 2, 2, 1), finalResult); // Left fragment from first subtraction.
  162. Assert.Contains (new Rectangle (4, 2, 2, 1), finalResult); // Right fragment from first subtraction.
  163. }
  164. // Additional focused tests for L-shaped subtraction scenarios:
  165. [Fact]
  166. public void SubtractRectangle_LShapedSubtract_HorizontalThenVertical ()
  167. {
  168. // Arrange:
  169. // First, subtract a horizontal band.
  170. Rectangle original = new (0, 0, 10, 10);
  171. Rectangle subtractHorizontal = new (0, 4, 10, 2);
  172. var horizontalResult = Region.SubtractRectangle (original, subtractHorizontal).ToList ();
  173. // Expect two fragments: top (0,0,10,4) and bottom (0,6,10,4).
  174. Assert.Equal (2, horizontalResult.Count);
  175. Assert.Contains (new Rectangle (0, 0, 10, 4), horizontalResult);
  176. Assert.Contains (new Rectangle (0, 6, 10, 4), horizontalResult);
  177. // Act:
  178. // Now, subtract a vertical piece from the top fragment.
  179. Rectangle subtractVertical = new (3, 0, 2, 4);
  180. var finalResult = Region.SubtractRectangle (horizontalResult [0], subtractVertical).ToList ();
  181. // Assert:
  182. // The subtraction yields two fragments:
  183. // Left fragment: (0,0,3,4)
  184. // Right fragment: (5,0,5,4)
  185. Assert.Equal (2, finalResult.Count);
  186. Assert.Contains (new Rectangle (0, 0, 3, 4), finalResult);
  187. Assert.Contains (new Rectangle (5, 0, 5, 4), finalResult);
  188. }
  189. [Fact]
  190. public void SubtractRectangle_LShapedSubtract_VerticalThenHorizontal ()
  191. {
  192. // Arrange:
  193. // First, subtract a vertical band.
  194. // Original: (0,0,10,10)
  195. // Vertical subtract: (4,0,2,10) produces two fragments:
  196. // Left: (0,0,4,10) and Right: (6,0,4,10)
  197. Rectangle original = new (0, 0, 10, 10);
  198. Rectangle subtractVertical = new (4, 0, 2, 10);
  199. var verticalResult = Region.SubtractRectangle (original, subtractVertical).ToList ();
  200. Assert.Equal (2, verticalResult.Count);
  201. Assert.Contains (new Rectangle (0, 0, 4, 10), verticalResult);
  202. Assert.Contains (new Rectangle (6, 0, 4, 10), verticalResult);
  203. // Act:
  204. // Now, subtract a horizontal piece from the left fragment.
  205. // Horizontal subtract: (0,3,4,2)
  206. // from the left fragment (0,0,4,10)
  207. // Let's determine the expected fragments:
  208. // 1. Top band: since original.Top (0) < subtract.Top (3), we get:
  209. // (0,0,4, 3) -- height = subtract.Top - original.Top = 3.
  210. // 2. Bottom band: since original.Bottom (10) > subtract.Bottom (5), we get:
  211. // (0,5,4, 5) -- height = original.Bottom - subtract.Bottom = 5.
  212. // No left or right fragments are produced because subtractHorizontal spans the full width.
  213. // Total fragments: 2.
  214. Rectangle subtractHorizontal = new (0, 3, 4, 2);
  215. var finalResult = Region.SubtractRectangle (verticalResult [0], subtractHorizontal).ToList ();
  216. // Assert:
  217. // Expecting two fragments: (0,0,4,3) and (0,5,4,5).
  218. Assert.Equal (2, finalResult.Count);
  219. Assert.Contains (new Rectangle (0, 0, 4, 3), finalResult);
  220. Assert.Contains (new Rectangle (0, 5, 4, 5), finalResult);
  221. }
  222. }