Skip to content

Commit 4d852f9

Browse files
committed
Strengthen field sorting tests
* Isolate in-place cases with fresh entry fixtures. * Verify stable ordering for unspecified fields and public writer integration. * Reject ambiguous custom orders, including case-only duplicates.
1 parent 08e370a commit 4d852f9

1 file changed

Lines changed: 63 additions & 25 deletions

File tree

Lines changed: 63 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -1,27 +1,32 @@
11
import pytest
22

33
from bibtexparser import Library
4+
from bibtexparser import write_string
45
from bibtexparser.middlewares.sorting_entry_fields import SortFieldsAlphabeticallyMiddleware
56
from bibtexparser.middlewares.sorting_entry_fields import SortFieldsCustomMiddleware
67
from bibtexparser.model import Entry
78
from bibtexparser.model import Field
89

9-
TEST_ENTRY = Entry(
10-
"article",
11-
"Cesar2013",
12-
[
13-
Field("author", "Cesar, J.", 1),
14-
Field("title", "A title", 2),
15-
Field("note", "A note", 3),
16-
Field("journal", "A journal", 3),
17-
Field("year", "2013", 4),
18-
],
19-
)
10+
11+
def _test_entry():
12+
"""Return a fresh entry so in-place middleware tests cannot affect each other."""
13+
return Entry(
14+
"article",
15+
"Cesar2013",
16+
[
17+
Field("author", "Cesar, J.", 1),
18+
Field("title", "A title", 2),
19+
Field("note", "A note", 3),
20+
Field("journal", "A journal", 3),
21+
Field("year", "2013", 4),
22+
],
23+
)
2024

2125

2226
@pytest.mark.parametrize("inplace", [True, False])
2327
def test_sort_alphabetically(inplace: bool):
24-
library = Library(blocks=[TEST_ENTRY])
28+
original_entry = _test_entry()
29+
library = Library(blocks=[original_entry])
2530
m = SortFieldsAlphabeticallyMiddleware(allow_inplace_modification=inplace)
2631
transformed = m.transform(library)
2732
entry = transformed.entries[0]
@@ -34,16 +39,17 @@ def test_sort_alphabetically(inplace: bool):
3439
# Sanity Checks against unintended external effects
3540
assert len(transformed.blocks) == 1
3641
if inplace:
37-
assert entry is TEST_ENTRY
42+
assert entry is original_entry
3843
else:
39-
assert entry is not TEST_ENTRY
44+
assert entry is not original_entry
4045

4146

4247
@pytest.mark.parametrize("inplace", [True, False])
4348
def test_sort_custom_order_case_insensitive(inplace: bool):
4449
custom_order = ("author", "yEar", "title", "Journal") # assess case insensitive
4550

46-
library = Library(blocks=[TEST_ENTRY])
51+
original_entry = _test_entry()
52+
library = Library(blocks=[original_entry])
4753
# case insensitivity is default
4854
m = SortFieldsCustomMiddleware(order=custom_order, allow_inplace_modification=inplace)
4955
transformed = m.transform(library)
@@ -57,28 +63,60 @@ def test_sort_custom_order_case_insensitive(inplace: bool):
5763
# Sanity Checks against unintended external effects
5864
assert len(transformed.blocks) == 1
5965
if inplace:
60-
assert entry is TEST_ENTRY
66+
assert entry is original_entry
6167
else:
62-
assert entry is not TEST_ENTRY
68+
assert entry is not original_entry
6369

6470

6571
def test_sort_order_custom_case_sensitive():
6672
custom_order = ("author", "yEar", "title", "Journal") # assess case sensitive
6773

68-
library = Library(blocks=[TEST_ENTRY])
74+
library = Library(blocks=[_test_entry()])
6975
m = SortFieldsCustomMiddleware(order=custom_order, case_sensitive=True)
7076
transformed = m.transform(library)
7177
entry = transformed.entries[0]
7278
assert entry.fields[0].key == "author"
7379
assert entry.fields[1].key == "title"
7480

75-
# Unspecified fields (due to case sensitivity) are appended
76-
assert entry.fields[2].key == "year"
77-
78-
# Unspecified fields (due to case sensitivity) are appended
81+
# Unspecified fields are appended in their original relative order.
82+
assert entry.fields[2].key == "note"
7983
assert entry.fields[3].key == "journal"
80-
81-
# Unspecified fields are appended
82-
assert entry.fields[4].key == "note"
84+
assert entry.fields[4].key == "year"
8385

8486
assert len(transformed.blocks) == 1
87+
88+
89+
def test_custom_order_applies_during_public_write():
90+
"""The public writer applies custom ordering without mutating the source library."""
91+
original_entry = _test_entry()
92+
library = Library(blocks=[original_entry])
93+
middleware = SortFieldsCustomMiddleware(
94+
order=("year", "author"), allow_inplace_modification=False
95+
)
96+
97+
written = write_string(library, prepend_middleware=[middleware])
98+
written_field_keys = [
99+
line.split("=", maxsplit=1)[0].strip() for line in written.splitlines() if "=" in line
100+
]
101+
102+
assert written_field_keys == ["year", "author", "title", "note", "journal"]
103+
assert [field.key for field in original_entry.fields] == [
104+
"author",
105+
"title",
106+
"note",
107+
"journal",
108+
"year",
109+
]
110+
111+
112+
@pytest.mark.parametrize(
113+
"order",
114+
[
115+
pytest.param(("title", "title"), id="identical"),
116+
pytest.param(("title", "TITLE"), id="case-insensitive"),
117+
],
118+
)
119+
def test_custom_order_rejects_duplicate_keys(order):
120+
"""Ambiguous custom orders fail early, including case-only duplicates by default."""
121+
with pytest.raises(ValueError, match="title"):
122+
SortFieldsCustomMiddleware(order=order)

0 commit comments

Comments
 (0)