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);
}
}
}
}