mirror of
https://github.com/octoleo/restic.git
synced 2024-11-15 01:34:06 +00:00
210 lines
4.6 KiB
Go
210 lines
4.6 KiB
Go
|
// Copyright 2009 The Go Authors. All rights reserved.
|
||
|
// Use of this source code is governed by a BSD-style
|
||
|
// license that can be found in the LICENSE file.
|
||
|
|
||
|
package fs_test
|
||
|
|
||
|
import (
|
||
|
"os"
|
||
|
"path/filepath"
|
||
|
"runtime"
|
||
|
"testing"
|
||
|
|
||
|
"github.com/kr/fs"
|
||
|
)
|
||
|
|
||
|
type PathTest struct {
|
||
|
path, result string
|
||
|
}
|
||
|
|
||
|
type Node struct {
|
||
|
name string
|
||
|
entries []*Node // nil if the entry is a file
|
||
|
mark int
|
||
|
}
|
||
|
|
||
|
var tree = &Node{
|
||
|
"testdata",
|
||
|
[]*Node{
|
||
|
{"a", nil, 0},
|
||
|
{"b", []*Node{}, 0},
|
||
|
{"c", nil, 0},
|
||
|
{
|
||
|
"d",
|
||
|
[]*Node{
|
||
|
{"x", nil, 0},
|
||
|
{"y", []*Node{}, 0},
|
||
|
{
|
||
|
"z",
|
||
|
[]*Node{
|
||
|
{"u", nil, 0},
|
||
|
{"v", nil, 0},
|
||
|
},
|
||
|
0,
|
||
|
},
|
||
|
},
|
||
|
0,
|
||
|
},
|
||
|
},
|
||
|
0,
|
||
|
}
|
||
|
|
||
|
func walkTree(n *Node, path string, f func(path string, n *Node)) {
|
||
|
f(path, n)
|
||
|
for _, e := range n.entries {
|
||
|
walkTree(e, filepath.Join(path, e.name), f)
|
||
|
}
|
||
|
}
|
||
|
|
||
|
func makeTree(t *testing.T) {
|
||
|
walkTree(tree, tree.name, func(path string, n *Node) {
|
||
|
if n.entries == nil {
|
||
|
fd, err := os.Create(path)
|
||
|
if err != nil {
|
||
|
t.Errorf("makeTree: %v", err)
|
||
|
return
|
||
|
}
|
||
|
fd.Close()
|
||
|
} else {
|
||
|
os.Mkdir(path, 0770)
|
||
|
}
|
||
|
})
|
||
|
}
|
||
|
|
||
|
func markTree(n *Node) { walkTree(n, "", func(path string, n *Node) { n.mark++ }) }
|
||
|
|
||
|
func checkMarks(t *testing.T, report bool) {
|
||
|
walkTree(tree, tree.name, func(path string, n *Node) {
|
||
|
if n.mark != 1 && report {
|
||
|
t.Errorf("node %s mark = %d; expected 1", path, n.mark)
|
||
|
}
|
||
|
n.mark = 0
|
||
|
})
|
||
|
}
|
||
|
|
||
|
// Assumes that each node name is unique. Good enough for a test.
|
||
|
// If clear is true, any incoming error is cleared before return. The errors
|
||
|
// are always accumulated, though.
|
||
|
func mark(path string, info os.FileInfo, err error, errors *[]error, clear bool) error {
|
||
|
if err != nil {
|
||
|
*errors = append(*errors, err)
|
||
|
if clear {
|
||
|
return nil
|
||
|
}
|
||
|
return err
|
||
|
}
|
||
|
name := info.Name()
|
||
|
walkTree(tree, tree.name, func(path string, n *Node) {
|
||
|
if n.name == name {
|
||
|
n.mark++
|
||
|
}
|
||
|
})
|
||
|
return nil
|
||
|
}
|
||
|
|
||
|
func TestWalk(t *testing.T) {
|
||
|
makeTree(t)
|
||
|
errors := make([]error, 0, 10)
|
||
|
clear := true
|
||
|
markFn := func(walker *fs.Walker) (err error) {
|
||
|
for walker.Step() {
|
||
|
err = mark(walker.Path(), walker.Stat(), walker.Err(), &errors, clear)
|
||
|
if err != nil {
|
||
|
break
|
||
|
}
|
||
|
}
|
||
|
return err
|
||
|
}
|
||
|
// Expect no errors.
|
||
|
err := markFn(fs.Walk(tree.name))
|
||
|
if err != nil {
|
||
|
t.Fatalf("no error expected, found: %s", err)
|
||
|
}
|
||
|
if len(errors) != 0 {
|
||
|
t.Fatalf("unexpected errors: %s", errors)
|
||
|
}
|
||
|
checkMarks(t, true)
|
||
|
errors = errors[0:0]
|
||
|
|
||
|
// Test permission errors. Only possible if we're not root
|
||
|
// and only on some file systems (AFS, FAT). To avoid errors during
|
||
|
// all.bash on those file systems, skip during go test -short.
|
||
|
if os.Getuid() > 0 && !testing.Short() {
|
||
|
// introduce 2 errors: chmod top-level directories to 0
|
||
|
os.Chmod(filepath.Join(tree.name, tree.entries[1].name), 0)
|
||
|
os.Chmod(filepath.Join(tree.name, tree.entries[3].name), 0)
|
||
|
|
||
|
// 3) capture errors, expect two.
|
||
|
// mark respective subtrees manually
|
||
|
markTree(tree.entries[1])
|
||
|
markTree(tree.entries[3])
|
||
|
// correct double-marking of directory itself
|
||
|
tree.entries[1].mark--
|
||
|
tree.entries[3].mark--
|
||
|
err := markFn(fs.Walk(tree.name))
|
||
|
if err != nil {
|
||
|
t.Fatalf("expected no error return from Walk, got %s", err)
|
||
|
}
|
||
|
if len(errors) != 2 {
|
||
|
t.Errorf("expected 2 errors, got %d: %s", len(errors), errors)
|
||
|
}
|
||
|
// the inaccessible subtrees were marked manually
|
||
|
checkMarks(t, true)
|
||
|
errors = errors[0:0]
|
||
|
|
||
|
// 4) capture errors, stop after first error.
|
||
|
// mark respective subtrees manually
|
||
|
markTree(tree.entries[1])
|
||
|
markTree(tree.entries[3])
|
||
|
// correct double-marking of directory itself
|
||
|
tree.entries[1].mark--
|
||
|
tree.entries[3].mark--
|
||
|
clear = false // error will stop processing
|
||
|
err = markFn(fs.Walk(tree.name))
|
||
|
if err == nil {
|
||
|
t.Fatalf("expected error return from Walk")
|
||
|
}
|
||
|
if len(errors) != 1 {
|
||
|
t.Errorf("expected 1 error, got %d: %s", len(errors), errors)
|
||
|
}
|
||
|
// the inaccessible subtrees were marked manually
|
||
|
checkMarks(t, false)
|
||
|
errors = errors[0:0]
|
||
|
|
||
|
// restore permissions
|
||
|
os.Chmod(filepath.Join(tree.name, tree.entries[1].name), 0770)
|
||
|
os.Chmod(filepath.Join(tree.name, tree.entries[3].name), 0770)
|
||
|
}
|
||
|
|
||
|
// cleanup
|
||
|
if err := os.RemoveAll(tree.name); err != nil {
|
||
|
t.Errorf("removeTree: %v", err)
|
||
|
}
|
||
|
}
|
||
|
|
||
|
func TestBug3486(t *testing.T) { // http://code.google.com/p/go/issues/detail?id=3486
|
||
|
root, err := filepath.EvalSymlinks(runtime.GOROOT())
|
||
|
if err != nil {
|
||
|
t.Fatal(err)
|
||
|
}
|
||
|
lib := filepath.Join(root, "lib")
|
||
|
src := filepath.Join(root, "src")
|
||
|
seenSrc := false
|
||
|
walker := fs.Walk(root)
|
||
|
for walker.Step() {
|
||
|
if walker.Err() != nil {
|
||
|
t.Fatal(walker.Err())
|
||
|
}
|
||
|
|
||
|
switch walker.Path() {
|
||
|
case lib:
|
||
|
walker.SkipDir()
|
||
|
case src:
|
||
|
seenSrc = true
|
||
|
}
|
||
|
}
|
||
|
if !seenSrc {
|
||
|
t.Fatalf("%q not seen", src)
|
||
|
}
|
||
|
}
|