跳转至

Lab 2:用测试找出 AI 代码中的错误

作业内容

这个 Lab 提供了 8 个由 AI 生成的环形缓冲区程序。它们都能编译,也能通过一些普通测试,但每个程序都有错误。另外它还提供了一个正确的参考程序。

你不需要修改这些 Rust 程序。你的任务是在 submission/cases.json 中为每个待检查程序编写一组测试,用尽量短的操作序列让它暴露错误。第 1 组对应 candidate_01,第 2 组对应 candidate_02,依次类推。检查器会把每组操作分别交给课程提供的正确程序和对应的待检查程序;只要两边有一步返回不同的结果,这一组就通过。

修改内容

本次作业只允许同学们修改 submission/cases.json,不允许修改其他文件。正式评分时,助教只会取出你的 submission/cases.json,放进一份未被修改的项目中运行。因此,修改本地的 Rust 程序或评分测试不会影响成绩。

数据格式

cases.json 的最外层是一个包含 8 项的数组。从前往后,这 8 组测试分别对应 candidate_01candidate_08。下面是一组测试的写法:

{
  "capacity": 3,
  "operations": [
    { "op": "write", "value": 10 },
    { "op": "write", "value": 20 },
    { "op": "read" },
    { "op": "overwrite", "value": -5 },
    { "op": "clear" }
  ]
}

每组测试只有两个字段:

  • capacity:缓冲区容量,必须是 1..=8 内的整数;
  • operations:按顺序执行的操作,每组必须有 1 到 30 个。

四种操作的写法和限制如下:

操作 JSON 写法 限制
write {"op":"write","value":10} 必须填写整数 value,范围为 -100..=100;缓冲区已满时不能修改其中的数据
read {"op":"read"} 不能填写 value;每次读取并删除最早写入的值
overwrite {"op":"overwrite","value":-5} 必须填写整数 value,范围为 -100..=100;缓冲区已满时删除最早写入的值再写入
clear {"op":"clear"} 不能填写 value;执行后缓冲区必须为空

不要在 JSON 中填写正确结果,检查器会自动计算。每个对象都只能使用上面列出的字段,不能自行增加字段。

你只需要提交一个测试数据文件:submission/cases.json。文件中必须正好有 8 组测试,依次对应 8 个待检查程序。所有测试合计不能超过 200 个操作。文件使用 UTF-8 编码,大小不能超过 64 KiB。数据写错时,检查器会告诉你具体是哪一组、哪一步不符合要求。

环形缓冲区的正确行为

每组测试都会创建一个容量固定、初始为空的环形缓冲区。缓冲区按先进先出(FIFO)的顺序保存 i32:最早写入且尚未读出的值最先被读出。

操作 正确行为
write(value) 缓冲区未满时,在末尾写入并返回 Success;已满时返回 Full,其中的数据不能改变
read() 缓冲区非空时,删除并返回最早写入的值 Value(value);为空时返回 Empty
overwrite(value) 未满时与 write 相同;已满时先删除最早写入的值,再在末尾写入新值;两种情况都返回 Success
clear() 删除缓冲区中的所有值并返回 Success;原本为空时也返回 Success

读出一个值后,空出来的位置可以继续写入。无论读写多少次,这些行为都不能改变。

本地检查

检查原理

src/reference.rs 是课程提供的正确程序,它完全按照上面的要求运行。你不需要修改它;检查器用它来计算每一步应该返回什么。

检查每一组测试时,检查器会:

  1. 分别运行正确程序和这一组对应的待检查程序;
  2. 向两边依次发送完全相同的操作;
  3. 每一步都比较两边返回的 SuccessFullEmptyValue(...)
  4. 发现不同后,记录第几组、第几步、正确结果和实际结果。

检查器按顺序判断 8 个待检查程序:

  • 如果待检查程序在这一组的任意一步返回了不同的结果,就说明这组测试成功找到了它的错误;
  • 如果整组操作执行结束后,待检查程序每一步的返回结果都与正确程序相同,这组测试失败,需要继续调整其中的操作;
  • 如果 cases.json 格式错误或不满足后文的数据限制,检查器不会运行这些程序,整份数据会直接判定为写法错误。

因此,待检查程序出现错误对你来说是成功;你的目标是让 8 个待检查程序都至少出现一次与正确程序不同的返回结果。只有达到 8/8,程序部分才全部通过。

例如,容量为 2 时依次执行 write(10)write(20)read(),最后一步应当得到 Value(10)。如果某个程序返回 Value(20),这组数据就找到了它没有按先进先出顺序读取的错误。

有些操作当下返回的结果看起来没问题,却错误地改变了缓冲区中的数据或顺序。这时需要继续添加 read 等操作,直到这个错误出现在返回结果中。一个程序可能有多个问题,只要找到其中一个能够通过返回结果观察到的问题即可;不要求所有同学使用相同的测试方法。

本地验证测试数据

每次修改 submission/cases.json 后,先运行检查器:

cargo run --bin checker

检查器会读取你的 JSON,并分别检查它能否让 8 个待检查程序暴露错误。输出中的每一项对应一个程序:

  • ✓ candidate_03:第 3 组已发现错误:第 3 组已经让这个程序返回了错误结果,这一项完成;
  • ✗ candidate_03:第 3 组尚未发现错误:需要继续调整第 3 组的操作。

最后一行会显示总结果,例如 已找出 5/8 个程序的问题。达到 8/8 才表示程序部分全部完成。仓库自带的初始数据故意只找出 1 个程序的问题,因此第一次运行显示 1/8 是正常的,不是环境配置失败。

只要还没有达到 8/8,检查器就会以失败状态结束;某些终端或 IDE 可能因此显示“命令失败”。这表示测试数据还不完整,不表示检查器无法运行。

达到 8/8 后,再运行自动测试:

cargo test --release

这条命令会运行 9 项测试:1 项检查 JSON 写法和数据范围,另外 8 项分别对应 8 个待检查程序。提交前应当看到 9 项全部通过。GitLab CI 和正式评分使用相同的检查内容。

提交方式

  1. 在课程分配的私有 GitLab 仓库中,只修改并提交 submission/cases.json
  2. 推送后查看 GitLab 的 CI 页面(它会自动运行检查器和测试),确认检查器显示 8/8 且测试通过;
  3. 在网络学堂作业中上传一个或多个脱敏后的 Agent Session JSON,文件命名见环境配置
  4. 在网络学堂作业的正文输入框中填写最终推送到 GitLab 的 commit 哈希。不要把 Session、Token、API Key 或 .env 提交到 Git 仓库。

推送到 GitLab 后的自动检查只用于及时反馈。正式评分仍会把你的 JSON 放进助教保存的原始项目中运行,避免其他文件的修改影响结果。

评分

项目 分值
测试数据能找出 8 个程序的问题(每个 0.25) 2.0
Session 文件和 commit 信息完整 0.5
合计 2.5

8 个程序分别计分。没有全部找出时,已经成功触发的问题仍然得分。