chore: import original project baseline
Import the pre-repair source tree as the history baseline. Runtime data (data/), virtualenvs, bytecode caches and logs are gitignored so local secrets and user state stay out of the repo.
This commit is contained in:
@@ -0,0 +1,87 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
"""
|
||||
file_reader 单元测试(标准库 unittest,零额外依赖)
|
||||
运行:在项目根目录执行 python -m unittest discover tests -v
|
||||
或直接 python tests/test_file_attach.py
|
||||
"""
|
||||
import os
|
||||
import sys
|
||||
import tempfile
|
||||
import unittest
|
||||
|
||||
# 保证直接运行(python tests/xxx.py)时也能 import 到项目根下的包
|
||||
sys.path.insert(0, os.path.join(os.path.dirname(os.path.abspath(__file__)), ".."))
|
||||
|
||||
from ui.views.system_tools.file_reader import BINARY_EXTS, read_text_file # noqa: E402
|
||||
|
||||
|
||||
class ReadTextFileTest(unittest.TestCase):
|
||||
"""read_text_file:编码探测 / 二进制探测 / 大小守卫"""
|
||||
|
||||
def _write(self, data: bytes, suffix: str = ".txt") -> str:
|
||||
fd, path = tempfile.mkstemp(suffix=suffix)
|
||||
with os.fdopen(fd, "wb") as f:
|
||||
f.write(data)
|
||||
self.addCleanup(os.remove, path)
|
||||
return path
|
||||
|
||||
def test_utf8_file(self):
|
||||
path = self._write("你好,世界\nhello".encode("utf-8"))
|
||||
content, enc, size_kb, lines = read_text_file(path)
|
||||
self.assertIn("你好,世界", content)
|
||||
self.assertIn("hello", content)
|
||||
self.assertEqual(lines, 2)
|
||||
self.assertIn(enc, ("utf-8-sig", "utf-8"))
|
||||
self.assertGreater(size_kb, 0)
|
||||
|
||||
def test_utf8_bom_file(self):
|
||||
path = self._write(b"\xef\xbb\xbf" + "带BOM".encode("utf-8"))
|
||||
content, enc, _, _ = read_text_file(path)
|
||||
self.assertEqual(content, "带BOM") # utf-8-sig 会吃掉 BOM
|
||||
self.assertEqual(enc, "utf-8-sig")
|
||||
|
||||
def test_gbk_file_falls_back_to_gb18030(self):
|
||||
path = self._write("中文GBK内容".encode("gbk"))
|
||||
content, enc, _, _ = read_text_file(path)
|
||||
self.assertEqual(content, "中文GBK内容")
|
||||
self.assertEqual(enc, "gb18030")
|
||||
|
||||
def test_binary_file_rejected(self):
|
||||
path = self._write(b"\x00\x01\x02\x03binary-payload")
|
||||
with self.assertRaises(ValueError):
|
||||
read_text_file(path)
|
||||
|
||||
def test_oversize_file_rejected(self):
|
||||
path = self._write(b"a" * 100)
|
||||
with self.assertRaises(ValueError):
|
||||
read_text_file(path, max_bytes=10)
|
||||
|
||||
def test_latin1_fallback_never_fails(self):
|
||||
# 0xFF 既非合法 UTF-8 也非合法 GB18030 引导字节,应由 latin-1 兜底
|
||||
path = self._write(b"\xff\xfe\xfd plain text")
|
||||
content, enc, _, _ = read_text_file(path)
|
||||
self.assertEqual(enc, "latin-1")
|
||||
self.assertIn("plain text", content)
|
||||
|
||||
|
||||
class BinaryExtBlacklistTest(unittest.TestCase):
|
||||
"""黑名单分类:Word/Excel 等被拒,常见代码/文本文件放行"""
|
||||
|
||||
def test_office_and_binary_blocked(self):
|
||||
for ext in (".doc", ".docx", ".xls", ".xlsx", ".ppt", ".pptx",
|
||||
".zip", ".exe", ".dll", ".mp4", ".ttf", ".db", ".psd"):
|
||||
self.assertIn(ext, BINARY_EXTS, f"{ext} 应在黑名单中")
|
||||
|
||||
def test_pdf_not_blacklisted(self):
|
||||
# PDF 改由专用分支(pdf_reader)处理,不再走二进制黑名单
|
||||
self.assertNotIn(".pdf", BINARY_EXTS, ".pdf 应由 PDF 专用分支处理,不应在黑名单中")
|
||||
|
||||
def test_text_and_code_allowed(self):
|
||||
for ext in (".py", ".js", ".ts", ".java", ".c", ".cpp", ".go", ".rs",
|
||||
".md", ".txt", ".json", ".yaml", ".html", ".css", ".sql",
|
||||
".sh", ".csv", ".log", ".ipynb", ""):
|
||||
self.assertNotIn(ext, BINARY_EXTS, f"{ext} 不应在黑名单中")
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
unittest.main()
|
||||
Reference in New Issue
Block a user