fix(contract): enums 的 MODES 漂移守卫改按目录收集,抗前端类型拆分
CI / Backend (build / vet / test / cross-compile) (push) Has been cancelled
CI / Frontend (tsc + vite build) (push) Has been cancelled

TestModeTableMatchesFrontendModes 原先写死读 frontend/web/src/lib/types.ts;阶段 0 把该
文件拆成 barrel + lib/types/*.ts 后 MODES 住进了 types/chat.ts ⇒ 测试红。

改为读 barrel + 目录下全部 .ts(新增 frontendTypesDir 常量与 readFrontendTypes 辅助):
「MODES 住哪个文件」不再是本测试的耦合点,以后再搬也不用改它;barrel 缺失
(backend-only checkout)仍按 fs.ErrNotExist 跳过。

验证:go test ./internal/contract/enums/ 绿;全树 go test ./... = 58 包 ok / 0 FAIL;
gofmt -l 干净。
This commit is contained in:
AskaEth committed 2026-10-04 10:54:07 +08:00
1 parent 6e0323b446
commit 89434e4f99
1 file changed
+38 -8
+38 -8
View File
@@ -18,6 +18,7 @@ import (
"regexp"
"slices"
"sort"
"strings"
"testing"
"git.yeij.top/AskaEth/Cyrene_v2/internal/contract/enums"
@@ -128,23 +129,52 @@ func TestMoodTableMatchesEmotionBuiltins(t *testing.T) {
}
}
// frontendTypesDir 是前端共享类型的目录:barrel(lib/types.ts)+ 按域拆分的
// lib/types/*.ts(阶段 0 的结构拆分,方案见 DevDocs/audit/_plan.md)。
const frontendTypesDir = "../../../frontend/web/src/lib/types"
// readFrontendTypes 汇总 barrel 与目录下全部 .ts 的源码。按目录收集而不是写死单个文件,
// 是为了让「MODES 数组住在哪个文件」不成为本测试的耦合点——以后再搬一次也不用改它。
// barrel 缺失(backend-only checkout)时返回 fs.ErrNotExist,由调用方跳过。
func readFrontendTypes() ([]byte, error) {
paths := []string{frontendTypesDir + ".ts"}
entries, err := os.ReadDir(frontendTypesDir)
if err != nil && !errors.Is(err, fs.ErrNotExist) {
return nil, err
}
for _, e := range entries {
if !e.IsDir() && strings.HasSuffix(e.Name(), ".ts") {
paths = append(paths, frontendTypesDir+"/"+e.Name())
}
}
var all []byte
for _, p := range paths {
raw, err := os.ReadFile(p)
if err != nil {
return nil, err
}
all = append(all, raw...)
all = append(all, '\n')
}
return all, nil
}
// TestModeTableMatchesFrontendModes asserts the mode table matches the frontend's
// Mode union / MODES array (frontend/web/src/lib/types.ts), the only code-level
// definition of the nine modes. This is the cross-language drift guard: adding a
// mode on either side without the other fails here.
// Mode union / MODES array, the only code-level definition of the nine modes. This
// is the cross-language drift guard: adding a mode on either side without the other
// fails here.
func TestModeTableMatchesFrontendModes(t *testing.T) {
t.Parallel()
const typesPath = "../../../frontend/web/src/lib/types.ts"
raw, err := os.ReadFile(typesPath)
raw, err := readFrontendTypes()
if err != nil {
if errors.Is(err, fs.ErrNotExist) {
t.Skipf("%s not present (backend-only checkout)", typesPath)
t.Skipf("%s not present (backend-only checkout)", frontendTypesDir)
}
t.Fatalf("read %s: %v", typesPath, err)
t.Fatalf("read frontend types: %v", err)
}
block := regexp.MustCompile(`(?s)export const MODES\s*:[^=]*=\s*\[(.*?)\]`).FindSubmatch(raw)
if block == nil {
t.Fatalf("MODES array not found in %s", typesPath)
t.Fatalf("MODES array not found under %s", frontendTypesDir)
}
quoted := regexp.MustCompile(`"([^"]+)"`).FindAllStringSubmatch(string(block[1]), -1)
frontend := make([]string, 0, len(quoted))