using System.Collections.Concurrent; using Xunit.Abstractions; namespace DrawingTests.RegionTests; /// /// Tests for . /// public class DrawOuterBoundaryTests (ITestOutputHelper output) { private readonly ITestOutputHelper _output = output; [Fact] public void DrawOuterBoundary_AfterIntersect_DrawsIntersectedBoundary () { // Arrange var region = new Region (new (0, 0, 10, 10)); region.Intersect (new Rectangle (5, 5, 10, 10)); var canvas = new LineCanvas (); // Act region.DrawOuterBoundary (canvas, LineStyle.Single); // Assert Dictionary cells = canvas.GetCellMap (); Assert.NotEmpty (cells); } [Fact] public void DrawOuterBoundary_AfterMinimalUnion_DrawsMinimalBoundary () { // Arrange var region = new Region (new (0, 0, 3, 3)); region.MinimalUnion (new Rectangle (3, 0, 3, 3)); var canvas = new LineCanvas (); // Act region.DrawOuterBoundary (canvas, LineStyle.Single); // Assert Dictionary cells = canvas.GetCellMap (); Assert.NotEmpty (cells); } [Fact] public void DrawOuterBoundary_ComplexShape_HandlesMultipleRegions () { // Arrange - Create a complex shape with multiple rectangles var region = new Region (new (0, 0, 3, 3)); region.Union (new Rectangle (3, 3, 3, 3)); region.Union (new Rectangle (6, 0, 3, 3)); var canvas = new LineCanvas (); // Act region.DrawOuterBoundary (canvas, LineStyle.Single); // Assert Dictionary cells = canvas.GetCellMap (); Assert.NotEmpty (cells); } [Fact] public void DrawOuterBoundary_DiagonallyConnectedRectangles_DrawsOuterBoundary () { // Arrange - Test the specific case from BUGBUG comment: (0,0,3,3) and (3,3,3,3) var region = new Region (new (0, 0, 3, 3)); region.Union (new Rectangle (3, 3, 3, 3)); var canvas = new LineCanvas (); // Act region.DrawOuterBoundary (canvas, LineStyle.Single); // Assert Dictionary cells = canvas.GetCellMap (); Assert.NotEmpty (cells); // Note: According to BUGBUG comment, this should draw specific shape // with connecting corner but currently draws incorrectly } [Fact] public void DrawOuterBoundary_EmptyRegion_DoesNotThrow () { // Arrange var region = new Region (); var canvas = new LineCanvas (); // Act Exception exception = Record.Exception (() => region.DrawOuterBoundary (canvas, LineStyle.Single)); // Assert Assert.Null (exception); Assert.Empty (canvas.GetCellMap ()); } [Fact] public void DrawOuterBoundary_GridPattern_DrawsOuterBoundary () { // Arrange - Create a checkerboard pattern var region = new Region (new (0, 0, 2, 2)); region.Union (new Rectangle (4, 0, 2, 2)); region.Union (new Rectangle (0, 4, 2, 2)); region.Union (new Rectangle (4, 4, 2, 2)); var canvas = new LineCanvas (); // Act region.DrawOuterBoundary (canvas, LineStyle.Single); // Assert Dictionary cells = canvas.GetCellMap (); Assert.NotEmpty (cells); } [Fact] public void DrawOuterBoundary_HollowRectangle_DrawsOuterAndInnerBoundaries () { // Arrange - Create a hollow rectangle (outer rect with inner rect removed) var region = new Region (new (0, 0, 10, 10)); region.Exclude (new Rectangle (2, 2, 6, 6)); var canvas = new LineCanvas (); // Act region.DrawOuterBoundary (canvas, LineStyle.Single); // Assert Dictionary cells = canvas.GetCellMap (); Assert.NotEmpty (cells); } [Fact] public void DrawOuterBoundary_HorizontalLineRectangle_DrawsHorizontalLine () { // Arrange - A horizontal line (width>1, height=1) var region = new Region (new (0, 0, 4, 1)); var canvas = new LineCanvas (); // Act region.DrawOuterBoundary (canvas, LineStyle.Single); // Assert Dictionary cells = canvas.GetCellMap (); Assert.NotEmpty (cells); } [Fact] public void DrawOuterBoundary_LShapedRegion_DrawsLShapeBoundary () { // Arrange - Create an L-shape var region = new Region (new (0, 0, 3, 3)); region.Union (new Rectangle (0, 3, 3, 3)); var canvas = new LineCanvas (); // Act region.DrawOuterBoundary (canvas, LineStyle.Single); // Assert Dictionary cells = canvas.GetCellMap (); Assert.NotEmpty (cells); } [Fact] public void DrawOuterBoundary_MultipleCallsOnSameCanvas_AccumulatesLines () { // Arrange var region1 = new Region (new (0, 0, 3, 3)); var region2 = new Region (new (5, 5, 3, 3)); var canvas = new LineCanvas (); // Act region1.DrawOuterBoundary (canvas, LineStyle.Single); int cellCountAfterFirst = canvas.GetCellMap ().Count; region2.DrawOuterBoundary (canvas, LineStyle.Single); int cellCountAfterSecond = canvas.GetCellMap ().Count; // Assert Assert.True (cellCountAfterSecond >= cellCountAfterFirst); } [Fact] public void DrawOuterBoundary_MultipleRegionsWithGaps_DrawsSeparateBoundaries () { // Arrange var region = new Region (); region.Union (new Rectangle (0, 0, 2, 2)); region.Union (new Rectangle (4, 0, 2, 2)); region.Union (new Rectangle (8, 0, 2, 2)); var canvas = new LineCanvas (); // Act region.DrawOuterBoundary (canvas, LineStyle.Single); // Assert Dictionary cells = canvas.GetCellMap (); Assert.NotEmpty (cells); // Should have three separate boundary regions } [Fact] public void DrawOuterBoundary_OverlappingRectangles_DrawsOuterBoundaryOnly () { // Arrange - Two overlapping rectangles var region = new Region (new (0, 0, 5, 5)); region.Union (new Rectangle (3, 3, 5, 5)); var canvas = new LineCanvas (); // Act region.DrawOuterBoundary (canvas, LineStyle.Single); // Assert Dictionary cells = canvas.GetCellMap (); Assert.NotEmpty (cells); // Should only draw outer perimeter, not the overlapping internal area } [Fact] public void DrawOuterBoundary_RectangleAtNegativeCoordinates_DrawsBoundary () { // Arrange var region = new Region (new (-5, -5, 3, 3)); var canvas = new LineCanvas (); // Act region.DrawOuterBoundary (canvas, LineStyle.Single); // Assert Dictionary cells = canvas.GetCellMap (); Assert.NotEmpty (cells); } [Fact] public void DrawOuterBoundary_SinglePixelRectangle_DrawsSinglePoint () { // Arrange - A 1x1 rectangle var region = new Region (new (5, 5, 1, 1)); var canvas = new LineCanvas (); // Act region.DrawOuterBoundary (canvas, LineStyle.Single); // Assert Dictionary cells = canvas.GetCellMap (); Assert.NotEmpty (cells); } [Fact] public void DrawOuterBoundary_SingleRectangle_DrawsBoundary () { // Arrange var region = new Region (new (0, 0, 3, 3)); var canvas = new LineCanvas (); // Act region.DrawOuterBoundary (canvas, LineStyle.Single); // Assert Dictionary cells = canvas.GetCellMap (); Assert.NotEmpty (cells); } [Fact] public void DrawOuterBoundary_SingleWidthRegion_DrawsCorrectly () { // Arrange - Test the specific case mentioned in BUGBUG comment var region = new Region (new (0, 0, 1, 4)); var canvas = new LineCanvas (); // Act region.DrawOuterBoundary (canvas, LineStyle.Single); // Assert Dictionary cells = canvas.GetCellMap (); Assert.NotEmpty (cells); // Note: According to BUGBUG, this should draw a single vertical line // but currently draws too wide } [Fact] public void DrawOuterBoundary_ThreadSafety_MultipleThreadsDrawing () { // Arrange var region = new Region (new (0, 0, 10, 10)); ConcurrentBag exceptions = new (); // Act Parallel.For ( 0, 10, i => { try { var canvas = new LineCanvas (); region.DrawOuterBoundary (canvas, LineStyle.Single); } catch (Exception ex) { exceptions.Add (ex); } }); // Assert Assert.Empty (exceptions); } [Fact] public void DrawOuterBoundary_ThreeWidthRegion_DrawsCorrectly () { // Arrange - Test the specific case mentioned in BUGBUG comment var region = new Region (new (20, 0, 3, 4)); var canvas = new LineCanvas (); // Act region.DrawOuterBoundary (canvas, LineStyle.Single); // Assert Dictionary cells = canvas.GetCellMap (); Assert.NotEmpty (cells); } [Fact] public void DrawOuterBoundary_TShapedRegion_DrawsCorrectBoundary () { // Arrange - Create a T-shape var region = new Region (new (0, 0, 9, 3)); // Horizontal bar region.Union (new Rectangle (3, 3, 3, 6)); // Vertical bar var canvas = new LineCanvas (); // Act region.DrawOuterBoundary (canvas, LineStyle.Single); // Assert Dictionary cells = canvas.GetCellMap (); Assert.NotEmpty (cells); } [Fact] public void DrawOuterBoundary_TwoAdjacentRectangles_DrawsOuterPerimeter () { // Arrange - Two rectangles side by side var region = new Region (new (0, 0, 3, 3)); region.Union (new Rectangle (3, 0, 3, 3)); var canvas = new LineCanvas (); // Act region.DrawOuterBoundary (canvas, LineStyle.Single); // Assert Dictionary cells = canvas.GetCellMap (); Assert.NotEmpty (cells); // Should draw outer boundary, not internal dividing line // The combined region should be treated as one shape } [Fact] public void DrawOuterBoundary_TwoSeparateRectangles_DrawsTwoBoundaries () { // Arrange - Two non-adjacent rectangles var region = new Region (new (0, 0, 2, 2)); region.Union (new Rectangle (5, 5, 2, 2)); var canvas = new LineCanvas (); // Act region.DrawOuterBoundary (canvas, LineStyle.Single); // Assert Dictionary cells = canvas.GetCellMap (); Assert.NotEmpty (cells); // Should have boundaries for both rectangles Assert.True (cells.Count > 0); } [Fact] public void DrawOuterBoundary_TwoWidthRegion_DrawsCorrectly () { // Arrange - Test the specific case mentioned in BUGBUG comment var region = new Region (new (10, 0, 2, 4)); var canvas = new LineCanvas (); // Act region.DrawOuterBoundary (canvas, LineStyle.Single); // Assert Dictionary cells = canvas.GetCellMap (); Assert.NotEmpty (cells); } [Theory] [InlineData (0, 0)] [InlineData (10, 10)] [InlineData (-5, -5)] [InlineData (100, 100)] public void DrawOuterBoundary_VariousPositions_DrawsBoundary (int x, int y) { // Arrange var region = new Region (new (x, y, 5, 5)); var canvas = new LineCanvas (); // Act Exception exception = Record.Exception (() => region.DrawOuterBoundary (canvas, LineStyle.Single)); // Assert Assert.Null (exception); Dictionary cells = canvas.GetCellMap (); Assert.NotEmpty (cells); } [Theory] [InlineData (1, 1)] [InlineData (1, 5)] [InlineData (5, 1)] [InlineData (2, 2)] [InlineData (10, 10)] [InlineData (100, 100)] public void DrawOuterBoundary_VariousSizes_DrawsBoundary (int width, int height) { // Arrange var region = new Region (new (0, 0, width, height)); var canvas = new LineCanvas (); // Act Exception exception = Record.Exception (() => region.DrawOuterBoundary (canvas, LineStyle.Single)); // Assert Assert.Null (exception); Dictionary cells = canvas.GetCellMap (); Assert.NotEmpty (cells); } [Fact] public void DrawOuterBoundary_VerticalLineRectangle_DrawsVerticalLine () { // Arrange - A vertical line (width=1, height>1) var region = new Region (new (0, 0, 1, 4)); var canvas = new LineCanvas (); // Act region.DrawOuterBoundary (canvas, LineStyle.Single); // Assert Dictionary cells = canvas.GetCellMap (); Assert.NotEmpty (cells); } [Fact] public void DrawOuterBoundary_VeryLargeRegion_FallsBackToDrawBoundaries () { // Arrange - Create a region larger than the 1000x1000 threshold var region = new Region (new (0, 0, 1100, 1100)); var canvas = new LineCanvas (); // Act Exception exception = Record.Exception (() => region.DrawOuterBoundary (canvas, LineStyle.Single)); // Assert Assert.Null (exception); // Should fall back to DrawBoundaries for very large regions Dictionary cells = canvas.GetCellMap (); Assert.NotEmpty (cells); } [Fact] public void DrawOuterBoundary_WithCustomAttribute_AppliesAttribute () { // Arrange var region = new Region (new (0, 0, 3, 3)); var canvas = new LineCanvas (); var attribute = new Attribute (Color.Red, Color.Blue); // Act region.DrawOuterBoundary (canvas, LineStyle.Single, attribute); // Assert Dictionary cells = canvas.GetCellMap (); Assert.NotEmpty (cells); } [Fact] public void DrawOuterBoundary_WithDifferentLineStyles_DrawsWithCorrectStyle () { // Arrange var region = new Region (new (0, 0, 3, 3)); // Test each line style foreach (LineStyle style in Enum.GetValues ()) { var canvas = new LineCanvas (); // Act region.DrawOuterBoundary (canvas, style); // Assert Dictionary cells = canvas.GetCellMap (); Assert.NotEmpty (cells); } } [Fact] public void DrawOuterBoundary_ZeroHeightRectangle_HandlesGracefully () { // Arrange - Rectangle with zero height var region = new Region (new (5, 5, 5, 0)); var canvas = new LineCanvas (); // Act Exception exception = Record.Exception (() => region.DrawOuterBoundary (canvas, LineStyle.Single)); // Assert Assert.Null (exception); } [Fact] public void DrawOuterBoundary_ZeroWidthRectangle_HandlesGracefully () { // Arrange - Rectangle with zero width var region = new Region (new (5, 5, 0, 5)); var canvas = new LineCanvas (); // Act Exception exception = Record.Exception (() => region.DrawOuterBoundary (canvas, LineStyle.Single)); // Assert Assert.Null (exception); } }