修复:CI 部署环境与 ref 错配、迁移碎片化、图片意图 source_span、章节物化脏版式、会话历史与本地语音不一致
新增:TTS 上传 COS 与分片、章节 reading_segments 物化与快照、markdown 清洗、会话消息 repository、语音 store 重构与相关测试
This commit is contained in:
89
api/tests/test_reading_segments_dedupe.py
Normal file
89
api/tests/test_reading_segments_dedupe.py
Normal file
@@ -0,0 +1,89 @@
|
||||
"""reading_segments:正文已含与主插图相同 asset 时不重复 cover_image。"""
|
||||
|
||||
import unittest
|
||||
|
||||
from app.features.memoir.helpers import build_reading_segments
|
||||
from app.features.memoir.reading_segment_materialize import (
|
||||
build_reading_segments_snapshot,
|
||||
resolve_reading_segments_for_chapter_detail,
|
||||
)
|
||||
|
||||
|
||||
class _Intent:
|
||||
def __init__(self, asset_id: str):
|
||||
self.intent_role = "primary"
|
||||
self.asset_id = asset_id
|
||||
self.caption = "cap"
|
||||
self.prompt_brief = None
|
||||
self.style_profile = None
|
||||
self.error = None
|
||||
self.status = "completed"
|
||||
self.created_at = None
|
||||
self.updated_at = None
|
||||
|
||||
|
||||
class _Story:
|
||||
def __init__(self, sid: str, body: str, asset_id: str):
|
||||
self.id = sid
|
||||
self.title = "T"
|
||||
self.canonical_markdown = body
|
||||
self.image_intents = [_Intent(asset_id)]
|
||||
|
||||
|
||||
class _Link:
|
||||
def __init__(self, order: int, story: _Story):
|
||||
self.order_index = order
|
||||
self.story = story
|
||||
|
||||
|
||||
class _Ch:
|
||||
def __init__(self, story: _Story):
|
||||
self.story_links = [_Link(0, story)]
|
||||
|
||||
|
||||
class ReadingSegmentsDedupeTest(unittest.TestCase):
|
||||
def test_omits_cover_when_primary_asset_in_body(self):
|
||||
aid = "c67d11c5-23b7-4ab9-91ed-c05b5a27a12b"
|
||||
body = f"正文\n\n\n\n更多"
|
||||
st = _Story("s1", body, aid)
|
||||
ch = _Ch(st)
|
||||
asset_url_map = {aid: "https://cos.example/img.png"}
|
||||
segs = build_reading_segments(ch, asset_url_map=asset_url_map)
|
||||
self.assertEqual(len(segs), 1)
|
||||
self.assertIn("https://cos.example", segs[0]["body_markdown"])
|
||||
self.assertIsNone(segs[0]["cover_image"])
|
||||
|
||||
def test_keeps_cover_when_primary_not_in_body(self):
|
||||
aid = "aaaaaaaa-bbbb-cccc-dddd-eeeeeeeeeeee"
|
||||
body = "仅文字无图"
|
||||
st = _Story("s1", body, aid)
|
||||
ch = _Ch(st)
|
||||
asset_url_map = {aid: "https://cos.example/cover.png"}
|
||||
segs = build_reading_segments(ch, asset_url_map=asset_url_map)
|
||||
self.assertEqual(len(segs), 1)
|
||||
self.assertIsNotNone(segs[0]["cover_image"])
|
||||
self.assertTrue(segs[0]["cover_image"].get("url"))
|
||||
|
||||
def test_persisted_snapshot_hydrate_matches_live_materialize(self):
|
||||
aid = "aaaaaaaa-bbbb-cccc-dddd-eeeeeeeeeeee"
|
||||
body = "仅文字无图"
|
||||
st = _Story("s1", body, aid)
|
||||
ch = _Ch(st)
|
||||
ch.reading_segments_json = build_reading_segments_snapshot(ch)
|
||||
ch.markdown_compose_dirty = False
|
||||
asset_url_map = {aid: "https://cos.example/cover.png"}
|
||||
live = build_reading_segments(ch, asset_url_map=asset_url_map)
|
||||
via_snapshot = resolve_reading_segments_for_chapter_detail(
|
||||
ch, asset_url_map=asset_url_map
|
||||
)
|
||||
self.assertEqual(len(live), len(via_snapshot))
|
||||
self.assertEqual(live[0]["story_id"], via_snapshot[0]["story_id"])
|
||||
self.assertEqual(live[0]["body_markdown"], via_snapshot[0]["body_markdown"])
|
||||
self.assertEqual(
|
||||
(live[0]["cover_image"] or {}).get("url"),
|
||||
(via_snapshot[0]["cover_image"] or {}).get("url"),
|
||||
)
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
unittest.main()
|
||||
Reference in New Issue
Block a user