Skip to content

Commit 40815df

Browse files
committed
Fix Color and test it
1 parent 010107a commit 40815df

File tree

2 files changed

+275
-5
lines changed

2 files changed

+275
-5
lines changed

modules/yup_graphics/graphics/yup_Color.cpp

Lines changed: 6 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -66,7 +66,10 @@ float parseNextFloat (String::CharPointerType& data)
6666
++data;
6767

6868
if (*data == '-')
69+
{
70+
isNegative = true;
6971
++data;
72+
}
7073

7174
while (*data >= '0' && *data <= '9')
7275
{
@@ -77,16 +80,14 @@ float parseNextFloat (String::CharPointerType& data)
7780
if (*data == '.')
7881
{
7982
++data;
80-
float decimalPart = 0;
81-
float decimalFactor = 10;
83+
float decimalFactor = 10.0f;
8284

8385
while (*data >= '0' && *data <= '9')
8486
{
85-
decimalPart = decimalPart * 10 + (*data - '0');
87+
result += (*data - '0') / decimalFactor;
88+
decimalFactor *= 10.0f;
8689
++data;
8790
}
88-
89-
result += decimalPart / decimalFactor;
9091
}
9192

9293
if (*data == '%')

tests/yup_graphics/yup_Color.cpp

Lines changed: 269 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -581,3 +581,272 @@ TEST (ColorTests, Chaining_Operations)
581581
EXPECT_EQ (modified.getGreen(), 128);
582582
EXPECT_EQ (modified.getBlue(), 64);
583583
}
584+
585+
TEST (ColorTests, HSL_String_Parsing)
586+
{
587+
// Test basic HSL parsing (hue normalized to 0-1 range, not degrees)
588+
// Green: hue = 120/360 = 0.333...
589+
Color fromHSL = Color::fromString ("hsl(0.333, 1, 0.5)");
590+
EXPECT_GT (fromHSL.getGreen(), 200); // Green dominant
591+
EXPECT_LT (fromHSL.getRed(), 50);
592+
EXPECT_LT (fromHSL.getBlue(), 50);
593+
594+
// Test HSL with percentage values
595+
// Blue: hue = 240/360 = 0.666...
596+
Color fromHSLPercent = Color::fromString ("hsl(0.666, 100%, 50%)");
597+
EXPECT_GT (fromHSLPercent.getBlue(), 200); // Blue dominant
598+
EXPECT_LT (fromHSLPercent.getRed(), 50);
599+
EXPECT_LT (fromHSLPercent.getGreen(), 50);
600+
601+
// Test HSLA parsing
602+
// Red: hue = 0
603+
Color fromHSLA = Color::fromString ("hsla(0, 1, 0.5, 0.5)");
604+
EXPECT_GT (fromHSLA.getRed(), 200); // Red dominant
605+
EXPECT_LT (fromHSLA.getGreen(), 50);
606+
EXPECT_LT (fromHSLA.getBlue(), 50);
607+
EXPECT_NEAR (fromHSLA.getAlpha(), 127, 1); // Alpha ~0.5
608+
609+
// Test HSLA with percentage and decimal values mixed
610+
// Yellow: hue = 60/360 = 0.166...
611+
Color fromHSLAMixed = Color::fromString ("hsla(0.166, 100%, 50%, 0.75)");
612+
EXPECT_GT (fromHSLAMixed.getRed(), 200); // Yellow (red + green)
613+
EXPECT_GT (fromHSLAMixed.getGreen(), 200);
614+
EXPECT_LT (fromHSLAMixed.getBlue(), 50);
615+
EXPECT_NEAR (fromHSLAMixed.getAlpha(), 191, 1); // Alpha ~0.75
616+
617+
// Test HSL with spaces and commas
618+
// Cyan: hue = 180/360 = 0.5
619+
Color fromHSLSpaces = Color::fromString ("hsl( 0.5 , 1 , 0.5 )");
620+
EXPECT_GT (fromHSLSpaces.getBlue(), 200); // Cyan (green + blue)
621+
EXPECT_GT (fromHSLSpaces.getGreen(), 200);
622+
EXPECT_LT (fromHSLSpaces.getRed(), 50);
623+
624+
// Test invalid HSL format (should return transparentBlack)
625+
Color fromInvalidHSL = Color::fromString ("hsl_invalid(0, 0, 0)");
626+
EXPECT_EQ (fromInvalidHSL.getARGB(), Colors::transparentBlack);
627+
}
628+
629+
TEST (ColorTests, RGB_String_Parsing_EdgeCases)
630+
{
631+
// Test invalid RGB format (should return transparentBlack)
632+
Color fromInvalidRGB = Color::fromString ("rgb_invalid(255, 0, 0)");
633+
EXPECT_EQ (fromInvalidRGB.getARGB(), Colors::transparentBlack);
634+
635+
// Test RGB with extra spaces
636+
Color fromRGBSpaces = Color::fromString ("rgb( 255 , 128 , 64 )");
637+
EXPECT_EQ (fromRGBSpaces.getRed(), 255);
638+
EXPECT_EQ (fromRGBSpaces.getGreen(), 128);
639+
EXPECT_EQ (fromRGBSpaces.getBlue(), 64);
640+
641+
// Test RGB with no spaces
642+
Color fromRGBNoSpaces = Color::fromString ("rgb(255,128,64)");
643+
EXPECT_EQ (fromRGBNoSpaces.getRed(), 255);
644+
EXPECT_EQ (fromRGBNoSpaces.getGreen(), 128);
645+
EXPECT_EQ (fromRGBNoSpaces.getBlue(), 64);
646+
647+
// Test RGBA with spaces
648+
Color fromRGBASpaces = Color::fromString ("rgba( 100 , 150 , 200 , 128 )");
649+
EXPECT_EQ (fromRGBASpaces.getRed(), 100);
650+
EXPECT_EQ (fromRGBASpaces.getGreen(), 150);
651+
EXPECT_EQ (fromRGBASpaces.getBlue(), 200);
652+
EXPECT_EQ (fromRGBASpaces.getAlpha(), 128);
653+
}
654+
655+
TEST (ColorTests, ParseNextInt_Coverage)
656+
{
657+
// Test negative number parsing via RGB (if implementation supports it)
658+
Color fromNegative = Color::fromString ("rgb(-10, 50, 100)");
659+
EXPECT_NO_THROW (fromNegative.getRed()); // Should handle gracefully
660+
661+
// Test numbers with leading zeros
662+
Color fromLeadingZeros = Color::fromString ("rgb(001, 050, 100)");
663+
EXPECT_EQ (fromLeadingZeros.getRed(), 1);
664+
EXPECT_EQ (fromLeadingZeros.getGreen(), 50);
665+
EXPECT_EQ (fromLeadingZeros.getBlue(), 100);
666+
667+
// Test multiple commas and spaces
668+
Color fromMultipleDelimiters = Color::fromString ("rgb( , 10 , , 20 , 30 )");
669+
EXPECT_NO_THROW (fromMultipleDelimiters.getRed()); // Should handle gracefully
670+
}
671+
672+
TEST (ColorTests, ParseNextFloat_Coverage)
673+
{
674+
// Test multi-digit decimal values in HSL (now that parsing is fixed)
675+
Color fromHSLDecimal = Color::fromString ("hsl(0.333, 0.75, 0.5)");
676+
EXPECT_NO_THROW (fromHSLDecimal.getRed()); // Should parse decimal correctly
677+
678+
// Test values without decimals
679+
Color fromHSLNoDecimal = Color::fromString ("hsl(0, 0, 0)");
680+
EXPECT_EQ (fromHSLNoDecimal.getRed(), 0);
681+
EXPECT_EQ (fromHSLNoDecimal.getGreen(), 0);
682+
EXPECT_EQ (fromHSLNoDecimal.getBlue(), 0);
683+
684+
// Test percentage values with decimals
685+
Color fromHSLPercentDecimal = Color::fromString ("hsl(0, 50.5%, 25.25%)");
686+
EXPECT_NO_THROW (fromHSLPercentDecimal.getRed()); // Should handle percentage with decimals
687+
688+
// Test mixed formats (decimals and percentages)
689+
Color fromHSLMixed = Color::fromString ("hsl(0.666, 80.5%, 0.625)");
690+
EXPECT_NO_THROW (fromHSLMixed.getRed());
691+
692+
// Test edge case: percentage at 0%
693+
Color fromHSLZeroPercent = Color::fromString ("hsl(0, 0%, 50%)");
694+
EXPECT_NEAR (fromHSLZeroPercent.getRed(), 127, 2);
695+
EXPECT_NEAR (fromHSLZeroPercent.getGreen(), 127, 2);
696+
EXPECT_NEAR (fromHSLZeroPercent.getBlue(), 127, 2);
697+
698+
// Test edge case: percentage at 100%
699+
Color fromHSLHundredPercent = Color::fromString ("hsl(0, 100%, 50%)");
700+
EXPECT_GT (fromHSLHundredPercent.getRed(), 200);
701+
EXPECT_LT (fromHSLHundredPercent.getGreen(), 50);
702+
EXPECT_LT (fromHSLHundredPercent.getBlue(), 50);
703+
704+
// Test HSLA with multi-digit float alpha
705+
Color fromHSLAFloats = Color::fromString ("hsla(0.5, 0.456, 0.789, 0.625)");
706+
EXPECT_NO_THROW (fromHSLAFloats.getRed());
707+
EXPECT_NEAR (fromHSLAFloats.getAlpha(), 159, 1); // 0.625 * 255
708+
}
709+
710+
TEST (ColorTests, FromHSL_HueToRGB_EdgeCases)
711+
{
712+
// Test to hit line 528: t < 0.0f branch in hue2rgb lambda
713+
// This occurs when h - 1.0f/3.0f is negative (when h < 1/3)
714+
Color c1 = Color::fromHSL (0.0f, 1.0f, 0.5f);
715+
EXPECT_GT (c1.getRed(), 200); // Red dominant
716+
EXPECT_LT (c1.getGreen(), 50);
717+
EXPECT_LT (c1.getBlue(), 50);
718+
719+
Color c2 = Color::fromHSL (0.1f, 1.0f, 0.5f);
720+
EXPECT_NO_THROW (c2.getRed()); // Should handle h < 1/3
721+
722+
Color c3 = Color::fromHSL (0.2f, 1.0f, 0.5f);
723+
EXPECT_NO_THROW (c3.getRed()); // Should handle h < 1/3
724+
725+
// Test to hit line 530: t > 1.0f branch in hue2rgb lambda
726+
// This occurs when h + 1.0f/3.0f is > 1.0 (when h > 2/3)
727+
Color c4 = Color::fromHSL (0.7f, 1.0f, 0.5f);
728+
EXPECT_NO_THROW (c4.getRed()); // Should handle h > 2/3
729+
730+
Color c5 = Color::fromHSL (0.9f, 1.0f, 0.5f);
731+
EXPECT_NO_THROW (c5.getRed()); // Should handle h > 2/3
732+
733+
// Test edge cases for different ranges in hue2rgb
734+
// t < 1/6 (line 531-532)
735+
Color c6 = Color::fromHSL (0.05f, 1.0f, 0.5f);
736+
EXPECT_NO_THROW (c6.getRed());
737+
738+
// 1/6 <= t < 1/2 (line 533-534)
739+
Color c7 = Color::fromHSL (0.25f, 1.0f, 0.5f);
740+
EXPECT_NO_THROW (c7.getRed());
741+
742+
// 1/2 <= t < 2/3 (line 535-536)
743+
Color c8 = Color::fromHSL (0.5f, 1.0f, 0.5f);
744+
EXPECT_NO_THROW (c8.getRed());
745+
746+
// t >= 2/3 (line 537)
747+
Color c9 = Color::fromHSL (0.8f, 1.0f, 0.5f);
748+
EXPECT_NO_THROW (c9.getRed());
749+
}
750+
751+
TEST (ColorTests, FromHSV_AllSwitchCases)
752+
{
753+
// Test all 6 cases in the switch statement (lines 623-652)
754+
755+
// Case 0: hue in [0, 1/6) - red to yellow
756+
Color case0 = Color::fromHSV (0.0f, 1.0f, 1.0f);
757+
EXPECT_EQ (case0.getRed(), 255);
758+
EXPECT_EQ (case0.getGreen(), 0);
759+
EXPECT_EQ (case0.getBlue(), 0);
760+
761+
// Case 1: hue in [1/6, 2/6) - yellow to green
762+
Color case1 = Color::fromHSV (1.0f / 6.0f + 0.05f, 1.0f, 1.0f);
763+
EXPECT_GT (case1.getGreen(), 200); // Green becoming dominant
764+
EXPECT_LT (case1.getBlue(), 50);
765+
766+
// Case 2: hue in [2/6, 3/6) - green to cyan
767+
Color case2 = Color::fromHSV (2.0f / 6.0f + 0.05f, 1.0f, 1.0f);
768+
EXPECT_GT (case2.getGreen(), 200); // Green dominant
769+
EXPECT_LT (case2.getRed(), 50);
770+
771+
// Case 3: hue in [3/6, 4/6) - cyan to blue
772+
Color case3 = Color::fromHSV (3.0f / 6.0f + 0.05f, 1.0f, 1.0f);
773+
EXPECT_GT (case3.getBlue(), 200); // Blue becoming dominant
774+
EXPECT_LT (case3.getRed(), 50);
775+
776+
// Case 4: hue in [4/6, 5/6) - blue to magenta
777+
Color case4 = Color::fromHSV (4.0f / 6.0f + 0.05f, 1.0f, 1.0f);
778+
EXPECT_GT (case4.getBlue(), 200); // Blue dominant
779+
EXPECT_LT (case4.getGreen(), 50);
780+
781+
// Case 5: hue in [5/6, 1.0) - magenta to red
782+
Color case5 = Color::fromHSV (5.0f / 6.0f + 0.05f, 1.0f, 1.0f);
783+
EXPECT_GT (case5.getRed(), 200); // Red becoming dominant
784+
EXPECT_LT (case5.getGreen(), 50);
785+
786+
// Test exact boundaries
787+
Color boundary0 = Color::fromHSV (0.0f, 1.0f, 1.0f);
788+
EXPECT_NO_THROW (boundary0.getRed());
789+
790+
Color boundary1 = Color::fromHSV (1.0f / 6.0f, 1.0f, 1.0f);
791+
EXPECT_NO_THROW (boundary1.getRed());
792+
793+
Color boundary2 = Color::fromHSV (2.0f / 6.0f, 1.0f, 1.0f);
794+
EXPECT_NO_THROW (boundary2.getRed());
795+
796+
Color boundary3 = Color::fromHSV (3.0f / 6.0f, 1.0f, 1.0f);
797+
EXPECT_NO_THROW (boundary3.getRed());
798+
799+
Color boundary4 = Color::fromHSV (4.0f / 6.0f, 1.0f, 1.0f);
800+
EXPECT_NO_THROW (boundary4.getRed());
801+
802+
Color boundary5 = Color::fromHSV (5.0f / 6.0f, 1.0f, 1.0f);
803+
EXPECT_NO_THROW (boundary5.getRed());
804+
}
805+
806+
TEST (ColorTests, OverlaidWith_AlphaBlending)
807+
{
808+
// Test line 784-785: destAlpha <= 0
809+
Color transparent (0x00ff0000); // Fully transparent red
810+
Color opaqueSrc (0xff0000ff); // Fully opaque blue
811+
Color result1 = transparent.overlaidWith (opaqueSrc);
812+
EXPECT_EQ (result1.getARGB(), opaqueSrc.getARGB()); // Should return src
813+
814+
// Test line 789-790: resA <= 0
815+
Color fullyTransparent (0x00000000);
816+
Color alsoTransparent (0x00ffffff);
817+
Color result2 = fullyTransparent.overlaidWith (alsoTransparent);
818+
EXPECT_EQ (result2.getARGB(), alsoTransparent.getARGB()); // Should return src
819+
820+
// Test normal blending (lines 792-796)
821+
Color semiDest (0x80ff0000); // Semi-transparent red
822+
Color semiSrc (0x800000ff); // Semi-transparent blue
823+
Color result3 = semiDest.overlaidWith (semiSrc);
824+
EXPECT_NE (result3.getARGB(), semiDest.getARGB()); // Should be blended
825+
EXPECT_NE (result3.getARGB(), semiSrc.getARGB()); // Should be blended
826+
EXPECT_GT (result3.getAlpha(), 0); // Should have some alpha
827+
828+
// Test with different alpha combinations
829+
Color dest1 (0xc0ff0000); // 75% opaque red
830+
Color src1 (0x400000ff); // 25% opaque blue
831+
Color result4 = dest1.overlaidWith (src1);
832+
EXPECT_GT (result4.getRed(), result4.getBlue()); // Red should dominate
833+
834+
// Test with opaque dest and semi-transparent src
835+
Color opaqueDest (0xffff0000); // Fully opaque red
836+
Color semiSrc2 (0x800000ff); // Semi-transparent blue
837+
Color result5 = opaqueDest.overlaidWith (semiSrc2);
838+
EXPECT_GT (result5.getRed(), 0); // Should have red component
839+
EXPECT_GT (result5.getBlue(), 0); // Should have blue component
840+
841+
// Test with semi-transparent dest and opaque src
842+
Color semiDest2 (0x80ff0000); // Semi-transparent red
843+
Color opaqueSrc2 (0xff0000ff); // Fully opaque blue
844+
Color result6 = semiDest2.overlaidWith (opaqueSrc2);
845+
EXPECT_EQ (result6.getBlue(), 255); // Blue should be dominant
846+
847+
// Edge case: both nearly opaque
848+
Color nearlyOpaqueDest (0xfeff0000);
849+
Color nearlyOpaqueSrc (0xfe0000ff);
850+
Color result7 = nearlyOpaqueDest.overlaidWith (nearlyOpaqueSrc);
851+
EXPECT_NO_THROW (result7.getRed()); // Should handle without issues
852+
}

0 commit comments

Comments
 (0)