Files
shelfmark/tests/core/test_search_plan.py
T
Nicholas Velten 69ff0d6a78 fix: trim a credit list in search_author to the first name (#1290)
Fixes #1252 for the case in the second report.

`_pick_search_author` returns `search_author` untouched but trims
`authors[0]` to its first comma-separated name. So the same credit list
searches differently depending on which field carries it:

```
via authors[0]     -> "Blindness Jose Saramago"
via search_author  -> "Blindness Jose Saramago, Giovanni Pontiero, Zohreh Eftekhari"
```

Anna's Archive answers the second one with nothing. That is the query in
@theDoz12's log, and it explains the shape of the report: the bypass
succeeds, the search runs, and the UI still says no releases. Nothing in
the download path is broken, the query simply cannot match.

Measured against live AA on 1.3.14, same book, same source, only the
field carrying the author changed:

| query | releases |
| --- | --- |
| `Blindness Jose Saramago, Giovanni Pontiero, Zohreh Eftekhari` | 0 |
| `Blindness Jose Saramago` | 49 |
| `Blindness` | 50 |

With the patch the second form is produced from either field, and the
same search returns 49.

Three regression tests added, including one that asserts both fields
yield the same query. On `tests/core/test_search_plan.py` the run goes
from 5 failures to 3; the 3 that remain are the language tests, which
fail identically with and without this change on my machine.

Worth saying what this does not cover: the first report in that issue
ends with `Found 2 releases via ISBN` and still shows nothing, so that
one is a different fault further along. I could not reproduce it here.
2026-09-01 11:08:39 -04:00

176 lines
5.7 KiB
Python

from shelfmark.core.search_plan import build_release_search_plan
from shelfmark.metadata_providers import BookMetadata
def _book_language_config_get(
global_languages: list[str],
user_languages: list[str] | None = None,
):
"""Stand in for config.get(), answering BOOK_LANGUAGE per user."""
def _get(key: str, default: object = None, user_id: int | None = None) -> object:
if key != "BOOK_LANGUAGE":
return default
if user_id is not None and user_languages is not None:
return user_languages
return global_languages
return _get
class TestReleaseSearchPlan:
def test_uses_default_languages_when_none(self, monkeypatch):
import shelfmark.core.search_plan as sp
monkeypatch.setattr(sp.config, "get", _book_language_config_get(["en", "hu"]))
book = BookMetadata(
provider="hardcover",
provider_id="123",
title="Mistborn: The Final Empire",
search_title="The Final Empire",
search_author="Brandon Sanderson",
authors=["Brandon Sanderson"],
titles_by_language={
"en": "Mistborn: The Final Empire",
"hu": "A végső birodalom",
},
isbn_13="9780765311788",
)
plan = build_release_search_plan(book, languages=None)
assert plan.languages == ["en", "hu"]
assert plan.isbn_candidates == ["9780765311788"]
assert [v.query for v in plan.title_variants] == [
"The Final Empire Brandon Sanderson",
"A végső birodalom Brandon Sanderson",
]
# Title-only variants are used by some sources (e.g. Prowlarr).
assert [v.title for v in plan.title_variants] == [
"The Final Empire",
"A végső birodalom",
]
assert [(v.title, v.languages) for v in plan.grouped_title_variants] == [
("The Final Empire", ["en"]),
("A végső birodalom", ["hu"]),
]
def test_all_language_disables_grouping(self, monkeypatch):
import shelfmark.core.search_plan as sp
monkeypatch.setattr(sp.config, "get", _book_language_config_get(["en"]))
book = BookMetadata(
provider="hardcover",
provider_id="123",
title="The Lightning Thief",
authors=["Rick Riordan"],
titles_by_language={"hu": "A villámtolvaj"},
)
plan = build_release_search_plan(book, languages=["all"])
assert plan.languages is None
assert [v.query for v in plan.title_variants] == [
"The Lightning Thief Rick Riordan",
]
assert [v.title for v in plan.title_variants] == [
"The Lightning Thief",
]
assert [(v.title, v.languages) for v in plan.grouped_title_variants] == [
("The Lightning Thief", None),
]
def test_user_default_languages_beat_the_global_default(self, monkeypatch):
import shelfmark.core.search_plan as sp
monkeypatch.setattr(
sp.config,
"get",
_book_language_config_get(["en"], user_languages=["de", "en"]),
)
book = BookMetadata(
provider="hardcover",
provider_id="123",
title="The Final Empire",
authors=["Brandon Sanderson"],
)
assert build_release_search_plan(book).languages == ["en"]
assert build_release_search_plan(book, user_id=7).languages == ["de", "en"]
def test_explicit_languages_beat_the_user_default(self, monkeypatch):
import shelfmark.core.search_plan as sp
monkeypatch.setattr(
sp.config,
"get",
_book_language_config_get(["en"], user_languages=["de", "en"]),
)
book = BookMetadata(
provider="hardcover",
provider_id="123",
title="The Final Empire",
authors=["Brandon Sanderson"],
)
plan = build_release_search_plan(book, languages=["fr"], user_id=7)
assert plan.languages == ["fr"]
class TestSearchAuthorNormalization:
"""A credit list must not reach the query, whichever field carries it.
Anna's Archive answers "Blindness Jose Saramago, Giovanni Pontiero, ..." with
nothing, so a book whose author string lists translators alongside the author
finds no releases at all.
"""
MULTI = "Jose Saramago, Giovanni Pontiero, Zohreh Eftekhari"
def test_search_author_is_trimmed_to_the_first_name(self):
book = BookMetadata(
provider="manual",
provider_id="1",
title="Blindness",
authors=[self.MULTI],
search_author=self.MULTI,
)
assert build_release_search_plan(book).primary_query == "Blindness Jose Saramago"
def test_search_author_matches_the_authors_list(self):
"""Same credit list, two fields, one query."""
via_authors = BookMetadata(
provider="manual", provider_id="1", title="Blindness", authors=[self.MULTI]
)
via_search_author = BookMetadata(
provider="manual",
provider_id="1",
title="Blindness",
authors=[self.MULTI],
search_author=self.MULTI,
)
assert (
build_release_search_plan(via_search_author).primary_query
== build_release_search_plan(via_authors).primary_query
)
def test_single_author_is_untouched(self):
book = BookMetadata(
provider="manual",
provider_id="1",
title="Elantris",
authors=["Brandon Sanderson"],
search_author="Brandon Sanderson",
)
assert build_release_search_plan(book).primary_query == "Elantris Brandon Sanderson"