File size: 5,527 Bytes
df51fac
 
 
03b3d27
cbd62a3
d1ccc47
 
 
cbd62a3
 
 
df51fac
d1ccc47
 
df51fac
 
 
 
d1ccc47
9ca8ee5
cbd62a3
df51fac
 
03b3d27
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
df51fac
 
 
cbd62a3
d1ccc47
df51fac
 
d1ccc47
df51fac
 
 
d1ccc47
df51fac
cbd62a3
df51fac
 
 
d1ccc47
9ca8ee5
cbd62a3
03b3d27
 
 
 
 
 
 
 
 
 
d1ccc47
03b3d27
 
 
 
d1ccc47
03b3d27
9ca8ee5
cbd62a3
03b3d27
 
 
d1ccc47
03b3d27
 
 
d1ccc47
03b3d27
cbd62a3
03b3d27
d1ccc47
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
9ca8ee5
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
cbd62a3
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
from unittest.mock import MagicMock
from sync.anthology_source import iter_papers


def _make_fake_paper(full_id, title, abstract, authors, venue, year, url, bibtex="", pdf_url=""):
    parent = MagicMock()
    parent.venue_acronym = venue

    pdf = MagicMock()
    pdf.url = pdf_url

    paper = MagicMock()
    paper.full_id = full_id
    paper.parent = parent
    paper.title = title
    paper.abstract = abstract
    paper.authors = authors
    paper.year = year
    paper.web_url = url
    paper.to_bibtex.return_value = bibtex
    paper.pdf = pdf
    return paper


class FakeMarkupText:
    """Stand-in for acl_anthology.text.MarkupText, which exposes .as_text()."""

    def __init__(self, text):
        self._text = text

    def as_text(self):
        return self._text


class FakeName:
    """Stand-in for acl_anthology.people.Name, exposing .as_first_last()."""

    def __init__(self, first, last):
        self.first = first
        self.last = last

    def as_first_last(self):
        if not self.first:
            return self.last
        return f"{self.first} {self.last}"


class FakeNameSpecification:
    """Stand-in for acl_anthology.people.NameSpecification, exposing .name."""

    def __init__(self, name):
        self.name = name


def test_iter_papers_maps_fields(monkeypatch):
    fake_anthology = MagicMock()
    fake_anthology.papers.return_value = [
        _make_fake_paper("2023.acl-long.1", "Title One", "Abstract one", ["Alice", "Bob"], "ACL", "2023", "http://x/p1", "@inproceedings{one,\n  title = \"Title One\"}", "http://x/p1.pdf"),
        _make_fake_paper("2022.emnlp-main.2", "Title Two", None, [], "EMNLP", "2022", "http://x/p2"),
    ]

    monkeypatch.setattr("sync.anthology_source.Anthology", lambda datadir: fake_anthology)

    results = list(iter_papers("/fake/repo"))
    assert results[0] == {
        "id": "2023.acl-long.1", "title": "Title One", "abstract": "Abstract one",
        "authors": "Alice, Bob", "venue": "ACL", "year": 2023, "url": "http://x/p1",
        "bibtex": "@inproceedings{one,\n  title = \"Title One\"}", "pdf_url": "http://x/p1.pdf",
    }
    assert results[1]["abstract"] == ""
    assert results[1]["authors"] == ""
    assert results[1]["year"] == 2022
    assert results[1]["bibtex"] == ""
    assert results[1]["pdf_url"] == ""


def test_iter_papers_handles_real_markup_text_and_name_objects(monkeypatch):
    """The real acl_anthology package (verified against installed 1.2.0) has
    Paper.title/abstract as MarkupText objects (.as_text()) and Paper.authors
    as a tuple of NameSpecification objects exposing `.name.as_first_last()`.
    """
    fake_anthology = MagicMock()
    fake_anthology.papers.return_value = [
        _make_fake_paper(
            "2024.naacl-long.3",
            FakeMarkupText("Real Title"),
            FakeMarkupText("Real abstract text"),
            [FakeNameSpecification(FakeName("Alice", "Smith")), FakeNameSpecification(FakeName(None, "Cher"))],
            "NAACL",
            "2024",
            "http://x/p3",
            "@inproceedings{smith-2024-real}",
            "http://x/p3.pdf",
        ),
    ]

    monkeypatch.setattr("sync.anthology_source.Anthology", lambda datadir: fake_anthology)

    results = list(iter_papers("/fake/repo"))
    assert results[0] == {
        "id": "2024.naacl-long.3", "title": "Real Title", "abstract": "Real abstract text",
        "authors": "Alice Smith, Cher", "venue": "NAACL", "year": 2024, "url": "http://x/p3",
        "bibtex": "@inproceedings{smith-2024-real}", "pdf_url": "http://x/p3.pdf",
    }


def test_iter_papers_uses_datadir_subdirectory_of_local_checkout(monkeypatch):
    """anthology_path is the root of a git clone; the library expects the
    nested data/ directory, not the checkout root itself, and must not
    treat anthology_path as a repo URL to re-clone."""
    captured = {}

    def fake_anthology_ctor(datadir):
        captured["datadir"] = datadir
        anthology = MagicMock()
        anthology.papers.return_value = []
        return anthology

    monkeypatch.setattr("sync.anthology_source.Anthology", fake_anthology_ctor)

    list(iter_papers("/fake/checkout"))
    assert captured["datadir"] == "/fake/checkout/data"


def test_iter_papers_bibtex_falls_back_on_error(monkeypatch):
    """Papers whose bibkey is NO_BIBKEY (e.g. some frontmatter) raise
    ValueError from to_bibtex(); the sync must yield bibtex="" for those
    rather than crash."""
    fake_anthology = MagicMock()

    paper = _make_fake_paper("2023.acl-frontmatter.1", "Preface", "", [], "ACL", "2023", "http://x/pf")
    paper.to_bibtex.side_effect = ValueError("Cannot generate BibTeX entry without bibkey")
    fake_anthology.papers.return_value = [paper]

    monkeypatch.setattr("sync.anthology_source.Anthology", lambda datadir: fake_anthology)

    results = list(iter_papers("/fake/repo"))
    assert results[0]["bibtex"] == ""


def test_iter_papers_pdf_url_falls_back_when_no_pdf(monkeypatch):
    """Frontmatter and some older papers have no PDF reference (Paper.pdf is
    None); the sync must yield pdf_url="" for those rather than crash."""
    fake_anthology = MagicMock()

    paper = _make_fake_paper("2023.acl-frontmatter.1", "Preface", "", [], "ACL", "2023", "http://x/pf")
    paper.pdf = None
    fake_anthology.papers.return_value = [paper]

    monkeypatch.setattr("sync.anthology_source.Anthology", lambda datadir: fake_anthology)

    results = list(iter_papers("/fake/repo"))
    assert results[0]["pdf_url"] == ""