|
| 1 | +import re |
| 2 | +import unittest |
| 3 | +from types import SimpleNamespace |
| 4 | + |
| 5 | +from common.handle.impl.text.text_split_handle import TextSplitHandle |
| 6 | +from common.utils.split_model import SplitModel, get_split_model |
| 7 | + |
| 8 | + |
| 9 | +class SplitModelTestCase(unittest.TestCase): |
| 10 | + @staticmethod |
| 11 | + def paragraphs(text, filename='test.md'): |
| 12 | + return [ |
| 13 | + (' '.join(row['title'].split()), row['content'].strip()) |
| 14 | + for row in get_split_model(filename).parse(text) |
| 15 | + ] |
| 16 | + |
| 17 | + def test_same_heading_at_different_levels(self): |
| 18 | + for level in range(1, 6): |
| 19 | + with self.subTest(level=level): |
| 20 | + parent, child = '#' * level, '#' * (level + 1) |
| 21 | + text = ( |
| 22 | + f'{parent} 员工手册目录\n\n' |
| 23 | + f'{child} 第一部分:公司概述\n目录条目一\n\n' |
| 24 | + f'{child} 第二部分:人力资源\n目录条目二\n\n' |
| 25 | + f'{parent} 第一部分:公司概述\n正文内容\n' |
| 26 | + ) |
| 27 | + self.assertEqual(self.paragraphs(text), [ |
| 28 | + ('员工手册目录 第一部分:公司概述', '目录条目一'), |
| 29 | + ('员工手册目录 第二部分:人力资源', '目录条目二'), |
| 30 | + ('第一部分:公司概述', '正文内容'), |
| 31 | + ]) |
| 32 | + |
| 33 | + def test_heading_text_in_body_does_not_start_section(self): |
| 34 | + text = '# 目录\n引用:# 正文\n\n# 正文\n正文内容' |
| 35 | + self.assertEqual(self.paragraphs(text), [ |
| 36 | + ('目录', '引用:# 正文'), |
| 37 | + ('正文', '正文内容'), |
| 38 | + ]) |
| 39 | + |
| 40 | + def test_heading_text_in_code_block_does_not_start_section(self): |
| 41 | + text = '# 目录\n```markdown\n# 正文\n```\n\n# 正文\n正文内容' |
| 42 | + self.assertEqual(self.paragraphs(text), [ |
| 43 | + ('目录', '```markdown\n# 正文\n```'), |
| 44 | + ('正文', '正文内容'), |
| 45 | + ]) |
| 46 | + |
| 47 | + def test_repeated_headings_keep_each_body(self): |
| 48 | + text = '# 章节\n第一段提到 # 章节\n\n# 章节\n第二段' |
| 49 | + self.assertEqual(self.paragraphs(text), [ |
| 50 | + ('章节', '第一段提到 # 章节'), |
| 51 | + ('章节', '第二段'), |
| 52 | + ]) |
| 53 | + |
| 54 | + def test_heading_prefix_does_not_end_section(self): |
| 55 | + text = '# 前言\n引用:# 公司概述扩展\n\n# 公司概述扩展\n扩展内容\n\n# 公司概述\n正文' |
| 56 | + self.assertEqual(self.paragraphs(text), [ |
| 57 | + ('前言', '引用:# 公司概述扩展'), |
| 58 | + ('公司概述扩展', '扩展内容'), |
| 59 | + ('公司概述', '正文'), |
| 60 | + ]) |
| 61 | + |
| 62 | + def test_preamble_is_preserved(self): |
| 63 | + text = '前言提到 # 正文\n\n# 正文\n正文内容' |
| 64 | + self.assertEqual(self.paragraphs(text), [ |
| 65 | + ('', '前言提到 # 正文'), |
| 66 | + ('正文', '正文内容'), |
| 67 | + ]) |
| 68 | + |
| 69 | + def test_custom_patterns_with_capture_groups(self): |
| 70 | + pattern = re.compile(r'(?m)^(# .+)$|^(## .+)$') |
| 71 | + text = '# 目录\n引用:## 公司概述\n\n## 公司概述\n正文' |
| 72 | + result = SplitModel([pattern], with_filter=False).parse(text) |
| 73 | + self.assertEqual([(row['title'].strip(), row['content'].strip()) for row in result], [ |
| 74 | + ('目录', '引用:## 公司概述'), |
| 75 | + ('公司概述', '正文'), |
| 76 | + ]) |
| 77 | + |
| 78 | + def test_invalid_patterns_fall_back_to_plain_text(self): |
| 79 | + for pattern in (None, '', ' ', '['): |
| 80 | + with self.subTest(pattern=pattern): |
| 81 | + self.assertEqual(SplitModel([pattern]).parse('普通文本'), [ |
| 82 | + {'title': '', 'content': '普通文本'}, |
| 83 | + ]) |
| 84 | + |
| 85 | + def test_long_heading_keeps_text_after_title_limit(self): |
| 86 | + heading = '# ' + '标题' * 150 |
| 87 | + rows = get_split_model('test.md').parse(heading + '\n正文') |
| 88 | + self.assertEqual(len(rows), 1) |
| 89 | + self.assertEqual(rows[0]['title'], heading[:255].replace('#', '')) |
| 90 | + self.assertEqual(rows[0]['content'], heading[255:] + '\n正文') |
| 91 | + |
| 92 | + def test_plain_text_splitting(self): |
| 93 | + self.assertEqual(self.paragraphs('第一段\n\n第二段', 'test.txt'), [ |
| 94 | + ('', '第一段'), |
| 95 | + ('', '第二段'), |
| 96 | + ]) |
| 97 | + |
| 98 | + def test_text_upload_handler_keeps_directory_under_its_heading(self): |
| 99 | + text = ( |
| 100 | + '# 员工手册目录\n\n' |
| 101 | + '## 第一部分:公司概述\n目录条目一\n\n' |
| 102 | + '## 第二部分:人力资源\n目录条目二\n\n' |
| 103 | + '# 第一部分:公司概述\n\n' |
| 104 | + '## 公司简介\n正文内容\n' |
| 105 | + ) |
| 106 | + for newline in ('\n', '\r\n', '\r'): |
| 107 | + with self.subTest(newline=repr(newline)): |
| 108 | + result = TextSplitHandle().handle( |
| 109 | + SimpleNamespace(name='员工手册目录.md'), [], False, 100000, |
| 110 | + lambda _: text.replace('\n', newline).encode('utf-8'), None, |
| 111 | + ) |
| 112 | + self.assertEqual([ |
| 113 | + (' '.join(row['title'].split()), row['content'].strip()) for row in result['content'] |
| 114 | + ], [ |
| 115 | + ('员工手册目录 第一部分:公司概述', '目录条目一'), |
| 116 | + ('员工手册目录 第二部分:人力资源', '目录条目二'), |
| 117 | + ('第一部分:公司概述 公司简介', '正文内容'), |
| 118 | + ]) |
| 119 | + |
| 120 | + |
| 121 | +if __name__ == '__main__': |
| 122 | + unittest.main() |
0 commit comments