test(goauto): pin SYB filter behaviour against real variationSku samples #269

The samples are the ones the production database actually holds: 档口 codes
like "新寮-雅伊阁大码女装#301" and "DD#004" must be filtered, while own
codes like "PDD0582", "my238", "1" and "引流款" must not, and an empty
variationSku is a product without a supplier code rather than a 档口 item.

The test also asserts the two structural rules record different hit counts.
That is the property the previous aggregate-per-kind write could not hold,
and the disable-confirmation dialog depends on it.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01NTDbDcwbDw1TSAcE6wfh2F
This commit is contained in:
QiuSW
2026-09-11 16:37:43 +08:00
co-authored by Claude Opus 5
parent 20f59b68bd
commit 78df997fc3
@@ -0,0 +1,84 @@
package sybproductfilter
import (
"context"
"testing"
"time"
)
// 用线上真实取到的 variationSku 样本,验证过滤判定与每条规则各自计数。
func TestRealWorldSamplesPerRuleCounting(t *testing.T) {
db := testDB(t)
ctx := context.Background()
set, err := LoadEnabled(ctx, db)
if err != nil {
t.Fatal(err)
}
samples := []struct {
v string
wantKind string // "" = 不过滤
}{
{"新寮-雅伊阁大码女装#301", "char"},
{"广达-爆款大码女装#9018", "char"},
{"DD#004", "char"},
{"300斤牛奶絲圓領#A057", "char"},
{"上寮-琪琪尚雅网批#2604##(&15)", "char"},
{"PDD0582", ""},
{"my238", ""},
{"le171", ""},
{"1", ""},
{"引流款", ""},
{"", ""},
}
hits := HitCounter{}
var charN, kwN, keptN int
for _, s := range samples {
rule := set.Match(s.v)
if s.wantKind == "" {
if rule != nil {
t.Fatalf("%q 不应被过滤,却命中了 %q", s.v, rule.Keyword)
}
keptN++
continue
}
if rule == nil || rule.Kind != s.wantKind {
t.Fatalf("%q 应命中 %s 规则,实际 %v", s.v, s.wantKind, rule)
}
hits.Add(rule)
if rule.Kind == "char" {
charN++
} else {
kwN++
}
}
if charN != 5 || kwN != 0 || keptN != 6 {
t.Fatalf("统计不符:char=%d keyword=%d kept=%d", charN, kwN, keptN)
}
if err := UpdateHits(ctx, db, set, hits, time.Now().UTC()); err != nil {
t.Fatal(err)
}
after, err := LoadEnabled(ctx, db)
if err != nil {
t.Fatal(err)
}
got := map[string]int{}
for _, x := range after.Chars {
if x.LastHitCount == nil {
t.Fatalf("规则 %q 必须被写入命中数", x.Keyword)
}
got[x.Keyword] = *x.LastHitCount
}
// "#" 命中 4 条(301/9018/DD#004/A057 ... 其中带 - 的先被 "-" 规则接走)
if got["-"]+got["#"] != 5 {
t.Fatalf("两条结构规则命中数之和应为 5,实际 - =%d # =%d", got["-"], got["#"])
}
if got["-"] == got["#"] {
t.Fatalf("两条规则不应记成同一个数(这正是 #269 修的 bug): - =%d # =%d", got["-"], got["#"])
}
for _, x := range after.Keywords {
if x.LastHitCount == nil || *x.LastHitCount != 0 {
t.Fatalf("未命中的关键词 %q 应记 0,实际 %v", x.Keyword, x.LastHitCount)
}
}
t.Logf("结构规则命中:- =%d # =%d", got["-"], got["#"])
}