Skip to content

Feat/card synopsis - #19

Merged
FFFold merged 4 commits into
mainfrom
feat/card-synopsis
Aug 19, 2026
Merged

Feat/card synopsis#19
FFFold merged 4 commits into
mainfrom
feat/card-synopsis

Conversation

@FFFold

@FFFold FFFold commented Aug 19, 2026

Copy link
Copy Markdown
Owner

Summary by Sourcery

在已支持的渲染结果卡片中,安全地添加规范化的漫画简介。

新功能:

  • 在订阅确认、章节列表和更新通知卡片上显示漫画简介。

错误修复:

  • 在渲染前清理漫画描述,防止原始 HTML、脚本和样式内容出现在卡片中。

改进:

  • 规范简介文本,并用可选的、截断后的简介内容替换旧版卡片提示和阅读引导。

文档:

  • 记录渲染卡片对简介的支持以及清理行为。

测试:

  • 为简介的渲染、清理、转义、截断、空描述,以及命令/更新集成添加测试覆盖。

杂项:

  • 在未发布的变更日志中记录对简介的支持。
Original summary in English

Summary by Sourcery

Add safely normalized manga synopses to supported rendered result cards.

New Features:

  • Display manga synopses on subscription confirmation, chapter-list, and update-notification cards.

Bug Fixes:

  • Sanitize manga descriptions before rendering to prevent raw HTML, script, and style content from appearing in cards.

Enhancements:

  • Normalize synopsis text and replace legacy card hints and reading prompts with optional, truncated synopsis content.

Documentation:

  • Document synopsis support and sanitization behavior for rendered cards.

Tests:

  • Add coverage for synopsis rendering, sanitization, escaping, truncation, empty descriptions, and command/update integration.

Chores:

  • Record synopsis support in the unreleased changelog.

新功能:

  • 在订阅确认、更新通知和章节列表卡片上显示漫画简介。

错误修复:

  • 在渲染前通过移除不安全的 HTML 和 script/style 内容来清理简介内容。

改进:

  • 通过解码实体、折叠空白字符以及为卡片布局截断过长描述来规范简介文本。
  • 使用可选的简介内容替换旧版卡片页脚及阅读/刷新提示。

文档:

  • 为渲染卡片记录简介展示和清理行为。

测试:

  • 增加对简介渲染、清理、截断、空描述以及命令集成的测试覆盖。
Original summary in English

Summary by Sourcery

在已支持的渲染结果卡片中,安全地添加规范化的漫画简介。

新功能:

  • 在订阅确认、章节列表和更新通知卡片上显示漫画简介。

错误修复:

  • 在渲染前清理漫画描述,防止原始 HTML、脚本和样式内容出现在卡片中。

改进:

  • 规范简介文本,并用可选的、截断后的简介内容替换旧版卡片提示和阅读引导。

文档:

  • 记录渲染卡片对简介的支持以及清理行为。

测试:

  • 为简介的渲染、清理、转义、截断、空描述,以及命令/更新集成添加测试覆盖。

杂项:

  • 在未发布的变更日志中记录对简介的支持。
Original summary in English

Summary by Sourcery

Add safely normalized manga synopses to supported rendered result cards.

New Features:

  • Display manga synopses on subscription confirmation, chapter-list, and update-notification cards.

Bug Fixes:

  • Sanitize manga descriptions before rendering to prevent raw HTML, script, and style content from appearing in cards.

Enhancements:

  • Normalize synopsis text and replace legacy card hints and reading prompts with optional, truncated synopsis content.

Documentation:

  • Document synopsis support and sanitization behavior for rendered cards.

Tests:

  • Add coverage for synopsis rendering, sanitization, escaping, truncation, empty descriptions, and command/update integration.

Chores:

  • Record synopsis support in the unreleased changelog.

新功能:

  • 在订阅确认、章节列表和更新通知卡片上显示漫画简介。

缺陷修复:

  • 在渲染前清洗漫画描述,防止原始 HTML 和脚本/样式内容出现在卡片中。

改进优化:

  • 使用简洁、截断的简介文本和响应式行数限制,替换卡片特定的操作与阅读提示。

文档:

  • 更新用户和开发者文档,说明卡片渲染中对简介的支持情况。

测试:

  • 增加对描述清洗、截断、转义、空描述以及简介在卡片与指令流程中传播的测试覆盖。

杂项维护:

  • 在未发布的更新日志中记录对简介功能的支持。
Original summary in English

Summary by Sourcery

在已支持的渲染结果卡片中,安全地添加规范化的漫画简介。

新功能:

  • 在订阅确认、章节列表和更新通知卡片上显示漫画简介。

错误修复:

  • 在渲染前清理漫画描述,防止原始 HTML、脚本和样式内容出现在卡片中。

改进:

  • 规范简介文本,并用可选的、截断后的简介内容替换旧版卡片提示和阅读引导。

文档:

  • 记录渲染卡片对简介的支持以及清理行为。

测试:

  • 为简介的渲染、清理、转义、截断、空描述,以及命令/更新集成添加测试覆盖。

杂项:

  • 在未发布的变更日志中记录对简介的支持。
Original summary in English

Summary by Sourcery

Add safely normalized manga synopses to supported rendered result cards.

New Features:

  • Display manga synopses on subscription confirmation, chapter-list, and update-notification cards.

Bug Fixes:

  • Sanitize manga descriptions before rendering to prevent raw HTML, script, and style content from appearing in cards.

Enhancements:

  • Normalize synopsis text and replace legacy card hints and reading prompts with optional, truncated synopsis content.

Documentation:

  • Document synopsis support and sanitization behavior for rendered cards.

Tests:

  • Add coverage for synopsis rendering, sanitization, escaping, truncation, empty descriptions, and command/update integration.

Chores:

  • Record synopsis support in the unreleased changelog.

新功能:

  • 在订阅确认、更新通知和章节列表卡片上显示漫画简介。

错误修复:

  • 在渲染前通过移除不安全的 HTML 和 script/style 内容来清理简介内容。

改进:

  • 通过解码实体、折叠空白字符以及为卡片布局截断过长描述来规范简介文本。
  • 使用可选的简介内容替换旧版卡片页脚及阅读/刷新提示。

文档:

  • 为渲染卡片记录简介展示和清理行为。

测试:

  • 增加对简介渲染、清理、截断、空描述以及命令集成的测试覆盖。
Original summary in English

Summary by Sourcery

在已支持的渲染结果卡片中,安全地添加规范化的漫画简介。

新功能:

  • 在订阅确认、章节列表和更新通知卡片上显示漫画简介。

错误修复:

  • 在渲染前清理漫画描述,防止原始 HTML、脚本和样式内容出现在卡片中。

改进:

  • 规范简介文本,并用可选的、截断后的简介内容替换旧版卡片提示和阅读引导。

文档:

  • 记录渲染卡片对简介的支持以及清理行为。

测试:

  • 为简介的渲染、清理、转义、截断、空描述,以及命令/更新集成添加测试覆盖。

杂项:

  • 在未发布的变更日志中记录对简介的支持。
Original summary in English

Summary by Sourcery

Add safely normalized manga synopses to supported rendered result cards.

New Features:

  • Display manga synopses on subscription confirmation, chapter-list, and update-notification cards.

Bug Fixes:

  • Sanitize manga descriptions before rendering to prevent raw HTML, script, and style content from appearing in cards.

Enhancements:

  • Normalize synopsis text and replace legacy card hints and reading prompts with optional, truncated synopsis content.

Documentation:

  • Document synopsis support and sanitization behavior for rendered cards.

Tests:

  • Add coverage for synopsis rendering, sanitization, escaping, truncation, empty descriptions, and command/update integration.

Chores:

  • Record synopsis support in the unreleased changelog.

@FFFold
FFFold marked this pull request as ready for review August 19, 2026 00:38
@sourcery-ai

sourcery-ai Bot commented Aug 19, 2026

Copy link
Copy Markdown

审阅者指南

在 T2I 卡片中引入清洗后的漫画描述作为 synopsis 字段,通过订阅/更新/章节流程传递描述,并更新文档/测试以覆盖新行为和 HTML 清洗工具。

更新通知卡片 synopsis 线缆的序列图

sequenceDiagram
    participant Updater as SuwayomiUpdater
    participant Manga as MangaObject
    participant Cards as cards_py
    participant T2I as T2IRenderer

    Updater->>Manga: _check_one_manga
    Manga-->>Updater: manga_obj(description, thumbnail_url, status)
    Updater->>Updater: _run(build item dict with description)
    Updater->>Cards: build_update_card(items, heading)
    Cards->>Cards: clean_description(description)
    Cards-->>Updater: tmpldata(items with synopsis)
    Updater->>Cards: embed_covers(client, tmpldata_items)
    Cards-->>Updater: tmpldata_with_covers
    Updater->>T2I: render_card(html_render, tmpldata_with_covers, timeout)
    T2I-->>Updater: jpeg_image_with_synopsis
Loading

文件级变更

变更 详情 文件
添加 clean_description 工具,将 Suwayomi 漫画描述规整为用于卡片渲染的纯文本简介(synopsis)。
  • 定义 SYNOPSIS_MAX_CHARS 和正则辅助方法,从描述中剥离/规范化 HTML、块级标签以及 script/style 内容。
  • 实现 clean_description 以处理 None/空输入、HTML 实体反转义、空白折叠,以及带省略号的长度截断。
  • 从 cards 模块导出 clean_description,并通过单元测试覆盖 HTML 清洗、截断、空输入以及 script/style 移除等行为。
suwayomi/cards.py
tests/test_cards.py
在订阅确认、更新以及章节标题卡片上渲染基于描述的 synopsis,替代之前的提示/页脚文本。
  • 扩展卡片 Jinja 模板,增加 .synopsis 样式以及针对订阅确认、更新条目及章节标题卡片的条件 synopsis 区块,移除提示/页脚文本渲染。
  • 修改 build_subscribe_confirm_card 接受 manga.description,通过 clean_description 生成 synopsis,并停止使用 footer。
  • 修改 build_update_card,将清洗后的描述以 synopsis 传入而不是 read_hint,并更新 build_chapter_cards 只在标题卡片上从 manga.description 附加 synopsis。
  • 更新 main.py 和 updater.py 中的异步流程,将 description 填充进构建卡片的调用中,用 description 替换 read_hint/refresh hint,并从 Manga 对象中传递 description。
suwayomi/cards.py
main.py
suwayomi/updater.py
更新测试和辅助工厂,以断言渲染卡片中 synopsis 的存在,并确保 updater 传递描述。
  • 调整卡片相关测试,在 manga/item fixture 中包含 description,在订阅确认、更新和章节标题卡片上断言 synopsis 值,并在适用处验证紧凑 synopsis 行为。
  • 更新 updater 测试,以确认 description 被转发到 render_update_card_fn 的 items 中。
  • 扩展 list_chapters 测试,以确保首个章节卡片携带 synopsis,而延续卡片不携带。
tests/test_cards.py
tests/test_card_commands.py
tests/test_list_chapters.py
tests/test_updater.py
刷新 README 和开发者文档,以说明 T2I 卡片中的 synopsis 行为和描述清洗。
  • 说明结果卡片现在会在章节列表、订阅确认以及更新通知卡片上展示漫画 synopsis,并调整 result_cards_enabled 的配置说明。
  • 在开发和贡献文档中澄清,cards.py 除了处理 T2I 模板、数据准备、封面和缓存之外,还负责描述清洗。
  • 更新 AGENTS 概览,提及在构建卡片时使用 clean_description,以及 updater 会为更新卡片暴露 description。
  • 添加 CHANGELOG 条目,描述新的 synopsis 功能以及模板提示文本的移除。
README.md
docs/dev/development.md
CONTRIBUTING.md
AGENTS.md
CHANGELOG.md

提示与命令

与 Sourcery 交互

  • 触发新审阅: 在 Pull Request 上评论 @sourcery-ai review
  • 继续讨论: 直接回复 Sourcery 的审阅评论。
  • 从审阅评论生成 GitHub Issue: 通过回复审阅评论,请求 Sourcery 从该评论创建一个 Issue。你也可以在审阅评论中回复 @sourcery-ai issue 来从该评论创建 Issue。
  • 生成 Pull Request 标题: 在 Pull Request 标题任意位置写上 @sourcery-ai,即可随时生成标题。你也可以在 Pull Request 中评论 @sourcery-ai title 来(重新)生成标题。
  • 生成 Pull Request 摘要: 在 Pull Request 正文任意位置写上 @sourcery-ai summary,即可在你想要的位置生成 PR 摘要。你也可以在 Pull Request 中评论 @sourcery-ai summary 来(重新)生成摘要。
  • 生成审阅者指南: 在 Pull Request 中评论 @sourcery-ai guide,即可随时(重新)生成审阅者指南。
  • 解决所有 Sourcery 评论: 在 Pull Request 中评论 @sourcery-ai resolve,即可解决所有 Sourcery 评论。如果你已经处理完所有评论且不想再看到它们,这会很有用。
  • 撤销所有 Sourcery 审阅: 在 Pull Request 中评论 @sourcery-ai dismiss,即可撤销所有现有的 Sourcery 审阅。特别适用于你希望从一次新的审阅开始——别忘了评论 @sourcery-ai review 来触发新的审阅!

自定义你的体验

访问你的控制面板以:

  • 启用或禁用审阅特性,例如 Sourcery 生成的 Pull Request 摘要、审阅者指南等。
  • 更改审阅语言。
  • 添加、移除或编辑自定义审阅指令。
  • 调整其他审阅设置。

获取帮助

Original review guide in English

Reviewer's Guide

Introduce cleaned manga descriptions into T2I cards as a synopsis field, wire descriptions through subscribe/update/chapter flows, and update docs/tests to cover the new behavior and HTML-cleaning utility.

Sequence diagram for update notification card synopsis wiring

sequenceDiagram
    participant Updater as SuwayomiUpdater
    participant Manga as MangaObject
    participant Cards as cards_py
    participant T2I as T2IRenderer

    Updater->>Manga: _check_one_manga
    Manga-->>Updater: manga_obj(description, thumbnail_url, status)
    Updater->>Updater: _run(build item dict with description)
    Updater->>Cards: build_update_card(items, heading)
    Cards->>Cards: clean_description(description)
    Cards-->>Updater: tmpldata(items with synopsis)
    Updater->>Cards: embed_covers(client, tmpldata_items)
    Cards-->>Updater: tmpldata_with_covers
    Updater->>T2I: render_card(html_render, tmpldata_with_covers, timeout)
    T2I-->>Updater: jpeg_image_with_synopsis
Loading

File-Level Changes

Change Details Files
Add clean_description utility to normalize Suwayomi manga descriptions into plain-text synopses for card rendering.
  • Define SYNOPSIS_MAX_CHARS and regex helpers to strip/normalize HTML, block tags, and script/style content from descriptions.
  • Implement clean_description to handle None/empty input, HTML entity unescaping, whitespace folding, and length truncation with ellipsis.
  • Expose clean_description from cards module and cover behavior with unit tests for HTML stripping, truncation, empty input, and script/style removal.
suwayomi/cards.py
tests/test_cards.py
Render description-based synopsis on subscribe confirm, update, and chapter header cards instead of previous hint/footer text.
  • Extend card Jinja template with .synopsis styles and conditional synopsis blocks for subscribe confirm, update items, and chapter header cards, removing hint/footer text rendering.
  • Change build_subscribe_confirm_card to accept manga.description, generate synopsis via clean_description, and stop using footer.
  • Change build_update_card to pass cleaned description as synopsis instead of read_hint, and update build_chapter_cards to attach synopsis from manga.description on header cards only.
  • Update async flows in main.py and updater.py to populate description into card-building calls, replacing read_hint/refresh hint with description, and propagate description from Manga objects.
suwayomi/cards.py
main.py
suwayomi/updater.py
Update tests and helper factories to assert synopsis presence on rendered cards and ensure updater passes descriptions through.
  • Adjust card-related tests to include description in manga/item fixtures, assert synopsis values on subscribe confirm, update, and chapter header cards, and verify compact synopsis behavior where applicable.
  • Update updater tests to confirm that description is forwarded into render_update_card_fn items.
  • Extend list_chapters tests to ensure the first chapter card carries synopsis while continuation cards do not.
tests/test_cards.py
tests/test_card_commands.py
tests/test_list_chapters.py
tests/test_updater.py
Refresh README and developer docs to document synopsis behavior and description cleaning in T2I cards.
  • Document that result cards now show manga synopsis on chapter list, subscribe confirm, and update notification cards, and adjust configuration description for result_cards_enabled.
  • Clarify in development and contributing docs that cards.py handles description cleaning in addition to T2I template, data prep, covers, and caching.
  • Update AGENTS overview to mention clean_description usage in card-building and that updater exposes description for update cards.
  • Add CHANGELOG entry describing the new synopsis feature and removal of template hint text.
README.md
docs/dev/development.md
CONTRIBUTING.md
AGENTS.md
CHANGELOG.md

Tips and commands

Interacting with Sourcery

  • Trigger a new review: Comment @sourcery-ai review on the pull request.
  • Continue discussions: Reply directly to Sourcery's review comments.
  • Generate a GitHub issue from a review comment: Ask Sourcery to create an
    issue from a review comment by replying to it. You can also reply to a
    review comment with @sourcery-ai issue to create an issue from it.
  • Generate a pull request title: Write @sourcery-ai anywhere in the pull
    request title to generate a title at any time. You can also comment
    @sourcery-ai title on the pull request to (re-)generate the title at any time.
  • Generate a pull request summary: Write @sourcery-ai summary anywhere in
    the pull request body to generate a PR summary at any time exactly where you
    want it. You can also comment @sourcery-ai summary on the pull request to
    (re-)generate the summary at any time.
  • Generate reviewer's guide: Comment @sourcery-ai guide on the pull
    request to (re-)generate the reviewer's guide at any time.
  • Resolve all Sourcery comments: Comment @sourcery-ai resolve on the
    pull request to resolve all Sourcery comments. Useful if you've already
    addressed all the comments and don't want to see them anymore.
  • Dismiss all Sourcery reviews: Comment @sourcery-ai dismiss on the pull
    request to dismiss all existing Sourcery reviews. Especially useful if you
    want to start fresh with a new review - don't forget to comment
    @sourcery-ai review to trigger a new review!

Customizing Your Experience

Access your dashboard to:

  • Enable or disable review features such as the Sourcery-generated pull request
    summary, the reviewer's guide, and others.
  • Change the review language.
  • Add, remove or edit custom review instructions.
  • Adjust other review settings.

Getting Help

@sourcery-ai sourcery-ai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hey - 我发现了 1 个问题,并给出了一些总体反馈:

  • 新的 .synopsis CSS 类替代了 .hint,但部分卡片变体(例如搜索、批量订阅、订阅)仍然渲染带有 class="hint" 的元素;建议要么保留一组最小化的 .hint 样式,要么更新这些模板使用 .synopsis 或其他类,以避免出现意料之外的视觉回归。
  • _SCRIPT_STYLE_RE 在整个描述文本上使用了带 DOTALL 的贪婪 .*?;对于非常大的 HTML 内容,这可能相对开销较大,并有可能意外跨越格式不正确或嵌套的标签——建议收紧该正则(例如限制匹配长度,或者对这些块使用 HTML 解析器),以提升 clean_description 的健壮性。
供 AI Agents 使用的提示
Please address the comments from this code review:

## Overall Comments
- 新的 `.synopsis` CSS 类替代了 `.hint`,但部分卡片变体(例如搜索、批量订阅、订阅)仍然渲染带有 `class="hint"` 的元素;建议要么保留一组最小化的 `.hint` 样式,要么更新这些模板使用 `.synopsis` 或其他类,以避免出现意料之外的视觉回归。
- `_SCRIPT_STYLE_RE` 在整个描述文本上使用了带 DOTALL 的贪婪 `.*?`;对于非常大的 HTML 内容,这可能相对开销较大,并有可能意外跨越格式不正确或嵌套的标签——建议收紧该正则(例如限制匹配长度,或者对这些块使用 HTML 解析器),以提升 `clean_description` 的健壮性。

## Individual Comments

### Comment 1
<location path="tests/test_cards.py" line_range="67-70" />
<code_context>
+    assert clean_description(raw) == "少年吞下了诅咒的手指, 踏上讨伐&之路。"
+
+
+def test_clean_description_truncates_with_ellipsis():
+    text = "字" * 500
+    cleaned = clean_description(text, max_chars=100)
+    assert cleaned == "字" * 100 + "…"
+
+
</code_context>
<issue_to_address>
**suggestion (testing):** Add a test that exercises the default `SYNOPSIS_MAX_CHARS` truncation behavior

Currently truncation is only verified with an explicit `max_chars=100`. Please add a test that calls `clean_description` without `max_chars` so it uses the default `SYNOPSIS_MAX_CHARS`, and asserts the resulting length and ellipsis position. This helps catch regressions if `SYNOPSIS_MAX_CHARS` changes or if off‑by‑one errors are introduced in the truncation logic.

Suggested implementation:

```python
def test_clean_description_strips_html_and_whitespace():
    raw = "<p>  少年<b>吞下了</b>诅咒的手指,\n踏上讨伐&amp;之路。  </p>"
    assert clean_description(raw) == "少年吞下了诅咒的手指, 踏上讨伐&之路。"



def test_clean_description_truncates_with_ellipsis():
    text = "" * 500
    cleaned = clean_description(text, max_chars=100)
    assert cleaned == "" * 100 + ""


def test_clean_description_uses_default_max_chars_truncation():
    text = "" * (SYNOPSIS_MAX_CHARS + 50)
    cleaned = clean_description(text)
    # Truncation should use SYNOPSIS_MAX_CHARS characters and then append an ellipsis.
    assert len(cleaned) == SYNOPSIS_MAX_CHARS + 1
    assert cleaned.endswith("")
    assert cleaned[:-1] == "" * SYNOPSIS_MAX_CHARS


def test_build_subscribe_confirm_card():

```

To make this test pass, ensure `SYNOPSIS_MAX_CHARS` is imported into `tests/test_cards.py` from the module where it is defined, e.g.:

- At the top of `tests/test_cards.py`, add `from <module> import SYNOPSIS_MAX_CHARS` (adjust `<module>` to match your existing imports and where `clean_description` is defined).
</issue_to_address>

Sourcery 对开源项目免费——如果你觉得我们的评审有帮助,欢迎分享 ✨
帮我变得更有用!请在每条评论上点 👍 或 👎,我会根据这些反馈改进为你提供的评审质量。
Original comment in English

Hey - I've found 1 issue, and left some high level feedback:

  • The new .synopsis CSS class replaces .hint, but some card variants (e.g., search, batch subscription, subscriptions) still render elements with class="hint"; consider either retaining minimal .hint styles or updating those templates to use .synopsis/another class to avoid unexpected visual regressions.
  • _SCRIPT_STYLE_RE uses a greedy .*? with DOTALL over the whole description; for very large HTML blobs this could be relatively expensive and may accidentally span malformed or nested tags—consider constraining the pattern (e.g., limiting length, or using an HTML parser for those blocks) to make clean_description more robust.
Prompt for AI Agents
Please address the comments from this code review:

## Overall Comments
- The new `.synopsis` CSS class replaces `.hint`, but some card variants (e.g., search, batch subscription, subscriptions) still render elements with `class="hint"`; consider either retaining minimal `.hint` styles or updating those templates to use `.synopsis`/another class to avoid unexpected visual regressions.
- `_SCRIPT_STYLE_RE` uses a greedy `.*?` with DOTALL over the whole description; for very large HTML blobs this could be relatively expensive and may accidentally span malformed or nested tags—consider constraining the pattern (e.g., limiting length, or using an HTML parser for those blocks) to make `clean_description` more robust.

## Individual Comments

### Comment 1
<location path="tests/test_cards.py" line_range="67-70" />
<code_context>
+    assert clean_description(raw) == "少年吞下了诅咒的手指, 踏上讨伐&之路。"
+
+
+def test_clean_description_truncates_with_ellipsis():
+    text = "字" * 500
+    cleaned = clean_description(text, max_chars=100)
+    assert cleaned == "字" * 100 + "…"
+
+
</code_context>
<issue_to_address>
**suggestion (testing):** Add a test that exercises the default `SYNOPSIS_MAX_CHARS` truncation behavior

Currently truncation is only verified with an explicit `max_chars=100`. Please add a test that calls `clean_description` without `max_chars` so it uses the default `SYNOPSIS_MAX_CHARS`, and asserts the resulting length and ellipsis position. This helps catch regressions if `SYNOPSIS_MAX_CHARS` changes or if off‑by‑one errors are introduced in the truncation logic.

Suggested implementation:

```python
def test_clean_description_strips_html_and_whitespace():
    raw = "<p>  少年<b>吞下了</b>诅咒的手指,\n踏上讨伐&amp;之路。  </p>"
    assert clean_description(raw) == "少年吞下了诅咒的手指, 踏上讨伐&之路。"



def test_clean_description_truncates_with_ellipsis():
    text = "" * 500
    cleaned = clean_description(text, max_chars=100)
    assert cleaned == "" * 100 + ""


def test_clean_description_uses_default_max_chars_truncation():
    text = "" * (SYNOPSIS_MAX_CHARS + 50)
    cleaned = clean_description(text)
    # Truncation should use SYNOPSIS_MAX_CHARS characters and then append an ellipsis.
    assert len(cleaned) == SYNOPSIS_MAX_CHARS + 1
    assert cleaned.endswith("")
    assert cleaned[:-1] == "" * SYNOPSIS_MAX_CHARS


def test_build_subscribe_confirm_card():

```

To make this test pass, ensure `SYNOPSIS_MAX_CHARS` is imported into `tests/test_cards.py` from the module where it is defined, e.g.:

- At the top of `tests/test_cards.py`, add `from <module> import SYNOPSIS_MAX_CHARS` (adjust `<module>` to match your existing imports and where `clean_description` is defined).
</issue_to_address>

Sourcery is free for open source - if you like our reviews please consider sharing them ✨
Help me be more useful! Please click 👍 or 👎 on each comment and I'll use the feedback to improve your reviews.

Comment thread tests/test_cards.py
Comment on lines +67 to +70
def test_clean_description_truncates_with_ellipsis():
text = "字" * 500
cleaned = clean_description(text, max_chars=100)
assert cleaned == "字" * 100 + "…"

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

suggestion (testing): 添加一个测试,用于覆盖默认 SYNOPSIS_MAX_CHARS 的截断行为

目前截断逻辑只通过显式传入 max_chars=100 进行了验证。请添加一个调用 clean_description 且不传入 max_chars 的测试,使其使用默认的 SYNOPSIS_MAX_CHARS,并断言结果的长度和省略号的位置。这样可以在 SYNOPSIS_MAX_CHARS 修改或截断逻辑出现 off‑by‑one 错误时及时发现回归。

建议的实现:

def test_clean_description_strips_html_and_whitespace():
    raw = "<p>  少年<b>吞下了</b>诅咒的手指,\n踏上讨伐&amp;之路。  </p>"
    assert clean_description(raw) == "少年吞下了诅咒的手指, 踏上讨伐&之路。"



def test_clean_description_truncates_with_ellipsis():
    text = "字" * 500
    cleaned = clean_description(text, max_chars=100)
    assert cleaned == "字" * 100 + "…"


def test_clean_description_uses_default_max_chars_truncation():
    text = "字" * (SYNOPSIS_MAX_CHARS + 50)
    cleaned = clean_description(text)
    # Truncation should use SYNOPSIS_MAX_CHARS characters and then append an ellipsis.
    assert len(cleaned) == SYNOPSIS_MAX_CHARS + 1
    assert cleaned.endswith("…")
    assert cleaned[:-1] == "字" * SYNOPSIS_MAX_CHARS


def test_build_subscribe_confirm_card():

为了让这个测试通过,请确保在定义 SYNOPSIS_MAX_CHARS 的模块中,将它导入到 tests/test_cards.py,例如:

  • tests/test_cards.py 文件顶部添加 from <module> import SYNOPSIS_MAX_CHARS(将 <module> 调整为与你现有的导入以及 clean_description 所在模块相匹配的值)。
Original comment in English

suggestion (testing): Add a test that exercises the default SYNOPSIS_MAX_CHARS truncation behavior

Currently truncation is only verified with an explicit max_chars=100. Please add a test that calls clean_description without max_chars so it uses the default SYNOPSIS_MAX_CHARS, and asserts the resulting length and ellipsis position. This helps catch regressions if SYNOPSIS_MAX_CHARS changes or if off‑by‑one errors are introduced in the truncation logic.

Suggested implementation:

def test_clean_description_strips_html_and_whitespace():
    raw = "<p>  少年<b>吞下了</b>诅咒的手指,\n踏上讨伐&amp;之路。  </p>"
    assert clean_description(raw) == "少年吞下了诅咒的手指, 踏上讨伐&之路。"



def test_clean_description_truncates_with_ellipsis():
    text = "字" * 500
    cleaned = clean_description(text, max_chars=100)
    assert cleaned == "字" * 100 + "…"


def test_clean_description_uses_default_max_chars_truncation():
    text = "字" * (SYNOPSIS_MAX_CHARS + 50)
    cleaned = clean_description(text)
    # Truncation should use SYNOPSIS_MAX_CHARS characters and then append an ellipsis.
    assert len(cleaned) == SYNOPSIS_MAX_CHARS + 1
    assert cleaned.endswith("…")
    assert cleaned[:-1] == "字" * SYNOPSIS_MAX_CHARS


def test_build_subscribe_confirm_card():

To make this test pass, ensure SYNOPSIS_MAX_CHARS is imported into tests/test_cards.py from the module where it is defined, e.g.:

  • At the top of tests/test_cards.py, add from <module> import SYNOPSIS_MAX_CHARS (adjust <module> to match your existing imports and where clean_description is defined).

@FFFold
FFFold merged commit ff98dd3 into main Aug 19, 2026
2 checks passed
@FFFold
FFFold deleted the feat/card-synopsis branch August 19, 2026 00:48
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant