|
| 1 | +package codegraph |
| 2 | + |
| 3 | +import ( |
| 4 | + "os" |
| 5 | + "path/filepath" |
| 6 | + "strings" |
| 7 | + "testing" |
| 8 | +) |
| 9 | + |
| 10 | +// issue #140:自动生成的源码(EF Core 模型快照、protoc / go generate 产物等)按头部标记跳过, |
| 11 | +// 不喂给 tree-sitter、不进图谱 —— 避免大型 .NET 仓把子进程顶过内存上限(exit 75)。 |
| 12 | +func TestIsGeneratedSource(t *testing.T) { |
| 13 | + gen := []string{ |
| 14 | + "// <auto-generated />\npublic class Foo {}\n", // EF Core / .NET |
| 15 | + "// <auto-generated>\n// 由工具生成\n// </auto-generated>\nclass F{}", // 带换行的 .NET 头 |
| 16 | + "// Code generated by protoc-gen-go. DO NOT EDIT.\npackage pb\n", // Go / protoc |
| 17 | + "/* @generated */\nexport const x = 1\n", // @generated 约定 |
| 18 | + } |
| 19 | + for _, s := range gen { |
| 20 | + if !isGeneratedSource([]byte(s)) { |
| 21 | + t.Errorf("应判定为生成文件:\n%s", s) |
| 22 | + } |
| 23 | + } |
| 24 | + normal := []string{ |
| 25 | + "package x\n\nfunc RealFunc() {}\n", |
| 26 | + "public class Service {\n // do not edit lightly, but hand-written\n", // 注:不含 DO NOT EDIT 全大写连写 |
| 27 | + "", |
| 28 | + } |
| 29 | + for _, s := range normal { |
| 30 | + if isGeneratedSource([]byte(s)) { |
| 31 | + t.Errorf("正常源码不该判定为生成文件:\n%q", s) |
| 32 | + } |
| 33 | + } |
| 34 | + |
| 35 | + // 标记在 1KB 头部之外 → 不判定(只扫头部,省时且避免误伤正文里偶然出现的字样)。 |
| 36 | + deep := strings.Repeat("x\n", 2000) + "// <auto-generated />\n" |
| 37 | + if isGeneratedSource([]byte(deep)) { |
| 38 | + t.Error("超出头部扫描窗口的标记不应触发判定") |
| 39 | + } |
| 40 | +} |
| 41 | + |
| 42 | +// TestMigrationsDirSkipped:`Migrations/` 目录(EF Core / Django 约定)整体跳过。 |
| 43 | +func TestMigrationsDirSkipped(t *testing.T) { |
| 44 | + for _, n := range []string{"migrations", "Migrations", "MIGRATIONS"} { |
| 45 | + if !shouldSkipDir(n) { |
| 46 | + t.Errorf("%q 应被跳过", n) |
| 47 | + } |
| 48 | + } |
| 49 | +} |
| 50 | + |
| 51 | +// TestAssembleSkipsGeneratedAndMigrations:端到端验证收紧后的行为(issue #140): |
| 52 | +// - 手写文件入图; |
| 53 | +// - **大**生成文件跳过(内存元凶 + 低导航价值); |
| 54 | +// - **小**生成文件**保留**(常含被引用的类型定义,且不撑内存); |
| 55 | +// - Migrations 目录整体跳过。 |
| 56 | +func TestAssembleSkipsGeneratedAndMigrations(t *testing.T) { |
| 57 | + root := t.TempDir() |
| 58 | + mk := func(rel, content string) { |
| 59 | + p := filepath.Join(root, rel) |
| 60 | + if err := os.MkdirAll(filepath.Dir(p), 0o755); err != nil { |
| 61 | + t.Fatal(err) |
| 62 | + } |
| 63 | + if err := os.WriteFile(p, []byte(content), 0o644); err != nil { |
| 64 | + t.Fatal(err) |
| 65 | + } |
| 66 | + } |
| 67 | + const genHeader = "// Code generated by tool. DO NOT EDIT.\npackage x\n\n" |
| 68 | + // 大生成文件:头部标记 + ≥128KiB 短注释行填充(不触发超长行)+ 一个符号。 |
| 69 | + pad := strings.Repeat("// padding line to inflate file size\n", 4000) // ~148 KiB |
| 70 | + mk("real.go", "package x\n\nfunc RealFunc() {}\n") // 手写,入图 |
| 71 | + mk("gen_small.go", genHeader+"func GeneratedSmall() {}\n") // 生成但小 → 保留 |
| 72 | + mk("gen_big.go", genHeader+pad+"func GeneratedBig() {}\n") // 生成且大 → 跳过 |
| 73 | + mk("Migrations/mig.go", "package x\n\nfunc MigFunc() {}\n") // Migrations 目录 → 跳过 |
| 74 | + |
| 75 | + ix := &Index{root: root} |
| 76 | + g, _, err := ix.assemble(nil, false) |
| 77 | + if err != nil { |
| 78 | + t.Fatal(err) |
| 79 | + } |
| 80 | + names := map[string]bool{} |
| 81 | + for _, s := range g.Symbols { |
| 82 | + names[s.Name] = true |
| 83 | + } |
| 84 | + if !names["RealFunc"] { |
| 85 | + t.Error("手写文件的 RealFunc 应入图") |
| 86 | + } |
| 87 | + if !names["GeneratedSmall"] { |
| 88 | + t.Error("小生成文件的 GeneratedSmall 应保留入图(收紧后只跳大文件)") |
| 89 | + } |
| 90 | + if names["GeneratedBig"] { |
| 91 | + t.Error("大生成文件的 GeneratedBig 不该入图") |
| 92 | + } |
| 93 | + if names["MigFunc"] { |
| 94 | + t.Error("Migrations 目录的 MigFunc 不该入图") |
| 95 | + } |
| 96 | +} |
0 commit comments