1#include <QtTest/QTest>
2
3#include <poppler-qt6.h>
4#include <poppler-form.h>
5#include <poppler-private.h>
6#include <Form.h>
7
8class TestForms : public QObject
9{
10 Q_OBJECT
11public:
12 explicit TestForms(QObject *parent = nullptr) : QObject(parent) { }
13private slots:
14 void testCheckbox(); // Test for issue #655
15 void testCheckboxIssue159(); // Test for issue #159
16 void testSetIcon(); // Test that setIcon will always be valid.
17 void testSetPrintable();
18 void testSetAppearanceText();
19 void testStandAloneWidgets(); // check for 'de facto' tooltips. Issue #34
20 void testUnicodeFieldAttributes();
21};
22
23void TestForms::testCheckbox()
24{
25 // Test for checkbox issue #655
26 std::unique_ptr<Poppler::Document> document = Poppler::Document::load(TESTDATADIR "/unittestcases/latex-hyperref-checkbox-issue-655.pdf");
27 QVERIFY(document);
28
29 std::unique_ptr<Poppler::Page> page(document->page(index: 0));
30 QVERIFY(page);
31
32 std::vector<std::unique_ptr<Poppler::FormField>> forms = page->formFields();
33 QCOMPARE(forms.size(), 1);
34
35 Poppler::FormField *form = forms.at(n: 0).get();
36 QCOMPARE(form->type(), Poppler::FormField::FormButton);
37
38 Poppler::FormFieldButton *chkFormFieldButton = static_cast<Poppler::FormFieldButton *>(form);
39
40 // Test this is actually a Checkbox
41 QCOMPARE(chkFormFieldButton->buttonType(), Poppler::FormFieldButton::CheckBox);
42
43 // checkbox comes initially 'unchecked'
44 QCOMPARE(chkFormFieldButton->state(), false);
45 // let's mark it as 'checked'
46 chkFormFieldButton->setState(true);
47 // now test if it was succesfully 'checked'
48 QCOMPARE(chkFormFieldButton->state(), true);
49}
50
51void TestForms::testStandAloneWidgets()
52{
53 // Check for 'de facto' tooltips. Issue #34
54 std::unique_ptr<Poppler::Document> document = Poppler::Document::load(TESTDATADIR "/unittestcases/tooltip.pdf");
55 QVERIFY(document);
56
57 std::unique_ptr<Poppler::Page> page = document->page(index: 0);
58 QVERIFY(page);
59
60 std::vector<std::unique_ptr<Poppler::FormField>> forms = page->formFields();
61
62 QCOMPARE(forms.size(), 3);
63
64 for (const std::unique_ptr<Poppler::FormField> &field : forms) {
65 QCOMPARE(field->type(), Poppler::FormField::FormButton);
66
67 Poppler::FormFieldButton *fieldButton = static_cast<Poppler::FormFieldButton *>(field.get());
68 QCOMPARE(fieldButton->buttonType(), Poppler::FormFieldButton::Push);
69
70 FormField *ff = Poppler::FormFieldData::getFormWidget(f: fieldButton)->getField();
71 QVERIFY(ff);
72 QCOMPARE(ff->isStandAlone(), true);
73
74 // tooltip.pdf has only these 3 standalone widgets
75 QVERIFY(field->uiName() == QStringLiteral("This is a tooltip!") || // clazy:exclude=qstring-allocations
76 field->uiName() == QStringLiteral("Sulfuric acid") || field->uiName() == QString::fromUtf8("little Gauß"));
77 }
78}
79
80void TestForms::testCheckboxIssue159()
81{
82 // Test for checkbox issue #159
83 std::unique_ptr<Poppler::Document> document = Poppler::Document::load(TESTDATADIR "/unittestcases/checkbox_issue_159.pdf");
84 QVERIFY(document);
85
86 std::unique_ptr<Poppler::Page> page = document->page(index: 0);
87 QVERIFY(page);
88
89 Poppler::FormFieldButton *beerFieldButton = nullptr;
90 Poppler::FormFieldButton *wineFieldButton = nullptr;
91
92 std::vector<std::unique_ptr<Poppler::FormField>> forms = page->formFields();
93
94 // Let's find and assign the "Wine" and "Beer" radio buttons
95 for (const std::unique_ptr<Poppler::FormField> &field : forms) {
96 if (field->type() != Poppler::FormField::FormButton) {
97 continue;
98 }
99
100 Poppler::FormFieldButton *fieldButton = static_cast<Poppler::FormFieldButton *>(field.get());
101 if (fieldButton->buttonType() != Poppler::FormFieldButton::Radio) {
102 continue;
103 }
104
105 // printf("%s \n", fieldButton->caption().toLatin1().data());
106 if (fieldButton->caption() == QStringLiteral("Wine")) {
107 wineFieldButton = fieldButton;
108 } else if (fieldButton->caption() == QStringLiteral("Beer")) {
109 beerFieldButton = fieldButton;
110 }
111 }
112
113 // "Beer" and "Wine" radiobuttons belong to the same RadioButton group.
114 // So selecting one should unselect the other.
115 QVERIFY(beerFieldButton);
116 QVERIFY(wineFieldButton);
117
118 // Test that the RadioButton group comes with "Beer" initially selected
119 QCOMPARE(beerFieldButton->state(), true);
120
121 // Now select "Wine". As a result "Beer" should no longer be selected.
122 wineFieldButton->setState(true);
123
124 // Test that "Beer" is indeed not reporting as being selected
125 QCOMPARE(beerFieldButton->state(), false);
126}
127
128void TestForms::testSetIcon()
129{
130 std::unique_ptr<Poppler::Document> document = Poppler::Document::load(TESTDATADIR "/unittestcases/form_set_icon.pdf");
131 QVERIFY(document);
132
133 std::unique_ptr<Poppler::Page> page = document->page(index: 0);
134 QVERIFY(page);
135
136 std::vector<std::unique_ptr<Poppler::FormField>> forms = page->formFields();
137
138 Poppler::FormFieldButton *anmButton = nullptr;
139
140 // First we are finding the field which will have its icon changed
141 for (const std::unique_ptr<Poppler::FormField> &field : forms) {
142
143 if (field->type() != Poppler::FormField::FormButton) {
144 continue;
145 }
146
147 Poppler::FormFieldButton *fieldButton = static_cast<Poppler::FormFieldButton *>(field.get());
148 if (field->name() == QStringLiteral("anm0")) {
149 anmButton = fieldButton;
150 }
151 }
152
153 QVERIFY(anmButton);
154
155 // Then we set the Icon on this field, for every other field
156 // And verify if it has a valid icon
157 for (const std::unique_ptr<Poppler::FormField> &field : forms) {
158
159 if (field->type() != Poppler::FormField::FormButton) {
160 continue;
161 }
162
163 Poppler::FormFieldButton *fieldButton = static_cast<Poppler::FormFieldButton *>(field.get());
164 if (field->name() == QStringLiteral("anm0")) {
165 continue;
166 }
167
168 Poppler::FormFieldIcon newIcon = fieldButton->icon();
169
170 anmButton->setIcon(newIcon);
171
172 Poppler::FormFieldIcon anmIcon = anmButton->icon();
173
174 QVERIFY(Poppler::FormFieldIconData::getData(anmIcon));
175 QVERIFY(Poppler::FormFieldIconData::getData(anmIcon)->icon);
176
177 QCOMPARE(Poppler::FormFieldIconData::getData(anmIcon)->icon->lookupNF("AP").dictLookupNF("N").getRef().num, Poppler::FormFieldIconData::getData(newIcon)->icon->lookupNF("AP").dictLookupNF("N").getRef().num);
178 }
179
180 // Just making sure that setting a invalid icon will still produce a valid icon.
181 anmButton->setIcon(Poppler::FormFieldIcon(nullptr));
182 Poppler::FormFieldIcon anmIcon = anmButton->icon();
183
184 QVERIFY(Poppler::FormFieldIconData::getData(anmIcon));
185 QVERIFY(Poppler::FormFieldIconData::getData(anmIcon)->icon);
186}
187
188void TestForms::testSetPrintable()
189{
190 std::unique_ptr<Poppler::Document> document = Poppler::Document::load(TESTDATADIR "/unittestcases/form_set_icon.pdf");
191 QVERIFY(document);
192
193 std::unique_ptr<Poppler::Page> page = document->page(index: 0);
194 QVERIFY(page);
195
196 std::vector<std::unique_ptr<Poppler::FormField>> forms = page->formFields();
197
198 for (std::unique_ptr<Poppler::FormField> &field : forms) {
199 field->setPrintable(true);
200 QCOMPARE(field->isPrintable(), true);
201
202 field->setPrintable(false);
203 QCOMPARE(field->isPrintable(), false);
204 }
205}
206
207void TestForms::testSetAppearanceText()
208{
209 std::unique_ptr<Poppler::Document> document = Poppler::Document::load(TESTDATADIR "/unittestcases/checkbox_issue_159.pdf");
210 QVERIFY(document);
211
212 std::unique_ptr<Poppler::Page> page = document->page(index: 0);
213 QVERIFY(page);
214
215 std::vector<std::unique_ptr<Poppler::FormField>> forms = page->formFields();
216
217 int nTextForms = 0;
218
219 for (std::unique_ptr<Poppler::FormField> &field : forms) {
220
221 if (field->type() != Poppler::FormField::FormText) {
222 continue;
223 }
224
225 nTextForms++;
226
227 Poppler::FormFieldText *fft = static_cast<Poppler::FormFieldText *>(field.get());
228
229 const QString textToSet = "HOLA" + fft->name();
230 fft->setAppearanceText(textToSet);
231
232 Dict *dict = Poppler::FormFieldData::getFormWidget(f: fft)->getObj()->getDict();
233 Object strObject = dict->lookup(key: "AP").dictLookup(key: "N");
234
235 QVERIFY(strObject.isStream());
236
237 GooString s;
238 strObject.getStream()->fillGooString(s: &s);
239
240 const QString textToFind = QStringLiteral("\n(%1) Tj\n").arg(a: textToSet);
241 QVERIFY(s.toStr().find(textToFind.toStdString()) != std::string::npos);
242 }
243
244 QCOMPARE(nTextForms, 5);
245}
246
247void TestForms::testUnicodeFieldAttributes()
248{
249 std::unique_ptr<Poppler::Document> document = Poppler::Document::load(TESTDATADIR "/unittestcases/fieldWithUtf16Names.pdf");
250 QVERIFY(document);
251
252 std::unique_ptr<Poppler::Page> page = document->page(index: 0);
253 QVERIFY(page);
254
255 std::vector<std::unique_ptr<Poppler::FormField>> forms = page->formFields();
256
257 Poppler::FormField *field = forms.front().get();
258
259 QCOMPARE(field->name(), QStringLiteral("Tex"));
260 QCOMPARE(field->uiName(), QStringLiteral("Texto de ayuda"));
261}
262
263QTEST_GUILESS_MAIN(TestForms)
264#include "check_forms.moc"
265

source code of poppler/qt6/tests/check_forms.cpp