diff options
Diffstat (limited to 'gitignore_test.go')
| -rw-r--r-- | gitignore_test.go | 220 |
1 files changed, 220 insertions, 0 deletions
diff --git a/gitignore_test.go b/gitignore_test.go new file mode 100644 index 0000000..db9f25b --- /dev/null +++ b/gitignore_test.go @@ -0,0 +1,220 @@ +package main + +import ( + "testing" + + ignore "github.com/sabhiram/go-gitignore" +) + +func TestGitignore_SimplePatterns(t *testing.T) { + tests := []struct { + name string + patterns []string + path string + expected bool + }{ + {"exact file", []string{"foo.txt"}, "foo.txt", true}, + {"exact file no match", []string{"foo.txt"}, "bar.txt", false}, + {"wildcard extension", []string{"*.log"}, "debug.log", true}, + {"wildcard no match", []string{"*.log"}, "debug.txt", false}, + {"directory pattern with content", []string{"build/"}, "build/output.o", true}, + {"leading slash anchored", []string{"/foo"}, "foo", true}, + {"leading slash anchored no match", []string{"/foo"}, "bar/foo", false}, + {"comment line ignored", []string{"# this is a comment"}, "foo", false}, + {"empty line ignored", []string{""}, "foo", false}, + } + + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + gi := ignore.CompileIgnoreLines(tt.patterns...) + result := gi.MatchesPath(tt.path) + if result != tt.expected { + t.Errorf("MatchesPath(%q) = %v, want %v", tt.path, result, tt.expected) + } + }) + } +} + +func TestGitignore_Negation(t *testing.T) { + gi := ignore.CompileIgnoreLines("*.log", "!important.log") + + tests := []struct { + path string + expected bool + }{ + {"debug.log", true}, + {"important.log", false}, + {"test.log", true}, + {"readme.txt", false}, + } + + for _, tt := range tests { + t.Run(tt.path, func(t *testing.T) { + result := gi.MatchesPath(tt.path) + if result != tt.expected { + t.Errorf("MatchesPath(%q) = %v, want %v", tt.path, result, tt.expected) + } + }) + } +} + +func TestGitignore_DoubleStar(t *testing.T) { + tests := []struct { + name string + patterns []string + path string + expected bool + }{ + {"double star prefix", []string{"**/temp"}, "temp", true}, + {"double star prefix nested", []string{"**/temp"}, "foo/temp", true}, + {"double star prefix deep nested", []string{"**/temp"}, "foo/bar/baz/temp", true}, + {"double star suffix", []string{"temp/**"}, "temp/file.txt", true}, + {"double star suffix deep", []string{"temp/**"}, "temp/sub/file.txt", true}, + {"double star middle", []string{"foo/**/bar"}, "foo/bar", true}, + {"double star middle nested", []string{"foo/**/bar"}, "foo/x/y/bar", true}, + } + + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + gi := ignore.CompileIgnoreLines(tt.patterns...) + result := gi.MatchesPath(tt.path) + if result != tt.expected { + t.Errorf("MatchesPath(%q) = %v, want %v", tt.path, result, tt.expected) + } + }) + } +} + +func TestGitignore_QuestionMark(t *testing.T) { + // NOTE: go-gitignore does not support ? wildcard + // This test documents the limitation + gi := ignore.CompileIgnoreLines("?.txt") + + result := gi.MatchesPath("a.txt") + if result { + t.Log("go-gitignore now supports ? wildcard - update docs") + } else { + t.Log("go-gitignore does NOT support ? wildcard - known limitation") + } +} + +func TestGitignore_BracketRange(t *testing.T) { + gi := ignore.CompileIgnoreLines("[abc].txt") + + tests := []struct { + path string + expected bool + }{ + {"a.txt", true}, + {"b.txt", true}, + {"c.txt", true}, + {"d.txt", false}, + } + + for _, tt := range tests { + t.Run(tt.path, func(t *testing.T) { + result := gi.MatchesPath(tt.path) + if result != tt.expected { + t.Errorf("MatchesPath(%q) = %v, want %v", tt.path, result, tt.expected) + } + }) + } +} + +func TestGitignore_NestedGitignore(t *testing.T) { + rules := map[string][]string{ + ".gitignore": {"*.log"}, + "subdir/.gitignore": {"*.tmp"}, + "subdir/deep/.gitignore": {"*.bak"}, + } + + gi := ignore.CompileIgnoreLines(rules[".gitignore"]...) + + tests := []struct { + name string + path string + expected bool + }{ + {"root log", "debug.log", true}, + {"root txt", "readme.txt", false}, + } + + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + result := gi.MatchesPath(tt.path) + if result != tt.expected { + t.Errorf("MatchesPath(%q) = %v, want %v", tt.path, result, tt.expected) + } + }) + } + + // Nested gitignore needs separate handling per directory + subGi := ignore.CompileIgnoreLines(rules["subdir/.gitignore"]...) + if subGi.MatchesPath("file.tmp") != true { + t.Error("subdir gitignore should match *.tmp") + } +} + +func TestGitignore_CombinedPatterns(t *testing.T) { + gi := ignore.CompileIgnoreLines( + "*.o", + "*.a", + "build/", + "!lib/special.o", + ) + + tests := []struct { + path string + expected bool + }{ + {"foo.o", true}, + {"lib.a", true}, + {"build/output.o", true}, + {"lib/special.o", false}, + {"src/main.c", false}, + } + + for _, tt := range tests { + t.Run(tt.path, func(t *testing.T) { + result := gi.MatchesPath(tt.path) + if result != tt.expected { + t.Errorf("MatchesPath(%q) = %v, want %v", tt.path, result, tt.expected) + } + }) + } +} + +func TestGitignore_HashInFilename(t *testing.T) { + gi := ignore.CompileIgnoreLines("*.txt") + + tests := []struct { + path string + expected bool + }{ + {"file#1.txt", true}, + {"file#2.txt", true}, + {"readme.md", false}, + } + + for _, tt := range tests { + t.Run(tt.path, func(t *testing.T) { + result := gi.MatchesPath(tt.path) + if result != tt.expected { + t.Errorf("MatchesPath(%q) = %v, want %v", tt.path, result, tt.expected) + } + }) + } +} + +func TestGitignore_TrailingSpace(t *testing.T) { + // NOTE: go-gitignore does not handle trailing spaces in patterns + // This test documents the limitation + gi := ignore.CompileIgnoreLines("foo.txt ") + + result := gi.MatchesPath("foo.txt") + if result { + t.Log("go-gitignore handles trailing spaces correctly") + } else { + t.Log("go-gitignore does NOT handle trailing spaces - known limitation") + } +} |
