using System; namespace Prism.UnitTests { public class HsvTests : UnitTestSharp.TestFixture { private const double Tolerance = 1e-12; public static bool Near(double expected, double actual) { return Math.Abs(expected - actual) < Tolerance; } public static Hsv Gray(double hue, double value) { return new Hsv(hue, 0, value); } public class CtorTests : UnitTestSharp.TestFixture { public void AssignsAllFourParts() { var color = new Hsv(0.25, 0.5, 0.75, 0.125); CheckEqual(0.25, color.Hue); CheckEqual(0.5, color.Saturation); CheckEqual(0.75, color.Value); CheckEqual(0.125, color.Alpha); } public void WithoutAlpha_IsOpaque() { CheckEqual(1.0, new Hsv(0.25, 0.5, 0.75).Alpha); } public void HueAboveOne_WrapsAround() { CheckEqual(0.25, new Hsv(1.25, 1, 1).Hue); } public void NegativeHue_WrapsForwards() { CheckEqual(0.75, new Hsv(-0.25, 1, 1).Hue); } public void HueOfExactlyOne_WrapsToZero() { CheckEqual(0.0, new Hsv(1, 1, 1).Hue); } public void HueTooSmallToLeaveZero_StaysZero() { CheckEqual(0.0, new Hsv(-1e-20, 1, 1).Hue); } public void NaNHue_Throws() { CheckThrow(typeof(ArgumentOutOfRangeException)); new Hsv(double.NaN, 1, 1); } public void InfiniteHue_Throws() { CheckThrow(typeof(ArgumentOutOfRangeException)); new Hsv(double.NegativeInfinity, 1, 1); } public void SaturationAboveOne_Throws() { CheckThrow(typeof(ArgumentOutOfRangeException)); new Hsv(0, 1.1, 1); } public void NegativeSaturation_Throws() { CheckThrow(typeof(ArgumentOutOfRangeException)); new Hsv(0, -0.1, 1); } public void NaNValue_Throws() { CheckThrow(typeof(ArgumentOutOfRangeException)); new Hsv(0, 1, double.NaN); } public void ValueAboveOne_Throws() { CheckThrow(typeof(ArgumentOutOfRangeException)); new Hsv(0, 1, 1.1); } public void AlphaAboveOne_Throws() { CheckThrow(typeof(ArgumentOutOfRangeException)); new Hsv(0, 1, 1, 1.1); } public void NegativeAlpha_Throws() { CheckThrow(typeof(ArgumentOutOfRangeException)); new Hsv(0, 1, 1, -0.1); } } public class FromColorTests : UnitTestSharp.TestFixture { public void Red_IsHueZero() { CheckEqual(new Hsv(0, 1, 1), Hsv.FromColor(Color.FromArgb(255, 0, 0))); } public void Yellow_IsASixthOfTheWayRound() { CheckEqual(new Hsv(1 / 6.0, 1, 1), Hsv.FromColor(Color.FromArgb(255, 255, 0))); } public void Green_IsAThirdOfTheWayRound() { CheckEqual(new Hsv(2 / 6.0, 1, 1), Hsv.FromColor(Color.FromArgb(0, 255, 0))); } public void Cyan_IsHalfwayRound() { CheckEqual(new Hsv(3 / 6.0, 1, 1), Hsv.FromColor(Color.FromArgb(0, 255, 255))); } public void Blue_IsTwoThirdsOfTheWayRound() { CheckEqual(new Hsv(4 / 6.0, 1, 1), Hsv.FromColor(Color.FromArgb(0, 0, 255))); } public void Magenta_WrapsToFiveSixths() { Hsv magenta = Hsv.FromColor(Color.FromArgb(255, 0, 255)); CheckTrue(Near(5 / 6.0, magenta.Hue)); CheckEqual(1.0, magenta.Saturation); CheckEqual(1.0, magenta.Value); } public void ARedWithSomeBlue_SitsJustBeforeRedFromBelow() { Hsv rose = Hsv.FromColor(Color.FromArgb(255, 0, 51)); CheckTrue(Near(1 - 51 / 255.0 / 6, rose.Hue)); } public void Orange_IsBetweenRedAndYellow() { Hsv orange = Hsv.FromColor(Color.FromArgb(255, 128, 0)); CheckTrue(Near(128 / 255.0 / 6, orange.Hue)); } public void ADarkRed_KeepsFullSaturationAndLosesValue() { CheckEqual(new Hsv(0, 1, 128 / 255.0), Hsv.FromColor(Color.FromArgb(128, 0, 0))); } public void APaleRed_HasLowSaturationAndFullValue() { CheckEqual(new Hsv(0, 51 / 255.0, 1), Hsv.FromColor(Color.FromArgb(255, 204, 204))); } public void Gray_HasHueZeroAndNoSaturation() { CheckEqual(new Hsv(0, 0, 128 / 255.0), Hsv.FromColor(Color.FromArgb(128, 128, 128))); } public void Black_IsAllZero() { CheckEqual(new Hsv(0, 0, 0), Hsv.FromColor(Color.FromArgb(0, 0, 0))); } public void White_IsFullValueWithNoSaturation() { CheckEqual(new Hsv(0, 0, 1), Hsv.FromColor(Color.FromArgb(255, 255, 255))); } public void AlphaIsCarriedOverAsACoverageFraction() { CheckEqual(128 / 255.0, Hsv.FromColor(Color.FromArgb(128, 255, 0, 0)).Alpha); } } public class ToSrgbTests : UnitTestSharp.TestFixture { public void KeepsTheChannelsUnrounded() { CheckEqual(new SrgbColor(1, 0.375, 0, 0.5), new Hsv(0.0625, 1, 1, 0.5).ToSrgb()); } } public class ToColorTests : UnitTestSharp.TestFixture { public void HueZero_IsRed() { CheckEqual(Color.FromArgb(255, 0, 0), new Hsv(0, 1, 1).ToColor()); } public void ASixthOfTheWayRound_IsYellow() { CheckEqual(Color.FromArgb(255, 255, 0), new Hsv(1 / 6.0, 1, 1).ToColor()); } public void AThirdOfTheWayRound_IsGreen() { CheckEqual(Color.FromArgb(0, 255, 0), new Hsv(2 / 6.0, 1, 1).ToColor()); } public void HalfwayRound_IsCyan() { CheckEqual(Color.FromArgb(0, 255, 255), new Hsv(3 / 6.0, 1, 1).ToColor()); } public void TwoThirdsOfTheWayRound_IsBlue() { CheckEqual(Color.FromArgb(0, 0, 255), new Hsv(4 / 6.0, 1, 1).ToColor()); } public void FiveSixthsOfTheWayRound_IsMagenta() { CheckEqual(Color.FromArgb(255, 0, 255), new Hsv(5 / 6.0, 1, 1).ToColor()); } public void HalfwayBetweenRedAndYellow_IsOrange() { CheckEqual(Color.FromArgb(255, 128, 0), new Hsv(1 / 12.0, 1, 1).ToColor()); } public void NoSaturation_IsAGrayOfThatValue() { CheckEqual(Color.FromArgb(128, 128, 128), new Hsv(0.6, 0, 0.5).ToColor()); } public void NoValue_IsBlackWhateverTheHue() { CheckEqual(Color.FromArgb(0, 0, 0), new Hsv(0.6, 1, 0).ToColor()); } public void HalfSaturation_MixesInHalfTheValueAsTheLowChannels() { CheckEqual(Color.FromArgb(255, 128, 128), new Hsv(0, 0.5, 1).ToColor()); } public void AlphaIsRoundedToAByte() { CheckEqual((byte)128, new Hsv(0, 1, 1, 0.5).ToColor().Alpha); } public void UndoesFromColor_ForAnOrange() { CheckEqual(Color.FromArgb(255, 165, 0), Hsv.FromColor(Color.FromArgb(255, 165, 0)).ToColor()); } public void UndoesFromColor_ForATeal() { CheckEqual(Color.FromArgb(0, 128, 128), Hsv.FromColor(Color.FromArgb(0, 128, 128)).ToColor()); } public void UndoesFromColor_ForAColorWithAlpha() { Color original = Color.FromArgb(77, 12, 34, 56); CheckEqual(original, Hsv.FromColor(original).ToColor()); } public void UndoesFromColor_ForAColorWithBlueTheLargest() { Color original = Color.FromArgb(200, 40, 220); CheckEqual(original, Hsv.FromColor(original).ToColor()); } } public class LerpTests : UnitTestSharp.TestFixture { public void AtZero_IsTheStart() { var from = new Hsv(0.25, 0.5, 0.5, 1); CheckEqual(from, Hsv.Lerp(from, new Hsv(0.5, 1, 1, 0), 0)); } public void AtOne_IsTheEnd() { var to = new Hsv(0.5, 1, 0.75, 0.5); CheckEqual(to, Hsv.Lerp(new Hsv(0.25, 0.5, 0.5, 1), to, 1)); } public void BlendsSaturationAndValueLinearly() { Hsv blended = Hsv.Lerp(new Hsv(0.25, 0.25, 0.5, 1), new Hsv(0.25, 0.75, 1, 1), 0.5); CheckEqual(new Hsv(0.25, 0.5, 0.75, 1), blended); } public void AlphaBlendsLinearly_LeavingTheSameColorAlone() { Hsv blended = Hsv.Lerp( new Hsv(0.25, 0.5, 0.5, 0.25), new Hsv(0.25, 0.5, 0.5, 0.75), 0.25); CheckEqual(new Hsv(0.25, 0.5, 0.5, 0.375), blended); } public void ATransparentStart_AddsNoColor() { Hsv blended = Hsv.Lerp( new Hsv(0.25, 0.25, 0.25, 0), new Hsv(0.5, 0.75, 1, 1), 0.5); CheckEqual(new Hsv(0.5, 0.75, 1, 0.5), blended); } public void ATransparentEnd_AddsNoColor() { Hsv blended = Hsv.Lerp( new Hsv(0.25, 0.25, 0.25, 1), new Hsv(0.5, 0.75, 1, 0), 0.5); CheckEqual(new Hsv(0.25, 0.25, 0.25, 0.5), blended); } public void BothTransparent_BlendTheColorsLinearly() { Hsv blended = Hsv.Lerp( new Hsv(0.25, 0.25, 0.25, 0), new Hsv(0.5, 0.75, 0.75, 0), 0.5); CheckEqual(new Hsv(0.375, 0.5, 0.5, 0), blended); } public void UnequalAlphas_WeighEachColorByItsAlpha() { Hsv blended = Hsv.Lerp( new Hsv(0.25, 0.25, 0.25, 0.25), new Hsv(0.5, 0.75, 0.75, 0.75), 0.5); CheckEqual(new Hsv(0.4375, 0.625, 0.625, 0.5), blended); } public void WithoutADirection_TakesTheShorterWay() { CheckEqual(0.0, Hsv.Lerp(new Hsv(0.875, 1, 1), new Hsv(0.125, 1, 1), 0.5).Hue); } public void AmountBelowZero_Throws() { CheckThrow(typeof(ArgumentOutOfRangeException)); Hsv.Lerp(new Hsv(0, 1, 1), new Hsv(0.5, 1, 1), -0.1); } public void AmountAboveOne_Throws() { CheckThrow(typeof(ArgumentOutOfRangeException)); Hsv.Lerp(new Hsv(0, 1, 1), new Hsv(0.5, 1, 1), 1.1); } public void NaNAmount_Throws() { CheckThrow(typeof(ArgumentOutOfRangeException)); Hsv.Lerp(new Hsv(0, 1, 1), new Hsv(0.5, 1, 1), double.NaN); } public void AnUnknownDirection_Throws() { CheckThrow(typeof(ArgumentOutOfRangeException)); Hsv.Lerp(new Hsv(0, 1, 1), new Hsv(0.5, 1, 1), 0.5, (HueDirection)99); } public class DirectionTests : UnitTestSharp.TestFixture { public void Shortest_TakesTheShorterArc() { CheckEqual( 0.0, Hsv.Lerp(new Hsv(0.875, 1, 1), new Hsv(0.125, 1, 1), 0.5, HueDirection.Shortest).Hue); } public void Longest_TakesTheLongerArc() { CheckEqual(0.875, Hsv.Lerp(new Hsv(0.25, 1, 1), new Hsv(0.5, 1, 1), 0.5, HueDirection.Longest).Hue); } public void Increasing_WrapsPastOneToReachALowerHue() { CheckEqual( 0.0, Hsv.Lerp(new Hsv(0.75, 1, 1), new Hsv(0.25, 1, 1), 0.5, HueDirection.Increasing).Hue); } public void Decreasing_WrapsPastZeroToReachAHigherHue() { CheckEqual( 0.0, Hsv.Lerp(new Hsv(0.25, 1, 1), new Hsv(0.75, 1, 1), 0.5, HueDirection.Decreasing).Hue); } } public class ColorsWithoutAHueTests : UnitTestSharp.TestFixture { public void AGrayStart_TakesTheEndsHue() { CheckEqual(new Hsv(0.25, 0.5, 0.75), Hsv.Lerp(Gray(0.5, 0.5), new Hsv(0.25, 1, 1), 0.5)); } public void ABlackStart_TakesTheEndsHue() { CheckEqual(new Hsv(0.25, 1, 0.5), Hsv.Lerp(new Hsv(0.9, 1, 0), new Hsv(0.25, 1, 1), 0.5)); } public void AGrayEnd_KeepsTheStartsHue() { CheckEqual(new Hsv(0.25, 0.5, 0.75), Hsv.Lerp(new Hsv(0.25, 1, 1), Gray(0.5, 0.5), 0.5)); } public void ABlackEnd_KeepsTheStartsHue() { CheckEqual(new Hsv(0.25, 1, 0.5), Hsv.Lerp(new Hsv(0.25, 1, 1), new Hsv(0.9, 1, 0), 0.5)); } public void TwoWithoutAHue_KeepTheStartsHue() { CheckEqual(new Hsv(0.25, 0, 0.75), Hsv.Lerp(Gray(0.25, 0.5), Gray(0.75, 1), 0.5)); } } } public class EqualityTests : UnitTestSharp.TestFixture { public void SameParts_AreEqual() { CheckTrue(new Hsv(0.1, 0.2, 0.3, 0.4).Equals(new Hsv(0.1, 0.2, 0.3, 0.4))); CheckTrue(new Hsv(0.1, 0.2, 0.3, 0.4) == new Hsv(0.1, 0.2, 0.3, 0.4)); CheckFalse(new Hsv(0.1, 0.2, 0.3, 0.4) != new Hsv(0.1, 0.2, 0.3, 0.4)); } public void AnyDifferentPart_IsNotEqual() { var baseColor = new Hsv(0.1, 0.2, 0.3, 0.4); CheckFalse(baseColor.Equals(new Hsv(0.9, 0.2, 0.3, 0.4))); CheckFalse(baseColor.Equals(new Hsv(0.1, 0.9, 0.3, 0.4))); CheckFalse(baseColor.Equals(new Hsv(0.1, 0.2, 0.9, 0.4))); CheckFalse(baseColor.Equals(new Hsv(0.1, 0.2, 0.3, 0.9))); CheckTrue(baseColor != new Hsv(0.1, 0.2, 0.3, 0.9)); } public void BoxedColor_IsEqualToTheSameColor() { CheckTrue(new Hsv(0.1, 0.2, 0.3).Equals((object)new Hsv(0.1, 0.2, 0.3))); } public void ANonHsv_IsNotEqual() { CheckFalse(new Hsv(0.1, 0.2, 0.3).Equals("color")); } public void EqualColors_HaveTheSameHashCode() { CheckEqual(new Hsv(0.1, 0.2, 0.3, 0.4).GetHashCode(), new Hsv(0.1, 0.2, 0.3, 0.4).GetHashCode()); } } } }