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)
 | 
						|
	}
 | 
						|
}
 |