github.com/rclone/rclone@v1.66.1-0.20240517100346-7b89735ae726/fstest/mockfs/mockfs.go (about) 1 // Package mockfs provides mock Fs for testing. 2 package mockfs 3 4 import ( 5 "context" 6 "errors" 7 "fmt" 8 "io" 9 "path" 10 "time" 11 12 "github.com/rclone/rclone/fs" 13 "github.com/rclone/rclone/fs/config/configmap" 14 "github.com/rclone/rclone/fs/hash" 15 ) 16 17 // Register with Fs 18 func Register() { 19 fs.Register(&fs.RegInfo{ 20 Name: "mockfs", 21 Description: "Mock FS", 22 NewFs: NewFs, 23 Options: []fs.Option{{ 24 Name: "potato", 25 Help: "Does it have a potato?.", 26 Required: true, 27 }}, 28 }) 29 } 30 31 // Fs is a minimal mock Fs 32 type Fs struct { 33 name string // the name of the remote 34 root string // The root directory (OS path) 35 features *fs.Features // optional features 36 rootDir fs.DirEntries // directory listing of root 37 hashes hash.Set // which hashes we support 38 } 39 40 // ErrNotImplemented is returned by unimplemented methods 41 var ErrNotImplemented = errors.New("not implemented") 42 43 // NewFs returns a new mock Fs 44 func NewFs(ctx context.Context, name string, root string, config configmap.Mapper) (fs.Fs, error) { 45 f := &Fs{ 46 name: name, 47 root: root, 48 } 49 f.features = (&fs.Features{}).Fill(ctx, f) 50 return f, nil 51 } 52 53 // AddObject adds an Object for List to return 54 // Only works for the root for the moment 55 func (f *Fs) AddObject(o fs.Object) { 56 f.rootDir = append(f.rootDir, o) 57 // Make this object part of mockfs if possible 58 do, ok := o.(interface{ SetFs(f fs.Fs) }) 59 if ok { 60 do.SetFs(f) 61 } 62 } 63 64 // Name of the remote (as passed into NewFs) 65 func (f *Fs) Name() string { 66 return f.name 67 } 68 69 // Root of the remote (as passed into NewFs) 70 func (f *Fs) Root() string { 71 return f.root 72 } 73 74 // String returns a description of the FS 75 func (f *Fs) String() string { 76 return fmt.Sprintf("Mock file system at %s", f.root) 77 } 78 79 // Precision of the ModTimes in this Fs 80 func (f *Fs) Precision() time.Duration { 81 return time.Second 82 } 83 84 // Hashes returns the supported hash types of the filesystem 85 func (f *Fs) Hashes() hash.Set { 86 return f.hashes 87 } 88 89 // SetHashes sets the hashes that this supports 90 func (f *Fs) SetHashes(hashes hash.Set) { 91 f.hashes = hashes 92 } 93 94 // Features returns the optional features of this Fs 95 func (f *Fs) Features() *fs.Features { 96 return f.features 97 } 98 99 // List the objects and directories in dir into entries. The 100 // entries can be returned in any order but should be for a 101 // complete directory. 102 // 103 // dir should be "" to list the root, and should not have 104 // trailing slashes. 105 // 106 // This should return ErrDirNotFound if the directory isn't 107 // found. 108 func (f *Fs) List(ctx context.Context, dir string) (entries fs.DirEntries, err error) { 109 if dir == "" { 110 return f.rootDir, nil 111 } 112 return entries, fs.ErrorDirNotFound 113 } 114 115 // NewObject finds the Object at remote. If it can't be found 116 // it returns the error ErrorObjectNotFound. 117 func (f *Fs) NewObject(ctx context.Context, remote string) (fs.Object, error) { 118 dirPath := path.Dir(remote) 119 if dirPath == "" || dirPath == "." { 120 for _, entry := range f.rootDir { 121 if entry.Remote() == remote { 122 return entry.(fs.Object), nil 123 } 124 } 125 } 126 return nil, fs.ErrorObjectNotFound 127 } 128 129 // Put in to the remote path with the modTime given of the given size 130 // 131 // May create the object even if it returns an error - if so 132 // will return the object and the error, otherwise will return 133 // nil and the error 134 func (f *Fs) Put(ctx context.Context, in io.Reader, src fs.ObjectInfo, options ...fs.OpenOption) (fs.Object, error) { 135 return nil, ErrNotImplemented 136 } 137 138 // Mkdir makes the directory (container, bucket) 139 // 140 // Shouldn't return an error if it already exists 141 func (f *Fs) Mkdir(ctx context.Context, dir string) error { 142 return ErrNotImplemented 143 } 144 145 // Rmdir removes the directory (container, bucket) if empty 146 // 147 // Return an error if it doesn't exist or isn't empty 148 func (f *Fs) Rmdir(ctx context.Context, dir string) error { 149 return ErrNotImplemented 150 } 151 152 // Assert it is the correct type 153 var _ fs.Fs = (*Fs)(nil)