2014-07-12 15:45:33 -07:00
|
|
|
// Copyright (C) 2014 Jakob Borg and Contributors (see the CONTRIBUTORS file).
|
|
|
|
// All rights reserved. Use of this source code is governed by an MIT-style
|
|
|
|
// license that can be found in the LICENSE file.
|
2014-06-01 13:50:14 -07:00
|
|
|
|
2014-03-08 15:02:01 -07:00
|
|
|
package scanner
|
2014-03-02 15:58:14 -07:00
|
|
|
|
|
|
|
import (
|
2014-08-26 01:11:25 -07:00
|
|
|
"bytes"
|
2014-03-02 15:58:14 -07:00
|
|
|
"fmt"
|
2014-08-16 09:33:01 -07:00
|
|
|
"path/filepath"
|
2014-08-30 00:22:23 -07:00
|
|
|
"reflect"
|
2014-08-30 00:55:01 -07:00
|
|
|
rdebug "runtime/debug"
|
2014-07-30 11:10:46 -07:00
|
|
|
"sort"
|
2014-03-02 15:58:14 -07:00
|
|
|
"testing"
|
2014-07-17 05:48:02 -07:00
|
|
|
|
2014-08-01 07:35:37 -07:00
|
|
|
"github.com/syncthing/syncthing/protocol"
|
2014-03-02 15:58:14 -07:00
|
|
|
)
|
|
|
|
|
2014-08-30 00:22:23 -07:00
|
|
|
type testfile struct {
|
2014-03-02 15:58:14 -07:00
|
|
|
name string
|
|
|
|
size int
|
|
|
|
hash string
|
2014-08-30 00:22:23 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
type testfileList []testfile
|
|
|
|
|
|
|
|
var testdata = testfileList{
|
|
|
|
{"afile", 4, "b5bb9d8014a0f9b1d61e21e796d78dccdf1352f23cd32812f4850b878ae4944c"},
|
|
|
|
{"dir1", 128, ""},
|
2014-08-31 14:32:27 -07:00
|
|
|
{filepath.Join("dir1", "dfile"), 5, "49ae93732fcf8d63fe1cce759664982dbd5b23161f007dba8561862adc96d063"},
|
2014-08-30 00:22:23 -07:00
|
|
|
{"dir2", 128, ""},
|
2014-08-31 14:32:27 -07:00
|
|
|
{filepath.Join("dir2", "cfile"), 4, "bf07a7fbb825fc0aae7bf4a1177b2b31fcf8a3feeaf7092761e18c859ee52a9c"},
|
2014-08-30 00:22:23 -07:00
|
|
|
{"excludes", 78, "1f5ac95d9e6fb2516629a029d788d27953c7bb2f4dc09184b660fdda0c8f2f04"},
|
|
|
|
{"further-excludes", 5, "7eb0a548094fa6295f7fd9200d69973e5f5ec5c04f2a86d998080ac43ecf89f1"},
|
|
|
|
{"loop-excludes", 18, "2db057aa82a8b8fe4b1367ccc875259ed4b8020255820d4e3d4bfe78f0dd3f2a"},
|
2014-03-02 15:58:14 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
var correctIgnores = map[string][]string{
|
2014-06-16 07:18:19 -07:00
|
|
|
".": {".*", "quux"},
|
2014-03-02 15:58:14 -07:00
|
|
|
}
|
|
|
|
|
2014-08-30 00:55:01 -07:00
|
|
|
func init() {
|
|
|
|
// This test runs the risk of entering infinite recursion if it fails.
|
|
|
|
// Limit the stack size to 10 megs to creash early in that case instead of
|
|
|
|
// potentially taking down the box...
|
|
|
|
rdebug.SetMaxStack(10 * 1 << 20)
|
|
|
|
}
|
|
|
|
|
2014-08-11 11:20:01 -07:00
|
|
|
func TestWalkSub(t *testing.T) {
|
|
|
|
w := Walker{
|
|
|
|
Dir: "testdata",
|
2014-08-30 00:22:23 -07:00
|
|
|
Sub: "dir2",
|
2014-08-11 11:20:01 -07:00
|
|
|
BlockSize: 128 * 1024,
|
|
|
|
IgnoreFile: ".stignore",
|
|
|
|
}
|
2014-08-26 01:11:25 -07:00
|
|
|
fchan, err := w.Walk()
|
2014-08-11 11:20:01 -07:00
|
|
|
var files []protocol.FileInfo
|
|
|
|
for f := range fchan {
|
|
|
|
files = append(files, f)
|
|
|
|
}
|
|
|
|
if err != nil {
|
|
|
|
t.Fatal(err)
|
|
|
|
}
|
|
|
|
|
2014-08-30 00:22:23 -07:00
|
|
|
// The directory contains two files, where one is ignored from a higher
|
|
|
|
// level. We should see only the directory and one of the files.
|
|
|
|
|
|
|
|
if len(files) != 2 {
|
|
|
|
t.Fatalf("Incorrect length %d != 2", len(files))
|
2014-08-11 11:20:01 -07:00
|
|
|
}
|
2014-08-30 00:22:23 -07:00
|
|
|
if files[0].Name != "dir2" {
|
|
|
|
t.Errorf("Incorrect file %v != dir2", files[0])
|
|
|
|
}
|
2014-08-31 14:32:27 -07:00
|
|
|
if files[1].Name != filepath.Join("dir2", "cfile") {
|
2014-08-30 00:22:23 -07:00
|
|
|
t.Errorf("Incorrect file %v != dir2/cfile", files[1])
|
2014-08-11 11:20:01 -07:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2014-03-02 15:58:14 -07:00
|
|
|
func TestWalk(t *testing.T) {
|
2014-03-08 15:02:01 -07:00
|
|
|
w := Walker{
|
|
|
|
Dir: "testdata",
|
|
|
|
BlockSize: 128 * 1024,
|
|
|
|
IgnoreFile: ".stignore",
|
|
|
|
}
|
2014-05-04 09:20:25 -07:00
|
|
|
|
2014-08-30 00:22:23 -07:00
|
|
|
fchan, err := w.Walk()
|
2014-05-04 09:20:25 -07:00
|
|
|
if err != nil {
|
|
|
|
t.Fatal(err)
|
|
|
|
}
|
2014-03-02 15:58:14 -07:00
|
|
|
|
2014-08-30 00:22:23 -07:00
|
|
|
var tmp []protocol.FileInfo
|
|
|
|
for f := range fchan {
|
|
|
|
tmp = append(tmp, f)
|
2014-03-02 15:58:14 -07:00
|
|
|
}
|
2014-08-30 00:22:23 -07:00
|
|
|
sort.Sort(fileList(tmp))
|
|
|
|
files := fileList(tmp).testfiles()
|
2014-03-02 15:58:14 -07:00
|
|
|
|
2014-08-30 00:22:23 -07:00
|
|
|
if !reflect.DeepEqual(files, testdata) {
|
|
|
|
t.Errorf("Walk returned unexpected data\nExpected: %v\nActual: %v", testdata, files)
|
2014-03-02 15:58:14 -07:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2014-05-04 09:20:25 -07:00
|
|
|
func TestWalkError(t *testing.T) {
|
|
|
|
w := Walker{
|
|
|
|
Dir: "testdata-missing",
|
|
|
|
BlockSize: 128 * 1024,
|
|
|
|
IgnoreFile: ".stignore",
|
|
|
|
}
|
2014-08-26 01:11:25 -07:00
|
|
|
_, err := w.Walk()
|
2014-05-04 09:20:25 -07:00
|
|
|
|
|
|
|
if err == nil {
|
|
|
|
t.Error("no error from missing directory")
|
|
|
|
}
|
|
|
|
|
|
|
|
w = Walker{
|
|
|
|
Dir: "testdata/bar",
|
|
|
|
BlockSize: 128 * 1024,
|
|
|
|
IgnoreFile: ".stignore",
|
|
|
|
}
|
2014-08-26 01:11:25 -07:00
|
|
|
_, err = w.Walk()
|
2014-05-04 09:20:25 -07:00
|
|
|
|
|
|
|
if err == nil {
|
|
|
|
t.Error("no error from non-directory")
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2014-03-02 15:58:14 -07:00
|
|
|
func TestIgnore(t *testing.T) {
|
2014-08-26 01:11:25 -07:00
|
|
|
patStr := bytes.NewBufferString(`
|
|
|
|
t2
|
|
|
|
/t3
|
|
|
|
sub/dir/*
|
|
|
|
*/other/test
|
|
|
|
**/deep
|
|
|
|
`)
|
2014-08-31 14:32:27 -07:00
|
|
|
patterns := parseIgnoreFile(patStr, "", "", make(map[string]map[string]bool))
|
2014-08-26 01:11:25 -07:00
|
|
|
|
|
|
|
patStr = bytes.NewBufferString(`
|
|
|
|
bar
|
|
|
|
z*
|
|
|
|
q[abc]x
|
|
|
|
`)
|
2014-08-31 14:32:27 -07:00
|
|
|
patterns = append(patterns, parseIgnoreFile(patStr, "foo", "", make(map[string]map[string]bool))...)
|
2014-08-26 01:11:25 -07:00
|
|
|
|
|
|
|
patStr = bytes.NewBufferString(`
|
|
|
|
quux
|
|
|
|
.*
|
|
|
|
`)
|
2014-08-31 14:32:27 -07:00
|
|
|
patterns = append(patterns, parseIgnoreFile(patStr, "foo/baz", "", make(map[string]map[string]bool))...)
|
2014-08-16 09:33:01 -07:00
|
|
|
|
2014-03-02 15:58:14 -07:00
|
|
|
var tests = []struct {
|
|
|
|
f string
|
|
|
|
r bool
|
|
|
|
}{
|
2014-08-16 09:33:01 -07:00
|
|
|
{filepath.Join("foo", "bar"), true},
|
2014-08-26 01:11:25 -07:00
|
|
|
{filepath.Join("t3"), true},
|
2014-08-16 09:33:01 -07:00
|
|
|
{filepath.Join("foofoo"), false},
|
|
|
|
{filepath.Join("foo", "quux"), false},
|
|
|
|
{filepath.Join("foo", "zuux"), true},
|
|
|
|
{filepath.Join("foo", "qzuux"), false},
|
|
|
|
{filepath.Join("foo", "baz", "t1"), false},
|
|
|
|
{filepath.Join("foo", "baz", "t2"), true},
|
2014-08-26 01:11:25 -07:00
|
|
|
{filepath.Join("foo", "baz", "t3"), false},
|
2014-08-16 09:33:01 -07:00
|
|
|
{filepath.Join("foo", "baz", "bar"), true},
|
|
|
|
{filepath.Join("foo", "baz", "quuxa"), false},
|
|
|
|
{filepath.Join("foo", "baz", "aquux"), false},
|
|
|
|
{filepath.Join("foo", "baz", ".quux"), true},
|
|
|
|
{filepath.Join("foo", "baz", "zquux"), true},
|
|
|
|
{filepath.Join("foo", "baz", "quux"), true},
|
|
|
|
{filepath.Join("foo", "bazz", "quux"), false},
|
2014-08-26 01:11:25 -07:00
|
|
|
{filepath.Join("sub", "dir", "hej"), true},
|
|
|
|
{filepath.Join("deeper", "sub", "dir", "hej"), true},
|
|
|
|
{filepath.Join("other", "test"), false},
|
|
|
|
{filepath.Join("sub", "other", "test"), true},
|
|
|
|
{filepath.Join("deeper", "sub", "other", "test"), true},
|
|
|
|
{filepath.Join("deep"), true},
|
|
|
|
{filepath.Join("deeper", "deep"), true},
|
|
|
|
{filepath.Join("deeper", "deeper", "deep"), true},
|
2014-03-02 15:58:14 -07:00
|
|
|
}
|
|
|
|
|
2014-03-08 15:02:01 -07:00
|
|
|
w := Walker{}
|
2014-03-02 15:58:14 -07:00
|
|
|
for i, tc := range tests {
|
2014-03-08 15:02:01 -07:00
|
|
|
if r := w.ignoreFile(patterns, tc.f); r != tc.r {
|
2014-08-16 09:33:01 -07:00
|
|
|
t.Errorf("Incorrect ignoreFile() #%d (%s); E: %v, A: %v", i, tc.f, tc.r, r)
|
2014-03-02 15:58:14 -07:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2014-07-30 11:10:46 -07:00
|
|
|
|
|
|
|
type fileList []protocol.FileInfo
|
|
|
|
|
|
|
|
func (f fileList) Len() int {
|
|
|
|
return len(f)
|
|
|
|
}
|
|
|
|
|
|
|
|
func (f fileList) Less(a, b int) bool {
|
|
|
|
return f[a].Name < f[b].Name
|
|
|
|
}
|
|
|
|
|
|
|
|
func (f fileList) Swap(a, b int) {
|
|
|
|
f[a], f[b] = f[b], f[a]
|
|
|
|
}
|
2014-08-30 00:22:23 -07:00
|
|
|
|
|
|
|
func (l fileList) testfiles() testfileList {
|
|
|
|
testfiles := make(testfileList, len(l))
|
|
|
|
for i, f := range l {
|
|
|
|
if len(f.Blocks) > 1 {
|
|
|
|
panic("simple test case stuff only supports a single block per file")
|
|
|
|
}
|
|
|
|
testfiles[i] = testfile{name: f.Name, size: int(f.Size())}
|
|
|
|
if len(f.Blocks) == 1 {
|
|
|
|
testfiles[i].hash = fmt.Sprintf("%x", f.Blocks[0].Hash)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return testfiles
|
|
|
|
}
|
|
|
|
|
|
|
|
func (l testfileList) String() string {
|
|
|
|
var b bytes.Buffer
|
|
|
|
b.WriteString("{\n")
|
|
|
|
for _, f := range l {
|
|
|
|
fmt.Fprintf(&b, " %s (%d bytes): %s\n", f.name, f.size, f.hash)
|
|
|
|
}
|
|
|
|
b.WriteString("}")
|
|
|
|
return b.String()
|
|
|
|
}
|