• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 // Copyright 2021 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/fpdfdoc/cpdf_action.h"
6 
7 #include "core/fpdfapi/parser/cpdf_dictionary.h"
8 #include "core/fpdfapi/parser/cpdf_name.h"
9 #include "core/fpdfapi/parser/cpdf_string.h"
10 #include "core/fxcrt/retain_ptr.h"
11 #include "testing/gtest/include/gtest/gtest.h"
12 
13 namespace {
14 
CreateActionDictWithType(const ByteString & action_type)15 RetainPtr<CPDF_Dictionary> CreateActionDictWithType(
16     const ByteString& action_type) {
17   auto dict = pdfium::MakeRetain<CPDF_Dictionary>();
18   dict->SetNewFor<CPDF_Name>("Type", "Action");
19   dict->SetNewFor<CPDF_Name>("S", action_type);
20   return dict;
21 }
22 
CreateActionDictWithoutType(const ByteString & action_type)23 RetainPtr<CPDF_Dictionary> CreateActionDictWithoutType(
24     const ByteString& action_type) {
25   auto dict = pdfium::MakeRetain<CPDF_Dictionary>();
26   dict->SetNewFor<CPDF_Name>("S", action_type);
27   return dict;
28 }
29 
CreateActionDictWithInvalidType(const ByteString & action_type)30 RetainPtr<CPDF_Dictionary> CreateActionDictWithInvalidType(
31     const ByteString& action_type) {
32   auto dict = pdfium::MakeRetain<CPDF_Dictionary>();
33   dict->SetNewFor<CPDF_Name>("Type", "Lights");
34   dict->SetNewFor<CPDF_Name>("S", action_type);
35   return dict;
36 }
37 
CreateInvalidActionDictWithType(const ByteString & action_type)38 RetainPtr<CPDF_Dictionary> CreateInvalidActionDictWithType(
39     const ByteString& action_type) {
40   auto dict = pdfium::MakeRetain<CPDF_Dictionary>();
41   dict->SetNewFor<CPDF_Name>("Type", "Action");
42   dict->SetNewFor<CPDF_String>("S", action_type);
43   return dict;
44 }
45 
CreateInvalidActionDictWithoutType(const ByteString & action_type)46 RetainPtr<CPDF_Dictionary> CreateInvalidActionDictWithoutType(
47     const ByteString& action_type) {
48   auto dict = pdfium::MakeRetain<CPDF_Dictionary>();
49   dict->SetNewFor<CPDF_String>("S", action_type);
50   return dict;
51 }
52 
53 }  // namespace
54 
TEST(CPDFActionTest,GetType)55 TEST(CPDFActionTest, GetType) {
56   static constexpr struct {
57     const char* action_type;
58     CPDF_Action::Type expected_type;
59   } kValidTestCases[] = {
60       {"GoTo", CPDF_Action::Type::kGoTo},
61       {"GoToR", CPDF_Action::Type::kGoToR},
62       {"GoToE", CPDF_Action::Type::kGoToE},
63       {"Launch", CPDF_Action::Type::kLaunch},
64       {"Thread", CPDF_Action::Type::kThread},
65       {"URI", CPDF_Action::Type::kURI},
66       {"Sound", CPDF_Action::Type::kSound},
67       {"Movie", CPDF_Action::Type::kMovie},
68       {"Hide", CPDF_Action::Type::kHide},
69       {"Named", CPDF_Action::Type::kNamed},
70       {"SubmitForm", CPDF_Action::Type::kSubmitForm},
71       {"ResetForm", CPDF_Action::Type::kResetForm},
72       {"ImportData", CPDF_Action::Type::kImportData},
73       {"JavaScript", CPDF_Action::Type::kJavaScript},
74       {"SetOCGState", CPDF_Action::Type::kSetOCGState},
75       {"Rendition", CPDF_Action::Type::kRendition},
76       {"Trans", CPDF_Action::Type::kTrans},
77       {"GoTo3DView", CPDF_Action::Type::kGoTo3DView},
78   };
79 
80   // Test correctly constructed actions.
81   for (const auto& test_case : kValidTestCases) {
82     {
83       // Type is present.
84       CPDF_Action action(CreateActionDictWithType(test_case.action_type));
85       EXPECT_EQ(test_case.expected_type, action.GetType());
86     }
87     {
88       // Type is optional, so omitting it is ok.
89       CPDF_Action action(CreateActionDictWithoutType(test_case.action_type));
90       EXPECT_EQ(test_case.expected_type, action.GetType());
91     }
92   }
93 
94   // Test incorrectly constructed actions.
95   for (const auto& test_case : kValidTestCases) {
96     {
97       // Type is optional, but must be valid if present.
98       CPDF_Action action(
99           CreateActionDictWithInvalidType(test_case.action_type));
100       EXPECT_EQ(CPDF_Action::Type::kUnknown, action.GetType());
101     }
102     {
103       // The action type (/S) must be a name.
104       CPDF_Action action(
105           CreateInvalidActionDictWithType(test_case.action_type));
106       EXPECT_EQ(CPDF_Action::Type::kUnknown, action.GetType());
107     }
108     {
109       // The action type (/S) must be a name.
110       CPDF_Action action(
111           CreateInvalidActionDictWithoutType(test_case.action_type));
112       EXPECT_EQ(CPDF_Action::Type::kUnknown, action.GetType());
113     }
114   }
115 
116   static constexpr const char* kInvalidTestCases[] = {
117       "Camera",
118       "Javascript",
119       "Unknown",
120   };
121 
122   // Test invalid actions.
123   for (const char* test_case : kInvalidTestCases) {
124     CPDF_Action action(CreateActionDictWithType(test_case));
125     EXPECT_EQ(CPDF_Action::Type::kUnknown, action.GetType());
126   }
127 }
128