仰望星辰工作室

gitcat

gitcat/ internal/gitx/gitx_test.go 4.5 KB · 153 行 原始文件
1package gitx
2
3import (
4 "context"
5 "errors"
6 "os"
7 "path/filepath"
8 "strings"
9 "testing"
10 "time"
11)
12
13func TestValidRef(t *testing.T) {
14 ok := []string{"main", "v1.2.3", "feature/login", "refs/heads/x", "HEAD",
15 "a1b2c3d", "release-2024", "_underscore"}
16 for _, r := range ok {
17 if !ValidRef(r) {
18 t.Errorf("%q 应为合法 ref", r)
19 }
20 }
21 bad := []string{"", "-x", "--upload-pack=evil", "a b", "a..b", "a~1",
22 "a^", "a:b", "a?b", "a*b", "a[b", `a\b`, "a@{0}", "!bang", "a\nb",
23 strings.Repeat("x", 256)}
24 for _, r := range bad {
25 if ValidRef(r) {
26 t.Errorf("%q 应被判为非法 ref", r)
27 }
28 }
29}
30
31func TestValidRepoName(t *testing.T) {
32 for _, n := range []string{"demo", "a", "my-project", "a.b_c", "Repo123"} {
33 if !ValidRepoName(n) {
34 t.Errorf("%q 应为合法仓库名", n)
35 }
36 }
37 for _, n := range []string{"", ".hidden", "-lead", "a/b", `a\b`, "..",
38 "a..b", "x.git", "X.GIT", "a b", strings.Repeat("x", 65)} {
39 if ValidRepoName(n) {
40 t.Errorf("%q 应为非法仓库名", n)
41 }
42 }
43}
44
45func TestCommandTimeoutIsApplied(t *testing.T) {
46 old := commandTimeout()
47 SetCommandTimeout(150 * time.Millisecond)
48 defer SetCommandTimeout(old)
49
50 dir := t.TempDir()
51 if err := InitBare(dir, "main"); err != nil {
52 t.Fatalf("InitBare 失败: %v", err)
53 }
54 // 不存在的对象上跑 log,正常会立刻返回;这里主要验证超时机制
55 // 不会让 run 退化成无超时。
56 start := time.Now()
57 _, _ = Log(filepath.Join(dir, "missing.git"), "HEAD", 5, 0)
58 if d := time.Since(start); d > 5*time.Second {
59 t.Errorf("命令耗时 %v,明显超出预期", d)
60 }
61}
62
63func TestRunLimitRejectsOversizedOutput(t *testing.T) {
64 dir := t.TempDir()
65 if err := InitBare(dir, "main"); err != nil {
66 t.Fatalf("InitBare 失败: %v", err)
67 }
68 // 造一个 1MB 的文件
69 big := strings.Repeat("A", 1<<20)
70 blob := runStdin(t, dir, big, "hash-object", "-w", "--stdin")
71 tree := runStdin(t, dir, "100644 blob "+blob+"\tlarge.txt\n", "mktree")
72 commit := runStdin(t, dir, "", "commit-tree", tree, "-m", "big")
73 _, _ = run(dir, "update-ref", "refs/heads/main", commit)
74
75 if n, err := LineCount(dir, "main", "large.txt"); err != nil || n != 1 {
76 t.Errorf("单行 1MB 文件的行数 = %d (err=%v),期望 1", n, err)
77 }
78 if _, err := BlobLimited(dir, "main", "large.txt", 1024); !errors.Is(err, ErrTooLarge) {
79 t.Errorf("超出上限应返回 ErrTooLarge,实际 %v", err)
80 }
81 if b, err := BlobLimited(dir, "main", "large.txt", 2<<20); err != nil || len(b) != 1<<20 {
82 t.Errorf("未超限时读取失败: len=%d err=%v", len(b), err)
83 }
84}
85
86// TestLineCountNoDeadlock 回归:scanner 提前放弃时若不关闭读端,
87// cmd.Wait 会一直等到命令超时(曾表现为单次请求 60 秒)。
88func TestLineCountNoDeadlock(t *testing.T) {
89 dir := t.TempDir()
90 if err := InitBare(dir, "main"); err != nil {
91 t.Fatalf("InitBare 失败: %v", err)
92 }
93 // 无换行的 3MB 内容:scanner 会因超长行中止
94 huge := strings.Repeat("A", 3<<20)
95 blob := runStdin(t, dir, huge, "hash-object", "-w", "--stdin")
96 tree := runStdin(t, dir, "100644 blob "+blob+"\thuge.txt\n", "mktree")
97 commit := runStdin(t, dir, "", "commit-tree", tree, "-m", "huge")
98 _, _ = run(dir, "update-ref", "refs/heads/main", commit)
99
100 done := make(chan struct{})
101 go func() {
102 _, _ = LineCount(dir, "main", "huge.txt")
103 close(done)
104 }()
105 select {
106 case <-done:
107 case <-time.After(10 * time.Second):
108 t.Fatal("LineCount 卡死(读端未关闭)")
109 }
110}
111
112func TestIsBinary(t *testing.T) {
113 if !IsBinary([]byte("abc\x00def")) {
114 t.Error("含 NUL 应判为二进制")
115 }
116 if IsBinary([]byte("普通文本内容")) {
117 t.Error("纯文本不应判为二进制")
118 }
119}
120
121func TestIsBareRepo(t *testing.T) {
122 dir := filepath.Join(t.TempDir(), "r.git")
123 if IsBareRepo(dir) {
124 t.Error("不存在的目录不应被识别为裸仓库")
125 }
126 if err := InitBare(dir, "main"); err != nil {
127 t.Fatalf("InitBare 失败: %v", err)
128 }
129 if !IsBareRepo(dir) {
130 t.Error("初始化后应被识别为裸仓库")
131 }
132 if _, err := os.Stat(filepath.Join(dir, "HEAD")); err != nil {
133 t.Errorf("缺少 HEAD: %v", err)
134 }
135}
136
137func TestSetDefaultBranchRejectsBadRef(t *testing.T) {
138 dir := t.TempDir()
139 if err := InitBare(dir, "main"); err != nil {
140 t.Fatalf("InitBare 失败: %v", err)
141 }
142 if err := SetDefaultBranch(dir, "--upload-pack=evil"); err == nil {
143 t.Error("非法分支名应被拒绝")
144 }
145 if err := SetDefaultBranch(dir, "dev"); err != nil {
146 t.Errorf("合法分支名被拒: %v", err)
147 }
148 if got := CurrentBranch(dir); got != "dev" {
149 t.Errorf("当前分支 = %q,期望 dev", got)
150 }
151}
152
153var _ = context.Background