Skip to content

Latest commit

 

History

9 Commits

Folders and files

NameName
Last commit message
Last commit date
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

cpp-utgen

cpp-utgen 是一个面向 C/C++ 项目的大模型单元测试生成工具。它结合 LLVM/Clang 静态分析结果生成 GoogleTest,并对每个测试依次执行编译、运行和大模型修复,最终筛选可用测试、统计覆盖率并导出测试集。

工作流

目标项目源码 + compile_commands.json
                 |
                 v
    brinfo / focxt / include-finder
                 |
                 v
          大模型生成 GoogleTest
                 |
                 v
逐测试:编译 -> 编译修复 -> 运行 -> 测试修复
                 |
                 v
      filter_manifest.json 记录状态
                 |
                 v
       覆盖率统计 + 可用测试导出

默认流程在每个 test_*.cpp 生成后立即进入检查闭环:

  1. 编译失败时调用大模型修复,并重新编译候选。
  2. 编译通过后运行测试;断言、Mock、异常、崩溃和超时等失败会进入测试修复。
  3. 编译修复和测试修复共享单测试修复轮数,默认最多 10 轮。
  4. 最终通过的测试标记为 kept=true;仍失败的测试标记为 kept=false,原文件不会被删除。
  5. 只有状态有效且最终保留的测试参与覆盖率统计,并导出到 filtered_tests*

工具生成四类测试,用于对比路径需求和项目上下文对生成结果的影响:

类型 输出目录 路径测试需求 项目上下文
基础生成 llm_tests
上下文增强 llm_tests_cxt
需求增强 llm_tests_req
需求与上下文增强 llm_tests_req_cxt

仓库结构

路径 说明
utgen/ Python 主程序、逐测试工作流、编译/运行修复和覆盖率统计。
analysis-tools/ 可独立构建的 brinfofocxtinclude-finder Clang Tooling 工具。
docs/palm-cpp-unit-test-generation.md 技术路线、模块设计、数据结构和完整运行说明。
pyproject.tomluv.lock Python 3.12 环境和锁定依赖。

静态分析工具直接链接已安装的 LLVM/Clang 17 开发包,不需要下载完整 LLVM 源码树。构建细节及 macOS 安装方法见 静态分析工具说明

环境要求

  • uv 和 Python 3.12;项目依赖由 uv.lock 锁定。
  • CMake 3.20 或更高版本、Ninja,以及可编译目标项目的 C/C++ 工具链。
  • LLVM/Clang 17 开发包、clang-scan-depsclangd-indexer
  • GoogleTest、CTest,以及覆盖率阶段使用的 gcovlcovgenhtml
  • 可访问的 OpenAI 兼容大模型接口。

macOS 建议通过 Homebrew 安装 llvm@17、CMake、Ninja、uv 和 lcov。Homebrew 的 llvm@17 不包含 clangd-indexer,需按 macOS 配置说明 单独安装官方 LLVM 17 系列索引工具。

快速开始

以下命令均在仓库根目录执行。

1. 同步 Python 环境

uv sync --frozen

uv 会按照 .python-versionuv.lock 创建或更新根目录下的 .venv,无需手动激活虚拟环境。

2. 构建静态分析工具

将路径替换为本机 LLVM/Clang 17 的 CMake 包目录:

cmake -S analysis-tools -B analysis-tools/build -G Ninja \
  -DCMAKE_BUILD_TYPE=Release \
  -DLLVM_DIR=/path/to/llvm/lib/cmake/llvm \
  -DClang_DIR=/path/to/llvm/lib/cmake/clang
cmake --build analysis-tools/build
ctest --test-dir analysis-tools/build --output-on-failure

CMake 默认从 LLVM 安装前缀识别 Clang 内建头文件目录;非标准布局可额外传入 -DCPP_UTGEN_CLANG_RESOURCE_DIR="$(/path/to/clang-17 -print-resource-dir)"。该目录会记录在分析工具中,移动 LLVM 安装后应重新配置并构建。

可以直接使用构建目录中的可执行文件,也可以统一安装:

cmake --install analysis-tools/build --prefix "$HOME/.local"
export PATH="$HOME/.local/bin:$PATH"

include-finder 由 Python 主流程从 PATH 查找;若不安装,请把 analysis-tools/build/include-finder 加入 PATH

3. 配置本机路径和大模型接口

utgen/ 下创建不会被 Git 跟踪的 config_private.py

import os

URL = "https://your-llm-endpoint/v1/chat/completions"
API_KEY = "your-api-key"
MODEL = "your-model-name"
LIBCLANG_PATH = "/path/to/libclang.so"  # macOS 使用 libclang.dylib
BRINFO_PATH = "/path/to/brinfo"
FOCXT_PATH = "/path/to/focxt"
CPU_COUNT = os.cpu_count() or 4
CLANG_SCAN_DEPS_PATH = "/path/to/clang-scan-deps"
CLANGD_INDEXER_PATH = "/path/to/clangd-indexer"

MODEL 用于选择 OpenAI 兼容接口提供的聊天补全模型。libclang 动态库、Python clang 绑定和各分析工具应统一使用 LLVM 17 系列。请勿把 API Key 或本机绝对路径写入会提交的 utgen/config.py

4. 准备目标项目

目标 C/C++ 项目需要能够生成编译数据库:

cmake -S /path/to/project -B /path/to/project/build -G Ninja \
  -DCMAKE_BUILD_TYPE=Debug \
  -DCMAKE_EXPORT_COMPILE_COMMANDS=ON

目标项目还需要启用 CTest 和 GoogleTest、接入四类 llm_tests* 子目录及 llm_coverage,并准备覆盖率配置。完整 CMake 示例和 ctest.sh 说明见 准备目标 C/C++ 项目

5. 生成跨文件依赖

uv run --frozen python utgen/decldef.py \
  -p /path/to/project \
  -b /path/to/project/build

该步骤调用 clang-scan-depsclangd-indexer,在目标项目的 project_info/ 中生成依赖、声明和定义数据。仅在已有 deps.jsondecl_def.yaml 时才使用 --no-preprocess

6. 生成、验证并筛选测试

uv run --frozen python utgen/main.py \
  -p /path/to/project \
  -b /path/to/project/build \
  --max-repair-rounds 10 \
  --repair-choices 3 \
  --test-timeout 600

该命令完成项目分析、四类测试生成、逐测试编译与运行修复、最终复验、覆盖率统计和测试导出。只生成需求与上下文增强测试时添加 -t req-cxt-t base 表示无后缀的 llm_tests-t 可重复指定,省略时处理全部四类。项目级生成会产生较多大模型调用,建议先用小型目标项目验证工具链和配置。

主要产物

所有产物均写入目标项目,而不是本仓库:

产物 说明
llm_reqs/*_cxt.json brinfofocxt 的静态分析结果。
includes.json include-finder 收集的项目内头文件。
llm_tests* 全部生成测试、修复结果、日志和失败测试;C 源码的测试也使用 .cpp GoogleTest。
llm_tests*/filter_manifest.json 每个测试的编译、运行、修复轮数、文件哈希和 kept 状态。
filtered_tests* 仅包含最终编译通过、运行通过且状态有效的测试。
result*.csv 四类生成策略对应的编译、测试和覆盖率统计。
llm_coverage/ 覆盖率目标及运行产物。
project_info/ 源文件依赖、声明与定义映射等预处理结果。

测试目录层级、命名方式、GoogleTest 格式以及 Mock/异常示例见 单元测试用例格式规范

分阶段命令

# 复用已有 brinfo/focxt 分析结果,重新生成测试
uv run --frozen python utgen/main.py -p /path/to/project -b /path/to/project/build --no-analysis

# 不重新生成测试,对已有产物执行完整后处理
uv run --frozen python utgen/main.py -p /path/to/project -b /path/to/project/build --post-analysis

# 对已有产物分别执行编译检查、运行检查和导出
uv run --frozen python utgen/main.py -p /path/to/project -b /path/to/project/build --compile-only
uv run --frozen python utgen/main.py -p /path/to/project -b /path/to/project/build --test-only
uv run --frozen python utgen/main.py -p /path/to/project -b /path/to/project/build --export-only

默认主流程已自动调用编译修复和测试修复。compile_repair.pytest_repair.py 主要用于处理旧产物或人工控制阶段;详细参数见 UTGen 使用说明

注意事项

  • 主流程会注释目标项目中的 maintesttests 函数并生成 .bak 文件,建议在目标项目的临时副本、容器或干净 Git 工作树中运行。
  • compile_commands.json 是静态分析和测试编译的核心输入,路径错误或内容过期会导致后续阶段失败。
  • 失败测试不会被物理删除;是否保留由 filter_manifest.json 中的状态决定。
  • 修改 llm_tests* 中的测试后,旧哈希状态会失效,需要重新执行编译和运行检查才能导出。
  • --batch-workflow 可复现“全部生成后统一检查”的历史流程;新任务建议使用默认逐测试闭环。
  • macOS 上的覆盖率工具兼容性取决于目标项目所用编译器,正式运行前应先用小型项目验证 gcov 与 lcov 链路。

文档

About

Automatically Generate Unit Tests for C/C++ Programs using LLMs and Program Analysis

Resources

Stars

0 stars

Watchers

2 watching

Forks

Releases

Packages

Contributors

Languages