From cdce75706de7e76e73550a0582e1fd28af324fd0 Mon Sep 17 00:00:00 2001 From: weili Date: Wed, 13 Apr 2016 14:40:10 -0700 Subject: Add iterators and unit tests for CPDF_Array class Add iterators to enable range based for loop. Also add unit tests for recent modified functions. Review URL: https://codereview.chromium.org/1878803002 --- BUILD.gn | 1 + core/fpdfapi/fpdf_parser/cpdf_array_unittest.cpp | 181 +++++++++++++++++++++++ core/fpdfapi/fpdf_parser/include/cpdf_array.h | 8 + pdfium.gyp | 1 + 4 files changed, 191 insertions(+) create mode 100644 core/fpdfapi/fpdf_parser/cpdf_array_unittest.cpp diff --git a/BUILD.gn b/BUILD.gn index e3131481ec..64f03e16c6 100644 --- a/BUILD.gn +++ b/BUILD.gn @@ -1639,6 +1639,7 @@ test("pdfium_unittests") { "core/fpdfapi/fpdf_font/fpdf_font_unittest.cpp", "core/fpdfapi/fpdf_page/fpdf_page_parser_old_unittest.cpp", "core/fpdfapi/fpdf_page/fpdf_page_parser_unittest.cpp", + "core/fpdfapi/fpdf_parser/cpdf_array_unittest.cpp", "core/fpdfapi/fpdf_parser/cpdf_object_unittest.cpp", "core/fpdfapi/fpdf_parser/cpdf_parser_unittest.cpp", "core/fpdfapi/fpdf_parser/cpdf_simple_parser_unittest.cpp", diff --git a/core/fpdfapi/fpdf_parser/cpdf_array_unittest.cpp b/core/fpdfapi/fpdf_parser/cpdf_array_unittest.cpp new file mode 100644 index 0000000000..58642a610f --- /dev/null +++ b/core/fpdfapi/fpdf_parser/cpdf_array_unittest.cpp @@ -0,0 +1,181 @@ +// 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 "core/fpdfapi/fpdf_parser/include/cpdf_array.h" +#include "core/fpdfapi/fpdf_parser/include/cpdf_number.h" +#include "core/fpdfapi/fpdf_parser/include/cpdf_reference.h" + +#include + +#include "testing/gtest/include/gtest/gtest.h" + +namespace { + +using ScopedArray = std::unique_ptr>; + +} // namespace + +TEST(cpdf_array, RemoveAt) { + { + int elems[] = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10}; + ScopedArray arr(new CPDF_Array); + for (size_t i = 0; i < FX_ArraySize(elems); ++i) + arr->AddInteger(elems[i]); + arr->RemoveAt(3, 3); + int expected[] = {1, 2, 3, 7, 8, 9, 10}; + EXPECT_EQ(FX_ArraySize(expected), arr->GetCount()); + for (size_t i = 0; i < FX_ArraySize(expected); ++i) + EXPECT_EQ(expected[i], arr->GetIntegerAt(i)); + arr->RemoveAt(4, 2); + int expected2[] = {1, 2, 3, 7, 10}; + EXPECT_EQ(FX_ArraySize(expected2), arr->GetCount()); + for (size_t i = 0; i < FX_ArraySize(expected2); ++i) + EXPECT_EQ(expected2[i], arr->GetIntegerAt(i)); + } + { + // When the range is out of bound, RemoveAt has no effect. + int elems[] = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10}; + ScopedArray arr(new CPDF_Array); + for (size_t i = 0; i < FX_ArraySize(elems); ++i) + arr->AddInteger(elems[i]); + arr->RemoveAt(8, 5); + EXPECT_EQ(FX_ArraySize(elems), arr->GetCount()); + for (size_t i = 0; i < FX_ArraySize(elems); ++i) + EXPECT_EQ(elems[i], arr->GetIntegerAt(i)); + arr->RemoveAt(0, 12); + EXPECT_EQ(FX_ArraySize(elems), arr->GetCount()); + arr->RemoveAt(11, 1); + EXPECT_EQ(FX_ArraySize(elems), arr->GetCount()); + } +} + +TEST(cpdf_array, InsertAt) { + { + int elems[] = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10}; + ScopedArray arr(new CPDF_Array); + for (size_t i = 0; i < FX_ArraySize(elems); ++i) + arr->InsertAt(i, new CPDF_Number(elems[i])); + EXPECT_EQ(FX_ArraySize(elems), arr->GetCount()); + for (size_t i = 0; i < FX_ArraySize(elems); ++i) + EXPECT_EQ(elems[i], arr->GetIntegerAt(i)); + arr->InsertAt(3, new CPDF_Number(33)); + arr->InsertAt(6, new CPDF_Number(55)); + arr->InsertAt(12, new CPDF_Number(12)); + int expected[] = {1, 2, 3, 33, 4, 5, 55, 6, 7, 8, 9, 10, 12}; + EXPECT_EQ(FX_ArraySize(expected), arr->GetCount()); + for (size_t i = 0; i < FX_ArraySize(expected); ++i) + EXPECT_EQ(expected[i], arr->GetIntegerAt(i)); + } + { + // When the position to insert is beyond the upper bound, + // an element is inserted at that position while other unfilled + // positions have nullptr. + int elems[] = {1, 2}; + ScopedArray arr(new CPDF_Array); + for (size_t i = 0; i < FX_ArraySize(elems); ++i) + arr->InsertAt(i, new CPDF_Number(elems[i])); + arr->InsertAt(10, new CPDF_Number(10)); + EXPECT_EQ(11, arr->GetCount()); + for (size_t i = 0; i < FX_ArraySize(elems); ++i) + EXPECT_EQ(elems[i], arr->GetIntegerAt(i)); + for (size_t i = FX_ArraySize(elems); i < 10; ++i) + EXPECT_EQ(nullptr, arr->GetObjectAt(i)); + EXPECT_EQ(10, arr->GetIntegerAt(10)); + } +} + +TEST(cpdf_array, Clone) { + { + // Basic case. + int elems[] = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10}; + ScopedArray arr(new CPDF_Array); + for (size_t i = 0; i < FX_ArraySize(elems); ++i) + arr->InsertAt(i, new CPDF_Number(elems[i])); + ScopedArray arr2(arr->Clone()->AsArray()); + EXPECT_EQ(arr->GetCount(), arr2->GetCount()); + for (size_t i = 0; i < FX_ArraySize(elems); ++i) { + // Clone() always create new objects. + EXPECT_NE(arr->GetObjectAt(i), arr2->GetObjectAt(i)); + EXPECT_EQ(arr->GetIntegerAt(i), arr2->GetIntegerAt(i)); + } + } + { + // Clone() with and without dereferencing reference objects. + static const size_t kNumOfRows = 3; + static const size_t kNumOfRowElems = 5; + int elems[kNumOfRows][kNumOfRowElems] = { + {1, 2, 3, 4, 5}, {10, 9, 8, 7, 6}, {11, 12, 13, 14, 15}}; + ScopedArray arr(new CPDF_Array); + // Indirect references to indirect objects. + std::unique_ptr obj_holder( + new CPDF_IndirectObjectHolder(nullptr)); + for (size_t i = 0; i < kNumOfRows; ++i) { + CPDF_Array* arr_elem = new CPDF_Array; + for (size_t j = 0; j < kNumOfRowElems; ++j) { + CPDF_Number* obj = new CPDF_Number(elems[i][j]); + // Starts object number from 1. + int obj_num = i * kNumOfRowElems + j + 1; + obj_holder->InsertIndirectObject(obj_num, obj); + arr_elem->InsertAt(j, new CPDF_Reference(obj_holder.get(), obj_num), + obj_holder.get()); + } + arr->InsertAt(i, arr_elem); + } + ASSERT_EQ(kNumOfRows, arr->GetCount()); + // Not dereferencing reference objects means just creating new references + // instead of new copies of direct objects. + ScopedArray arr1(arr->Clone(FALSE)->AsArray()); + EXPECT_EQ(arr->GetCount(), arr1->GetCount()); + // Dereferencing reference objects creates new copies of direct objects. + ScopedArray arr2(arr->Clone(TRUE)->AsArray()); + EXPECT_EQ(arr->GetCount(), arr2->GetCount()); + for (size_t i = 0; i < kNumOfRows; ++i) { + CPDF_Array* arr_elem = arr->GetObjectAt(i)->AsArray(); + CPDF_Array* arr1_elem = arr1->GetObjectAt(i)->AsArray(); + CPDF_Array* arr2_elem = arr2->GetObjectAt(i)->AsArray(); + EXPECT_NE(arr_elem, arr1_elem); + EXPECT_NE(arr_elem, arr2_elem); + for (size_t j = 0; j < kNumOfRowElems; ++j) { + auto elem_obj = arr_elem->GetObjectAt(j); + auto elem_obj1 = arr1_elem->GetObjectAt(j); + auto elem_obj2 = arr2_elem->GetObjectAt(j); + // Results from not deferencing reference objects. + EXPECT_NE(elem_obj, elem_obj1); + EXPECT_TRUE(elem_obj1->IsReference()); + EXPECT_EQ(elem_obj->GetDirect(), elem_obj1->GetDirect()); + EXPECT_EQ(elem_obj->GetInteger(), elem_obj1->GetInteger()); + // Results from deferencing reference objects. + EXPECT_NE(elem_obj, elem_obj2); + EXPECT_TRUE(elem_obj2->IsNumber()); + EXPECT_NE(elem_obj->GetDirect(), elem_obj2); + EXPECT_EQ(elem_obj->GetObjNum(), elem_obj2->GetObjNum()); + EXPECT_EQ(elem_obj->GetInteger(), elem_obj2->GetInteger()); + } + } + arr.reset(); + ASSERT_EQ(kNumOfRows, arr1->GetCount()); + for (size_t i = 0; i < kNumOfRows; ++i) { + for (size_t j = 0; j < kNumOfRowElems; ++j) { + // Results from not deferencing reference objects. + auto elem_obj1 = arr1->GetObjectAt(i)->AsArray()->GetObjectAt(j); + EXPECT_TRUE(elem_obj1->IsReference()); + EXPECT_EQ(elems[i][j], elem_obj1->GetInteger()); + // Results from deferencing reference objects. + EXPECT_EQ(elems[i][j], + arr2->GetObjectAt(i)->AsArray()->GetIntegerAt(j)); + } + } + } +} + +TEST(cpdf_array, Iterator) { + int elems[] = {-23, -11, 3, 455, 2345877, + 0, 7895330, -12564334, 10000, -100000}; + ScopedArray arr(new CPDF_Array); + for (size_t i = 0; i < FX_ArraySize(elems); ++i) + arr->InsertAt(i, new CPDF_Number(elems[i])); + size_t index = 0; + for (const auto& it : *arr) + EXPECT_EQ(elems[index++], it->AsNumber()->GetInteger()); +} diff --git a/core/fpdfapi/fpdf_parser/include/cpdf_array.h b/core/fpdfapi/fpdf_parser/include/cpdf_array.h index ac3bf41b45..dfe03b9d70 100644 --- a/core/fpdfapi/fpdf_parser/include/cpdf_array.h +++ b/core/fpdfapi/fpdf_parser/include/cpdf_array.h @@ -16,6 +16,9 @@ class CPDF_Array : public CPDF_Object { public: + using iterator = std::vector::iterator; + using const_iterator = std::vector::const_iterator; + CPDF_Array(); // CPDF_Object. @@ -57,6 +60,11 @@ class CPDF_Array : public CPDF_Object { AddReference(pDoc, obj->GetObjNum()); } + iterator begin() { return m_Objects.begin(); } + iterator end() { return m_Objects.end(); } + const_iterator begin() const { return m_Objects.begin(); } + const_iterator end() const { return m_Objects.end(); } + protected: ~CPDF_Array() override; diff --git a/pdfium.gyp b/pdfium.gyp index d4b22bd918..c43e9a9324 100644 --- a/pdfium.gyp +++ b/pdfium.gyp @@ -930,6 +930,7 @@ 'core/fpdfapi/fpdf_font/fpdf_font_unittest.cpp', 'core/fpdfapi/fpdf_page/fpdf_page_parser_unittest.cpp', 'core/fpdfapi/fpdf_page/fpdf_page_parser_old_unittest.cpp', + 'core/fpdfapi/fpdf_parser/cpdf_array_unittest.cpp', 'core/fpdfapi/fpdf_parser/cpdf_object_unittest.cpp', 'core/fpdfapi/fpdf_parser/cpdf_parser_unittest.cpp', 'core/fpdfapi/fpdf_parser/cpdf_simple_parser_unittest.cpp', -- cgit v1.2.3