From f2ce6646c4cbe9ed100d50d0ae59b627df85a97e Mon Sep 17 00:00:00 2001 From: tamakyi Date: Thu, 24 Sep 2026 22:48:32 +0800 Subject: [PATCH] =?UTF-8?q?=E6=8A=A5=E5=91=8A=EF=BC=9A=E8=A1=A5=20P2=20?= =?UTF-8?q?=E6=89=B9=E6=AC=A1=EF=BC=88=E8=A6=86=E7=9B=96=E7=8E=87=E5=8F=A3?= =?UTF-8?q?=E5=BE=84=E4=B8=8E=E5=85=B3=E9=94=AE=E9=A1=B5=E5=86=92=E7=83=9F?= =?UTF-8?q?=EF=BC=89=E8=AE=B0=E5=BD=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- audit-2026-09-21.md | 104 ++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 104 insertions(+) diff --git a/audit-2026-09-21.md b/audit-2026-09-21.md index de46639..02907b4 100644 --- a/audit-2026-09-21.md +++ b/audit-2026-09-21.md @@ -1076,3 +1076,107 @@ go test -count=1 -v ./... + +--- + +# 修复记录(第十二批 · P2:覆盖率口径与关键页冒烟) + +## 一、先纠正一个测量错误:`rond` 不是 38.8% + +看到「`rond` 只有 38.8%」本来准备补测试,取证后发现**数字是量错了**: + +`go test -cover` 只统计**测试文件所在那个包**自己的执行。而 `internal/rond` 一半的代码 +(`export.go` 1416 行)由 `internal/web` 的 `TestMovementCleanExport` 驱动;`geo`/`gpx`/ +`notes`/`votes` 同理由 `web`/`stats` 驱动。按 `-cover` 量,这些包一律报 0%。 + +| 包 | `-cover`(假口径) | `-coverpkg=./internal/...`(真) | +|---|---|---| +| `internal/rond` | 38.8% | **82.2%** | +| `internal/geo` | 0% | **92.9%** | +| `internal/stats` | 62.2% | **83.7%** | +| `internal/web` | 53.2% | 53.2%(它自己不假) | + +⇒ `verify.sh --cover` 改用 `-coverpkg=./internal/...`,并按包打印。**项目合计 62.3%**。 + +解析 profile 时有个坑:`-coverpkg` 下每个测试二进制都会给同一段代码写一条记录, +同一个 `(文件,行段)` 会出现多条(一条 `count=0`、一条 `count>0`)。**必须按块取 max**; +直接求和等于把语句数乘上二进制份数,每包都会显示成只有 `1/N`(第一版 awk 就这么错的, +`web` 印成 4.4%)。 + +## 二、真去补的时候,只补「线上会走到」的 + +把未覆盖行段拉出来逐条看,绝大部分是 `nil` 分支和 `if err != nil { return err }`——补那些是灌水。 +真正「线上会走到、却一条用例都没有」的只有两处: + +**① `BuildMergePlan` 的地点/活动冲突**(`placePick`/`activityPick` 长期 0%)。差异页线上确实会提交 +这两类选择,而用例只造过「新增」。补 `merge_clash_test.go`(冲突 + 删除逐条勾选)后 +`merge.go` 64.3% → **96.4%**。 +变异验证:把地点判据从 `PickBackup` 改成 `PickDB` ⇒ 红在「只有选了『用实机』的地点该更新」; +把活动键从 `activityKey(cf.DB)` 改成 `cf.DB.Name` ⇒ 红在「有 UUID 的活动应按 UUID 对上」。 + +**② `internal/gpx` 整包零测试**(61 条语句,0/61)。它解析的是**用户上传的 XML**, +正是最该有测试的地方。补 `gpx_test.go` 8 条:`trk`/`rte` 两条分支、track 名退回 `metadata>name`、 +`(0,0)` 空点丢弃、单点轨迹丢弃并报错、非法 XML、没有轨迹点、时间格式错不致命、里程数值。 +⇒ **0% → 96.0%**。 +变异验证:`(0,0)` 跳过改成 `if false` ⇒ 红在「该被丢掉,实际剩 3 个点」; +地球半径 6371→6300 ⇒ 红在「1 度纬度该约 111.19 km」。 + +## 三、顺手清掉两处死代码 + +两者都做过全仓核查(含模板——Go 模板能调方法,`{{.Total}}` 这种不能只搜 `.go`): + +| 死代码 | 核查结果 | +|---|---| +| `rond.Counts.Total()` | 零引用。模板里的 `.Total` 都是各页 view 结构体自己的字段。 | +| `gpx.Track.BBox()` | 零引用。`handlers_topics.go` 里的 `fitBBox` 是无关变量,`gpx.Track` 从未传进模板。 | + +**没有为它们写测试**——为了把 0% 填成 100% 而给死代码补用例,只会把死代码固化下来。 + +## 四、一条「实测否证」的记录 + +`geo.Haversine` 用 `math.Asin(math.Min(1, math.Sqrt(a)))` 夹了一道,`gpx` 那份没有, +SQL 里(`handlers_topics.go`)也没有。三条公式、两个半径(6371.0 / 6371.0088)。 + +本来准备按「缺夹子会出 NaN」去修,**实测不成立**:对跖点附近 `h` 最多到 `1+2^-52` +((45,0)→(-45,180) 就是这个值),而 `math.Sqrt(1+2^-52)` 会回舍成正好 `1.0`, +`asin(1.0)=π/2`,出不了 NaN。所以**没改代码**,只留一条 `TestLengthKmAntipodalIsFinite` +把「对跖点不出 NaN」钉住(将来换公式或去掉开方会立刻红),并在注释里写明这是实测结论。 + +半径差 6371.0 vs 6371.0088 的数值影响:146 km 上差 **0.20 米**,纯属口径不统一,不影响功能。 + +## 五、关键页冒烟:`scripts/smoke.py` + +Go 侧模板守卫只能证明「模板里有那段文字」。白屏、JS 抛错、内容区块被压成 0 高, +**模板测试全是绿的**。冒烟按三种口径各走一遍(16 页): + +1. **站长(浏览器)**:HTTP 200 + 落点路径没跳走 + 内容区块在且尺寸非 0 + 零 JS 报错 +2. **访客(纯 HTTP)**:公开页 200;后台页必须 **303 跳登录**(绝不能 200)——`urllib` 不跟随跳转即可, + 比开 Chrome 快一个数量级 +3. **访客(浏览器)抽检** `/` 与地点详情:只在访客侧复现的 bug 藏在这里 + +接进 `verify.sh --smoke`(只跑冒烟)/ `--all`(全量 + 冒烟)。 + +三条实测踩出来的坑: + +- **关键区块不能取 `nav.nav`**:它在 `layout.html` 里,内容块整个没渲染它照样在,等于没断言。 + 改成地图页取地图容器、其余取首个 `.card`(`#home-map` / `#map` / `#place-map` / `#taxonomy`)。 +- **用 `.card` 而不是 `div.card`**:专题列表的卡片是 ``, + 写 `div.card` 一个都选不中——而 `querySelector` 返回 null 时尺寸也是 0,打印出来跟 + 「元素被压成 0 宽」一模一样。第一版就据此差点去查布局 bug。日志已把两者分开印。 +- **`--min-body` 只是兜「整页空白」**:专题列表正文天生 166 字(就一个专题卡片),阈值定 200 会假红。 + 另外「公开页面」是受总开关控制的,冒烟先探测 `/places` 的访客状态码再决定同类页的期望值。 + +**变异验证**:往 `timeline.html` 塞一句 `` +(`debug=true` 下模板热加载,不用重启)⇒ 冒烟立刻红在「JS 报错」上,且**状态码、内容区尺寸全都正常** +——正好说明没有这条断言就会放过它。验完已还原(`git status` 无该文件)。 + +## 六、收尾验收 + +``` +./scripts/verify.sh # 284 个顶层用例(含子测试更多)/ 0 FAIL / 0 SKIP +./scripts/verify.sh --all # 全量 + 冒烟 16 页全绿 +./scripts/verify.sh --cover # 按包覆盖率 + 项目合计 62.3% +./scripts/verify.sh --fast # gofmt / vet / build 干净 +``` + +`--fast` / `--smoke` / `--cover` / `--all` / 未知参数 → exit 2 的门都实测过。