From c559156da52805513e11b1b2a057001b6fa63f90 Mon Sep 17 00:00:00 2001 From: Dan Sinclair Date: Wed, 17 May 2017 09:39:04 -0400 Subject: Adding CXFA_Parse unittests MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This CL adds the beginning of unittests for the CXFA_Parse code. Change-Id: I06e556f1a35405bc683c536d390071917ee330a6 Reviewed-on: https://pdfium-review.googlesource.com/5556 Reviewed-by: Nicolás Peña Commit-Queue: dsinclair --- BUILD.gn | 3 +- testing/libfuzzer/pdf_fm2js_fuzzer.cc | 10 +-- xfa/fxfa/fm2js/cxfa_fm2jscontext.cpp | 16 +++- xfa/fxfa/fm2js/cxfa_fmexpression.h | 1 + xfa/fxfa/fm2js/cxfa_fmparse.cpp | 14 ++++ xfa/fxfa/fm2js/cxfa_fmparse.h | 5 +- xfa/fxfa/fm2js/cxfa_fmparse_unittest.cpp | 135 +++++++++++++++++++++++++++++++ xfa/fxfa/fm2js/cxfa_fmprogram.cpp | 40 --------- xfa/fxfa/fm2js/cxfa_fmprogram.h | 29 ------- 9 files changed, 170 insertions(+), 83 deletions(-) create mode 100644 xfa/fxfa/fm2js/cxfa_fmparse_unittest.cpp delete mode 100644 xfa/fxfa/fm2js/cxfa_fmprogram.cpp delete mode 100644 xfa/fxfa/fm2js/cxfa_fmprogram.h diff --git a/BUILD.gn b/BUILD.gn index 7b7e120526..b40acab3ad 100644 --- a/BUILD.gn +++ b/BUILD.gn @@ -1673,8 +1673,6 @@ if (pdf_enable_xfa) { "xfa/fxfa/fm2js/cxfa_fmlexer.h", "xfa/fxfa/fm2js/cxfa_fmparse.cpp", "xfa/fxfa/fm2js/cxfa_fmparse.h", - "xfa/fxfa/fm2js/cxfa_fmprogram.cpp", - "xfa/fxfa/fm2js/cxfa_fmprogram.h", "xfa/fxfa/fm2js/cxfa_fmsimpleexpression.cpp", "xfa/fxfa/fm2js/cxfa_fmsimpleexpression.h", "xfa/fxfa/fxfa.h", @@ -1911,6 +1909,7 @@ test("pdfium_unittests") { "xfa/fxfa/app/xfa_ffbarcode_unittest.cpp", "xfa/fxfa/cxfa_ffapp_unittest.cpp", "xfa/fxfa/fm2js/cxfa_fmlexer_unittest.cpp", + "xfa/fxfa/fm2js/cxfa_fmparse_unittest.cpp", "xfa/fxfa/fm2js/cxfa_fmsimpleexpression_unittest.cpp", "xfa/fxfa/parser/xfa_utils_unittest.cpp", ] diff --git a/testing/libfuzzer/pdf_fm2js_fuzzer.cc b/testing/libfuzzer/pdf_fm2js_fuzzer.cc index 8cc98fcf54..226fb4096e 100644 --- a/testing/libfuzzer/pdf_fm2js_fuzzer.cc +++ b/testing/libfuzzer/pdf_fm2js_fuzzer.cc @@ -8,20 +8,16 @@ #include "core/fxcrt/fx_basic.h" #include "core/fxcrt/fx_safe_types.h" #include "core/fxcrt/fx_string.h" -#include "xfa/fxfa/fm2js/cxfa_fmprogram.h" +#include "xfa/fxfa/fm2js/cxfa_fm2jscontext.h" extern "C" int LLVMFuzzerTestOneInput(const uint8_t* data, size_t size) { FX_SAFE_STRSIZE safe_size = size; if (!safe_size.IsValid()) return 0; + CFX_WideTextBuf js; CFX_WideString input = CFX_WideString::FromUTF8(CFX_ByteStringC(data, safe_size.ValueOrDie())); - CXFA_FMProgram program(input.AsStringC()); - if (!program.ParseProgram()) - return 0; - - CFX_WideTextBuf js; - program.TranslateProgram(js); + CXFA_FM2JSContext::Translate(input.AsStringC(), &js); return 0; } diff --git a/xfa/fxfa/fm2js/cxfa_fm2jscontext.cpp b/xfa/fxfa/fm2js/cxfa_fm2jscontext.cpp index c9c0f4a379..b074a9aa57 100644 --- a/xfa/fxfa/fm2js/cxfa_fm2jscontext.cpp +++ b/xfa/fxfa/fm2js/cxfa_fm2jscontext.cpp @@ -18,7 +18,7 @@ #include "third_party/base/ptr_util.h" #include "third_party/base/stl_util.h" #include "xfa/fxfa/app/xfa_ffnotify.h" -#include "xfa/fxfa/fm2js/cxfa_fmprogram.h" +#include "xfa/fxfa/fm2js/cxfa_fmparse.h" #include "xfa/fxfa/parser/cxfa_document.h" #include "xfa/fxfa/parser/cxfa_localevalue.h" #include "xfa/fxfa/parser/cxfa_node.h" @@ -6119,8 +6119,18 @@ bool CXFA_FM2JSContext::Translate(const CFX_WideStringC& wsFormcalc, return true; } - CXFA_FMProgram program(wsFormcalc); - return program.ParseProgram() && program.TranslateProgram(*wsJavascript); + CXFA_FMErrorInfo errorInfo; + CXFA_FMParse parser(wsFormcalc, &errorInfo); + + std::unique_ptr func = parser.Parse(); + if (!errorInfo.message.IsEmpty()) + return false; + + if (!func->ToJavaScript(*wsJavascript)) + return false; + + wsJavascript->AppendChar(0); + return true; } CXFA_FM2JSContext::CXFA_FM2JSContext(v8::Isolate* pScriptIsolate, diff --git a/xfa/fxfa/fm2js/cxfa_fmexpression.h b/xfa/fxfa/fm2js/cxfa_fmexpression.h index c04bc2f117..b2bbc43968 100644 --- a/xfa/fxfa/fm2js/cxfa_fmexpression.h +++ b/xfa/fxfa/fm2js/cxfa_fmexpression.h @@ -28,6 +28,7 @@ class CXFA_FMExpression { explicit CXFA_FMExpression(uint32_t line); CXFA_FMExpression(uint32_t line, XFA_FM_EXPTYPE type); virtual ~CXFA_FMExpression() {} + virtual bool ToJavaScript(CFX_WideTextBuf& javascript); virtual bool ToImpliedReturnJS(CFX_WideTextBuf&); uint32_t GetLine() { return m_line; } diff --git a/xfa/fxfa/fm2js/cxfa_fmparse.cpp b/xfa/fxfa/fm2js/cxfa_fmparse.cpp index cac7ad1b59..6e80a40d0c 100644 --- a/xfa/fxfa/fm2js/cxfa_fmparse.cpp +++ b/xfa/fxfa/fm2js/cxfa_fmparse.cpp @@ -26,6 +26,20 @@ CXFA_FMParse::CXFA_FMParse(const CFX_WideStringC& wsFormcalc, CXFA_FMParse::~CXFA_FMParse() {} +std::unique_ptr CXFA_FMParse::Parse() { + NextToken(); + if (HasError()) + return nullptr; + + auto expressions = ParseTopExpression(); + if (HasError()) + return nullptr; + + std::vector arguments; + return pdfium::MakeUnique( + 1, true, L"", std::move(arguments), std::move(expressions)); +} + void CXFA_FMParse::NextToken() { m_pToken = m_lexer->NextToken(); while (m_pToken->m_type == TOKreserver) { diff --git a/xfa/fxfa/fm2js/cxfa_fmparse.h b/xfa/fxfa/fm2js/cxfa_fmparse.h index 43a4450128..625145e7a2 100644 --- a/xfa/fxfa/fm2js/cxfa_fmparse.h +++ b/xfa/fxfa/fm2js/cxfa_fmparse.h @@ -18,13 +18,14 @@ class CXFA_FMParse { CXFA_FMParse(const CFX_WideStringC& wsFormcalc, CXFA_FMErrorInfo* pErrorInfo); ~CXFA_FMParse(); - void NextToken(); - std::vector> ParseTopExpression(); + std::unique_ptr Parse(); private: + void NextToken(); void Check(XFA_FM_TOKEN op); void Error(const wchar_t* msg, ...); bool HasError() const; + std::vector> ParseTopExpression(); std::unique_ptr ParseFunction(); std::unique_ptr ParseExpression(); std::unique_ptr ParseVarExpression(); diff --git a/xfa/fxfa/fm2js/cxfa_fmparse_unittest.cpp b/xfa/fxfa/fm2js/cxfa_fmparse_unittest.cpp new file mode 100644 index 0000000000..a17808ae88 --- /dev/null +++ b/xfa/fxfa/fm2js/cxfa_fmparse_unittest.cpp @@ -0,0 +1,135 @@ +// Copyright 2017 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_fmparse.h" + +#include + +#include "testing/gtest/include/gtest/gtest.h" +#include "testing/test_support.h" +#include "third_party/base/ptr_util.h" + +TEST(CXFA_FMParseTest, Empty) { + CXFA_FMErrorInfo errorInfo; + auto parser = pdfium::MakeUnique(L"", &errorInfo); + std::unique_ptr ast = parser->Parse(); + ASSERT(ast != nullptr); + EXPECT_TRUE(errorInfo.message.IsEmpty()); + + CFX_WideTextBuf buf; + EXPECT_TRUE(ast->ToJavaScript(buf)); + // TODO(dsinclair): This is a little weird ..... + EXPECT_EQ(L"// comments only", buf.AsStringC()); +} + +TEST(CXFA_FMParseTest, CommentOnlyIsError) { + CXFA_FMErrorInfo errorInfo; + auto parser = pdfium::MakeUnique(L"; Just comment", &errorInfo); + std::unique_ptr ast = parser->Parse(); + ASSERT(ast != nullptr); + // TODO(dsinclair): This isn't allowed per the spec. + EXPECT_TRUE(errorInfo.message.IsEmpty()); + // EXPECT_FALSE(errorInfo.message.IsEmpty()); + + CFX_WideTextBuf buf; + EXPECT_TRUE(ast->ToJavaScript(buf)); + EXPECT_EQ(L"// comments only", buf.AsStringC()); +} + +TEST(CXFA_FMParseTest, CommentThenValue) { + CXFA_FMErrorInfo errorInfo; + auto parser = + pdfium::MakeUnique(L"; Just comment\n12", &errorInfo); + std::unique_ptr ast = parser->Parse(); + ASSERT(ast != nullptr); + EXPECT_TRUE(errorInfo.message.IsEmpty()); + + CFX_WideTextBuf buf; + EXPECT_TRUE(ast->ToJavaScript(buf)); + EXPECT_EQ(L"(\n" + L"function ()\n" + L"{\n" + L"var foxit_xfa_formcalc_runtime_func_return_value = null;\n" + L"foxit_xfa_formcalc_runtime_func_return_value = 12;\n" + L"return foxit_xfa_formcalc_runtime.get_fm_value(" + L"foxit_xfa_formcalc_runtime_func_return_value);\n" + L"}\n" + L").call(this);\n", buf.AsStringC()); +} + +TEST(CXFA_FMParseTest, Parse) { + const wchar_t input[] = L"$ = Avg (-3, 5, -6, 12, -13);\n" + L"$ = Avg (Table2..Row[*].Cell1);\n" + L"\n" + L"if ($ ne -1)then\n" + L" border.fill.color.value = \"255,64,64\";\n" + L"else\n" + L" border.fill.color.value = \"20,170,13\";\n" + L"endif\n" + L"\n" + L"$"; + + CXFA_FMErrorInfo errorInfo; + auto parser = pdfium::MakeUnique(input, &errorInfo); + std::unique_ptr ast = parser->Parse(); + ASSERT(ast != nullptr); + EXPECT_TRUE(errorInfo.message.IsEmpty()); + + CFX_WideTextBuf buf; + EXPECT_TRUE(ast->ToJavaScript(buf)); + EXPECT_EQ( + L"(\nfunction ()\n{\n" + L"var foxit_xfa_formcalc_runtime_func_return_value = null;\n" + L"if (foxit_xfa_formcalc_runtime.is_fm_object(this))\n{\n" + L"foxit_xfa_formcalc_runtime.assign_value_operator(this, " + L"foxit_xfa_formcalc_runtime.Avg(" + L"foxit_xfa_formcalc_runtime.negative_operator(3), 5, " + L"foxit_xfa_formcalc_runtime.negative_operator(6), 12, " + L"foxit_xfa_formcalc_runtime.negative_operator(13)));\n" + L"}\n" + L"if (foxit_xfa_formcalc_runtime.is_fm_object(this))\n{\n" + L"foxit_xfa_formcalc_runtime.assign_value_operator(this, " + L"foxit_xfa_formcalc_runtime.Avg(" + L"foxit_xfa_formcalc_runtime.dot_accessor(" + L"foxit_xfa_formcalc_runtime.dotdot_accessor(Table2, \"Table2\", " + L"\"Row\", 1), \"\", \"Cell1\", 0, 0)));\n" + L"}\n" + L"if (foxit_xfa_formcalc_runtime.get_fm_value(" + L"foxit_xfa_formcalc_runtime.notequality_operator(this, " + L"foxit_xfa_formcalc_runtime.negative_operator(1))))\n{\n" + L"if (foxit_xfa_formcalc_runtime.is_fm_object(" + L"foxit_xfa_formcalc_runtime.dot_accessor(" + L"foxit_xfa_formcalc_runtime.dot_accessor(" + L"foxit_xfa_formcalc_runtime.dot_accessor(border, " + L"\"border\", \"fill\", 0, 0), \"\", \"color\", 0, 0), " + L"\"\", \"value\", 0, 0)))\n{\n" + L"foxit_xfa_formcalc_runtime.assign_value_operator(" + L"foxit_xfa_formcalc_runtime.dot_accessor(" + L"foxit_xfa_formcalc_runtime.dot_accessor(" + L"foxit_xfa_formcalc_runtime.dot_accessor(" + L"border, \"border\", \"fill\", 0, 0), \"\", " + L"\"color\", 0, 0), \"\", \"value\", 0, 0), " + L"\"255,64,64\");\n" + L"}\n" + L"}\nelse\n{\n" + L"if (foxit_xfa_formcalc_runtime.is_fm_object(" + L"foxit_xfa_formcalc_runtime.dot_accessor(" + L"foxit_xfa_formcalc_runtime.dot_accessor(" + L"foxit_xfa_formcalc_runtime.dot_accessor(" + L"border, \"border\", \"fill\", 0, 0), \"\", \"color\", " + L"0, 0), \"\", \"value\", 0, 0)))\n{\n" + L"foxit_xfa_formcalc_runtime.assign_value_operator(" + L"foxit_xfa_formcalc_runtime.dot_accessor(" + L"foxit_xfa_formcalc_runtime.dot_accessor(" + L"foxit_xfa_formcalc_runtime.dot_accessor(" + L"border, \"border\", \"fill\", 0, 0), \"\", " + L"\"color\", 0, 0), \"\", \"value\", 0, 0), " + L"\"20,170,13\");\n" + L"}\n" + L"}\n" + L"foxit_xfa_formcalc_runtime_func_return_value = this;\n" + L"return foxit_xfa_formcalc_runtime.get_fm_value(" + L"foxit_xfa_formcalc_runtime_func_return_value);\n" + L"}\n).call(this);\n", buf.AsStringC()); +} diff --git a/xfa/fxfa/fm2js/cxfa_fmprogram.cpp b/xfa/fxfa/fm2js/cxfa_fmprogram.cpp deleted file mode 100644 index 6e6385dae0..0000000000 --- a/xfa/fxfa/fm2js/cxfa_fmprogram.cpp +++ /dev/null @@ -1,40 +0,0 @@ -// Copyright 2014 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. - -// Original code copyright 2014 Foxit Software Inc. http://www.foxitsoftware.com - -#include "xfa/fxfa/fm2js/cxfa_fmprogram.h" - -#include -#include - -#include "third_party/base/ptr_util.h" - -CXFA_FMProgram::CXFA_FMProgram(const CFX_WideStringC& wsFormcalc) - : m_parse(wsFormcalc, &m_pErrorInfo) {} - -CXFA_FMProgram::~CXFA_FMProgram() {} - -bool CXFA_FMProgram::ParseProgram() { - m_parse.NextToken(); - if (!m_pErrorInfo.message.IsEmpty()) - return false; - - std::vector> expressions = - m_parse.ParseTopExpression(); - if (!m_pErrorInfo.message.IsEmpty()) - return false; - - std::vector arguments; - m_globalFunction = pdfium::MakeUnique( - 1, true, L"", std::move(arguments), std::move(expressions)); - return true; -} - -bool CXFA_FMProgram::TranslateProgram(CFX_WideTextBuf& wsJavaScript) { - if (!m_globalFunction->ToJavaScript(wsJavaScript)) - return false; - wsJavaScript.AppendChar(0); - return true; -} diff --git a/xfa/fxfa/fm2js/cxfa_fmprogram.h b/xfa/fxfa/fm2js/cxfa_fmprogram.h deleted file mode 100644 index e2a8a984f2..0000000000 --- a/xfa/fxfa/fm2js/cxfa_fmprogram.h +++ /dev/null @@ -1,29 +0,0 @@ -// Copyright 2014 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. - -// Original code copyright 2014 Foxit Software Inc. http://www.foxitsoftware.com - -#ifndef XFA_FXFA_FM2JS_CXFA_FMPROGRAM_H_ -#define XFA_FXFA_FM2JS_CXFA_FMPROGRAM_H_ - -#include - -#include "xfa/fxfa/fm2js/cxfa_fmerrorinfo.h" -#include "xfa/fxfa/fm2js/cxfa_fmparse.h" - -class CXFA_FMProgram { - public: - explicit CXFA_FMProgram(const CFX_WideStringC& wsFormcalc); - ~CXFA_FMProgram(); - - bool ParseProgram(); - bool TranslateProgram(CFX_WideTextBuf& wsJavaScript); - - private: - CXFA_FMErrorInfo m_pErrorInfo; - CXFA_FMParse m_parse; - std::unique_ptr m_globalFunction; -}; - -#endif // XFA_FXFA_FM2JS_CXFA_FMPROGRAM_H_ -- cgit v1.2.3