505 lines
13 KiB
Go
505 lines
13 KiB
Go
|
|
package glob
|
||
|
|
|
||
|
|
import (
|
||
|
|
"archive/zip"
|
||
|
|
"bytes"
|
||
|
|
"io"
|
||
|
|
"io/fs"
|
||
|
|
"reflect"
|
||
|
|
"sort"
|
||
|
|
"testing"
|
||
|
|
"testing/fstest"
|
||
|
|
)
|
||
|
|
|
||
|
|
func setupFS() fs.ReadDirFS {
|
||
|
|
// Create an in-memory FS with a mix of files and directories
|
||
|
|
return fstest.MapFS{
|
||
|
|
"main.go": &fstest.MapFile{Data: []byte("package main")},
|
||
|
|
"main_test.go": &fstest.MapFile{Data: []byte("package main_test")},
|
||
|
|
"README.md": &fstest.MapFile{Data: []byte("# readme")},
|
||
|
|
"LICENSE": &fstest.MapFile{Data: []byte("MIT")},
|
||
|
|
"docs/guide.md": &fstest.MapFile{Data: []byte("Docs")},
|
||
|
|
"docs/other.txt": &fstest.MapFile{Data: []byte("Other")},
|
||
|
|
"docs/hidden/.keep": &fstest.MapFile{Data: []byte("")},
|
||
|
|
"assets/img.png": &fstest.MapFile{Data: []byte("PNG")},
|
||
|
|
"assets/style.css": &fstest.MapFile{Data: []byte("CSS")},
|
||
|
|
".gitignore": &fstest.MapFile{Data: []byte("*.log")},
|
||
|
|
".hiddenfile": &fstest.MapFile{Data: []byte("")},
|
||
|
|
"emptydir": &fstest.MapFile{Mode: fs.ModeDir | 0o755},
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
// helper to get base names for easier comparison
|
||
|
|
func basenames(entries []fs.DirEntry) []string {
|
||
|
|
names := []string{}
|
||
|
|
for _, e := range entries {
|
||
|
|
names = append(names, e.Name())
|
||
|
|
}
|
||
|
|
sort.Strings(names)
|
||
|
|
return names
|
||
|
|
}
|
||
|
|
|
||
|
|
func TestGlobFS_MultiplePatterns(t *testing.T) {
|
||
|
|
memfs := setupFS()
|
||
|
|
gfs, err := NewGlobFS(memfs, "*.go", "*.md", "assets/*", "docs/guide.md", ".gitignore")
|
||
|
|
|
||
|
|
if err != nil {
|
||
|
|
t.Errorf("unexpected error while creating glob fs: %v", err)
|
||
|
|
}
|
||
|
|
|
||
|
|
tests := []struct {
|
||
|
|
path string
|
||
|
|
want []string
|
||
|
|
wantErr bool
|
||
|
|
}{
|
||
|
|
{path: ".", want: []string{"README.md", "assets", "docs", "main.go", "main_test.go", ".gitignore"}},
|
||
|
|
{path: "assets", want: []string{"img.png", "style.css"}},
|
||
|
|
{path: "docs", want: []string{"guide.md"}},
|
||
|
|
{path: "docs/hidden", want: []string{}, wantErr: true},
|
||
|
|
{path: "emptydir", want: []string{}, wantErr: true},
|
||
|
|
}
|
||
|
|
|
||
|
|
for _, tc := range tests {
|
||
|
|
tc := tc // capture range variable
|
||
|
|
t.Run(escape(tc.path), func(t *testing.T) {
|
||
|
|
entries, err := fs.ReadDir(gfs, tc.path)
|
||
|
|
if tc.wantErr && err == nil {
|
||
|
|
t.Errorf("expected error, got nil")
|
||
|
|
return
|
||
|
|
}
|
||
|
|
if !tc.wantErr && err != nil {
|
||
|
|
t.Errorf("unexpected error: %v", err)
|
||
|
|
return
|
||
|
|
}
|
||
|
|
got := basenames(entries)
|
||
|
|
sort.Strings(tc.want)
|
||
|
|
if !reflect.DeepEqual(got, tc.want) {
|
||
|
|
t.Errorf("got %v; want %v", got, tc.want)
|
||
|
|
}
|
||
|
|
})
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
func TestGlobFS_Open(t *testing.T) {
|
||
|
|
memfs := setupFS()
|
||
|
|
gfs, err := NewGlobFS(memfs, "*.go", "*.md", "assets/*", "docs/guide.md", ".gitignore")
|
||
|
|
|
||
|
|
if err != nil {
|
||
|
|
t.Errorf("unexpected error while creating glob fs: %v", err)
|
||
|
|
}
|
||
|
|
|
||
|
|
type test struct {
|
||
|
|
path string
|
||
|
|
wantErr bool
|
||
|
|
}
|
||
|
|
tests := []test{
|
||
|
|
{path: "main.go"},
|
||
|
|
{path: "README.md"},
|
||
|
|
{path: "LICENSE", wantErr: true},
|
||
|
|
{path: "assets/img.png"},
|
||
|
|
{path: "assets/style.css"},
|
||
|
|
{path: "assets/nonexistent.png", wantErr: true},
|
||
|
|
{path: "docs/guide.md"},
|
||
|
|
{path: "docs/other.txt", wantErr: true},
|
||
|
|
{path: ".gitignore"},
|
||
|
|
{path: ".hiddenfile", wantErr: true},
|
||
|
|
{path: "docs/hidden/.keep", wantErr: true},
|
||
|
|
{path: "emptydir", wantErr: true},
|
||
|
|
{path: "docs"}, // allowed because it contains matching file(s)
|
||
|
|
{path: "assets"}, // allowed because it contains matching file(s)
|
||
|
|
}
|
||
|
|
for _, tc := range tests {
|
||
|
|
tc := tc
|
||
|
|
t.Run(escape(tc.path), func(t *testing.T) {
|
||
|
|
f, err := gfs.Open(tc.path)
|
||
|
|
if tc.wantErr && err == nil {
|
||
|
|
t.Errorf("expected error, got file")
|
||
|
|
if f != nil {
|
||
|
|
f.Close()
|
||
|
|
}
|
||
|
|
} else if !tc.wantErr && err != nil {
|
||
|
|
t.Errorf("unexpected error: %v", err)
|
||
|
|
} else if !tc.wantErr && err == nil {
|
||
|
|
info, _ := f.Stat()
|
||
|
|
if info.IsDir() {
|
||
|
|
_, derr := fs.ReadDir(gfs, tc.path)
|
||
|
|
if derr != nil && !tc.wantErr {
|
||
|
|
t.Errorf("unexpected error: %v", derr)
|
||
|
|
}
|
||
|
|
}
|
||
|
|
f.Close()
|
||
|
|
}
|
||
|
|
})
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
func TestGlobFS_ReadFile(t *testing.T) {
|
||
|
|
memfs := setupFS()
|
||
|
|
gfs, err := NewGlobFS(memfs, "*.go", "*.md", "assets/*", ".gitignore")
|
||
|
|
|
||
|
|
if err != nil {
|
||
|
|
t.Errorf("unexpected error while creating glob fs: %v", err)
|
||
|
|
}
|
||
|
|
|
||
|
|
tests := []struct {
|
||
|
|
name string
|
||
|
|
want []byte
|
||
|
|
wantErr bool
|
||
|
|
}{
|
||
|
|
{name: "main.go", want: []byte("package main")},
|
||
|
|
{name: "main_test.go", want: []byte("package main_test")},
|
||
|
|
{name: "README.md", want: []byte("# readme")},
|
||
|
|
{name: "assets/img.png", want: []byte("PNG")},
|
||
|
|
{name: "assets/style.css", want: []byte("CSS")},
|
||
|
|
{name: ".gitignore", want: []byte("*.log")},
|
||
|
|
{name: "LICENSE", wantErr: true}, // not allowed by filter
|
||
|
|
{name: "docs/guide.md", wantErr: true}, // not allowed by filter
|
||
|
|
{name: "docs/hidden/.keep", wantErr: true}, // not allowed by filter
|
||
|
|
{name: "doesnotexist.txt", wantErr: true}, // does not exist
|
||
|
|
}
|
||
|
|
|
||
|
|
for _, tc := range tests {
|
||
|
|
tc := tc
|
||
|
|
t.Run(escape(tc.name), func(t *testing.T) {
|
||
|
|
got, err := fs.ReadFile(gfs, tc.name)
|
||
|
|
if tc.wantErr {
|
||
|
|
if err == nil {
|
||
|
|
t.Errorf("expected error, got nil (got=%q)", got)
|
||
|
|
}
|
||
|
|
} else {
|
||
|
|
if err != nil {
|
||
|
|
t.Errorf("unexpected error: %v", err)
|
||
|
|
}
|
||
|
|
if string(got) != string(tc.want) {
|
||
|
|
t.Errorf("got %q; want %q", got, tc.want)
|
||
|
|
}
|
||
|
|
}
|
||
|
|
})
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
func TestGlobFS_RelativePaths(t *testing.T) {
|
||
|
|
memfs := setupFS()
|
||
|
|
gfs, err := NewGlobFS(memfs, "docs/*.md")
|
||
|
|
if err != nil {
|
||
|
|
t.Errorf("unexpected error while creating glob fs: %v", err)
|
||
|
|
}
|
||
|
|
entries, err := fs.ReadDir(gfs, "docs")
|
||
|
|
if err != nil {
|
||
|
|
t.Fatal(err)
|
||
|
|
}
|
||
|
|
got := basenames(entries)
|
||
|
|
want := []string{"guide.md"}
|
||
|
|
if !reflect.DeepEqual(got, want) {
|
||
|
|
t.Errorf("docs/*.md: got %v, want %v", got, want)
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
func TestGlobFS_NoMatchesOpen(t *testing.T) {
|
||
|
|
gfs, err := NewGlobFS(setupFS(), "*.xyz")
|
||
|
|
if err != nil {
|
||
|
|
t.Errorf("unexpected error while creating glob fs: %v", err)
|
||
|
|
}
|
||
|
|
_, err = gfs.Open("main.go")
|
||
|
|
if err == nil {
|
||
|
|
t.Fatal("expected error when opening file with no matches")
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
func TestGlobFS_NoMatchesStat(t *testing.T) {
|
||
|
|
gfs, err := NewGlobFS(setupFS(), "*.xyz")
|
||
|
|
if err != nil {
|
||
|
|
t.Errorf("unexpected error while creating glob fs: %v", err)
|
||
|
|
}
|
||
|
|
_, err = fs.Stat(gfs, "main.go")
|
||
|
|
if err == nil {
|
||
|
|
t.Fatal("expected error with no matches: stat")
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
func TestGlobFS_NoMatchesReadDir(t *testing.T) {
|
||
|
|
gfs, err := NewGlobFS(setupFS(), "*.xyz")
|
||
|
|
if err != nil {
|
||
|
|
t.Errorf("unexpected error while creating glob fs: %v", err)
|
||
|
|
}
|
||
|
|
_, err = fs.ReadDir(gfs, "main.go")
|
||
|
|
if err == nil {
|
||
|
|
t.Fatal("expected error with no matches: readdir")
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
func TestGlobFS_NoMatchesReadFile(t *testing.T) {
|
||
|
|
gfs, err := NewGlobFS(setupFS(), "*.xyz")
|
||
|
|
if err != nil {
|
||
|
|
t.Errorf("unexpected error while creating glob fs: %v", err)
|
||
|
|
}
|
||
|
|
_, err = fs.ReadFile(gfs, "main.go")
|
||
|
|
if err == nil {
|
||
|
|
t.Fatal("expected error with no matches: readfile")
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
func TestGlobFS_MatchEmptyDirExact(t *testing.T) {
|
||
|
|
// the trailing slash indicates that the directory should be included
|
||
|
|
gfs, err := NewGlobFS(setupFS(), "emptydir/")
|
||
|
|
if err != nil {
|
||
|
|
t.Errorf("unexpected error while creating glob fs: %v", err)
|
||
|
|
}
|
||
|
|
_, err = fs.ReadDir(gfs, "emptydir")
|
||
|
|
if err != nil {
|
||
|
|
t.Errorf("unexpected error: %v", err)
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
func TestGlobFS_MatchEmptyDirExact2(t *testing.T) {
|
||
|
|
// the trailing slash indicates that the directory should be included
|
||
|
|
gfs, err := NewGlobFS(setupFS(), "emptydir/*")
|
||
|
|
if err != nil {
|
||
|
|
t.Errorf("unexpected error while creating glob fs: %v", err)
|
||
|
|
}
|
||
|
|
_, err = fs.ReadDir(gfs, "emptydir")
|
||
|
|
if err != nil {
|
||
|
|
t.Errorf("unexpected error: %v", err)
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
func TestGlobFS_NoMatchEmptyDirExact(t *testing.T) {
|
||
|
|
// no traling slash indicates that the directory must be a file to be included
|
||
|
|
gfs, err := NewGlobFS(setupFS(), "emptydir")
|
||
|
|
if err != nil {
|
||
|
|
t.Errorf("unexpected error while creating glob fs: %v", err)
|
||
|
|
}
|
||
|
|
_, err = fs.ReadDir(gfs, "emptydir")
|
||
|
|
if err == nil {
|
||
|
|
t.Fatal("expected error with no matches: readfile")
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
func TestGlobFS_IntegrationWithStdlibWalkDir(t *testing.T) {
|
||
|
|
memfs := setupFS()
|
||
|
|
gfs, err := NewGlobFS(memfs, "*.go", "docs/guide.md")
|
||
|
|
if err != nil {
|
||
|
|
t.Errorf("unexpected error while creating glob fs: %v", err)
|
||
|
|
}
|
||
|
|
// Use fs.WalkDir with our filtered FS
|
||
|
|
var walked []string
|
||
|
|
err = fs.WalkDir(gfs, ".", func(path string, d fs.DirEntry, err error) error {
|
||
|
|
if err != nil {
|
||
|
|
t.Fatalf("the %q caused: %v", path, err)
|
||
|
|
return err
|
||
|
|
}
|
||
|
|
walked = append(walked, path)
|
||
|
|
return nil
|
||
|
|
})
|
||
|
|
if err != nil {
|
||
|
|
t.Fatal(err)
|
||
|
|
}
|
||
|
|
// Only files and dirs matching or containing matches should appear
|
||
|
|
for _, p := range walked {
|
||
|
|
if p == "." || p == "main.go" || p == "main_test.go" || p == "docs" || p == "docs/guide.md" {
|
||
|
|
continue
|
||
|
|
}
|
||
|
|
t.Errorf("WalkDir: unexpected path %q", p)
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
func TestGlobFS_InvalidPattern(t *testing.T) {
|
||
|
|
_, err := NewGlobFS(setupFS(), "[invalid")
|
||
|
|
if err == nil {
|
||
|
|
t.Fatal("expected error for invalid pattern, got nil")
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
func TestGlobFS_WildcardInDirSegment(t *testing.T) {
|
||
|
|
gfs, err := NewGlobFS(setupFS(), "docs/*/*.md")
|
||
|
|
if err != nil {
|
||
|
|
t.Fatalf("unexpected error: %v", err)
|
||
|
|
}
|
||
|
|
entries, err := fs.ReadDir(gfs, "docs/hidden")
|
||
|
|
if err != nil {
|
||
|
|
t.Errorf("unexpected error: %v", err)
|
||
|
|
}
|
||
|
|
if len(entries) != 0 {
|
||
|
|
t.Errorf("expected no entries, got %v", basenames(entries))
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
func TestGlobFS_DeeplyNestedMatch(t *testing.T) {
|
||
|
|
memfs := fstest.MapFS{
|
||
|
|
"a/b/c/d.txt": &fstest.MapFile{Data: []byte("deep")},
|
||
|
|
}
|
||
|
|
gfs, err := NewGlobFS(memfs, "a/b/c/*.txt")
|
||
|
|
if err != nil {
|
||
|
|
t.Fatalf("unexpected error: %v", err)
|
||
|
|
}
|
||
|
|
data, err := fs.ReadFile(gfs, "a/b/c/d.txt")
|
||
|
|
if err != nil {
|
||
|
|
t.Errorf("unexpected error: %v", err)
|
||
|
|
}
|
||
|
|
if string(data) != "deep" {
|
||
|
|
t.Errorf("got %q, want %q", data, "deep")
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
func TestGlobFS_HiddenFilesOnly(t *testing.T) {
|
||
|
|
gfs, err := NewGlobFS(setupFS(), ".*")
|
||
|
|
if err != nil {
|
||
|
|
t.Fatalf("unexpected error: %v", err)
|
||
|
|
}
|
||
|
|
entries, err := fs.ReadDir(gfs, ".")
|
||
|
|
if err != nil {
|
||
|
|
t.Fatalf("unexpected error: %v", err)
|
||
|
|
}
|
||
|
|
got := basenames(entries)
|
||
|
|
want := []string{".gitignore", ".hiddenfile"}
|
||
|
|
if !reflect.DeepEqual(got, want) {
|
||
|
|
t.Errorf("got %v, want %v", got, want)
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
// Test directory pattern matching with various directory globs
|
||
|
|
func TestGlobFS_DirectoryPatterns(t *testing.T) {
|
||
|
|
memfs := fstest.MapFS{
|
||
|
|
"foo/bar/baz.txt": &fstest.MapFile{Data: []byte("baz")},
|
||
|
|
"foo/bar/qux.txt": &fstest.MapFile{Data: []byte("qux")},
|
||
|
|
"foo/readme.md": &fstest.MapFile{Data: []byte("readme")},
|
||
|
|
"foo/empty/.keep": &fstest.MapFile{Data: []byte("")}, // represent empty dir by a file inside
|
||
|
|
"top.txt": &fstest.MapFile{Data: []byte("top")},
|
||
|
|
}
|
||
|
|
|
||
|
|
t.Run("single dir segment wildcard", func(t *testing.T) {
|
||
|
|
gfs, err := NewGlobFS(memfs, "foo/bar/*")
|
||
|
|
if err != nil {
|
||
|
|
t.Fatalf("unexpected error: %v", err)
|
||
|
|
}
|
||
|
|
entries, err := fs.ReadDir(gfs, "foo/bar")
|
||
|
|
if err != nil {
|
||
|
|
t.Fatalf("unexpected error: %v", err)
|
||
|
|
}
|
||
|
|
got := basenames(entries)
|
||
|
|
want := []string{"baz.txt", "qux.txt"}
|
||
|
|
if !reflect.DeepEqual(got, want) {
|
||
|
|
t.Errorf("got %v, want %v", got, want)
|
||
|
|
}
|
||
|
|
})
|
||
|
|
|
||
|
|
t.Run("recursive dir wildcard", func(t *testing.T) {
|
||
|
|
gfs, err := NewGlobFS(memfs, "foo/bar/*")
|
||
|
|
if err != nil {
|
||
|
|
t.Fatalf("unexpected error: %v", err)
|
||
|
|
}
|
||
|
|
entries, err := fs.ReadDir(gfs, "foo/bar")
|
||
|
|
if err != nil {
|
||
|
|
t.Fatalf("unexpected error: %v", err)
|
||
|
|
}
|
||
|
|
got := basenames(entries)
|
||
|
|
want := []string{"baz.txt", "qux.txt"}
|
||
|
|
if !reflect.DeepEqual(got, want) {
|
||
|
|
t.Errorf("got %v, want %v", got, want)
|
||
|
|
}
|
||
|
|
entries, err = fs.ReadDir(gfs, "foo")
|
||
|
|
if err != nil {
|
||
|
|
t.Fatalf("unexpected error: %v", err)
|
||
|
|
}
|
||
|
|
got = basenames(entries)
|
||
|
|
want = []string{"bar"}
|
||
|
|
if !reflect.DeepEqual(got, want) {
|
||
|
|
t.Errorf("got %v, want %v", got, want)
|
||
|
|
}
|
||
|
|
})
|
||
|
|
|
||
|
|
t.Run("match empty directory", func(t *testing.T) {
|
||
|
|
gfs, err := NewGlobFS(memfs, "foo/empty/")
|
||
|
|
if err != nil {
|
||
|
|
t.Fatalf("unexpected error: %v", err)
|
||
|
|
}
|
||
|
|
entries, err := fs.ReadDir(gfs, "foo/empty")
|
||
|
|
if err != nil {
|
||
|
|
t.Fatalf("unexpected error: %v", err)
|
||
|
|
}
|
||
|
|
if len(entries) != 0 {
|
||
|
|
t.Errorf("expected empty, got %v", basenames(entries))
|
||
|
|
}
|
||
|
|
})
|
||
|
|
|
||
|
|
t.Run("top-level dir wildcard", func(t *testing.T) {
|
||
|
|
gfs, err := NewGlobFS(memfs, "*/bar/*")
|
||
|
|
if err != nil {
|
||
|
|
t.Fatalf("unexpected error: %v", err)
|
||
|
|
}
|
||
|
|
entries, err := fs.ReadDir(gfs, "foo/bar")
|
||
|
|
if err != nil {
|
||
|
|
t.Fatalf("unexpected error: %v", err)
|
||
|
|
}
|
||
|
|
got := basenames(entries)
|
||
|
|
want := []string{"baz.txt", "qux.txt"}
|
||
|
|
if !reflect.DeepEqual(got, want) {
|
||
|
|
t.Errorf("got %v, want %v", got, want)
|
||
|
|
}
|
||
|
|
})
|
||
|
|
}
|
||
|
|
|
||
|
|
func TestGlobFS_IntegrationWithStdlibZipWriter(t *testing.T) {
|
||
|
|
gfs, err := NewGlobFS(setupFS(), "*")
|
||
|
|
if err != nil {
|
||
|
|
t.Errorf("unexpected error while creating glob fs: %v", err)
|
||
|
|
}
|
||
|
|
|
||
|
|
want := map[string]string{
|
||
|
|
"main.go": "package main",
|
||
|
|
"main_test.go": "package main_test",
|
||
|
|
"README.md": "# readme",
|
||
|
|
"LICENSE": "MIT",
|
||
|
|
".gitignore": "*.log",
|
||
|
|
".hiddenfile": "",
|
||
|
|
}
|
||
|
|
|
||
|
|
buf := new(bytes.Buffer)
|
||
|
|
wr := zip.NewWriter(buf)
|
||
|
|
err = wr.AddFS(gfs)
|
||
|
|
if err != nil {
|
||
|
|
t.Fatalf("adding fs to zip writer: %v", err)
|
||
|
|
}
|
||
|
|
err = wr.Close()
|
||
|
|
if err != nil {
|
||
|
|
t.Fatalf("close zip writer: %v", err)
|
||
|
|
}
|
||
|
|
|
||
|
|
rd, err := zip.NewReader(bytes.NewReader(buf.Bytes()), int64(len(buf.Bytes())))
|
||
|
|
if err != nil {
|
||
|
|
t.Fatalf("invalid zip archive: %v", err)
|
||
|
|
}
|
||
|
|
|
||
|
|
got := make(map[string]string)
|
||
|
|
for _, f := range rd.File {
|
||
|
|
rc, err := f.Open()
|
||
|
|
if err != nil {
|
||
|
|
t.Fatalf("cannot open file %s: %v", f.Name, err)
|
||
|
|
}
|
||
|
|
content, err := io.ReadAll(rc)
|
||
|
|
defer rc.Close()
|
||
|
|
if err != nil {
|
||
|
|
t.Fatalf("cannot read file %s: %v", f.Name, err)
|
||
|
|
}
|
||
|
|
got[f.Name] = string(content)
|
||
|
|
}
|
||
|
|
|
||
|
|
// Compare expected vs actual.
|
||
|
|
for name, exp := range want {
|
||
|
|
act, ok := got[name]
|
||
|
|
if !ok {
|
||
|
|
t.Errorf("expected file %q not found in zip", name)
|
||
|
|
continue
|
||
|
|
}
|
||
|
|
if act != exp {
|
||
|
|
t.Errorf("content mismatch for %q:\nexpected: %q\nactual: %q", name, exp, act)
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
// Check for unexpected extra files.
|
||
|
|
for name := range got {
|
||
|
|
if _, ok := want[name]; !ok {
|
||
|
|
t.Errorf("unexpected file %q found in zip", name)
|
||
|
|
}
|
||
|
|
}
|
||
|
|
}
|