gobot.io/x/gobot@v1.16.0/sysfs/fs_mock.go (about) 1 package sysfs 2 3 import ( 4 "errors" 5 "io/ioutil" 6 "os" 7 "strings" 8 "time" 9 ) 10 11 var _ File = (*MockFile)(nil) 12 var _ Filesystem = (*MockFilesystem)(nil) 13 14 // MockFilesystem represents a filesystem of mock files. 15 type MockFilesystem struct { 16 Seq int // Increases with each write or read. 17 Files map[string]*MockFile 18 WithReadError bool 19 WithWriteError bool 20 } 21 22 // A MockFile represents a mock file that contains a single string. Any write 23 // overwrites, and any read returns from the start. 24 type MockFile struct { 25 Contents string 26 Seq int // When this file was last written or read. 27 Opened bool 28 Closed bool 29 fd uintptr 30 31 fs *MockFilesystem 32 } 33 34 var ( 35 readErr = errors.New("read error") 36 writeErr = errors.New("write error") 37 ) 38 39 // Write writes string(b) to f.Contents 40 func (f *MockFile) Write(b []byte) (n int, err error) { 41 if f.fs.WithWriteError { 42 return 0, writeErr 43 } 44 return f.WriteString(string(b)) 45 } 46 47 // Seek seeks to a specific offset in a file 48 func (f *MockFile) Seek(offset int64, whence int) (ret int64, err error) { 49 return offset, nil 50 } 51 52 // WriteString writes s to f.Contents 53 func (f *MockFile) WriteString(s string) (ret int, err error) { 54 f.Contents = s 55 f.Seq = f.fs.next() 56 return len(s), nil 57 } 58 59 // Sync implements the File interface Sync function 60 func (f *MockFile) Sync() (err error) { 61 return nil 62 } 63 64 // Read copies b bytes from f.Contents 65 func (f *MockFile) Read(b []byte) (n int, err error) { 66 if f.fs.WithReadError { 67 return 0, readErr 68 } 69 70 count := len(b) 71 if len(f.Contents) < count { 72 count = len(f.Contents) 73 } 74 copy(b, []byte(f.Contents)[:count]) 75 f.Seq = f.fs.next() 76 77 return count, nil 78 } 79 80 // ReadAt calls MockFile.Read 81 func (f *MockFile) ReadAt(b []byte, off int64) (n int, err error) { 82 return f.Read(b) 83 } 84 85 // Fd returns a random uintprt based on the time of the MockFile creation 86 func (f *MockFile) Fd() uintptr { 87 return f.fd 88 } 89 90 // Close implements the File interface Close function 91 func (f *MockFile) Close() error { 92 return nil 93 } 94 95 // NewMockFilesystem returns a new MockFilesystem given a list of file paths 96 func NewMockFilesystem(files []string) *MockFilesystem { 97 m := &MockFilesystem{ 98 Files: make(map[string]*MockFile), 99 } 100 101 for i := range files { 102 m.Add(files[i]) 103 } 104 105 return m 106 } 107 108 // OpenFile opens file name from fs.Files, if the file does not exist it returns an os.PathError 109 func (fs *MockFilesystem) OpenFile(name string, flag int, perm os.FileMode) (file File, err error) { 110 f, ok := fs.Files[name] 111 if ok { 112 f.Opened = true 113 f.Closed = false 114 return f, nil 115 } 116 return (*MockFile)(nil), &os.PathError{Err: errors.New(name + ": No such file.")} 117 } 118 119 // Stat returns a generic FileInfo for all files in fs.Files. 120 // If the file does not exist it returns an os.PathError 121 func (fs *MockFilesystem) Stat(name string) (os.FileInfo, error) { 122 _, ok := fs.Files[name] 123 if ok { 124 // return file based mock FileInfo 125 tmpFile, err := ioutil.TempFile("", name) 126 if err != nil { 127 return nil, err 128 } 129 defer os.Remove(tmpFile.Name()) 130 131 return os.Stat(tmpFile.Name()) 132 } 133 134 dirName := name + "/" 135 for path := range fs.Files { 136 if strings.HasPrefix(path, dirName) { 137 // return dir based mock FileInfo 138 tmpDir, err := ioutil.TempDir("", name) 139 if err != nil { 140 return nil, err 141 } 142 defer os.RemoveAll(tmpDir) 143 144 return os.Stat(tmpDir) 145 } 146 } 147 148 return nil, &os.PathError{Err: errors.New(name + ": No such file.")} 149 } 150 151 // Add adds a new file to fs.Files given a name, and returns the newly created file 152 func (fs *MockFilesystem) Add(name string) *MockFile { 153 f := &MockFile{ 154 Seq: -1, 155 fd: uintptr(time.Now().UnixNano() & 0xffff), 156 fs: fs, 157 } 158 fs.Files[name] = f 159 return f 160 } 161 162 func (fs *MockFilesystem) next() int { 163 fs.Seq++ 164 return fs.Seq 165 }