rclone/fstest/mockfs/mockfs.go
2023-04-28 14:31:05 +01:00

154 lines
3.8 KiB
Go

// Package mockfs provides mock Fs for testing.
package mockfs
import (
"context"
"errors"
"fmt"
"io"
"path"
"time"
"github.com/rclone/rclone/fs"
"github.com/rclone/rclone/fs/config/configmap"
"github.com/rclone/rclone/fs/hash"
)
// Register with Fs
func Register() {
fs.Register(&fs.RegInfo{
Name: "mockfs",
Description: "Mock FS",
NewFs: NewFs,
Options: []fs.Option{{
Name: "potato",
Help: "Does it have a potato?.",
Required: true,
}},
})
}
// Fs is a minimal mock Fs
type Fs struct {
name string // the name of the remote
root string // The root directory (OS path)
features *fs.Features // optional features
rootDir fs.DirEntries // directory listing of root
hashes hash.Set // which hashes we support
}
// ErrNotImplemented is returned by unimplemented methods
var ErrNotImplemented = errors.New("not implemented")
// NewFs returns a new mock Fs
func NewFs(ctx context.Context, name string, root string, config configmap.Mapper) (fs.Fs, error) {
f := &Fs{
name: name,
root: root,
}
f.features = (&fs.Features{}).Fill(ctx, f)
return f, nil
}
// AddObject adds an Object for List to return
// Only works for the root for the moment
func (f *Fs) AddObject(o fs.Object) {
f.rootDir = append(f.rootDir, o)
// Make this object part of mockfs if possible
do, ok := o.(interface{ SetFs(f fs.Fs) })
if ok {
do.SetFs(f)
}
}
// Name of the remote (as passed into NewFs)
func (f *Fs) Name() string {
return f.name
}
// Root of the remote (as passed into NewFs)
func (f *Fs) Root() string {
return f.root
}
// String returns a description of the FS
func (f *Fs) String() string {
return fmt.Sprintf("Mock file system at %s", f.root)
}
// Precision of the ModTimes in this Fs
func (f *Fs) Precision() time.Duration {
return time.Second
}
// Hashes returns the supported hash types of the filesystem
func (f *Fs) Hashes() hash.Set {
return f.hashes
}
// SetHashes sets the hashes that this supports
func (f *Fs) SetHashes(hashes hash.Set) {
f.hashes = hashes
}
// Features returns the optional features of this Fs
func (f *Fs) Features() *fs.Features {
return f.features
}
// List the objects and directories in dir into entries. The
// entries can be returned in any order but should be for a
// complete directory.
//
// dir should be "" to list the root, and should not have
// trailing slashes.
//
// This should return ErrDirNotFound if the directory isn't
// found.
func (f *Fs) List(ctx context.Context, dir string) (entries fs.DirEntries, err error) {
if dir == "" {
return f.rootDir, nil
}
return entries, fs.ErrorDirNotFound
}
// NewObject finds the Object at remote. If it can't be found
// it returns the error ErrorObjectNotFound.
func (f *Fs) NewObject(ctx context.Context, remote string) (fs.Object, error) {
dirPath := path.Dir(remote)
if dirPath == "" || dirPath == "." {
for _, entry := range f.rootDir {
if entry.Remote() == remote {
return entry.(fs.Object), nil
}
}
}
return nil, fs.ErrorObjectNotFound
}
// Put in to the remote path with the modTime given of the given size
//
// May create the object even if it returns an error - if so
// will return the object and the error, otherwise will return
// nil and the error
func (f *Fs) Put(ctx context.Context, in io.Reader, src fs.ObjectInfo, options ...fs.OpenOption) (fs.Object, error) {
return nil, ErrNotImplemented
}
// Mkdir makes the directory (container, bucket)
//
// Shouldn't return an error if it already exists
func (f *Fs) Mkdir(ctx context.Context, dir string) error {
return ErrNotImplemented
}
// Rmdir removes the directory (container, bucket) if empty
//
// Return an error if it doesn't exist or isn't empty
func (f *Fs) Rmdir(ctx context.Context, dir string) error {
return ErrNotImplemented
}
// Assert it is the correct type
var _ fs.Fs = (*Fs)(nil)