563 lines
19 KiB
C++
563 lines
19 KiB
C++
/*
|
|
* 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
|