469 lines
9.7 KiB
Go
469 lines
9.7 KiB
Go
package repo
|
|
|
|
import (
|
|
"testing"
|
|
)
|
|
|
|
func TestMatchPattern(t *testing.T) {
|
|
tests := []struct {
|
|
name string
|
|
path string
|
|
pattern string
|
|
want bool
|
|
}{
|
|
{
|
|
name: "exact match",
|
|
path: "README.md",
|
|
pattern: "README.md",
|
|
want: true,
|
|
},
|
|
{
|
|
name: "wildcard match - all md files",
|
|
path: "docs/README.md",
|
|
pattern: "*.md",
|
|
want: true,
|
|
},
|
|
{
|
|
name: "wildcard match - yaml files",
|
|
path: ".gitea/workflows/build.yml",
|
|
pattern: "*.yml",
|
|
want: true,
|
|
},
|
|
{
|
|
name: "directory prefix match",
|
|
path: ".gitea/workflows/build.yml",
|
|
pattern: ".gitea/*",
|
|
want: true,
|
|
},
|
|
{
|
|
name: "recursive directory match",
|
|
path: ".github/workflows/test.yml",
|
|
pattern: ".github/**",
|
|
want: true,
|
|
},
|
|
{
|
|
name: "double star pattern",
|
|
path: "src/components/Button.tsx",
|
|
pattern: "**/*.tsx",
|
|
want: true,
|
|
},
|
|
{
|
|
name: "double star with prefix",
|
|
path: "src/internal/utils/helpers.go",
|
|
pattern: "src/**/*.go",
|
|
want: true,
|
|
},
|
|
{
|
|
name: "no match - wrong extension",
|
|
path: "main.go",
|
|
pattern: "*.md",
|
|
want: false,
|
|
},
|
|
{
|
|
name: "no match - wrong directory",
|
|
path: "docs/readme.md",
|
|
pattern: ".gitea/*",
|
|
want: false,
|
|
},
|
|
{
|
|
name: "negation pattern - exclude",
|
|
path: "node_modules/lodash/index.js",
|
|
pattern: "!node_modules/**",
|
|
want: false,
|
|
},
|
|
{
|
|
name: "negation pattern - include others",
|
|
path: "src/main.js",
|
|
pattern: "!node_modules/**",
|
|
want: true,
|
|
},
|
|
{
|
|
name: "empty pattern matches all",
|
|
path: "any/path/file.txt",
|
|
pattern: "",
|
|
want: true,
|
|
},
|
|
{
|
|
name: "exact directory match",
|
|
path: "src/components",
|
|
pattern: "src",
|
|
want: true,
|
|
},
|
|
{
|
|
name: "file inside directory",
|
|
path: "src/components/Button.tsx",
|
|
pattern: "src",
|
|
want: true,
|
|
},
|
|
}
|
|
|
|
for _, tt := range tests {
|
|
t.Run(tt.name, func(t *testing.T) {
|
|
got := matchPattern(tt.path, tt.pattern)
|
|
if got != tt.want {
|
|
t.Errorf("matchPattern(%q, %q) = %v, want %v", tt.path, tt.pattern, got, tt.want)
|
|
}
|
|
})
|
|
}
|
|
}
|
|
|
|
func TestFilterEntries(t *testing.T) {
|
|
entries := []TreeEntry{
|
|
{Path: "README.md", Type: "blob", SHA: "abc123"},
|
|
{Path: "main.go", Type: "blob", SHA: "def456"},
|
|
{Path: "docs", Type: "tree", SHA: "ghi789"},
|
|
{Path: "docs/guide.md", Type: "blob", SHA: "jkl012"},
|
|
{Path: ".gitea/workflows/build.yml", Type: "blob", SHA: "mno345"},
|
|
}
|
|
|
|
tests := []struct {
|
|
name string
|
|
pattern string
|
|
expected int
|
|
}{
|
|
{
|
|
name: "no pattern returns all",
|
|
pattern: "",
|
|
expected: 5,
|
|
},
|
|
{
|
|
name: "filter markdown files",
|
|
pattern: "*.md",
|
|
expected: 2,
|
|
},
|
|
{
|
|
name: "filter yaml files",
|
|
pattern: "*.yml",
|
|
expected: 1,
|
|
},
|
|
{
|
|
name: "filter by directory",
|
|
pattern: ".gitea/*",
|
|
expected: 1,
|
|
},
|
|
{
|
|
name: "filter go files",
|
|
pattern: "*.go",
|
|
expected: 1,
|
|
},
|
|
{
|
|
name: "no match returns empty",
|
|
pattern: "*.py",
|
|
expected: 0,
|
|
},
|
|
}
|
|
|
|
for _, tt := range tests {
|
|
t.Run(tt.name, func(t *testing.T) {
|
|
filtered := filterEntries(entries, tt.pattern)
|
|
if len(filtered) != tt.expected {
|
|
t.Errorf("filterEntries() returned %d entries, want %d", len(filtered), tt.expected)
|
|
}
|
|
})
|
|
}
|
|
}
|
|
|
|
func TestSlimTreeEntries(t *testing.T) {
|
|
entries := []TreeEntry{
|
|
{Path: "README.md", Type: "blob", SHA: "abc123", Size: 1024},
|
|
{Path: "docs", Type: "tree", SHA: "def456", Size: 0},
|
|
{Path: "main.go", Type: "blob", SHA: "ghi789", Size: 2048},
|
|
}
|
|
|
|
slimmed := slimTreeEntries(entries)
|
|
|
|
if len(slimmed) != len(entries) {
|
|
t.Errorf("slimTreeEntries() returned %d entries, want %d", len(slimmed), len(entries))
|
|
}
|
|
|
|
for i, entry := range slimmed {
|
|
if _, ok := entry["path"]; !ok {
|
|
t.Errorf("entry %d missing 'path' field", i)
|
|
}
|
|
if _, ok := entry["type"]; !ok {
|
|
t.Errorf("entry %d missing 'type' field", i)
|
|
}
|
|
if _, ok := entry["sha"]; !ok {
|
|
t.Errorf("entry %d missing 'sha' field", i)
|
|
}
|
|
|
|
entryType := entry["type"](string)
|
|
_, hasSize := entry["size"]
|
|
|
|
if entryType == "blob" && entries[i].Size > 0 && !hasSize {
|
|
t.Errorf("blob entry %d should have size field", i)
|
|
}
|
|
if entryType == "tree" && hasSize {
|
|
t.Errorf("tree entry %d should not have size field", i)
|
|
}
|
|
}
|
|
}
|
|
|
|
func TestMatchPattern_EdgeCases(t *testing.T) {
|
|
tests := []struct {
|
|
name string
|
|
path string
|
|
pattern string
|
|
want bool
|
|
}{
|
|
{
|
|
name: "empty path with empty pattern",
|
|
path: "",
|
|
pattern: "",
|
|
want: true,
|
|
},
|
|
{
|
|
name: "empty path with pattern",
|
|
path: "",
|
|
pattern: "*.go",
|
|
want: false,
|
|
},
|
|
{
|
|
name: "path with spaces",
|
|
path: "path with spaces/file.txt",
|
|
pattern: "*.txt",
|
|
want: true,
|
|
},
|
|
{
|
|
name: "special characters in path",
|
|
path: "path-with-dashes/file_name.txt",
|
|
pattern: "*.txt",
|
|
want: true,
|
|
},
|
|
{
|
|
name: "double star at start and end",
|
|
path: "deep/nested/path/file.go",
|
|
pattern: "**/*.go",
|
|
want: true,
|
|
},
|
|
{
|
|
name: "negation with double star",
|
|
path: "node_modules/deep/package.json",
|
|
pattern: "!node_modules/**",
|
|
want: false,
|
|
},
|
|
{
|
|
name: "complex glob pattern",
|
|
path: "src/components/Button.test.tsx",
|
|
pattern: "**/*.test.tsx",
|
|
want: true,
|
|
},
|
|
{
|
|
name: "directory only pattern",
|
|
path: "src/components",
|
|
pattern: "src/*",
|
|
want: true,
|
|
},
|
|
{
|
|
name: "trailing slash in directory",
|
|
path: "src/components/",
|
|
pattern: "src/*",
|
|
want: true,
|
|
},
|
|
{
|
|
name: "single character wildcard",
|
|
path: "file1.txt",
|
|
pattern: "file?.txt",
|
|
want: true,
|
|
},
|
|
{
|
|
name: "range pattern",
|
|
path: "file5.txt",
|
|
pattern: "file[0-9].txt",
|
|
want: true,
|
|
},
|
|
}
|
|
|
|
for _, tt := range tests {
|
|
t.Run(tt.name, func(t *testing.T) {
|
|
got := matchPattern(tt.path, tt.pattern)
|
|
if got != tt.want {
|
|
t.Errorf("matchPattern(%q, %q) = %v, want %v", tt.path, tt.pattern, got, tt.want)
|
|
}
|
|
})
|
|
}
|
|
}
|
|
|
|
func TestFilterEntries_EdgeCases(t *testing.T) {
|
|
tests := []struct {
|
|
name string
|
|
entries []TreeEntry
|
|
pattern string
|
|
expected int
|
|
}{
|
|
{
|
|
name: "nil entries",
|
|
entries: nil,
|
|
pattern: "*.go",
|
|
expected: 0,
|
|
},
|
|
{
|
|
name: "empty entries",
|
|
entries: []TreeEntry{},
|
|
pattern: "*.go",
|
|
expected: 0,
|
|
},
|
|
{
|
|
name: "entries with empty paths",
|
|
entries: []TreeEntry{
|
|
{Path: "", Type: "blob", SHA: "abc123"},
|
|
{Path: "main.go", Type: "blob", SHA: "def456"},
|
|
},
|
|
pattern: "*.go",
|
|
expected: 1,
|
|
},
|
|
{
|
|
name: "negation pattern",
|
|
entries: []TreeEntry{
|
|
{Path: "test.go", Type: "blob", SHA: "abc123"},
|
|
{Path: "vendor/lib.go", Type: "blob", SHA: "def456"},
|
|
},
|
|
pattern: "!vendor/**",
|
|
expected: 1,
|
|
},
|
|
{
|
|
name: "complex pattern",
|
|
entries: []TreeEntry{
|
|
{Path: "src/main.go", Type: "blob", SHA: "abc123"},
|
|
{Path: "src/test/main_test.go", Type: "blob", SHA: "def456"},
|
|
{Path: "docs/readme.md", Type: "blob", SHA: "ghi789"},
|
|
},
|
|
pattern: "src/**/*.go",
|
|
expected: 2,
|
|
},
|
|
}
|
|
|
|
for _, tt := range tests {
|
|
t.Run(tt.name, func(t *testing.T) {
|
|
filtered := filterEntries(tt.entries, tt.pattern)
|
|
if len(filtered) != tt.expected {
|
|
t.Errorf("filterEntries() returned %d entries, want %d", len(filtered), tt.expected)
|
|
}
|
|
})
|
|
}
|
|
}
|
|
|
|
func TestSlimTreeEntries_EdgeCases(t *testing.T) {
|
|
tests := []struct {
|
|
name string
|
|
entries []TreeEntry
|
|
wantLen int
|
|
wantErr bool
|
|
}{
|
|
{
|
|
name: "nil entries",
|
|
entries: nil,
|
|
wantLen: 0,
|
|
},
|
|
{
|
|
name: "empty entries",
|
|
entries: []TreeEntry{},
|
|
wantLen: 0,
|
|
},
|
|
{
|
|
name: "entry with zero size blob",
|
|
entries: []TreeEntry{
|
|
{Path: "empty.txt", Type: "blob", SHA: "abc", Size: 0},
|
|
},
|
|
wantLen: 1,
|
|
},
|
|
{
|
|
name: "entry with symlink type",
|
|
entries: []TreeEntry{
|
|
{Path: "link", Type: "symlink", SHA: "def", Size: 0},
|
|
},
|
|
wantLen: 1,
|
|
},
|
|
{
|
|
name: "many entries",
|
|
entries: []TreeEntry{
|
|
{Path: "file1.txt", Type: "blob", SHA: "a", Size: 100},
|
|
{Path: "file2.txt", Type: "blob", SHA: "b", Size: 200},
|
|
{Path: "file3.txt", Type: "blob", SHA: "c", Size: 300},
|
|
{Path: "dir1", Type: "tree", SHA: "d", Size: 0},
|
|
{Path: "dir2", Type: "tree", SHA: "e", Size: 0},
|
|
},
|
|
wantLen: 5,
|
|
},
|
|
}
|
|
|
|
for _, tt := range tests {
|
|
t.Run(tt.name, func(t *testing.T) {
|
|
slimmed := slimTreeEntries(tt.entries)
|
|
if len(slimmed) != tt.wantLen {
|
|
t.Errorf("slimTreeEntries() returned %d entries, want %d", len(slimmed), tt.wantLen)
|
|
}
|
|
})
|
|
}
|
|
}
|
|
|
|
func TestTreeEntryStruct(t *testing.T) {
|
|
tests := []struct {
|
|
name string
|
|
entry TreeEntry
|
|
}{
|
|
{
|
|
name: "minimal entry",
|
|
entry: TreeEntry{
|
|
Path: "file.txt",
|
|
Type: "blob",
|
|
SHA: "abc123",
|
|
},
|
|
},
|
|
{
|
|
name: "full entry",
|
|
entry: TreeEntry{
|
|
Path: "file.txt",
|
|
Type: "blob",
|
|
SHA: "def456789abc",
|
|
Size: 1024,
|
|
},
|
|
},
|
|
{
|
|
name: "tree entry",
|
|
entry: TreeEntry{
|
|
Path: "directory",
|
|
Type: "tree",
|
|
SHA: "ghi789",
|
|
Size: 0,
|
|
},
|
|
},
|
|
}
|
|
|
|
for _, tt := range tests {
|
|
t.Run(tt.name, func(t *testing.T) {
|
|
if tt.entry.Path == "" {
|
|
t.Error("Path should not be empty")
|
|
}
|
|
if tt.entry.Type == "" {
|
|
t.Error("Type should not be empty")
|
|
}
|
|
if tt.entry.SHA == "" {
|
|
t.Error("SHA should not be empty")
|
|
}
|
|
})
|
|
}
|
|
}
|
|
|
|
func TestTreeResponseStruct(t *testing.T) {
|
|
response := TreeResponse{
|
|
SHA: "abc123def456",
|
|
URL: "https://api.example.com/repos/owner/repo/git/trees/abc123",
|
|
Tree: []TreeEntry{},
|
|
Truncated: false,
|
|
}
|
|
|
|
if response.SHA == "" {
|
|
t.Error("SHA should not be empty")
|
|
}
|
|
if response.URL == "" {
|
|
t.Error("URL should not be empty")
|
|
}
|
|
if response.Tree == nil {
|
|
t.Error("Tree should not be nil")
|
|
}
|
|
if response.Truncated {
|
|
t.Error("Truncated should be false")
|
|
}
|
|
}
|