1 // Copyright 2023 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/object_tree_traversal_util.h"
6
7 #include <stdint.h>
8
9 #include <set>
10
11 #include "core/fpdfapi/parser/cpdf_document.h"
12 #include "testing/embedder_test.h"
13 #include "testing/gmock/include/gmock/gmock.h"
14 #include "testing/gtest/include/gtest/gtest.h"
15
16 using testing::UnorderedElementsAreArray;
17 using ObjectTreeTraversalUtilEmbedderTest = EmbedderTest;
18
19 namespace {
20
GetCPDFDocument(FPDF_DOCUMENT document)21 CPDF_Document* GetCPDFDocument(FPDF_DOCUMENT document) {
22 // This is cheating slightly to avoid a layering violation, since this file
23 // cannot include fpdfsdk/cpdfsdk_helpers.h to get access to
24 // CPDFDocumentFromFPDFDocument().
25 return reinterpret_cast<CPDF_Document*>((document));
26 }
27
28 } // namespace
29
TEST_F(ObjectTreeTraversalUtilEmbedderTest,GetObjectsWithReferencesBasic)30 TEST_F(ObjectTreeTraversalUtilEmbedderTest, GetObjectsWithReferencesBasic) {
31 ASSERT_TRUE(OpenDocument("hello_world.pdf"));
32 CPDF_Document* doc = GetCPDFDocument(document());
33 std::set<uint32_t> referenced_objects = GetObjectsWithReferences(doc);
34 EXPECT_THAT(referenced_objects,
35 UnorderedElementsAreArray({1, 2, 3, 4, 5, 6}));
36 }
37
TEST_F(ObjectTreeTraversalUtilEmbedderTest,GetObjectsWithReferencesNewDoc)38 TEST_F(ObjectTreeTraversalUtilEmbedderTest, GetObjectsWithReferencesNewDoc) {
39 ScopedFPDFDocument new_doc(FPDF_CreateNewDocument());
40 CPDF_Document* doc = GetCPDFDocument(new_doc.get());
41 std::set<uint32_t> referenced_objects = GetObjectsWithReferences(doc);
42 // Empty documents have a catalog and an empty pages object.
43 EXPECT_THAT(referenced_objects, UnorderedElementsAreArray({1, 2}));
44 }
45
TEST_F(ObjectTreeTraversalUtilEmbedderTest,GetObjectsWithReferencesCircularRefs)46 TEST_F(ObjectTreeTraversalUtilEmbedderTest,
47 GetObjectsWithReferencesCircularRefs) {
48 ASSERT_TRUE(OpenDocument("circular_viewer_ref.pdf"));
49 CPDF_Document* doc = GetCPDFDocument(document());
50 std::set<uint32_t> referenced_objects = GetObjectsWithReferences(doc);
51 // The trailer points at a catalog, and the catalog only references itself.
52 EXPECT_THAT(referenced_objects, UnorderedElementsAreArray({1}));
53 }
54
TEST_F(ObjectTreeTraversalUtilEmbedderTest,GetObjectsWithReferencesCrossRefStream)55 TEST_F(ObjectTreeTraversalUtilEmbedderTest,
56 GetObjectsWithReferencesCrossRefStream) {
57 ASSERT_TRUE(OpenDocument("bug_1399.pdf"));
58 CPDF_Document* doc = GetCPDFDocument(document());
59 std::set<uint32_t> referenced_objects = GetObjectsWithReferences(doc);
60 // The trailer is the dictionary inside /XRef object 16 0. Note that it
61 // references object 3 0, but the rest of the document does not.
62 EXPECT_THAT(referenced_objects,
63 UnorderedElementsAreArray({1, 2, 3, 4, 5, 12, 13, 14, 16}));
64 }
65
TEST_F(ObjectTreeTraversalUtilEmbedderTest,GetObjectsWithReferencesObjectZero)66 TEST_F(ObjectTreeTraversalUtilEmbedderTest,
67 GetObjectsWithReferencesObjectZero) {
68 ASSERT_TRUE(OpenDocument("rectangles_object_zero.pdf"));
69 CPDF_Document* doc = GetCPDFDocument(document());
70 std::set<uint32_t> referenced_objects = GetObjectsWithReferences(doc);
71 EXPECT_THAT(referenced_objects, UnorderedElementsAreArray({1, 2, 3, 4}));
72 }
73
TEST_F(ObjectTreeTraversalUtilEmbedderTest,GetObjectsWithMultipleReferencesBasic)74 TEST_F(ObjectTreeTraversalUtilEmbedderTest,
75 GetObjectsWithMultipleReferencesBasic) {
76 ASSERT_TRUE(OpenDocument("hello_world.pdf"));
77 CPDF_Document* doc = GetCPDFDocument(document());
78 std::set<uint32_t> referenced_objects = GetObjectsWithMultipleReferences(doc);
79 EXPECT_TRUE(referenced_objects.empty());
80 }
81
TEST_F(ObjectTreeTraversalUtilEmbedderTest,GetObjectsWithMultipleReferencesNewDoc)82 TEST_F(ObjectTreeTraversalUtilEmbedderTest,
83 GetObjectsWithMultipleReferencesNewDoc) {
84 ScopedFPDFDocument new_doc(FPDF_CreateNewDocument());
85 CPDF_Document* doc = GetCPDFDocument(new_doc.get());
86 std::set<uint32_t> referenced_objects = GetObjectsWithMultipleReferences(doc);
87 EXPECT_TRUE(referenced_objects.empty());
88 }
89
TEST_F(ObjectTreeTraversalUtilEmbedderTest,GetObjectsWithMultipleReferencesCircularRefs)90 TEST_F(ObjectTreeTraversalUtilEmbedderTest,
91 GetObjectsWithMultipleReferencesCircularRefs) {
92 ASSERT_TRUE(OpenDocument("circular_viewer_ref.pdf"));
93 CPDF_Document* doc = GetCPDFDocument(document());
94 std::set<uint32_t> referenced_objects = GetObjectsWithMultipleReferences(doc);
95 EXPECT_TRUE(referenced_objects.empty());
96 }
97
TEST_F(ObjectTreeTraversalUtilEmbedderTest,GetObjectsWithMultipleReferencesSharedObjects)98 TEST_F(ObjectTreeTraversalUtilEmbedderTest,
99 GetObjectsWithMultipleReferencesSharedObjects) {
100 ASSERT_TRUE(OpenDocument("hello_world_2_pages.pdf"));
101 CPDF_Document* doc = GetCPDFDocument(document());
102 std::set<uint32_t> referenced_objects = GetObjectsWithMultipleReferences(doc);
103 EXPECT_THAT(referenced_objects, UnorderedElementsAreArray({5, 6, 7}));
104 }
105
TEST_F(ObjectTreeTraversalUtilEmbedderTest,GetObjectsWithMultipleReferencesObjectZero)106 TEST_F(ObjectTreeTraversalUtilEmbedderTest,
107 GetObjectsWithMultipleReferencesObjectZero) {
108 ASSERT_TRUE(OpenDocument("rectangles_object_zero.pdf"));
109 CPDF_Document* doc = GetCPDFDocument(document());
110 std::set<uint32_t> referenced_objects = GetObjectsWithMultipleReferences(doc);
111 EXPECT_TRUE(referenced_objects.empty());
112 }
113