xref: /aosp_15_r20/external/pdfium/core/fpdfapi/parser/cpdf_array_unittest.cpp (revision 3ac0a46f773bac49fa9476ec2b1cf3f8da5ec3a4)
1 // Copyright 2016 The PDFium Authors
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4 
5 #include "core/fpdfapi/parser/cpdf_array.h"
6 
7 #include <iterator>
8 #include <memory>
9 #include <utility>
10 
11 #include "core/fpdfapi/parser/cpdf_boolean.h"
12 #include "core/fpdfapi/parser/cpdf_dictionary.h"
13 #include "core/fpdfapi/parser/cpdf_number.h"
14 #include "core/fpdfapi/parser/cpdf_reference.h"
15 #include "testing/gtest/include/gtest/gtest.h"
16 
TEST(ArrayTest,GetBooleanAt)17 TEST(ArrayTest, GetBooleanAt) {
18   auto arr = pdfium::MakeRetain<CPDF_Array>();
19   arr->AppendNew<CPDF_Boolean>(true);
20   arr->AppendNew<CPDF_Boolean>(false);
21   arr->AppendNew<CPDF_Number>(100);
22   arr->AppendNew<CPDF_Number>(0);
23 
24   ASSERT_EQ(4u, arr->size());
25   EXPECT_TRUE(arr->GetBooleanAt(0, true));
26   EXPECT_TRUE(arr->GetBooleanAt(0, false));
27   EXPECT_FALSE(arr->GetBooleanAt(1, true));
28   EXPECT_FALSE(arr->GetBooleanAt(1, false));
29   EXPECT_TRUE(arr->GetBooleanAt(2, true));
30   EXPECT_FALSE(arr->GetBooleanAt(2, false));
31   EXPECT_TRUE(arr->GetBooleanAt(3, true));
32   EXPECT_FALSE(arr->GetBooleanAt(3, false));
33   EXPECT_TRUE(arr->GetBooleanAt(99, true));
34   EXPECT_FALSE(arr->GetBooleanAt(99, false));
35 }
36 
TEST(ArrayTest,RemoveAt)37 TEST(ArrayTest, RemoveAt) {
38   {
39     const int elems[] = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10};
40     auto arr = pdfium::MakeRetain<CPDF_Array>();
41     for (size_t i = 0; i < std::size(elems); ++i)
42       arr->AppendNew<CPDF_Number>(elems[i]);
43     for (size_t i = 0; i < 3; ++i)
44       arr->RemoveAt(3);
45     const int expected[] = {1, 2, 3, 7, 8, 9, 10};
46     ASSERT_EQ(std::size(expected), arr->size());
47     for (size_t i = 0; i < std::size(expected); ++i)
48       EXPECT_EQ(expected[i], arr->GetIntegerAt(i));
49     arr->RemoveAt(4);
50     arr->RemoveAt(4);
51     const int expected2[] = {1, 2, 3, 7, 10};
52     ASSERT_EQ(std::size(expected2), arr->size());
53     for (size_t i = 0; i < std::size(expected2); ++i)
54       EXPECT_EQ(expected2[i], arr->GetIntegerAt(i));
55   }
56   {
57     // When the range is out of bound, RemoveAt() has no effect.
58     const int elems[] = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10};
59     auto arr = pdfium::MakeRetain<CPDF_Array>();
60     for (size_t i = 0; i < std::size(elems); ++i)
61       arr->AppendNew<CPDF_Number>(elems[i]);
62     arr->RemoveAt(11);
63     EXPECT_EQ(std::size(elems), arr->size());
64   }
65 }
66 
TEST(ArrayTest,Clear)67 TEST(ArrayTest, Clear) {
68   const int elems[] = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10};
69   auto arr = pdfium::MakeRetain<CPDF_Array>();
70   EXPECT_EQ(0U, arr->size());
71   for (size_t i = 0; i < std::size(elems); ++i)
72     arr->AppendNew<CPDF_Number>(elems[i]);
73   EXPECT_EQ(std::size(elems), arr->size());
74   arr->Clear();
75   EXPECT_EQ(0U, arr->size());
76 }
77 
TEST(ArrayTest,SetAtBeyond)78 TEST(ArrayTest, SetAtBeyond) {
79   auto arr = pdfium::MakeRetain<CPDF_Array>();
80   EXPECT_FALSE(arr->SetNewAt<CPDF_Number>(0, 0));
81   EXPECT_TRUE(arr->InsertNewAt<CPDF_Number>(0, 0));
82   EXPECT_FALSE(arr->SetNewAt<CPDF_Number>(1, 0));
83 }
84 
TEST(ArrayTest,InsertAt)85 TEST(ArrayTest, InsertAt) {
86   const int elems[] = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10};
87   auto arr = pdfium::MakeRetain<CPDF_Array>();
88   for (size_t i = 0; i < std::size(elems); ++i)
89     arr->InsertNewAt<CPDF_Number>(i, elems[i]);
90   ASSERT_EQ(std::size(elems), arr->size());
91   for (size_t i = 0; i < std::size(elems); ++i)
92     EXPECT_EQ(elems[i], arr->GetIntegerAt(i));
93   arr->InsertNewAt<CPDF_Number>(3, 33);
94   arr->InsertNewAt<CPDF_Number>(6, 55);
95   arr->InsertNewAt<CPDF_Number>(12, 12);
96   const int expected[] = {1, 2, 3, 33, 4, 5, 55, 6, 7, 8, 9, 10, 12};
97   ASSERT_EQ(std::size(expected), arr->size());
98   for (size_t i = 0; i < std::size(expected); ++i)
99     EXPECT_EQ(expected[i], arr->GetIntegerAt(i));
100 }
101 
TEST(ArrayTest,InsertAtBeyond)102 TEST(ArrayTest, InsertAtBeyond) {
103   auto arr = pdfium::MakeRetain<CPDF_Array>();
104   EXPECT_FALSE(arr->InsertNewAt<CPDF_Number>(1, 0));
105   EXPECT_TRUE(arr->InsertNewAt<CPDF_Number>(0, 0));
106   EXPECT_FALSE(arr->InsertNewAt<CPDF_Number>(2, 0));
107 }
108 
TEST(ArrayTest,Clone)109 TEST(ArrayTest, Clone) {
110   {
111     // Basic case.
112     const int elems[] = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10};
113     auto arr = pdfium::MakeRetain<CPDF_Array>();
114     for (size_t i = 0; i < std::size(elems); ++i)
115       arr->InsertNewAt<CPDF_Number>(i, elems[i]);
116     RetainPtr<CPDF_Array> arr2 = ToArray(arr->Clone());
117     ASSERT_EQ(arr->size(), arr2->size());
118     for (size_t i = 0; i < std::size(elems); ++i) {
119       // Clone() always create new objects.
120       EXPECT_NE(arr->GetObjectAt(i), arr2->GetObjectAt(i));
121       EXPECT_EQ(arr->GetIntegerAt(i), arr2->GetIntegerAt(i));
122     }
123   }
124   {
125     // Clone() with and without dereferencing reference objects.
126     static const size_t kNumOfRows = 3;
127     static const size_t kNumOfRowElems = 5;
128     const int elems[kNumOfRows][kNumOfRowElems] = {
129         {1, 2, 3, 4, 5}, {10, 9, 8, 7, 6}, {11, 12, 13, 14, 15}};
130     auto arr = pdfium::MakeRetain<CPDF_Array>();
131     // Indirect references to indirect objects.
132     auto obj_holder = std::make_unique<CPDF_IndirectObjectHolder>();
133     for (size_t i = 0; i < kNumOfRows; ++i) {
134       auto arr_elem = pdfium::MakeRetain<CPDF_Array>();
135       for (size_t j = 0; j < kNumOfRowElems; ++j) {
136         auto obj = pdfium::MakeRetain<CPDF_Number>(elems[i][j]);
137         // Starts object number from 1.
138         int obj_num = i * kNumOfRowElems + j + 1;
139         obj_holder->ReplaceIndirectObjectIfHigherGeneration(obj_num,
140                                                             std::move(obj));
141         arr_elem->InsertNewAt<CPDF_Reference>(j, obj_holder.get(), obj_num);
142       }
143       arr->InsertAt(i, std::move(arr_elem));
144     }
145     ASSERT_EQ(kNumOfRows, arr->size());
146     // Not dereferencing reference objects means just creating new references
147     // instead of new copies of direct objects.
148     RetainPtr<CPDF_Array> arr1 = ToArray(arr->Clone());
149     ASSERT_EQ(arr->size(), arr1->size());
150     // Dereferencing reference objects creates new copies of direct objects.
151     RetainPtr<CPDF_Array> arr2 = ToArray(arr->CloneDirectObject());
152     ASSERT_EQ(arr->size(), arr2->size());
153     for (size_t i = 0; i < kNumOfRows; ++i) {
154       const CPDF_Array* arr_elem = arr->GetObjectAt(i)->AsArray();
155       const CPDF_Array* arr1_elem = arr1->GetObjectAt(i)->AsArray();
156       const CPDF_Array* arr2_elem = arr2->GetObjectAt(i)->AsArray();
157       EXPECT_NE(arr_elem, arr1_elem);
158       EXPECT_NE(arr_elem, arr2_elem);
159       for (size_t j = 0; j < kNumOfRowElems; ++j) {
160         auto elem_obj = arr_elem->GetObjectAt(j);
161         auto elem_obj1 = arr1_elem->GetObjectAt(j);
162         auto elem_obj2 = arr2_elem->GetObjectAt(j);
163         // Results from not deferencing reference objects.
164         EXPECT_NE(elem_obj, elem_obj1);
165         EXPECT_TRUE(elem_obj1->IsReference());
166         EXPECT_EQ(elem_obj->GetDirect(), elem_obj1->GetDirect());
167         EXPECT_EQ(elem_obj->GetInteger(), elem_obj1->GetInteger());
168         // Results from deferencing reference objects.
169         EXPECT_NE(elem_obj, elem_obj2);
170         EXPECT_TRUE(elem_obj2->IsNumber());
171         EXPECT_NE(elem_obj->GetDirect(), elem_obj2);
172         EXPECT_EQ(elem_obj->GetObjNum(), elem_obj2->GetObjNum());
173         EXPECT_EQ(elem_obj->GetInteger(), elem_obj2->GetInteger());
174       }
175     }
176     arr.Reset();
177     ASSERT_EQ(kNumOfRows, arr1->size());
178     for (size_t i = 0; i < kNumOfRows; ++i) {
179       for (size_t j = 0; j < kNumOfRowElems; ++j) {
180         // Results from not deferencing reference objects.
181         auto elem_obj1 = arr1->GetObjectAt(i)->AsArray()->GetObjectAt(j);
182         EXPECT_TRUE(elem_obj1->IsReference());
183         EXPECT_EQ(elems[i][j], elem_obj1->GetInteger());
184         // Results from deferencing reference objects.
185         EXPECT_EQ(elems[i][j],
186                   arr2->GetObjectAt(i)->AsArray()->GetIntegerAt(j));
187       }
188     }
189   }
190 }
191 
TEST(ArrayTest,Find)192 TEST(ArrayTest, Find) {
193   auto arr = pdfium::MakeRetain<CPDF_Array>();
194   auto dict0 = pdfium::MakeRetain<CPDF_Dictionary>();
195   auto dict1 = pdfium::MakeRetain<CPDF_Dictionary>();
196   auto dict2 = pdfium::MakeRetain<CPDF_Dictionary>();
197   arr->Append(dict0);
198   arr->Append(dict1);
199 
200   absl::optional<size_t> maybe_found = arr->Find(nullptr);
201   EXPECT_FALSE(maybe_found.has_value());
202 
203   maybe_found = arr->Find(dict0.Get());
204   ASSERT_TRUE(maybe_found.has_value());
205   EXPECT_EQ(0u, maybe_found.value());
206 
207   maybe_found = arr->Find(dict1.Get());
208   ASSERT_TRUE(maybe_found.has_value());
209   EXPECT_EQ(1u, maybe_found.value());
210 
211   maybe_found = arr->Find(dict2.Get());
212   EXPECT_FALSE(maybe_found.has_value());
213 }
214 
TEST(ArrayTest,Contains)215 TEST(ArrayTest, Contains) {
216   auto arr = pdfium::MakeRetain<CPDF_Array>();
217   auto dict0 = pdfium::MakeRetain<CPDF_Dictionary>();
218   auto dict1 = pdfium::MakeRetain<CPDF_Dictionary>();
219   auto dict2 = pdfium::MakeRetain<CPDF_Dictionary>();
220   arr->Append(dict0);
221   arr->Append(dict1);
222   EXPECT_TRUE(arr->Contains(dict0.Get()));
223   EXPECT_TRUE(arr->Contains(dict1.Get()));
224   EXPECT_FALSE(arr->Contains(dict2.Get()));
225 }
226 
TEST(ArrayTest,Iterator)227 TEST(ArrayTest, Iterator) {
228   const int elems[] = {-23, -11,     3,         455,   2345877,
229                        0,   7895330, -12564334, 10000, -100000};
230   auto arr = pdfium::MakeRetain<CPDF_Array>();
231   for (size_t i = 0; i < std::size(elems); ++i)
232     arr->InsertNewAt<CPDF_Number>(i, elems[i]);
233 
234   size_t index = 0;
235   CPDF_ArrayLocker locker(arr);
236   for (const auto& it : locker)
237     EXPECT_EQ(elems[index++], it->AsNumber()->GetInteger());
238   EXPECT_EQ(std::size(elems), index);
239 }
240