Files
Genarrative/plugins/agc-godot-editor/native/gdextension/tests/test_dependencies.py
T
kdletters fdc48aa573
Project CI / AI game creator shell Rust shard 1/4 (push) Failing after 17s
Project CI / AI game creator shell Rust shard 4/4 (push) Failing after 18s
Project CI / AI game creator shell Rust shard 3/4 (push) Failing after 18s
Project CI / AI game creator shell Rust shard 2/4 (push) Failing after 18s
Project CI / Backend tests (push) Failing after 17s
Project CI / AI game creator shell Rust smoke (push) Failing after 19s
Project CI / Native shell tests (push) Failing after 18s
Project CI / AI game creator shell Rust crates (push) Failing after 18s
Project CI / Frontend tests (push) Failing after 6s
Project CI / AI game creator shell web tests (push) Failing after 11s
Project CI / Repository checks (push) Failing after 11s
将 Godot 原生引导迁移到官方 C++ 绑定
使用固定版本 godot-cpp 替换手写 C ABI 引导并保留执行协议
采用 MSVC 与 CMake 构建,校验依赖归档和源码缓存
修复动态卸载时的实例绑定与单例包装生命周期
补充构建缓存测试、实机验收结果及分发文档
2026-09-20 22:00:44 +08:00

74 lines
3.2 KiB
Python

import hashlib
import importlib.util
import json
from pathlib import Path
import sys
import tempfile
import unittest
import zipfile
from unittest.mock import patch
sys.dont_write_bytecode = True
spec = importlib.util.spec_from_file_location("dependencies", Path(__file__).parents[1] / "prepare_dependencies.py")
dependencies = importlib.util.module_from_spec(spec)
spec.loader.exec_module(dependencies)
class DependencyTests(unittest.TestCase):
def setUp(self):
self.temp = tempfile.TemporaryDirectory()
self.addCleanup(self.temp.cleanup)
self.root = Path(self.temp.name)
self.commit = "a" * 40
self.name = f"godot-cpp-{self.commit}"
self.archive = self.root / ".build/dependencies" / f"{self.commit}.zip"
self.archive.parent.mkdir(parents=True)
(self.root / "vendor").mkdir()
(self.root / "vendor/LICENSE.txt").write_bytes(b"MIT\r\n")
self.write_archive({"LICENSE.md": b"MIT\n", "src/core.cpp": b"verified"})
def write_archive(self, entries):
with zipfile.ZipFile(self.archive, "w") as output:
for name, content in entries.items():
output.writestr(f"{self.name}/{name}", content)
provenance = {"commit": self.commit,
"archiveUrl": f"https://codeload.github.com/godotengine/godot-cpp/zip/{self.commit}",
"archiveSha256": hashlib.sha256(self.archive.read_bytes()).hexdigest()}
(self.root / "vendor/provenance.json").write_text(json.dumps(provenance), encoding="utf-8")
def test_verified_archive_is_reusable_offline(self):
with patch("urllib.request.urlopen", side_effect=AssertionError("Unexpected network")):
source = dependencies.prepare(self.root)
self.assertEqual(source, dependencies.prepare(self.root))
self.assertEqual((source / "src/core.cpp").read_bytes(), b"verified")
def test_corrupt_archive_is_rejected_and_preserved(self):
self.archive.write_bytes(b"corrupt")
with self.assertRaisesRegex(ValueError, "SHA256 mismatch"):
dependencies.prepare(self.root)
self.assertEqual(self.archive.read_bytes(), b"corrupt")
def test_modified_source_is_rejected_even_with_valid_archive(self):
source = dependencies.prepare(self.root)
(source / "src/core.cpp").write_bytes(b"modified")
with self.assertRaisesRegex(ValueError, "Modified godot-cpp"):
dependencies.prepare(self.root)
self.assertEqual((source / "src/core.cpp").read_bytes(), b"modified")
def test_extra_source_is_rejected(self):
source = dependencies.prepare(self.root)
(source / "extra.cpp").write_text("unexpected", encoding="utf-8")
with self.assertRaisesRegex(ValueError, "Unexpected dependency"):
dependencies.prepare(self.root)
def test_archive_paths_cannot_escape_on_windows_or_posix(self):
for name in ["../../escaped", "C:\\escaped", "..\\escaped"]:
with self.subTest(name=name):
self.write_archive({name: b"unexpected"})
with self.assertRaisesRegex(ValueError, "Unsafe dependency"):
dependencies.prepare(self.root)
if __name__ == "__main__":
unittest.main()