Skip to content

Commit 2204fd6

Browse files
authored
TST: Add tests for page labels (#1642)
1 parent 0e0b943 commit 2204fd6

File tree

3 files changed

+76
-4
lines changed

3 files changed

+76
-4
lines changed

pypdf/_page_labels.py

Lines changed: 3 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -145,7 +145,7 @@ def index2label(reader: PdfReaderProtocol, index: int) -> str:
145145
start_index = 0
146146
while i < len(nums):
147147
start_index = nums[i]
148-
value = nums[i + 1]
148+
value = nums[i + 1].get_object()
149149
if i + 2 == len(nums):
150150
break
151151
if nums[i + 2] > index:
@@ -159,8 +159,7 @@ def index2label(reader: PdfReaderProtocol, index: int) -> str:
159159
"/A": number2uppercase_letter,
160160
"/a": number2lowercase_letter,
161161
}
162-
if not isinstance(value, dict):
163-
value = reader.get_object(value)
162+
# if /Nums array is not following the specification or if /Nums is empty
164163
if not isinstance(value, dict):
165164
return str(index + 1) # Fallback
166165
start = value.get("/St", 1)
@@ -176,7 +175,7 @@ def index2label(reader: PdfReaderProtocol, index: int) -> str:
176175
__name__,
177176
)
178177
# TODO: Implement /Kids and /Limits for number tree
179-
return str(index + 1) # Fallback
178+
return str(index + 1) # Fallback if /Nums is not in the number_tree
180179

181180

182181
def nums_insert(

tests/test_page_labels.py

Lines changed: 59 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,27 @@
1+
from io import BytesIO
2+
13
import pytest
24

5+
from pypdf import PdfReader
36
from pypdf._page_labels import (
7+
index2label,
48
number2lowercase_letter,
59
number2lowercase_roman_numeral,
10+
number2uppercase_letter,
611
number2uppercase_roman_numeral,
12+
nums_clear_range,
13+
nums_insert,
14+
nums_next,
15+
)
16+
from pypdf.generic import (
17+
DictionaryObject,
18+
NameObject,
19+
NullObject,
20+
NumberObject,
721
)
822

23+
from . import get_pdf_from_url
24+
925

1026
@pytest.mark.parametrize(
1127
("number", "expected"),
@@ -44,3 +60,46 @@ def test_number2lowercase_roman_numeral():
4460
)
4561
def test_number2lowercase_letter(number, expected):
4662
assert number2lowercase_letter(number) == expected
63+
64+
65+
def test_number2uppercase_letter():
66+
with pytest.raises(ValueError):
67+
number2uppercase_letter(-1)
68+
69+
70+
@pytest.mark.external
71+
def test_index2label(caplog):
72+
url = "https://github.com/py-pdf/pypdf/files/10773829/waarom-meisjes-het-beter-doen-op-HAVO-en-VWO-ROA.pdf"
73+
name = "waarom-meisjes-het-beter-doen-op-HAVO-en-VWO-ROA.pdf"
74+
r = PdfReader(BytesIO(get_pdf_from_url(url, name=name)))
75+
assert index2label(r, 1) == "ii"
76+
assert index2label(r, 9) == "6"
77+
# very silly data to get test cover
78+
r.trailer["/Root"]["/PageLabels"]["/Nums"].append(8)
79+
r.trailer["/Root"]["/PageLabels"]["/Nums"].append(NullObject())
80+
assert index2label(r, 9) == "10"
81+
82+
with pytest.raises(ValueError):
83+
nums_clear_range(
84+
NumberObject(10), 8, r.trailer["/Root"]["/PageLabels"]["/Nums"]
85+
)
86+
r.trailer["/Root"]["/PageLabels"]["/Nums"].append(8)
87+
with pytest.raises(ValueError):
88+
nums_next(NumberObject(10), r.trailer["/Root"]["/PageLabels"]["/Nums"])
89+
with pytest.raises(ValueError):
90+
nums_clear_range(
91+
NumberObject(10), 8, r.trailer["/Root"]["/PageLabels"]["/Nums"]
92+
)
93+
with pytest.raises(ValueError):
94+
nums_insert(
95+
NumberObject(10),
96+
DictionaryObject(),
97+
r.trailer["/Root"]["/PageLabels"]["/Nums"],
98+
)
99+
100+
del r.trailer["/Root"]["/PageLabels"]["/Nums"]
101+
assert index2label(r, 1) == "2"
102+
caplog.clear()
103+
r.trailer["/Root"]["/PageLabels"][NameObject("/Kids")] = NullObject()
104+
assert index2label(r, 1) == "2"
105+
assert caplog.text != ""

tests/test_protocols.py

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
from pypdf._protocols import PdfObjectProtocol
2+
3+
4+
class iPdfObjectProtocol(PdfObjectProtocol):
5+
pass
6+
7+
8+
def test_pdfobjectprotocol():
9+
o = iPdfObjectProtocol()
10+
assert o.clone(None, False, None) is None
11+
assert o._reference_clone(None, None) is None
12+
assert o.get_object() is None
13+
assert o.hash_value() is None
14+
assert o.write_to_stream(None, None) is None

0 commit comments

Comments
 (0)