""" 测试输出器功能 """ import sys import os from pathlib import Path # 添加项目路径到 sys.path project_root = Path(__file__).parent sys.path.insert(0, str(project_root)) from src.outputs import ObsidianWriter, GitSync from src.models import Content, ContentType, ContentStatus, TimelineEntry, ContentAnalysis from src.config import Config def create_test_content() -> Content: """创建测试数据""" content = Content( id="test001", source="bilibili", source_id="BV1234567890", url="https://www.bilibili.com/video/BV1234567890", title="Python 高级编程教程 - 装饰器深入解析", author="编程大师", description="深入讲解 Python 装饰器的原理和应用", duration=1800, # 30分钟 content_type=ContentType.VIDEO, status=ContentStatus.GENERATED, transcript="""欢迎来到本期的 Python 高级编程教程。 今天我们要深入探讨装饰器的原理和应用。 首先,让我们理解装饰器的基本概念... [更多字幕内容...]""", summary="本教程深入讲解了 Python 装饰器的原理,包括闭包、函数装饰器、类装饰器等核心概念,并通过实际案例展示了装饰器在日志、缓存、权限验证等场景中的应用。", one_liner="30分钟深入理解 Python 装饰器,从原理到实战", key_points=[ "装饰器本质上是高阶函数", "闭包是装饰器实现的基础", "@语法糖只是语法糖", "装饰器可以带参数", "类装饰器也是常见模式", ], tags=["Python", "装饰器", "高级编程", "教程"], quality_score=85.5, outline=[ "什么是装饰器", "装饰器的原理", "函数装饰器", "带参数的装饰器", "类装饰器", "装饰器应用场景", "实战案例", ], timeline=[ TimelineEntry( timestamp="00:00", title="课程介绍", description="介绍本课程的主要内容和学习目标" ), TimelineEntry( timestamp="02:30", title="装饰器基础", description="讲解装饰器的基本概念和语法" ), TimelineEntry( timestamp="10:00", title="装饰器原理", description="深入理解装饰器背后的实现原理" ), TimelineEntry( timestamp="20:00", title="实战案例", description="通过实际代码演示装饰器的应用" ), ], category="编程", ) # 添加详细分析 content.analysis = ContentAnalysis( one_liner="30分钟深入理解 Python 装饰器,从原理到实战", summary="本教程深入讲解了 Python 装饰器的原理,包括闭包、函数装饰器、类装饰器等核心概念。", key_points=[ "装饰器本质上是高阶函数", "闭包是装饰器实现的基础", "@语法糖只是语法糖", ], tags=["Python", "装饰器"], quality_score=85.5, prerequisites=["Python 基础语法", "函数基础", "面向对象基础"], outline=[ {"title": "装饰器基础", "content": "什么是装饰器,基本语法"}, {"title": "实现原理", "content": "闭包的作用,装饰器的执行流程"}, {"title": "高级用法", "content": "带参数的装饰器,类装饰器"}, {"title": "实际应用", "content": "日志记录、性能测试、权限验证"}, ], pitfalls=[ "忘记保留原函数的元数据(如 __name__, __doc__)", "装饰器中修改参数可能导致意外行为", "多层装饰器的执行顺序容易混淆", ], practice_advice=[ "多动手实践,编写不同类型的装饰器", "使用 functools.wraps 保留函数元数据", "在复杂场景下考虑使用类装饰器", ], ) return content def create_test_content_no_subtitle() -> Content: """创建无字幕的测试数据""" content = Content( id="test002", source="bilibili", source_id="BV0987654321", url="https://www.bilibili.com/video/BV0987654321", title="无字幕测试视频", author="测试UP主", description="这是一个没有字幕的测试视频", duration=300, # 5分钟 content_type=ContentType.VIDEO, status=ContentStatus.GENERATED, transcript="", # 空字幕 summary="这是一个测试视频,用于验证无字幕时的输出", one_liner="测试无字幕视频的输出功能", key_points=[ "测试要点1", "测试要点2", ], tags=["测试"], quality_score=60.0, ) return content def test_obsidian_writer(): """测试 ObsidianWriter""" print("=" * 60) print("测试 ObsidianWriter") print("=" * 60) # 创建测试配置 config = Config() # 使用临时测试目录 test_vault = Path("/tmp/test_obsidian_vault") if test_vault.exists(): import shutil shutil.rmtree(test_vault) test_vault.mkdir(parents=True, exist_ok=True) # 修改配置使用测试 vault config._config['obsidian']['vault_path'] = str(test_vault) # 创建写入器 writer = ObsidianWriter(config) # 测试1: 有字幕的内容 print("\n测试1: 写入有字幕的内容") content1 = create_test_content() file_path1 = writer.write(content1, config) if file_path1: print(f"✓ 成功写入: {file_path1}") # 检查文件是否存在 if Path(file_path1).exists(): print(f"✓ 文件存在") # 读取并显示前20行 print("\n文件内容预览(前20行):") with open(file_path1, 'r', encoding='utf-8') as f: lines = f.readlines()[:20] for i, line in enumerate(lines, 1): print(f"{i:2d}: {line.rstrip()}") else: print(f"✗ 文件不存在") else: print("✗ 写入失败") # 测试2: 无字幕的内容 print("\n" + "-" * 60) print("测试2: 写入无字幕的内容") content2 = create_test_content_no_subtitle() file_path2 = writer.write(content2, config) if file_path2: print(f"✓ 成功写入: {file_path2}") # 检查文件是否存在 if Path(file_path2).exists(): print(f"✓ 文件存在") # 读取并显示最后几行 print("\n文件内容预览(最后10行):") with open(file_path2, 'r', encoding='utf-8') as f: lines = f.readlines() for line in lines[-10:]: print(f" {line.rstrip()}") else: print(f"✗ 文件不存在") else: print("✗ 写入失败") # 检查目录结构 print("\n" + "-" * 60) print("目录结构:") print(f"{test_vault}/") for root, dirs, files in os.walk(test_vault): level = root.replace(str(test_vault), '').count(os.sep) indent = ' ' * 2 * level print(f"{indent}{os.path.basename(root)}/") subindent = ' ' * 2 * (level + 1) for file in files: print(f"{subindent}{file}") # 清理测试目录 print("\n" + "-" * 60) print(f"测试目录: {test_vault}") print("测试完成后可手动删除测试目录") return file_path1 is not None and file_path2 is not None def test_git_sync(): """测试 GitSync""" print("\n" + "=" * 60) print("测试 GitSync") print("=" * 60) # 创建测试 vault test_vault = Path("/tmp/test_git_vault") if test_vault.exists(): import shutil shutil.rmtree(test_vault) test_vault.mkdir(parents=True, exist_ok=True) # 初始化 Git 仓库 try: subprocess_result = os.system(f"cd {test_vault} && git init && git config user.email 'test@example.com' && git config user.name 'Test User' > /dev/null 2>&1") print(f"✓ Git 仓库初始化成功") except: print("✗ Git 初始化失败,跳过 GitSync 测试") return False # 创建测试配置 config = Config() config._config['obsidian']['vault_path'] = str(test_vault) config._config['git']['enabled'] = True config._config['git']['auto_push'] = False # 不测试 push,避免需要远程仓库 # 创建 Git 同步器 sync = GitSync(config) # 测试1: 检查 Git 状态 print("\n测试1: 检查是否为 Git 仓库") is_repo = sync._is_git_repo() print(f"✓ 是否为 Git 仓库: {is_repo}") # 测试2: 创建测试文件并同步 print("\n测试2: 创建文件并同步") test_file = test_vault / "test.md" test_file.write_text("# 测试文件\n\n这是一个测试文件。") result = sync.sync(config) print(f"✓ 同步结果: {result}") # 测试3: 检查 Git 状态 print("\n测试3: 检查 Git 状态") os.system(f"cd {test_vault} && git log --oneline -n 3") print("\n" + "-" * 60) print(f"测试目录: {test_vault}") print("测试完成后可手动删除测试目录") return result def main(): """主测试函数""" print("\n" + "=" * 60) print("Obsidian-KB 输出器测试") print("=" * 60) results = {} # 测试 ObsidianWriter results['obsidian_writer'] = test_obsidian_writer() # 测试 GitSync results['git_sync'] = test_git_sync() # 汇总结果 print("\n" + "=" * 60) print("测试结果汇总") print("=" * 60) for test_name, result in results.items(): status = "✓ 通过" if result else "✗ 失败" print(f"{test_name}: {status}") # 总体结果 all_passed = all(results.values()) print("\n" + "=" * 60) if all_passed: print("✓ 所有测试通过!") else: print("✗ 部分测试失败") print("=" * 60) return all_passed if __name__ == "__main__": success = main() sys.exit(0 if success else 1)