GoPLS Viewer

Home|gopls/internal/fastwalk/fastwalk_test.go
1// Copyright 2016 The Go Authors. All rights reserved.
2// Use of this source code is governed by a BSD-style
3// license that can be found in the LICENSE file.
4
5package fastwalk_test
6
7import (
8    "bytes"
9    "flag"
10    "fmt"
11    "io/ioutil"
12    "os"
13    "path/filepath"
14    "reflect"
15    "runtime"
16    "sort"
17    "strings"
18    "sync"
19    "testing"
20
21    "golang.org/x/tools/internal/fastwalk"
22)
23
24func formatFileModes(m map[string]os.FileModestring {
25    var keys []string
26    for k := range m {
27        keys = append(keysk)
28    }
29    sort.Strings(keys)
30    var buf bytes.Buffer
31    for _k := range keys {
32        fmt.Fprintf(&buf"%-20s: %v\n"km[k])
33    }
34    return buf.String()
35}
36
37func testFastWalk(t *testing.Tfiles map[string]stringcallback func(path stringtyp os.FileModeerrorwant map[string]os.FileMode) {
38    tempdirerr := ioutil.TempDir("""test-fast-walk")
39    if err != nil {
40        t.Fatal(err)
41    }
42    defer os.RemoveAll(tempdir)
43
44    symlinks := map[string]string{}
45    for pathcontents := range files {
46        file := filepath.Join(tempdir"/src"path)
47        if err := os.MkdirAll(filepath.Dir(file), 0755); err != nil {
48            t.Fatal(err)
49        }
50        var err error
51        if strings.HasPrefix(contents"LINK:") {
52            symlinks[file] = filepath.FromSlash(strings.TrimPrefix(contents"LINK:"))
53        } else {
54            err = ioutil.WriteFile(file, []byte(contents), 0644)
55        }
56        if err != nil {
57            t.Fatal(err)
58        }
59    }
60
61    // Create symlinks after all other files. Otherwise, directory symlinks on
62    // Windows are unusable (see https://golang.org/issue/39183).
63    for filedst := range symlinks {
64        err = os.Symlink(dstfile)
65        if err != nil {
66            if writeErr := ioutil.WriteFile(file, []byte(dst), 0644); writeErr == nil {
67                // Couldn't create symlink, but could write the file.
68                // Probably this filesystem doesn't support symlinks.
69                // (Perhaps we are on an older Windows and not running as administrator.)
70                t.Skipf("skipping because symlinks appear to be unsupported: %v"err)
71            }
72        }
73    }
74
75    got := map[string]os.FileMode{}
76    var mu sync.Mutex
77    err = fastwalk.Walk(tempdir, func(path stringtyp os.FileModeerror {
78        mu.Lock()
79        defer mu.Unlock()
80        if !strings.HasPrefix(pathtempdir) {
81            t.Errorf("bogus prefix on %q, expect %q"pathtempdir)
82        }
83        key := filepath.ToSlash(strings.TrimPrefix(pathtempdir))
84        if olddup := got[key]; dup {
85            t.Errorf("callback called twice for key %q: %v -> %v"keyoldtyp)
86        }
87        got[key] = typ
88        return callback(pathtyp)
89    })
90
91    if err != nil {
92        t.Fatalf("callback returned: %v"err)
93    }
94    if !reflect.DeepEqual(gotwant) {
95        t.Errorf("walk mismatch.\n got:\n%v\nwant:\n%v"formatFileModes(got), formatFileModes(want))
96    }
97}
98
99func TestFastWalk_Basic(t *testing.T) {
100    testFastWalk(t, map[string]string{
101        "foo/foo.go":   "one",
102        "bar/bar.go":   "two",
103        "skip/skip.go""skip",
104    },
105        func(path stringtyp os.FileModeerror {
106            return nil
107        },
108        map[string]os.FileMode{
109            "":                  os.ModeDir,
110            "/src":              os.ModeDir,
111            "/src/bar":          os.ModeDir,
112            "/src/bar/bar.go":   0,
113            "/src/foo":          os.ModeDir,
114            "/src/foo/foo.go":   0,
115            "/src/skip":         os.ModeDir,
116            "/src/skip/skip.go"0,
117        })
118}
119
120func TestFastWalk_LongFileName(t *testing.T) {
121    longFileName := strings.Repeat("x"255)
122
123    testFastWalk(t, map[string]string{
124        longFileName"one",
125    },
126        func(path stringtyp os.FileModeerror {
127            return nil
128        },
129        map[string]os.FileMode{
130            "":                     os.ModeDir,
131            "/src":                 os.ModeDir,
132            "/src/" + longFileName0,
133        },
134    )
135}
136
137func TestFastWalk_Symlink(t *testing.T) {
138    testFastWalk(t, map[string]string{
139        "foo/foo.go":       "one",
140        "bar/bar.go":       "LINK:../foo/foo.go",
141        "symdir":           "LINK:foo",
142        "broken/broken.go""LINK:../nonexistent",
143    },
144        func(path stringtyp os.FileModeerror {
145            return nil
146        },
147        map[string]os.FileMode{
148            "":                      os.ModeDir,
149            "/src":                  os.ModeDir,
150            "/src/bar":              os.ModeDir,
151            "/src/bar/bar.go":       os.ModeSymlink,
152            "/src/foo":              os.ModeDir,
153            "/src/foo/foo.go":       0,
154            "/src/symdir":           os.ModeSymlink,
155            "/src/broken":           os.ModeDir,
156            "/src/broken/broken.go"os.ModeSymlink,
157        })
158}
159
160func TestFastWalk_SkipDir(t *testing.T) {
161    testFastWalk(t, map[string]string{
162        "foo/foo.go":   "one",
163        "bar/bar.go":   "two",
164        "skip/skip.go""skip",
165    },
166        func(path stringtyp os.FileModeerror {
167            if typ == os.ModeDir && strings.HasSuffix(path"skip") {
168                return filepath.SkipDir
169            }
170            return nil
171        },
172        map[string]os.FileMode{
173            "":                os.ModeDir,
174            "/src":            os.ModeDir,
175            "/src/bar":        os.ModeDir,
176            "/src/bar/bar.go"0,
177            "/src/foo":        os.ModeDir,
178            "/src/foo/foo.go"0,
179            "/src/skip":       os.ModeDir,
180        })
181}
182
183func TestFastWalk_SkipFiles(t *testing.T) {
184    // Directory iteration order is undefined, so there's no way to know
185    // which file to expect until the walk happens. Rather than mess
186    // with the test infrastructure, just mutate want.
187    var mu sync.Mutex
188    want := map[string]os.FileMode{
189        "":              os.ModeDir,
190        "/src":          os.ModeDir,
191        "/src/zzz":      os.ModeDir,
192        "/src/zzz/c.go"0,
193    }
194
195    testFastWalk(t, map[string]string{
196        "a_skipfiles.go""a",
197        "b_skipfiles.go""b",
198        "zzz/c.go":       "c",
199    },
200        func(path stringtyp os.FileModeerror {
201            if strings.HasSuffix(path"_skipfiles.go") {
202                mu.Lock()
203                defer mu.Unlock()
204                want["/src/"+filepath.Base(path)] = 0
205                return fastwalk.ErrSkipFiles
206            }
207            return nil
208        },
209        want)
210    if len(want) != 5 {
211        t.Errorf("saw too many files: wanted 5, got %v (%v)"len(want), want)
212    }
213}
214
215func TestFastWalk_TraverseSymlink(t *testing.T) {
216    testFastWalk(t, map[string]string{
217        "foo/foo.go":   "one",
218        "bar/bar.go":   "two",
219        "skip/skip.go""skip",
220        "symdir":       "LINK:foo",
221    },
222        func(path stringtyp os.FileModeerror {
223            if typ == os.ModeSymlink {
224                return fastwalk.ErrTraverseLink
225            }
226            return nil
227        },
228        map[string]os.FileMode{
229            "":                   os.ModeDir,
230            "/src":               os.ModeDir,
231            "/src/bar":           os.ModeDir,
232            "/src/bar/bar.go":    0,
233            "/src/foo":           os.ModeDir,
234            "/src/foo/foo.go":    0,
235            "/src/skip":          os.ModeDir,
236            "/src/skip/skip.go":  0,
237            "/src/symdir":        os.ModeSymlink,
238            "/src/symdir/foo.go"0,
239        })
240}
241
242var benchDir = flag.String("benchdir"runtime.GOROOT(), "The directory to scan for BenchmarkFastWalk")
243
244func BenchmarkFastWalk(b *testing.B) {
245    b.ReportAllocs()
246    for i := 0i < b.Ni++ {
247        err := fastwalk.Walk(*benchDir, func(path stringtyp os.FileModeerror { return nil })
248        if err != nil {
249            b.Fatal(err)
250        }
251    }
252}
253
MembersX
fastwalk
testFastWalk.RangeStmt_911.contents
testFastWalk.BlockStmt.key
TestFastWalk_LongFileName.t
TestFastWalk_SkipDir
testFastWalk.callback
testFastWalk.RangeStmt_911.path
TestFastWalk_Symlink
testFastWalk.got
TestFastWalk_Basic.t
TestFastWalk_LongFileName
reflect
formatFileModes.RangeStmt_523.k
testFastWalk.t
testFastWalk.RangeStmt_911.BlockStmt.file
testFastWalk.RangeStmt_1469.BlockStmt.BlockStmt.writeErr
TestFastWalk_SkipFiles.mu
BenchmarkFastWalk.i
testFastWalk.RangeStmt_1469.file
TestFastWalk_SkipDir.t
TestFastWalk_SkipFiles
fmt
formatFileModes.m
formatFileModes.buf
testFastWalk.tempdir
testFastWalk.err
TestFastWalk_SkipFiles.want
formatFileModes.keys
testFastWalk.files
testFastWalk.RangeStmt_1469.dst
TestFastWalk_SkipFiles.t
BenchmarkFastWalk.BlockStmt.err
sort
testFastWalk.RangeStmt_911.BlockStmt.err
TestFastWalk_LongFileName.longFileName
TestFastWalk_TraverseSymlink
TestFastWalk_TraverseSymlink.t
flag
strings
testFastWalk.symlinks
testFastWalk.mu
TestFastWalk_Symlink.t
TestFastWalk_Basic
BenchmarkFastWalk
BenchmarkFastWalk.b
testing
formatFileModes
formatFileModes.RangeStmt_433.k
testFastWalk
testFastWalk.want
Members
X