一键导入
jungle-test
为 Jungle C++26 游戏引擎项目编写单元测试。触发词:写测试、单元测试、test、为 X 写测试、测试 X、add test for X。默认行为:单元测试(<module>/unit_tests/*.cpp)。仅当用户明确说"集成测试"才生成集成测试(tests/)。
用 Codex 或 Claude 帮你安装 复制这段 Prompt,粘贴到 Codex、Claude 或其他助手里,让它检查 Skill 页面并帮你完成安装。
菜单
为 Jungle C++26 游戏引擎项目编写单元测试。触发词:写测试、单元测试、test、为 X 写测试、测试 X、add test for X。默认行为:单元测试(<module>/unit_tests/*.cpp)。仅当用户明确说"集成测试"才生成集成测试(tests/)。
用 Codex 或 Claude 帮你安装 复制这段 Prompt,粘贴到 Codex、Claude 或其他助手里,让它检查 Skill 页面并帮你完成安装。
基于 SOC 职业分类
| name | jungle-test |
| description | 为 Jungle C++26 游戏引擎项目编写单元测试。触发词:写测试、单元测试、test、为 X 写测试、测试 X、add test for X。默认行为:单元测试(<module>/unit_tests/*.cpp)。仅当用户明确说"集成测试"才生成集成测试(tests/)。 |
| argument-hint | 模块名、类名或组件名(如 hash_map、ComponentID、rwspinlock) |
| user-invocable | true |
用户输入
├─ 明确包含"集成测试" → 集成测试(tests/ 目录)
└─ 其他一切 → 单元测试(<module>/unit_tests/ 目录)
#include "jungle/test/test.h"
JUNGLE_SYNC_TEST(describe_what_is_tested) {
JUNGLE_SYNC_ASSERT(condition, "失败信息 {}", args...);
JUNGLE_SYNC_SUCCESS();
}
hash_map_default_state、component_id_copy_and_move)try/catch、throw、dynamic_cast、typeid、RTTI、异常从用户输入中提取被测试对象名称。可能的输入形式:
hash_mapComponentIDrwspinlock在代码库中搜索该名称,确定它属于哪个模块:
| 模块 | 命名空间 | 测试目录 |
|---|---|---|
jungle-base | jungle:: | jungle-base/unit_tests/ |
jungle-core | jungle::core:: | jungle-core/unit_tests/ |
jungle-tasks | jungle::tasks:: / jungle::sync:: | jungle-tasks/unit_tests/ |
搜索策略:
include/ 目录 grep 头文件声明在开始编写之前,读取同模块下至少一个已有测试文件,确认:
using namespace 惯例覆盖以下维度(按优先级):
文件模板(模板中的注释仅用于说明,实际生成代码时除 MIT 标记外不写任何注释):
// Copyright (C) 2026 pointer-to-bios <pointer-to-bios@outlook.com>
// SPDX-License-Identifier: MIT
#include "<被测头文件路径>"
#include "jungle/test/test.h"
// 如果涉及异步,还需:
// #include "jungle/test/async_test.h"
using namespace jungle;
// 根据需要添加子命名空间
JUNGLE_SYNC_TEST(descriptive_test_name) {
// Arrange: 准备测试数据
// Act: 执行操作
// Assert: 验证结果
JUNGLE_SYNC_ASSERT(condition, "中文描述:期望的行为");
JUNGLE_SYNC_SUCCESS();
}
约束:
mit snippet 直接生成)#pragma once 不用于 .cpp 测试文件try/catch、throwyield)能否使用。例如,yield() 后假定另一 worker 上的任务"已经执行到某个挂起点"就是脆弱的时序依赖;而用 yield() 仅让出执行权让调度器有机会推进、最终通过 co_await jh 等待任务完成则是安全的。对于同步原语(如 condition_variable、spinlock)的异步测试,优先使用谓词等待(co_await cv(pred))来消除时序竞争,谓词在 await_ready 中即被求值:若条件已为真则立即返回不挂起,若已挂起则被 notify 唤醒后重新检查谓词。两种路径下测试行为均确定。jungle-tasks 模块的异步测试运行在多线程运行时上,tasks::spawn 将任务随机分配到不同 worker。
脆弱时序依赖的本质是:测试假定 task A 已到达某个内部状态时 task B 才执行下一步,但二者在不同 worker 上并发运行,到达顺序不受控制。
脆弱的时序依赖(禁止):
// ❌ 假定 yield 后派生任务已挂载到 cv — 不同 worker 上不成立
auto jh = tasks::spawn([&]() -> async::future<> {
co_await cv();
});
co_await this_task::yield(); // 派生任务可能在另一 worker 上,尚未执行
cv.notify_one(); // 可能先于 await_suspend,丢唤醒
// ❌ 无条件等待 + 依赖时序 — 同样的问题
auto jh = tasks::spawn([&]() -> async::future<> {
co_await cv(); // 无条件挂起
});
co_await this_task::yield(); // 不保证任务已挂载到 cv
cv.notify_one(); // 可能先于 await_suspend 执行
消除时序依赖(正确):
// ✅ 谓词等待:无论 notify 先于或后于挂载,行为一致
JUNGLE_ASYNC_TEST(example_predicate_wait) {
condition_variable cv;
bool ready = false;
bool done = false;
auto jh = tasks::spawn([&]() -> async::future<> {
co_await cv([&] { return ready; }); // await_ready 即检查谓词
done = true;
});
ready = true;
cv.notify_one();
co_await jh;
JUNGLE_ASYNC_ASSERT(done, "等待者应完成执行");
JUNGLE_ASYNC_SUCCESS();
}
yield() 和 sleep() 本身并非禁止使用——禁止的是让测试结果依赖不可控的任务间并发执行顺序。yield() 用于让出执行权、co_await jh 用于等待任务完成,这些是安全且必要的同步手段。
在模块的 CMakeLists.txt 中找到 JUNGLE_UNIT_TEST_SOURCES 列表,添加新的 .cpp 文件。
链接依赖参考:
jungle-base → target_link_libraries(... PUBLIC jungle::test)jungle-core → target_link_libraries(... PUBLIC jungle::test jungle::core)jungle-tasks → target_link_libraries(... PUBLIC jungle::test-async)(异步测试需 jungle::test-async)禁止主动构建或运行测试:除非用户明确要求(如"构建并运行"、"跑一下测试"),否则仅生成代码和修改 CMakeLists.txt,不执行任何构建或运行命令。
当用户明确要求构建或运行时:
Build_CMakeTools / RunCtest_CMakeTools 工具),不得回退到终端命令(run_in_terminal)。tests/<name>.cpptests/CMakeLists.txt 中注册:add_executable + add_testint main() 入口,可以自由组合多个测试操作-freflection、-fcontracts)jungle::ustrjungle::hash_map 而非 std::unordered_mapjungle::types/int.h 中的类型