|
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.
// Copyright (C) 2004-2008 Novell, Inc (http://www.novell.com)
//
// Permission is hereby granted, free of charge, to any person obtaining
// a copy of this software and associated documentation files (the
// "Software"), to deal in the Software without restriction, including
// without limitation the rights to use, copy, modify, merge, publish,
// distribute, sublicense, and/or sell copies of the Software, and to
// permit persons to whom the Software is furnished to do so, subject to
// the following conditions:
//
// The above copyright notice and this permission notice shall be
// included in all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
using System.Drawing.Drawing2D;
using System.Runtime.InteropServices;
namespace System.Drawing.Tests;
public class RegionTests
{
private static readonly Graphics s_graphic = Graphics.FromImage(new Bitmap(1, 1));
private static Region CreateDisposedRegion()
{
Region region = new();
region.Dispose();
return region;
}
[Fact]
public void Ctor_Default()
{
using Region region = new();
Assert.False(region.IsEmpty(s_graphic));
Assert.True(region.IsInfinite(s_graphic));
Assert.Equal(new RectangleF(-4194304, -4194304, 8388608, 8388608), region.GetBounds(s_graphic));
}
[Theory]
[InlineData(-1, -2, -3, -4, true)]
[InlineData(0, 0, 0, 0, true)]
[InlineData(1, 2, 3, 4, false)]
public void Ctor_Rectangle(int x, int y, int width, int height, bool isEmpty)
{
Rectangle rectangle = new(x, y, width, height);
using Region region = new(rectangle);
Assert.Equal(isEmpty, region.IsEmpty(s_graphic));
Assert.False(region.IsInfinite(s_graphic));
Assert.Equal(new RectangleF(x, y, width, height), region.GetBounds(s_graphic));
}
[Theory]
[InlineData(1, 2, 3, float.NegativeInfinity, true)]
[InlineData(-1, -2, -3, -4, true)]
[InlineData(0, 0, 0, 0, true)]
[InlineData(1, 2, 3, 4, false)]
[InlineData(float.MaxValue, float.MaxValue, float.MaxValue, float.MaxValue, true)]
public void Ctor_RectangleF(float x, float y, float width, float height, bool isEmpty)
{
RectangleF rectangle = new(x, y, width, height);
using Region region = new(rectangle);
Assert.Equal(isEmpty, region.IsEmpty(s_graphic));
Assert.False(region.IsInfinite(s_graphic));
Assert.Equal(rectangle, region.GetBounds(s_graphic));
}
public static IEnumerable<object[]> Region_TestData()
{
yield return new object[] { new Region() };
yield return new object[] { new Region(new Rectangle(0, 0, 0, 0)) };
yield return new object[] { new Region(new Rectangle(1, 2, 3, 4)) };
}
[Theory]
[MemberData(nameof(Region_TestData))]
public void Ctor_RegionData(Region region)
{
using (region)
{
using Region otherRegion = new(region.GetRegionData());
using Matrix matrix = new();
Assert.Equal(region.GetBounds(s_graphic), otherRegion.GetBounds(s_graphic));
Assert.Equal(region.GetRegionScans(matrix), otherRegion.GetRegionScans(matrix));
}
}
[Fact]
public void Ctor_RegionDataOfRegionWithPath_Success()
{
using GraphicsPath graphicsPath = new();
graphicsPath.AddRectangle(new Rectangle(1, 2, 3, 4));
using Region region = new(graphicsPath);
Ctor_RegionData(region);
}
[Fact]
public void Ctor_RegionDataOfRegionWithRegionData_Success()
{
using Region region = new(new Rectangle(1, 2, 3, 4));
using Region other = new(region.GetRegionData());
Ctor_RegionData(other);
}
[Fact]
public void Ctor_NullRegionData_ThrowsArgumentNullException()
{
AssertExtensions.Throws<ArgumentNullException>("rgnData", () => new Region((RegionData)null));
}
[Fact]
public void Ctor_EmptyRegionData_ThrowsArgumentException()
{
using Region region = new();
RegionData regionData = region.GetRegionData();
regionData.Data = [];
AssertExtensions.Throws<ArgumentException>(null, () => new Region(regionData));
}
[Theory]
[InlineData(1)]
[InlineData(7)]
[InlineData(256)]
public void Ctor_InvalidRegionData_ThrowsExternalException(int dataLength)
{
using Region region = new();
RegionData regionData = region.GetRegionData();
regionData.Data = new byte[dataLength];
Assert.Throws<ExternalException>(() => new Region(regionData));
}
[Fact]
public void Ctor_EmptyGraphicsPath_ThrowsExternalException()
{
using GraphicsPath graphicsPath = new();
using Region region = new(graphicsPath);
RegionData regionData = region.GetRegionData();
Assert.Throws<ExternalException>(() => new Region(regionData));
}
[Fact]
public void Ctor_NullDataInRegionData_ThrowsNullReferenceException()
{
using Region region = new();
RegionData regionData = region.GetRegionData();
regionData.Data = null;
Assert.Throws<NullReferenceException>(() => new Region(regionData));
}
[Fact]
public void Ctor_GraphicsPath()
{
using GraphicsPath graphicsPath = new();
graphicsPath.AddRectangle(new Rectangle(1, 2, 3, 4));
graphicsPath.AddRectangle(new Rectangle(4, 5, 6, 7));
using Region region = new(graphicsPath);
using Matrix matrix = new();
Assert.Equal(
[
new(1, 2, 3, 3),
new(1, 5, 9, 1),
new(4, 6, 6, 6)
], region.GetRegionScans(matrix));
Assert.Equal(new RectangleF(1, 2, 9, 10), region.GetBounds(s_graphic));
}
[Fact]
public void Ctor_EmptyGraphicsPath()
{
using GraphicsPath graphicsPath = new();
using Region region = new(graphicsPath);
using Matrix matrix = new();
Assert.True(region.IsEmpty(s_graphic));
Assert.Empty(region.GetRegionScans(matrix));
}
public static IEnumerable<object[]> Ctor_InfiniteGraphicsPath_TestData()
{
GraphicsPath path1 = new();
path1.AddRectangle(new Rectangle(-4194304, -4194304, 8388608, 8388608));
yield return new object[] { path1, true };
GraphicsPath path2 = new();
path2.AddRectangle(new Rectangle(-4194304, -4194304, 8388608, 8388608));
path2.AddRectangle(Rectangle.Empty);
yield return new object[] { path2, true };
GraphicsPath path3 = new();
path3.AddRectangle(new Rectangle(-4194304, -4194304, 8388608, 8388608));
path3.AddRectangle(new Rectangle(1, 2, 3, 4));
yield return new object[] { path3, false };
GraphicsPath path4 = new();
path4.AddCurve([new(-4194304, -4194304), new(4194304, 4194304)]);
yield return new object[] { path4, false };
GraphicsPath path5 = new();
path5.AddPolygon([new(-4194304, -4194304), new(-4194304, 4194304), new(4194304, 4194304), new(4194304, -4194304)]);
yield return new object[] { path5, true };
GraphicsPath path6 = new();
path6.AddPolygon([new(-4194304, -4194304), new(-4194304, 4194304), new(4194304, 4194304), new(4194304, -4194304), new(-4194304, -4194304)]);
yield return new object[] { path6, true };
}
[Theory]
[MemberData(nameof(Ctor_InfiniteGraphicsPath_TestData))]
public void Ctor_InfiniteGraphicsPath_IsInfinite(GraphicsPath path, bool isInfinite)
{
using (path)
using (Region region = new(path))
{
Assert.Equal(isInfinite, region.IsInfinite(s_graphic));
}
}
[Fact]
public void Ctor_GraphicsPathTooLarge_SetsToEmpty()
{
using GraphicsPath path = new();
path.AddCurve([new(-4194304, -4194304), new(4194304, 4194304)]);
using Region region = new(path);
using Matrix matrix = new();
Assert.Empty(region.GetRegionScans(matrix));
}
[Fact]
public void Ctor_NullGraphicsPath_ThrowsArgumentNullException()
{
AssertExtensions.Throws<ArgumentNullException>("path", () => new Region((GraphicsPath)null));
}
[Fact]
public void Ctor_DisposedGraphicsPath_ThrowsArgumentException()
{
GraphicsPath path = new();
path.Dispose();
AssertExtensions.Throws<ArgumentException>(null, () => new Region(path));
}
[Theory]
[MemberData(nameof(Region_TestData))]
public void Clone(Region region)
{
using (region)
using (Region clone = Assert.IsType<Region>(region.Clone()))
using (Matrix matrix = new())
{
Assert.NotSame(region, clone);
Assert.Equal(region.GetBounds(s_graphic), clone.GetBounds(s_graphic));
Assert.Equal(region.GetRegionScans(matrix), clone.GetRegionScans(matrix));
}
}
[Fact]
public void Clone_Disposed_ThrowsArgumentException()
{
AssertExtensions.Throws<ArgumentException>(null, () => CreateDisposedRegion().Clone());
}
public static IEnumerable<object[]> Complement_TestData()
{
yield return new object[]
{
new Region(new RectangleF(10, 10, 100, 100)),
new RectangleF[] { new(40, 60, 100, 20) },
new RectangleF[] { new(110, 60, 30, 20) }
};
yield return new object[]
{
new Region(new RectangleF(70, 10, 100, 100)),
new RectangleF[] { new(40, 60, 100, 20) },
new RectangleF[] { new(40, 60, 30, 20) }
};
yield return new object[]
{
new Region(new RectangleF(40, 100, 100, 100)),
new RectangleF[] { new(70, 80, 50, 40) },
new RectangleF[] { new(70, 80, 50, 20) }
};
yield return new object[]
{
new Region(new RectangleF(40, 10, 100, 100)),
new RectangleF[] { new(70, 80, 50, 40) },
new RectangleF[] { new(70, 110, 50, 10) }
};
yield return new object[]
{
new Region(new RectangleF(30, 30, 80, 80)),
new RectangleF[]
{
new(45, 45, 200, 200),
new(160, 260, 10, 10),
new(170, 260, 10, 10),
},
new RectangleF[] { new(170, 260, 10, 10) }
};
yield return new object[]
{
new Region(),
new RectangleF[] { RectangleF.Empty },
Array.Empty<RectangleF>()
};
yield return new object[]
{
new Region(),
new RectangleF[] { new(1, 2, 3, 4) },
Array.Empty<RectangleF>()
};
}
[Theory]
[MemberData(nameof(Complement_TestData))]
public void Complement_Region_Success(Region region, RectangleF[] rectangles, RectangleF[] expectedScans)
{
using (region)
{
foreach (RectangleF rect in rectangles)
{
using Region other = new(rect);
region.Complement(other);
}
using Matrix matrix = new();
Assert.Equal(expectedScans, region.GetRegionScans(matrix));
}
}
[Fact]
public void Complement_UnionRegion_Success()
{
using Region region = new(new Rectangle(20, 20, 20, 20));
using Region other = new(new Rectangle(20, 80, 20, 10));
using Matrix matrix = new();
other.Union(new Rectangle(60, 60, 30, 10));
region.Complement(other);
Assert.Equal(
[
new(60, 60, 30, 10),
new(20, 80, 20, 10)
], region.GetRegionScans(matrix));
}
[Fact]
public void Complement_InfiniteAndWithIntersectRegion_Success()
{
using Region region = new();
using Matrix matrix = new();
region.Intersect(new Rectangle(5, 5, -10, -10));
region.Complement(new Rectangle(-5, -5, 12, 12));
Assert.False(region.IsEmpty(s_graphic));
Assert.False(region.IsInfinite(s_graphic));
Assert.Equal(
[
new(5, -5, 2, 10),
new(-5, 5, 12, 2)
], region.GetRegionScans(matrix));
}
[Fact]
public void Complement_InfiniteRegion_Success()
{
using Region region = new(new Rectangle(1, 2, 3, 4));
using Matrix matrix = new();
using Region other = new();
region.Complement(other);
Assert.Equal(
[
new(-4194304, -4194304, 8388608, 4194306),
new(-4194304, 2, 4194305, 4),
new(4, 2, 4194300, 4),
new(-4194304, 6, 8388608, 4194298)
], region.GetRegionScans(matrix));
}
[Fact]
public void Complement_NullRegion_ThrowsArgumentNullException()
{
using Region region = new();
AssertExtensions.Throws<ArgumentNullException>("region", () => region.Complement((Region)null));
}
[Fact]
public void Complement_DisposedRegion_ThrowsArgumentException()
{
AssertExtensions.Throws<ArgumentException>(null, () => new Region().Complement(CreateDisposedRegion()));
}
[Fact]
public void Complement_SameRegion_ThrowsInvalidOperationException()
{
using Region region = new();
Assert.Throws<InvalidOperationException>(() => region.Complement(region));
}
[Theory]
[MemberData(nameof(Complement_TestData))]
public void Complement_Rectangle_Success(Region region, RectangleF[] rectangles, RectangleF[] expectedScans)
{
using (region)
{
foreach (RectangleF rect in rectangles)
{
region.Complement(new Rectangle((int)rect.X, (int)rect.Y, (int)rect.Width, (int)rect.Height));
}
using Matrix matrix = new();
Assert.Equal(expectedScans, region.GetRegionScans(matrix));
}
}
[Theory]
[MemberData(nameof(Complement_TestData))]
public void Complement_RectangleF_Success(Region region, RectangleF[] rectangles, RectangleF[] expectedScans)
{
using (region)
{
foreach (RectangleF rect in rectangles)
{
region.Complement(rect);
}
using Matrix matrix = new();
Assert.Equal(expectedScans, region.GetRegionScans(matrix));
}
}
[Theory]
[MemberData(nameof(Complement_TestData))]
public void Complement_GraphicsPath_Success(Region region, RectangleF[] rectangles, RectangleF[] expectedScans)
{
using (region)
{
foreach (RectangleF rect in rectangles)
{
using GraphicsPath path = new();
path.AddRectangle(rect);
region.Complement(path);
}
using Matrix matrix = new();
Assert.Equal(expectedScans, region.GetRegionScans(matrix));
}
}
[Fact]
public void Complement_GraphicsPathWithMultipleRectangles_Success()
{
Rectangle rect1 = new(20, 30, 60, 80);
Rectangle rect2 = new(50, 40, 60, 80);
using Graphics graphics = Graphics.FromImage(new Bitmap(600, 800));
using Region region1 = new(rect1);
using Region region2 = new(rect2);
using Matrix matrix = new();
graphics.DrawRectangle(Pens.Green, rect1);
graphics.DrawRectangle(Pens.Red, rect2);
region1.Complement(region2);
graphics.FillRegion(Brushes.Blue, region1);
graphics.DrawRectangles(Pens.Yellow, region1.GetRegionScans(matrix));
Assert.Equal(
[
new(80, 40, 30, 70),
new(50, 110, 60, 10)
], region1.GetRegionScans(matrix));
}
[Fact]
public void Complement_EmptyPathWithInfiniteRegion_MakesEmpty()
{
using Region region = new();
using GraphicsPath graphicsPath = new();
region.Complement(graphicsPath);
Assert.True(region.IsEmpty(s_graphic));
}
[Fact]
public void Complement_NullGraphicsPath_ThrowsArgumentNullException()
{
using Region region = new();
AssertExtensions.Throws<ArgumentNullException>("path", () => region.Complement((GraphicsPath)null));
}
[Fact]
public void Complement_Disposed_ThrowsArgumentException()
{
Region disposedRegion = CreateDisposedRegion();
using GraphicsPath graphicPath = new();
using Region other = new();
AssertExtensions.Throws<ArgumentException>(null, () => disposedRegion.Complement(graphicPath));
AssertExtensions.Throws<ArgumentException>(null, () => disposedRegion.Complement(default(Rectangle)));
AssertExtensions.Throws<ArgumentException>(null, () => disposedRegion.Complement(default(RectangleF)));
AssertExtensions.Throws<ArgumentException>(null, () => disposedRegion.Complement(disposedRegion));
}
public static IEnumerable<object[]> Equals_TestData()
{
static Region Empty()
{
Region emptyRegion = new();
emptyRegion.MakeEmpty();
return emptyRegion;
}
Region createdRegion = new();
yield return new object[] { createdRegion, createdRegion, true };
yield return new object[] { new Region(), new Region(), true };
yield return new object[] { new Region(), Empty(), false };
yield return new object[] { new Region(), new Region(new Rectangle(1, 2, 3, 4)), false };
yield return new object[] { Empty(), Empty(), true };
yield return new object[] { Empty(), new Region(new Rectangle(0, 0, 0, 0)), true };
yield return new object[] { Empty(), new Region(new Rectangle(1, 2, 3, 3)), false };
yield return new object[] { new Region(new Rectangle(1, 2, 3, 4)), new Region(new Rectangle(1, 2, 3, 4)), true };
yield return new object[] { new Region(new Rectangle(1, 2, 3, 4)), new Region(new RectangleF(1, 2, 3, 4)), true };
yield return new object[] { new Region(new Rectangle(1, 2, 3, 4)), new Region(new Rectangle(2, 2, 3, 4)), false };
yield return new object[] { new Region(new Rectangle(1, 2, 3, 4)), new Region(new Rectangle(1, 3, 3, 4)), false };
yield return new object[] { new Region(new Rectangle(1, 2, 3, 4)), new Region(new Rectangle(1, 2, 4, 4)), false };
yield return new object[] { new Region(new Rectangle(1, 2, 3, 4)), new Region(new Rectangle(1, 2, 3, 5)), false };
GraphicsPath graphics1 = new();
graphics1.AddRectangle(new Rectangle(1, 2, 3, 4));
GraphicsPath graphics2 = new();
graphics2.AddRectangle(new Rectangle(1, 2, 3, 4));
GraphicsPath graphics3 = new();
graphics3.AddRectangle(new Rectangle(2, 2, 3, 4));
GraphicsPath graphics4 = new();
graphics4.AddRectangle(new Rectangle(1, 3, 3, 4));
GraphicsPath graphics5 = new();
graphics5.AddRectangle(new Rectangle(1, 2, 4, 4));
GraphicsPath graphics6 = new();
graphics6.AddRectangle(new Rectangle(1, 2, 3, 5));
yield return new object[] { new Region(graphics1), new Region(graphics1), true };
yield return new object[] { new Region(graphics1), new Region(graphics2), true };
yield return new object[] { new Region(graphics1), new Region(graphics3), false };
yield return new object[] { new Region(graphics1), new Region(graphics4), false };
yield return new object[] { new Region(graphics1), new Region(graphics5), false };
yield return new object[] { new Region(graphics1), new Region(graphics6), false };
}
[Theory]
[MemberData(nameof(Equals_TestData))]
public void Equals_Valid_ReturnsExpected(Region region, Region other, bool expected)
{
using (region)
using (other)
{
Assert.Equal(expected, region.Equals(other, s_graphic));
}
}
[Fact]
public void Equals_NullRegion_ThrowsArgumentNullException()
{
using Region region = new();
AssertExtensions.Throws<ArgumentNullException>("region", () => region.Equals(null, s_graphic));
}
[Fact]
public void Equals_NullGraphics_ThrowsArgumentNullException()
{
using Region region = new();
AssertExtensions.Throws<ArgumentNullException>("g", () => region.Equals(region, null));
}
[Fact]
public void Equals_DisposedGraphics_ThrowsArgumentException()
{
using Region region = new();
using Region other = new();
using Bitmap image = new(10, 10);
var graphics = Graphics.FromImage(image);
graphics.Dispose();
AssertExtensions.Throws<ArgumentException>(null, () => region.Equals(region, graphics));
}
[Fact]
public void Equals_Disposed_ThrowsArgumentException()
{
Region disposedRegion = CreateDisposedRegion();
AssertExtensions.Throws<ArgumentException>(null, () => disposedRegion.Equals(new Region(), s_graphic));
AssertExtensions.Throws<ArgumentException>(null, () => new Region().Equals(disposedRegion, s_graphic));
}
public static IEnumerable<object[]> Exclude_TestData()
{
yield return new object[]
{
new Region(new Rectangle(500, 30, 60, 80)),
new RectangleF[] { new(500, 30, 60, 80) },
Array.Empty<RectangleF>()
};
yield return new object[]
{
new Region(new Rectangle(500, 30, 60, 80)),
new RectangleF[] { RectangleF.Empty },
new RectangleF[] { new(500, 30, 60, 80) }
};
yield return new object[]
{
new Region(),
new RectangleF[] { new(520, 40, 60, 80) },
new RectangleF[]
{
new(-4194304, -4194304, 8388608, 4194344),
new(-4194304, 40, 4194824, 80),
new(580, 40, 4193724, 80),
new(-4194304, 120, 8388608, 4194184)
}
};
yield return new object[]
{
new Region(),
new RectangleF[] { RectangleF.Empty },
new RectangleF[] { new Rectangle(-4194304, -4194304, 8388608, 8388608) }
};
// Intersecting from the right.
yield return new object[]
{
new Region(new Rectangle(10, 10, 100, 100)),
new RectangleF[] { new(40, 60, 100, 20) },
new RectangleF[]
{
new(10, 10, 100, 50),
new(10, 60, 30, 20),
new(10, 80, 100, 30)
}
};
// Intersecting from the left.
yield return new object[]
{
new Region(new Rectangle(70, 10, 100, 100)),
new RectangleF[] { new(40, 60, 100, 20) },
new RectangleF[]
{
new(70, 10, 100, 50),
new(140, 60, 30, 20),
new(70, 80, 100, 30)
}
};
// Intersecting from the top.
yield return new object[]
{
new Region(new Rectangle(40, 100, 100, 100)),
new RectangleF[] { new(70, 80, 50, 40) },
new RectangleF[]
{
new(40, 100, 30, 20),
new(120, 100, 20, 20),
new(40, 120, 100, 80)
}
};
// Intersecting from the bottom.
yield return new object[]
{
new Region(new Rectangle(40, 10, 100, 100)),
new RectangleF[] { new(70, 80, 50, 40) },
new RectangleF[]
{
new(40, 10, 100, 70),
new(40, 80, 30, 30),
new(120, 80, 20, 30)
}
};
// Multiple regions.
yield return new object[]
{
new Region(new Rectangle(30, 30, 80, 80)),
new RectangleF[]
{
new(45, 45, 200, 200),
new(160, 260, 10, 10),
new(170, 260, 10, 10)
},
new RectangleF[]
{
new(30, 30, 80, 15),
new(30, 45, 15, 65)
}
};
// Intersecting from the top with a larger rect.
yield return new object[]
{
new Region(new Rectangle(50, 100, 100, 100)),
new RectangleF[] { new(30, 70, 150, 40) },
new RectangleF[] { new(50, 110, 100, 90) }
};
// Intersecting from the right with a larger rect.
yield return new object[]
{
new Region(new Rectangle(70, 60, 100, 70)),
new RectangleF[] { new(40, 10, 100, 150) },
new RectangleF[] { new(140, 60, 30, 70) }
};
// Intersecting from the left with a larger rect.
yield return new object[]
{
new Region(new Rectangle(70, 60, 100, 70)),
new RectangleF[] { new(100, 10, 100, 150) },
new RectangleF[] { new(70, 60, 30, 70) }
};
// Intersecting from the bottom with a larger rect.
yield return new object[]
{
new Region(new Rectangle(20, 20, 100, 100)),
new RectangleF[] { new(10, 80, 140, 150) },
new RectangleF[] { new(20, 20, 100, 60) }
};
yield return new object[]
{
new Region(new Rectangle(130, 30, 60, 80)),
new RectangleF[] { new(170, 40, 60, 80) },
new RectangleF[]
{
new(130, 30, 60, 10),
new(130, 40, 40, 70)
}
};
}
[Theory]
[MemberData(nameof(Exclude_TestData))]
public void Exclude_Region_Success(Region region, RectangleF[] rectangles, RectangleF[] expectedScans)
{
using (region)
{
foreach (RectangleF rect in rectangles)
{
using Region other = new(rect);
region.Exclude(other);
}
using Matrix matrix = new();
Assert.Equal(expectedScans, region.GetRegionScans(matrix));
}
}
[Fact]
public void Exclude_UnionRegion_Success()
{
using Region region = new(new RectangleF(20, 20, 20, 20));
using Region union = new(new RectangleF(20, 80, 20, 10));
using Matrix matrix = new();
union.Union(new RectangleF(60, 60, 30, 10));
region.Exclude(union);
Assert.Equal([new(20, 20, 20, 20)], region.GetRegionScans(matrix));
}
[Fact]
public void Exclude_InfiniteRegion_Success()
{
using Region region = new(new Rectangle(1, 2, 3, 4));
using Region other = new();
using Matrix matrix = new();
region.Exclude(other);
Assert.Equal([], region.GetRegionScans(matrix));
}
[Fact]
public void Exclude_NullRegion_ThrowsArgumentNullException()
{
using Region region = new();
AssertExtensions.Throws<ArgumentNullException>("region", () => region.Exclude((Region)null));
}
[Fact]
public void Exclude_DisposedRegion_ThrowsArgumentException()
{
AssertExtensions.Throws<ArgumentException>(null, () => new Region().Exclude(CreateDisposedRegion()));
}
[Fact]
public void Exclude_SameRegion_ThrowsInvalidOperationException()
{
using Region region = new();
Assert.Throws<InvalidOperationException>(() => region.Exclude(region));
}
[Theory]
[MemberData(nameof(Exclude_TestData))]
public void Exclude_Rectangle_Success(Region region, RectangleF[] rectangles, RectangleF[] expectedScans)
{
using (region)
{
foreach (RectangleF rect in rectangles)
{
region.Exclude(new Rectangle((int)rect.X, (int)rect.Y, (int)rect.Width, (int)rect.Height));
}
using Matrix matrix = new();
Assert.Equal(expectedScans, region.GetRegionScans(matrix));
}
}
[Theory]
[MemberData(nameof(Exclude_TestData))]
public void Exclude_RectangleF_Success(Region region, RectangleF[] rectangles, RectangleF[] expectedScans)
{
using (region)
{
foreach (RectangleF rect in rectangles)
{
region.Exclude(rect);
}
using Matrix matrix = new();
Assert.Equal(expectedScans, region.GetRegionScans(matrix));
}
}
[Theory]
[MemberData(nameof(Exclude_TestData))]
public void Exclude_GraphicsPath_Success(Region region, RectangleF[] rectangles, RectangleF[] expectedScans)
{
using (region)
{
foreach (RectangleF rect in rectangles)
{
using GraphicsPath path = new();
path.AddRectangle(rect);
region.Exclude(path);
}
using Matrix matrix = new();
Assert.Equal(expectedScans, region.GetRegionScans(matrix));
}
}
[Fact]
public void Exclude_EmptyPathWithInfiniteRegion_MakesInfinite()
{
using Region region = new();
using GraphicsPath graphicsPath = new();
region.Exclude(graphicsPath);
Assert.True(region.IsInfinite(s_graphic));
}
[Fact]
public void Exclude_NullGraphicsPath_ThrowsArgumentNullException()
{
using Region region = new();
AssertExtensions.Throws<ArgumentNullException>("path", () => region.Exclude((GraphicsPath)null));
}
[Fact]
public void Exclude_Disposed_ThrowsArgumentException()
{
Region disposedRegion = CreateDisposedRegion();
using GraphicsPath graphicsPath = new();
using Region other = new();
AssertExtensions.Throws<ArgumentException>(null, () => disposedRegion.Exclude(graphicsPath));
AssertExtensions.Throws<ArgumentException>(null, () => disposedRegion.Exclude(default(Rectangle)));
AssertExtensions.Throws<ArgumentException>(null, () => disposedRegion.Exclude(default(RectangleF)));
AssertExtensions.Throws<ArgumentException>(null, () => disposedRegion.Exclude(other));
}
[Fact]
public void FromHrgn_ValidHrgn_ReturnsExpected()
{
using Region region = new(new Rectangle(1, 2, 3, 4));
IntPtr handle1 = region.GetHrgn(s_graphic);
IntPtr handle2 = region.GetHrgn(s_graphic);
Assert.NotEqual(IntPtr.Zero, handle1);
Assert.NotEqual(handle1, handle2);
Region newRegion = Region.FromHrgn(handle1);
IntPtr handle3 = newRegion.GetHrgn(s_graphic);
Assert.NotEqual(handle3, handle1);
Assert.Equal(new RectangleF(1, 2, 3, 4), newRegion.GetBounds(s_graphic));
region.ReleaseHrgn(handle1);
region.ReleaseHrgn(handle2);
newRegion.ReleaseHrgn(handle3);
}
[Fact]
public void FromHrgn_ZeroHrgn_ThrowsArgumentException()
{
AssertExtensions.Throws<ArgumentException>(null, () => Region.FromHrgn(IntPtr.Zero));
}
[Fact]
public void GetHrgn_Infinite_ReturnsZero()
{
using Region region = new(new Rectangle(1, 2, 3, 4));
IntPtr handle = region.GetHrgn(s_graphic);
Assert.NotEqual(IntPtr.Zero, handle);
region.ReleaseHrgn(handle);
region.MakeInfinite();
Assert.Equal(IntPtr.Zero, region.GetHrgn(s_graphic));
}
[Fact]
public void GetHrgn_Empty_ReturnsNonZero()
{
using Region region = new();
Assert.Equal(IntPtr.Zero, region.GetHrgn(s_graphic));
region.MakeEmpty();
IntPtr handle = region.GetHrgn(s_graphic);
Assert.NotEqual(IntPtr.Zero, handle);
region.ReleaseHrgn(handle);
}
[Fact]
public void GetHrgn_NullGraphics_ThrowsArgumentNullException()
{
using Region region = new();
AssertExtensions.Throws<ArgumentNullException>("g", () => region.GetHrgn(null));
}
[Fact]
public void GetHrgn_Disposed_ThrowsArgumentException()
{
AssertExtensions.Throws<ArgumentException>(null, () => CreateDisposedRegion().GetHrgn(s_graphic));
}
[Fact]
public void ReleaseHrgn_ZeroHandle_ThrowsArgumentNullException()
{
using Region region = new();
AssertExtensions.Throws<ArgumentNullException>("regionHandle", () => region.ReleaseHrgn(IntPtr.Zero));
}
[Fact]
public void GetBounds_NullGraphics_ThrowsArgumentNullException()
{
using Region region = new();
AssertExtensions.Throws<ArgumentNullException>("g", () => region.GetBounds(null));
}
[Fact]
public void GetBounds_DisposedGraphics_ThrowsArgumentException()
{
using Region region = new();
using Bitmap image = new(10, 10);
var graphics = Graphics.FromImage(image);
graphics.Dispose();
AssertExtensions.Throws<ArgumentException>(null, () => region.GetBounds(graphics));
}
[Fact]
public void GetBounds_Disposed_ThrowsArgumentException()
{
AssertExtensions.Throws<ArgumentException>(null, () => CreateDisposedRegion().GetBounds(s_graphic));
}
[Fact]
public void GetRegionData_Disposed_ThrowsArgumentException()
{
AssertExtensions.Throws<ArgumentException>(null, () => CreateDisposedRegion().GetRegionData());
}
[Fact]
public void GetRegionScans_CustomMatrix_TransformsRegionScans()
{
using Matrix matrix = new();
using Region region = new(new Rectangle(1, 2, 3, 4));
using Matrix emptyMatrix = new();
matrix.Translate(10, 11);
matrix.Scale(5, 6);
Assert.Equal([new(1, 2, 3, 4)], region.GetRegionScans(emptyMatrix));
Assert.Equal([new(15, 23, 15, 24)], region.GetRegionScans(matrix));
}
[Fact]
public void GetRegionScans_NullMatrix_ThrowsArgumentNullException()
{
using Region region = new();
AssertExtensions.Throws<ArgumentNullException>("matrix", () => region.GetRegionScans(null));
}
[Fact]
public void GetRegionScans_Disposed_ThrowsArgumentException()
{
using Matrix matrix = new();
AssertExtensions.Throws<ArgumentException>(null, () => CreateDisposedRegion().GetRegionScans(matrix));
}
[Fact]
public void GetRegionScans_DisposedMatrix_ThrowsArgumentException()
{
using Region region = new();
Matrix matrix = new();
matrix.Dispose();
AssertExtensions.Throws<ArgumentException>(null, () => region.GetRegionScans(matrix));
}
[Fact]
public void Intersect_SmallerRect_Success()
{
using Region clipRegion = new();
using Matrix matrix = new();
Rectangle smaller = new(5, 5, -10, -10);
clipRegion.Intersect(smaller);
Assert.False(clipRegion.IsEmpty(s_graphic));
Assert.False(clipRegion.IsInfinite(s_graphic));
RectangleF[] rects = clipRegion.GetRegionScans(matrix);
Assert.Single(rects);
Assert.Equal(new RectangleF(-5, -5, 10, 10), rects[0]);
}
public static IEnumerable<object[]> Intersect_TestData()
{
yield return new object[]
{
new Region(new Rectangle(500, 30, 60, 80)),
new RectangleF[] { new(500, 30, 60, 80) },
new RectangleF[] { new(500, 30, 60, 80) }
};
yield return new object[]
{
new Region(new Rectangle(0, 0, 0, 0)),
new RectangleF[] { new(500, 30, 60, 80) },
Array.Empty<RectangleF>()
};
yield return new object[]
{
new Region(new Rectangle(500, 30, 60, 80)),
new RectangleF[] { RectangleF.Empty },
Array.Empty<RectangleF>()
};
yield return new object[]
{
new Region(),
new RectangleF[] { new(520, 40, 60, 80) },
new RectangleF[] { new Rectangle(520, 40, 60, 80) }
};
yield return new object[]
{
new Region(),
new RectangleF[] { RectangleF.Empty },
Array.Empty<RectangleF>()
};
yield return new object[]
{
new Region(new RectangleF(260, 30, 60, 80)),
new RectangleF[] { new(290, 40, 60, 90) },
new RectangleF[] { new(290, 40, 30, 70) }
};
yield return new object[]
{
new Region(new RectangleF(20, 330, 40, 50)),
new RectangleF[]
{
new(50, 340, 40, 50),
new(70, 360, 30, 50),
new(80, 400, 30, 10)
},
Array.Empty<RectangleF>()
};
}
[Theory]
[MemberData(nameof(Intersect_TestData))]
public void Intersect_Region_Success(Region region, RectangleF[] rectangles, RectangleF[] expectedScans)
{
using (region)
{
foreach (RectangleF rect in rectangles)
{
using Region rectangleRegion = new(rect);
region.Intersect(rectangleRegion);
}
using Matrix matrix = new();
Assert.Equal(expectedScans, region.GetRegionScans(matrix));
}
}
[Fact]
public void Intersect_InfiniteRegion_Success()
{
using Region region = new(new Rectangle(1, 2, 3, 4));
using Matrix matrix = new();
using Region infiniteRegion = new();
region.Intersect(infiniteRegion);
Assert.Equal([new Rectangle(1, 2, 3, 4)], region.GetRegionScans(matrix));
}
[Fact]
public void Intersect_NullRegion_ThrowsArgumentNullException()
{
using Region region = new();
AssertExtensions.Throws<ArgumentNullException>("region", () => region.Intersect((Region)null));
}
[Fact]
public void Intersect_DisposedRegion_ThrowsArgumentException()
{
AssertExtensions.Throws<ArgumentException>(null, () => new Region().Intersect(CreateDisposedRegion()));
}
[Fact]
public void Intersect_SameRegion_ThrowsInvalidOperationException()
{
using Region region = new();
Assert.Throws<InvalidOperationException>(() => region.Intersect(region));
}
[Theory]
[MemberData(nameof(Intersect_TestData))]
public void Intersect_Rectangle_Success(Region region, RectangleF[] rectangles, RectangleF[] expectedScans)
{
using (region)
{
foreach (RectangleF rect in rectangles)
{
region.Intersect(new Rectangle((int)rect.X, (int)rect.Y, (int)rect.Width, (int)rect.Height));
}
using Matrix matrix = new();
Assert.Equal(expectedScans, region.GetRegionScans(matrix));
}
}
[Fact]
public void Intersect_InfiniteRegionWithSmallerRectangle_Success()
{
using Region region = new();
using Matrix matrix = new();
region.Intersect(new Rectangle(5, 5, -10, -10));
Assert.False(region.IsEmpty(s_graphic));
Assert.False(region.IsInfinite(s_graphic));
Assert.Equal([new(-5, -5, 10, 10)], region.GetRegionScans(matrix));
}
[Theory]
[MemberData(nameof(Intersect_TestData))]
public void Intersect_RectangleF_Success(Region region, RectangleF[] rectangles, RectangleF[] expectedScans)
{
using (region)
{
foreach (RectangleF rect in rectangles)
{
region.Intersect(rect);
}
using Matrix matrix = new();
Assert.Equal(expectedScans, region.GetRegionScans(matrix));
}
}
[Fact]
public void Intersect_InfiniteRegionWithSmallerRectangleF_Success()
{
using Region region = new();
using Matrix matrix = new();
region.Intersect(new RectangleF(5, 5, -10, -10));
Assert.False(region.IsEmpty(s_graphic));
Assert.False(region.IsInfinite(s_graphic));
Assert.Equal([new(-5, -5, 10, 10)], region.GetRegionScans(matrix));
}
[Theory]
[MemberData(nameof(Intersect_TestData))]
public void Intersect_GraphicsPath_Success(Region region, RectangleF[] rectangles, RectangleF[] expectedScans)
{
using (region)
{
foreach (RectangleF rect in rectangles)
{
using GraphicsPath path = new();
path.AddRectangle(rect);
region.Intersect(path);
}
using Matrix matrix = new();
Assert.Equal(expectedScans, region.GetRegionScans(matrix));
}
}
[Fact]
public void Intersect_EmptyPathWithInfiniteRegion_MakesEmpty()
{
using Region region = new();
using GraphicsPath graphicsPath = new();
region.Intersect(graphicsPath);
Assert.True(region.IsEmpty(s_graphic));
}
[Fact]
public void Intersect_NullGraphicsPath_ThrowsArgumentNullException()
{
using Region region = new();
AssertExtensions.Throws<ArgumentNullException>("path", () => region.Intersect((GraphicsPath)null));
}
[Fact]
public void Intersect_Disposed_ThrowsArgumentException()
{
Region disposedRegion = CreateDisposedRegion();
using GraphicsPath graphicsPath = new();
using Region other = new();
AssertExtensions.Throws<ArgumentException>(null, () => disposedRegion.Intersect(graphicsPath));
AssertExtensions.Throws<ArgumentException>(null, () => disposedRegion.Intersect(default(Rectangle)));
AssertExtensions.Throws<ArgumentException>(null, () => disposedRegion.Intersect(default(RectangleF)));
AssertExtensions.Throws<ArgumentException>(null, () => disposedRegion.Intersect(other));
}
[Fact]
public void IsEmpty_NullGraphics_ThrowsArgumentNullException()
{
using Region region = new();
AssertExtensions.Throws<ArgumentNullException>("g", () => region.IsEmpty(null));
}
[Fact]
public void IsEmpty_Disposed_ThrowsArgumentException()
{
AssertExtensions.Throws<ArgumentException>(null, () => CreateDisposedRegion().IsEmpty(s_graphic));
}
[Fact]
public void IsInfinite_NullGraphics_ThrowsArgumentNullException()
{
using Region region = new();
AssertExtensions.Throws<ArgumentNullException>("g", () => region.IsInfinite(null));
}
[Fact]
public void IsInfinite_DisposedGraphics_ThrowsArgumentException()
{
using Region region = new();
using Bitmap image = new(10, 10);
var graphics = Graphics.FromImage(image);
graphics.Dispose();
AssertExtensions.Throws<ArgumentException>(null, () => region.IsInfinite(graphics));
}
[Fact]
public void IsInfinite_Disposed_ThrowsArgumentException()
{
AssertExtensions.Throws<ArgumentException>(null, () => CreateDisposedRegion().IsInfinite(s_graphic));
}
public static IEnumerable<object[]> IsVisible_Rectangle_TestData()
{
Region infiniteExclude = new();
infiniteExclude.Exclude(new Rectangle(387, 292, 189, 133));
infiniteExclude.Exclude(new Rectangle(387, 66, 189, 133));
yield return new object[] { infiniteExclude, new Rectangle(66, 292, 189, 133), true };
yield return new object[] { new Region(), Rectangle.Empty, false };
yield return new object[] { new Region(new Rectangle(0, 0, 10, 10)), new Rectangle(0, 0, 0, 1), false };
yield return new object[] { new Region(new Rectangle(500, 30, 60, 80)), new Rectangle(500, 30, 60, 80), true };
yield return new object[] { new Region(new Rectangle(500, 30, 60, 80)), new Rectangle(520, 40, 60, 80), true };
yield return new object[] { new Region(new Rectangle(1, 1, 2, 1)), new Rectangle(1, 1, 2, 1), true };
yield return new object[] { new Region(new Rectangle(1, 1, 2, 1)), new Rectangle(1, 1, 2, 2), true };
yield return new object[] { new Region(new Rectangle(1, 1, 2, 1)), new Rectangle(1, 1, 10, 10), true };
yield return new object[] { new Region(new Rectangle(1, 1, 2, 1)), new Rectangle(1, 1, 1, 1), true };
yield return new object[] { new Region(new Rectangle(1, 1, 2, 1)), new Rectangle(2, 2, 1, 1), false };
yield return new object[] { new Region(new Rectangle(1, 1, 2, 1)), new Rectangle(0, 0, 1, 1), false };
yield return new object[] { new Region(new Rectangle(1, 1, 2, 1)), new Rectangle(3, 3, 1, 1), false };
}
[Theory]
[MemberData(nameof(IsVisible_Rectangle_TestData))]
public void IsVisible_Rectangle_ReturnsExpected(Region region, Rectangle rectangle, bool expected)
{
using (region)
using (Bitmap image = new(10, 10))
{
var disposedGraphics = Graphics.FromImage(image);
disposedGraphics.Dispose();
Assert.Equal(expected, region.IsVisible(rectangle));
Assert.Equal(expected, region.IsVisible((RectangleF)rectangle));
Assert.Equal(expected, region.IsVisible(rectangle, s_graphic));
Assert.Equal(expected, region.IsVisible(rectangle, disposedGraphics));
Assert.Equal(expected, region.IsVisible(rectangle, null));
Assert.Equal(expected, region.IsVisible((RectangleF)rectangle, s_graphic));
Assert.Equal(expected, region.IsVisible((RectangleF)rectangle, disposedGraphics));
Assert.Equal(expected, region.IsVisible((RectangleF)rectangle, null));
Assert.Equal(expected, region.IsVisible(rectangle.X, rectangle.Y, rectangle.Width, rectangle.Height));
Assert.Equal(expected, region.IsVisible((float)rectangle.X, rectangle.Y, rectangle.Width, rectangle.Height));
Assert.Equal(expected, region.IsVisible(rectangle.X, rectangle.Y, rectangle.Width, rectangle.Height, s_graphic));
Assert.Equal(expected, region.IsVisible(rectangle.X, rectangle.Y, rectangle.Width, rectangle.Height, disposedGraphics));
Assert.Equal(expected, region.IsVisible(rectangle.X, rectangle.Y, rectangle.Width, rectangle.Height, null));
Assert.Equal(expected, region.IsVisible((float)rectangle.X, rectangle.Y, rectangle.Width, rectangle.Height, s_graphic));
Assert.Equal(expected, region.IsVisible((float)rectangle.X, rectangle.Y, rectangle.Width, rectangle.Height, disposedGraphics));
Assert.Equal(expected, region.IsVisible((float)rectangle.X, rectangle.Y, rectangle.Width, rectangle.Height, null));
}
}
public static IEnumerable<object[]> IsVisible_Point_TestData()
{
Region infiniteExclude = new();
infiniteExclude.Exclude(new Rectangle(387, 292, 189, 133));
infiniteExclude.Exclude(new Rectangle(387, 66, 189, 133));
yield return new object[] { infiniteExclude, new Point(66, 292), true };
yield return new object[] { new Region(), Point.Empty, true };
yield return new object[] { new Region(new Rectangle(500, 30, 60, 80)), new Point(500, 29), false };
yield return new object[] { new Region(new Rectangle(500, 30, 60, 80)), new Point(500, 30), true };
yield return new object[] { new Region(new Rectangle(1, 1, 2, 1)), new Point(0, 1), false };
yield return new object[] { new Region(new Rectangle(1, 1, 2, 1)), new Point(1, 0), false };
yield return new object[] { new Region(new Rectangle(1, 1, 2, 1)), new Point(2, 0), false };
yield return new object[] { new Region(new Rectangle(1, 1, 2, 1)), new Point(3, 0), false };
yield return new object[] { new Region(new Rectangle(1, 1, 2, 1)), new Point(1, 1), true };
yield return new object[] { new Region(new Rectangle(1, 1, 2, 1)), new Point(2, 1), true };
yield return new object[] { new Region(new Rectangle(1, 1, 2, 1)), new Point(3, 1), false };
yield return new object[] { new Region(new Rectangle(1, 1, 2, 1)), new Point(0, 2), false };
yield return new object[] { new Region(new Rectangle(1, 1, 2, 1)), new Point(2, 2), false };
yield return new object[] { new Region(new Rectangle(1, 1, 2, 1)), new Point(3, 2), false };
}
[Theory]
[MemberData(nameof(IsVisible_Point_TestData))]
public void IsVisible_Point_ReturnsExpected(Region region, Point point, bool expected)
{
using (region)
using (Bitmap image = new(10, 10))
{
var disposedGraphics = Graphics.FromImage(image);
disposedGraphics.Dispose();
Assert.Equal(expected, region.IsVisible(point));
Assert.Equal(expected, region.IsVisible((PointF)point));
Assert.Equal(expected, region.IsVisible(point, s_graphic));
Assert.Equal(expected, region.IsVisible(point, disposedGraphics));
Assert.Equal(expected, region.IsVisible(point, null));
Assert.Equal(expected, region.IsVisible((PointF)point, s_graphic));
Assert.Equal(expected, region.IsVisible((PointF)point, disposedGraphics));
Assert.Equal(expected, region.IsVisible((PointF)point, null));
Assert.Equal(expected, region.IsVisible(point.X, point.Y));
Assert.Equal(expected, region.IsVisible(point.X, point.Y, s_graphic));
Assert.Equal(expected, region.IsVisible(point.X, point.Y, disposedGraphics));
Assert.Equal(expected, region.IsVisible(point.X, point.Y, null));
Assert.Equal(expected, region.IsVisible(point.X, point.Y, s_graphic));
Assert.Equal(expected, region.IsVisible(point.X, point.Y, disposedGraphics));
Assert.Equal(expected, region.IsVisible(point.X, point.Y, null));
Assert.Equal(expected, region.IsVisible((float)point.X, point.Y, s_graphic));
Assert.Equal(expected, region.IsVisible((float)point.X, point.Y, disposedGraphics));
Assert.Equal(expected, region.IsVisible((float)point.X, point.Y, null));
}
}
[Fact]
public void IsVisible_Disposed_ThrowsArgumentException()
{
Region disposedRegion = CreateDisposedRegion();
AssertExtensions.Throws<ArgumentException>(null, () => disposedRegion.IsVisible(1f, 2f));
AssertExtensions.Throws<ArgumentException>(null, () => disposedRegion.IsVisible(new PointF(1, 2)));
AssertExtensions.Throws<ArgumentException>(null, () => disposedRegion.IsVisible(new Point(1, 2)));
AssertExtensions.Throws<ArgumentException>(null, () => disposedRegion.IsVisible(1f, 2f, s_graphic));
AssertExtensions.Throws<ArgumentException>(null, () => disposedRegion.IsVisible(new PointF(1, 2), s_graphic));
AssertExtensions.Throws<ArgumentException>(null, () => disposedRegion.IsVisible(new Point(1, 2), s_graphic));
AssertExtensions.Throws<ArgumentException>(null, () => disposedRegion.IsVisible(1f, 2f, 3f, 4f));
AssertExtensions.Throws<ArgumentException>(null, () => disposedRegion.IsVisible(new Rectangle(1, 2, 3, 4)));
AssertExtensions.Throws<ArgumentException>(null, () => disposedRegion.IsVisible(new RectangleF(1, 2, 3, 4)));
AssertExtensions.Throws<ArgumentException>(null, () => disposedRegion.IsVisible(1f, 2f, 3f, 4f, s_graphic));
AssertExtensions.Throws<ArgumentException>(null, () => disposedRegion.IsVisible(new Rectangle(1, 2, 3, 4), s_graphic));
AssertExtensions.Throws<ArgumentException>(null, () => disposedRegion.IsVisible(new RectangleF(1, 2, 3, 4), s_graphic));
AssertExtensions.Throws<ArgumentException>(null, () => disposedRegion.IsVisible(1, 2, s_graphic));
AssertExtensions.Throws<ArgumentException>(null, () => disposedRegion.IsVisible(1, 2, 3, 4));
AssertExtensions.Throws<ArgumentException>(null, () => disposedRegion.IsVisible(1, 2, 3, 4, s_graphic));
}
[Theory]
[MemberData(nameof(Region_TestData))]
public void MakeEmpty_NonEmpty_Success(Region region)
{
using (region)
{
region.MakeEmpty();
Assert.True(region.IsEmpty(s_graphic));
Assert.False(region.IsInfinite(s_graphic));
Assert.Equal(RectangleF.Empty, region.GetBounds(s_graphic));
using (Matrix matrix = new())
{
Assert.Empty(region.GetRegionScans(matrix));
}
region.MakeEmpty();
Assert.True(region.IsEmpty(s_graphic));
}
}
[Fact]
public void MakeEmpty_Disposed_ThrowsArgumentException()
{
AssertExtensions.Throws<ArgumentException>(null, () => CreateDisposedRegion().MakeEmpty());
}
[Theory]
[MemberData(nameof(Region_TestData))]
public void MakeInfinite_NonInfinity_Success(Region region)
{
using (region)
{
region.MakeInfinite();
Assert.False(region.IsEmpty(s_graphic));
Assert.True(region.IsInfinite(s_graphic));
Assert.Equal(new RectangleF(-4194304, -4194304, 8388608, 8388608), region.GetBounds(s_graphic));
region.MakeInfinite();
Assert.False(region.IsEmpty(s_graphic));
Assert.True(region.IsInfinite(s_graphic));
}
}
[Fact]
public void MakeInfinite_Disposed_ThrowsArgumentException()
{
AssertExtensions.Throws<ArgumentException>(null, () => CreateDisposedRegion().MakeInfinite());
}
public static IEnumerable<object[]> Union_TestData()
{
yield return new object[]
{
new Region(new Rectangle(500, 30, 60, 80)),
new RectangleF[] { new(500, 30, 60, 80) },
new RectangleF[] { new(500, 30, 60, 80) }
};
yield return new object[]
{
new Region(new Rectangle(500, 30, 60, 80)),
new RectangleF[] { RectangleF.Empty },
new RectangleF[] { new(500, 30, 60, 80) }
};
yield return new object[]
{
new Region(new Rectangle(500, 30, 60, 80)),
new RectangleF[] { new(520, 30, 60, 80) },
new RectangleF[] { new(500, 30, 80, 80) }
};
yield return new object[]
{
new Region(new Rectangle(500, 30, 60, 80)),
new RectangleF[] { new(520, 40, 60, 80) },
new RectangleF[]
{
new(500, 30, 60, 10),
new(500, 40, 80, 70),
new(520, 110, 60, 10),
}
};
yield return new object[]
{
new Region(),
new RectangleF[] { new(520, 40, 60, 80) },
new RectangleF[] { new Rectangle(-4194304, -4194304, 8388608, 8388608) }
};
yield return new object[]
{
new Region(),
new RectangleF[] { RectangleF.Empty },
new RectangleF[] { new Rectangle(-4194304, -4194304, 8388608, 8388608) }
};
// No intersecting rects.
yield return new object[]
{
new Region(new Rectangle(20, 20, 20, 20)),
new RectangleF[]
{
new(20, 80, 20, 10),
new(60, 60, 30, 10)
},
new RectangleF[]
{
new(20, 20, 20, 20),
new(60, 60, 30, 10),
new(20, 80, 20, 10)
}
};
yield return new object[]
{
new Region(new Rectangle(20, 180, 40, 50)),
new RectangleF[]
{
new(50, 190, 40, 50),
new(70, 210, 30, 50)
},
new RectangleF[]
{
new(20, 180, 40, 10),
new(20, 190, 70, 20),
new(20, 210, 80, 20),
new(50, 230, 50, 10),
new(70, 240, 30, 20)
}
};
yield return new object[]
{
new Region(new Rectangle(20, 330, 40, 50)),
new RectangleF[]
{
new(50, 340, 40, 50),
new(70, 360, 30, 50),
new(80, 400, 30, 10)
},
new RectangleF[]
{
new(20, 330, 40, 10),
new(20, 340, 70, 20),
new(20, 360, 80, 20),
new(50, 380, 50, 10),
new(70, 390, 30, 10),
new(70, 400, 40, 10)
}
};
yield return new object[]
{
new Region(new Rectangle(10, 20, 50, 50)),
new RectangleF[]
{
new(100, 100, 60, 60),
new(200, 200, 80, 80)
},
new RectangleF[]
{
new(10, 20, 50, 50),
new(100, 100, 60, 60),
new(200, 200, 80, 80)
}
};
// Intersecting from the right.
yield return new object[]
{
new Region(new Rectangle(10, 10, 100, 100)),
new RectangleF[] { new(40, 60, 100, 20) },
new RectangleF[]
{
new(10, 10, 100, 50),
new(10, 60, 130, 20),
new(10, 80, 100, 30)
}
};
// Intersecting from the left.
yield return new object[]
{
new Region(new Rectangle(70, 10, 100, 100)),
new RectangleF[] { new(40, 60, 100, 20) },
new RectangleF[]
{
new(70, 10, 100, 50),
new(40, 60, 130, 20),
new(70, 80, 100, 30)
}
};
// Intersecting from the top.
yield return new object[]
{
new Region(new Rectangle(40, 100, 100, 100)),
new RectangleF[] { new(70, 80, 50, 40) },
new RectangleF[]
{
new(70, 80, 50, 20),
new(40, 100, 100, 100)
}
};
// Intersecting from the bottom.
yield return new object[]
{
new Region(new Rectangle(40, 10, 100, 100)),
new RectangleF[] { new(70, 80, 50, 40) },
new RectangleF[]
{
new(40, 10, 100, 100),
new(70, 110, 50, 10)
}
};
// Multiple regions separated by 0 pixels.
yield return new object[]
{
new Region(new Rectangle(30, 30, 80, 80)),
new RectangleF[]
{
new(45, 45, 200, 200),
new(160, 260, 10, 10),
new(170, 260, 10, 10)
},
new RectangleF[]
{
new(30, 30, 80, 15),
new(30, 45, 215, 65),
new(45, 110, 200, 135),
new(160, 260, 20, 10)
}
};
}
[Theory]
[MemberData(nameof(Union_TestData))]
public void Union_Region_Success(Region region, RectangleF[] rectangles, RectangleF[] expectedScans)
{
using (region)
{
foreach (RectangleF rect in rectangles)
{
using Region other = new(rect);
region.Union(other);
}
using Matrix matrix = new();
Assert.Equal(expectedScans, region.GetRegionScans(matrix));
}
}
[Fact]
public void Union_InfiniteRegion_Success()
{
using Region region = new(new Rectangle(1, 2, 3, 4));
using Region other = new();
using Matrix matrix = new();
region.Union(other);
Assert.Equal([new Rectangle(-4194304, -4194304, 8388608, 8388608)], region.GetRegionScans(matrix));
}
[Fact]
public void Union_NullRegion_ThrowsArgumentNullException()
{
using Region region = new();
AssertExtensions.Throws<ArgumentNullException>("region", () => region.Union((Region)null));
}
[Fact]
public void Union_DisposedRegion_ThrowsArgumentException()
{
using Region region = new();
AssertExtensions.Throws<ArgumentException>(null, () => region.Union(CreateDisposedRegion()));
}
[Fact]
public void Union_SameRegion_ThrowsInvalidOperationException()
{
using Region region = new();
Assert.Throws<InvalidOperationException>(() => region.Union(region));
}
[Theory]
[MemberData(nameof(Union_TestData))]
public void Union_Rectangle_Success(Region region, RectangleF[] rectangles, RectangleF[] expectedScans)
{
using (region)
{
foreach (RectangleF rect in rectangles)
{
region.Union(new Rectangle((int)rect.X, (int)rect.Y, (int)rect.Width, (int)rect.Height));
}
using Matrix matrix = new();
Assert.Equal(expectedScans, region.GetRegionScans(matrix));
}
}
[Theory]
[MemberData(nameof(Union_TestData))]
public void Union_RectangleF_Success(Region region, RectangleF[] rectangles, RectangleF[] expectedScans)
{
using (region)
{
foreach (RectangleF rect in rectangles)
{
region.Union(rect);
}
using Matrix matrix = new();
Assert.Equal(expectedScans, region.GetRegionScans(matrix));
}
}
[Theory]
[MemberData(nameof(Union_TestData))]
public void Union_GraphicsPath_Success(Region region, RectangleF[] rectangles, RectangleF[] expectedScans)
{
using (region)
{
foreach (RectangleF rect in rectangles)
{
using GraphicsPath path = new();
path.AddRectangle(rect);
region.Union(path);
}
using Matrix matrix = new();
Assert.Equal(expectedScans, region.GetRegionScans(matrix));
}
}
[Fact]
public void Union_EmptyPathWithInfiniteRegion_MakesInfinite()
{
using Region region = new();
using GraphicsPath graphicsPath = new();
region.Union(graphicsPath);
Assert.True(region.IsInfinite(s_graphic));
}
[Fact]
public void Union_NullGraphicsPath_ThrowsArgumentNullException()
{
using Region region = new();
AssertExtensions.Throws<ArgumentNullException>("path", () => region.Union((GraphicsPath)null));
}
[Fact]
public void Union_Disposed_ThrowsArgumentException()
{
Region disposedRegion = CreateDisposedRegion();
using GraphicsPath graphicsPath = new();
using Region other = new();
AssertExtensions.Throws<ArgumentException>(null, () => disposedRegion.Union(graphicsPath));
AssertExtensions.Throws<ArgumentException>(null, () => disposedRegion.Union(default(Rectangle)));
AssertExtensions.Throws<ArgumentException>(null, () => disposedRegion.Union(default(RectangleF)));
AssertExtensions.Throws<ArgumentException>(null, () => disposedRegion.Union(disposedRegion));
}
[Fact]
public void Transform_EmptyMatrix_Nop()
{
using Region region = new(new RectangleF(1, 2, 3, 4));
using Matrix matrix = new();
region.Transform(matrix);
Assert.Equal([new(1, 2, 3, 4)], region.GetRegionScans(matrix));
}
[Fact]
public void Transform_CustomMatrix_Success()
{
using Region region = new(new RectangleF(1, 2, 3, 4));
using Matrix matrix = new();
using Matrix emptyMatrix = new();
matrix.Translate(10, 11);
matrix.Scale(5, 6);
region.Transform(matrix);
Assert.Equal([new(15, 23, 15, 24)], region.GetRegionScans(emptyMatrix));
}
[Theory]
[InlineData(0, 0, 0)]
[InlineData(2, 2, 0)]
[InlineData(0.5, 0.5, 0)]
[InlineData(1, 1, 45)]
public void Transform_Infinity_Nop(float scaleX, float scaleY, int angle)
{
using Region region = new();
using Matrix matrix = new();
using Matrix emptyMatrix = new();
matrix.Translate(10, 11);
matrix.Scale(scaleX, scaleY);
matrix.Rotate(angle);
region.Transform(matrix);
Assert.True(region.IsInfinite(s_graphic));
Assert.Equal([new(-4194304, -4194304, 8388608, 8388608)], region.GetRegionScans(emptyMatrix));
}
[Fact]
public void Transform_InfinityIntersectScale_Success()
{
using Region region = new();
using Matrix matrix = new();
using Matrix emptyMatrix = new();
matrix.Scale(2, 0.5f);
region.Intersect(new Rectangle(-10, -10, 20, 20));
region.Transform(matrix);
Assert.False(region.IsInfinite(s_graphic));
Assert.Equal([new(-20, -5, 40, 10)], region.GetRegionScans(emptyMatrix));
}
[Fact]
public void Transform_InfinityIntersectTransform_Success()
{
using Region region = new();
using Matrix matrix = new(2, 0, 0, 0.5f, 10, 10);
using Matrix emptyMatrix = new();
region.Intersect(new Rectangle(-10, -10, 20, 20));
region.Transform(matrix);
Assert.False(region.IsInfinite(s_graphic));
Assert.Equal([new(-10, 5, 40, 10)], region.GetRegionScans(emptyMatrix));
}
[Fact]
public void Transform_NullMatrix_ThrowsArgumentNullException()
{
using Region region = new();
AssertExtensions.Throws<ArgumentNullException>("matrix", () => region.Transform(null));
}
[Fact]
public void Transform_Disposed_ThrowsArgumentException()
{
using Matrix matrix = new();
AssertExtensions.Throws<ArgumentException>(null, () => CreateDisposedRegion().Transform(matrix));
}
[Theory]
[InlineData(0, 0)]
[InlineData(2, 3)]
[InlineData(-2, -3)]
public void Translate_Int_Success(float dx, float dy)
{
using Region region = new(new RectangleF(1, 2, 3, 4));
using Matrix matrix = new();
region.Translate(dx, dy);
Assert.Equal([new(1 + dx, 2 + dy, 3, 4)], region.GetRegionScans(matrix));
}
[Fact]
public void Translate_IntInfinityIntersect_Success()
{
using Region region = new();
using Matrix matrix = new();
region.Intersect(new Rectangle(-10, -10, 20, 20));
region.Translate(10, 10);
Assert.False(region.IsInfinite(s_graphic));
Assert.Equal([new(0, 0, 20, 20)], region.GetRegionScans(matrix));
}
[Theory]
[InlineData(0, 0)]
[InlineData(2, 3)]
public void Translate_Float_Success(int dx, int dy)
{
using Region region = new(new RectangleF(1, 2, 3, 4));
using Matrix matrix = new();
region.Translate(dx, dy);
Assert.Equal([new(1 + dx, 2 + dy, 3, 4)], region.GetRegionScans(matrix));
}
[Fact]
public void Translate_FloatInfinityIntersect_Success()
{
using Region region = new();
using Matrix matrix = new();
region.Intersect(new Rectangle(-10, -10, 20, 20));
region.Translate(10f, 10f);
Assert.False(region.IsInfinite(s_graphic));
Assert.Equal([new(0, 0, 20, 20)], region.GetRegionScans(matrix));
}
[Fact]
public void Translate_Infinity_Nop()
{
using Region region = new();
using Matrix matrix = new();
region.Translate(10, 10);
region.Translate(10f, 10f);
Assert.True(region.IsInfinite(s_graphic));
Assert.Equal([new(-4194304, -4194304, 8388608, 8388608)], region.GetRegionScans(matrix));
}
[Theory]
[InlineData(float.MaxValue)]
[InlineData(float.MinValue)]
[InlineData(float.NaN)]
[InlineData(float.PositiveInfinity)]
[InlineData(float.NegativeInfinity)]
public void Translate_InvalidFloatValue_EmptiesRegion(float f)
{
using Region region = new(new RectangleF(1, 2, 3, 4));
using Matrix matrix = new();
region.Translate(f, 0);
Assert.True(region.IsEmpty(s_graphic));
Assert.False(region.IsInfinite(s_graphic));
Assert.Empty(region.GetRegionScans(matrix));
}
[Fact]
public void Translate_Disposed_ThrowsArgumentException()
{
Region disposedRegion = CreateDisposedRegion();
AssertExtensions.Throws<ArgumentException>(null, () => disposedRegion.Translate(1, 2));
AssertExtensions.Throws<ArgumentException>(null, () => disposedRegion.Translate(1f, 2f));
}
public static IEnumerable<object[]> Xor_TestData()
{
yield return new object[]
{
new Region(new RectangleF(500, 30, 60, 80)),
new RectangleF[] { new(500, 30, 60, 80) },
Array.Empty<RectangleF>()
};
yield return new object[]
{
new Region(new RectangleF(500, 30, 60, 80)),
new RectangleF[] { RectangleF.Empty },
new RectangleF[] { new(500, 30, 60, 80) }
};
yield return new object[]
{
new Region(new RectangleF(0, 0, 0, 0)),
new RectangleF[] { new(500, 30, 60, 80) },
new RectangleF[] { new(500, 30, 60, 80) }
};
yield return new object[]
{
new Region(),
new RectangleF[] { new(520, 40, 60, 80) },
new RectangleF[]
{
new(-4194304, -4194304, 8388608, 4194344),
new(-4194304, 40, 4194824, 80),
new(580, 40, 4193724, 80),
new(-4194304, 120, 8388608, 4194184)
}
};
yield return new object[]
{
new Region(),
new RectangleF[] { RectangleF.Empty },
new RectangleF[] { new Rectangle(-4194304, -4194304, 8388608, 8388608) }
};
yield return new object[]
{
new Region(new RectangleF(380, 30, 60, 80)),
new RectangleF[] { new(410, 40, 60, 80) },
new RectangleF[]
{
new(380, 30, 60, 10),
new(380, 40, 30, 70),
new(440, 40, 30, 70),
new(410, 110, 60, 10)
}
};
}
[Theory]
[MemberData(nameof(Xor_TestData))]
public void Xor_Region_Success(Region region, RectangleF[] rectangles, RectangleF[] expectedScans)
{
using (region)
{
foreach (RectangleF rect in rectangles)
{
using Region other = new(rect);
region.Xor(other);
}
using Matrix matrix = new();
Assert.Equal(expectedScans, region.GetRegionScans(matrix));
}
}
[Fact]
public void Xor_InfiniteRegion_Success()
{
using Region region = new(new Rectangle(1, 2, 3, 4));
using Region other = new();
using Matrix matrix = new();
region.Xor(other);
Assert.Equal(
[
new(-4194304, -4194304, 8388608, 4194306),
new(-4194304, 2, 4194305, 4),
new(4, 2, 4194300, 4),
new(-4194304, 6, 8388608, 4194298)
], region.GetRegionScans(matrix));
}
[Fact]
public void Xor_NullRegion_ThrowsArgumentNullException()
{
using Region region = new();
AssertExtensions.Throws<ArgumentNullException>("region", () => region.Xor((Region)null));
}
[Fact]
public void Xor_DisposedRegion_ThrowsArgumentException()
{
using Region region = new();
AssertExtensions.Throws<ArgumentException>(null, () => region.Xor(CreateDisposedRegion()));
}
[Fact]
public void Xor_SameRegion_ThrowsInvalidOperationException()
{
using Region region = new();
Assert.Throws<InvalidOperationException>(() => region.Xor(region));
}
[Theory]
[MemberData(nameof(Xor_TestData))]
public void Xor_Rectangle_Success(Region region, RectangleF[] rectangles, RectangleF[] expectedScans)
{
using (region)
{
foreach (RectangleF rect in rectangles)
{
region.Xor(new Rectangle((int)rect.X, (int)rect.Y, (int)rect.Width, (int)rect.Height));
}
using Matrix matrix = new();
Assert.Equal(expectedScans, region.GetRegionScans(matrix));
}
}
[Theory]
[MemberData(nameof(Xor_TestData))]
public void Xor_RectangleF_Success(Region region, RectangleF[] rectangles, RectangleF[] expectedScans)
{
using (region)
{
foreach (RectangleF rect in rectangles)
{
region.Xor(rect);
}
using Matrix matrix = new();
Assert.Equal(expectedScans, region.GetRegionScans(matrix));
}
}
[Theory]
[MemberData(nameof(Xor_TestData))]
public void Xor_GraphicsPath_Success(Region region, RectangleF[] rectangles, RectangleF[] expectedScans)
{
using (region)
{
foreach (RectangleF rect in rectangles)
{
using GraphicsPath path = new();
path.AddRectangle(rect);
region.Xor(path);
}
using Matrix matrix = new();
Assert.Equal(expectedScans, region.GetRegionScans(matrix));
}
}
[Fact]
public void Xor_EmptyPathWithInfiniteRegion_MakesInfinite()
{
using Region region = new();
using GraphicsPath graphicsPath = new();
region.Xor(graphicsPath);
Assert.True(region.IsInfinite(s_graphic));
}
[Fact]
public void Xor_NullGraphicsPath_ThrowsArgumentNullException()
{
using Region region = new();
AssertExtensions.Throws<ArgumentNullException>("path", () => region.Xor((GraphicsPath)null));
}
[Fact]
public void Xor_Disposed_ThrowsArgumentException()
{
Region disposedRegion = CreateDisposedRegion();
using GraphicsPath graphicsPath = new();
using Region other = new();
AssertExtensions.Throws<ArgumentException>(null, () => disposedRegion.Xor(graphicsPath));
AssertExtensions.Throws<ArgumentException>(null, () => disposedRegion.Xor(default(Rectangle)));
AssertExtensions.Throws<ArgumentException>(null, () => disposedRegion.Xor(default(RectangleF)));
AssertExtensions.Throws<ArgumentException>(null, () => disposedRegion.Xor(other));
}
}
|