From 6efc0ad16665ab74c5033bdc36dbcb7c8aad7e6c Mon Sep 17 00:00:00 2001 From: Tom Sepez Date: Tue, 2 Jun 2015 17:11:18 -0700 Subject: Merge to XFA: Automated test case for 487928. Original Review URL: https://codereview.chromium.org/1153213004 R=thestig@chromium.org TBR=thestig@chromium.org Review URL: https://codereview.chromium.org/1158483004 --- BUILD.gn | 1 + fpdfsdk/src/fpdfformfill_embeddertest.cpp | 15 ++ pdfium.gyp | 1 + testing/embedder_test.cpp | 86 ++++------- testing/embedder_test.h | 11 +- testing/embedder_test_mock_delegate.h | 2 + testing/embedder_test_timer_handling_delegate.h | 54 +++++++ testing/resources/bug_487928.in | 122 ++++++++++++++++ testing/resources/bug_487928.pdf | 180 ++++++++++++++++++++++++ 9 files changed, 413 insertions(+), 59 deletions(-) create mode 100644 testing/embedder_test_timer_handling_delegate.h create mode 100644 testing/resources/bug_487928.in create mode 100644 testing/resources/bug_487928.pdf diff --git a/BUILD.gn b/BUILD.gn index 22b09608cd..cc958b8ad5 100644 --- a/BUILD.gn +++ b/BUILD.gn @@ -1588,6 +1588,7 @@ test("pdfium_embeddertests") { "testing/embedder_test.cpp", "testing/embedder_test.h", "testing/embedder_test_mock_delegate.h", + "testing/embedder_test_timer_handling_delegate.h", "testing/fx_string_testhelpers.cpp", "testing/fx_string_testhelpers.h", ] diff --git a/fpdfsdk/src/fpdfformfill_embeddertest.cpp b/fpdfsdk/src/fpdfformfill_embeddertest.cpp index b4cc111a00..615ada99f9 100644 --- a/fpdfsdk/src/fpdfformfill_embeddertest.cpp +++ b/fpdfsdk/src/fpdfformfill_embeddertest.cpp @@ -6,6 +6,7 @@ #include "../../public/fpdf_formfill.h" #include "../../testing/embedder_test.h" #include "../../testing/embedder_test_mock_delegate.h" +#include "../../testing/embedder_test_timer_handling_delegate.h" #include "testing/gmock/include/gmock/gmock.h" #include "testing/gtest/include/gtest/gtest.h" @@ -19,6 +20,8 @@ TEST_F(FPDFFormFillEmbeddertest, FirstTest) { EmbedderTestMockDelegate mock; EXPECT_CALL(mock, Alert(_, _, _, _)).Times(0); EXPECT_CALL(mock, UnsupportedHandler(_)).Times(0); + EXPECT_CALL(mock, SetTimer(_, _)).Times(0); + EXPECT_CALL(mock, KillTimer(_)).Times(0); SetDelegate(&mock); EXPECT_TRUE(OpenDocument("testing/resources/hello_world.pdf")); @@ -26,3 +29,15 @@ TEST_F(FPDFFormFillEmbeddertest, FirstTest) { EXPECT_NE(nullptr, page); UnloadPage(page); } + +TEST_F(FPDFFormFillEmbeddertest, BUG_487928) { + EmbedderTestTimerHandlingDelegate delegate; + SetDelegate(&delegate); + + EXPECT_TRUE(OpenDocument("testing/resources/bug_487928.pdf")); + FPDF_PAGE page = LoadPage(0); + EXPECT_NE(nullptr, page); + DoOpenActions(); + delegate.AdvanceTime(5000); + UnloadPage(page); +} diff --git a/pdfium.gyp b/pdfium.gyp index 8cd3c372e5..3ef1a13049 100644 --- a/pdfium.gyp +++ b/pdfium.gyp @@ -959,6 +959,7 @@ 'testing/embedder_test.cpp', 'testing/embedder_test.h', 'testing/embedder_test_mock_delegate.h', + 'testing/embedder_test_timer_handling_delegate.h', 'testing/fx_string_testhelpers.cpp', 'testing/fx_string_testhelpers.h', ], diff --git a/testing/embedder_test.cpp b/testing/embedder_test.cpp index 29de4caad4..1003cb5187 100644 --- a/testing/embedder_test.cpp +++ b/testing/embedder_test.cpp @@ -18,8 +18,8 @@ #include "../public/fpdf_text.h" #include "../public/fpdfview.h" #include "testing/gmock/include/gmock/gmock.h" -#include "v8/include/v8.h" #include "v8/include/libplatform/libplatform.h" +#include "v8/include/v8.h" #ifdef _WIN32 #define snprintf _snprintf @@ -95,58 +95,6 @@ static bool GetExternalData(const std::string& exe_path, } // namespace -class EmbedderTestDefaultDelegate : public EmbedderTest::Delegate { - public: - int Alert(FPDF_WIDESTRING, FPDF_WIDESTRING, int, int) override { - printf("Form_Alert called.\n"); - return 0; - } - - void UnsupportedHandler(int type) { - std::string feature = "Unknown"; - switch (type) { - case FPDF_UNSP_DOC_XFAFORM: - feature = "XFA"; - break; - case FPDF_UNSP_DOC_PORTABLECOLLECTION: - feature = "Portfolios_Packages"; - break; - case FPDF_UNSP_DOC_ATTACHMENT: - case FPDF_UNSP_ANNOT_ATTACHMENT: - feature = "Attachment"; - break; - case FPDF_UNSP_DOC_SECURITY: - feature = "Rights_Management"; - break; - case FPDF_UNSP_DOC_SHAREDREVIEW: - feature = "Shared_Review"; - break; - case FPDF_UNSP_DOC_SHAREDFORM_ACROBAT: - case FPDF_UNSP_DOC_SHAREDFORM_FILESYSTEM: - case FPDF_UNSP_DOC_SHAREDFORM_EMAIL: - feature = "Shared_Form"; - break; - case FPDF_UNSP_ANNOT_3DANNOT: - feature = "3D"; - break; - case FPDF_UNSP_ANNOT_MOVIE: - feature = "Movie"; - break; - case FPDF_UNSP_ANNOT_SOUND: - feature = "Sound"; - break; - case FPDF_UNSP_ANNOT_SCREEN_MEDIA: - case FPDF_UNSP_ANNOT_SCREEN_RICHMEDIA: - feature = "Screen"; - break; - case FPDF_UNSP_ANNOT_SIG: - feature = "Digital_Signature"; - break; - } - printf("Unsupported feature: %s.\n", feature.c_str()); - } -}; - class TestLoader { public: TestLoader(const char* pBuf, size_t len); @@ -184,7 +132,7 @@ EmbedderTest::EmbedderTest() : memset(&hints_, 0, sizeof(hints_)); memset(&file_access_, 0, sizeof(file_access_)); memset(&file_avail_, 0, sizeof(file_avail_)); - default_delegate_ = new EmbedderTestDefaultDelegate(); + default_delegate_ = new EmbedderTest::Delegate(); delegate_ = default_delegate_; } @@ -194,9 +142,15 @@ EmbedderTest::~EmbedderTest() { void EmbedderTest::SetUp() { v8::V8::InitializeICU(); - v8::Platform* platform = v8::platform::CreateDefaultPlatform(); - v8::V8::InitializePlatform(platform); - v8::V8::Initialize(); + + platform_ = v8::platform::CreateDefaultPlatform(); + v8::V8::InitializePlatform(platform_); + v8::V8::Initialize(); + + // By enabling predictable mode, V8 won't post any background tasks. + const char predictable_flag[] = "--predictable"; + v8::V8::SetFlagsFromString(predictable_flag, + static_cast(strlen(predictable_flag))); #ifdef V8_USE_EXTERNAL_STARTUP_DATA ASSERT_TRUE(GetExternalData(g_exe_path_, "natives_blob.bin", &natives_)); @@ -222,9 +176,10 @@ void EmbedderTest::TearDown() { } FPDFAvail_Destroy(avail_); FPDF_DestroyLibrary(); + v8::V8::ShutdownPlatform(); + delete platform_; delete loader_; free(file_contents_); - v8::V8::ShutdownPlatform(); } bool EmbedderTest::OpenDocument(const std::string& filename) { @@ -272,6 +227,8 @@ bool EmbedderTest::OpenDocument(const std::string& filename) { FPDF_FORMFILLINFO* formfillinfo = static_cast(this); memset(formfillinfo, 0, sizeof(FPDF_FORMFILLINFO)); formfillinfo->version = 1; + formfillinfo->FFI_SetTimer = SetTimerTrampoline; + formfillinfo->FFI_KillTimer = KillTimerTrampoline; formfillinfo->m_pJsPlatform = platform; form_handle_ = FPDFDOC_InitFormFillEnvironment(document_, formfillinfo); @@ -343,6 +300,19 @@ int EmbedderTest::AlertTrampoline(IPDF_JSPLATFORM* platform, return test->delegate_->Alert(message, title, type, icon); } +// static +int EmbedderTest::SetTimerTrampoline(FPDF_FORMFILLINFO* info, + int msecs, TimerCallback fn) { + EmbedderTest* test = static_cast(info); + return test->delegate_->SetTimer(msecs, fn); +} + +// static +void EmbedderTest::KillTimerTrampoline(FPDF_FORMFILLINFO* info, int id) { + EmbedderTest* test = static_cast(info); + return test->delegate_->KillTimer(id); +} + // Can't use gtest-provided main since we need to stash the path to the // executable in order to find the external V8 binary data files. int main(int argc, char** argv) { diff --git a/testing/embedder_test.h b/testing/embedder_test.h index 5cede6c6b4..b0834ddecd 100644 --- a/testing/embedder_test.h +++ b/testing/embedder_test.h @@ -36,6 +36,12 @@ class EmbedderTest : public ::testing::Test, int type, int icon) { return 0; } + + // Equivalent to FPDF_FORMFILLINFO::FFI_SetTimer(). + virtual int SetTimer(int msecs, TimerCallback fn) { return 0; } + + // Equivalent to FPDF_FORMFILLINFO::FFI_KillTimer(). + virtual void KillTimer(int id) { } }; EmbedderTest(); @@ -81,6 +87,7 @@ class EmbedderTest : public ::testing::Test, FX_DOWNLOADHINTS hints_; FPDF_FILEACCESS file_access_; FX_FILEAVAIL file_avail_; + v8::Platform* platform_; v8::StartupData natives_; v8::StartupData snapshot_; TestLoader* loader_; @@ -91,7 +98,9 @@ class EmbedderTest : public ::testing::Test, static void UnsupportedHandlerTrampoline(UNSUPPORT_INFO*, int type); static int AlertTrampoline(IPDF_JSPLATFORM* plaform, FPDF_WIDESTRING message, FPDF_WIDESTRING title, int type, int icon); + static int SetTimerTrampoline(FPDF_FORMFILLINFO* info, int msecs, + TimerCallback fn); + static void KillTimerTrampoline(FPDF_FORMFILLINFO* info, int id); }; #endif // TESTING_EMBEDDER_TEST_H_ - diff --git a/testing/embedder_test_mock_delegate.h b/testing/embedder_test_mock_delegate.h index 526e11774e..1e4e99513d 100644 --- a/testing/embedder_test_mock_delegate.h +++ b/testing/embedder_test_mock_delegate.h @@ -13,6 +13,8 @@ class EmbedderTestMockDelegate : public EmbedderTest::Delegate { MOCK_METHOD1(UnsupportedHandler, void(int type)); MOCK_METHOD4(Alert, int(FPDF_WIDESTRING message, FPDF_WIDESTRING title, int type, int icon)); + MOCK_METHOD2(SetTimer, int(int msecs, TimerCallback fn)); + MOCK_METHOD1(KillTimer, void(int msecs)); }; #endif // TESTING_EMBEDDER_TEST_MOCK_DELEGATE_H_ diff --git a/testing/embedder_test_timer_handling_delegate.h b/testing/embedder_test_timer_handling_delegate.h new file mode 100644 index 0000000000..d05a134b4e --- /dev/null +++ b/testing/embedder_test_timer_handling_delegate.h @@ -0,0 +1,54 @@ +// Copyright 2015 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. + +#ifndef TESTING_EMBEDDER_TEST_TIMER_HANDLING_DELEGATE_H_ +#define TESTING_EMBEDDER_TEST_TIMER_HANDLING_DELEGATE_H_ + +#include +#include + +#include "embedder_test.h" + +class EmbedderTestTimerHandlingDelegate : public EmbedderTest::Delegate { +public: + int SetTimer(int msecs, TimerCallback fn) override { + expiry_to_timer_map_.insert(std::pair( + msecs + imaginary_elapsed_msecs_, Timer(++next_timer_id_, fn))); + return next_timer_id_; + } + + void KillTimer(int id) override { + for (auto iter = expiry_to_timer_map_.begin(); + iter != expiry_to_timer_map_.end(); ++iter) { + if (iter->second.first == id) { + expiry_to_timer_map_.erase(iter); + break; + } + } + } + + void AdvanceTime(int increment_msecs) { + imaginary_elapsed_msecs_ += increment_msecs; + while (1) { + auto iter = expiry_to_timer_map_.begin(); + if (iter == expiry_to_timer_map_.end()) { + break; + } + Timer t = iter->second; + if (t.first > imaginary_elapsed_msecs_) { + break; + } + expiry_to_timer_map_.erase(iter); + t.second(t.first); // Fire timer. + } + } + +protected: + using Timer = std::pair; // ID, callback pair. + std::multimap expiry_to_timer_map_; // Keyed by timeout. + int next_timer_id_ = 0; + int imaginary_elapsed_msecs_ = 0; +}; + +#endif // TESTING_EMBEDDER_TEST_TIMER_HANDLING_DELEGATE_H_ diff --git a/testing/resources/bug_487928.in b/testing/resources/bug_487928.in new file mode 100644 index 0000000000..9f6d7f2bd1 --- /dev/null +++ b/testing/resources/bug_487928.in @@ -0,0 +1,122 @@ +{{header}} +{{object 1 0}} << + /Type /Catalog + /Pages 2 0 R + /AcroForm 6 0 R + /Names <> +>> +endobj +{{object 2 0}} << + /Type /Pages + /Count 1 + /Kids [4 0 R] +>> +endobj +{{object 4 0}} << + /Type /Page + /Parent 2 0 R + /MediaBox [0 0 612 792] + /CropBox [0 0 612 792] + /Resources <<>> + /Annots [5 0 R] +>> +endobj +{{object 5 0}} << + /FT /Tx + /Ff 29360128 + /T (txtName) + /Type /Annot + /Subtype /Widget + /F 4 + /M (D:20150514070426+05'30') + /Rect [180.279 715.6 256.186 744.072] + /BS << + /W 1 + /S /S + >> + /DA (/Helv 0 Tf 0 0 0 rg) + /AP <> + /V () + /AA 19 0 R +>> +endobj +{{object 6 0}} << + /DR << + /Font <> + >> + /DA (/Helv 0 Tf 0 g) + /Fields [5 0 R] +>> +endobj +{{object 7 0}} << + /Type /Font + /Subtype /Type1 + /BaseFont /Helvetica + /Encoding /WinAnsiEncoding +>> +endobj +{{object 8 0}} << + /Type /XObject + /Subtype /Form + /FormType 1 + /Matrix [1 0 0 1 0 0] + /BBox [0 0 75.907 28.472] + /Resources << + /Font <> + >> +>> +stream +q +Q + + +endstream +endobj +{{object 11 0}} << + /Type /Action + /S /JavaScript + /JS 50 0 R +>> +endobj +{{object 13 0}} << + /Names [(startDelay) 11 0 R] +>> +endobj +{{object 19 0}} << + /V 53 0 R +>> +endobj +{{object 50 0}} << +>> +stream +function startDelay() +{ + f = this.getField("txtName"); + f.delay = true; + f.value = 'test'; + f.delay = false; +} +app.setTimeOut("startDelay()", 3000); +endstream +endobj +{{object 53 0}} << + /Type /Action + /S /JavaScript + /JS 54 0 R +>> +endobj +{{object 54 0}} << +>> +stream +f1 = this.getField("txtName"); +f1.delay = true; +f1.value = 'test new'; +f1.delay = false; +endstream +endobj +{{xref}} +trailer << + /Root 1 0 R +>> +{{startxref}} +%%EOF diff --git a/testing/resources/bug_487928.pdf b/testing/resources/bug_487928.pdf new file mode 100644 index 0000000000..dcfdebc1b0 --- /dev/null +++ b/testing/resources/bug_487928.pdf @@ -0,0 +1,180 @@ +%PDF-1.7 +% ò¤ô +1 0 obj << + /Type /Catalog + /Pages 2 0 R + /AcroForm 6 0 R + /Names <> +>> +endobj +2 0 obj << + /Type /Pages + /Count 1 + /Kids [4 0 R] +>> +endobj +4 0 obj << + /Type /Page + /Parent 2 0 R + /MediaBox [0 0 612 792] + /CropBox [0 0 612 792] + /Resources <<>> + /Annots [5 0 R] +>> +endobj +5 0 obj << + /FT /Tx + /Ff 29360128 + /T (txtName) + /Type /Annot + /Subtype /Widget + /F 4 + /M (D:20150514070426+05'30') + /Rect [180.279 715.6 256.186 744.072] + /BS << + /W 1 + /S /S + >> + /DA (/Helv 0 Tf 0 0 0 rg) + /AP <> + /V () + /AA 19 0 R +>> +endobj +6 0 obj << + /DR << + /Font <> + >> + /DA (/Helv 0 Tf 0 g) + /Fields [5 0 R] +>> +endobj +7 0 obj << + /Type /Font + /Subtype /Type1 + /BaseFont /Helvetica + /Encoding /WinAnsiEncoding +>> +endobj +8 0 obj << + /Type /XObject + /Subtype /Form + /FormType 1 + /Matrix [1 0 0 1 0 0] + /BBox [0 0 75.907 28.472] + /Resources << + /Font <> + >> +>> +stream +q +Q + + +endstream +endobj +11 0 obj << + /Type /Action + /S /JavaScript + /JS 50 0 R +>> +endobj +13 0 obj << + /Names [(startDelay) 11 0 R] +>> +endobj +19 0 obj << + /V 53 0 R +>> +endobj +50 0 obj << +>> +stream +function startDelay() +{ + f = this.getField("txtName"); + f.delay = true; + f.value = 'test'; + f.delay = false; +} +app.setTimeOut("startDelay()", 3000); +endstream +endobj +53 0 obj << + /Type /Action + /S /JavaScript + /JS 54 0 R +>> +endobj +54 0 obj << +>> +stream +f1 = this.getField("txtName"); +f1.delay = true; +f1.value = 'test new'; +f1.delay = false; +endstream +endobj +xref +0 55 +0000000000 65535 f +0000000015 00000 n +0000000118 00000 n +0000000000 65535 f +0000000181 00000 n +0000000320 00000 n +0000000595 00000 n +0000000697 00000 n +0000000802 00000 n +0000000000 65535 f +0000000000 65535 f +0000000994 00000 n +0000000000 65535 f +0000001062 00000 n +0000000000 65535 f +0000000000 65535 f +0000000000 65535 f +0000000000 65535 f +0000000000 65535 f +0000001115 00000 n +0000000000 65535 f +0000000000 65535 f +0000000000 65535 f +0000000000 65535 f +0000000000 65535 f +0000000000 65535 f +0000000000 65535 f +0000000000 65535 f +0000000000 65535 f +0000000000 65535 f +0000000000 65535 f +0000000000 65535 f +0000000000 65535 f +0000000000 65535 f +0000000000 65535 f +0000000000 65535 f +0000000000 65535 f +0000000000 65535 f +0000000000 65535 f +0000000000 65535 f +0000000000 65535 f +0000000000 65535 f +0000000000 65535 f +0000000000 65535 f +0000000000 65535 f +0000000000 65535 f +0000000000 65535 f +0000000000 65535 f +0000000000 65535 f +0000000000 65535 f +0000001149 00000 n +0000000000 65535 f +0000000000 65535 f +0000001341 00000 n +0000001409 00000 n +trailer << + /Root 1 0 R +>> +startxref +1537 +%%EOF -- cgit v1.2.3