// SPDX-License-Identifier: GPL-3.0-or-later package ignore import ( "os" "os/exec" "path/filepath" "sort" "strings" "testing" ) var oracleFiles = []string{ "a.txt", "b.log", "a1.txt", "abc", ".hidden", "foo.part", "keep.part", "dir/c.txt", "dir/d.log", "dir/.hidden2", "dir/sub/e.txt", "build/out.bin", "src/build/x.go", "doc/readme.md", "doc/sub/readme.md", "deep/a/b/c/file.tmp", "x/z.txt", "x/y/z.txt", "sub/f.txt", "space name.txt", "x]y", "xay", "xby", "a/b", "1.txt", "]a.txt", "a.b", "xyz", "aq", "bq", } var oracleSets = [][]string{ {"*.log"}, {"/a.txt"}, {"build/"}, {"doc/*.md"}, {"**/readme.md"}, {"deep/**"}, {"x/**/z.txt"}, {"*.part", "!keep.part"}, {".*"}, {"a?.txt", "[ab]*.txt"}, {"[!a]*.txt"}, {"dir/", "!dir/c.txt"}, {"sub"}, {"space name.txt"}, {"*", "!*.txt"}, {"dir/**/*.txt"}, {"x[]a]y"}, {"a[/]b"}, {"[[:digit:]]*.txt"}, {"[!]a]*"}, {"a[[:punct:]]b"}, {"x[[:alpha:]]z"}, {"[a\\b]q"}, } // TestAgainstGit compares every file and directory of a real tree against // `git check-ignore --no-index` for each pattern set. func TestAgainstGit(t *testing.T) { if _, err := exec.LookPath("git"); err != nil { t.Skip("git not installed") } root := t.TempDir() t.Setenv("HOME", root) t.Setenv("GIT_CONFIG_GLOBAL", os.DevNull) t.Setenv("GIT_CONFIG_NOSYSTEM", "1") for _, f := range oracleFiles { p := filepath.Join(root, f) if err := os.MkdirAll(filepath.Dir(p), 0o755); err != nil { t.Fatal(err) } if err := os.WriteFile(p, nil, 0o644); err != nil { t.Fatal(err) } } if out, err := exec.Command("git", "-C", root, "init", "-q").CombinedOutput(); err != nil { t.Fatalf("git init: %v %s", err, out) } // every path in the tree, files and directories, relative and slash-separated var paths []string isDir := map[string]bool{} filepath.WalkDir(root, func(p string, d os.DirEntry, err error) error { rel, _ := filepath.Rel(root, p) if rel == "." || rel == ".git" || strings.HasPrefix(rel, ".git"+string(filepath.Separator)) || rel == ".gitignore" { if rel == ".git" { return filepath.SkipDir } return nil } rel = filepath.ToSlash(rel) paths = append(paths, rel) isDir[rel] = d.IsDir() return nil }) sort.Strings(paths) for _, set := range oracleSets { if err := os.WriteFile(filepath.Join(root, ".gitignore"), []byte(strings.Join(set, "\n")+"\n"), 0o644); err != nil { t.Fatal(err) } cmd := exec.Command("git", "-C", root, "check-ignore", "--no-index", "--stdin") cmd.Stdin = strings.NewReader(strings.Join(paths, "\n") + "\n") out, _ := cmd.Output() // exit status 1 means "nothing ignored" gitIgnored := map[string]bool{} for _, l := range strings.Split(strings.TrimSpace(string(out)), "\n") { if l != "" { gitIgnored[strings.TrimSuffix(l, "/")] = true } } m, err := New(set) if err != nil { t.Fatalf("New(%q): %v", set, err) } for _, p := range paths { if got := m.Match(p, isDir[p]); got != gitIgnored[p] { t.Errorf("patterns %q, path %q (dir=%v): krino says %v, git says %v", set, p, isDir[p], got, gitIgnored[p]) } } } }