1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
|
package testsuite
import (
"errors"
"fmt"
"io/fs"
"path/filepath"
"strings"
)
var (
// ErrFSBadLength is returned by [FS.Compare] for a directory with an
// unexpected amount of dents.
ErrFSBadLength = errors.New("bad dir length")
// ErrFSBadData is returned by [FS.Compare] for a file with unexpected
// contents.
ErrFSBadData = errors.New("data differs")
// ErrFSBadMode is returned by [FS.Compare] for an entry with unexpected
// mode.
ErrFSBadMode = errors.New("mode differs")
// ErrFSInvalidEnt is returned by [FS.Compare] if an invalid [FS] is visited.
ErrFSInvalidEnt = errors.New("invalid entry condition")
)
// FS represents part of a filesystem hierarchy.
type FS struct {
// Expected mode of corresponding entry.
Mode fs.FileMode `json:"mode"`
// Expected directory contents. The directory is not descended if Dir is nil.
Dir map[string]*FS `json:"dir"`
// Expected file contents. The file is not read if Data is nil.
Data *string `json:"data"`
}
// dprintf calls printf if it is non-nil.
func dprintf(printf func(format string, a ...any), format string, a ...any) {
if printf == nil {
return
}
printf(format, a...)
}
// printDir prints a failed [FS.Compare] directory.
func printDir(
printf func(format string, a ...any),
prefix string,
dir []fs.DirEntry,
) {
names := make([]string, len(dir))
for i, ent := range dir {
name := ent.Name()
if ent.IsDir() {
name += "/"
}
names[i] = fmt.Sprintf("%q", name)
}
dprintf(printf, "[FAIL] d %s: %s", prefix, strings.Join(names, " "))
}
// Compare compares the contents of prefix against the hierarchy described by s.
func (s *FS) Compare(
printf func(format string, a ...any),
prefix string,
e fs.FS,
) error {
if s.Data != nil {
if s.Dir != nil {
panic("invalid state")
}
panic("invalid compare call")
}
if s.Dir == nil {
dprintf(printf, "[ OK ] s %s", prefix)
return nil
}
var dir []fs.DirEntry
if d, err := fs.ReadDir(e, prefix); err != nil {
return err
} else if len(d) != len(s.Dir) {
printDir(printf, prefix, d)
return ErrFSBadLength
} else {
dir = d
}
for _, got := range dir {
name := got.Name()
if want, ok := s.Dir[name]; !ok {
printDir(printf, prefix, dir)
return fs.ErrNotExist
} else if want.Dir != nil && !got.IsDir() {
printDir(printf, prefix, dir)
return ErrFSInvalidEnt
} else {
name = filepath.Join(prefix, name)
if fi, err := got.Info(); err != nil {
return err
} else if fi.Mode() != want.Mode {
dprintf(printf, "[FAIL] m %s: %#o, want %#o",
name, uint32(fi.Mode()), uint32(want.Mode))
return ErrFSBadMode
}
if want.Data != nil {
if want.Dir != nil {
panic("invalid state")
}
if v, err := fs.ReadFile(e, name); err != nil {
return err
} else if string(v) != *want.Data {
dprintf(printf,
"[FAIL] f %s\n\t got: %s\n\twant: %s",
name, v, *want.Data,
)
return ErrFSBadData
}
dprintf(printf, "[ OK ] f %s", name)
} else if err := want.Compare(printf, name, e); err != nil {
return err
}
}
}
dprintf(printf, "[ OK ] d %s", prefix)
return nil
}
|