Merge to XFA: Automated test case for 487928.
authorTom Sepez <tsepez@chromium.org>
Wed, 3 Jun 2015 00:11:18 +0000 (17:11 -0700)
committerTom Sepez <tsepez@chromium.org>
Wed, 3 Jun 2015 00:11:18 +0000 (17:11 -0700)
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
fpdfsdk/src/fpdfformfill_embeddertest.cpp
pdfium.gyp
testing/embedder_test.cpp
testing/embedder_test.h
testing/embedder_test_mock_delegate.h
testing/embedder_test_timer_handling_delegate.h [new file with mode: 0644]
testing/resources/bug_487928.in [new file with mode: 0644]
testing/resources/bug_487928.pdf [new file with mode: 0644]

index 22b0960..cc958b8 100644 (file)
--- 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",
   ]
index b4cc111..615ada9 100644 (file)
@@ -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);
+}
index 8cd3c37..3ef1a13 100644 (file)
         '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',
       ],
index 29de4ca..1003cb5 100644 (file)
@@ -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<int>(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<FPDF_FORMFILLINFO*>(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<EmbedderTest*>(info);
+  return test->delegate_->SetTimer(msecs, fn);
+}
+
+// static
+void EmbedderTest::KillTimerTrampoline(FPDF_FORMFILLINFO* info, int id) {
+  EmbedderTest* test = static_cast<EmbedderTest*>(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) {
index 5cede6c..b0834dd 100644 (file)
@@ -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_
-
index 526e117..1e4e995 100644 (file)
@@ -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 (file)
index 0000000..d05a134
--- /dev/null
@@ -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 <map>
+#include <utility>
+
+#include "embedder_test.h"
+
+class EmbedderTestTimerHandlingDelegate : public EmbedderTest::Delegate {
+public:
+  int SetTimer(int msecs, TimerCallback fn) override {
+    expiry_to_timer_map_.insert(std::pair<int, Timer>(
+        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<int, TimerCallback>;  // ID, callback pair.
+  std::multimap<int, Timer> 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 (file)
index 0000000..9f6d7f2
--- /dev/null
@@ -0,0 +1,122 @@
+{{header}}
+{{object 1 0}} <<
+  /Type /Catalog
+  /Pages 2 0 R
+  /AcroForm 6 0 R
+  /Names <</JavaScript 13 0 R>>
+>>
+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 <</N 8 0 R>>
+  /V ()
+  /AA 19 0 R
+>>
+endobj
+{{object 6 0}} <<
+  /DR <<
+    /Font <</Helv 7 0 R>>
+  >>
+  /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 <</FXF0 7 0 R>>
+  >>
+>>
+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 (file)
index 0000000..dcfdebc
--- /dev/null
@@ -0,0 +1,180 @@
+%PDF-1.7
+% ò¤ô
+1 0 obj <<
+  /Type /Catalog
+  /Pages 2 0 R
+  /AcroForm 6 0 R
+  /Names <</JavaScript 13 0 R>>
+>>
+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 <</N 8 0 R>>
+  /V ()
+  /AA 19 0 R
+>>
+endobj
+6 0 obj <<
+  /DR <<
+    /Font <</Helv 7 0 R>>
+  >>
+  /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 <</FXF0 7 0 R>>
+  >>
+>>
+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