Files
FabledCurator/tests/test_page_number_parser.py
T
bvandeusen db490e92df
CI / lint (push) Successful in 3s
CI / frontend-build (push) Successful in 20s
CI / backend-lint-and-test (push) Successful in 26s
CI / integration (push) Successful in 3m4s
feat(series): post→series flows + browse list — backend (FC-6.2)
The post-aware on-ramp + the data behind the missing Series browse view.

- page_number_parser: conservative stated-page parser (pages 9-12 / page 5 /
  [3/8] / 3 of 8), keyword-gated to avoid false positives. Pure + unit-tested.
- SeriesService.promote_post_to_series: a self-contained post becomes its own
  series — series tag named after the post, one chapter, the post's images as
  pages (ordered by capture order; stated pages parsed from title/description).
- SeriesService.add_post_as_chapter: append a post as the next chapter of an
  existing series, titled after the post and slotted by parsed page number
  (a "pages 1-4" post lands ahead of the "pages 9-12" chapter).
- SeriesService.list_series: browse cards — cover thumb, artist, chapter/page
  counts, gap flag, last-updated; sort recent|name|size + filter by artist.
- API: GET /api/series, POST /api/series/from-post, POST /api/series/<id>/add-post.
- Resolver uses ImageRecord.primary_post_id (same linkage the posts feed renders).

Frontend (Add-to-series control + Series view + nav) lands next.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-07 18:34:11 -04:00

40 lines
1.3 KiB
Python
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
"""Pure unit tests for the stated-page parser (FC-6.2)."""
from backend.app.services.page_number_parser import parse_page_range
def test_explicit_ranges():
assert parse_page_range("pages 9-12") == (9, 12)
assert parse_page_range("pg 912") == (9, 12) # en-dash
assert parse_page_range("pp. 9 - 12") == (9, 12)
assert parse_page_range("Chapter 2 (pages 1-4)") == (1, 4)
def test_reversed_range_is_normalized():
assert parse_page_range("pages 12-9") == (9, 12)
def test_single_page():
assert parse_page_range("Page 5") == (5, 5)
assert parse_page_range("pg 5") == (5, 5)
def test_fraction_forms_take_the_numerator():
assert parse_page_range("[3/8]") == (3, 3)
assert parse_page_range("(3/8)") == (3, 3)
assert parse_page_range("page 3 of 8") == (3, 3)
assert parse_page_range("pg 3/8") == (3, 3)
def test_no_page_keyword_is_none():
# Bare numbers / non-page words must not match (false positives are worse).
assert parse_page_range("My Comic Part Three") is None
assert parse_page_range("Episode 5") is None
assert parse_page_range("Released 2024") is None
assert parse_page_range("Part 3") is None
def test_empty_and_none():
assert parse_page_range("") is None
assert parse_page_range(None) is None