""" 集成测试:测试 PyArmor 加密打包 -> 存储 -> 加载 -> 执行 全流程 """ import sys import os import tempfile import shutil # 添加项目模块路径 sys.path.insert(0, os.path.join(os.path.dirname(__file__), "..", "src")) TEST_DB = os.path.join(os.path.dirname(__file__), "test_pyarmor_integration.db") def create_test_module(): """创建测试用的 Python 模块""" return """ def greet(name): return f"Hello, {name}! This is a PyArmor protected module." class Calculator: def add(self, a, b): return a + b def multiply(self, a, b): return a * b VERSION = "1.0.0" """ def test_pyarmor_obfuscate(): """测试 PyArmor 混淆功能""" print("=" * 60) print("测试 1: PyArmor 混淆功能") print("=" * 60) from module_bank.pyarmor_encryption import PyArmorEncryption enc = PyArmorEncryption(obf_code=1, obf_mod=1) # 检查 PyArmor 是否可用 if not enc.check_pyarmor_available(): print("ERROR: PyArmor 未安装或不可用") return False source = create_test_module() print(f"原始代码长度: {len(source)} 字节") try: obfuscated_code, runtime_data = enc.obfuscate_source( source, "test_protected_module" ) print(f"混淆后代码长度: {len(obfuscated_code)} 字节") print(f"运行时文件: {'有' if runtime_data else '无'}") print(f"运行时数据大小: {len(runtime_data) if runtime_data else 0} 字节") # 验证是否被保护 assert enc.is_pyarmor_protected(obfuscated_code), "代码应被标记为 PyArmor 保护" print(f"PyArmor 保护标记: 正确") # 提取运行时模块名 runtime_name = enc.extract_runtime_info(obfuscated_code) print(f"运行时模块名: {runtime_name}") print("测试 1 通过!\n") return True except Exception as e: print(f"ERROR: {e}") import traceback traceback.print_exc() return False def test_pack_with_pyarmor(): """测试使用 PyArmor 打包到 SQLite""" print("=" * 60) print("测试 2: 使用 PyArmor 打包到 SQLite") print("=" * 60) # 清理旧的测试数据库 if os.path.exists(TEST_DB): os.remove(TEST_DB) try: from module_bank.python_to_sqlite import PythonToSQLite # 使用 PyArmor 创建打包器 packer = PythonToSQLite( TEST_DB, pyarmor_obfuscate=True, pyarmor_obf_code=1, pyarmor_obf_mod=1, ) source = create_test_module() packer.importer.add_module("test_protected_module", source, is_package=False) print("模块已打包到数据库") # 验证模块已存储 modules = packer.list_modules() module_names = [m["module_name"] for m in modules] assert "test_protected_module" in module_names, "模块应在数据库中存在" print(f"数据库中的模块: {module_names}") # 验证运行时已存储 runtimes = packer.importer.list_runtimes() print(f"数据库中的运行时: {[r['runtime_name'] for r in runtimes]}") # 验证 pyarmor_protected 标记 cursor = packer.importer.connection.execute( "SELECT pyarmor_protected FROM python_modules WHERE module_name = ?", ("test_protected_module",), ) row = cursor.fetchone() assert row["pyarmor_protected"] == 1, "模块应标记为 pyarmor_protected" print("PyArmor 保护标记: 已正确设置") print("测试 2 通过!\n") return True except Exception as e: print(f"ERROR: {e}") import traceback traceback.print_exc() return False def test_import_pyarmor_module(): """测试从 SQLite 导入并执行 PyArmor 保护的模块""" print("=" * 60) print("测试 3: 从 SQLite 导入并执行 PyArmor 保护模块") print("=" * 60) try: from module_bank.python_to_sqlite import PythonToSQLite from module_bank.sqlite_meta_path_finder import SQLiteMetaPathFinder packer = PythonToSQLite(TEST_DB) # 安装导入器 finder = packer.install_importer() # 尝试导入模块 import importlib mod = importlib.import_module("test_protected_module") print(f"模块导入成功: {mod}") print(f"模块名: {mod.__name__}") print(f"模块文件: {mod.__file__}") # 调用模块函数 result = mod.greet("World") print(f"调用 greet('World'): {result}") assert result == "Hello, World! This is a PyArmor protected module." # 使用模块类 calc = mod.Calculator() assert calc.add(3, 4) == 7 assert calc.multiply(3, 4) == 12 print(f"Calculator.add(3, 4) = {calc.add(3, 4)}") print(f"Calculator.multiply(3, 4) = {calc.multiply(3, 4)}") # 访问模块变量 print(f"VERSION = {mod.VERSION}") assert mod.VERSION == "1.0.0" print("测试 3 通过!\n") # 清理 sys.meta_path.remove(finder) if "test_protected_module" in sys.modules: del sys.modules["test_protected_module"] return True except Exception as e: print(f"ERROR: {e}") import traceback traceback.print_exc() return False def test_cli_with_pyarmor(): """测试 CLI 的 PyArmor 参数""" print("=" * 60) print("测试 4: CLI --pyarmor 参数") print("=" * 60) try: import tempfile # 创建临时源文件 tmpdir = tempfile.mkdtemp() src_file = os.path.join(tmpdir, "hello_module.py") with open(src_file, "w", encoding="utf-8") as f: f.write("def hello():\n return 'Hello from PyArmor CLI!'\n") db_path = os.path.join(tmpdir, "test_cli.db") # 测试解析 --pyarmor 参数 from module_bank.cli import main as cli_main # 保存原始argv old_argv = sys.argv try: sys.argv = [ "mbank", "pack", src_file, "--db", db_path, "--name", "hello_cli_module", "--pyarmor", ] cli_main() print("CLI pack with --pyarmor 执行成功") # 验证模块已用 PyArmor 保护 from module_bank.sqlite_module_importer import SQLiteModuleImporter importer = SQLiteModuleImporter(db_path) cursor = importer.connection.execute( "SELECT pyarmor_protected FROM python_modules WHERE module_name = ?", ("hello_cli_module",), ) row = cursor.fetchone() assert row and row["pyarmor_protected"] == 1, "CLI 打包的模块应启用 PyArmor" print("CLI 打包的模块已正确启用 PyArmor 保护") # 验证运行时存储 runtimes = importer.list_runtimes() assert len(runtimes) > 0, "CLI 打包后应有运行时文件存储在数据库中" print(f"运行时已存储: {[r['runtime_name'] for r in runtimes]}") finally: sys.argv = old_argv shutil.rmtree(tmpdir, ignore_errors=True) print("测试 4 通过!\n") return True except Exception as e: print(f"ERROR: {e}") import traceback traceback.print_exc() return False def cleanup(): """清理测试文件""" if os.path.exists(TEST_DB): os.remove(TEST_DB) print(f"已清理测试数据库: {TEST_DB}") if __name__ == "__main__": print("\n" + "=" * 60) print("PyArmor 集成测试套件") print("=" * 60 + "\n") tests = [ ("PyArmor 混淆功能", test_pyarmor_obfuscate), ("PyArmor 打包到 SQLite", test_pack_with_pyarmor), ("从 SQLite 导入 PyArmor 模块", test_import_pyarmor_module), ("CLI --pyarmor 参数", test_cli_with_pyarmor), ] passed = 0 failed = 0 for name, func in tests: print(f"\n>>> 运行测试: {name}") try: if func(): passed += 1 else: failed += 1 except Exception as e: print(f"测试异常: {e}") import traceback traceback.print_exc() failed += 1 cleanup() print("\n" + "=" * 60) print(f"测试完成: {passed} 通过, {failed} 失败") print("=" * 60) sys.exit(1 if failed > 0 else 0)