package web import ( "io/fs" "strings" "testing" ) // funcBody 从 marker 起按大括号配平取出一段函数体(含 marker)。 // 这几段代码里的字符串字面量都不含大括号,直接数括号是安全的。 func funcBody(src, marker string) string { i := strings.Index(src, marker) if i < 0 { return "" } j := strings.Index(src[i:], "{") if j < 0 { return "" } depth := 0 for k := i + j; k < len(src); k++ { switch src[k] { case '{': depth++ case '}': depth-- if depth == 0 { return src[i : k+1] } } } return "" } // TestMapLayersDropStaleResponses 守住「开关关着图层还在画」这个竞态。 // // 勾选 → 请求发出 → 用户立刻取消 → 请求回包。回包若直接 addTo(map),图层就画上去了。 // 修法是给每次调用发一个序号,回包时对不上就作废;关键是**序号必须在 `if (!on) return;` // 之前就递增**,否则取消时压根不会作废在途的那次请求。 // // 判据放在源码文本上:这是「两个异步分支的相对顺序」,用 CDP 造这个时序既慢又脆。 func TestMapLayersDropStaleResponses(t *testing.T) { js, err := staticFS.ReadFile("static/js/rond-map.js") if err != nil { t.Fatalf("读取 rond-map.js 失败: %v", err) } src := string(js) for _, c := range []struct{ setter, seq, draw string }{ {"window.rondMap.setGpx = function (on)", "gpxSeq", "addTo(map)"}, {"window.rondMap.setHeat = function (on)", "heatSeq", "addTo(map)"}, {"window.rondMap.setCityAgg = function (on)", "citySeq", "addTo(map)"}, } { body := funcBody(src, c.setter) if body == "" { t.Fatalf("在 rond-map.js 里找不到 %s 的函数体(写法变了,这条守卫就失效了)", c.setter) } inc := strings.Index(body, "++"+c.seq) off := strings.Index(body, "if (!on) return;") guard := strings.Index(body, "seq !== "+c.seq) draw := strings.Index(body, c.draw) if inc < 0 || off < 0 || inc > off { t.Errorf("%s:必须在 `if (!on) return;` 之前先递增序号(否则取消时作废不了在途回包)", c.setter) } if guard < 0 || draw < 0 || guard > draw { t.Errorf("%s:回包在 %s 之前没有做 `seq !== %s` 作废检查", c.setter, c.draw, c.seq) } } // 行程轨迹开关在模板里(map.html),症状一样:取消勾选后旧回包把轨迹画回来。 html, err := fs.ReadFile(tmplFS, "templates/map.html") if err != nil { t.Fatalf("读取 map.html 失败: %v", err) } body := funcBody(string(html), "function refreshTrack()") if body == "" { t.Fatal("在 map.html 里找不到 refreshTrack(写法变了,这条守卫就失效了)") } inc := strings.Index(body, "++trackSeq") off := strings.Index(body, "if (!trackOn)") guard := strings.Index(body, "seq !== trackSeq") draw := strings.Index(body, "setTrack(d.segs") if inc < 0 || off < 0 || inc > off { t.Error("refreshTrack:必须在 `if (!trackOn)` 之前先递增序号") } if guard < 0 || draw < 0 || guard > draw { t.Error("refreshTrack:回包在 setTrack(d.segs…) 之前没有做 `seq !== trackSeq` 作废检查") } }