Migration This is my new public git source viewer. Source coming soon. Please contact with concerns/bugs. Contact me

internal/modules/blob_test.go

8d1bb5bfdd2cba82488775b46308efed740132a8 · 3.4 KB · 121 lines raw

1 package modules
2
3 import (
4 "fmt"
5 "os"
6 "os/exec"
7 "path/filepath"
8 "strings"
9 "testing"
10
11 "gsg/internal/core"
12 "gsg/internal/gitx"
13 )
14
15 // blobCtx commits files into a throwaway repository and returns a Ctx
16 // pointing at it. Isolation matches internal/gitx's own test helper, so a
17 // machine with commit.gpgsign=true globally behaves like CI.
18 func blobCtx(t *testing.T, files map[string]string) *core.Ctx {
19 t.Helper()
20 dir := t.TempDir()
21 env := []string{
22 "PATH=" + os.Getenv("PATH"),
23 "HOME=" + dir,
24 "GIT_CONFIG_NOSYSTEM=1",
25 "GIT_AUTHOR_NAME=test", "GIT_AUTHOR_EMAIL=test@example.com",
26 "GIT_COMMITTER_NAME=test", "GIT_COMMITTER_EMAIL=test@example.com",
27 }
28 git := func(args ...string) {
29 t.Helper()
30 cmd := exec.Command("git", append([]string{"-C", dir, "-c", "commit.gpgsign=false"}, args...)...)
31 cmd.Env = env
32 if out, err := cmd.CombinedOutput(); err != nil {
33 t.Fatalf("git %v: %v\n%s", args, err, out)
34 }
35 }
36 git("init", "-q", ".")
37 for name, body := range files {
38 if err := os.WriteFile(filepath.Join(dir, name), []byte(body), 0o644); err != nil {
39 t.Fatal(err)
40 }
41 }
42 git("add", "-A")
43 git("commit", "-qm", "fixture")
44
45 repo, err := gitx.Open(dir)
46 if err != nil {
47 t.Fatal(err)
48 }
49 sha, err := repo.Resolve("HEAD")
50 if err != nil {
51 t.Fatal(err)
52 }
53 return &core.Ctx{Repo: repo, Ref: "HEAD", Commit: sha}
54 }
55
56 func blobAt(t *testing.T, c *core.Ctx, path string) Blob {
57 t.Helper()
58 c.Path = path
59 v, err := blobMod(c)
60 if err != nil {
61 t.Fatalf("blob %q: %v", path, err)
62 }
63 b, ok := v.(Blob)
64 if !ok {
65 t.Fatalf("blob %q: got %T", path, v)
66 }
67 return b
68 }
69
70 // Past maxStructuredSize a config file is served as plain numbered lines:
71 // no parse, no fold ranges, no anchor resolution -- and Oversize set so the
72 // view can say why rather than silently dropping the tooling.
73 func TestStructuredSizeGate(t *testing.T) {
74 var big strings.Builder
75 big.WriteString("items: &items\n")
76 for i := 0; big.Len() <= maxStructuredSize; i++ {
77 fmt.Fprintf(&big, " - name: item-%d\n value: %d\n", i, i)
78 }
79 small := "items: &items\n - name: a\ncopy: *items\n"
80
81 c := blobCtx(t, map[string]string{"big.yaml": big.String(), "small.yaml": small})
82
83 b := blobAt(t, c, "big.yaml")
84 if b.Lang != "yaml" {
85 t.Errorf("Lang = %q, want yaml", b.Lang)
86 }
87 if !b.Oversize || b.Structured() {
88 t.Errorf("Oversize = %v, Structured = %v; want true, false", b.Oversize, b.Structured())
89 }
90 if b.ParseErr != nil {
91 t.Errorf("oversize file was parsed anyway: %+v", b.ParseErr)
92 }
93 if len(b.Lines) == 0 {
94 t.Fatal("oversize file rendered no lines")
95 }
96 for _, l := range b.Lines {
97 if l.FoldTo != 0 || l.Depth != 0 || l.Key != "" || l.Anchor != nil || l.Ref != nil {
98 t.Fatalf("line %d carries structure past the size limit: %+v", l.N, l)
99 }
100 }
101
102 s := blobAt(t, c, "small.yaml")
103 if !s.Structured() || s.Oversize {
104 t.Fatalf("small file: Structured = %v, Oversize = %v", s.Structured(), s.Oversize)
105 }
106 if s.Lines[0].Anchor == nil || s.Lines[2].Ref == nil {
107 t.Error("small file lost its anchor/alias annotations")
108 }
109 if s.Lines[0].FoldTo != 2 {
110 t.Errorf("small file FoldTo = %d, want 2", s.Lines[0].FoldTo)
111 }
112 }
113
114 // A non-config file is never structured, whatever its size.
115 func TestPlainFileIsNotStructured(t *testing.T) {
116 c := blobCtx(t, map[string]string{"main.go": "package main\n\nfunc main() {}\n"})
117 b := blobAt(t, c, "main.go")
118 if b.Structured() || b.Oversize || b.Lang != "" {
119 t.Errorf("go file: Lang = %q, Structured = %v, Oversize = %v", b.Lang, b.Structured(), b.Oversize)
120 }
121 }