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 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166
|
package mtree
import (
"encoding/json"
"os"
"path/filepath"
"testing"
"time"
)
var mockTime = time.Unix(1337888823, 0)
// Here be some dodgy testing. In particular, we have to mess around with some
// of the FsEval functions. In particular, we change all of the FileInfos to a
// different value.
type mockFileInfo struct {
os.FileInfo
}
func (fi mockFileInfo) Mode() os.FileMode {
return os.FileMode(fi.FileInfo.Mode() | 0777)
}
func (fi mockFileInfo) ModTime() time.Time {
return mockTime
}
type MockFsEval struct {
open, lstat, readdir, keywordFunc int
}
// Open must have the same semantics as os.Open.
func (fs *MockFsEval) Open(path string) (*os.File, error) {
fs.open++
return os.Open(path)
}
// Lstat must have the same semantics as os.Lstat.
func (fs *MockFsEval) Lstat(path string) (os.FileInfo, error) {
fs.lstat++
fi, err := os.Lstat(path)
return mockFileInfo{fi}, err
}
// Readdir must have the same semantics as calling os.Open on the given
// path and then returning the result of (*os.File).Readdir(-1).
func (fs *MockFsEval) Readdir(path string) ([]os.FileInfo, error) {
fs.readdir++
fh, err := os.Open(path)
if err != nil {
return nil, err
}
defer fh.Close()
fis, err := fh.Readdir(-1)
if err != nil {
return nil, err
}
for idx := range fis {
fis[idx] = mockFileInfo{fis[idx]}
}
return fis, nil
}
// KeywordFunc must return a wrapper around the provided function (in other
// words, the returned function must refer to the same keyword).
func (fs *MockFsEval) KeywordFunc(fn KeywordFunc) KeywordFunc {
fs.keywordFunc++
return fn
}
//gocyclo:ignore
func TestCheckFsEval(t *testing.T) {
dir, err := os.MkdirTemp("", "test-check-fs-eval")
if err != nil {
t.Fatal(err)
}
defer os.RemoveAll(dir) // clean up
content := []byte("If you hide your ignorance, no one will hit you and you'll never learn.")
tmpfn := filepath.Join(dir, "tmpfile")
if err := os.WriteFile(tmpfn, content, 0451); err != nil {
t.Fatal(err)
}
// Walk this tempdir
mock := &MockFsEval{}
dh, err := Walk(dir, nil, append(DefaultKeywords, "sha1"), mock)
if err != nil {
t.Fatal(err)
}
// Make sure that mock functions have been called.
if mock.open == 0 {
t.Errorf("mock.Open not called")
}
if mock.lstat == 0 {
t.Errorf("mock.Lstat not called")
}
if mock.readdir == 0 {
t.Errorf("mock.Readdir not called")
}
if mock.keywordFunc == 0 {
t.Errorf("mock.KeywordFunc not called")
}
// Check for sanity. This ought to pass.
mock = &MockFsEval{}
res, err := Check(dir, dh, nil, mock)
if err != nil {
t.Fatal(err)
}
if len(res) > 0 {
t.Errorf("%#v", res)
}
// Make sure that mock functions have been called.
if mock.open == 0 {
t.Errorf("mock.Open not called")
}
if mock.lstat == 0 {
t.Errorf("mock.Lstat not called")
}
if mock.readdir == 0 {
t.Errorf("mock.Readdir not called")
}
if mock.keywordFunc == 0 {
t.Errorf("mock.KeywordFunc not called")
}
// This should FAIL.
res, err = Check(dir, dh, nil, nil)
if err != nil {
t.Fatal(err)
}
if len(res) == 0 {
t.Errorf("expected Check to fail")
}
// Modify the metadata so you can get the right output.
if err := os.Chmod(tmpfn, 0777); err != nil {
t.Fatal(err)
}
if err := os.Chtimes(tmpfn, mockTime, mockTime); err != nil {
t.Fatal(err)
}
if err := os.Chmod(dir, 0777); err != nil {
t.Fatal(err)
}
if err := os.Chtimes(dir, mockTime, mockTime); err != nil {
t.Fatal(err)
}
// It should now succeed.
res, err = Check(dir, dh, nil, nil)
if err != nil {
t.Fatal(err)
}
if len(res) > 0 {
buf, err := json.MarshalIndent(res, "", " ")
if err != nil {
t.Errorf("%#v", res)
} else {
t.Errorf("%s", buf)
}
}
}
|