using System; using System.Drawing; using System.IO; namespace Blacklight.Core.UnitTests { public class CursorImageTests : UnitTestSharp.TestFixture { public static readonly byte[] Red = { 0xFF, 0x00, 0x00, 0xFF }; public static readonly byte[] Green = { 0x00, 0xFF, 0x00, 0xFF }; public static readonly byte[] Blue = { 0x00, 0x00, 0xFF, 0xFF }; public static readonly byte[] Clear = { 0x00, 0x00, 0x00, 0x00 }; public static readonly byte[] Amber = { 0xFF, 0xC0, 0x40, 0xFF }; public static readonly byte[] Violet = { 0x80, 0x00, 0xFF, 0xC0 }; public static readonly byte[] Teal = { 0x00, 0x80, 0x80, 0xFF }; /// /// A 2x2 PNG holding Red, Green on the top row and Blue, Clear on the bottom. /// public static readonly byte[] TwoByTwoPng = { 0x89, 0x50, 0x4E, 0x47, 0x0D, 0x0A, 0x1A, 0x0A, 0x00, 0x00, 0x00, 0x0D, 0x49, 0x48, 0x44, 0x52, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x02, 0x08, 0x06, 0x00, 0x00, 0x00, 0x72, 0xB6, 0x0D, 0x24, 0x00, 0x00, 0x00, 0x13, 0x49, 0x44, 0x41, 0x54, 0x78, 0xDA, 0x63, 0xF8, 0xCF, 0xC0, 0xF0, 0x1F, 0x0C, 0x81, 0x34, 0x88, 0x60, 0x00, 0x00, 0x3F, 0xD2, 0x05, 0xFB, 0x7F, 0xE6, 0x6A, 0x2B, 0x00, 0x00, 0x00, 0x00, 0x49, 0x45, 0x4E, 0x44, 0xAE, 0x42, 0x60, 0x82, }; public static readonly Size GridSize = new Size(3, 2); public static byte[] Pixels(params byte[][] pixels) { var returnMe = new byte[pixels.Length * CursorImage.BytesPerPixel]; for (int i = 0; i < pixels.Length; ++i) { Array.Copy(pixels[i], 0, returnMe, i * CursorImage.BytesPerPixel, CursorImage.BytesPerPixel); } return returnMe; } /// /// Red, Green, Blue over Amber, Violet, Teal. Wider than it is tall, and with no pixel that is all zeroes, /// so a crop that ignored the stride or returned an empty buffer can't pass by coincidence. /// public static byte[] Grid() { return Pixels(Red, Green, Blue, Amber, Violet, Teal); } public class CtorTests : UnitTestSharp.TestFixture { public void AssignsPixelsSizeAndHotspot() { byte[] pixels = Pixels(Red, Green); var cursor = new CursorImage(pixels, new Size(2, 1), new Point(1, 0)); CheckEqual(pixels, cursor.Rgba); CheckEqual(new Size(2, 1), cursor.Size); CheckEqual(new Point(1, 0), cursor.Hotspot); } public void HotspotOnTheLastPixel_IsAccepted() { var cursor = new CursorImage(Pixels(Red, Green, Blue, Clear), new Size(2, 2), new Point(1, 1)); CheckEqual(new Point(1, 1), cursor.Hotspot); } public void NullPixels_Throws() { CheckThrow(typeof(ArgumentNullException)); new CursorImage(null, new Size(1, 1), Point.Empty); } public void ZeroWidth_Throws() { CheckThrow(typeof(ArgumentOutOfRangeException)); new CursorImage(Array.Empty(), new Size(0, 1), Point.Empty); } public void ZeroHeight_Throws() { CheckThrow(typeof(ArgumentOutOfRangeException)); new CursorImage(Array.Empty(), new Size(1, 0), Point.Empty); } public void PixelCountDisagreeingWithTheSize_Throws() { CheckThrow(typeof(ArgumentException)); new CursorImage(Pixels(Red), new Size(2, 1), Point.Empty); } public void HotspotPastTheRightEdge_Throws() { CheckThrow(typeof(ArgumentOutOfRangeException)); new CursorImage(Pixels(Red), new Size(1, 1), new Point(1, 0)); } public void HotspotPastTheBottomEdge_Throws() { CheckThrow(typeof(ArgumentOutOfRangeException)); new CursorImage(Pixels(Red), new Size(1, 1), new Point(0, 1)); } public void HotspotLeftOfTheImage_Throws() { CheckThrow(typeof(ArgumentOutOfRangeException)); new CursorImage(Pixels(Red), new Size(1, 1), new Point(-1, 0)); } public void HotspotAboveTheImage_Throws() { CheckThrow(typeof(ArgumentOutOfRangeException)); new CursorImage(Pixels(Red), new Size(1, 1), new Point(0, -1)); } } public class FromRgbaTests : UnitTestSharp.TestFixture { public void WholeSourceAtScaleOne_CopiesEveryPixel() { var cursor = CursorImage.FromRgba(Grid(), GridSize, new Rectangle(0, 0, 3, 2), Point.Empty); CheckEqual(GridSize, cursor.Size); CheckEqual(Grid(), cursor.Rgba); } public void OffsetRegion_TakesOnlyThePixelsInside() { var cursor = CursorImage.FromRgba(Grid(), GridSize, new Rectangle(2, 1, 1, 1), Point.Empty); CheckEqual(new Size(1, 1), cursor.Size); CheckEqual(Pixels(Teal), cursor.Rgba); } public void NarrowRegion_StepsByTheSourceStrideNotTheRegionWidth() { var cursor = CursorImage.FromRgba(Grid(), GridSize, new Rectangle(0, 0, 2, 2), Point.Empty); CheckEqual(new Size(2, 2), cursor.Size); CheckEqual(Pixels(Red, Green, Amber, Violet), cursor.Rgba); } public void Scaled_RepeatsEachPixelOnBothAxes() { var cursor = CursorImage.FromRgba(Grid(), GridSize, new Rectangle(1, 0, 2, 2), Point.Empty, scale: 2); CheckEqual(new Size(4, 4), cursor.Size); CheckEqual( Pixels( Green, Green, Blue, Blue, Green, Green, Blue, Blue, Violet, Violet, Teal, Teal, Violet, Violet, Teal, Teal), cursor.Rgba); } public void ScaledRegionBelowTheTop_ReadsFromTheOffsetSourceRow() { var cursor = CursorImage.FromRgba(Grid(), GridSize, new Rectangle(1, 1, 2, 1), Point.Empty, scale: 2); CheckEqual(new Size(4, 2), cursor.Size); CheckEqual( Pixels( Violet, Violet, Teal, Teal, Violet, Violet, Teal, Teal), cursor.Rgba); } public void Scaled_MovesTheHotspotWithTheArt() { var cursor = CursorImage.FromRgba( Grid(), GridSize, new Rectangle(0, 0, 3, 2), new Point(1, 1), scale: 3); CheckEqual(new Point(3, 3), cursor.Hotspot); } public void HotspotIsMeasuredFromTheRegion_NotTheSource() { var cursor = CursorImage.FromRgba(Grid(), GridSize, new Rectangle(2, 1, 1, 1), Point.Empty); CheckEqual(Point.Empty, cursor.Hotspot); } public void NullSource_Throws() { CheckThrow(typeof(ArgumentNullException)); CursorImage.FromRgba(null, new Size(1, 1), new Rectangle(0, 0, 1, 1), Point.Empty); } public void ZeroWidthSource_Throws() { CheckThrow(typeof(ArgumentOutOfRangeException)); CursorImage.FromRgba(Array.Empty(), new Size(0, 1), new Rectangle(0, 0, 1, 1), Point.Empty); } public void ZeroHeightSource_Throws() { CheckThrow(typeof(ArgumentOutOfRangeException)); CursorImage.FromRgba(Array.Empty(), new Size(1, 0), new Rectangle(0, 0, 1, 1), Point.Empty); } public void PixelCountDisagreeingWithTheSourceSize_Throws() { CheckThrow(typeof(ArgumentException)); CursorImage.FromRgba(Pixels(Red), new Size(2, 1), new Rectangle(0, 0, 1, 1), Point.Empty); } public void RegionWithNoWidth_Throws() { CheckThrow(typeof(ArgumentOutOfRangeException)); CursorImage.FromRgba(Pixels(Red), new Size(1, 1), new Rectangle(0, 0, 0, 1), Point.Empty); } public void RegionWithNoHeight_Throws() { CheckThrow(typeof(ArgumentOutOfRangeException)); CursorImage.FromRgba(Pixels(Red), new Size(1, 1), new Rectangle(0, 0, 1, 0), Point.Empty); } public void RegionStartingLeftOfTheSource_Throws() { CheckThrow(typeof(ArgumentOutOfRangeException)); CursorImage.FromRgba(Pixels(Red), new Size(1, 1), new Rectangle(-1, 0, 1, 1), Point.Empty); } public void RegionStartingAboveTheSource_Throws() { CheckThrow(typeof(ArgumentOutOfRangeException)); CursorImage.FromRgba(Pixels(Red), new Size(1, 1), new Rectangle(0, -1, 1, 1), Point.Empty); } public void RegionRunningPastTheRightEdge_Throws() { CheckThrow(typeof(ArgumentOutOfRangeException)); CursorImage.FromRgba(Pixels(Red), new Size(1, 1), new Rectangle(0, 0, 2, 1), Point.Empty); } public void RegionRunningPastTheBottomEdge_Throws() { CheckThrow(typeof(ArgumentOutOfRangeException)); CursorImage.FromRgba(Pixels(Red), new Size(1, 1), new Rectangle(0, 0, 1, 2), Point.Empty); } public void ScaleBelowOne_Throws() { CheckThrow(typeof(ArgumentOutOfRangeException)); CursorImage.FromRgba(Pixels(Red), new Size(1, 1), new Rectangle(0, 0, 1, 1), Point.Empty, scale: 0); } // The constructor rejects a hotspot off the finished image too, so only the region-relative reading of // it is this method's own to pin down. public void HotspotOutsideTheRegionButInsideTheSource_Throws() { CheckThrow(typeof(ArgumentOutOfRangeException)); CursorImage.FromRgba(Grid(), GridSize, new Rectangle(0, 0, 1, 1), new Point(2, 0)); } } public class FromImageStreamTests : UnitTestSharp.TestFixture { public void DecodesToStraightRgbaInReadingOrder() { var cursor = CursorImage.FromImageStream( new MemoryStream(TwoByTwoPng), new Rectangle(0, 0, 2, 2), Point.Empty); CheckEqual(new Size(2, 2), cursor.Size); CheckEqual(Pixels(Red, Green, Blue, Clear), cursor.Rgba); } public void CropsAndScalesWhatItDecoded() { var cursor = CursorImage.FromImageStream( new MemoryStream(TwoByTwoPng), new Rectangle(1, 0, 1, 1), Point.Empty, scale: 2); CheckEqual(new Size(2, 2), cursor.Size); CheckEqual(Pixels(Green, Green, Green, Green), cursor.Rgba); } public void NullStream_Throws() { CheckThrow(typeof(ArgumentNullException)); CursorImage.FromImageStream(null, new Rectangle(0, 0, 1, 1), Point.Empty); } } } }