blob: 3f5eaccbac80fab247ebc8df25640d9b7068656c [file] [log] [blame]
// Copyright 2016 PDFium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "xfa/fxfa/fm2js/cxfa_fmlexer.h"
#include <memory>
#include <vector>
#include "testing/gtest/include/gtest/gtest.h"
#include "third_party/base/stl_util.h"
TEST(CXFA_FMLexerTest, NullString) {
WideStringView null_string;
CXFA_FMLexer lexer(null_string);
CXFA_FMToken token = lexer.NextToken();
EXPECT_EQ(TOKeof, token.m_type);
EXPECT_TRUE(lexer.IsComplete());
}
TEST(CXFA_FMLexerTest, EmptyString) {
CXFA_FMLexer lexer(L"");
CXFA_FMToken token = lexer.NextToken();
EXPECT_EQ(TOKeof, token.m_type);
EXPECT_TRUE(lexer.IsComplete());
}
TEST(CXFA_FMLexerTest, Numbers) {
{
CXFA_FMLexer lexer(L"-12");
CXFA_FMToken token = lexer.NextToken();
// TODO(dsinclair): Should this return -12 instead of two tokens?
EXPECT_EQ(TOKminus, token.m_type);
token = lexer.NextToken();
EXPECT_EQ(L"12", token.m_string);
token = lexer.NextToken();
EXPECT_EQ(TOKeof, token.m_type);
}
{
CXFA_FMLexer lexer(L"1.5362");
CXFA_FMToken token = lexer.NextToken();
EXPECT_EQ(TOKnumber, token.m_type);
EXPECT_EQ(L"1.5362", token.m_string);
}
{
CXFA_FMLexer lexer(L"0.875");
CXFA_FMToken token = lexer.NextToken();
EXPECT_EQ(TOKnumber, token.m_type);
EXPECT_EQ(L"0.875", token.m_string);
}
{
CXFA_FMLexer lexer(L"5.56e-2");
CXFA_FMToken token = lexer.NextToken();
EXPECT_EQ(TOKnumber, token.m_type);
EXPECT_EQ(L"5.56e-2", token.m_string);
}
{
CXFA_FMLexer lexer(L"1.234E10");
CXFA_FMToken token = lexer.NextToken();
EXPECT_EQ(TOKnumber, token.m_type);
EXPECT_EQ(L"1.234E10", token.m_string);
}
{
CXFA_FMLexer lexer(L"123456789.012345678");
CXFA_FMToken token = lexer.NextToken();
EXPECT_EQ(TOKnumber, token.m_type);
// TODO(dsinclair): This should round as per IEEE 64-bit values.
// EXPECT_EQ(L"123456789.01234567", token.m_string);
EXPECT_EQ(L"123456789.012345678", token.m_string);
}
{
CXFA_FMLexer lexer(L"99999999999999999");
CXFA_FMToken token = lexer.NextToken();
EXPECT_EQ(TOKnumber, token.m_type);
// TODO(dsinclair): This is spec'd as rounding when > 16 significant digits
// prior to the exponent.
// EXPECT_EQ(L"100000000000000000", token.m_string);
EXPECT_EQ(L"99999999999999999", token.m_string);
EXPECT_TRUE(lexer.IsComplete());
}
}
// The quotes are stripped in CXFA_FMStringExpression::ToJavaScript.
TEST(CXFA_FMLexerTest, Strings) {
{
CXFA_FMLexer lexer(L"\"The cat jumped over the fence.\"");
CXFA_FMToken token = lexer.NextToken();
EXPECT_EQ(TOKstring, token.m_type);
EXPECT_EQ(L"\"The cat jumped over the fence.\"", token.m_string);
token = lexer.NextToken();
EXPECT_EQ(TOKeof, token.m_type);
}
{
CXFA_FMLexer lexer(L"\"\"");
CXFA_FMToken token = lexer.NextToken();
EXPECT_EQ(TOKstring, token.m_type);
EXPECT_EQ(L"\"\"", token.m_string);
}
{
CXFA_FMLexer lexer(
L"\"The message reads: \"\"Warning: Insufficient Memory\"\"\"");
CXFA_FMToken token = lexer.NextToken();
EXPECT_EQ(TOKstring, token.m_type);
EXPECT_EQ(L"\"The message reads: \"\"Warning: Insufficient Memory\"\"\"",
token.m_string);
}
{
CXFA_FMLexer lexer(
L"\"\\u0047\\u006f\\u0066\\u0069\\u0073\\u0068\\u0021\\u000d\\u000a\"");
CXFA_FMToken token = lexer.NextToken();
EXPECT_EQ(TOKstring, token.m_type);
EXPECT_EQ(
L"\"\\u0047\\u006f\\u0066\\u0069\\u0073\\u0068\\u0021\\u000d\\u000a\"",
token.m_string);
EXPECT_TRUE(lexer.IsComplete());
}
}
// Note, 'this' is a keyword but is not matched by the lexer.
TEST(CXFA_FMLexerTest, OperatorsAndKeywords) {
struct {
const wchar_t* op;
XFA_FM_TOKEN token;
} op[] = {{L"+", TOKplus},
{L"/", TOKdiv},
{L"-", TOKminus},
{L"&", TOKand},
{L"|", TOKor},
{L"*", TOKmul},
{L"<", TOKlt},
{L">", TOKgt},
{L"==", TOKeq},
{L"<>", TOKne},
{L"<=", TOKle},
{L">=", TOKge},
{L"and", TOKksand},
{L"break", TOKbreak},
{L"continue", TOKcontinue},
{L"do", TOKdo},
{L"downto", TOKdownto},
{L"else", TOKelse},
{L"elseif", TOKelseif},
{L"end", TOKend},
{L"endfor", TOKendfor},
{L"endfunc", TOKendfunc},
{L"endif", TOKendif},
{L"endwhile", TOKendwhile},
{L"eq", TOKkseq},
{L"exit", TOKexit},
{L"for", TOKfor},
{L"foreach", TOKforeach},
{L"func", TOKfunc},
{L"ge", TOKksge},
{L"gt", TOKksgt},
{L"if", TOKif},
{L"in", TOKin},
{L"infinity", TOKinfinity},
{L"le", TOKksle},
{L"lt", TOKkslt},
{L"nan", TOKnan},
{L"ne", TOKksne},
{L"not", TOKksnot},
{L"null", TOKnull},
{L"or", TOKksor},
{L"return", TOKreturn},
{L"step", TOKstep},
{L"then", TOKthen},
{L"throw", TOKthrow},
{L"upto", TOKupto},
{L"var", TOKvar},
{L"while", TOKwhile},
// The following are defined but aren't in the spec.
{L"(", TOKlparen},
{L")", TOKrparen},
{L",", TOKcomma},
{L".", TOKdot},
{L"[", TOKlbracket},
{L"]", TOKrbracket},
{L"..", TOKdotdot},
{L".#", TOKdotscream},
{L".*", TOKdotstar}};
for (size_t i = 0; i < pdfium::size(op); ++i) {
CXFA_FMLexer lexer(op[i].op);
CXFA_FMToken token = lexer.NextToken();
EXPECT_EQ(op[i].token, token.m_type);
EXPECT_TRUE(lexer.IsComplete());
}
}
TEST(CXFA_FMLexerTest, Comments) {
{
CXFA_FMLexer lexer(L"// Empty.");
CXFA_FMToken token = lexer.NextToken();
EXPECT_EQ(TOKeof, token.m_type);
}
{
CXFA_FMLexer lexer(L"//");
CXFA_FMToken token = lexer.NextToken();
EXPECT_EQ(TOKeof, token.m_type);
}
{
CXFA_FMLexer lexer(L"123 // Empty.\n\"str\"");
CXFA_FMToken token = lexer.NextToken();
EXPECT_EQ(TOKnumber, token.m_type);
EXPECT_EQ(L"123", token.m_string);
token = lexer.NextToken();
EXPECT_EQ(TOKstring, token.m_type);
EXPECT_EQ(L"\"str\"", token.m_string);
token = lexer.NextToken();
EXPECT_EQ(TOKeof, token.m_type);
}
{
CXFA_FMLexer lexer(L";");
CXFA_FMToken token = lexer.NextToken();
EXPECT_EQ(TOKeof, token.m_type);
}
{
CXFA_FMLexer lexer(L"; Empty.");
CXFA_FMToken token = lexer.NextToken();
EXPECT_EQ(TOKeof, token.m_type);
}
{
CXFA_FMLexer lexer(L"123 ;Empty.\n\"str\"");
CXFA_FMToken token = lexer.NextToken();
EXPECT_EQ(TOKnumber, token.m_type);
EXPECT_EQ(L"123", token.m_string);
token = lexer.NextToken();
EXPECT_EQ(TOKstring, token.m_type);
EXPECT_EQ(L"\"str\"", token.m_string);
token = lexer.NextToken();
EXPECT_EQ(TOKeof, token.m_type);
EXPECT_TRUE(lexer.IsComplete());
}
}
TEST(CXFA_FMLexerTest, ValidIdentifiers) {
std::vector<const wchar_t*> identifiers = {
L"a", L"an_identifier", L"_ident", L"$ident", L"!ident", L"GetAddr"};
for (const auto* ident : identifiers) {
CXFA_FMLexer lexer(ident);
CXFA_FMToken token = lexer.NextToken();
EXPECT_EQ(TOKidentifier, token.m_type);
EXPECT_EQ(ident, token.m_string);
EXPECT_TRUE(lexer.IsComplete());
}
}
TEST(CXFA_FMLexerTest, InvalidIdentifiers) {
{
CXFA_FMLexer lexer(L"#a");
CXFA_FMToken token = lexer.NextToken();
EXPECT_EQ(TOKreserver, token.m_type);
}
{
CXFA_FMLexer lexer(L"1a");
CXFA_FMToken token = lexer.NextToken();
EXPECT_EQ(TOKreserver, token.m_type);
}
{
CXFA_FMLexer lexer(L"an@identifier");
CXFA_FMToken token = lexer.NextToken();
EXPECT_NE(TOKreserver, token.m_type);
token = lexer.NextToken();
EXPECT_EQ(TOKreserver, token.m_type);
token = lexer.NextToken();
EXPECT_EQ(TOKreserver, token.m_type);
}
{
CXFA_FMLexer lexer(L"_ident@");
CXFA_FMToken token = lexer.NextToken();
EXPECT_NE(TOKreserver, token.m_type);
token = lexer.NextToken();
EXPECT_EQ(TOKreserver, token.m_type);
EXPECT_FALSE(lexer.IsComplete());
}
}
TEST(CXFA_FMLexerTest, Whitespace) {
{
CXFA_FMLexer lexer(L" \t\xc\x9\xb");
CXFA_FMToken token = lexer.NextToken();
EXPECT_EQ(TOKeof, token.m_type);
}
{
CXFA_FMLexer lexer(L"123 \t\xc\x9\xb 456");
CXFA_FMToken token = lexer.NextToken();
EXPECT_EQ(TOKnumber, token.m_type);
EXPECT_EQ(L"123", token.m_string);
token = lexer.NextToken();
EXPECT_EQ(TOKnumber, token.m_type);
EXPECT_EQ(L"456", token.m_string);
token = lexer.NextToken();
EXPECT_EQ(TOKeof, token.m_type);
EXPECT_TRUE(lexer.IsComplete());
}
}
TEST(CXFA_FMLexerTest, NullData) {
CXFA_FMLexer lexer(WideStringView(L"\x2d\x32\x00\x2d\x32", 5));
CXFA_FMToken token = lexer.NextToken();
EXPECT_EQ(TOKminus, token.m_type);
token = lexer.NextToken();
EXPECT_EQ(TOKnumber, token.m_type);
EXPECT_EQ(L"2", token.m_string);
token = lexer.NextToken();
EXPECT_EQ(TOKeof, token.m_type);
EXPECT_FALSE(lexer.IsComplete());
}