internal/gitutil/endofoptions_test.go

v1.10.0
gitbay/internal/gitutil/endofoptions_test.go history · blame · raw

54 lines · 2530 bytes

 1package gitutil
 2
 3import (
 4	"bytes"
 5	"os"
 6	"path/filepath"
 7	"testing"
 8)
 9
10// A ref reaching gitutil is user input: a URL segment or an argument. Every
11// git invocation ends option parsing before it, so a ref shaped like an
12// option is a bad revision, never a flag (#135). The payload here is an
13// option several subcommands accept, whose effect would be a file.
14func TestRefsAreNotOptions(t *testing.T) {
15	dir := t.TempDir()
16	git(t, dir, "init", "-q", "-b", "main")
17	write(t, dir, "f.txt", "hi\n")
18	git(t, dir, "add", ".")
19	git(t, dir, "commit", "-q", "-m", "base")
20	pwn := filepath.Join(t.TempDir(), "pwned")
21	ref := "--output=" + pwn
22
23	var sink bytes.Buffer
24	calls := map[string]func() error{
25		"CountCommits": func() error { CountCommits(dir, ref); return nil },
26		"Contributors": func() error { Contributors(dir, ref); return nil },
27		"Languages":    func() error { Languages(dir, ref, func(string) string { return "x" }); return nil },
28		"RevList":      func() error { _, err := RevList(dir, ref, 1); return err },
29		"RevListPath":  func() error { _, err := RevListPath(dir, ref, "f.txt", 1); return err },
30		"PeelToCommit": func() error { _, err := PeelToCommit(dir, ref); return err },
31		"ReadCommit":   func() error { _, err := ReadCommit(dir, ref); return err },
32		"ListTree":     func() error { _, err := ListTree(dir, ref, ""); return err },
33		"ReadBlob":     func() error { _, err := ReadBlob(dir, ref, "f.txt", 1<<20); return err },
34		"ResolveRef":   func() error { _, err := ResolveRef(dir, ref); return err },
35		"Archive":      func() error { return Archive(dir, ref, "x", &sink) },
36		"Grep":         func() error { _, err := Grep(dir, ref, "hi", 10); return err },
37		"MergeBase":    func() error { _, err := MergeBase(dir, ref, "main"); return err },
38		"Diff":         func() error { _, err := Diff(dir, ref, "main", 1<<20); return err },
39		"DiffFiles":    func() error { _, err := DiffFiles(dir, ref, "main"); return err },
40		"RevListRange": func() error { _, err := RevListRange(dir, "main", ref); return err },
41		"Blame":        func() error { _, err := Blame(dir, ref, "f.txt", 1, 1); return err },
42		"TipCommit":    func() error { TipCommit(dir, ref); return nil },
43		"StatPath":     func() error { StatPath(dir, ref, "f.txt"); return nil },
44	}
45	for name, call := range calls {
46		call()
47		if _, err := os.Stat(pwn); err == nil {
48			t.Fatalf("%s: ref %q was parsed as an option and wrote a file", name, ref)
49		}
50	}
51	if _, err := ResolveRef(dir, ref); err == nil {
52		t.Fatal("option-shaped ref resolved")
53	}
54}