Add unit tests for CPDF_FormField::IsItemSelected()
Change CPDF_FormField to allow initialization with a null
CPDF_InteractiveForm.
Bug: pdfium:1505
Change-Id: I168783c333870fdedb6931daf18e7e6d9da3b96e
Reviewed-on: https://pdfium-review.googlesource.com/c/pdfium/+/68810
Commit-Queue: Daniel Hosseinian <dhoss@chromium.org>
Reviewed-by: Lei Zhang <thestig@chromium.org>
diff --git a/core/fpdfdoc/BUILD.gn b/core/fpdfdoc/BUILD.gn
index f25ace9..caf53f9 100644
--- a/core/fpdfdoc/BUILD.gn
+++ b/core/fpdfdoc/BUILD.gn
@@ -106,7 +106,10 @@
]
deps = [
":fpdfdoc",
+ "../../constants",
+ "../fpdfapi/page",
"../fpdfapi/parser",
+ "../fpdfapi/render",
]
pdfium_root_dir = "../../"
}
diff --git a/core/fpdfdoc/cpdf_formfield_unittest.cpp b/core/fpdfdoc/cpdf_formfield_unittest.cpp
index ca75891..2174efb 100644
--- a/core/fpdfdoc/cpdf_formfield_unittest.cpp
+++ b/core/fpdfdoc/cpdf_formfield_unittest.cpp
@@ -4,13 +4,73 @@
#include "core/fpdfdoc/cpdf_formfield.h"
+#include <vector>
+
+#include "constants/form_fields.h"
+#include "constants/form_flags.h"
+#include "core/fpdfapi/page/cpdf_docpagedata.h"
+#include "core/fpdfapi/page/cpdf_pagemodule.h"
+#include "core/fpdfapi/parser/cpdf_array.h"
#include "core/fpdfapi/parser/cpdf_dictionary.h"
+#include "core/fpdfapi/parser/cpdf_document.h"
#include "core/fpdfapi/parser/cpdf_indirect_object_holder.h"
#include "core/fpdfapi/parser/cpdf_name.h"
+#include "core/fpdfapi/parser/cpdf_number.h"
#include "core/fpdfapi/parser/cpdf_reference.h"
+#include "core/fpdfapi/parser/cpdf_string.h"
+#include "core/fpdfapi/render/cpdf_docrenderdata.h"
+#include "core/fpdfdoc/cpdf_interactiveform.h"
#include "testing/gtest/include/gtest/gtest.h"
+#include "third_party/base/stl_util.h"
-TEST(cpdf_formfield, GetFullNameForDict) {
+namespace {
+
+// Create and destroys the page module that is necessary when instantiating a
+// CPDF_Document.
+class ScopedCPDF_PageModule {
+ public:
+ ScopedCPDF_PageModule() { CPDF_PageModule::Create(); }
+ ~ScopedCPDF_PageModule() { CPDF_PageModule::Destroy(); }
+};
+
+class CPDF_TestEmptyDocument final : public CPDF_Document {
+ public:
+ CPDF_TestEmptyDocument()
+ : CPDF_Document(pdfium::MakeUnique<CPDF_DocRenderData>(),
+ pdfium::MakeUnique<CPDF_DocPageData>()) {}
+};
+
+void TestMultiselectFieldDict(RetainPtr<CPDF_Array> opt_array,
+ RetainPtr<CPDF_Object> values,
+ RetainPtr<CPDF_Object> selected_indices,
+ const std::vector<int>& expected_indices,
+ const std::vector<int>& excluded_indices) {
+ auto form_dict = pdfium::MakeRetain<CPDF_Dictionary>();
+ form_dict->SetNewFor<CPDF_Name>("Type", "Annot");
+ form_dict->SetNewFor<CPDF_Name>("Subtype", "Widget");
+ form_dict->SetNewFor<CPDF_Name>(pdfium::form_fields::kFT,
+ pdfium::form_fields::kCh);
+ constexpr int kMuliSelectFlag = pdfium::form_flags::kChoiceMultiSelect;
+ form_dict->SetNewFor<CPDF_Number>(pdfium::form_fields::kFf, kMuliSelectFlag);
+ form_dict->SetFor("Opt", opt_array);
+ form_dict->SetFor(pdfium::form_fields::kV, values);
+ form_dict->SetFor("I", selected_indices);
+
+ CPDF_TestEmptyDocument doc;
+ CPDF_InteractiveForm form(&doc);
+ CPDF_FormField form_field(&form, form_dict.Get());
+ for (int i = 0; i < form_field.CountOptions(); i++) {
+ const bool expected_selected = pdfium::ContainsValue(expected_indices, i);
+ EXPECT_EQ(expected_selected, form_field.IsItemSelected(i));
+ }
+ for (int i : excluded_indices) {
+ EXPECT_FALSE(form_field.IsItemSelected(i));
+ }
+}
+
+} // namespace
+
+TEST(CPDF_FormFieldTest, GetFullNameForDict) {
WideString name = CPDF_FormField::GetFullNameForDict(nullptr);
EXPECT_TRUE(name.IsEmpty());
@@ -47,3 +107,220 @@
name = CPDF_FormField::GetFullNameForDict(dict3);
EXPECT_STREQ("bar.foo.qux", name.ToUTF8().c_str());
}
+
+TEST(CPDF_FormFieldTest, IsItemSelected) {
+ ScopedCPDF_PageModule page_module;
+
+ auto opt_array = pdfium::MakeRetain<CPDF_Array>();
+ opt_array->AppendNew<CPDF_String>(L"Alpha");
+ opt_array->AppendNew<CPDF_String>(L"Beta");
+ opt_array->AppendNew<CPDF_String>(L"Gamma");
+ opt_array->AppendNew<CPDF_String>(L"Delta");
+ opt_array->AppendNew<CPDF_String>(L"Epsilon");
+
+ {
+ // No Values (/V) or Selected Indices (/I) objects.
+ std::vector<int> expected_indices;
+ std::vector<int> excluded_indices{-1, 5};
+ TestMultiselectFieldDict(opt_array, /*values=*/nullptr,
+ /*selected_indices=*/nullptr, expected_indices,
+ excluded_indices);
+ }
+ {
+ // Values (/V) object is just a string.
+ auto values = pdfium::MakeRetain<CPDF_String>(/*pPool=*/nullptr, L"Gamma");
+ std::vector<int> expected_indices{2};
+ std::vector<int> excluded_indices{-1, 5};
+ TestMultiselectFieldDict(opt_array, values, /*selected_indices=*/nullptr,
+ expected_indices, excluded_indices);
+ }
+ {
+ // Values (/V) object is just an invalid string.
+ auto values = pdfium::MakeRetain<CPDF_String>(/*pPool=*/nullptr, L"Omega");
+ std::vector<int> expected_indices;
+ std::vector<int> excluded_indices{-1, 5};
+ TestMultiselectFieldDict(opt_array, values, /*selected_indices=*/nullptr,
+ expected_indices, excluded_indices);
+ }
+ {
+ // Values (/V) object is an array with one object.
+ auto values = pdfium::MakeRetain<CPDF_Array>();
+ values->AppendNew<CPDF_String>(L"Beta");
+ // TODO(bug_1505): Should be selected at index 1.
+ std::vector<int> expected_indices;
+ std::vector<int> excluded_indices{-1, 5};
+ TestMultiselectFieldDict(opt_array, values, /*selected_indices=*/nullptr,
+ expected_indices, excluded_indices);
+ }
+ {
+ // Values (/V) object is an array with one invalid object.
+ auto values = pdfium::MakeRetain<CPDF_Array>();
+ values->AppendNew<CPDF_String>(L"Omega");
+ std::vector<int> expected_indices;
+ std::vector<int> excluded_indices{-1, 5};
+ TestMultiselectFieldDict(opt_array, values, /*selected_indices=*/nullptr,
+ expected_indices, excluded_indices);
+ }
+ {
+ // Values (/V) object is an array with multiple objects.
+ auto values = pdfium::MakeRetain<CPDF_Array>();
+ values->AppendNew<CPDF_String>(L"Beta");
+ values->AppendNew<CPDF_String>(L"Epsilon");
+ // TODO(bug_1505): Should be selected at index 1 and index 4.
+ std::vector<int> expected_indices;
+ std::vector<int> excluded_indices{-1, 5};
+ TestMultiselectFieldDict(opt_array, values, /*selected_indices=*/nullptr,
+ expected_indices, excluded_indices);
+ }
+ {
+ // Values (/V) object is an array with multiple objects with one invalid.
+ auto values = pdfium::MakeRetain<CPDF_Array>();
+ values->AppendNew<CPDF_String>(L"Beta");
+ values->AppendNew<CPDF_String>(L"Epsilon");
+ values->AppendNew<CPDF_String>(L"Omega");
+ // TODO(bug_1505): Should be selected at index 1 and index 4.
+ std::vector<int> expected_indices;
+ std::vector<int> excluded_indices{-1, 5};
+ TestMultiselectFieldDict(opt_array, values, /*selected_indices=*/nullptr,
+ expected_indices, excluded_indices);
+ }
+ {
+ // Selected indices (/I) object is just a number.
+ auto selected_indices = pdfium::MakeRetain<CPDF_Number>(3);
+ std::vector<int> expected_indices{3};
+ std::vector<int> excluded_indices{-1, 5};
+ TestMultiselectFieldDict(opt_array, /*values=*/nullptr, selected_indices,
+ expected_indices, excluded_indices);
+ }
+ {
+ // Selected indices (/I) object is just an invalid number.
+ auto selected_indices = pdfium::MakeRetain<CPDF_Number>(26);
+ std::vector<int> expected_indices;
+ std::vector<int> excluded_indices{-1, 5, 26};
+ TestMultiselectFieldDict(opt_array, /*values=*/nullptr, selected_indices,
+ expected_indices, excluded_indices);
+ }
+ {
+ // Selected indices (/I) object is an array with one object.
+ auto selected_indices = pdfium::MakeRetain<CPDF_Array>();
+ selected_indices->AppendNew<CPDF_Number>(0);
+ std::vector<int> expected_indices{0};
+ std::vector<int> excluded_indices{-1, 5};
+ TestMultiselectFieldDict(opt_array, /*values=*/nullptr, selected_indices,
+ expected_indices, excluded_indices);
+ }
+ {
+ // Selected indices (/I) object is an array with multiple objects.
+ auto selected_indices = pdfium::MakeRetain<CPDF_Array>();
+ selected_indices->AppendNew<CPDF_Number>(0);
+ selected_indices->AppendNew<CPDF_Number>(2);
+ selected_indices->AppendNew<CPDF_Number>(3);
+ std::vector<int> expected_indices{0, 2, 3};
+ std::vector<int> excluded_indices{-1, 5};
+ TestMultiselectFieldDict(opt_array, /*values=*/nullptr, selected_indices,
+ expected_indices, excluded_indices);
+ }
+ {
+ // Selected indices (/I) object is an array with multiple objects and some
+ // are invalid.
+ auto selected_indices = pdfium::MakeRetain<CPDF_Array>();
+ selected_indices->AppendNew<CPDF_Number>(0);
+ selected_indices->AppendNew<CPDF_Number>(2);
+ selected_indices->AppendNew<CPDF_Number>(3);
+ selected_indices->AppendNew<CPDF_Number>(-5);
+ selected_indices->AppendNew<CPDF_Number>(12);
+ selected_indices->AppendNew<CPDF_Number>(42);
+ std::vector<int> expected_indices{0, 2, 3};
+ std::vector<int> excluded_indices{-5, -1, 5, 12, 42};
+ TestMultiselectFieldDict(opt_array, /*values=*/nullptr, selected_indices,
+ expected_indices, excluded_indices);
+ }
+ {
+ // Values (/V) or Selected Indices (/I) objects conflict with different
+ // lengths.
+ auto values = pdfium::MakeRetain<CPDF_Array>();
+ values->AppendNew<CPDF_String>(L"Beta");
+ values->AppendNew<CPDF_String>(L"Epsilon");
+ auto selected_indices = pdfium::MakeRetain<CPDF_Array>();
+ selected_indices->AppendNew<CPDF_Number>(0);
+ selected_indices->AppendNew<CPDF_Number>(2);
+ selected_indices->AppendNew<CPDF_Number>(3);
+ // TODO(bug_1505): Should be selected at index 1 and index 4.
+ std::vector<int> expected_indices{0, 2, 3};
+ std::vector<int> excluded_indices{-1, 5};
+ TestMultiselectFieldDict(opt_array, values, selected_indices,
+ expected_indices, excluded_indices);
+ }
+ {
+ // Values (/V) or Selected Indices (/I) objects conflict with same lengths.
+ auto values = pdfium::MakeRetain<CPDF_Array>();
+ values->AppendNew<CPDF_String>(L"Alpha");
+ values->AppendNew<CPDF_String>(L"Epsilon");
+ auto selected_indices = pdfium::MakeRetain<CPDF_Array>();
+ selected_indices->AppendNew<CPDF_Number>(2);
+ selected_indices->AppendNew<CPDF_Number>(3);
+ // TODO(bug_1505): Should be selected at index 0 and index 4.
+ std::vector<int> expected_indices{2, 3};
+ std::vector<int> excluded_indices{-1, 5};
+ TestMultiselectFieldDict(opt_array, values, selected_indices,
+ expected_indices, excluded_indices);
+ }
+ {
+ // Values (/V) or Selected Indices (/I) objects conflict with values being
+ // invalid.
+ auto values = pdfium::MakeRetain<CPDF_Array>();
+ values->AppendNew<CPDF_String>(L"Beta");
+ values->AppendNew<CPDF_String>(L"Epsilon");
+ values->AppendNew<CPDF_String>(L"Omega");
+ auto selected_indices = pdfium::MakeRetain<CPDF_Array>();
+ selected_indices->AppendNew<CPDF_Number>(1);
+ selected_indices->AppendNew<CPDF_Number>(4);
+ std::vector<int> expected_indices{1, 4};
+ std::vector<int> excluded_indices{-1, 5};
+ TestMultiselectFieldDict(opt_array, values, selected_indices,
+ expected_indices, excluded_indices);
+ }
+ {
+ // Values (/V) or Selected Indices (/I) objects conflict with selected
+ // indices being invalid.
+ auto values = pdfium::MakeRetain<CPDF_Array>();
+ values->AppendNew<CPDF_String>(L"Beta");
+ values->AppendNew<CPDF_String>(L"Epsilon");
+ auto selected_indices = pdfium::MakeRetain<CPDF_Array>();
+ selected_indices->AppendNew<CPDF_Number>(1);
+ selected_indices->AppendNew<CPDF_Number>(4);
+ selected_indices->AppendNew<CPDF_Number>(26);
+ std::vector<int> expected_indices{1, 4};
+ std::vector<int> excluded_indices{-1, 5, 26};
+ TestMultiselectFieldDict(opt_array, values, selected_indices,
+ expected_indices, excluded_indices);
+ }
+ {
+ // Values (/V) or Selected Indices (/I) objects conflict with both being
+ // invalid.
+ auto values = pdfium::MakeRetain<CPDF_Array>();
+ values->AppendNew<CPDF_String>(L"Beta");
+ values->AppendNew<CPDF_String>(L"Epsilon");
+ values->AppendNew<CPDF_String>(L"Omega");
+ auto selected_indices = pdfium::MakeRetain<CPDF_Array>();
+ selected_indices->AppendNew<CPDF_Number>(0);
+ selected_indices->AppendNew<CPDF_Number>(2);
+ selected_indices->AppendNew<CPDF_Number>(3);
+ selected_indices->AppendNew<CPDF_Number>(26);
+ // TODO(bug_1505): Should be selected at index 1 and index 4.
+ std::vector<int> expected_indices{0, 2, 3};
+ std::vector<int> excluded_indices{-1, 5, 26};
+ TestMultiselectFieldDict(opt_array, values, selected_indices,
+ expected_indices, excluded_indices);
+ }
+ {
+ // Values (/V) or Selected Indices (/I) objects conflict with each not being
+ // an array.
+ auto values = pdfium::MakeRetain<CPDF_String>(/*pPool=*/nullptr, L"Gamma");
+ auto selected_indices = pdfium::MakeRetain<CPDF_Number>(4);
+ std::vector<int> expected_indices{2};
+ std::vector<int> excluded_indices{-1, 5};
+ TestMultiselectFieldDict(opt_array, values, selected_indices,
+ expected_indices, excluded_indices);
+ }
+}