first commit

This commit is contained in:
2026-03-10 16:18:05 +00:00
commit 11f9c069b5
31635 changed files with 3187747 additions and 0 deletions

View File

@@ -0,0 +1,44 @@
/*
* Copyright (c) Meta Platforms, Inc. and affiliates.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*/
#include <gtest/gtest.h>
#include <react/renderer/css/CSSAngle.h>
#include <react/renderer/css/CSSValueParser.h>
namespace facebook::react {
TEST(CSSAngle, angle_values) {
auto emptyValue = parseCSSProperty<CSSAngle>("");
EXPECT_TRUE(std::holds_alternative<std::monostate>(emptyValue));
auto degreeValue = parseCSSProperty<CSSAngle>("10deg");
EXPECT_TRUE(std::holds_alternative<CSSAngle>(degreeValue));
EXPECT_EQ(std::get<CSSAngle>(degreeValue).degrees, 10.0f);
auto spongebobCaseValue = parseCSSProperty<CSSAngle>("20dEg");
EXPECT_TRUE(std::holds_alternative<CSSAngle>(spongebobCaseValue));
EXPECT_EQ(std::get<CSSAngle>(spongebobCaseValue).degrees, 20.0f);
auto radianValue = parseCSSProperty<CSSAngle>("10rad");
EXPECT_TRUE(std::holds_alternative<CSSAngle>(radianValue));
ASSERT_NEAR(std::get<CSSAngle>(radianValue).degrees, 572.958f, 0.001f);
auto negativeRadianValue = parseCSSProperty<CSSAngle>("-10rad");
EXPECT_TRUE(std::holds_alternative<CSSAngle>(negativeRadianValue));
ASSERT_NEAR(
std::get<CSSAngle>(negativeRadianValue).degrees, -572.958f, 0.001f);
auto gradianValue = parseCSSProperty<CSSAngle>("10grad");
EXPECT_TRUE(std::holds_alternative<CSSAngle>(gradianValue));
ASSERT_NEAR(std::get<CSSAngle>(gradianValue).degrees, 9.0f, 0.001f);
auto turnValue = parseCSSProperty<CSSAngle>(".25turn");
EXPECT_TRUE(std::holds_alternative<CSSAngle>(turnValue));
EXPECT_EQ(std::get<CSSAngle>(turnValue).degrees, 90.0f);
}
} // namespace facebook::react

View File

@@ -0,0 +1,560 @@
/*
* Copyright (c) Meta Platforms, Inc. and affiliates.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*/
#include <gtest/gtest.h>
#include <react/renderer/css/CSSBackgroundImage.h>
namespace facebook::react {
namespace {
CSSColorStop
makeCSSColorStop(uint8_t r, uint8_t g, uint8_t b, uint8_t a = 255) {
return CSSColorStop{.color = CSSColor{.r = r, .g = g, .b = b, .a = a}};
}
} // namespace
class CSSBackgroundImageTest : public ::testing::Test {};
TEST_F(CSSBackgroundImageTest, LinearGradientToRight) {
auto result = parseCSSProperty<CSSBackgroundImage>(
"linear-gradient(to right, red, blue)");
decltype(result) expected = CSSLinearGradientFunction{
.direction =
CSSLinearGradientDirection{.value = CSSAngle{.degrees = 90.0f}},
.items = {makeCSSColorStop(255, 0, 0), makeCSSColorStop(0, 0, 255)}};
ASSERT_EQ(result, expected);
}
TEST_F(CSSBackgroundImageTest, LinearGradientToBottomRight) {
auto result = parseCSSProperty<CSSBackgroundImage>(
"linear-gradient(to bottom right, red, blue)");
decltype(result) expected = CSSLinearGradientFunction{
.direction =
CSSLinearGradientDirection{
.value = CSSLinearGradientDirectionKeyword::ToBottomRight},
.items = {makeCSSColorStop(255, 0, 0), makeCSSColorStop(0, 0, 255)}};
ASSERT_EQ(result, expected);
}
TEST_F(CSSBackgroundImageTest, EmptyStringReturnsEmptyArray) {
auto result = parseCSSProperty<CSSBackgroundImageList>("");
ASSERT_TRUE(std::holds_alternative<std::monostate>(result));
}
TEST_F(CSSBackgroundImageTest, InvalidValueReturnsEmptyArray) {
auto result = parseCSSProperty<CSSBackgroundImageList>("linear-");
ASSERT_TRUE(std::holds_alternative<std::monostate>(result));
}
TEST_F(CSSBackgroundImageTest, LinearGradientWithWhitespacesInDirection) {
auto result = parseCSSProperty<CSSBackgroundImage>(
"linear-gradient(to bottom right, red, blue)");
decltype(result) expected = CSSLinearGradientFunction{
.direction =
CSSLinearGradientDirection{
.value = CSSLinearGradientDirectionKeyword::ToBottomRight},
.items = {makeCSSColorStop(255, 0, 0), makeCSSColorStop(0, 0, 255)}};
ASSERT_EQ(result, expected);
}
TEST_F(CSSBackgroundImageTest, LinearGradientWithRandomWhitespaces) {
auto result = parseCSSProperty<CSSBackgroundImage>(
" linear-gradient(to bottom right, red 30%, blue 80%) ");
decltype(result) expected = CSSLinearGradientFunction{
.direction =
CSSLinearGradientDirection{
.value = CSSLinearGradientDirectionKeyword::ToBottomRight},
.items = {
CSSColorStop{
.color = CSSColor{.r = 255, .g = 0, .b = 0, .a = 255},
.startPosition = CSSPercentage{.value = 30.0f}},
CSSColorStop{
.color = CSSColor{.r = 0, .g = 0, .b = 255, .a = 255},
.startPosition = CSSPercentage{.value = 80.0f}},
}};
ASSERT_EQ(result, expected);
}
TEST_F(CSSBackgroundImageTest, LinearGradientWithAngle) {
auto result =
parseCSSProperty<CSSBackgroundImage>("linear-gradient(45deg, red, blue)");
decltype(result) expected = CSSLinearGradientFunction{
.direction =
CSSLinearGradientDirection{.value = CSSAngle{.degrees = 45.0f}},
.items = {makeCSSColorStop(255, 0, 0), makeCSSColorStop(0, 0, 255)}};
ASSERT_EQ(result, expected);
}
TEST_F(CSSBackgroundImageTest, LinearGradientCaseInsensitive) {
auto result = parseCSSProperty<CSSBackgroundImage>(
"LiNeAr-GradieNt(To Bottom, Red, Blue)");
decltype(result) expected = CSSLinearGradientFunction{
.direction =
CSSLinearGradientDirection{.value = CSSAngle{.degrees = 180.0f}},
.items = {makeCSSColorStop(255, 0, 0), makeCSSColorStop(0, 0, 255)}};
ASSERT_EQ(result, expected);
}
TEST_F(CSSBackgroundImageTest, MultipleLinearGradientsWithNewlines) {
auto result = parseCSSProperty<CSSBackgroundImageList>(
"\n linear-gradient(to top, red, blue),\n linear-gradient(to bottom, green, yellow)");
decltype(result) expected = CSSBackgroundImageList{
{CSSLinearGradientFunction{
.direction =
CSSLinearGradientDirection{.value = CSSAngle{.degrees = 0.0f}},
.items =
{CSSColorStop{
.color = CSSColor{.r = 255, .g = 0, .b = 0, .a = 255}},
CSSColorStop{
.color = CSSColor{.r = 0, .g = 0, .b = 255, .a = 255}}}},
CSSLinearGradientFunction{
.direction =
CSSLinearGradientDirection{.value = CSSAngle{.degrees = 180.0f}},
.items = {
CSSColorStop{
.color = CSSColor{.r = 0, .g = 128, .b = 0, .a = 255}},
CSSColorStop{
.color = CSSColor{.r = 255, .g = 255, .b = 0, .a = 255}},
}}}};
ASSERT_EQ(result, expected);
}
TEST_F(CSSBackgroundImageTest, LinearGradientWithMultipleColorStops) {
auto result = parseCSSProperty<CSSBackgroundImage>(
"linear-gradient(to bottom, red 0%, green 50%, blue 100%)");
decltype(result) expected = CSSLinearGradientFunction{
.direction =
CSSLinearGradientDirection{.value = CSSAngle{.degrees = 180.0f}},
.items = {
CSSColorStop{
.color = CSSColor{.r = 255, .g = 0, .b = 0, .a = 255},
.startPosition = CSSPercentage{.value = 0.0f}},
CSSColorStop{
.color = CSSColor{.r = 0, .g = 128, .b = 0, .a = 255},
.startPosition = CSSPercentage{.value = 50.0f}},
CSSColorStop{
.color = CSSColor{.r = 0, .g = 0, .b = 255, .a = 255},
.startPosition = CSSPercentage{.value = 100.0f}},
}};
ASSERT_EQ(result, expected);
}
TEST_F(CSSBackgroundImageTest, LinearGradientWithColorStopEndPosition) {
auto result = parseCSSProperty<CSSBackgroundImage>(
"linear-gradient(red 10% 30%, blue 50%)");
decltype(result) expected = CSSLinearGradientFunction{
.direction =
CSSLinearGradientDirection{.value = CSSAngle{.degrees = 180.0f}},
.items = {
CSSColorStop{
.color = CSSColor{.r = 255, .g = 0, .b = 0, .a = 255},
.startPosition = CSSPercentage{.value = 10.0f},
.endPosition = CSSPercentage{.value = 30.0f}},
CSSColorStop{
.color = CSSColor{.r = 0, .g = 0, .b = 255, .a = 255},
.startPosition = CSSPercentage{.value = 50.0f}}}};
ASSERT_EQ(result, expected);
}
TEST_F(CSSBackgroundImageTest, LinearGradientMixedPositionedStops) {
auto result = parseCSSProperty<CSSBackgroundImage>(
"linear-gradient(to right, red, green, blue 60%, yellow, purple)");
decltype(result) expected = CSSLinearGradientFunction{
.direction =
CSSLinearGradientDirection{.value = CSSAngle{.degrees = 90.0f}},
.items = {
makeCSSColorStop(255, 0, 0),
makeCSSColorStop(0, 128, 0),
CSSColorStop{
.color = CSSColor{.r = 0, .g = 0, .b = 255, .a = 255},
.startPosition = CSSPercentage{.value = 60.0f}},
makeCSSColorStop(255, 255, 0),
makeCSSColorStop(128, 0, 128),
}};
ASSERT_EQ(result, expected);
}
TEST_F(CSSBackgroundImageTest, LinearGradientWithHslColors) {
auto result = parseCSSProperty<CSSBackgroundImage>(
"linear-gradient(hsl(330, 100%, 45.1%), hsl(0, 100%, 50%))");
decltype(result) expected = CSSLinearGradientFunction{
.direction =
CSSLinearGradientDirection{.value = CSSAngle{.degrees = 180.0f}},
.items = {makeCSSColorStop(230, 0, 115), makeCSSColorStop(255, 0, 0)}};
ASSERT_EQ(result, expected);
}
TEST_F(CSSBackgroundImageTest, LinearGradientWithoutDirection) {
auto result =
parseCSSProperty<CSSBackgroundImage>("linear-gradient(#e66465, #9198e5)");
decltype(result) expected = CSSLinearGradientFunction{
.direction =
CSSLinearGradientDirection{.value = CSSAngle{.degrees = 180.0f}},
.items = {
makeCSSColorStop(230, 100, 101), makeCSSColorStop(145, 152, 229)}};
ASSERT_EQ(result, expected);
}
TEST_F(CSSBackgroundImageTest, LinearGradientInvalidCases) {
const std::vector<std::string> invalidInputs = {
"linear-gradient(45deg, rede, blue)",
"linear-gradient(45 deg, red, blue)",
"linear-gradient(to left2, red, blue)",
"linear-gradient(to left, red 5, blue)"};
for (const auto& input : invalidInputs) {
const auto result = parseCSSProperty<CSSBackgroundImage>(input);
ASSERT_TRUE(std::holds_alternative<std::monostate>(result))
<< "Input should be invalid: " << input;
}
}
TEST_F(CSSBackgroundImageTest, LinearGradientWithMultipleTransitionHints) {
auto result = parseCSSProperty<CSSBackgroundImage>(
"linear-gradient(red, 20%, blue, 60%, green, 80%, yellow)");
decltype(result) expected = CSSLinearGradientFunction{
.direction =
CSSLinearGradientDirection{.value = CSSAngle{.degrees = 180.0f}},
.items = {
makeCSSColorStop(255, 0, 0),
CSSColorHint{.position = CSSPercentage{.value = 20.0f}},
makeCSSColorStop(0, 0, 255),
CSSColorHint{.position = CSSPercentage{.value = 60.0f}},
makeCSSColorStop(0, 128, 0),
CSSColorHint{.position = CSSPercentage{.value = 80.0f}},
makeCSSColorStop(255, 255, 0),
}};
ASSERT_EQ(result, expected);
}
TEST_F(CSSBackgroundImageTest, LinearGradientInvalidTransitionHints) {
const std::vector<std::string> invalidInputs = {
// color hints must be between two color stops
"linear-gradient(red, 30%, blue, 60%, green, 80%)",
"linear-gradient(red, 30%, 60%, green)",
"linear-gradient(20%, red, green)"};
for (const auto& input : invalidInputs) {
const auto result = parseCSSProperty<CSSBackgroundImageList>(input);
ASSERT_TRUE(std::holds_alternative<std::monostate>(result))
<< "Input should be invalid: " << input;
}
}
TEST_F(CSSBackgroundImageTest, LinearGradientWithMixedUnits) {
auto result = parseCSSProperty<CSSBackgroundImage>(
"linear-gradient(red 10%, 20px, blue 30%, purple 40px)");
decltype(result) expected = CSSLinearGradientFunction{
.direction =
CSSLinearGradientDirection{.value = CSSAngle{.degrees = 180.0f}},
.items = {
CSSColorStop{
.color = CSSColor{.r = 255, .g = 0, .b = 0, .a = 255},
.startPosition = CSSPercentage{.value = 10.0f}},
CSSColorHint{
.position = CSSLength{.value = 20.0f, .unit = CSSLengthUnit::Px}},
CSSColorStop{
.color = CSSColor{.r = 0, .g = 0, .b = 255, .a = 255},
.startPosition = CSSPercentage{.value = 30.0f}},
CSSColorStop{
.color = CSSColor{.r = 128, .g = 0, .b = 128, .a = 255},
.startPosition =
CSSLength{.value = 40.0f, .unit = CSSLengthUnit::Px}},
}};
ASSERT_EQ(result, expected);
}
TEST_F(CSSBackgroundImageTest, RadialGradientBasic) {
auto result =
parseCSSProperty<CSSBackgroundImage>("radial-gradient(red, blue)");
decltype(result) expected = CSSRadialGradientFunction{
.shape = CSSRadialGradientShape::Ellipse,
.size = CSSRadialGradientSizeKeyword::FarthestCorner,
.position =
CSSRadialGradientPosition{
.top = CSSPercentage{.value = 50.0f},
.left = CSSPercentage{.value = 50.0f}},
.items = {makeCSSColorStop(255, 0, 0), makeCSSColorStop(0, 0, 255)}};
ASSERT_EQ(result, expected);
}
TEST_F(CSSBackgroundImageTest, RadialGradientInferCircleFromSingleLength) {
auto result =
parseCSSProperty<CSSBackgroundImage>("radial-gradient(100px, red, blue)");
decltype(result) expected = CSSRadialGradientFunction{
.shape = CSSRadialGradientShape::Circle,
.size =
CSSRadialGradientExplicitSize{
.sizeX = CSSLength{.value = 100.0f, .unit = CSSLengthUnit::Px},
.sizeY = CSSLength{.value = 100.0f, .unit = CSSLengthUnit::Px}},
.position =
CSSRadialGradientPosition{
.top = CSSPercentage{.value = 50.0f},
.left = CSSPercentage{.value = 50.0f}},
.items = {makeCSSColorStop(255, 0, 0), makeCSSColorStop(0, 0, 255)}};
ASSERT_EQ(result, expected);
}
TEST_F(CSSBackgroundImageTest, RadialGradientInferEllipseFromDoubleLength) {
auto result = parseCSSProperty<CSSBackgroundImage>(
"radial-gradient(100px 50px, red, blue)");
decltype(result) expected = CSSRadialGradientFunction{
.shape = CSSRadialGradientShape::Ellipse,
.size =
CSSRadialGradientExplicitSize{
.sizeX = CSSLength{.value = 100.0f, .unit = CSSLengthUnit::Px},
.sizeY = CSSLength{.value = 50.0f, .unit = CSSLengthUnit::Px}},
.position =
CSSRadialGradientPosition{
.top = CSSPercentage{.value = 50.0f},
.left = CSSPercentage{.value = 50.0f}},
.items = {makeCSSColorStop(255, 0, 0), makeCSSColorStop(0, 0, 255)}};
ASSERT_EQ(result, expected);
}
TEST_F(CSSBackgroundImageTest, RadialGradientExplicitShapeWithSize) {
auto result = parseCSSProperty<CSSBackgroundImage>(
"radial-gradient(circle 100px at center, red, blue 80%)");
decltype(result) expected = CSSRadialGradientFunction{
.shape = CSSRadialGradientShape::Circle,
.size =
CSSRadialGradientExplicitSize{
.sizeX = CSSLength{.value = 100.0f, .unit = CSSLengthUnit::Px},
.sizeY = CSSLength{.value = 100.0f, .unit = CSSLengthUnit::Px}},
.position =
CSSRadialGradientPosition{
.top = CSSPercentage{.value = 50.0f},
.left = CSSPercentage{.value = 50.0f}},
.items = {
makeCSSColorStop(255, 0, 0),
CSSColorStop{
.color = CSSColor{.r = 0, .g = 0, .b = 255, .a = 255},
.startPosition = CSSPercentage{.value = 80.0f}}}};
ASSERT_EQ(result, expected);
}
// 1. position syntax: [ left | center | right | top | bottom |
// <length-percentage> ]
TEST_F(CSSBackgroundImageTest, RadialGradientPositionLengthSyntax) {
auto result = parseCSSProperty<CSSBackgroundImage>(
"radial-gradient(circle at 20px, red, blue)");
decltype(result) expected = CSSRadialGradientFunction{
.shape = CSSRadialGradientShape::Circle,
.size = CSSRadialGradientSizeKeyword::FarthestCorner,
.position =
CSSRadialGradientPosition{
.top = CSSPercentage{.value = 50.0f},
.left = CSSLength{.value = 20.0f, .unit = CSSLengthUnit::Px}},
.items = {makeCSSColorStop(255, 0, 0), makeCSSColorStop(0, 0, 255)}};
ASSERT_EQ(result, expected);
}
// 2. position syntax: [ left | center | right ] && [ top | center | bottom ]
TEST_F(CSSBackgroundImageTest, RadialGradientPositionKeywordCombinations) {
const std::vector<std::string> inputs = {
"radial-gradient(circle at left top, red, blue)",
"radial-gradient(circle at top left, red, blue)"};
decltype(parseCSSProperty<CSSBackgroundImage>(inputs[0])) expected =
CSSRadialGradientFunction{
.shape = CSSRadialGradientShape::Circle,
.size = CSSRadialGradientSizeKeyword::FarthestCorner,
.position =
CSSRadialGradientPosition{
.top = CSSPercentage{.value = 0.0f},
.left = CSSPercentage{.value = 0.0f}},
.items = {makeCSSColorStop(255, 0, 0), makeCSSColorStop(0, 0, 255)}};
for (const auto& input : inputs) {
auto result = parseCSSProperty<CSSBackgroundImage>(input);
ASSERT_EQ(result, expected) << "Failed for input: " << input;
}
}
// 3. position syntax: [ left | center | right | <length-percentage> ] [ top
// | center | bottom | <length-percentage> ]
TEST_F(CSSBackgroundImageTest, RadialGradientComplexPositionSyntax) {
const std::vector<std::pair<std::string, CSSRadialGradientPosition>>
testCases = {
{
"radial-gradient(circle at left 20px, red, blue)",
{.top = CSSLength{.value = 20.0f, .unit = CSSLengthUnit::Px},
.left = CSSPercentage{.value = 0.f}},
},
{
"radial-gradient(circle at 20px 20px, red, blue)",
{.top = CSSLength{.value = 20.0f, .unit = CSSLengthUnit::Px},
.left = CSSLength{.value = 20.0f, .unit = CSSLengthUnit::Px}},
},
{
"radial-gradient(circle at right 50px, red, blue)",
{.top = CSSLength{.value = 50.0f, .unit = CSSLengthUnit::Px},
.right = CSSPercentage{.value = 0.f}},
}};
for (const auto& [input, expectedPosition] : testCases) {
const auto result = parseCSSProperty<CSSBackgroundImage>(input);
decltype(result) expected = CSSRadialGradientFunction{
.shape = CSSRadialGradientShape::Circle,
.size = CSSRadialGradientSizeKeyword::FarthestCorner,
.position = expectedPosition,
.items = {makeCSSColorStop(255, 0, 0), makeCSSColorStop(0, 0, 255)}};
ASSERT_EQ(result, expected);
}
}
// 4. position syntax: [ [ left | right ] <length-percentage> ] && [ [ top |
// bottom ] <length-percentage> ]
TEST_F(CSSBackgroundImageTest, RadialGradientSeparatePositionPercentages) {
auto result = parseCSSProperty<CSSBackgroundImage>(
"radial-gradient(at top 0% right 10%, red, blue)");
decltype(result) expected = CSSRadialGradientFunction{
.shape = CSSRadialGradientShape::Ellipse,
.size = CSSRadialGradientSizeKeyword::FarthestCorner,
.position =
CSSRadialGradientPosition{
.top = CSSPercentage{.value = 0.0f},
.right = CSSPercentage{.value = 10.0f}},
.items = {makeCSSColorStop(255, 0, 0), makeCSSColorStop(0, 0, 255)}};
ASSERT_EQ(result, expected);
}
TEST_F(CSSBackgroundImageTest, RadialGradientWithTransitionHints) {
auto result = parseCSSProperty<CSSBackgroundImage>(
"radial-gradient(circle, red 0%, 25%, blue 50%, 75%, green 100%)");
decltype(result) expected = CSSRadialGradientFunction{
.shape = CSSRadialGradientShape::Circle,
.size = CSSRadialGradientSizeKeyword::FarthestCorner,
.position =
CSSRadialGradientPosition{
.top = CSSPercentage{.value = 50.0f},
.left = CSSPercentage{.value = 50.0f}},
.items = {
CSSColorStop{
.color = CSSColor{.r = 255, .g = 0, .b = 0, .a = 255},
.startPosition = CSSPercentage{.value = 0.0f}},
CSSColorHint{.position = CSSPercentage{.value = 25.0f}},
CSSColorStop{
.color = CSSColor{.r = 0, .g = 0, .b = 255, .a = 255},
.startPosition = CSSPercentage{.value = 50.0f}},
CSSColorHint{.position = CSSPercentage{.value = 75.0f}},
CSSColorStop{
.color = CSSColor{.r = 0, .g = 128, .b = 0, .a = 255},
.startPosition = CSSPercentage{.value = 100.0f}},
}};
ASSERT_EQ(result, expected);
}
TEST_F(CSSBackgroundImageTest, MultipleGradientsRadialAndLinear) {
auto result = parseCSSProperty<CSSBackgroundImageList>(
"radial-gradient(circle at top left, red, blue), linear-gradient(to bottom, green, yellow)");
decltype(result) expected = CSSBackgroundImageList{
{CSSRadialGradientFunction{
.shape = CSSRadialGradientShape::Circle,
.size = CSSRadialGradientSizeKeyword::FarthestCorner,
.position =
CSSRadialGradientPosition{
.top = CSSPercentage{.value = 0.0f},
.left = CSSPercentage{.value = 0.0f}},
.items = {makeCSSColorStop(255, 0, 0), makeCSSColorStop(0, 0, 255)}},
CSSLinearGradientFunction{
.direction =
CSSLinearGradientDirection{.value = CSSAngle{.degrees = 180.0f}},
.items = {
makeCSSColorStop(0, 128, 0), makeCSSColorStop(255, 255, 0)}}}};
ASSERT_EQ(result, expected);
}
TEST_F(CSSBackgroundImageTest, RadialGradientMixedCase) {
auto result = parseCSSProperty<CSSBackgroundImage>(
"RaDiAl-GrAdIeNt(CiRcLe ClOsEsT-sIdE aT cEnTeR, rEd, bLuE)");
decltype(result) expected = CSSRadialGradientFunction{
.shape = CSSRadialGradientShape::Circle,
.size = CSSRadialGradientSizeKeyword::ClosestSide,
.position =
CSSRadialGradientPosition{
.top = CSSPercentage{.value = 50.0f},
.left = CSSPercentage{.value = 50.0f}},
.items = {makeCSSColorStop(255, 0, 0), makeCSSColorStop(0, 0, 255)}};
ASSERT_EQ(result, expected);
}
TEST_F(CSSBackgroundImageTest, RadialGradientWhitespaceVariations) {
auto result = parseCSSProperty<CSSBackgroundImage>(
"radial-gradient( circle farthest-corner at 25% 75% , red 0% , blue 100% )");
decltype(result) expected = CSSRadialGradientFunction{
.shape = CSSRadialGradientShape::Circle,
.size = CSSRadialGradientSizeKeyword::FarthestCorner,
.position =
CSSRadialGradientPosition{
.top = CSSPercentage{.value = 75.0f},
.left = CSSPercentage{.value = 25.0f}},
.items = {
CSSColorStop{
.color = CSSColor{.r = 255, .g = 0, .b = 0, .a = 255},
.startPosition = CSSPercentage{.value = 0.0f}},
CSSColorStop{
.color = CSSColor{.r = 0, .g = 0, .b = 255, .a = 255},
.startPosition = CSSPercentage{.value = 100.0f}},
}};
ASSERT_EQ(result, expected);
}
TEST_F(CSSBackgroundImageTest, RadialGradientInvalidCases) {
const std::vector<std::string> invalidInputs = {
"radial-gradient(circle at top leftt, red, blue)",
"radial-gradient(circle at, red, blue)",
"radial-gradient(ellipse 100px, red, blue)",
"radial-gradient(ellipse at top 20% top 50%, red, blue)"};
for (const auto& input : invalidInputs) {
const auto result = parseCSSProperty<CSSBackgroundImageList>(input);
ASSERT_TRUE(std::holds_alternative<std::monostate>(result))
<< "Input should be invalid: " << input;
}
}
TEST_F(CSSBackgroundImageTest, RadialGradientMultipleColorStops) {
auto result = parseCSSProperty<CSSBackgroundImage>(
"radial-gradient(red 0%, yellow 30%, green 60%, blue 100%)");
decltype(result) expected = CSSRadialGradientFunction{
.shape = CSSRadialGradientShape::Ellipse,
.size = CSSRadialGradientSizeKeyword::FarthestCorner,
.position =
CSSRadialGradientPosition{
.top = CSSPercentage{.value = 50.0f},
.left = CSSPercentage{.value = 50.0f}},
.items = {
CSSColorStop{
.color = CSSColor{.r = 255, .g = 0, .b = 0, .a = 255},
.startPosition = CSSPercentage{.value = 0.0f}},
CSSColorStop{
.color = CSSColor{.r = 255, .g = 255, .b = 0, .a = 255},
.startPosition = CSSPercentage{.value = 30.0f}},
CSSColorStop{
.color = CSSColor{.r = 0, .g = 128, .b = 0, .a = 255},
.startPosition = CSSPercentage{.value = 60.0f}},
CSSColorStop{
.color = CSSColor{.r = 0, .g = 0, .b = 255, .a = 255},
.startPosition = CSSPercentage{.value = 100.0f}}}};
ASSERT_EQ(result, expected);
}
TEST_F(CSSBackgroundImageTest, InvalidGradientFunctionName) {
const std::string input =
"aoeusntial-gradient(red 0%, yellow 30%, green 60%, blue 100%)";
const auto result = parseCSSProperty<CSSBackgroundImageList>(input);
ASSERT_TRUE(std::holds_alternative<std::monostate>(result));
}
TEST_F(CSSBackgroundImageTest, RadialGradientNegativeRadius) {
const std::vector<std::string> invalidInputs = {
"radial-gradient(circle -100px, red, blue)",
"radial-gradient(ellipse 100px -40px, red, blue)"};
for (const auto& input : invalidInputs) {
const auto result = parseCSSProperty<CSSBackgroundImageList>(input);
ASSERT_TRUE(std::holds_alternative<std::monostate>(result))
<< "Input should be invalid: " << input;
}
}
} // namespace facebook::react

View File

@@ -0,0 +1,495 @@
/*
* Copyright (c) Meta Platforms, Inc. and affiliates.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*/
#include <gtest/gtest.h>
#include <react/renderer/css/CSSColor.h>
#include <react/renderer/css/CSSValueParser.h>
namespace facebook::react {
TEST(CSSColor, hex_color_values) {
auto emptyValue = parseCSSProperty<CSSColor>("");
EXPECT_TRUE(std::holds_alternative<std::monostate>(emptyValue));
auto hex3DigitColorValue = parseCSSProperty<CSSColor>("#fff");
EXPECT_TRUE(std::holds_alternative<CSSColor>(hex3DigitColorValue));
EXPECT_EQ(std::get<CSSColor>(hex3DigitColorValue).r, 255);
EXPECT_EQ(std::get<CSSColor>(hex3DigitColorValue).g, 255);
EXPECT_EQ(std::get<CSSColor>(hex3DigitColorValue).b, 255);
EXPECT_EQ(std::get<CSSColor>(hex3DigitColorValue).a, 255);
auto hex4DigitColorValue = parseCSSProperty<CSSColor>("#ffff");
EXPECT_TRUE(std::holds_alternative<CSSColor>(hex4DigitColorValue));
EXPECT_EQ(std::get<CSSColor>(hex4DigitColorValue).r, 255);
EXPECT_EQ(std::get<CSSColor>(hex4DigitColorValue).g, 255);
EXPECT_EQ(std::get<CSSColor>(hex4DigitColorValue).b, 255);
EXPECT_EQ(std::get<CSSColor>(hex4DigitColorValue).a, 255);
auto hex6DigitColorValue = parseCSSProperty<CSSColor>("#ffffff");
EXPECT_TRUE(std::holds_alternative<CSSColor>(hex6DigitColorValue));
EXPECT_EQ(std::get<CSSColor>(hex6DigitColorValue).r, 255);
EXPECT_EQ(std::get<CSSColor>(hex6DigitColorValue).g, 255);
EXPECT_EQ(std::get<CSSColor>(hex6DigitColorValue).b, 255);
EXPECT_EQ(std::get<CSSColor>(hex6DigitColorValue).a, 255);
auto hex8DigitColorValue = parseCSSProperty<CSSColor>("#ffffffff");
EXPECT_TRUE(std::holds_alternative<CSSColor>(hex8DigitColorValue));
EXPECT_EQ(std::get<CSSColor>(hex8DigitColorValue).r, 255);
EXPECT_EQ(std::get<CSSColor>(hex8DigitColorValue).g, 255);
EXPECT_EQ(std::get<CSSColor>(hex8DigitColorValue).b, 255);
EXPECT_EQ(std::get<CSSColor>(hex8DigitColorValue).a, 255);
auto hexMixedCaseColorValue = parseCSSProperty<CSSColor>("#FFCc99");
EXPECT_TRUE(std::holds_alternative<CSSColor>(hexMixedCaseColorValue));
EXPECT_EQ(std::get<CSSColor>(hexMixedCaseColorValue).r, 255);
EXPECT_EQ(std::get<CSSColor>(hexMixedCaseColorValue).g, 204);
EXPECT_EQ(std::get<CSSColor>(hexMixedCaseColorValue).b, 153);
EXPECT_EQ(std::get<CSSColor>(hexMixedCaseColorValue).a, 255);
auto hexDigitOnlyColorValue = parseCSSProperty<CSSColor>("#369");
EXPECT_TRUE(std::holds_alternative<CSSColor>(hexDigitOnlyColorValue));
EXPECT_EQ(std::get<CSSColor>(hexDigitOnlyColorValue).r, 51);
EXPECT_EQ(std::get<CSSColor>(hexDigitOnlyColorValue).g, 102);
EXPECT_EQ(std::get<CSSColor>(hexDigitOnlyColorValue).b, 153);
EXPECT_EQ(std::get<CSSColor>(hexDigitOnlyColorValue).a, 255);
auto hexAlphaTestValue = parseCSSProperty<CSSColor>("#FFFFFFCC");
EXPECT_TRUE(std::holds_alternative<CSSColor>(hexAlphaTestValue));
EXPECT_EQ(std::get<CSSColor>(hexAlphaTestValue).r, 255);
EXPECT_EQ(std::get<CSSColor>(hexAlphaTestValue).g, 255);
EXPECT_EQ(std::get<CSSColor>(hexAlphaTestValue).b, 255);
EXPECT_EQ(std::get<CSSColor>(hexAlphaTestValue).a, 204);
}
TEST(CSSColor, named_colors) {
auto invalidNamedColorTestValue = parseCSSProperty<CSSColor>("redd");
EXPECT_TRUE(
std::holds_alternative<std::monostate>(invalidNamedColorTestValue));
auto namedColorTestValue1 = parseCSSProperty<CSSColor>("red");
EXPECT_TRUE(std::holds_alternative<CSSColor>(namedColorTestValue1));
EXPECT_EQ(std::get<CSSColor>(namedColorTestValue1).r, 255);
EXPECT_EQ(std::get<CSSColor>(namedColorTestValue1).g, 0);
EXPECT_EQ(std::get<CSSColor>(namedColorTestValue1).b, 0);
EXPECT_EQ(std::get<CSSColor>(namedColorTestValue1).a, 255);
auto namedColorTestValue2 = parseCSSProperty<CSSColor>("cornsilk");
EXPECT_TRUE(std::holds_alternative<CSSColor>(namedColorTestValue2));
EXPECT_EQ(std::get<CSSColor>(namedColorTestValue2).r, 255);
EXPECT_EQ(std::get<CSSColor>(namedColorTestValue2).g, 248);
EXPECT_EQ(std::get<CSSColor>(namedColorTestValue2).b, 220);
EXPECT_EQ(std::get<CSSColor>(namedColorTestValue2).a, 255);
auto namedColorMixedCaseTestValue = parseCSSProperty<CSSColor>("sPrINgGrEEn");
EXPECT_TRUE(std::holds_alternative<CSSColor>(namedColorMixedCaseTestValue));
EXPECT_EQ(std::get<CSSColor>(namedColorMixedCaseTestValue).r, 0);
EXPECT_EQ(std::get<CSSColor>(namedColorMixedCaseTestValue).g, 255);
EXPECT_EQ(std::get<CSSColor>(namedColorMixedCaseTestValue).b, 127);
EXPECT_EQ(std::get<CSSColor>(namedColorMixedCaseTestValue).a, 255);
auto transparentColor = parseCSSProperty<CSSColor>("transparent");
EXPECT_TRUE(std::holds_alternative<CSSColor>(transparentColor));
EXPECT_EQ(std::get<CSSColor>(transparentColor).r, 0);
EXPECT_EQ(std::get<CSSColor>(transparentColor).g, 0);
EXPECT_EQ(std::get<CSSColor>(transparentColor).b, 0);
EXPECT_EQ(std::get<CSSColor>(transparentColor).a, 0);
}
TEST(CSSColor, rgb_rgba_values) {
auto simpleValue = parseCSSProperty<CSSColor>("rgb(255, 255, 255)");
EXPECT_TRUE(std::holds_alternative<CSSColor>(simpleValue));
EXPECT_EQ(std::get<CSSColor>(simpleValue).r, 255);
EXPECT_EQ(std::get<CSSColor>(simpleValue).g, 255);
EXPECT_EQ(std::get<CSSColor>(simpleValue).b, 255);
EXPECT_EQ(std::get<CSSColor>(simpleValue).a, 255);
auto capsValue = parseCSSProperty<CSSColor>("RGB(255, 255, 255)");
EXPECT_TRUE(std::holds_alternative<CSSColor>(capsValue));
EXPECT_EQ(std::get<CSSColor>(capsValue).r, 255);
EXPECT_EQ(std::get<CSSColor>(capsValue).g, 255);
EXPECT_EQ(std::get<CSSColor>(capsValue).b, 255);
EXPECT_EQ(std::get<CSSColor>(capsValue).a, 255);
auto modernSyntaxValue = parseCSSProperty<CSSColor>("rgb(255 255 255)");
EXPECT_TRUE(std::holds_alternative<CSSColor>(modernSyntaxValue));
EXPECT_EQ(std::get<CSSColor>(modernSyntaxValue).r, 255);
EXPECT_EQ(std::get<CSSColor>(modernSyntaxValue).g, 255);
EXPECT_EQ(std::get<CSSColor>(modernSyntaxValue).b, 255);
EXPECT_EQ(std::get<CSSColor>(modernSyntaxValue).a, 255);
auto mixedDelimeterValue = parseCSSProperty<CSSColor>("rgb(255,255 255)");
EXPECT_TRUE(std::holds_alternative<std::monostate>(mixedDelimeterValue));
auto mixedSpacingValue = parseCSSProperty<CSSColor>("rgb( 5 4 3)");
EXPECT_TRUE(std::holds_alternative<CSSColor>(mixedSpacingValue));
EXPECT_EQ(std::get<CSSColor>(mixedSpacingValue).r, 5);
EXPECT_EQ(std::get<CSSColor>(mixedSpacingValue).g, 4);
EXPECT_EQ(std::get<CSSColor>(mixedSpacingValue).b, 3);
EXPECT_EQ(std::get<CSSColor>(mixedSpacingValue).a, 255);
auto clampedValue = parseCSSProperty<CSSColor>("rgb(-50, 500, 0)");
EXPECT_TRUE(std::holds_alternative<CSSColor>(clampedValue));
EXPECT_EQ(std::get<CSSColor>(clampedValue).r, 0);
EXPECT_EQ(std::get<CSSColor>(clampedValue).g, 255);
EXPECT_EQ(std::get<CSSColor>(clampedValue).b, 0);
EXPECT_EQ(std::get<CSSColor>(clampedValue).a, 255);
auto fractionalValue = parseCSSProperty<CSSColor>("rgb(0.5, 0.5, 0.5)");
EXPECT_TRUE(std::holds_alternative<CSSColor>(fractionalValue));
EXPECT_EQ(std::get<CSSColor>(fractionalValue).r, 1);
EXPECT_EQ(std::get<CSSColor>(fractionalValue).g, 1);
EXPECT_EQ(std::get<CSSColor>(fractionalValue).b, 1);
EXPECT_EQ(std::get<CSSColor>(fractionalValue).a, 255);
auto percentageValue = parseCSSProperty<CSSColor>("rgb(50%, 50%, 50%)");
EXPECT_TRUE(std::holds_alternative<CSSColor>(percentageValue));
EXPECT_EQ(std::get<CSSColor>(percentageValue).r, 128);
EXPECT_EQ(std::get<CSSColor>(percentageValue).g, 128);
EXPECT_EQ(std::get<CSSColor>(percentageValue).b, 128);
auto mixedLegacyNumberPercentageValue =
parseCSSProperty<CSSColor>("rgb(50%, 0.5, 50%)");
EXPECT_TRUE(
std::holds_alternative<std::monostate>(mixedLegacyNumberPercentageValue));
auto mixedModernNumberPercentageValue =
parseCSSProperty<CSSColor>("rgb(50% 0.5 50%)");
EXPECT_TRUE(
std::holds_alternative<CSSColor>(mixedModernNumberPercentageValue));
EXPECT_EQ(std::get<CSSColor>(mixedModernNumberPercentageValue).r, 128);
EXPECT_EQ(std::get<CSSColor>(mixedModernNumberPercentageValue).g, 1);
EXPECT_EQ(std::get<CSSColor>(mixedModernNumberPercentageValue).b, 128);
EXPECT_EQ(std::get<CSSColor>(mixedModernNumberPercentageValue).a, 255);
auto rgbWithNumberAlphaValue =
parseCSSProperty<CSSColor>("rgb(255 255 255 0.5)");
EXPECT_TRUE(std::holds_alternative<CSSColor>(rgbWithNumberAlphaValue));
EXPECT_EQ(std::get<CSSColor>(rgbWithNumberAlphaValue).r, 255);
EXPECT_EQ(std::get<CSSColor>(rgbWithNumberAlphaValue).g, 255);
EXPECT_EQ(std::get<CSSColor>(rgbWithNumberAlphaValue).b, 255);
EXPECT_EQ(std::get<CSSColor>(rgbWithNumberAlphaValue).a, 128);
auto rgbWithPercentageAlphaValue =
parseCSSProperty<CSSColor>("rgb(255 255 255 50%)");
EXPECT_TRUE(std::holds_alternative<CSSColor>(rgbWithPercentageAlphaValue));
EXPECT_EQ(std::get<CSSColor>(rgbWithPercentageAlphaValue).r, 255);
EXPECT_EQ(std::get<CSSColor>(rgbWithPercentageAlphaValue).g, 255);
EXPECT_EQ(std::get<CSSColor>(rgbWithPercentageAlphaValue).b, 255);
EXPECT_EQ(std::get<CSSColor>(rgbWithPercentageAlphaValue).a, 128);
auto rgbWithSolidusAlphaValue =
parseCSSProperty<CSSColor>("rgb(255 255 255 / 0.5)");
EXPECT_TRUE(std::holds_alternative<CSSColor>(rgbWithSolidusAlphaValue));
EXPECT_EQ(std::get<CSSColor>(rgbWithSolidusAlphaValue).r, 255);
EXPECT_EQ(std::get<CSSColor>(rgbWithSolidusAlphaValue).g, 255);
EXPECT_EQ(std::get<CSSColor>(rgbWithSolidusAlphaValue).b, 255);
EXPECT_EQ(std::get<CSSColor>(rgbWithSolidusAlphaValue).a, 128);
auto rgbLegacySyntaxWithSolidusAlphaValue =
parseCSSProperty<CSSColor>("rgb(1, 4, 5 /0.5)");
EXPECT_TRUE(
std::holds_alternative<std::monostate>(
rgbLegacySyntaxWithSolidusAlphaValue));
auto rgbaWithSolidusAlphaValue =
parseCSSProperty<CSSColor>("rgba(255 255 255 / 0.5)");
EXPECT_TRUE(std::holds_alternative<CSSColor>(rgbaWithSolidusAlphaValue));
EXPECT_EQ(std::get<CSSColor>(rgbaWithSolidusAlphaValue).r, 255);
EXPECT_EQ(std::get<CSSColor>(rgbaWithSolidusAlphaValue).g, 255);
EXPECT_EQ(std::get<CSSColor>(rgbaWithSolidusAlphaValue).b, 255);
EXPECT_EQ(std::get<CSSColor>(rgbaWithSolidusAlphaValue).a, 128);
auto rgbaWithPercentageSolidusAlphaValue =
parseCSSProperty<CSSColor>("rgba(255 255 255 / 50%)");
EXPECT_TRUE(
std::holds_alternative<CSSColor>(rgbaWithPercentageSolidusAlphaValue));
EXPECT_EQ(std::get<CSSColor>(rgbaWithPercentageSolidusAlphaValue).r, 255);
EXPECT_EQ(std::get<CSSColor>(rgbaWithPercentageSolidusAlphaValue).g, 255);
EXPECT_EQ(std::get<CSSColor>(rgbaWithPercentageSolidusAlphaValue).b, 255);
EXPECT_EQ(std::get<CSSColor>(rgbaWithPercentageSolidusAlphaValue).a, 128);
auto rgbaWithoutAlphaValue = parseCSSProperty<CSSColor>("rgba(255 255 255)");
EXPECT_TRUE(std::holds_alternative<CSSColor>(rgbaWithoutAlphaValue));
EXPECT_EQ(std::get<CSSColor>(rgbaWithoutAlphaValue).r, 255);
EXPECT_EQ(std::get<CSSColor>(rgbaWithoutAlphaValue).g, 255);
EXPECT_EQ(std::get<CSSColor>(rgbaWithoutAlphaValue).b, 255);
EXPECT_EQ(std::get<CSSColor>(rgbaWithoutAlphaValue).a, 255);
auto surroundingWhitespaceValue =
parseCSSProperty<CSSColor>(" rgb(255, 1, 2) ");
EXPECT_TRUE(std::holds_alternative<CSSColor>(surroundingWhitespaceValue));
EXPECT_EQ(std::get<CSSColor>(surroundingWhitespaceValue).r, 255);
EXPECT_EQ(std::get<CSSColor>(surroundingWhitespaceValue).g, 1);
EXPECT_EQ(std::get<CSSColor>(surroundingWhitespaceValue).b, 2);
EXPECT_EQ(std::get<CSSColor>(surroundingWhitespaceValue).a, 255);
auto valueWithSingleComponent = parseCSSProperty<CSSColor>("rgb(255)");
EXPECT_TRUE(std::holds_alternative<std::monostate>(valueWithSingleComponent));
auto valueWithTooFewComponents = parseCSSProperty<CSSColor>("rgb(255, 255)");
EXPECT_TRUE(
std::holds_alternative<std::monostate>(valueWithTooFewComponents));
auto valueWithTooManyComponents =
parseCSSProperty<CSSColor>("rgb(255, 255, 255, 255, 255)");
EXPECT_TRUE(
std::holds_alternative<std::monostate>(valueWithTooManyComponents));
auto valueStartingWithComma = parseCSSProperty<CSSColor>("rgb(, 1, 2)");
EXPECT_TRUE(std::holds_alternative<std::monostate>(valueStartingWithComma));
auto valueEndingWithComma = parseCSSProperty<CSSColor>("rgb(1, 2, )");
EXPECT_TRUE(std::holds_alternative<std::monostate>(valueEndingWithComma));
}
TEST(CSSColor, hsl_hsla_values) {
auto simpleValue = parseCSSProperty<CSSColor>("hsl(180, 50%, 50%)");
EXPECT_TRUE(std::holds_alternative<CSSColor>(simpleValue));
EXPECT_EQ(std::get<CSSColor>(simpleValue).r, 64);
EXPECT_EQ(std::get<CSSColor>(simpleValue).g, 191);
EXPECT_EQ(std::get<CSSColor>(simpleValue).b, 191);
EXPECT_EQ(std::get<CSSColor>(simpleValue).a, 255);
auto modernSyntaxValue = parseCSSProperty<CSSColor>("hsl(180 50% 50%)");
EXPECT_TRUE(std::holds_alternative<CSSColor>(modernSyntaxValue));
EXPECT_EQ(std::get<CSSColor>(modernSyntaxValue).r, 64);
EXPECT_EQ(std::get<CSSColor>(modernSyntaxValue).g, 191);
EXPECT_EQ(std::get<CSSColor>(modernSyntaxValue).b, 191);
EXPECT_EQ(std::get<CSSColor>(modernSyntaxValue).a, 255);
auto degreesValue = parseCSSProperty<CSSColor>("hsl(180deg, 50%, 50%)");
EXPECT_TRUE(std::holds_alternative<CSSColor>(degreesValue));
EXPECT_EQ(std::get<CSSColor>(degreesValue).r, 64);
EXPECT_EQ(std::get<CSSColor>(degreesValue).g, 191);
EXPECT_EQ(std::get<CSSColor>(degreesValue).b, 191);
EXPECT_EQ(std::get<CSSColor>(degreesValue).a, 255);
auto turnValue = parseCSSProperty<CSSColor>("hsl(0.5turn, 50%, 50%)");
EXPECT_TRUE(std::holds_alternative<CSSColor>(turnValue));
EXPECT_EQ(std::get<CSSColor>(turnValue).r, 64);
EXPECT_EQ(std::get<CSSColor>(turnValue).g, 191);
EXPECT_EQ(std::get<CSSColor>(turnValue).b, 191);
EXPECT_EQ(std::get<CSSColor>(turnValue).a, 255);
auto legacySyntaxAlphaValue =
parseCSSProperty<CSSColor>("hsl(70, 190%, 75%, 0.5)");
EXPECT_TRUE(std::holds_alternative<CSSColor>(legacySyntaxAlphaValue));
EXPECT_EQ(std::get<CSSColor>(legacySyntaxAlphaValue).r, 234);
EXPECT_EQ(std::get<CSSColor>(legacySyntaxAlphaValue).g, 255);
EXPECT_EQ(std::get<CSSColor>(legacySyntaxAlphaValue).b, 128);
EXPECT_EQ(std::get<CSSColor>(legacySyntaxAlphaValue).a, 128);
auto modernSyntaxAlphaValue =
parseCSSProperty<CSSColor>("hsl(70 190% 75% 0.5)");
EXPECT_TRUE(std::holds_alternative<CSSColor>(modernSyntaxAlphaValue));
EXPECT_EQ(std::get<CSSColor>(modernSyntaxAlphaValue).r, 234);
EXPECT_EQ(std::get<CSSColor>(modernSyntaxAlphaValue).g, 255);
EXPECT_EQ(std::get<CSSColor>(modernSyntaxAlphaValue).b, 128);
EXPECT_EQ(std::get<CSSColor>(modernSyntaxAlphaValue).a, 128);
auto modernSyntaxWithSolidusAlphaValue =
parseCSSProperty<CSSColor>("hsl(70 190% 75% 0.5)");
EXPECT_TRUE(
std::holds_alternative<CSSColor>(modernSyntaxWithSolidusAlphaValue));
EXPECT_EQ(std::get<CSSColor>(modernSyntaxWithSolidusAlphaValue).r, 234);
EXPECT_EQ(std::get<CSSColor>(modernSyntaxWithSolidusAlphaValue).g, 255);
EXPECT_EQ(std::get<CSSColor>(modernSyntaxWithSolidusAlphaValue).b, 128);
EXPECT_EQ(std::get<CSSColor>(modernSyntaxWithSolidusAlphaValue).a, 128);
auto percentageAlphaValue =
parseCSSProperty<CSSColor>("hsl(70 190% 75% 50%)");
EXPECT_TRUE(std::holds_alternative<CSSColor>(percentageAlphaValue));
EXPECT_EQ(std::get<CSSColor>(percentageAlphaValue).r, 234);
EXPECT_EQ(std::get<CSSColor>(percentageAlphaValue).g, 255);
EXPECT_EQ(std::get<CSSColor>(percentageAlphaValue).b, 128);
EXPECT_EQ(std::get<CSSColor>(percentageAlphaValue).a, 128);
auto hslaWithSolidusAlphaValue =
parseCSSProperty<CSSColor>("hsla(70 190% 75% / 0.5)");
EXPECT_TRUE(std::holds_alternative<CSSColor>(hslaWithSolidusAlphaValue));
EXPECT_EQ(std::get<CSSColor>(hslaWithSolidusAlphaValue).r, 234);
EXPECT_EQ(std::get<CSSColor>(hslaWithSolidusAlphaValue).g, 255);
EXPECT_EQ(std::get<CSSColor>(hslaWithSolidusAlphaValue).b, 128);
EXPECT_EQ(std::get<CSSColor>(hslaWithSolidusAlphaValue).a, 128);
auto rgbLegacySyntaxWithSolidusAlphaValue =
parseCSSProperty<CSSColor>("hsl(1, 4, 5 / 0.5)");
EXPECT_TRUE(
std::holds_alternative<std::monostate>(
rgbLegacySyntaxWithSolidusAlphaValue));
auto hslaWithoutAlphaValue = parseCSSProperty<CSSColor>("hsla(70 190% 75%)");
EXPECT_TRUE(std::holds_alternative<CSSColor>(hslaWithoutAlphaValue));
EXPECT_EQ(std::get<CSSColor>(hslaWithoutAlphaValue).r, 234);
EXPECT_EQ(std::get<CSSColor>(hslaWithoutAlphaValue).g, 255);
EXPECT_EQ(std::get<CSSColor>(hslaWithoutAlphaValue).b, 128);
EXPECT_EQ(std::get<CSSColor>(hslaWithoutAlphaValue).a, 255);
auto surroundingWhitespaceValue =
parseCSSProperty<CSSColor>(" hsl(180, 50%, 50%) ");
EXPECT_TRUE(std::holds_alternative<CSSColor>(surroundingWhitespaceValue));
EXPECT_EQ(std::get<CSSColor>(surroundingWhitespaceValue).r, 64);
EXPECT_EQ(std::get<CSSColor>(surroundingWhitespaceValue).g, 191);
EXPECT_EQ(std::get<CSSColor>(surroundingWhitespaceValue).b, 191);
EXPECT_EQ(std::get<CSSColor>(surroundingWhitespaceValue).a, 255);
auto modernSyntaxWithNumberComponent =
parseCSSProperty<CSSColor>("hsl(180 50 50%)");
EXPECT_TRUE(
std::holds_alternative<CSSColor>(modernSyntaxWithNumberComponent));
EXPECT_EQ(std::get<CSSColor>(modernSyntaxWithNumberComponent).r, 64);
EXPECT_EQ(std::get<CSSColor>(modernSyntaxWithNumberComponent).g, 191);
EXPECT_EQ(std::get<CSSColor>(modernSyntaxWithNumberComponent).b, 191);
EXPECT_EQ(std::get<CSSColor>(modernSyntaxWithNumberComponent).a, 255);
auto legacySyntaxWithNumberComponent =
parseCSSProperty<CSSColor>("hsl(180, 50, 50%)");
EXPECT_TRUE(
std::holds_alternative<std::monostate>(legacySyntaxWithNumberComponent));
auto clampedComponentValue =
parseCSSProperty<CSSColor>("hsl(360, -100%, 120%)");
EXPECT_TRUE(std::holds_alternative<CSSColor>(clampedComponentValue));
EXPECT_EQ(std::get<CSSColor>(clampedComponentValue).r, 255);
EXPECT_EQ(std::get<CSSColor>(clampedComponentValue).g, 255);
EXPECT_EQ(std::get<CSSColor>(clampedComponentValue).b, 255);
EXPECT_EQ(std::get<CSSColor>(clampedComponentValue).a, 255);
auto manyDegreesValue = parseCSSProperty<CSSColor>("hsl(540deg, 50%, 50%)");
EXPECT_TRUE(std::holds_alternative<CSSColor>(manyDegreesValue));
EXPECT_EQ(std::get<CSSColor>(manyDegreesValue).r, 64);
EXPECT_EQ(std::get<CSSColor>(manyDegreesValue).g, 191);
EXPECT_EQ(std::get<CSSColor>(manyDegreesValue).b, 191);
EXPECT_EQ(std::get<CSSColor>(manyDegreesValue).a, 255);
auto negativeDegreesValue =
parseCSSProperty<CSSColor>("hsl(-180deg, 50%, 50%)");
EXPECT_TRUE(std::holds_alternative<CSSColor>(negativeDegreesValue));
EXPECT_EQ(std::get<CSSColor>(negativeDegreesValue).r, 64);
EXPECT_EQ(std::get<CSSColor>(negativeDegreesValue).g, 191);
EXPECT_EQ(std::get<CSSColor>(negativeDegreesValue).b, 191);
EXPECT_EQ(std::get<CSSColor>(negativeDegreesValue).a, 255);
auto valueWithSingleComponent = parseCSSProperty<CSSColor>("hsl(180deg)");
EXPECT_TRUE(std::holds_alternative<std::monostate>(valueWithSingleComponent));
auto valueWithTooFewComponents =
parseCSSProperty<CSSColor>("hsl(180deg, 50%)");
EXPECT_TRUE(
std::holds_alternative<std::monostate>(valueWithTooFewComponents));
auto valueWithTooManyComponents =
parseCSSProperty<CSSColor>("hsl(70 190% 75% 0.5 0.5)");
EXPECT_TRUE(
std::holds_alternative<std::monostate>(valueWithTooManyComponents));
auto valueStartingWithComma =
parseCSSProperty<CSSColor>("hsl(,540deg, 50%, 50%)");
EXPECT_TRUE(std::holds_alternative<std::monostate>(valueStartingWithComma));
auto valueEndingWithComma =
parseCSSProperty<CSSColor>("hsl(540deg, 50%, 50%,)");
EXPECT_TRUE(std::holds_alternative<std::monostate>(valueEndingWithComma));
}
TEST(CSSColor, hwb_values) {
auto simpleValue = parseCSSProperty<CSSColor>("hwb(208 14% 42%)");
EXPECT_TRUE(std::holds_alternative<CSSColor>(simpleValue));
EXPECT_EQ(std::get<CSSColor>(simpleValue).r, 36);
EXPECT_EQ(std::get<CSSColor>(simpleValue).g, 96);
EXPECT_EQ(std::get<CSSColor>(simpleValue).b, 148);
EXPECT_EQ(std::get<CSSColor>(simpleValue).a, 255);
auto grayValue = parseCSSProperty<CSSColor>("hwb(208 100 100)");
EXPECT_TRUE(std::holds_alternative<CSSColor>(grayValue));
EXPECT_EQ(std::get<CSSColor>(grayValue).r, 128);
EXPECT_EQ(std::get<CSSColor>(grayValue).g, 128);
EXPECT_EQ(std::get<CSSColor>(grayValue).b, 128);
EXPECT_EQ(std::get<CSSColor>(grayValue).a, 255);
auto angleValue = parseCSSProperty<CSSColor>("hwb(36.3028E-1rad 14% 42%)");
EXPECT_TRUE(std::holds_alternative<CSSColor>(angleValue));
EXPECT_EQ(std::get<CSSColor>(angleValue).r, 36);
EXPECT_EQ(std::get<CSSColor>(angleValue).g, 96);
EXPECT_EQ(std::get<CSSColor>(angleValue).b, 148);
EXPECT_EQ(std::get<CSSColor>(angleValue).a, 255);
auto legacySyntaxValue = parseCSSProperty<CSSColor>("hwb(208, 14%, 42%)");
EXPECT_TRUE(std::holds_alternative<std::monostate>(legacySyntaxValue));
auto alphaValue = parseCSSProperty<CSSColor>("hwb(208 14% 42% 0.5)");
EXPECT_TRUE(std::holds_alternative<CSSColor>(alphaValue));
EXPECT_EQ(std::get<CSSColor>(alphaValue).r, 36);
EXPECT_EQ(std::get<CSSColor>(alphaValue).g, 96);
EXPECT_EQ(std::get<CSSColor>(alphaValue).b, 148);
EXPECT_EQ(std::get<CSSColor>(alphaValue).a, 128);
auto alphaPercentageValue =
parseCSSProperty<CSSColor>("hwb(208 14% 42% 50%)");
EXPECT_TRUE(std::holds_alternative<CSSColor>(alphaPercentageValue));
EXPECT_EQ(std::get<CSSColor>(alphaPercentageValue).r, 36);
EXPECT_EQ(std::get<CSSColor>(alphaPercentageValue).g, 96);
EXPECT_EQ(std::get<CSSColor>(alphaPercentageValue).b, 148);
EXPECT_EQ(std::get<CSSColor>(alphaPercentageValue).a, 128);
auto alphaSolidusValue = parseCSSProperty<CSSColor>("hwb(208 14% 42% / 0.5)");
EXPECT_TRUE(std::holds_alternative<CSSColor>(alphaSolidusValue));
EXPECT_EQ(std::get<CSSColor>(alphaSolidusValue).r, 36);
EXPECT_EQ(std::get<CSSColor>(alphaSolidusValue).g, 96);
EXPECT_EQ(std::get<CSSColor>(alphaSolidusValue).b, 148);
EXPECT_EQ(std::get<CSSColor>(alphaSolidusValue).a, 128);
auto mixedWhitespaceValue =
parseCSSProperty<CSSColor>(" hwb( 208 14% 42% /0.5 ) ");
EXPECT_TRUE(std::holds_alternative<CSSColor>(mixedWhitespaceValue));
EXPECT_EQ(std::get<CSSColor>(mixedWhitespaceValue).r, 36);
EXPECT_EQ(std::get<CSSColor>(mixedWhitespaceValue).g, 96);
EXPECT_EQ(std::get<CSSColor>(mixedWhitespaceValue).b, 148);
EXPECT_EQ(std::get<CSSColor>(mixedWhitespaceValue).a, 128);
auto extraDegreesValue = parseCSSProperty<CSSColor>("hwb(568 14% 42% / 0.5)");
EXPECT_TRUE(std::holds_alternative<CSSColor>(extraDegreesValue));
EXPECT_EQ(std::get<CSSColor>(extraDegreesValue).r, 36);
EXPECT_EQ(std::get<CSSColor>(extraDegreesValue).g, 96);
EXPECT_EQ(std::get<CSSColor>(extraDegreesValue).b, 148);
EXPECT_EQ(std::get<CSSColor>(extraDegreesValue).a, 128);
auto negativeDegreesValue =
parseCSSProperty<CSSColor>("hwb(-152 14% 42% / 0.5)");
EXPECT_TRUE(std::holds_alternative<CSSColor>(negativeDegreesValue));
EXPECT_EQ(std::get<CSSColor>(negativeDegreesValue).r, 36);
EXPECT_EQ(std::get<CSSColor>(negativeDegreesValue).g, 96);
EXPECT_EQ(std::get<CSSColor>(negativeDegreesValue).b, 148);
EXPECT_EQ(std::get<CSSColor>(negativeDegreesValue).a, 128);
auto missingComponentsValue = parseCSSProperty<CSSColor>("hwb(208 14%)");
EXPECT_TRUE(std::holds_alternative<std::monostate>(missingComponentsValue));
auto tooManyComponentsValue =
parseCSSProperty<CSSColor>("hwb(208 14% 42% 0.5 0.5)");
EXPECT_TRUE(std::holds_alternative<std::monostate>(tooManyComponentsValue));
auto valueStartingWithComma =
parseCSSProperty<CSSColor>("hwb(,208 14% 42% / 0.5)");
EXPECT_TRUE(std::holds_alternative<std::monostate>(valueStartingWithComma));
auto valueEndingWithComma =
parseCSSProperty<CSSColor>("hwb(208 14% 42% / 0.5,)");
EXPECT_TRUE(std::holds_alternative<std::monostate>(valueEndingWithComma));
}
TEST(CSSColor, constexpr_values) {
[[maybe_unused]] constexpr auto emptyValue = parseCSSProperty<CSSColor>("");
[[maybe_unused]] constexpr auto hexColorValue =
parseCSSProperty<CSSColor>("#fff");
[[maybe_unused]] constexpr auto rgbFunctionValue =
parseCSSProperty<CSSColor>("rgb(255, 255, 255)");
}
} // namespace facebook::react

View File

@@ -0,0 +1,577 @@
/*
* Copyright (c) Meta Platforms, Inc. and affiliates.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*/
#include <gtest/gtest.h>
#include <react/renderer/css/CSSFilter.h>
#include <react/renderer/css/CSSValueParser.h>
namespace facebook::react {
TEST(CSSFilter, blur) {
auto value = parseCSSProperty<CSSFilterFunction>("blur(10px)");
EXPECT_TRUE(std::holds_alternative<CSSBlurFilter>(value));
EXPECT_EQ(std::get<CSSBlurFilter>(value).amount.value, 10.0f);
EXPECT_EQ(std::get<CSSBlurFilter>(value).amount.unit, CSSLengthUnit::Px);
}
TEST(CSSFilter, blur_funky) {
auto value = parseCSSProperty<CSSFilterFunction>("bLUr( 10px )");
EXPECT_TRUE(std::holds_alternative<CSSBlurFilter>(value));
EXPECT_EQ(std::get<CSSBlurFilter>(value).amount.value, 10.0f);
EXPECT_EQ(std::get<CSSBlurFilter>(value).amount.unit, CSSLengthUnit::Px);
}
TEST(CSSFilter, blur_default) {
auto value = parseCSSProperty<CSSFilterFunction>("blur()");
EXPECT_TRUE(std::holds_alternative<CSSBlurFilter>(value));
EXPECT_EQ(std::get<CSSBlurFilter>(value).amount.value, 0.0f);
EXPECT_EQ(std::get<CSSBlurFilter>(value).amount.unit, CSSLengthUnit::Px);
}
TEST(CSSFilter, blur_number) {
auto value = parseCSSProperty<CSSFilterFunction>("blur(10)");
EXPECT_TRUE(std::holds_alternative<std::monostate>(value));
}
TEST(CSSFilter, brightness_number) {
auto value = parseCSSProperty<CSSFilterFunction>("brightness(10)");
EXPECT_TRUE(std::holds_alternative<CSSBrightnessFilter>(value));
EXPECT_EQ(std::get<CSSBrightnessFilter>(value).amount, 10.0f);
}
TEST(CSSFilter, brightness_percent) {
auto value = parseCSSProperty<CSSFilterFunction>("brightness(10%)");
EXPECT_TRUE(std::holds_alternative<CSSBrightnessFilter>(value));
EXPECT_EQ(std::get<CSSBrightnessFilter>(value).amount, 0.1f);
}
TEST(CSSFilter, brightness_funky) {
auto value = parseCSSProperty<CSSFilterFunction>("brightneSS( 10% )");
EXPECT_TRUE(std::holds_alternative<CSSBrightnessFilter>(value));
EXPECT_EQ(std::get<CSSBrightnessFilter>(value).amount, 0.1f);
}
TEST(CSSFilter, brightness_default) {
auto value = parseCSSProperty<CSSFilterFunction>("brightness()");
EXPECT_TRUE(std::holds_alternative<CSSBrightnessFilter>(value));
EXPECT_EQ(std::get<CSSBrightnessFilter>(value).amount, 1.0f);
}
TEST(CSSFilter, brightness_negative_number) {
auto value = parseCSSProperty<CSSFilterFunction>("brightness(-10)");
EXPECT_TRUE(std::holds_alternative<std::monostate>(value));
}
TEST(CSSFilter, brightness_negative_percent) {
auto value = parseCSSProperty<CSSFilterFunction>("brightness(-10%)");
EXPECT_TRUE(std::holds_alternative<std::monostate>(value));
}
TEST(CSSFilter, bightness_length) {
auto value = parseCSSProperty<CSSFilterFunction>("brightness(10px)");
EXPECT_TRUE(std::holds_alternative<std::monostate>(value));
}
TEST(CSSFilter, contrast_number) {
auto value = parseCSSProperty<CSSFilterFunction>("contrast(10)");
EXPECT_TRUE(std::holds_alternative<CSSContrastFilter>(value));
EXPECT_EQ(std::get<CSSContrastFilter>(value).amount, 10.0f);
}
TEST(CSSFilter, contrast_percent) {
auto value = parseCSSProperty<CSSFilterFunction>("contrast(10%)");
EXPECT_TRUE(std::holds_alternative<CSSContrastFilter>(value));
EXPECT_EQ(std::get<CSSContrastFilter>(value).amount, 0.1f);
}
TEST(CSSFilter, contrast_funky) {
auto value = parseCSSProperty<CSSFilterFunction>("contrast( 10% )");
EXPECT_TRUE(std::holds_alternative<CSSContrastFilter>(value));
EXPECT_EQ(std::get<CSSContrastFilter>(value).amount, 0.1f);
}
TEST(CSSFilter, contrast_default) {
auto value = parseCSSProperty<CSSFilterFunction>("contrast()");
EXPECT_TRUE(std::holds_alternative<CSSContrastFilter>(value));
EXPECT_EQ(std::get<CSSContrastFilter>(value).amount, 1.0f);
}
TEST(CSSFilter, contrast_negative_number) {
auto value = parseCSSProperty<CSSFilterFunction>("contrast(-10)");
EXPECT_TRUE(std::holds_alternative<std::monostate>(value));
}
TEST(CSSFilter, contrast_negative_percent) {
auto value = parseCSSProperty<CSSFilterFunction>("contrast(-10%)");
EXPECT_TRUE(std::holds_alternative<std::monostate>(value));
}
TEST(CSSFilter, contrast_length) {
auto value = parseCSSProperty<CSSFilterFunction>("contrast(10px)");
EXPECT_TRUE(std::holds_alternative<std::monostate>(value));
}
TEST(CSSFilter, drop_shadow_no_blur) {
auto value = parseCSSProperty<CSSFilterFunction>("drop-shadow(10px 5px)");
EXPECT_TRUE(std::holds_alternative<CSSDropShadowFilter>(value));
EXPECT_EQ(std::get<CSSDropShadowFilter>(value).offsetX.value, 10.0f);
EXPECT_EQ(
std::get<CSSDropShadowFilter>(value).offsetX.unit, CSSLengthUnit::Px);
EXPECT_EQ(std::get<CSSDropShadowFilter>(value).offsetY.value, 5.0f);
EXPECT_EQ(
std::get<CSSDropShadowFilter>(value).offsetY.unit, CSSLengthUnit::Px);
EXPECT_EQ(std::get<CSSDropShadowFilter>(value).standardDeviation.value, 0.0f);
EXPECT_EQ(
std::get<CSSDropShadowFilter>(value).standardDeviation.unit,
CSSLengthUnit::Px);
EXPECT_EQ(std::get<CSSDropShadowFilter>(value).color, CSSColor::black());
}
TEST(CSSFilter, drop_shadow_no_blur_negative_offset) {
auto value = parseCSSProperty<CSSFilterFunction>("drop-shadow(10px -5em)");
EXPECT_TRUE(std::holds_alternative<CSSDropShadowFilter>(value));
EXPECT_EQ(std::get<CSSDropShadowFilter>(value).offsetX.value, 10.0f);
EXPECT_EQ(
std::get<CSSDropShadowFilter>(value).offsetX.unit, CSSLengthUnit::Px);
EXPECT_EQ(std::get<CSSDropShadowFilter>(value).offsetY.value, -5.0f);
EXPECT_EQ(
std::get<CSSDropShadowFilter>(value).offsetY.unit, CSSLengthUnit::Em);
EXPECT_EQ(std::get<CSSDropShadowFilter>(value).standardDeviation.value, 0.0f);
EXPECT_EQ(
std::get<CSSDropShadowFilter>(value).standardDeviation.unit,
CSSLengthUnit::Px);
EXPECT_EQ(std::get<CSSDropShadowFilter>(value).color, CSSColor::black());
}
TEST(CSSFilter, drop_shadow_no_blur_funky) {
auto value = parseCSSProperty<CSSFilterFunction>("drop-Shadow( 10px 5px )");
EXPECT_TRUE(std::holds_alternative<CSSDropShadowFilter>(value));
EXPECT_EQ(std::get<CSSDropShadowFilter>(value).offsetX.value, 10.0f);
EXPECT_EQ(
std::get<CSSDropShadowFilter>(value).offsetX.unit, CSSLengthUnit::Px);
EXPECT_EQ(std::get<CSSDropShadowFilter>(value).offsetY.value, 5.0f);
EXPECT_EQ(
std::get<CSSDropShadowFilter>(value).offsetY.unit, CSSLengthUnit::Px);
EXPECT_EQ(std::get<CSSDropShadowFilter>(value).standardDeviation.value, 0.0f);
EXPECT_EQ(
std::get<CSSDropShadowFilter>(value).standardDeviation.unit,
CSSLengthUnit::Px);
EXPECT_EQ(std::get<CSSDropShadowFilter>(value).color, CSSColor::black());
}
TEST(CSSFilter, drop_shadow_no_blur_pre_color) {
auto value = parseCSSProperty<CSSFilterFunction>("drop-shadow(red 10px 5px)");
EXPECT_TRUE(std::holds_alternative<CSSDropShadowFilter>(value));
EXPECT_EQ(std::get<CSSDropShadowFilter>(value).offsetX.value, 10.0f);
EXPECT_EQ(
std::get<CSSDropShadowFilter>(value).offsetX.unit, CSSLengthUnit::Px);
EXPECT_EQ(std::get<CSSDropShadowFilter>(value).offsetY.value, 5.0f);
EXPECT_EQ(
std::get<CSSDropShadowFilter>(value).offsetY.unit, CSSLengthUnit::Px);
EXPECT_EQ(std::get<CSSDropShadowFilter>(value).standardDeviation.value, 0.0f);
EXPECT_EQ(
std::get<CSSDropShadowFilter>(value).standardDeviation.unit,
CSSLengthUnit::Px);
CSSColor red{.r = 255, .g = 0, .b = 0, .a = 255};
EXPECT_EQ(std::get<CSSDropShadowFilter>(value).color, red);
}
TEST(CSSFilter, drop_shadow_no_blur_post_color) {
auto value =
parseCSSProperty<CSSFilterFunction>("drop-shadow( 10px 5px red )");
EXPECT_TRUE(std::holds_alternative<CSSDropShadowFilter>(value));
EXPECT_EQ(std::get<CSSDropShadowFilter>(value).offsetX.value, 10.0f);
EXPECT_EQ(
std::get<CSSDropShadowFilter>(value).offsetX.unit, CSSLengthUnit::Px);
EXPECT_EQ(std::get<CSSDropShadowFilter>(value).offsetY.value, 5.0f);
EXPECT_EQ(
std::get<CSSDropShadowFilter>(value).offsetY.unit, CSSLengthUnit::Px);
EXPECT_EQ(std::get<CSSDropShadowFilter>(value).standardDeviation.value, 0.0f);
EXPECT_EQ(
std::get<CSSDropShadowFilter>(value).standardDeviation.unit,
CSSLengthUnit::Px);
CSSColor red{.r = 255, .g = 0, .b = 0, .a = 255};
EXPECT_EQ(std::get<CSSDropShadowFilter>(value).color, red);
}
TEST(CSSFilter, drop_shadow_with_blur) {
auto value = parseCSSProperty<CSSFilterFunction>("drop-shadow(10px 5px 3px)");
EXPECT_TRUE(std::holds_alternative<CSSDropShadowFilter>(value));
EXPECT_EQ(std::get<CSSDropShadowFilter>(value).offsetX.value, 10.0f);
EXPECT_EQ(
std::get<CSSDropShadowFilter>(value).offsetX.unit, CSSLengthUnit::Px);
EXPECT_EQ(std::get<CSSDropShadowFilter>(value).offsetY.value, 5.0f);
EXPECT_EQ(
std::get<CSSDropShadowFilter>(value).offsetY.unit, CSSLengthUnit::Px);
EXPECT_EQ(std::get<CSSDropShadowFilter>(value).standardDeviation.value, 3.0f);
EXPECT_EQ(
std::get<CSSDropShadowFilter>(value).standardDeviation.unit,
CSSLengthUnit::Px);
EXPECT_EQ(std::get<CSSDropShadowFilter>(value).color, CSSColor::black());
}
TEST(CSSFilter, drop_shadow_with_blur_pre_color) {
auto value =
parseCSSProperty<CSSFilterFunction>("drop-shadow(red 10px 5px 3px )");
EXPECT_TRUE(std::holds_alternative<CSSDropShadowFilter>(value));
EXPECT_EQ(std::get<CSSDropShadowFilter>(value).offsetX.value, 10.0f);
EXPECT_EQ(
std::get<CSSDropShadowFilter>(value).offsetX.unit, CSSLengthUnit::Px);
EXPECT_EQ(std::get<CSSDropShadowFilter>(value).offsetY.value, 5.0f);
EXPECT_EQ(
std::get<CSSDropShadowFilter>(value).offsetY.unit, CSSLengthUnit::Px);
EXPECT_EQ(std::get<CSSDropShadowFilter>(value).standardDeviation.value, 3.0f);
EXPECT_EQ(
std::get<CSSDropShadowFilter>(value).standardDeviation.unit,
CSSLengthUnit::Px);
CSSColor red{.r = 255, .g = 0, .b = 0, .a = 255};
EXPECT_EQ(std::get<CSSDropShadowFilter>(value).color, red);
}
TEST(CSSFilter, drop_shadow_with_blur_post_color) {
auto value =
parseCSSProperty<CSSFilterFunction>("drop-shadow( 10px 5px 3px red )");
EXPECT_TRUE(std::holds_alternative<CSSDropShadowFilter>(value));
EXPECT_EQ(std::get<CSSDropShadowFilter>(value).offsetX.value, 10.0f);
EXPECT_EQ(
std::get<CSSDropShadowFilter>(value).offsetX.unit, CSSLengthUnit::Px);
EXPECT_EQ(std::get<CSSDropShadowFilter>(value).offsetY.value, 5.0f);
EXPECT_EQ(
std::get<CSSDropShadowFilter>(value).offsetY.unit, CSSLengthUnit::Px);
EXPECT_EQ(std::get<CSSDropShadowFilter>(value).standardDeviation.value, 3.0f);
EXPECT_EQ(
std::get<CSSDropShadowFilter>(value).standardDeviation.unit,
CSSLengthUnit::Px);
CSSColor red{.r = 255, .g = 0, .b = 0, .a = 255};
EXPECT_EQ(std::get<CSSDropShadowFilter>(value).color, red);
}
TEST(CSSFilter, drop_shadow_number_first) {
auto value = parseCSSProperty<CSSFilterFunction>("drop-shadow(10 5px 3px)");
EXPECT_TRUE(std::holds_alternative<std::monostate>(value));
}
TEST(CSSFilter, drop_shadow_with_blur_negative) {
auto value =
parseCSSProperty<CSSFilterFunction>("drop-shadow(10px 5px -3px)");
EXPECT_TRUE(std::holds_alternative<std::monostate>(value));
}
TEST(CSSFilter, drop_shadow_missing_length) {
auto value = parseCSSProperty<CSSFilterFunction>("drop-shadow(10px)");
EXPECT_TRUE(std::holds_alternative<std::monostate>(value));
}
TEST(CSSFilter, drop_shadow_extra_length) {
auto value =
parseCSSProperty<CSSFilterFunction>("drop-shadow(10px 5px 3px 4px)");
EXPECT_TRUE(std::holds_alternative<std::monostate>(value));
}
TEST(CSSFilter, drop_shadow_duplicate_colors) {
auto value =
parseCSSProperty<CSSFilterFunction>("drop-shadow(red 10px 5px red)");
EXPECT_TRUE(std::holds_alternative<std::monostate>(value));
}
TEST(CSSFilter, grayscale_number) {
auto value = parseCSSProperty<CSSFilterFunction>("grayscale(10)");
EXPECT_TRUE(std::holds_alternative<CSSGrayscaleFilter>(value));
EXPECT_EQ(std::get<CSSGrayscaleFilter>(value).amount, 10.0f);
}
TEST(CSSFilter, grayscale_percent) {
auto value = parseCSSProperty<CSSFilterFunction>("grayscale(10%)");
EXPECT_TRUE(std::holds_alternative<CSSGrayscaleFilter>(value));
EXPECT_EQ(std::get<CSSGrayscaleFilter>(value).amount, 0.1f);
}
TEST(CSSFilter, grayscale_funky) {
auto value = parseCSSProperty<CSSFilterFunction>("grayscale( 10% )");
EXPECT_TRUE(std::holds_alternative<CSSGrayscaleFilter>(value));
EXPECT_EQ(std::get<CSSGrayscaleFilter>(value).amount, 0.1f);
}
TEST(CSSFilter, grayscale_default) {
auto value = parseCSSProperty<CSSFilterFunction>("grayscale()");
EXPECT_TRUE(std::holds_alternative<CSSGrayscaleFilter>(value));
EXPECT_EQ(std::get<CSSGrayscaleFilter>(value).amount, 1.0f);
}
TEST(CSSFilter, grayscale_negative_number) {
auto value = parseCSSProperty<CSSFilterFunction>("grayscale(-10)");
EXPECT_TRUE(std::holds_alternative<std::monostate>(value));
}
TEST(CSSFilter, grayscale_negative_percent) {
auto value = parseCSSProperty<CSSFilterFunction>("grayscale(-10%)");
EXPECT_TRUE(std::holds_alternative<std::monostate>(value));
}
TEST(CSSFilter, grayscale_length) {
auto value = parseCSSProperty<CSSFilterFunction>("grayscale(10px)");
EXPECT_TRUE(std::holds_alternative<std::monostate>(value));
}
TEST(CSSFilter, hue_rotate_degrees) {
auto value = parseCSSProperty<CSSFilterFunction>("hue-rotate(10deg)");
EXPECT_TRUE(std::holds_alternative<CSSHueRotateFilter>(value));
EXPECT_EQ(std::get<CSSHueRotateFilter>(value).degrees, 10.0f);
}
TEST(CSSFilter, hue_rotate_turn) {
auto value = parseCSSProperty<CSSFilterFunction>("hue-rotate(0.5turn)");
EXPECT_TRUE(std::holds_alternative<CSSHueRotateFilter>(value));
EXPECT_EQ(std::get<CSSHueRotateFilter>(value).degrees, 180.0f);
}
TEST(CSSFilter, hue_rotate_zero) {
auto value = parseCSSProperty<CSSFilterFunction>("hue-rotate(0)");
EXPECT_TRUE(std::holds_alternative<CSSHueRotateFilter>(value));
EXPECT_EQ(std::get<CSSHueRotateFilter>(value).degrees, 0.0f);
}
TEST(CSSFilter, hue_rotate_negative) {
auto value = parseCSSProperty<CSSFilterFunction>("hue-rotate(-10deg)");
EXPECT_TRUE(std::holds_alternative<CSSHueRotateFilter>(value));
EXPECT_EQ(std::get<CSSHueRotateFilter>(value).degrees, -10.0f);
}
TEST(CSSFilter, hue_rotate_default) {
auto value = parseCSSProperty<CSSFilterFunction>("hue-rotate()");
EXPECT_TRUE(std::holds_alternative<CSSHueRotateFilter>(value));
EXPECT_EQ(std::get<CSSHueRotateFilter>(value).degrees, 0.0f);
}
TEST(CSSFilter, hue_rotate_funky) {
auto value = parseCSSProperty<CSSFilterFunction>("Hue-Rotate( 10deg )");
EXPECT_TRUE(std::holds_alternative<CSSHueRotateFilter>(value));
EXPECT_EQ(std::get<CSSHueRotateFilter>(value).degrees, 10.0f);
}
TEST(CSSFilter, hue_rotate_percent) {
auto value = parseCSSProperty<CSSFilterFunction>("hue-rotate(10%)");
EXPECT_TRUE(std::holds_alternative<std::monostate>(value));
}
TEST(CSSFilter, hue_rotate_number) {
auto value = parseCSSProperty<CSSFilterFunction>("hue-rotate(10)");
EXPECT_TRUE(std::holds_alternative<std::monostate>(value));
}
TEST(CSSFilter, invert_number) {
auto value = parseCSSProperty<CSSFilterFunction>("invert(10)");
EXPECT_TRUE(std::holds_alternative<CSSInvertFilter>(value));
EXPECT_EQ(std::get<CSSInvertFilter>(value).amount, 10.0f);
}
TEST(CSSFilter, invert_percent) {
auto value = parseCSSProperty<CSSFilterFunction>("invert(10%)");
EXPECT_TRUE(std::holds_alternative<CSSInvertFilter>(value));
EXPECT_EQ(std::get<CSSInvertFilter>(value).amount, 0.1f);
}
TEST(CSSFilter, invert_funky) {
auto value = parseCSSProperty<CSSFilterFunction>("inVert( 10% )");
EXPECT_TRUE(std::holds_alternative<CSSInvertFilter>(value));
EXPECT_EQ(std::get<CSSInvertFilter>(value).amount, 0.1f);
}
TEST(CSSFilter, invert_default) {
auto value = parseCSSProperty<CSSFilterFunction>("invert()");
EXPECT_TRUE(std::holds_alternative<CSSInvertFilter>(value));
EXPECT_EQ(std::get<CSSInvertFilter>(value).amount, 1.0f);
}
TEST(CSSFilter, invert_negative_number) {
auto value = parseCSSProperty<CSSFilterFunction>("invert(-10)");
EXPECT_TRUE(std::holds_alternative<std::monostate>(value));
}
TEST(CSSFilter, invert_negative_percent) {
auto value = parseCSSProperty<CSSFilterFunction>("invert(-10%)");
EXPECT_TRUE(std::holds_alternative<std::monostate>(value));
}
TEST(CSSFilter, invert_length) {
auto value = parseCSSProperty<CSSFilterFunction>("invert(10px)");
EXPECT_TRUE(std::holds_alternative<std::monostate>(value));
}
TEST(CSSFilter, opacity_number) {
auto value = parseCSSProperty<CSSFilterFunction>("opacity(10)");
EXPECT_TRUE(std::holds_alternative<CSSOpacityFilter>(value));
EXPECT_EQ(std::get<CSSOpacityFilter>(value).amount, 10.0f);
}
TEST(CSSFilter, opacity_percent) {
auto value = parseCSSProperty<CSSFilterFunction>("opacity(10%)");
EXPECT_TRUE(std::holds_alternative<CSSOpacityFilter>(value));
EXPECT_EQ(std::get<CSSOpacityFilter>(value).amount, 0.1f);
}
TEST(CSSFilter, opacity_funky) {
auto value = parseCSSProperty<CSSFilterFunction>("oPAcity( 10% )");
EXPECT_TRUE(std::holds_alternative<CSSOpacityFilter>(value));
EXPECT_EQ(std::get<CSSOpacityFilter>(value).amount, 0.1f);
}
TEST(CSSFilter, opacity_default) {
auto value = parseCSSProperty<CSSFilterFunction>("opacity()");
EXPECT_TRUE(std::holds_alternative<CSSOpacityFilter>(value));
EXPECT_EQ(std::get<CSSOpacityFilter>(value).amount, 1.0f);
}
TEST(CSSFilter, opacity_negative_number) {
auto value = parseCSSProperty<CSSFilterFunction>("opacity(-10)");
EXPECT_TRUE(std::holds_alternative<std::monostate>(value));
}
TEST(CSSFilter, opacity_negative_percent) {
auto value = parseCSSProperty<CSSFilterFunction>("opacity(-10%)");
EXPECT_TRUE(std::holds_alternative<std::monostate>(value));
}
TEST(CSSFilter, opacity_length) {
auto value = parseCSSProperty<CSSFilterFunction>("opacity(10px)");
EXPECT_TRUE(std::holds_alternative<std::monostate>(value));
}
TEST(CSSFilter, saturate_number) {
auto value = parseCSSProperty<CSSFilterFunction>("saturate(10)");
EXPECT_TRUE(std::holds_alternative<CSSSaturateFilter>(value));
EXPECT_EQ(std::get<CSSSaturateFilter>(value).amount, 10.0f);
}
TEST(CSSFilter, saturate_percent) {
auto value = parseCSSProperty<CSSFilterFunction>("saturate(10%)");
EXPECT_TRUE(std::holds_alternative<CSSSaturateFilter>(value));
EXPECT_EQ(std::get<CSSSaturateFilter>(value).amount, 0.1f);
}
TEST(CSSFilter, saturate_funky) {
auto value = parseCSSProperty<CSSFilterFunction>("saturATE( 10% )");
EXPECT_TRUE(std::holds_alternative<CSSSaturateFilter>(value));
EXPECT_EQ(std::get<CSSSaturateFilter>(value).amount, 0.1f);
}
TEST(CSSFilter, saturate_default) {
auto value = parseCSSProperty<CSSFilterFunction>("saturate()");
EXPECT_TRUE(std::holds_alternative<CSSSaturateFilter>(value));
EXPECT_EQ(std::get<CSSSaturateFilter>(value).amount, 1.0f);
}
TEST(CSSFilter, saturate_negative_number) {
auto value = parseCSSProperty<CSSFilterFunction>("saturate(-10)");
EXPECT_TRUE(std::holds_alternative<std::monostate>(value));
}
TEST(CSSFilter, saturate_negative_percent) {
auto value = parseCSSProperty<CSSFilterFunction>("saturate(-10%)");
EXPECT_TRUE(std::holds_alternative<std::monostate>(value));
}
TEST(CSSFilter, saturate_length) {
auto value = parseCSSProperty<CSSFilterFunction>("saturate(10px)");
EXPECT_TRUE(std::holds_alternative<std::monostate>(value));
}
TEST(CSSFilter, sepia_number) {
auto value = parseCSSProperty<CSSFilterFunction>("sepia(10)");
EXPECT_TRUE(std::holds_alternative<CSSSepiaFilter>(value));
EXPECT_EQ(std::get<CSSSepiaFilter>(value).amount, 10.0f);
}
TEST(CSSFilter, sepia_percent) {
auto value = parseCSSProperty<CSSFilterFunction>("sepia(10%)");
EXPECT_TRUE(std::holds_alternative<CSSSepiaFilter>(value));
EXPECT_EQ(std::get<CSSSepiaFilter>(value).amount, 0.1f);
}
TEST(CSSFilter, sepia_funky) {
auto value = parseCSSProperty<CSSFilterFunction>("sepia( 10% )");
EXPECT_TRUE(std::holds_alternative<CSSSepiaFilter>(value));
EXPECT_EQ(std::get<CSSSepiaFilter>(value).amount, 0.1f);
}
TEST(CSSFilter, sepia_default) {
auto value = parseCSSProperty<CSSFilterFunction>("sepia()");
EXPECT_TRUE(std::holds_alternative<CSSSepiaFilter>(value));
EXPECT_EQ(std::get<CSSSepiaFilter>(value).amount, 1.0f);
}
TEST(CSSFilter, sepia_negative_number) {
auto value = parseCSSProperty<CSSFilterFunction>("sepia(-10)");
EXPECT_TRUE(std::holds_alternative<std::monostate>(value));
}
TEST(CSSFilter, sepia_negative_percent) {
auto value = parseCSSProperty<CSSFilterFunction>("sepia(-10%)");
EXPECT_TRUE(std::holds_alternative<std::monostate>(value));
}
TEST(CSSFilter, sepia_length) {
auto value = parseCSSProperty<CSSFilterFunction>("sepia(10px)");
EXPECT_TRUE(std::holds_alternative<std::monostate>(value));
}
TEST(CSSFilter, filter_list) {
auto value = parseCSSProperty<CSSFilterList>(
"blur(10px) brightness(0.5) drop-shadow(10px 10px 10px red)\t\n drop-shadow(4px -20em)");
EXPECT_TRUE(std::holds_alternative<CSSFilterList>(value));
auto list = std::get<CSSFilterList>(value);
EXPECT_EQ(list.size(), 4);
EXPECT_TRUE(std::holds_alternative<CSSBlurFilter>(list[0]));
EXPECT_EQ(std::get<CSSBlurFilter>(list[0]).amount.value, 10.0f);
EXPECT_EQ(std::get<CSSBlurFilter>(list[0]).amount.unit, CSSLengthUnit::Px);
EXPECT_TRUE(std::holds_alternative<CSSBrightnessFilter>(list[1]));
EXPECT_EQ(std::get<CSSBrightnessFilter>(list[1]).amount, 0.5f);
EXPECT_TRUE(std::holds_alternative<CSSDropShadowFilter>(list[2]));
EXPECT_EQ(std::get<CSSDropShadowFilter>(list[2]).offsetX.value, 10.0f);
EXPECT_EQ(
std::get<CSSDropShadowFilter>(list[2]).offsetX.unit, CSSLengthUnit::Px);
EXPECT_EQ(std::get<CSSDropShadowFilter>(list[2]).offsetY.value, 10.0f);
EXPECT_EQ(
std::get<CSSDropShadowFilter>(list[2]).offsetY.unit, CSSLengthUnit::Px);
EXPECT_EQ(
std::get<CSSDropShadowFilter>(list[2]).standardDeviation.value, 10.0f);
EXPECT_EQ(
std::get<CSSDropShadowFilter>(list[2]).standardDeviation.unit,
CSSLengthUnit::Px);
CSSColor red{.r = 255, .g = 0, .b = 0, .a = 255};
EXPECT_EQ(std::get<CSSDropShadowFilter>(list[2]).color, red);
EXPECT_TRUE(std::holds_alternative<CSSDropShadowFilter>(list[3]));
EXPECT_EQ(std::get<CSSDropShadowFilter>(list[3]).offsetX.value, 4.0f);
EXPECT_EQ(
std::get<CSSDropShadowFilter>(list[3]).offsetX.unit, CSSLengthUnit::Px);
EXPECT_EQ(std::get<CSSDropShadowFilter>(list[3]).offsetY.value, -20.0f);
EXPECT_EQ(
std::get<CSSDropShadowFilter>(list[3]).offsetY.unit, CSSLengthUnit::Em);
EXPECT_EQ(
std::get<CSSDropShadowFilter>(list[3]).standardDeviation.value, 0.0f);
EXPECT_EQ(
std::get<CSSDropShadowFilter>(list[3]).standardDeviation.unit,
CSSLengthUnit::Px);
EXPECT_EQ(std::get<CSSDropShadowFilter>(list[3]).color, CSSColor::black());
}
TEST(CSSFilter, filter_list_commas) {
auto value = parseCSSProperty<CSSFilterList>(
"blur(10px), brightness(0.5), drop-shadow(10px 10px 10px red), drop-shadow(4px -20em)");
EXPECT_TRUE(std::holds_alternative<std::monostate>(value));
}
} // namespace facebook::react

View File

@@ -0,0 +1,76 @@
/*
* Copyright (c) Meta Platforms, Inc. and affiliates.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*/
#include <gtest/gtest.h>
#include <react/renderer/css/CSSFontVariant.h>
#include <react/renderer/css/CSSValueParser.h>
namespace facebook::react {
TEST(CSSFontVariant, single_variant) {
auto commonLigatures = parseCSSProperty<CSSFontVariant>("common-ligatures");
EXPECT_TRUE(std::holds_alternative<CSSFontVariant>(commonLigatures));
EXPECT_EQ(
std::get<CSSFontVariant>(commonLigatures),
CSSFontVariant::CommonLigatures);
auto stylistic15 = parseCSSProperty<CSSFontVariant>("stylistic-fifteen");
EXPECT_TRUE(std::holds_alternative<CSSFontVariant>(stylistic15));
EXPECT_EQ(
std::get<CSSFontVariant>(stylistic15), CSSFontVariant::StylisticFifteen);
auto bogus = parseCSSProperty<CSSFontVariant>("inset");
EXPECT_TRUE(std::holds_alternative<std::monostate>(bogus));
}
TEST(CSSFontVariant, multiple_variants) {
auto commonLigatures =
parseCSSProperty<CSSFontVariantList>("common-ligatures");
EXPECT_TRUE(std::holds_alternative<CSSFontVariantList>(commonLigatures));
EXPECT_EQ(std::get<CSSFontVariantList>(commonLigatures).size(), 1);
EXPECT_EQ(
std::get<CSSFontVariantList>(commonLigatures)[0],
CSSFontVariant::CommonLigatures);
auto commonLigaturesAndHistoricalForms =
parseCSSProperty<CSSFontVariantList>("common-ligatures no-contextual");
EXPECT_TRUE(
std::holds_alternative<CSSFontVariantList>(
commonLigaturesAndHistoricalForms));
EXPECT_EQ(
std::get<CSSFontVariantList>(commonLigaturesAndHistoricalForms).size(),
2);
EXPECT_EQ(
std::get<CSSFontVariantList>(commonLigaturesAndHistoricalForms)[0],
CSSFontVariant::CommonLigatures);
EXPECT_EQ(
std::get<CSSFontVariantList>(commonLigaturesAndHistoricalForms)[1],
CSSFontVariant::NoContextual);
auto lotsOfWhitespace = parseCSSProperty<CSSFontVariantList>(
" no-discretionary-ligatures \n proportional-nums\tstylistic-twelve");
EXPECT_TRUE(std::holds_alternative<CSSFontVariantList>(lotsOfWhitespace));
EXPECT_EQ(std::get<CSSFontVariantList>(lotsOfWhitespace).size(), 3);
EXPECT_EQ(
std::get<CSSFontVariantList>(lotsOfWhitespace)[0],
CSSFontVariant::NoDiscretionaryLigatures);
EXPECT_EQ(
std::get<CSSFontVariantList>(lotsOfWhitespace)[1],
CSSFontVariant::ProportionalNums);
EXPECT_EQ(
std::get<CSSFontVariantList>(lotsOfWhitespace)[2],
CSSFontVariant::StylisticTwelve);
auto bogus = parseCSSProperty<CSSFontVariantList>("inset");
EXPECT_TRUE(std::holds_alternative<std::monostate>(bogus));
auto commaSeparated =
parseCSSProperty<CSSFontVariantList>("common-ligatures, stylistic-six");
EXPECT_TRUE(std::holds_alternative<std::monostate>(commaSeparated));
}
} // namespace facebook::react

View File

@@ -0,0 +1,52 @@
/*
* Copyright (c) Meta Platforms, Inc. and affiliates.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*/
#include <gtest/gtest.h>
#include <react/renderer/css/CSSKeyword.h>
#include <react/renderer/css/CSSValueParser.h>
namespace facebook::react {
TEST(CSSKeyword, keyword_values) {
auto emptyValue = parseCSSProperty<CSSKeyword>("");
EXPECT_TRUE(std::holds_alternative<std::monostate>(emptyValue));
auto inheritValue = parseCSSProperty<>("inherit");
EXPECT_TRUE(std::holds_alternative<CSSWideKeyword>(inheritValue));
EXPECT_EQ(std::get<CSSWideKeyword>(inheritValue), CSSWideKeyword::Inherit);
auto autoValue = parseCSSProperty<CSSKeyword>("auto");
EXPECT_TRUE(std::holds_alternative<CSSKeyword>(autoValue));
EXPECT_EQ(std::get<CSSKeyword>(autoValue), CSSKeyword::Auto);
auto autoCapsValue = parseCSSProperty<CSSKeyword>("AuTO");
EXPECT_TRUE(std::holds_alternative<CSSKeyword>(autoCapsValue));
EXPECT_EQ(std::get<CSSKeyword>(autoCapsValue), CSSKeyword::Auto);
auto autoDisallowedValue = parseCSSProperty<>("auto");
EXPECT_TRUE(std::holds_alternative<std::monostate>(autoDisallowedValue));
auto whitespaceValue = parseCSSProperty<CSSKeyword>(" flex-start ");
EXPECT_TRUE(std::holds_alternative<CSSKeyword>(whitespaceValue));
EXPECT_EQ(std::get<CSSKeyword>(whitespaceValue), CSSKeyword::FlexStart);
auto badIdentValue = parseCSSProperty<CSSKeyword>("bad");
EXPECT_TRUE(std::holds_alternative<std::monostate>(badIdentValue));
auto pxValue = parseCSSProperty<>("20px");
EXPECT_TRUE(std::holds_alternative<std::monostate>(pxValue));
auto multiValue = parseCSSProperty<>("auto flex-start");
EXPECT_TRUE(std::holds_alternative<std::monostate>(multiValue));
}
TEST(CSSKeyword, parse_constexpr) {
[[maybe_unused]] constexpr auto rowValue =
parseCSSProperty<CSSKeyword>("row");
}
} // namespace facebook::react

View File

@@ -0,0 +1,37 @@
/*
* Copyright (c) Meta Platforms, Inc. and affiliates.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*/
#include <gtest/gtest.h>
#include <react/renderer/css/CSSLengthPercentage.h>
#include <react/renderer/css/CSSValueParser.h>
namespace facebook::react {
TEST(CSSLengthPercentage, length_percentage_values) {
auto emptyValue = parseCSSProperty<CSSLengthPercentage>("");
EXPECT_TRUE(std::holds_alternative<std::monostate>(emptyValue));
auto autoValue = parseCSSProperty<CSSKeyword, CSSLengthPercentage>("auto");
EXPECT_TRUE(std::holds_alternative<CSSKeyword>(autoValue));
EXPECT_EQ(std::get<CSSKeyword>(autoValue), CSSKeyword::Auto);
auto autoValueReordered =
parseCSSProperty<CSSLengthPercentage, CSSKeyword>("auto");
EXPECT_TRUE(std::holds_alternative<CSSKeyword>(autoValueReordered));
EXPECT_EQ(std::get<CSSKeyword>(autoValueReordered), CSSKeyword::Auto);
auto pxValue = parseCSSProperty<CSSLengthPercentage>("20px");
EXPECT_TRUE(std::holds_alternative<CSSLength>(pxValue));
EXPECT_EQ(std::get<CSSLength>(pxValue).value, 20.0f);
EXPECT_EQ(std::get<CSSLength>(pxValue).unit, CSSLengthUnit::Px);
auto pctValue = parseCSSProperty<CSSLengthPercentage>("-40%");
EXPECT_TRUE(std::holds_alternative<CSSPercentage>(pctValue));
EXPECT_EQ(std::get<CSSPercentage>(pctValue).value, -40.0f);
}
} // namespace facebook::react

View File

@@ -0,0 +1,58 @@
/*
* Copyright (c) Meta Platforms, Inc. and affiliates.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*/
#include <gtest/gtest.h>
#include <react/renderer/css/CSSLength.h>
#include <react/renderer/css/CSSValueParser.h>
namespace facebook::react {
TEST(CSSLength, length_values) {
auto emptyValue = parseCSSProperty<CSSLength>("");
EXPECT_TRUE(std::holds_alternative<std::monostate>(emptyValue));
auto autoValue = parseCSSProperty<CSSKeyword, CSSLength>("auto");
EXPECT_TRUE(std::holds_alternative<CSSKeyword>(autoValue));
EXPECT_EQ(std::get<CSSKeyword>(autoValue), CSSKeyword::Auto);
auto pxValue = parseCSSProperty<CSSLength>("20px");
EXPECT_TRUE(std::holds_alternative<CSSLength>(pxValue));
EXPECT_EQ(std::get<CSSLength>(pxValue).value, 20.0f);
EXPECT_EQ(std::get<CSSLength>(pxValue).unit, CSSLengthUnit::Px);
auto capsValue = parseCSSProperty<CSSLength>("50PX");
EXPECT_TRUE(std::holds_alternative<CSSLength>(capsValue));
EXPECT_EQ(std::get<CSSLength>(capsValue).value, 50.0f);
EXPECT_EQ(std::get<CSSLength>(capsValue).unit, CSSLengthUnit::Px);
auto cmValue = parseCSSProperty<CSSLength>("453cm");
EXPECT_TRUE(std::holds_alternative<CSSLength>(cmValue));
EXPECT_TRUE(std::get<CSSLength>(cmValue).value == 453.0f);
EXPECT_EQ(std::get<CSSLength>(cmValue).unit, CSSLengthUnit::Cm);
auto unitlessZeroValue = parseCSSProperty<CSSLength>("0");
EXPECT_TRUE(std::holds_alternative<CSSLength>(unitlessZeroValue));
EXPECT_EQ(std::get<CSSLength>(unitlessZeroValue).value, 0.0f);
EXPECT_EQ(std::get<CSSLength>(unitlessZeroValue).unit, CSSLengthUnit::Px);
auto unitlessNonzeroValue = parseCSSProperty<CSSLength>("123");
EXPECT_TRUE(std::holds_alternative<std::monostate>(unitlessNonzeroValue));
auto pctValue = parseCSSProperty<CSSLength>("-40%");
EXPECT_TRUE(std::holds_alternative<std::monostate>(pctValue));
auto negativeValue = parseCSSProperty<CSSLength>("-20em");
EXPECT_TRUE(std::holds_alternative<CSSLength>(negativeValue));
EXPECT_EQ(std::get<CSSLength>(negativeValue).value, -20.0f);
EXPECT_EQ(std::get<CSSLength>(negativeValue).unit, CSSLengthUnit::Em);
}
TEST(CSSLength, parse_constexpr) {
[[maybe_unused]] constexpr auto pxValue = parseCSSProperty<CSSLength>("2px");
}
} // namespace facebook::react

View File

@@ -0,0 +1,157 @@
/*
* Copyright (c) Meta Platforms, Inc. and affiliates.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*/
#include <gtest/gtest.h>
#include <react/renderer/css/CSSCompoundDataType.h>
#include <react/renderer/css/CSSLength.h>
#include <react/renderer/css/CSSList.h>
#include <react/renderer/css/CSSNumber.h>
#include <react/renderer/css/CSSValueParser.h>
namespace facebook::react {
TEST(CSSList, empty_values) {
auto emptyValue = parseCSSProperty<CSSCommaSeparatedList<CSSNumber>>("");
EXPECT_TRUE(std::holds_alternative<std::monostate>(emptyValue));
auto whitespaceValue =
parseCSSProperty<CSSCommaSeparatedList<CSSNumber>>(" ");
EXPECT_TRUE(std::holds_alternative<std::monostate>(whitespaceValue));
auto commaValue = parseCSSProperty<CSSCommaSeparatedList<CSSNumber>>(",");
}
TEST(CSSList, single_value) {
auto simpleValue = parseCSSProperty<CSSCommaSeparatedList<CSSNumber>>("20");
EXPECT_TRUE(
std::holds_alternative<CSSCommaSeparatedList<CSSNumber>>(simpleValue));
EXPECT_EQ(std::get<CSSCommaSeparatedList<CSSNumber>>(simpleValue).size(), 1);
EXPECT_EQ(
std::get<CSSCommaSeparatedList<CSSNumber>>(simpleValue)[0].value, 20);
auto whitespaceValue =
parseCSSProperty<CSSCommaSeparatedList<CSSNumber>>(" 20 ");
EXPECT_TRUE(
std::holds_alternative<CSSCommaSeparatedList<CSSNumber>>(
whitespaceValue));
EXPECT_EQ(
std::get<CSSCommaSeparatedList<CSSNumber>>(whitespaceValue).size(), 1);
EXPECT_EQ(
std::get<CSSCommaSeparatedList<CSSNumber>>(whitespaceValue)[0].value, 20);
}
TEST(CSSList, wrong_type) {
auto simpleValue = parseCSSProperty<CSSCommaSeparatedList<CSSNumber>>("20px");
EXPECT_TRUE(std::holds_alternative<std::monostate>(simpleValue));
}
TEST(CSSList, multiple_comma_values) {
auto simpleValue =
parseCSSProperty<CSSCommaSeparatedList<CSSNumber>>("20, 30, 40");
EXPECT_TRUE(
std::holds_alternative<CSSCommaSeparatedList<CSSNumber>>(simpleValue));
EXPECT_EQ(std::get<CSSCommaSeparatedList<CSSNumber>>(simpleValue).size(), 3);
EXPECT_EQ(
std::get<CSSCommaSeparatedList<CSSNumber>>(simpleValue)[0].value, 20);
EXPECT_EQ(
std::get<CSSCommaSeparatedList<CSSNumber>>(simpleValue)[1].value, 30);
EXPECT_EQ(
std::get<CSSCommaSeparatedList<CSSNumber>>(simpleValue)[2].value, 40);
auto whitespaceValue =
parseCSSProperty<CSSCommaSeparatedList<CSSNumber>>(" 20 , 30 , 40 ");
EXPECT_TRUE(
std::holds_alternative<CSSCommaSeparatedList<CSSNumber>>(
whitespaceValue));
EXPECT_EQ(
std::get<CSSCommaSeparatedList<CSSNumber>>(whitespaceValue).size(), 3);
EXPECT_EQ(
std::get<CSSCommaSeparatedList<CSSNumber>>(whitespaceValue)[0].value, 20);
EXPECT_EQ(
std::get<CSSCommaSeparatedList<CSSNumber>>(whitespaceValue)[1].value, 30);
EXPECT_EQ(
std::get<CSSCommaSeparatedList<CSSNumber>>(whitespaceValue)[2].value, 40);
}
TEST(CSSList, multiple_space_values) {
auto simpleValue =
parseCSSProperty<CSSWhitespaceSeparatedList<CSSNumber>>("20 30 40");
EXPECT_TRUE(
std::holds_alternative<CSSWhitespaceSeparatedList<CSSNumber>>(
simpleValue));
EXPECT_EQ(
std::get<CSSWhitespaceSeparatedList<CSSNumber>>(simpleValue).size(), 3);
EXPECT_EQ(
std::get<CSSWhitespaceSeparatedList<CSSNumber>>(simpleValue)[0].value,
20);
EXPECT_EQ(
std::get<CSSWhitespaceSeparatedList<CSSNumber>>(simpleValue)[1].value,
30);
EXPECT_EQ(
std::get<CSSWhitespaceSeparatedList<CSSNumber>>(simpleValue)[2].value,
40);
auto whitespaceValue =
parseCSSProperty<CSSWhitespaceSeparatedList<CSSNumber>>(" 20 \n 30 40 ");
EXPECT_TRUE(
std::holds_alternative<CSSWhitespaceSeparatedList<CSSNumber>>(
whitespaceValue));
EXPECT_EQ(
std::get<CSSWhitespaceSeparatedList<CSSNumber>>(whitespaceValue).size(),
3);
EXPECT_EQ(
std::get<CSSWhitespaceSeparatedList<CSSNumber>>(whitespaceValue)[0].value,
20);
EXPECT_EQ(
std::get<CSSWhitespaceSeparatedList<CSSNumber>>(whitespaceValue)[1].value,
30);
EXPECT_EQ(
std::get<CSSWhitespaceSeparatedList<CSSNumber>>(whitespaceValue)[2].value,
40);
}
TEST(CSSList, extra_comma_tokens) {
auto extraTokensValue =
parseCSSProperty<CSSCommaSeparatedList<CSSNumber>>("20, 30, 40 50");
EXPECT_TRUE(std::holds_alternative<std::monostate>(extraTokensValue));
}
TEST(CSSList, extra_space_tokens) {
auto extraTokensValue =
parseCSSProperty<CSSWhitespaceSeparatedList<CSSNumber>>("20 30 40 ,50");
EXPECT_TRUE(std::holds_alternative<std::monostate>(extraTokensValue));
}
TEST(CSSList, extra_commas) {
auto prefixCommaValue =
parseCSSProperty<CSSCommaSeparatedList<CSSNumber>>(",20");
EXPECT_TRUE(std::holds_alternative<std::monostate>(prefixCommaValue));
auto suffixCommaValue =
parseCSSProperty<CSSCommaSeparatedList<CSSNumber>>("20,");
EXPECT_TRUE(std::holds_alternative<std::monostate>(suffixCommaValue));
}
TEST(CSSList, compound_data_type) {
using NumberLengthList =
CSSCommaSeparatedList<CSSCompoundDataType<CSSNumber, CSSLength>>;
auto compoundType = parseCSSProperty<NumberLengthList>("10px,20");
EXPECT_TRUE(std::holds_alternative<NumberLengthList>(compoundType));
auto& list = std::get<NumberLengthList>(compoundType);
EXPECT_EQ(list.size(), 2);
EXPECT_TRUE(std::holds_alternative<CSSLength>(list[0]));
EXPECT_EQ(std::get<CSSLength>(list[0]).value, 10);
EXPECT_EQ(std::get<CSSLength>(list[0]).unit, CSSLengthUnit::Px);
EXPECT_TRUE(std::holds_alternative<CSSNumber>(list[1]));
EXPECT_EQ(std::get<CSSNumber>(list[1]).value, 20);
}
} // namespace facebook::react

View File

@@ -0,0 +1,21 @@
/*
* Copyright (c) Meta Platforms, Inc. and affiliates.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*/
#include <gtest/gtest.h>
#include <react/renderer/css/CSSLength.h>
#include <react/renderer/css/CSSNumber.h>
#include <react/renderer/css/CSSValueParser.h>
namespace facebook::react {
TEST(CSSNumberLength, number_length_values) {
auto unitlessZeroValue = parseCSSProperty<CSSNumber, CSSLength>("0");
EXPECT_TRUE(std::holds_alternative<CSSNumber>(unitlessZeroValue));
EXPECT_EQ(std::get<CSSNumber>(unitlessZeroValue).value, 0.0f);
}
} // namespace facebook::react

View File

@@ -0,0 +1,30 @@
/*
* Copyright (c) Meta Platforms, Inc. and affiliates.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*/
#include <gtest/gtest.h>
#include <react/renderer/css/CSSNumber.h>
#include <react/renderer/css/CSSValueParser.h>
namespace facebook::react {
TEST(CSSNumber, number_values) {
auto emptyValue = parseCSSProperty<CSSNumber>("");
EXPECT_TRUE(std::holds_alternative<std::monostate>(emptyValue));
auto pxValue = parseCSSProperty<CSSNumber>("20px");
EXPECT_TRUE(std::holds_alternative<std::monostate>(pxValue));
auto numberValue = parseCSSProperty<CSSNumber>("123.456");
EXPECT_TRUE(std::holds_alternative<CSSNumber>(numberValue));
EXPECT_EQ(std::get<CSSNumber>(numberValue).value, 123.456f);
auto exponentValue = parseCSSProperty<CSSNumber>("-1.5E3");
EXPECT_TRUE(std::holds_alternative<CSSNumber>(exponentValue));
EXPECT_EQ(std::get<CSSNumber>(exponentValue).value, -1.5E3f);
}
} // namespace facebook::react

View File

@@ -0,0 +1,68 @@
/*
* Copyright (c) Meta Platforms, Inc. and affiliates.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*/
#include <gtest/gtest.h>
#include <react/renderer/css/CSSRatio.h>
#include <react/renderer/css/CSSValueParser.h>
namespace facebook::react {
TEST(CSSRatio, ratio_values) {
auto emptyValue = parseCSSProperty<CSSRatio>("");
EXPECT_TRUE(std::holds_alternative<std::monostate>(emptyValue));
auto validRatio = parseCSSProperty<CSSRatio>("16/9");
EXPECT_TRUE(std::holds_alternative<CSSRatio>(validRatio));
EXPECT_EQ(std::get<CSSRatio>(validRatio).numerator, 16.0f);
EXPECT_EQ(std::get<CSSRatio>(validRatio).denominator, 9.0f);
auto validRatioWithWhitespace = parseCSSProperty<CSSRatio>("16 / 9");
EXPECT_TRUE(std::holds_alternative<CSSRatio>(validRatioWithWhitespace));
EXPECT_EQ(std::get<CSSRatio>(validRatioWithWhitespace).numerator, 16.0f);
EXPECT_EQ(std::get<CSSRatio>(validRatioWithWhitespace).denominator, 9.0f);
auto singleNumberRatio = parseCSSProperty<CSSRatio>("16");
EXPECT_TRUE(std::holds_alternative<CSSRatio>(singleNumberRatio));
EXPECT_EQ(std::get<CSSRatio>(singleNumberRatio).numerator, 16.0f);
EXPECT_EQ(std::get<CSSRatio>(singleNumberRatio).denominator, 1.0f);
auto fractionalNumber = parseCSSProperty<CSSRatio>("16.5");
EXPECT_TRUE(std::holds_alternative<CSSRatio>(fractionalNumber));
EXPECT_EQ(std::get<CSSRatio>(fractionalNumber).numerator, 16.5f);
EXPECT_EQ(std::get<CSSRatio>(fractionalNumber).denominator, 1.0f);
auto fractionalNumerator = parseCSSProperty<CSSRatio>("16.5/9");
EXPECT_TRUE(std::holds_alternative<CSSRatio>(fractionalNumerator));
EXPECT_EQ(std::get<CSSRatio>(fractionalNumerator).numerator, 16.5f);
EXPECT_EQ(std::get<CSSRatio>(fractionalNumerator).denominator, 9.0f);
auto fractionalDenominator = parseCSSProperty<CSSRatio>("16/9.5");
EXPECT_TRUE(std::holds_alternative<CSSRatio>(fractionalDenominator));
EXPECT_EQ(std::get<CSSRatio>(fractionalDenominator).numerator, 16.0f);
}
TEST(CSSRatio, invalid_values) {
auto negativeNumber = parseCSSProperty<CSSRatio>("-16");
EXPECT_TRUE(std::holds_alternative<std::monostate>(negativeNumber));
auto missingDenominator = parseCSSProperty<CSSRatio>("16/");
EXPECT_TRUE(std::holds_alternative<std::monostate>(missingDenominator));
auto negativeNumerator = parseCSSProperty<CSSRatio>("-16/9");
EXPECT_TRUE(std::holds_alternative<std::monostate>(negativeNumerator));
auto negativeDenominator = parseCSSProperty<CSSRatio>("16/-9");
EXPECT_TRUE(std::holds_alternative<std::monostate>(negativeDenominator));
}
TEST(CSSRatio, degenerate_values) {
auto degenerateRatio = parseCSSProperty<CSSRatio>("0");
EXPECT_TRUE(std::holds_alternative<CSSRatio>(degenerateRatio));
EXPECT_TRUE(std::get<CSSRatio>(degenerateRatio).isDegenerate());
}
} // namespace facebook::react

View File

@@ -0,0 +1,339 @@
/*
* Copyright (c) Meta Platforms, Inc. and affiliates.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*/
#include <gtest/gtest.h>
#include <react/renderer/css/CSSList.h>
#include <react/renderer/css/CSSShadow.h>
#include <react/renderer/css/CSSValueParser.h>
namespace facebook::react {
TEST(CSSShadow, basic) {
auto value = parseCSSProperty<CSSShadow>("10px 5px");
EXPECT_TRUE(std::holds_alternative<CSSShadow>(value));
auto& shadow = std::get<CSSShadow>(value);
EXPECT_EQ(shadow.offsetX.value, 10.0f);
EXPECT_EQ(shadow.offsetX.unit, CSSLengthUnit::Px);
EXPECT_EQ(shadow.offsetY.value, 5.0f);
EXPECT_EQ(shadow.offsetY.unit, CSSLengthUnit::Px);
EXPECT_EQ(shadow.blurRadius.value, 0.0f);
EXPECT_EQ(shadow.blurRadius.unit, CSSLengthUnit::Px);
EXPECT_EQ(shadow.spreadDistance.value, 0.0f);
EXPECT_EQ(shadow.spreadDistance.unit, CSSLengthUnit::Px);
EXPECT_EQ(shadow.color, CSSColor::black());
EXPECT_FALSE(shadow.inset);
}
TEST(CSSShadow, rem_unit) {
auto value = parseCSSProperty<CSSShadow>("10px 5rem");
EXPECT_TRUE(std::holds_alternative<CSSShadow>(value));
auto& shadow = std::get<CSSShadow>(value);
EXPECT_EQ(shadow.offsetX.value, 10.0f);
EXPECT_EQ(shadow.offsetX.unit, CSSLengthUnit::Px);
EXPECT_EQ(shadow.offsetY.value, 5.0f);
EXPECT_EQ(shadow.offsetY.unit, CSSLengthUnit::Rem);
EXPECT_EQ(shadow.blurRadius.value, 0.0f);
EXPECT_EQ(shadow.blurRadius.unit, CSSLengthUnit::Px);
EXPECT_EQ(shadow.spreadDistance.value, 0.0f);
EXPECT_EQ(shadow.spreadDistance.unit, CSSLengthUnit::Px);
EXPECT_EQ(shadow.color, CSSColor::black());
EXPECT_FALSE(shadow.inset);
}
TEST(CSSShadow, unitless_zero_length) {
auto value = parseCSSProperty<CSSShadow>("10px 0");
EXPECT_TRUE(std::holds_alternative<CSSShadow>(value));
auto& shadow = std::get<CSSShadow>(value);
EXPECT_EQ(shadow.offsetX.value, 10.0f);
EXPECT_EQ(shadow.offsetX.unit, CSSLengthUnit::Px);
EXPECT_EQ(shadow.offsetY.value, 0.0f);
EXPECT_EQ(shadow.offsetY.unit, CSSLengthUnit::Px);
EXPECT_EQ(shadow.blurRadius.value, 0.0f);
EXPECT_EQ(shadow.blurRadius.unit, CSSLengthUnit::Px);
EXPECT_EQ(shadow.spreadDistance.value, 0.0f);
EXPECT_EQ(shadow.spreadDistance.unit, CSSLengthUnit::Px);
EXPECT_EQ(shadow.color, CSSColor::black());
EXPECT_FALSE(shadow.inset);
}
TEST(CSSShadow, multiple_whitespace) {
auto value = parseCSSProperty<CSSShadow>("10px 5px");
EXPECT_TRUE(std::holds_alternative<CSSShadow>(value));
auto& shadow = std::get<CSSShadow>(value);
EXPECT_EQ(shadow.offsetX.value, 10.0f);
EXPECT_EQ(shadow.offsetX.unit, CSSLengthUnit::Px);
EXPECT_EQ(shadow.offsetY.value, 5.0f);
EXPECT_EQ(shadow.offsetY.unit, CSSLengthUnit::Px);
EXPECT_EQ(shadow.blurRadius.value, 0.0f);
EXPECT_EQ(shadow.blurRadius.unit, CSSLengthUnit::Px);
EXPECT_EQ(shadow.spreadDistance.value, 0.0f);
EXPECT_EQ(shadow.spreadDistance.unit, CSSLengthUnit::Px);
EXPECT_EQ(shadow.color, CSSColor::black());
EXPECT_FALSE(shadow.inset);
}
TEST(CSSShadow, trailing_color) {
auto value = parseCSSProperty<CSSShadow>("10px 5px red");
EXPECT_TRUE(std::holds_alternative<CSSShadow>(value));
auto& shadow = std::get<CSSShadow>(value);
EXPECT_EQ(shadow.offsetX.value, 10.0f);
EXPECT_EQ(shadow.offsetX.unit, CSSLengthUnit::Px);
EXPECT_EQ(shadow.offsetY.value, 5.0f);
EXPECT_EQ(shadow.offsetY.unit, CSSLengthUnit::Px);
EXPECT_EQ(shadow.blurRadius.value, 0.0f);
EXPECT_EQ(shadow.blurRadius.unit, CSSLengthUnit::Px);
EXPECT_EQ(shadow.spreadDistance.value, 0.0f);
EXPECT_EQ(shadow.spreadDistance.unit, CSSLengthUnit::Px);
CSSColor red{.r = 255u, .g = 0u, .b = 0u, .a = 255u};
EXPECT_EQ(shadow.color, red);
EXPECT_FALSE(shadow.inset);
}
TEST(CSSShadow, leading_color) {
auto value = parseCSSProperty<CSSShadow>("red 10px 5px");
EXPECT_TRUE(std::holds_alternative<CSSShadow>(value));
auto& shadow = std::get<CSSShadow>(value);
EXPECT_EQ(shadow.offsetX.value, 10.0f);
EXPECT_EQ(shadow.offsetX.unit, CSSLengthUnit::Px);
EXPECT_EQ(shadow.offsetY.value, 5.0f);
EXPECT_EQ(shadow.offsetY.unit, CSSLengthUnit::Px);
EXPECT_EQ(shadow.blurRadius.value, 0.0f);
EXPECT_EQ(shadow.blurRadius.unit, CSSLengthUnit::Px);
EXPECT_EQ(shadow.spreadDistance.value, 0.0f);
EXPECT_EQ(shadow.spreadDistance.unit, CSSLengthUnit::Px);
CSSColor red{.r = 255u, .g = 0u, .b = 0u, .a = 255u};
EXPECT_EQ(shadow.color, red);
EXPECT_FALSE(shadow.inset);
}
TEST(CSSShadow, color_function) {
auto value = parseCSSProperty<CSSShadow>("10px 5px rgba(255, 0, 0, 0.5)");
EXPECT_TRUE(std::holds_alternative<CSSShadow>(value));
auto& shadow = std::get<CSSShadow>(value);
EXPECT_EQ(shadow.offsetX.value, 10.0f);
EXPECT_EQ(shadow.offsetX.unit, CSSLengthUnit::Px);
EXPECT_EQ(shadow.offsetY.value, 5.0f);
EXPECT_EQ(shadow.offsetY.unit, CSSLengthUnit::Px);
EXPECT_EQ(shadow.blurRadius.value, 0.0f);
EXPECT_EQ(shadow.blurRadius.unit, CSSLengthUnit::Px);
EXPECT_EQ(shadow.spreadDistance.value, 0.0f);
EXPECT_EQ(shadow.spreadDistance.unit, CSSLengthUnit::Px);
CSSColor red{.r = 255u, .g = 0u, .b = 0u, .a = 128u};
EXPECT_EQ(shadow.color, red);
EXPECT_FALSE(shadow.inset);
}
TEST(CSSShadow, blur_radius) {
auto value = parseCSSProperty<CSSShadow>("10px 5px 2px");
EXPECT_TRUE(std::holds_alternative<CSSShadow>(value));
auto& shadow = std::get<CSSShadow>(value);
EXPECT_EQ(shadow.offsetX.value, 10.0f);
EXPECT_EQ(shadow.offsetX.unit, CSSLengthUnit::Px);
EXPECT_EQ(shadow.offsetY.value, 5.0f);
EXPECT_EQ(shadow.offsetY.unit, CSSLengthUnit::Px);
EXPECT_EQ(shadow.blurRadius.value, 2.0f);
EXPECT_EQ(shadow.blurRadius.unit, CSSLengthUnit::Px);
EXPECT_EQ(shadow.spreadDistance.value, 0.0f);
EXPECT_EQ(shadow.spreadDistance.unit, CSSLengthUnit::Px);
EXPECT_EQ(shadow.color, CSSColor::black());
EXPECT_FALSE(shadow.inset);
}
TEST(CSSShadow, spread_distance) {
auto value = parseCSSProperty<CSSShadow>("10px 5px 2px 3px");
EXPECT_TRUE(std::holds_alternative<CSSShadow>(value));
auto& shadow = std::get<CSSShadow>(value);
EXPECT_EQ(shadow.offsetX.value, 10.0f);
EXPECT_EQ(shadow.offsetX.unit, CSSLengthUnit::Px);
EXPECT_EQ(shadow.offsetY.value, 5.0f);
EXPECT_EQ(shadow.offsetY.unit, CSSLengthUnit::Px);
EXPECT_EQ(shadow.blurRadius.value, 2.0f);
EXPECT_EQ(shadow.blurRadius.unit, CSSLengthUnit::Px);
EXPECT_EQ(shadow.spreadDistance.value, 3.0f);
EXPECT_EQ(shadow.spreadDistance.unit, CSSLengthUnit::Px);
EXPECT_EQ(shadow.color, CSSColor::black());
EXPECT_FALSE(shadow.inset);
}
TEST(CSSShadow, inset) {
auto value = parseCSSProperty<CSSShadow>("5px 2px inset");
EXPECT_TRUE(std::holds_alternative<CSSShadow>(value));
auto& shadow = std::get<CSSShadow>(value);
EXPECT_EQ(shadow.offsetX.value, 5.0f);
EXPECT_EQ(shadow.offsetX.unit, CSSLengthUnit::Px);
EXPECT_EQ(shadow.offsetY.value, 2.0f);
EXPECT_EQ(shadow.offsetY.unit, CSSLengthUnit::Px);
EXPECT_EQ(shadow.blurRadius.value, 0.0f);
EXPECT_EQ(shadow.blurRadius.unit, CSSLengthUnit::Px);
EXPECT_EQ(shadow.spreadDistance.value, 0.0f);
EXPECT_EQ(shadow.spreadDistance.unit, CSSLengthUnit::Px);
EXPECT_EQ(shadow.color, CSSColor::black());
EXPECT_TRUE(shadow.inset);
}
TEST(CSShadow, color_length_inset) {
auto value = parseCSSProperty<CSSShadow>("red 10px 10px inset");
EXPECT_TRUE(std::holds_alternative<CSSShadow>(value));
auto& shadow = std::get<CSSShadow>(value);
EXPECT_EQ(shadow.offsetX.value, 10.0f);
EXPECT_EQ(shadow.offsetX.unit, CSSLengthUnit::Px);
EXPECT_EQ(shadow.offsetY.value, 10.0f);
EXPECT_EQ(shadow.offsetY.unit, CSSLengthUnit::Px);
EXPECT_EQ(shadow.blurRadius.value, 0.0f);
EXPECT_EQ(shadow.blurRadius.unit, CSSLengthUnit::Px);
EXPECT_EQ(shadow.spreadDistance.value, 0.0f);
EXPECT_EQ(shadow.spreadDistance.unit, CSSLengthUnit::Px);
CSSColor red{.r = 255u, .g = 0u, .b = 0u, .a = 255u};
EXPECT_EQ(shadow.color, red);
EXPECT_TRUE(shadow.inset);
}
TEST(CSSShadow, multiple_shadows) {
auto value = parseCSSProperty<CSSShadowList>(
"10px 5px red, 5px 12px inset, inset 10px 45px 13px red");
EXPECT_TRUE(std::holds_alternative<CSSShadowList>(value));
auto& shadows = std::get<CSSShadowList>(value);
EXPECT_EQ(shadows.size(), 3);
EXPECT_EQ(shadows[0].offsetX.value, 10.0f);
EXPECT_EQ(shadows[0].offsetX.unit, CSSLengthUnit::Px);
EXPECT_EQ(shadows[0].offsetY.value, 5.0f);
EXPECT_EQ(shadows[0].offsetY.unit, CSSLengthUnit::Px);
EXPECT_EQ(shadows[0].blurRadius.value, 0.0f);
EXPECT_EQ(shadows[0].blurRadius.unit, CSSLengthUnit::Px);
EXPECT_EQ(shadows[0].spreadDistance.value, 0.0f);
EXPECT_EQ(shadows[0].spreadDistance.unit, CSSLengthUnit::Px);
CSSColor red{.r = 255u, .g = 0u, .b = 0u, .a = 255u};
EXPECT_EQ(shadows[0].color, red);
EXPECT_FALSE(shadows[0].inset);
EXPECT_EQ(shadows[1].offsetX.value, 5.0f);
EXPECT_EQ(shadows[1].offsetX.unit, CSSLengthUnit::Px);
EXPECT_EQ(shadows[1].offsetY.value, 12.0f);
EXPECT_EQ(shadows[1].offsetY.unit, CSSLengthUnit::Px);
EXPECT_EQ(shadows[1].blurRadius.value, 0.0f);
EXPECT_EQ(shadows[1].blurRadius.unit, CSSLengthUnit::Px);
EXPECT_EQ(shadows[1].spreadDistance.value, 0.0f);
EXPECT_EQ(shadows[1].spreadDistance.unit, CSSLengthUnit::Px);
EXPECT_EQ(shadows[1].color, CSSColor::black());
EXPECT_TRUE(shadows[1].inset);
EXPECT_EQ(shadows[2].offsetX.value, 10.0f);
EXPECT_EQ(shadows[2].offsetX.unit, CSSLengthUnit::Px);
EXPECT_EQ(shadows[2].offsetY.value, 45.0f);
EXPECT_EQ(shadows[2].offsetY.unit, CSSLengthUnit::Px);
EXPECT_EQ(shadows[2].blurRadius.value, 13.0f);
EXPECT_EQ(shadows[2].blurRadius.unit, CSSLengthUnit::Px);
EXPECT_EQ(shadows[2].spreadDistance.value, 0.0f);
EXPECT_EQ(shadows[2].spreadDistance.unit, CSSLengthUnit::Px);
EXPECT_EQ(shadows[2].color, red);
EXPECT_TRUE(shadows[2].inset);
}
TEST(CSSShadow, multiple_shadows_with_new_line) {
auto value = parseCSSProperty<CSSShadowList>(
"10px 5px red, \n5px 12px inset,\n inset 10px 45px 13px red");
EXPECT_TRUE(std::holds_alternative<CSSShadowList>(value));
auto& shadows = std::get<CSSShadowList>(value);
EXPECT_EQ(shadows.size(), 3);
EXPECT_EQ(shadows[0].offsetX.value, 10.0f);
EXPECT_EQ(shadows[0].offsetX.unit, CSSLengthUnit::Px);
EXPECT_EQ(shadows[0].offsetY.value, 5.0f);
EXPECT_EQ(shadows[0].offsetY.unit, CSSLengthUnit::Px);
EXPECT_EQ(shadows[0].blurRadius.value, 0.0f);
EXPECT_EQ(shadows[0].blurRadius.unit, CSSLengthUnit::Px);
EXPECT_EQ(shadows[0].spreadDistance.value, 0.0f);
EXPECT_EQ(shadows[0].spreadDistance.unit, CSSLengthUnit::Px);
CSSColor red{.r = 255u, .g = 0u, .b = 0u, .a = 255u};
EXPECT_EQ(shadows[0].color, red);
EXPECT_FALSE(shadows[0].inset);
EXPECT_EQ(shadows[1].offsetX.value, 5.0f);
EXPECT_EQ(shadows[1].offsetX.unit, CSSLengthUnit::Px);
EXPECT_EQ(shadows[1].offsetY.value, 12.0f);
EXPECT_EQ(shadows[1].offsetY.unit, CSSLengthUnit::Px);
EXPECT_EQ(shadows[1].blurRadius.value, 0.0f);
EXPECT_EQ(shadows[1].blurRadius.unit, CSSLengthUnit::Px);
EXPECT_EQ(shadows[1].spreadDistance.value, 0.0f);
EXPECT_EQ(shadows[1].spreadDistance.unit, CSSLengthUnit::Px);
EXPECT_EQ(shadows[1].color, CSSColor::black());
EXPECT_TRUE(shadows[1].inset);
EXPECT_EQ(shadows[2].offsetX.value, 10.0f);
EXPECT_EQ(shadows[2].offsetX.unit, CSSLengthUnit::Px);
EXPECT_EQ(shadows[2].offsetY.value, 45.0f);
EXPECT_EQ(shadows[2].offsetY.unit, CSSLengthUnit::Px);
EXPECT_EQ(shadows[2].blurRadius.value, 13.0f);
EXPECT_EQ(shadows[2].blurRadius.unit, CSSLengthUnit::Px);
EXPECT_EQ(shadows[2].spreadDistance.value, 0.0f);
EXPECT_EQ(shadows[2].spreadDistance.unit, CSSLengthUnit::Px);
EXPECT_EQ(shadows[2].color, red);
EXPECT_TRUE(shadows[2].inset);
}
TEST(CSSShadow, invalid_units) {
auto value = parseCSSProperty<CSSShadow>("red 10em 5$ 2| 3rp");
EXPECT_TRUE(std::holds_alternative<std::monostate>(value));
}
TEST(CSSShadow, too_many_lengths) {
auto value = parseCSSProperty<CSSShadow>("10px 5px 2px 3px 10px 10px");
EXPECT_TRUE(std::holds_alternative<std::monostate>(value));
}
TEST(CSSShadow, too_many_lengths_as_part_of_multiple) {
auto value =
parseCSSProperty<CSSShadowList>("10px 5px 2px 3px 10px 10px, 10px 5px");
EXPECT_TRUE(std::holds_alternative<std::monostate>(value));
}
TEST(CSSShadow, inset_between_lengths) {
auto value = parseCSSProperty<CSSShadow>("10px inset 5px");
EXPECT_TRUE(std::holds_alternative<std::monostate>(value));
}
TEST(CSSShadow, color_between_lengths) {
auto value = parseCSSProperty<CSSShadow>("10px blue 5px");
EXPECT_TRUE(std::holds_alternative<std::monostate>(value));
}
TEST(CSSShadow, invalid_keyword) {
auto value = parseCSSProperty<CSSShadow>("10px 5px outset");
EXPECT_TRUE(std::holds_alternative<std::monostate>(value));
}
TEST(CSSShadow, negative_blur) {
auto value = parseCSSProperty<CSSShadow>("red 5px 2px -3px");
EXPECT_TRUE(std::holds_alternative<std::monostate>(value));
}
TEST(CSSShadow, missing_unit) {
auto value = parseCSSProperty<CSSShadow>("10px 5");
EXPECT_TRUE(std::holds_alternative<std::monostate>(value));
}
} // namespace facebook::react

View File

@@ -0,0 +1,564 @@
/*
* Copyright (c) Meta Platforms, Inc. and affiliates.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*/
#include <gtest/gtest.h>
#include <react/renderer/css/CSSSyntaxParser.h>
namespace facebook::react {
TEST(CSSSyntaxParser, simple) {
CSSSyntaxParser parser{"1px solid black"};
auto pxValue = parser.consumeComponentValue<float>(
CSSDelimiter::OptionalWhitespace, [](const CSSPreservedToken& token) {
EXPECT_EQ(token.type(), CSSTokenType::Dimension);
EXPECT_EQ(token.numericValue(), 1.0f);
EXPECT_EQ(token.unit(), "px");
return token.numericValue();
});
EXPECT_EQ(pxValue, 1.0f);
auto identValue = parser.consumeComponentValue<std::string_view>(
CSSDelimiter::OptionalWhitespace, [](const CSSPreservedToken& token) {
EXPECT_EQ(token.type(), CSSTokenType::Ident);
EXPECT_EQ(token.stringValue(), "solid");
return token.stringValue();
});
EXPECT_EQ(identValue, "solid");
auto identValue2 = parser.consumeComponentValue<std::string_view>(
CSSDelimiter::OptionalWhitespace, [](const CSSPreservedToken& token) {
EXPECT_EQ(token.type(), CSSTokenType::Ident);
EXPECT_EQ(token.stringValue(), "black");
return token.stringValue();
});
EXPECT_EQ(identValue2, "black");
}
TEST(CSSSyntaxParser, single_function_no_args) {
CSSSyntaxParser parser{"foo()"};
auto funcName = parser.consumeComponentValue<std::string_view>(
[](const CSSFunctionBlock& function, CSSSyntaxParser& blockParser) {
EXPECT_EQ(function.name, "foo");
return function.name;
auto hasMoreTokens = blockParser.consumeComponentValue<bool>(
[](const CSSPreservedToken& /*token*/) { return true; });
EXPECT_FALSE(hasMoreTokens);
});
EXPECT_EQ(funcName, "foo");
}
TEST(CSSSyntaxParser, single_function_with_whitespace_delimited_args) {
CSSSyntaxParser parser{"foo( a b c)"};
auto funcArgs = parser.consumeComponentValue<std::vector<std::string>>(
[&](const CSSFunctionBlock& function, CSSSyntaxParser& blockParser) {
EXPECT_EQ(function.name, "foo");
std::vector<std::string> args;
args.emplace_back(blockParser.consumeComponentValue<std::string_view>(
CSSDelimiter::OptionalWhitespace,
[](const CSSPreservedToken& token) {
EXPECT_EQ(token.type(), CSSTokenType::Ident);
EXPECT_EQ(token.stringValue(), "a");
return token.stringValue();
}));
args.emplace_back(blockParser.consumeComponentValue<std::string_view>(
CSSDelimiter::Whitespace,
[](const CSSPreservedToken& token) {
EXPECT_EQ(token.type(), CSSTokenType::Ident);
EXPECT_EQ(token.stringValue(), "b");
return token.stringValue();
}));
args.emplace_back(blockParser.consumeComponentValue<std::string_view>(
CSSDelimiter::Whitespace,
[](const CSSPreservedToken& token) {
EXPECT_EQ(token.type(), CSSTokenType::Ident);
EXPECT_EQ(token.stringValue(), "c");
return token.stringValue();
}));
auto hasMoreTokens = blockParser.consumeComponentValue<bool>(
CSSDelimiter::Whitespace,
[](const CSSPreservedToken& /*token*/) { return true; });
EXPECT_FALSE(hasMoreTokens);
return args;
});
std::vector<std::string> expectedArgs{"a", "b", "c"};
EXPECT_EQ(funcArgs, expectedArgs);
}
TEST(CSSSyntaxParser, single_function_with_comma_delimited_args) {
CSSSyntaxParser parser{"rgb(100, 200, 50 )"};
auto funcArgs = parser.consumeComponentValue<std::array<uint8_t, 3>>(
[&](const CSSFunctionBlock& function, CSSSyntaxParser& blockParser) {
EXPECT_EQ(function.name, "rgb");
std::array<uint8_t, 3> rgb{};
rgb[0] = blockParser.consumeComponentValue<uint8_t>(
CSSDelimiter::OptionalWhitespace,
[](const CSSPreservedToken& token) {
EXPECT_EQ(token.type(), CSSTokenType::Number);
EXPECT_EQ(token.numericValue(), 100);
return static_cast<uint8_t>(token.numericValue());
});
rgb[1] = blockParser.consumeComponentValue<uint8_t>(
CSSDelimiter::Comma, [](const CSSPreservedToken& token) {
EXPECT_EQ(token.type(), CSSTokenType::Number);
EXPECT_EQ(token.numericValue(), 200);
return static_cast<uint8_t>(token.numericValue());
});
rgb[2] = blockParser.consumeComponentValue<uint8_t>(
CSSDelimiter::Comma, [](const CSSPreservedToken& token) {
EXPECT_EQ(token.type(), CSSTokenType::Number);
EXPECT_EQ(token.numericValue(), 50);
return static_cast<uint8_t>(token.numericValue());
});
auto hasMoreTokens = blockParser.consumeComponentValue<bool>(
CSSDelimiter::Whitespace,
[](const CSSPreservedToken& /*token*/) { return true; });
EXPECT_FALSE(hasMoreTokens);
return rgb;
});
std::array<uint8_t, 3> expectedArgs{{100, 200, 50}};
EXPECT_EQ(funcArgs, expectedArgs);
}
TEST(CSSSyntaxParser, single_function_with_mixed_delimited_args) {
CSSSyntaxParser parser{"rgb(100, 200 50 )"};
auto funcArgs = parser.consumeComponentValue<std::array<uint8_t, 3>>(
[&](const CSSFunctionBlock& function, CSSSyntaxParser& blockParser) {
EXPECT_EQ(function.name, "rgb");
std::array<uint8_t, 3> rgb{};
rgb[0] = blockParser.consumeComponentValue<uint8_t>(
CSSDelimiter::None, [](const CSSPreservedToken& token) {
EXPECT_EQ(token.type(), CSSTokenType::Number);
EXPECT_EQ(token.numericValue(), 100);
return static_cast<uint8_t>(token.numericValue());
});
rgb[1] = blockParser.consumeComponentValue<uint8_t>(
CSSDelimiter::CommaOrWhitespace,
[](const CSSPreservedToken& token) {
EXPECT_EQ(token.type(), CSSTokenType::Number);
EXPECT_EQ(token.numericValue(), 200);
return static_cast<uint8_t>(token.numericValue());
});
rgb[2] = blockParser.consumeComponentValue<uint8_t>(
CSSDelimiter::CommaOrWhitespace,
[](const CSSPreservedToken& token) {
EXPECT_EQ(token.type(), CSSTokenType::Number);
EXPECT_EQ(token.numericValue(), 50);
return static_cast<uint8_t>(token.numericValue());
});
auto hasMoreTokens = blockParser.consumeComponentValue<bool>(
CSSDelimiter::Whitespace,
[](const CSSPreservedToken& /*token*/) { return true; });
EXPECT_FALSE(hasMoreTokens);
return rgb;
});
std::array<uint8_t, 3> expectedArgs{{100, 200, 50}};
EXPECT_EQ(funcArgs, expectedArgs);
}
TEST(CSSSyntaxParser, complex) {
CSSSyntaxParser parser{"foo(a bar())baz() 12px"};
auto fooFunc = parser.consumeComponentValue<std::string_view>(
[&](const CSSFunctionBlock& function, CSSSyntaxParser& blockParser) {
EXPECT_EQ(function.name, "foo");
auto identArg = blockParser.consumeComponentValue<std::string_view>(
CSSDelimiter::OptionalWhitespace,
[](const CSSPreservedToken& token) {
EXPECT_EQ(token.type(), CSSTokenType::Ident);
EXPECT_EQ(token.stringValue(), "a");
return token.stringValue();
});
EXPECT_EQ(identArg, "a");
auto barFunc = blockParser.consumeComponentValue<std::string_view>(
CSSDelimiter::Whitespace,
[&](const CSSFunctionBlock& function,
CSSSyntaxParser& nestedBlockParser) {
EXPECT_EQ(function.name, "bar");
auto hasMoreTokens =
nestedBlockParser.consumeComponentValue<bool>(
CSSDelimiter::Whitespace,
[](const CSSPreservedToken& /*token*/) { return true; });
EXPECT_FALSE(hasMoreTokens);
return function.name;
});
EXPECT_EQ(barFunc, "bar");
auto hasMoreTokens = blockParser.consumeComponentValue<bool>(
CSSDelimiter::Whitespace,
[](const CSSPreservedToken& /*token*/) { return true; });
EXPECT_FALSE(hasMoreTokens);
return function.name;
});
EXPECT_EQ(fooFunc, "foo");
auto bazFunc = parser.consumeComponentValue<std::string_view>(
[&](const CSSFunctionBlock& function, CSSSyntaxParser& /*blockParser*/) {
EXPECT_EQ(function.name, "baz");
return function.name;
});
EXPECT_EQ(bazFunc, "baz");
auto pxValue = parser.consumeComponentValue<float>(
CSSDelimiter::Whitespace, [](const CSSPreservedToken& token) {
EXPECT_EQ(token.type(), CSSTokenType::Dimension);
EXPECT_EQ(token.numericValue(), 12.0f);
EXPECT_EQ(token.unit(), "px");
return token.numericValue();
});
EXPECT_EQ(pxValue, 12.0f);
}
TEST(CSSSyntaxParser, unterminated_functions) {
EXPECT_FALSE(
CSSSyntaxParser{"foo("}.consumeComponentValue<bool>(
[](const CSSFunctionBlock&, CSSSyntaxParser& /*blockParser*/) {
return true;
}));
EXPECT_FALSE(
CSSSyntaxParser{"foo(a bar()baz()"}.consumeComponentValue<bool>(
[](const CSSFunctionBlock&, CSSSyntaxParser& /*blockParser*/) {
return true;
}));
}
TEST(CSSSyntaxParser, simple_blocks) {
CSSSyntaxParser parser1{"(a)"};
auto identValue = parser1.consumeComponentValue<std::string_view>(
[&](const CSSSimpleBlock& block, CSSSyntaxParser& blockParser) {
EXPECT_EQ(block.openBracketType, CSSTokenType::OpenParen);
return blockParser.consumeComponentValue<std::string_view>(
[](const CSSPreservedToken& token) {
EXPECT_EQ(token.type(), CSSTokenType::Ident);
return token.stringValue();
});
});
EXPECT_EQ(identValue, "a");
CSSSyntaxParser parser2{"[b ]"};
auto identValue2 = parser2.consumeComponentValue<std::string_view>(
[&](const CSSSimpleBlock& block, CSSSyntaxParser& blockParser) {
EXPECT_EQ(block.openBracketType, CSSTokenType::OpenSquare);
return blockParser.consumeComponentValue<std::string_view>(
[](const CSSPreservedToken& token) {
EXPECT_EQ(token.type(), CSSTokenType::Ident);
return token.stringValue();
});
});
EXPECT_EQ(identValue2, "b");
CSSSyntaxParser parser3{"{c}"};
auto identValue3 = parser3.consumeComponentValue<std::string_view>(
[&](const CSSSimpleBlock& block, CSSSyntaxParser& blockParser) {
EXPECT_EQ(block.openBracketType, CSSTokenType::OpenCurly);
return blockParser.consumeComponentValue<std::string_view>(
[](const CSSPreservedToken& token) {
EXPECT_EQ(token.type(), CSSTokenType::Ident);
return token.stringValue();
});
});
EXPECT_EQ(identValue3, "c");
}
TEST(CSSSyntaxParser, unterminated_simple_blocks) {
CSSSyntaxParser parser1{"(a"};
auto identValue = parser1.consumeComponentValue<std::string_view>(
[&](const CSSSimpleBlock& block, CSSSyntaxParser& blockParser) {
EXPECT_EQ(block.openBracketType, CSSTokenType::OpenParen);
return blockParser.consumeComponentValue<std::string_view>(
[](const CSSPreservedToken& token) {
EXPECT_EQ(token.type(), CSSTokenType::Ident);
return token.stringValue();
});
});
EXPECT_EQ(identValue, "");
CSSSyntaxParser parser2{"[b "};
auto identValue2 = parser2.consumeComponentValue<std::string_view>(
[&](const CSSSimpleBlock& block, CSSSyntaxParser& blockParser) {
EXPECT_EQ(block.openBracketType, CSSTokenType::OpenSquare);
return blockParser.consumeComponentValue<std::string_view>(
[](const CSSPreservedToken& token) {
EXPECT_EQ(token.type(), CSSTokenType::Ident);
return token.stringValue();
});
});
EXPECT_EQ(identValue2, "");
CSSSyntaxParser parser3{"{c"};
auto identValue3 = parser3.consumeComponentValue<std::string_view>(
[&](const CSSSimpleBlock& block, CSSSyntaxParser& blockParser) {
EXPECT_EQ(block.openBracketType, CSSTokenType::OpenCurly);
return blockParser.consumeComponentValue<std::string_view>(
[](const CSSPreservedToken& token) {
EXPECT_EQ(token.type(), CSSTokenType::Ident);
return token.stringValue();
});
});
EXPECT_EQ(identValue3, "");
}
TEST(CSSSyntaxParser, unconsumed_function_args) {
CSSSyntaxParser parser{"foo(a)"};
auto funcValue =
parser.consumeComponentValue<std::optional<std::string_view>>(
[&](const CSSFunctionBlock& function,
CSSSyntaxParser& /*blockParser*/) {
EXPECT_EQ(function.name, "foo");
return function.name;
});
EXPECT_EQ(funcValue, std::nullopt);
}
TEST(CSSSyntaxParser, whitespace_surrounding_function_args) {
CSSSyntaxParser parser{"foo( a )"};
auto funcValue = parser.consumeComponentValue<std::string_view>(
[&](const CSSFunctionBlock& function, CSSSyntaxParser& blockParser) {
EXPECT_EQ(function.name, "foo");
auto identArg = blockParser.consumeComponentValue<std::string_view>(
CSSDelimiter::None, [](const CSSPreservedToken& token) {
EXPECT_EQ(token.type(), CSSTokenType::Ident);
EXPECT_EQ(token.stringValue(), "a");
return token.stringValue();
});
EXPECT_EQ(identArg, "a");
return function.name;
});
EXPECT_EQ(funcValue, "foo");
}
TEST(CSSSyntaxParser, unconsumed_simple_block_args) {
CSSSyntaxParser parser{"{a}"};
auto funcValue = parser.consumeComponentValue<std::optional<CSSTokenType>>(
[&](const CSSSimpleBlock& block, CSSSyntaxParser& /*blockParser*/) {
EXPECT_EQ(block.openBracketType, CSSTokenType::OpenCurly);
return block.openBracketType;
});
EXPECT_EQ(funcValue, std::nullopt);
}
TEST(CSSSyntaxParser, solidus_delimiter) {
CSSSyntaxParser parser{"foo / bar"};
auto identValue = parser.consumeComponentValue<std::string_view>(
[](const CSSPreservedToken& token) {
EXPECT_EQ(token.type(), CSSTokenType::Ident);
EXPECT_EQ(token.stringValue(), "foo");
return token.stringValue();
});
EXPECT_EQ(identValue, "foo");
auto identValue2 = parser.consumeComponentValue<std::string_view>(
CSSDelimiter::Solidus, [](const CSSPreservedToken& token) {
EXPECT_EQ(token.type(), CSSTokenType::Ident);
EXPECT_EQ(token.stringValue(), "bar");
return token.stringValue();
});
EXPECT_EQ(identValue2, "bar");
}
TEST(CSSSyntaxParser, solidus_delimiter_not_present) {
CSSSyntaxParser parser{"foo bar"};
auto identValue = parser.consumeComponentValue<std::string_view>(
[](const CSSPreservedToken& token) {
EXPECT_EQ(token.type(), CSSTokenType::Ident);
EXPECT_EQ(token.stringValue(), "foo");
return token.stringValue();
});
EXPECT_EQ(identValue, "foo");
auto identValue2 = parser.consumeComponentValue<bool>(
CSSDelimiter::Solidus,
[](const CSSPreservedToken& /*token*/) { return true; });
EXPECT_FALSE(identValue2);
}
TEST(CSSSyntaxParser, required_whitespace_not_present) {
CSSSyntaxParser parser{"foo/"};
auto identValue = parser.consumeComponentValue<std::string_view>(
[](const CSSPreservedToken& token) {
EXPECT_EQ(token.type(), CSSTokenType::Ident);
EXPECT_EQ(token.stringValue(), "foo");
return token.stringValue();
});
EXPECT_EQ(identValue, "foo");
auto delimValue1 = parser.consumeComponentValue<bool>(
CSSDelimiter::Whitespace,
[](const CSSPreservedToken& /*token*/) { return true; });
EXPECT_FALSE(delimValue1);
auto delimValue2 = parser.consumeComponentValue<std::string_view>(
CSSDelimiter::OptionalWhitespace, [](const CSSPreservedToken& token) {
EXPECT_EQ(token.type(), CSSTokenType::Delim);
EXPECT_EQ(token.stringValue(), "/");
return token.stringValue();
});
EXPECT_EQ(delimValue2, "/");
}
TEST(CSSSyntaxParser, solidus_or_whitespace) {
CSSSyntaxParser parser{"foo bar / baz potato, papaya"};
auto identValue1 = parser.consumeComponentValue<std::string_view>(
CSSDelimiter::OptionalWhitespace, [](const CSSPreservedToken& token) {
EXPECT_EQ(token.type(), CSSTokenType::Ident);
EXPECT_EQ(token.stringValue(), "foo");
return token.stringValue();
});
EXPECT_EQ(identValue1, "foo");
auto identValue2 = parser.consumeComponentValue<std::string_view>(
CSSDelimiter::SolidusOrWhitespace, [](const CSSPreservedToken& token) {
EXPECT_EQ(token.type(), CSSTokenType::Ident);
EXPECT_EQ(token.stringValue(), "bar");
return token.stringValue();
});
EXPECT_EQ(identValue2, "bar");
auto identValue3 = parser.consumeComponentValue<std::string_view>(
CSSDelimiter::SolidusOrWhitespace, [](const CSSPreservedToken& token) {
EXPECT_EQ(token.type(), CSSTokenType::Ident);
EXPECT_EQ(token.stringValue(), "baz");
return token.stringValue();
});
EXPECT_EQ(identValue3, "baz");
auto identValue4 = parser.consumeComponentValue<std::string_view>(
CSSDelimiter::SolidusOrWhitespace, [](const CSSPreservedToken& token) {
EXPECT_EQ(token.type(), CSSTokenType::Ident);
EXPECT_EQ(token.stringValue(), "potato");
return token.stringValue();
});
EXPECT_EQ(identValue4, "potato");
auto delimValue1 = parser.consumeComponentValue<bool>(
CSSDelimiter::SolidusOrWhitespace,
[](const CSSPreservedToken& /*token*/) { return true; });
EXPECT_FALSE(delimValue1);
}
TEST(CSSSyntaxParser, delimeter_not_consumed_when_no_component_value) {
CSSSyntaxParser parser{"foo ,"};
auto identValue = parser.consumeComponentValue<std::string_view>(
[](const CSSPreservedToken& token) {
EXPECT_EQ(token.type(), CSSTokenType::Ident);
EXPECT_EQ(token.stringValue(), "foo");
return token.stringValue();
});
EXPECT_EQ(identValue, "foo");
auto identValue2 = parser.consumeComponentValue<bool>(
CSSDelimiter::Comma,
[](const CSSPreservedToken& /*token*/) { return true; });
EXPECT_FALSE(identValue2);
auto hasComma = parser.consumeComponentValue<bool>(
CSSDelimiter::Whitespace, [](const CSSPreservedToken& token) {
EXPECT_EQ(token.type(), CSSTokenType::Comma);
return true;
});
EXPECT_TRUE(hasComma);
}
TEST(CSSSyntaxParser, component_value_not_consumed_on_visitor_failure) {
CSSSyntaxParser parser{"foo"};
bool visitor1Attempted = false;
bool visitor1Ret =
parser.consumeComponentValue<bool>([&](const CSSPreservedToken& token) {
EXPECT_EQ(token.stringValue(), "foo");
visitor1Attempted = true;
return false;
});
EXPECT_TRUE(visitor1Attempted);
EXPECT_FALSE(visitor1Ret);
bool visitor2Attempted = false;
parser.consumeComponentValue<bool>([&](const CSSPreservedToken& token) {
EXPECT_EQ(token.stringValue(), "foo");
visitor2Attempted = true;
return true;
});
EXPECT_TRUE(visitor2Attempted);
EXPECT_TRUE(visitor2Attempted);
bool visitor3Attempted = false;
bool visitor3Ret = parser.consumeComponentValue<bool>(
[&](const CSSPreservedToken& /*token*/) {
visitor3Attempted = true;
return true;
});
EXPECT_FALSE(visitor3Attempted);
EXPECT_FALSE(visitor3Ret);
}
} // namespace facebook::react

View File

@@ -0,0 +1,242 @@
/*
* Copyright (c) Meta Platforms, Inc. and affiliates.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*/
#include <gtest/gtest.h>
#include <react/renderer/css/CSSTokenizer.h>
namespace facebook::react {
#define EXPECT_TOKENS(characters, ...) \
{ \
CSSTokenizer tokenizer{characters}; \
\
for (const auto& expectedToken : \
std::initializer_list<CSSToken>{__VA_ARGS__}) { \
auto nextToken = tokenizer.next(); \
EXPECT_EQ(nextToken.type(), expectedToken.type()); \
EXPECT_EQ(nextToken.stringValue(), expectedToken.stringValue()); \
EXPECT_EQ(nextToken.numericValue(), expectedToken.numericValue()); \
EXPECT_EQ(nextToken.unit(), expectedToken.unit()); \
EXPECT_EQ(nextToken, expectedToken); \
} \
}
TEST(CSSTokenizer, eof_values) {
EXPECT_TOKENS("", CSSToken{CSSTokenType::EndOfFile});
}
TEST(CSSTokenizer, whitespace_values) {
EXPECT_TOKENS(
" ",
CSSToken{CSSTokenType::WhiteSpace},
CSSToken{CSSTokenType::EndOfFile});
EXPECT_TOKENS(
" \t",
CSSToken{CSSTokenType::WhiteSpace},
CSSToken{CSSTokenType::EndOfFile});
EXPECT_TOKENS(
"\n \t",
CSSToken{CSSTokenType::WhiteSpace},
CSSToken{CSSTokenType::EndOfFile});
}
TEST(CSSTokenizer, ident_values) {
EXPECT_TOKENS(
"auto",
CSSToken{CSSTokenType::Ident, "auto"},
CSSToken{CSSTokenType::EndOfFile});
EXPECT_TOKENS(
"inset auto left",
CSSToken{CSSTokenType::Ident, "inset"},
CSSToken{CSSTokenType::WhiteSpace},
CSSToken{CSSTokenType::Ident, "auto"},
CSSToken{CSSTokenType::WhiteSpace},
CSSToken{CSSTokenType::Ident, "left"},
CSSToken{CSSTokenType::EndOfFile});
}
TEST(CSSTokenizer, number_values) {
EXPECT_TOKENS(
"12",
CSSToken{CSSTokenType::Number, 12.0f},
CSSToken{CSSTokenType::EndOfFile});
EXPECT_TOKENS(
"-5",
CSSToken{CSSTokenType::Number, -5.0f},
CSSToken{CSSTokenType::EndOfFile});
EXPECT_TOKENS(
"123.0",
CSSToken{CSSTokenType::Number, 123.0f},
CSSToken{CSSTokenType::EndOfFile});
EXPECT_TOKENS(
"4.2E-1",
CSSToken{CSSTokenType::Number, 4.2e-1},
CSSToken{CSSTokenType::EndOfFile});
EXPECT_TOKENS(
"6e-10",
CSSToken{CSSTokenType::Number, 6e-10f},
CSSToken{CSSTokenType::EndOfFile});
EXPECT_TOKENS(
"+81.07e+0",
CSSToken{CSSTokenType::Number, +81.07e+0},
CSSToken{CSSTokenType::EndOfFile});
EXPECT_TOKENS(
"+.123e+0",
CSSToken{CSSTokenType::Number, +.123e+0},
CSSToken{CSSTokenType::EndOfFile});
EXPECT_TOKENS(
"3e-1000",
CSSToken{CSSTokenType::Number, 0},
CSSToken{CSSTokenType::EndOfFile});
EXPECT_TOKENS(
"3e1000",
CSSToken{CSSTokenType::Number, std::numeric_limits<float>::infinity()},
CSSToken{CSSTokenType::EndOfFile});
EXPECT_TOKENS(
"+.9999999999",
CSSToken{CSSTokenType::Number, +.9999999999},
CSSToken{CSSTokenType::EndOfFile});
}
TEST(CSSTokenizer, dimension_values) {
EXPECT_TOKENS(
"12px",
CSSToken{CSSTokenType::Dimension, 12.0f, "px"},
CSSToken{CSSTokenType::EndOfFile});
EXPECT_TOKENS(
"463.2abc",
CSSToken{CSSTokenType::Dimension, 463.2, "abc"},
CSSToken{CSSTokenType::EndOfFile});
EXPECT_TOKENS(
".3xyz",
CSSToken{CSSTokenType::Dimension, 0.3, "xyz"},
CSSToken{CSSTokenType::EndOfFile});
EXPECT_TOKENS(
"-0.5em",
CSSToken{CSSTokenType::Dimension, -0.5, "em"},
CSSToken{CSSTokenType::EndOfFile});
}
TEST(CSSTokenizer, percent_values) {
EXPECT_TOKENS(
"12%",
CSSToken{CSSTokenType::Percentage, 12.0f},
CSSToken{CSSTokenType::EndOfFile});
EXPECT_TOKENS(
"-28.5%",
CSSToken{CSSTokenType::Percentage, -28.5f},
CSSToken{CSSTokenType::EndOfFile});
EXPECT_TOKENS(
".02%",
CSSToken{CSSTokenType::Percentage, 0.02f},
CSSToken{CSSTokenType::EndOfFile});
}
TEST(CSSTokenizer, mixed_values) {
EXPECT_TOKENS(
"12px -100vh",
CSSToken{CSSTokenType::Dimension, 12.0f, "px"},
CSSToken{CSSTokenType::WhiteSpace},
CSSToken{CSSTokenType::Dimension, -100.0f, "vh"},
CSSToken{CSSTokenType::EndOfFile});
}
TEST(CSSTokenizer, ratio_values) {
EXPECT_TOKENS(
"16 / 9",
CSSToken{CSSTokenType::Number, 16.0f},
CSSToken{CSSTokenType::WhiteSpace},
CSSToken{CSSTokenType::Delim, "/"},
CSSToken{CSSTokenType::WhiteSpace},
CSSToken{CSSTokenType::Number, 9.0f},
CSSToken{CSSTokenType::EndOfFile});
}
TEST(CSSTokenizer, function_values) {
EXPECT_TOKENS(
"blur(50px)",
CSSToken{CSSTokenType::Function, "blur"},
CSSToken{CSSTokenType::Dimension, 50.0f, "px"},
CSSToken{CSSTokenType::CloseParen},
CSSToken{CSSTokenType::EndOfFile});
EXPECT_TOKENS(
"scale3d( 1.2, 150% 0.5) ",
CSSToken{CSSTokenType::Function, "scale3d"},
CSSToken{CSSTokenType::WhiteSpace},
CSSToken{CSSTokenType::Number, 1.2f},
CSSToken{CSSTokenType::Comma},
CSSToken{CSSTokenType::WhiteSpace},
CSSToken{CSSTokenType::Percentage, 150.f},
CSSToken{CSSTokenType::WhiteSpace},
CSSToken{CSSTokenType::Number, 0.5f},
CSSToken{CSSTokenType::CloseParen},
CSSToken{CSSTokenType::WhiteSpace},
CSSToken{CSSTokenType::EndOfFile});
EXPECT_TOKENS(
"blur (50px)",
CSSToken{CSSTokenType::Ident, "blur"},
CSSToken{CSSTokenType::WhiteSpace},
CSSToken{CSSTokenType::OpenParen},
CSSToken{CSSTokenType::Dimension, 50.0f, "px"},
CSSToken{CSSTokenType::CloseParen},
CSSToken{CSSTokenType::EndOfFile});
}
TEST(CSSTokenizer, invalid_values) {
EXPECT_TOKENS(
"100*",
CSSToken{CSSTokenType::Number, 100.0f},
CSSToken{CSSTokenType::Delim, "*"},
CSSToken{CSSTokenType::EndOfFile});
EXPECT_TOKENS(
"+",
CSSToken{CSSTokenType::Delim, "+"},
CSSToken{CSSTokenType::EndOfFile});
EXPECT_TOKENS(
"(%",
CSSToken{CSSTokenType::OpenParen},
CSSToken{CSSTokenType::Delim, "%"},
CSSToken{CSSTokenType::EndOfFile});
}
TEST(CSSTokenizer, hash_values) {
EXPECT_TOKENS(
"#Ff03BC",
CSSToken{CSSTokenType::Hash, "Ff03BC"},
CSSToken{CSSTokenType::EndOfFile});
EXPECT_TOKENS(
"#identifier",
CSSToken{CSSTokenType::Hash, "identifier"},
CSSToken{CSSTokenType::EndOfFile});
EXPECT_TOKENS(
"#*",
CSSToken{CSSTokenType::Delim, "#"},
CSSToken{CSSTokenType::Delim, "*"},
CSSToken{CSSTokenType::EndOfFile});
}
} // namespace facebook::react

View File

@@ -0,0 +1,428 @@
/*
* Copyright (c) Meta Platforms, Inc. and affiliates.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*/
#include <gtest/gtest.h>
#include <react/renderer/css/CSSRatio.h>
#include <react/renderer/css/CSSTransformOrigin.h>
namespace facebook::react {
TEST(CSSTransformOrigin, empty) {
auto emptyValue = parseCSSProperty<CSSTransformOrigin>("");
EXPECT_TRUE(std::holds_alternative<std::monostate>(emptyValue));
}
TEST(CSSTransformOrigin, single_keywords) {
auto left = parseCSSProperty<CSSTransformOrigin>("left");
EXPECT_TRUE(std::holds_alternative<CSSTransformOrigin>(left));
auto& leftOrigin = std::get<CSSTransformOrigin>(left);
EXPECT_TRUE(std::holds_alternative<CSSPercentage>(leftOrigin.x));
EXPECT_EQ(std::get<CSSPercentage>(leftOrigin.x).value, 0.0f);
EXPECT_TRUE(std::holds_alternative<CSSPercentage>(leftOrigin.y));
EXPECT_EQ(std::get<CSSPercentage>(leftOrigin.y).value, 50.0f);
EXPECT_EQ(leftOrigin.z, CSSLength{});
auto right = parseCSSProperty<CSSTransformOrigin>("right");
EXPECT_TRUE(std::holds_alternative<CSSTransformOrigin>(right));
auto& rightOrigin = std::get<CSSTransformOrigin>(right);
EXPECT_TRUE(std::holds_alternative<CSSPercentage>(rightOrigin.x));
EXPECT_EQ(std::get<CSSPercentage>(rightOrigin.x).value, 100.0f);
EXPECT_TRUE(std::holds_alternative<CSSPercentage>(rightOrigin.y));
EXPECT_EQ(std::get<CSSPercentage>(rightOrigin.y).value, 50.0f);
EXPECT_EQ(rightOrigin.z, CSSLength{});
auto top = parseCSSProperty<CSSTransformOrigin>("top");
EXPECT_TRUE(std::holds_alternative<CSSTransformOrigin>(top));
auto& topOrigin = std::get<CSSTransformOrigin>(top);
EXPECT_TRUE(std::holds_alternative<CSSPercentage>(topOrigin.x));
EXPECT_EQ(std::get<CSSPercentage>(topOrigin.x).value, 50.0f);
EXPECT_TRUE(std::holds_alternative<CSSPercentage>(topOrigin.y));
EXPECT_EQ(std::get<CSSPercentage>(topOrigin.y).value, 0.0f);
EXPECT_EQ(topOrigin.z, CSSLength{});
auto bottom = parseCSSProperty<CSSTransformOrigin>("bottom");
EXPECT_TRUE(std::holds_alternative<CSSTransformOrigin>(bottom));
auto& bottomOrigin = std::get<CSSTransformOrigin>(bottom);
EXPECT_TRUE(std::holds_alternative<CSSPercentage>(bottomOrigin.x));
EXPECT_EQ(std::get<CSSPercentage>(bottomOrigin.x).value, 50.0f);
EXPECT_TRUE(std::holds_alternative<CSSPercentage>(bottomOrigin.y));
EXPECT_EQ(std::get<CSSPercentage>(bottomOrigin.y).value, 100.0f);
EXPECT_EQ(bottomOrigin.z, CSSLength{});
auto center = parseCSSProperty<CSSTransformOrigin>("center");
EXPECT_TRUE(std::holds_alternative<CSSTransformOrigin>(center));
auto& centerOrigin = std::get<CSSTransformOrigin>(center);
EXPECT_TRUE(std::holds_alternative<CSSPercentage>(centerOrigin.x));
EXPECT_EQ(std::get<CSSPercentage>(centerOrigin.x).value, 50.0f);
EXPECT_TRUE(std::holds_alternative<CSSPercentage>(centerOrigin.y));
EXPECT_EQ(std::get<CSSPercentage>(centerOrigin.y).value, 50.0f);
EXPECT_EQ(centerOrigin.z, CSSLength{});
}
TEST(CSSTransformOrigin, single_length) {
auto val = parseCSSProperty<CSSTransformOrigin>("500px");
EXPECT_TRUE(std::holds_alternative<CSSTransformOrigin>(val));
auto& origin = std::get<CSSTransformOrigin>(val);
EXPECT_TRUE(std::holds_alternative<CSSLength>(origin.x));
EXPECT_EQ(std::get<CSSLength>(origin.x).value, 500.0f);
EXPECT_EQ(std::get<CSSLength>(origin.x).unit, CSSLengthUnit::Px);
EXPECT_TRUE(std::holds_alternative<CSSPercentage>(origin.y));
EXPECT_EQ(std::get<CSSPercentage>(origin.y).value, 50.0f);
EXPECT_EQ(origin.z, CSSLength{});
}
TEST(CSSTransformOrigin, single_percentage) {
auto val = parseCSSProperty<CSSTransformOrigin>("9000%");
EXPECT_TRUE(std::holds_alternative<CSSTransformOrigin>(val));
auto& origin = std::get<CSSTransformOrigin>(val);
EXPECT_TRUE(std::holds_alternative<CSSPercentage>(origin.x));
EXPECT_EQ(std::get<CSSPercentage>(origin.x).value, 9000.0f);
EXPECT_TRUE(std::holds_alternative<CSSPercentage>(origin.y));
EXPECT_EQ(std::get<CSSPercentage>(origin.y).value, 50.0f);
EXPECT_EQ(origin.z, CSSLength{});
}
TEST(CSSTransformOrigin, left_top) {
auto val = parseCSSProperty<CSSTransformOrigin>("left top");
EXPECT_TRUE(std::holds_alternative<CSSTransformOrigin>(val));
auto& origin = std::get<CSSTransformOrigin>(val);
EXPECT_TRUE(std::holds_alternative<CSSPercentage>(origin.x));
EXPECT_EQ(std::get<CSSPercentage>(origin.x).value, 0.0f);
EXPECT_TRUE(std::holds_alternative<CSSPercentage>(origin.y));
EXPECT_EQ(std::get<CSSPercentage>(origin.y).value, 0.0f);
EXPECT_EQ(origin.z, CSSLength{});
}
TEST(CSSTransformOrigin, top_left) {
auto val = parseCSSProperty<CSSTransformOrigin>("top left");
EXPECT_TRUE(std::holds_alternative<CSSTransformOrigin>(val));
auto& origin = std::get<CSSTransformOrigin>(val);
EXPECT_TRUE(std::holds_alternative<CSSPercentage>(origin.x));
EXPECT_EQ(std::get<CSSPercentage>(origin.x).value, 0.0f);
EXPECT_TRUE(std::holds_alternative<CSSPercentage>(origin.y));
EXPECT_EQ(std::get<CSSPercentage>(origin.y).value, 0.0f);
EXPECT_EQ(origin.z, CSSLength{});
}
TEST(CSSTransformOrigin, right_top) {
auto val = parseCSSProperty<CSSTransformOrigin>("right top");
EXPECT_TRUE(std::holds_alternative<CSSTransformOrigin>(val));
auto& origin = std::get<CSSTransformOrigin>(val);
EXPECT_TRUE(std::holds_alternative<CSSPercentage>(origin.x));
EXPECT_EQ(std::get<CSSPercentage>(origin.x).value, 100.0f);
EXPECT_TRUE(std::holds_alternative<CSSPercentage>(origin.y));
EXPECT_EQ(std::get<CSSPercentage>(origin.y).value, 0.0f);
EXPECT_EQ(origin.z, CSSLength{});
}
TEST(CSSTransformOrigin, center_center) {
auto val = parseCSSProperty<CSSTransformOrigin>("center center");
EXPECT_TRUE(std::holds_alternative<CSSTransformOrigin>(val));
auto& origin = std::get<CSSTransformOrigin>(val);
EXPECT_TRUE(std::holds_alternative<CSSPercentage>(origin.x));
EXPECT_EQ(std::get<CSSPercentage>(origin.x).value, 50.0f);
EXPECT_TRUE(std::holds_alternative<CSSPercentage>(origin.y));
EXPECT_EQ(std::get<CSSPercentage>(origin.y).value, 50.0f);
EXPECT_EQ(origin.z, CSSLength{});
}
TEST(CSSTransformOrigin, center_left) {
auto val = parseCSSProperty<CSSTransformOrigin>("center left");
EXPECT_TRUE(std::holds_alternative<CSSTransformOrigin>(val));
auto& origin = std::get<CSSTransformOrigin>(val);
EXPECT_TRUE(std::holds_alternative<CSSPercentage>(origin.x));
EXPECT_EQ(std::get<CSSPercentage>(origin.x).value, 0.0f);
EXPECT_TRUE(std::holds_alternative<CSSPercentage>(origin.y));
EXPECT_EQ(std::get<CSSPercentage>(origin.y).value, 50.0f);
EXPECT_EQ(origin.z, CSSLength{});
}
TEST(CSSTransformOrigin, left_bottom) {
auto val = parseCSSProperty<CSSTransformOrigin>("left bottom");
EXPECT_TRUE(std::holds_alternative<CSSTransformOrigin>(val));
auto& origin = std::get<CSSTransformOrigin>(val);
EXPECT_TRUE(std::holds_alternative<CSSPercentage>(origin.x));
EXPECT_EQ(std::get<CSSPercentage>(origin.x).value, 0.0f);
EXPECT_TRUE(std::holds_alternative<CSSPercentage>(origin.y));
EXPECT_EQ(std::get<CSSPercentage>(origin.y).value, 100.0f);
EXPECT_EQ(origin.z, CSSLength{});
}
TEST(CSSTransformOrigin, bottom_left) {
auto val = parseCSSProperty<CSSTransformOrigin>("bottom left");
EXPECT_TRUE(std::holds_alternative<CSSTransformOrigin>(val));
auto& origin = std::get<CSSTransformOrigin>(val);
EXPECT_TRUE(std::holds_alternative<CSSPercentage>(origin.x));
EXPECT_EQ(std::get<CSSPercentage>(origin.x).value, 0.0f);
EXPECT_TRUE(std::holds_alternative<CSSPercentage>(origin.y));
EXPECT_EQ(std::get<CSSPercentage>(origin.y).value, 100.0f);
EXPECT_EQ(origin.z, CSSLength{});
}
TEST(CSSTransformOrigin, bottom_bottom) {
auto val = parseCSSProperty<CSSTransformOrigin>("bottom bottom");
EXPECT_TRUE(std::holds_alternative<std::monostate>(val));
}
TEST(CSSTransformOrigin, right_right) {
auto val = parseCSSProperty<CSSTransformOrigin>("right right");
EXPECT_TRUE(std::holds_alternative<std::monostate>(val));
}
TEST(CSSTransformOrigin, center_left_length) {
auto val = parseCSSProperty<CSSTransformOrigin>("center left 500px");
EXPECT_TRUE(std::holds_alternative<CSSTransformOrigin>(val));
auto& origin = std::get<CSSTransformOrigin>(val);
EXPECT_TRUE(std::holds_alternative<CSSPercentage>(origin.x));
EXPECT_EQ(std::get<CSSPercentage>(origin.x).value, 0.0f);
EXPECT_TRUE(std::holds_alternative<CSSPercentage>(origin.y));
EXPECT_EQ(std::get<CSSPercentage>(origin.y).value, 50.0f);
EXPECT_EQ(origin.z.value, 500.0f);
EXPECT_EQ(origin.z.unit, CSSLengthUnit::Px);
}
TEST(CSSTransformOrigin, center_left_percentage) {
auto val = parseCSSProperty<CSSTransformOrigin>("center left 9000%");
EXPECT_TRUE(std::holds_alternative<std::monostate>(val));
}
TEST(CSSTransformOrigin, pct_center) {
auto val = parseCSSProperty<CSSTransformOrigin>("9000% center");
EXPECT_TRUE(std::holds_alternative<CSSTransformOrigin>(val));
auto& origin = std::get<CSSTransformOrigin>(val);
EXPECT_TRUE(std::holds_alternative<CSSPercentage>(origin.x));
EXPECT_EQ(std::get<CSSPercentage>(origin.x).value, 9000.0f);
EXPECT_TRUE(std::holds_alternative<CSSPercentage>(origin.y));
EXPECT_EQ(std::get<CSSPercentage>(origin.y).value, 50.0f);
EXPECT_EQ(origin.z, CSSLength{});
}
TEST(CSSTransformOrigin, length_center) {
auto val = parseCSSProperty<CSSTransformOrigin>("500px center");
EXPECT_TRUE(std::holds_alternative<CSSTransformOrigin>(val));
auto& origin = std::get<CSSTransformOrigin>(val);
EXPECT_TRUE(std::holds_alternative<CSSLength>(origin.x));
EXPECT_EQ(std::get<CSSLength>(origin.x).value, 500.0f);
EXPECT_EQ(std::get<CSSLength>(origin.x).unit, CSSLengthUnit::Px);
EXPECT_TRUE(std::holds_alternative<CSSPercentage>(origin.y));
EXPECT_EQ(std::get<CSSPercentage>(origin.y).value, 50.0f);
EXPECT_EQ(origin.z, CSSLength{});
}
TEST(CSSTransformOrigin, length_top) {
auto val = parseCSSProperty<CSSTransformOrigin>("500px top");
EXPECT_TRUE(std::holds_alternative<CSSTransformOrigin>(val));
auto& origin = std::get<CSSTransformOrigin>(val);
EXPECT_TRUE(std::holds_alternative<CSSLength>(origin.x));
EXPECT_EQ(std::get<CSSLength>(origin.x).value, 500.0f);
EXPECT_EQ(std::get<CSSLength>(origin.x).unit, CSSLengthUnit::Px);
EXPECT_TRUE(std::holds_alternative<CSSPercentage>(origin.y));
EXPECT_EQ(std::get<CSSPercentage>(origin.y).value, 0.0f);
EXPECT_EQ(origin.z, CSSLength{});
}
TEST(CSSTransformOrigin, length_left) {
auto val = parseCSSProperty<CSSTransformOrigin>("500px left");
EXPECT_TRUE(std::holds_alternative<std::monostate>(val));
}
TEST(CSSTransformOrigin, length_bottom_length) {
auto val = parseCSSProperty<CSSTransformOrigin>("500px bottom 500px");
EXPECT_TRUE(std::holds_alternative<CSSTransformOrigin>(val));
auto& origin = std::get<CSSTransformOrigin>(val);
EXPECT_TRUE(std::holds_alternative<CSSLength>(origin.x));
EXPECT_EQ(std::get<CSSLength>(origin.x).value, 500.0f);
EXPECT_EQ(std::get<CSSLength>(origin.x).unit, CSSLengthUnit::Px);
EXPECT_TRUE(std::holds_alternative<CSSPercentage>(origin.y));
EXPECT_EQ(std::get<CSSPercentage>(origin.y).value, 100.0f);
EXPECT_EQ(origin.z.value, 500.0f);
EXPECT_EQ(origin.z.unit, CSSLengthUnit::Px);
}
TEST(CSSTransformOrigin, length_right_percentage) {
auto val = parseCSSProperty<CSSTransformOrigin>("500px right 9000%");
EXPECT_TRUE(std::holds_alternative<std::monostate>(val));
}
TEST(CSSTransformOrigin, length_length) {
auto val = parseCSSProperty<CSSTransformOrigin>("500px 600px");
EXPECT_TRUE(std::holds_alternative<CSSTransformOrigin>(val));
auto& origin = std::get<CSSTransformOrigin>(val);
EXPECT_TRUE(std::holds_alternative<CSSLength>(origin.x));
EXPECT_EQ(std::get<CSSLength>(origin.x).value, 500.0f);
EXPECT_EQ(std::get<CSSLength>(origin.x).unit, CSSLengthUnit::Px);
EXPECT_TRUE(std::holds_alternative<CSSLength>(origin.y));
EXPECT_EQ(std::get<CSSLength>(origin.y).value, 600.0f);
EXPECT_EQ(std::get<CSSLength>(origin.y).unit, CSSLengthUnit::Px);
EXPECT_EQ(origin.z, CSSLength{});
}
TEST(CSSTransformOrigin, length_percentage) {
auto val = parseCSSProperty<CSSTransformOrigin>("500px 9000%");
EXPECT_TRUE(std::holds_alternative<CSSTransformOrigin>(val));
auto& origin = std::get<CSSTransformOrigin>(val);
EXPECT_TRUE(std::holds_alternative<CSSLength>(origin.x));
EXPECT_EQ(std::get<CSSLength>(origin.x).value, 500.0f);
EXPECT_EQ(std::get<CSSLength>(origin.x).unit, CSSLengthUnit::Px);
EXPECT_TRUE(std::holds_alternative<CSSPercentage>(origin.y));
EXPECT_EQ(std::get<CSSPercentage>(origin.y).value, 9000.0f);
EXPECT_EQ(origin.z, CSSLength{});
}
TEST(CSSTransformOrigin, percentage_length) {
auto val = parseCSSProperty<CSSTransformOrigin>("9000% 500px");
EXPECT_TRUE(std::holds_alternative<CSSTransformOrigin>(val));
auto& origin = std::get<CSSTransformOrigin>(val);
EXPECT_TRUE(std::holds_alternative<CSSPercentage>(origin.x));
EXPECT_EQ(std::get<CSSPercentage>(origin.x).value, 9000.0f);
EXPECT_TRUE(std::holds_alternative<CSSLength>(origin.y));
EXPECT_EQ(std::get<CSSLength>(origin.y).value, 500.0f);
EXPECT_EQ(std::get<CSSLength>(origin.y).unit, CSSLengthUnit::Px);
EXPECT_EQ(origin.z, CSSLength{});
}
TEST(CSSTransformOrigin, percentage_right) {
auto val = parseCSSProperty<CSSTransformOrigin>("9000% right");
EXPECT_TRUE(std::holds_alternative<std::monostate>(val));
}
TEST(CSSTransformOrigin, percentage_bottom) {
auto val = parseCSSProperty<CSSTransformOrigin>("9000% bottom");
EXPECT_TRUE(std::holds_alternative<CSSTransformOrigin>(val));
auto& origin = std::get<CSSTransformOrigin>(val);
EXPECT_TRUE(std::holds_alternative<CSSPercentage>(origin.x));
EXPECT_EQ(std::get<CSSPercentage>(origin.x).value, 9000.0f);
EXPECT_TRUE(std::holds_alternative<CSSPercentage>(origin.y));
EXPECT_EQ(std::get<CSSPercentage>(origin.y).value, 100.0f);
EXPECT_EQ(origin.z, CSSLength{});
}
TEST(CSSTransformOrigin, percentage_left) {
auto val = parseCSSProperty<CSSTransformOrigin>("9000% left");
EXPECT_TRUE(std::holds_alternative<std::monostate>(val));
}
TEST(CSSTransformOrigin, bottom_percentage) {
auto val = parseCSSProperty<CSSTransformOrigin>("bottom 9000%");
EXPECT_TRUE(std::holds_alternative<std::monostate>(val));
}
TEST(CSSTransformOrigin, center_percentage) {
auto val = parseCSSProperty<CSSTransformOrigin>("center 9000%");
EXPECT_TRUE(std::holds_alternative<CSSTransformOrigin>(val));
auto& origin = std::get<CSSTransformOrigin>(val);
EXPECT_TRUE(std::holds_alternative<CSSPercentage>(origin.x));
EXPECT_EQ(std::get<CSSPercentage>(origin.x).value, 50.0f);
EXPECT_TRUE(std::holds_alternative<CSSPercentage>(origin.y));
EXPECT_EQ(std::get<CSSPercentage>(origin.y).value, 9000.0f);
EXPECT_EQ(origin.z, CSSLength{});
}
TEST(CSSTransformOrigin, right_percentage) {
auto val = parseCSSProperty<CSSTransformOrigin>("right 9000%");
EXPECT_TRUE(std::holds_alternative<CSSTransformOrigin>(val));
auto& origin = std::get<CSSTransformOrigin>(val);
EXPECT_TRUE(std::holds_alternative<CSSPercentage>(origin.x));
EXPECT_EQ(std::get<CSSPercentage>(origin.x).value, 100.0f);
EXPECT_TRUE(std::holds_alternative<CSSPercentage>(origin.y));
EXPECT_EQ(std::get<CSSPercentage>(origin.y).value, 9000.0f);
EXPECT_EQ(origin.z, CSSLength{});
}
TEST(CSSTransformOrigin, percentage_percentage) {
auto val = parseCSSProperty<CSSTransformOrigin>("9000% 9001%");
EXPECT_TRUE(std::holds_alternative<CSSTransformOrigin>(val));
auto& origin = std::get<CSSTransformOrigin>(val);
EXPECT_TRUE(std::holds_alternative<CSSPercentage>(origin.x));
EXPECT_EQ(std::get<CSSPercentage>(origin.x).value, 9000.0f);
EXPECT_TRUE(std::holds_alternative<CSSPercentage>(origin.y));
EXPECT_EQ(std::get<CSSPercentage>(origin.y).value, 9001.0f);
EXPECT_EQ(origin.z, CSSLength{});
}
} // namespace facebook::react

View File

@@ -0,0 +1,701 @@
/*
* Copyright (c) Meta Platforms, Inc. and affiliates.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*/
#include <gtest/gtest.h>
#include <react/renderer/css/CSSTransform.h>
#include <react/renderer/css/CSSValueParser.h>
namespace facebook::react {
TEST(CSSTransform, matrix_basic) {
auto val = parseCSSProperty<CSSTransformFunction>("matrix(1, 2, 3, 4, 5, 6)");
EXPECT_TRUE(std::holds_alternative<CSSMatrix>(val));
auto& matrix = std::get<CSSMatrix>(val);
EXPECT_EQ(matrix.values[0], 1.0f);
EXPECT_EQ(matrix.values[1], 2.0f);
EXPECT_EQ(matrix.values[2], 3.0f);
EXPECT_EQ(matrix.values[3], 4.0f);
EXPECT_EQ(matrix.values[4], 5.0f);
EXPECT_EQ(matrix.values[5], 6.0f);
}
TEST(CSSTransform, matrix_funky) {
auto val =
parseCSSProperty<CSSTransformFunction>("mAtRiX( 1 , \n2,3, 4, \t5, 6)");
EXPECT_TRUE(std::holds_alternative<CSSMatrix>(val));
auto& matrix = std::get<CSSMatrix>(val);
EXPECT_EQ(matrix.values[0], 1.0f);
EXPECT_EQ(matrix.values[1], 2.0f);
EXPECT_EQ(matrix.values[2], 3.0f);
EXPECT_EQ(matrix.values[3], 4.0f);
EXPECT_EQ(matrix.values[4], 5.0f);
EXPECT_EQ(matrix.values[5], 6.0f);
}
TEST(CSSTransform, matrix_missing_elements) {
auto val = parseCSSProperty<CSSTransformFunction>("matrix(1, 2, 3, 4, 5)");
EXPECT_TRUE(std::holds_alternative<std::monostate>(val));
}
TEST(CSSTransform, matrix_extra_elements) {
auto val =
parseCSSProperty<CSSTransformFunction>("matrix(1, 2, 3, 4, 5, 6, 7)");
EXPECT_TRUE(std::holds_alternative<std::monostate>(val));
}
TEST(CSSTransform, matrix_pct) {
auto val =
parseCSSProperty<CSSTransformFunction>("matrix(1, 2%, 3, 4, 5, 6)");
EXPECT_TRUE(std::holds_alternative<std::monostate>(val));
}
TEST(CSSTransform, translate_basic) {
auto val = parseCSSProperty<CSSTransformFunction>("translate(4rem, 20%)");
EXPECT_TRUE(std::holds_alternative<CSSTranslate>(val));
auto& translate = std::get<CSSTranslate>(val);
EXPECT_TRUE(std::holds_alternative<CSSLength>(translate.x));
EXPECT_EQ(std::get<CSSLength>(translate.x).value, 4.0f);
EXPECT_EQ(std::get<CSSLength>(translate.x).unit, CSSLengthUnit::Rem);
EXPECT_TRUE(std::holds_alternative<CSSPercentage>(translate.y));
EXPECT_EQ(std::get<CSSPercentage>(translate.y).value, 20.0f);
}
TEST(CSSTransform, translate_funky) {
auto val =
parseCSSProperty<CSSTransformFunction>("traNslAte( 4rem, \n20% )");
EXPECT_TRUE(std::holds_alternative<CSSTranslate>(val));
auto& translate = std::get<CSSTranslate>(val);
EXPECT_TRUE(std::holds_alternative<CSSLength>(translate.x));
EXPECT_EQ(std::get<CSSLength>(translate.x).value, 4.0f);
EXPECT_EQ(std::get<CSSLength>(translate.x).unit, CSSLengthUnit::Rem);
EXPECT_TRUE(std::holds_alternative<CSSPercentage>(translate.y));
EXPECT_EQ(std::get<CSSPercentage>(translate.y).value, 20.0f);
}
TEST(CSSTransform, translate_default_y) {
auto val = parseCSSProperty<CSSTransformFunction>("translate(4rem)");
EXPECT_TRUE(std::holds_alternative<CSSTranslate>(val));
auto& translate = std::get<CSSTranslate>(val);
EXPECT_TRUE(std::holds_alternative<CSSLength>(translate.x));
EXPECT_EQ(std::get<CSSLength>(translate.x).value, 4.0f);
EXPECT_EQ(std::get<CSSLength>(translate.x).unit, CSSLengthUnit::Rem);
EXPECT_TRUE(std::holds_alternative<CSSLength>(translate.y));
EXPECT_EQ(std::get<CSSLength>(translate.y).value, 0.0f);
EXPECT_EQ(std::get<CSSLength>(translate.y).unit, CSSLengthUnit::Px);
}
TEST(CSSTransform, translate_missing_value) {
auto val = parseCSSProperty<CSSTransformFunction>("translate()");
EXPECT_TRUE(std::holds_alternative<std::monostate>(val));
}
TEST(CSSTransform, translate_extra_value) {
auto val =
parseCSSProperty<CSSTransformFunction>("translate(10px, 2px, 5px)");
EXPECT_TRUE(std::holds_alternative<std::monostate>(val));
}
TEST(CSSTransform, translate_number) {
auto val = parseCSSProperty<CSSTransformFunction>("translate(5)");
EXPECT_TRUE(std::holds_alternative<std::monostate>(val));
}
TEST(CSSTransform, translate3d_basic) {
auto val =
parseCSSProperty<CSSTransformFunction>("translate3d(4rem, 20%, 2px)");
EXPECT_TRUE(std::holds_alternative<CSSTranslate3D>(val));
auto& translate = std::get<CSSTranslate3D>(val);
EXPECT_TRUE(std::holds_alternative<CSSLength>(translate.x));
EXPECT_EQ(std::get<CSSLength>(translate.x).value, 4.0f);
EXPECT_EQ(std::get<CSSLength>(translate.x).unit, CSSLengthUnit::Rem);
EXPECT_TRUE(std::holds_alternative<CSSPercentage>(translate.y));
EXPECT_EQ(std::get<CSSPercentage>(translate.y).value, 20.0f);
EXPECT_EQ(translate.z.value, 2.0f);
EXPECT_EQ(translate.z.unit, CSSLengthUnit::Px);
}
TEST(CSSTransform, translate3d_funky) {
auto val = parseCSSProperty<CSSTransformFunction>(
"translAte3D( 4rem , 20% , 2px)");
EXPECT_TRUE(std::holds_alternative<CSSTranslate3D>(val));
auto& translate = std::get<CSSTranslate3D>(val);
EXPECT_TRUE(std::holds_alternative<CSSLength>(translate.x));
EXPECT_EQ(std::get<CSSLength>(translate.x).value, 4.0f);
EXPECT_EQ(std::get<CSSLength>(translate.x).unit, CSSLengthUnit::Rem);
EXPECT_TRUE(std::holds_alternative<CSSPercentage>(translate.y));
EXPECT_EQ(std::get<CSSPercentage>(translate.y).value, 20.0f);
EXPECT_EQ(translate.z.value, 2.0f);
EXPECT_EQ(translate.z.unit, CSSLengthUnit::Px);
}
TEST(CSSTransform, translate3d_missing_value) {
auto val = parseCSSProperty<CSSTransformFunction>("translate3d(4rem, 20%)");
EXPECT_TRUE(std::holds_alternative<std::monostate>(val));
}
TEST(CSSTransform, translate3d_extra_value) {
auto val =
parseCSSProperty<CSSTransformFunction>("ranslate3d(4rem, 20%, 2px, 6in)");
EXPECT_TRUE(std::holds_alternative<std::monostate>(val));
}
TEST(CSSTransform, translate3d_numbers) {
auto val = parseCSSProperty<CSSTransformFunction>("ranslate3d(4, 20, 2)");
EXPECT_TRUE(std::holds_alternative<std::monostate>(val));
}
TEST(CSSTransform, translate_x_length) {
auto val = parseCSSProperty<CSSTransformFunction>("translateX(900pt)");
EXPECT_TRUE(std::holds_alternative<CSSTranslateX>(val));
auto& translate = std::get<CSSTranslateX>(val);
EXPECT_TRUE(std::holds_alternative<CSSLength>(translate.value));
EXPECT_EQ(std::get<CSSLength>(translate.value).value, 900.0f);
EXPECT_EQ(std::get<CSSLength>(translate.value).unit, CSSLengthUnit::Pt);
}
TEST(CSSTransform, translate_x_pct) {
auto val = parseCSSProperty<CSSTransformFunction>("translateX(420%)");
EXPECT_TRUE(std::holds_alternative<CSSTranslateX>(val));
auto& translate = std::get<CSSTranslateX>(val);
EXPECT_TRUE(std::holds_alternative<CSSPercentage>(translate.value));
EXPECT_EQ(std::get<CSSPercentage>(translate.value).value, 420.0f);
}
TEST(CSSTransform, translate_x_funky) {
auto val = parseCSSProperty<CSSTransformFunction>("transLaTeX(420%)");
EXPECT_TRUE(std::holds_alternative<CSSTranslateX>(val));
auto& translate = std::get<CSSTranslateX>(val);
EXPECT_TRUE(std::holds_alternative<CSSPercentage>(translate.value));
EXPECT_EQ(std::get<CSSPercentage>(translate.value).value, 420.0f);
}
TEST(CSSTransform, translate_x_missing_value) {
auto val = parseCSSProperty<CSSTransformFunction>("transLaTeX()");
EXPECT_TRUE(std::holds_alternative<std::monostate>(val));
}
TEST(CSSTransform, translate_x_extra_value) {
auto val = parseCSSProperty<CSSTransformFunction>("transLaTeX(123cm, 45px)");
EXPECT_TRUE(std::holds_alternative<std::monostate>(val));
}
TEST(CSSTransform, translate_x_number) {
auto val = parseCSSProperty<CSSTransformFunction>("transLaTeX(456)");
EXPECT_TRUE(std::holds_alternative<std::monostate>(val));
}
TEST(CSSTransform, translate_y_length) {
auto val = parseCSSProperty<CSSTransformFunction>("translateY(900pt)");
EXPECT_TRUE(std::holds_alternative<CSSTranslateY>(val));
auto& translate = std::get<CSSTranslateY>(val);
EXPECT_TRUE(std::holds_alternative<CSSLength>(translate.value));
EXPECT_EQ(std::get<CSSLength>(translate.value).value, 900.0f);
EXPECT_EQ(std::get<CSSLength>(translate.value).unit, CSSLengthUnit::Pt);
}
TEST(CSSTransform, translate_y_pct) {
auto val = parseCSSProperty<CSSTransformFunction>("translateY(420%)");
EXPECT_TRUE(std::holds_alternative<CSSTranslateY>(val));
auto& translate = std::get<CSSTranslateY>(val);
EXPECT_TRUE(std::holds_alternative<CSSPercentage>(translate.value));
EXPECT_EQ(std::get<CSSPercentage>(translate.value).value, 420.0f);
}
TEST(CSSTransform, translate_y_funky) {
auto val = parseCSSProperty<CSSTransformFunction>("transLaTeY(420%)");
EXPECT_TRUE(std::holds_alternative<CSSTranslateY>(val));
auto& translate = std::get<CSSTranslateY>(val);
EXPECT_TRUE(std::holds_alternative<CSSPercentage>(translate.value));
EXPECT_EQ(std::get<CSSPercentage>(translate.value).value, 420.0f);
}
TEST(CSSTransform, translate_y_missing_value) {
auto val = parseCSSProperty<CSSTransformFunction>("transLaTeY()");
EXPECT_TRUE(std::holds_alternative<std::monostate>(val));
}
TEST(CSSTransform, translate_y_eytra_value) {
auto val = parseCSSProperty<CSSTransformFunction>("transLaTeY(123cm, 45py)");
EXPECT_TRUE(std::holds_alternative<std::monostate>(val));
}
TEST(CSSTransform, translate_y_number) {
auto val = parseCSSProperty<CSSTransformFunction>("transLaTeY(456)");
EXPECT_TRUE(std::holds_alternative<std::monostate>(val));
}
TEST(CSSTransform, scale_basic) {
auto val = parseCSSProperty<CSSTransformFunction>("scale(0.9, 9001%)");
EXPECT_TRUE(std::holds_alternative<CSSScale>(val));
auto& scale = std::get<CSSScale>(val);
EXPECT_EQ(scale.x, 0.9f);
EXPECT_EQ(scale.y, 90.01f);
}
TEST(CSSTransform, scale_single_value) {
auto val = parseCSSProperty<CSSTransformFunction>("scale(2.0)");
EXPECT_TRUE(std::holds_alternative<CSSScale>(val));
auto& scale = std::get<CSSScale>(val);
EXPECT_EQ(scale.x, 2.0f);
EXPECT_EQ(scale.y, 2.0f);
}
TEST(CSSTransform, scale_funky) {
auto val = parseCSSProperty<CSSTransformFunction>("sCale( 0.9, 9001%)");
EXPECT_TRUE(std::holds_alternative<CSSScale>(val));
auto& scale = std::get<CSSScale>(val);
EXPECT_EQ(scale.x, 0.9f);
EXPECT_EQ(scale.y, 90.01f);
}
TEST(CSSTransform, scale_missing_value) {
auto val = parseCSSProperty<CSSTransformFunction>("scale()");
EXPECT_TRUE(std::holds_alternative<std::monostate>(val));
}
TEST(CSSTransform, scale_extra_value) {
auto val = parseCSSProperty<CSSTransformFunction>("scale(0.9, 9001%, 1.0)");
EXPECT_TRUE(std::holds_alternative<std::monostate>(val));
}
TEST(CSSTransform, scale_length) {
auto val = parseCSSProperty<CSSTransformFunction>("scale(0.9, 9001pt)");
EXPECT_TRUE(std::holds_alternative<std::monostate>(val));
}
TEST(CSSTransform, scale_x_number) {
auto val = parseCSSProperty<CSSTransformFunction>("scaleX(50)");
EXPECT_TRUE(std::holds_alternative<CSSScaleX>(val));
auto& scaleX = std::get<CSSScaleX>(val);
EXPECT_EQ(scaleX.value, 50.0f);
}
TEST(CSSTransform, scale_x_pct) {
auto val = parseCSSProperty<CSSTransformFunction>("scaleX(50%)");
EXPECT_TRUE(std::holds_alternative<CSSScaleX>(val));
auto& scaleX = std::get<CSSScaleX>(val);
EXPECT_EQ(scaleX.value, 0.5f);
}
TEST(CSSTransform, scale_x_funky) {
auto val = parseCSSProperty<CSSTransformFunction>("scaLeX(50%)");
EXPECT_TRUE(std::holds_alternative<CSSScaleX>(val));
auto& scaleX = std::get<CSSScaleX>(val);
EXPECT_EQ(scaleX.value, 0.5f);
}
TEST(CSSTransform, scale_x_missing_value) {
auto val = parseCSSProperty<CSSTransformFunction>("scaLeX()");
EXPECT_TRUE(std::holds_alternative<std::monostate>(val));
}
TEST(CSSTransform, scale_x_extra_value) {
auto val = parseCSSProperty<CSSTransformFunction>("scaLeX(50%, 50%)");
EXPECT_TRUE(std::holds_alternative<std::monostate>(val));
}
TEST(CSSTransform, scale_x_length) {
auto val = parseCSSProperty<CSSTransformFunction>("scaLeX(50pt)");
EXPECT_TRUE(std::holds_alternative<std::monostate>(val));
}
TEST(CSSTransform, scale_y_number) {
auto val = parseCSSProperty<CSSTransformFunction>("scaleY(50)");
EXPECT_TRUE(std::holds_alternative<CSSScaleY>(val));
auto& scaleY = std::get<CSSScaleY>(val);
EXPECT_EQ(scaleY.value, 50.0f);
}
TEST(CSSTransform, scale_y_pct) {
auto val = parseCSSProperty<CSSTransformFunction>("scaleY(50%)");
EXPECT_TRUE(std::holds_alternative<CSSScaleY>(val));
auto& scaleY = std::get<CSSScaleY>(val);
EXPECT_EQ(scaleY.value, 0.5f);
}
TEST(CSSTransform, scale_y_funky) {
auto val = parseCSSProperty<CSSTransformFunction>("scaLeY(50%)");
EXPECT_TRUE(std::holds_alternative<CSSScaleY>(val));
auto& scaleY = std::get<CSSScaleY>(val);
EXPECT_EQ(scaleY.value, 0.5f);
}
TEST(CSSTransform, scale_y_missing_value) {
auto val = parseCSSProperty<CSSTransformFunction>("scaLeY()");
EXPECT_TRUE(std::holds_alternative<std::monostate>(val));
}
TEST(CSSTransform, scale_y_eytra_value) {
auto val = parseCSSProperty<CSSTransformFunction>("scaLeY(50%, 50%)");
EXPECT_TRUE(std::holds_alternative<std::monostate>(val));
}
TEST(CSSTransform, scale_y_length) {
auto val = parseCSSProperty<CSSTransformFunction>("scaLeY(50pt)");
EXPECT_TRUE(std::holds_alternative<std::monostate>(val));
}
TEST(CSSTransform, rotate_basic) {
auto val = parseCSSProperty<CSSTransformFunction>("rotate(90deg)");
EXPECT_TRUE(std::holds_alternative<CSSRotate>(val));
auto& rotate = std::get<CSSRotate>(val);
EXPECT_EQ(rotate.degrees, 90.0f);
}
TEST(CSSTransform, rotate_turn) {
auto val = parseCSSProperty<CSSTransformFunction>("rotate(1turn)");
EXPECT_TRUE(std::holds_alternative<CSSRotate>(val));
auto& rotate = std::get<CSSRotate>(val);
EXPECT_EQ(rotate.degrees, 360.0f);
}
TEST(CSSTransform, rotate_zero) {
auto val = parseCSSProperty<CSSTransformFunction>("rotate(0)");
EXPECT_TRUE(std::holds_alternative<CSSRotate>(val));
auto& rotate = std::get<CSSRotate>(val);
EXPECT_EQ(rotate.degrees, 0.0f);
}
TEST(CSSTransform, rotate_z) {
auto val = parseCSSProperty<CSSTransformFunction>("rotateZ(90deg)");
EXPECT_TRUE(std::holds_alternative<CSSRotateZ>(val));
auto& rotate = std::get<CSSRotateZ>(val);
EXPECT_EQ(rotate.degrees, 90.0f);
}
TEST(CSSTransform, rotate_funky) {
auto val = parseCSSProperty<CSSTransformFunction>("roTate(90deg)");
EXPECT_TRUE(std::holds_alternative<CSSRotate>(val));
auto& rotate = std::get<CSSRotate>(val);
EXPECT_EQ(rotate.degrees, 90.0f);
}
TEST(CSSTransform, rotate_missing_value) {
auto val = parseCSSProperty<CSSTransformFunction>("roTate()");
EXPECT_TRUE(std::holds_alternative<std::monostate>(val));
}
TEST(CSSTransform, rotate_extra_value) {
auto val = parseCSSProperty<CSSTransformFunction>("roTate(90deg, 90deg)");
EXPECT_TRUE(std::holds_alternative<std::monostate>(val));
}
TEST(CSSTransform, rotate_number) {
auto val = parseCSSProperty<CSSTransformFunction>("roTate(90)");
EXPECT_TRUE(std::holds_alternative<std::monostate>(val));
}
TEST(CSSTransform, rotate_x_basic) {
auto val = parseCSSProperty<CSSTransformFunction>("rotateX(90deg)");
EXPECT_TRUE(std::holds_alternative<CSSRotateX>(val));
auto& rotate = std::get<CSSRotateX>(val);
EXPECT_EQ(rotate.degrees, 90.0f);
}
TEST(CSSTransform, rotate_x_turn) {
auto val = parseCSSProperty<CSSTransformFunction>("rotateX(1turn)");
EXPECT_TRUE(std::holds_alternative<CSSRotateX>(val));
auto& rotate = std::get<CSSRotateX>(val);
EXPECT_EQ(rotate.degrees, 360.0f);
}
TEST(CSSTransform, rotate_x_zero) {
auto val = parseCSSProperty<CSSTransformFunction>("rotateX(0)");
EXPECT_TRUE(std::holds_alternative<CSSRotateX>(val));
auto& rotate = std::get<CSSRotateX>(val);
EXPECT_EQ(rotate.degrees, 0.0f);
}
TEST(CSSTransform, rotate_x_funky) {
auto val = parseCSSProperty<CSSTransformFunction>("roTateX(90deg)");
EXPECT_TRUE(std::holds_alternative<CSSRotateX>(val));
auto& rotate = std::get<CSSRotateX>(val);
EXPECT_EQ(rotate.degrees, 90.0f);
}
TEST(CSSTransform, rotate_x_missing_value) {
auto val = parseCSSProperty<CSSTransformFunction>("roTateX()");
EXPECT_TRUE(std::holds_alternative<std::monostate>(val));
}
TEST(CSSTransform, rotate_x_extra_value) {
auto val = parseCSSProperty<CSSTransformFunction>("roTateX(90deg, 90deg)");
EXPECT_TRUE(std::holds_alternative<std::monostate>(val));
}
TEST(CSSTransform, rotate_x_number) {
auto val = parseCSSProperty<CSSTransformFunction>("roTateX(90)");
EXPECT_TRUE(std::holds_alternative<std::monostate>(val));
}
TEST(CSSTransform, rotate_y_basic) {
auto val = parseCSSProperty<CSSTransformFunction>("rotateY(90deg)");
EXPECT_TRUE(std::holds_alternative<CSSRotateY>(val));
auto& rotate = std::get<CSSRotateY>(val);
EXPECT_EQ(rotate.degrees, 90.0f);
}
TEST(CSSTransform, rotate_y_turn) {
auto val = parseCSSProperty<CSSTransformFunction>("rotateY(1turn)");
EXPECT_TRUE(std::holds_alternative<CSSRotateY>(val));
auto& rotate = std::get<CSSRotateY>(val);
EXPECT_EQ(rotate.degrees, 360.0f);
}
TEST(CSSTransform, rotate_y_zero) {
auto val = parseCSSProperty<CSSTransformFunction>("rotateY(0)");
EXPECT_TRUE(std::holds_alternative<CSSRotateY>(val));
auto& rotate = std::get<CSSRotateY>(val);
EXPECT_EQ(rotate.degrees, 0.0f);
}
TEST(CSSTransform, rotate_y_funky) {
auto val = parseCSSProperty<CSSTransformFunction>("roTateY(90deg)");
EXPECT_TRUE(std::holds_alternative<CSSRotateY>(val));
auto& rotate = std::get<CSSRotateY>(val);
EXPECT_EQ(rotate.degrees, 90.0f);
}
TEST(CSSTransform, rotate_y_missing_value) {
auto val = parseCSSProperty<CSSTransformFunction>("roTateY()");
EXPECT_TRUE(std::holds_alternative<std::monostate>(val));
}
TEST(CSSTransform, rotate_y_extra_value) {
auto val = parseCSSProperty<CSSTransformFunction>("roTateY(90deg, 90deg)");
EXPECT_TRUE(std::holds_alternative<std::monostate>(val));
}
TEST(CSSTransform, rotate_y_number) {
auto val = parseCSSProperty<CSSTransformFunction>("roTateY(90)");
EXPECT_TRUE(std::holds_alternative<std::monostate>(val));
}
TEST(CSSTransform, skew_x_basic) {
auto val = parseCSSProperty<CSSTransformFunction>("skewX(90deg)");
EXPECT_TRUE(std::holds_alternative<CSSSkewX>(val));
auto& skew = std::get<CSSSkewX>(val);
EXPECT_EQ(skew.degrees, 90.0f);
}
TEST(CSSTransform, skew_x_turn) {
auto val = parseCSSProperty<CSSTransformFunction>("skewX(1turn)");
EXPECT_TRUE(std::holds_alternative<CSSSkewX>(val));
auto& skew = std::get<CSSSkewX>(val);
EXPECT_EQ(skew.degrees, 360.0f);
}
TEST(CSSTransform, skew_x_zero) {
auto val = parseCSSProperty<CSSTransformFunction>("skewX(0)");
EXPECT_TRUE(std::holds_alternative<CSSSkewX>(val));
auto& skew = std::get<CSSSkewX>(val);
EXPECT_EQ(skew.degrees, 0.0f);
}
TEST(CSSTransform, skew_x_funky) {
auto val = parseCSSProperty<CSSTransformFunction>("skeWx(90deg)");
EXPECT_TRUE(std::holds_alternative<CSSSkewX>(val));
auto& skew = std::get<CSSSkewX>(val);
EXPECT_EQ(skew.degrees, 90.0f);
}
TEST(CSSTransform, skew_x_missing_value) {
auto val = parseCSSProperty<CSSTransformFunction>("skeWx()");
EXPECT_TRUE(std::holds_alternative<std::monostate>(val));
}
TEST(CSSTransform, skew_x_extra_value) {
auto val = parseCSSProperty<CSSTransformFunction>("skeWx(90deg, 90deg)");
EXPECT_TRUE(std::holds_alternative<std::monostate>(val));
}
TEST(CSSTransform, skew_x_number) {
auto val = parseCSSProperty<CSSTransformFunction>("skeWx(90)");
EXPECT_TRUE(std::holds_alternative<std::monostate>(val));
}
TEST(CSSTransform, skew_y_basic) {
auto val = parseCSSProperty<CSSTransformFunction>("skewY(90deg)");
EXPECT_TRUE(std::holds_alternative<CSSSkewY>(val));
auto& skew = std::get<CSSSkewY>(val);
EXPECT_EQ(skew.degrees, 90.0f);
}
TEST(CSSTransform, skew_y_turn) {
auto val = parseCSSProperty<CSSTransformFunction>("skewY(1turn)");
EXPECT_TRUE(std::holds_alternative<CSSSkewY>(val));
auto& skew = std::get<CSSSkewY>(val);
EXPECT_EQ(skew.degrees, 360.0f);
}
TEST(CSSTransform, skew_y_zero) {
auto val = parseCSSProperty<CSSTransformFunction>("skewY(0)");
EXPECT_TRUE(std::holds_alternative<CSSSkewY>(val));
auto& skew = std::get<CSSSkewY>(val);
EXPECT_EQ(skew.degrees, 0.0f);
}
TEST(CSSTransform, skew_y_funky) {
auto val = parseCSSProperty<CSSTransformFunction>("skeWy(90deg)");
EXPECT_TRUE(std::holds_alternative<CSSSkewY>(val));
auto& skew = std::get<CSSSkewY>(val);
EXPECT_EQ(skew.degrees, 90.0f);
}
TEST(CSSTransform, skew_y_missing_value) {
auto val = parseCSSProperty<CSSTransformFunction>("skeWy()");
EXPECT_TRUE(std::holds_alternative<std::monostate>(val));
}
TEST(CSSTransform, skew_y_extra_value) {
auto val = parseCSSProperty<CSSTransformFunction>("skeWy(90deg, 90deg)");
EXPECT_TRUE(std::holds_alternative<std::monostate>(val));
}
TEST(CSSTransform, skew_y_number) {
auto val = parseCSSProperty<CSSTransformFunction>("skeWy(90)");
EXPECT_TRUE(std::holds_alternative<std::monostate>(val));
}
TEST(CSSTransform, perspective_basic) {
auto val = parseCSSProperty<CSSTransformFunction>("perspective(1000px)");
EXPECT_TRUE(std::holds_alternative<CSSPerspective>(val));
auto& perspective = std::get<CSSPerspective>(val);
EXPECT_EQ(perspective.length.value, 1000.0f);
EXPECT_EQ(perspective.length.unit, CSSLengthUnit::Px);
}
TEST(CSSTransform, perspective_zero) {
auto val = parseCSSProperty<CSSTransformFunction>("perspective(0)");
EXPECT_TRUE(std::holds_alternative<CSSPerspective>(val));
auto& perspective = std::get<CSSPerspective>(val);
EXPECT_EQ(perspective.length.value, 0.0f);
EXPECT_EQ(perspective.length.unit, CSSLengthUnit::Px);
}
TEST(CSSTransform, perspective_negative) {
auto val = parseCSSProperty<CSSTransformFunction>("perspective(-1000px)");
EXPECT_TRUE(std::holds_alternative<std::monostate>(val));
}
TEST(CSSTransform, perspective_funky) {
auto val = parseCSSProperty<CSSTransformFunction>("perspectivE(1000px)");
EXPECT_TRUE(std::holds_alternative<CSSPerspective>(val));
auto& perspective = std::get<CSSPerspective>(val);
EXPECT_EQ(perspective.length.value, 1000.0f);
EXPECT_EQ(perspective.length.unit, CSSLengthUnit::Px);
}
TEST(CSSTransform, perspective_missing_value) {
auto val = parseCSSProperty<CSSTransformFunction>("perspectivE()");
EXPECT_TRUE(std::holds_alternative<std::monostate>(val));
}
TEST(CSSTransform, perspective_extra_value) {
auto val =
parseCSSProperty<CSSTransformFunction>("perspectivE(1000px, 1000px)");
EXPECT_TRUE(std::holds_alternative<std::monostate>(val));
}
TEST(CSSTransform, perspective_number) {
auto val = parseCSSProperty<CSSTransformFunction>("perspectivE(1000)");
EXPECT_TRUE(std::holds_alternative<std::monostate>(val));
}
TEST(CSSTransform, transform_list) {
auto val = parseCSSProperty<CSSTransformList>(
"translate(100px, 200px) rotate(90deg) scale(2)");
EXPECT_TRUE(std::holds_alternative<CSSTransformList>(val));
auto& transformList = std::get<CSSTransformList>(val);
EXPECT_EQ(transformList.size(), 3);
EXPECT_TRUE(std::holds_alternative<CSSTranslate>(transformList[0]));
EXPECT_TRUE(std::holds_alternative<CSSRotate>(transformList[1]));
EXPECT_TRUE(std::holds_alternative<CSSScale>(transformList[2]));
auto& translate = std::get<CSSTranslate>(transformList[0]);
EXPECT_TRUE(std::holds_alternative<CSSLength>(translate.x));
EXPECT_TRUE(std::holds_alternative<CSSLength>(translate.y));
EXPECT_EQ(std::get<CSSLength>(translate.x).value, 100.0f);
EXPECT_EQ(std::get<CSSLength>(translate.y).value, 200.0f);
EXPECT_EQ(std::get<CSSLength>(translate.x).unit, CSSLengthUnit::Px);
EXPECT_EQ(std::get<CSSLength>(translate.y).unit, CSSLengthUnit::Px);
auto& rotate = std::get<CSSRotate>(transformList[1]);
EXPECT_EQ(rotate.degrees, 90.0f);
auto& scale = std::get<CSSScale>(transformList[2]);
EXPECT_EQ(scale.x, 2.0f);
EXPECT_EQ(scale.y, 2.0f);
}
TEST(CSSTransform, transform_list_comma_delimeter) {
auto val = parseCSSProperty<CSSTransformList>(
"translate(100px, 200px), rotate(90deg), scale(2)");
EXPECT_TRUE(std::holds_alternative<std::monostate>(val));
}
TEST(CSSTransform, transform_list_empty) {
auto val = parseCSSProperty<CSSTransformList>("");
EXPECT_TRUE(std::holds_alternative<std::monostate>(val));
}
} // namespace facebook::react

View File

@@ -0,0 +1,66 @@
/*
* Copyright (c) Meta Platforms, Inc. and affiliates.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*/
#include <gtest/gtest.h>
#include <react/renderer/css/CSSDataType.h>
#include <react/renderer/css/CSSNumber.h>
#include <react/renderer/css/CSSValueParser.h>
namespace facebook::react {
struct ConsumeDataType {
float number{};
constexpr bool operator==(const ConsumeDataType& other) const = default;
};
template <>
struct CSSDataTypeParser<ConsumeDataType> {
constexpr static std::optional<ConsumeDataType> consume(
CSSSyntaxParser& parser) {
auto val = parseNextCSSValue<CSSNumber>(parser);
if (std::holds_alternative<CSSNumber>(val)) {
return ConsumeDataType{std::get<CSSNumber>(val).value};
}
return {};
}
};
static_assert(CSSDataType<ConsumeDataType>);
TEST(CSSValueParser, consume_multiple_with_delimeter) {
CSSSyntaxParser parser{"1 2, 3, 4 / 5"};
auto next = parseNextCSSValue<ConsumeDataType>(parser);
EXPECT_TRUE(std::holds_alternative<ConsumeDataType>(next));
EXPECT_EQ(std::get<ConsumeDataType>(next).number, 1);
next = parseNextCSSValue<ConsumeDataType>(parser, CSSDelimiter::None);
EXPECT_FALSE(std::holds_alternative<ConsumeDataType>(next));
next = parseNextCSSValue<ConsumeDataType>(parser, CSSDelimiter::Whitespace);
EXPECT_TRUE(std::holds_alternative<ConsumeDataType>(next));
EXPECT_EQ(std::get<ConsumeDataType>(next).number, 2);
next = parseNextCSSValue<ConsumeDataType>(parser, CSSDelimiter::Comma);
EXPECT_TRUE(std::holds_alternative<ConsumeDataType>(next));
EXPECT_EQ(std::get<ConsumeDataType>(next).number, 3);
next = parseNextCSSValue<ConsumeDataType>(parser, CSSDelimiter::Comma);
EXPECT_TRUE(std::holds_alternative<ConsumeDataType>(next));
EXPECT_EQ(std::get<ConsumeDataType>(next).number, 4);
next = parseNextCSSValue<ConsumeDataType>(parser, CSSDelimiter::Solidus);
EXPECT_TRUE(std::holds_alternative<ConsumeDataType>(next));
EXPECT_EQ(std::get<ConsumeDataType>(next).number, 5);
next = parseNextCSSValue<ConsumeDataType>(parser);
EXPECT_FALSE(std::holds_alternative<ConsumeDataType>(next));
}
} // namespace facebook::react