Files
react-native/packages/react-native/ReactCommon/react/renderer/components/view/tests/CSSTokenizerTest.cpp
T
Nick GerlemanandFacebook GitHub Bot bc6105016c Add standards based lexer/tokenizer for CSS values (#42626)
Summary:
Pull Request resolved: https://github.com/facebook/react-native/pull/42626

Right now this is done by some combination of string splitting, JS side regexing, etc. This will not scale for math expressions, and gets more and more annoying when we try to add more.

In preparation for adding more units, this adds a tokenizer/lexer for a subset of CSS grammar, based on the spec. This is not hooked up to anything yet, and doesn't add a parser.

The algorithm uses a subset of the comprehensive instructions provided at https://www.w3.org/TR/css-syntax-3/#tokenizer-algorithms as a reference, with some major simplifications.

Changelog: [Internal]

Reviewed By: joevilches

Differential Revision: D53030661

fbshipit-source-id: c48bc572c5e02daee0b05e91830f2441528193d1
2024-01-29 17:47:30 -08:00

145 lines
3.8 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/components/view/CSSTokenizer.h>
#include <deque>
namespace facebook::react {
static void expectTokens(
std::string_view characters,
std::initializer_list<CSSToken> expectedTokens) {
CSSTokenizer tokenizer{characters};
for (const auto& expectedToken : expectedTokens) {
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) {
expectTokens("", {CSSToken{CSSTokenType::EndOfFile}});
}
TEST(CSSTokenizer, whitespace_values) {
expectTokens(
" ",
{CSSToken{CSSTokenType::WhiteSpace}, CSSToken{CSSTokenType::EndOfFile}});
expectTokens(
" \t",
{CSSToken{CSSTokenType::WhiteSpace}, CSSToken{CSSTokenType::EndOfFile}});
expectTokens(
"\n \t",
{CSSToken{CSSTokenType::WhiteSpace}, CSSToken{CSSTokenType::EndOfFile}});
}
TEST(CSSTokenizer, ident_values) {
expectTokens(
"auto",
{CSSToken{CSSTokenType::Ident, "auto"},
CSSToken{CSSTokenType::EndOfFile}});
expectTokens(
"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) {
expectTokens(
"12",
{CSSToken{CSSTokenType::Number, 12.0f},
CSSToken{CSSTokenType::EndOfFile}});
expectTokens(
"-5",
{CSSToken{CSSTokenType::Number, -5.0f},
CSSToken{CSSTokenType::EndOfFile}});
expectTokens(
"123.0",
{CSSToken{CSSTokenType::Number, 123.0f},
CSSToken{CSSTokenType::EndOfFile}});
expectTokens(
"4.2E-1",
{CSSToken{CSSTokenType::Number, 4.2e-1},
CSSToken{CSSTokenType::EndOfFile}});
expectTokens(
"6e-10",
{CSSToken{CSSTokenType::Number, 6e-10f},
CSSToken{CSSTokenType::EndOfFile}});
expectTokens(
"+81.07e+0",
{CSSToken{CSSTokenType::Number, +81.07e+0},
CSSToken{CSSTokenType::EndOfFile}});
}
TEST(CSSTokenizer, dimension_values) {
expectTokens(
"12px",
{CSSToken{CSSTokenType::Dimension, 12.0f, "px"},
CSSToken{CSSTokenType::EndOfFile}});
expectTokens(
"463.2abc",
{CSSToken{CSSTokenType::Dimension, 463.2, "abc"},
CSSToken{CSSTokenType::EndOfFile}});
}
TEST(CSSTokenizer, percent_values) {
expectTokens(
"12%",
{CSSToken{CSSTokenType::Percent, 12.0f},
CSSToken{CSSTokenType::EndOfFile}});
expectTokens(
"-28.5%",
{CSSToken{CSSTokenType::Percent, -28.5f},
CSSToken{CSSTokenType::EndOfFile}});
}
TEST(CSSTokenizer, mixed_values) {
expectTokens(
"12px -100vh",
{CSSToken{CSSTokenType::Dimension, 12.0f, "px"},
CSSToken{CSSTokenType::WhiteSpace},
CSSToken{CSSTokenType::Dimension, -100.0f, "vh"},
CSSToken{CSSTokenType::EndOfFile}});
}
TEST(CSSTokenizer, invalid_values) {
expectTokens(
"100*",
{CSSToken{CSSTokenType::Number, 100.0f},
CSSToken{CSSTokenType::Delim, "*"},
CSSToken{CSSTokenType::EndOfFile}});
expectTokens(
"+",
{CSSToken{CSSTokenType::Delim, "+"}, CSSToken{CSSTokenType::EndOfFile}});
expectTokens(
"(%",
{CSSToken{CSSTokenType::Delim, "("},
CSSToken{CSSTokenType::Delim, "%"},
CSSToken{CSSTokenType::EndOfFile}});
}
} // namespace facebook::react