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  }