SuperAPI AI 工具集

c-game-regression-testing

测试与质量

查看项目

更新于 10-30 16:18

技能介绍

用途

该技能面向单文件 C 游戏的回归测试。这类游戏是一个包含大量 static 声明的大型 .c 文件,外加一个存放 *_test.c 文件的目录,这些测试文件会被编译进游戏源码中。测试运行器通过 glob 匹配 *_test.c,因此把新的测试文件放入 source/ 目录即可自动加入测试套件。该模式适用于 Aeons Echo: Null Citadel 系列,同样适用于未来同类原生 C 游戏。

测试文件结构

测试文件应遵循以下形态:

#define WinMainCRTStartup WinMainDisabled   /* silence WinMain from the included game */
#include "the_game.c"                       /* single TU: tests see every static */
#include <stdio.h>
#include "test_platform_stubs.inc"          /* GL/window stubs */

static void reset_all(void){ memset(&g_save,0,sizeof(g_save));g_save.has_save=1;
init_player(1);clear_world();g_rng=; }   /* fixed seed = deterministic */
static int check(const char*name,int ok){printf("%s=%s\n",name,ok?"PASS":"FAIL");return ok;}
int main(void){ int ok=1; ok&=my_feature_works(); ... return ok?0:1; }

编译规则

  • 只编译测试文件本身。若同时加入 game.c,会产生大量多重定义错误(memset、_fltused、WinMainCRTStartup 以及每个 win32 导入)。
  • 必须使用 -fno-builtin:游戏自定义了 memset/memcpy,缺少该标志时编译器会把它们变成自递归。
  • 链接库放在源文件之后;添加 -Wl,--stack,8388608(用于大型静态数组)。
  • 测试使用 mingw gcc 构建,即使发布构建使用 clang 严格模式;两条工具链都必须保持通过。

模拟世界夹具

  • 空的 clear_world() 没有地板。任何发射投射物、掉落拾取物或期望爆炸落地的测试,都必须先 add_box() 一块地板(例如中心 v3(0,-.5,0),半尺寸 v3(60,.5,60))。
  • 要测试地图填充,直接调用 build_<level>() 构建器——load_level() 会引入导演设置、音频和生成恢复,这些不适合单元测试。
  • 测量原始受到伤害时,将玩家护甲归零(护甲会吸收约 65% 并造成误导)。
  • 驱动 AI 时设置 state=AI_ALERT; alert=9; target=-2; last_seen=player; attack_cd=0,然后在有界循环中步进 update_entities(1/60)(绝不使用无界等待)。

调试卡住的模拟测试

在步进循环内部放置 printf 探针,而不是循环之后:每约 120 tick 打印一次,例如 printf("k=%d state=%d tele=%d burst=%d cd=%.2f fired=%d sees=%d dist=%.1f\n", ...)。状态数字会直接指向卡住的关卡(telegraph 从未打开 vs 已打开但从未提交 vs 投射物已生成但从未落地)。

项目特定细节(路径、现有辅助函数清单、存档布局断言、发布门禁)参见 references/native-c-game-harness-notes.md。

纪律

用户以 ponytail/full 模式运行此工作:在编写任何新内容之前,先 grep 令牌统计和现有辅助函数——本次会话中两次计划的功能实际上已经发布(无障碍滑块、结果屏幕)。通过现有模式实现最短差异者胜出。