123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236 |
- // Package mockobject provides a mock object which can be created from a string
- package mockobject
- import (
- "bytes"
- "context"
- "errors"
- "fmt"
- "io"
- "time"
- "github.com/rclone/rclone/fs"
- "github.com/rclone/rclone/fs/hash"
- )
- var errNotImpl = errors.New("not implemented")
- // Object is a mock fs.Object useful for testing
- type Object string
- // New returns mock fs.Object useful for testing
- func New(name string) Object {
- return Object(name)
- }
- // String returns a description of the Object
- func (o Object) String() string {
- return string(o)
- }
- // Fs returns read only access to the Fs that this object is part of
- func (o Object) Fs() fs.Info {
- return nil
- }
- // Remote returns the remote path
- func (o Object) Remote() string {
- return string(o)
- }
- // Hash returns the selected checksum of the file
- // If no checksum is available it returns ""
- func (o Object) Hash(ctx context.Context, t hash.Type) (string, error) {
- return "", errNotImpl
- }
- // ModTime returns the modification date of the file
- // It should return a best guess if one isn't available
- func (o Object) ModTime(ctx context.Context) (t time.Time) {
- return t
- }
- // Size returns the size of the file
- func (o Object) Size() int64 { return 0 }
- // Storable says whether this object can be stored
- func (o Object) Storable() bool {
- return true
- }
- // SetModTime sets the metadata on the object to set the modification date
- func (o Object) SetModTime(ctx context.Context, t time.Time) error {
- return errNotImpl
- }
- // Open opens the file for read. Call Close() on the returned io.ReadCloser
- func (o Object) Open(ctx context.Context, options ...fs.OpenOption) (io.ReadCloser, error) {
- return nil, errNotImpl
- }
- // Update in to the object with the modTime given of the given size
- func (o Object) Update(ctx context.Context, in io.Reader, src fs.ObjectInfo, options ...fs.OpenOption) error {
- return errNotImpl
- }
- // Remove this object
- func (o Object) Remove(ctx context.Context) error {
- return errNotImpl
- }
- // SeekMode specifies the optional Seek interface for the ReadCloser returned by Open
- type SeekMode int
- const (
- // SeekModeNone specifies no seek interface
- SeekModeNone SeekMode = iota
- // SeekModeRegular specifies the regular io.Seek interface
- SeekModeRegular
- // SeekModeRange specifies the fs.RangeSeek interface
- SeekModeRange
- )
- // SeekModes contains all valid SeekMode's
- var SeekModes = []SeekMode{SeekModeNone, SeekModeRegular, SeekModeRange}
- // ContentMockObject mocks an fs.Object and has content, mod time
- type ContentMockObject struct {
- Object
- content []byte
- seekMode SeekMode
- f fs.Fs
- unknownSize bool
- modTime time.Time
- }
- // WithContent returns an fs.Object with the given content.
- func (o Object) WithContent(content []byte, mode SeekMode) *ContentMockObject {
- return &ContentMockObject{
- Object: o,
- content: content,
- seekMode: mode,
- }
- }
- // SetFs sets the return value of the Fs() call
- func (o *ContentMockObject) SetFs(f fs.Fs) {
- o.f = f
- }
- // SetUnknownSize makes the mock object return -1 for size if true
- func (o *ContentMockObject) SetUnknownSize(unknownSize bool) {
- o.unknownSize = unknownSize
- }
- // Fs returns read only access to the Fs that this object is part of
- //
- // This is nil unless SetFs has been called
- func (o *ContentMockObject) Fs() fs.Info {
- return o.f
- }
- // Open opens the file for read. Call Close() on the returned io.ReadCloser
- func (o *ContentMockObject) Open(ctx context.Context, options ...fs.OpenOption) (io.ReadCloser, error) {
- size := int64(len(o.content))
- var offset, limit int64 = 0, -1
- for _, option := range options {
- switch x := option.(type) {
- case *fs.SeekOption:
- offset = x.Offset
- case *fs.RangeOption:
- offset, limit = x.Decode(size)
- default:
- if option.Mandatory() {
- return nil, fmt.Errorf("unsupported mandatory option: %v", option)
- }
- }
- }
- if limit == -1 || offset+limit > size {
- limit = size - offset
- }
- var r *bytes.Reader
- if o.seekMode == SeekModeNone {
- r = bytes.NewReader(o.content[offset : offset+limit])
- } else {
- r = bytes.NewReader(o.content)
- _, err := r.Seek(offset, io.SeekStart)
- if err != nil {
- return nil, err
- }
- }
- switch o.seekMode {
- case SeekModeNone:
- return &readCloser{r}, nil
- case SeekModeRegular:
- return &readSeekCloser{r}, nil
- case SeekModeRange:
- return &readRangeSeekCloser{r}, nil
- default:
- return nil, errors.New(o.seekMode.String())
- }
- }
- // Size returns the size of the file
- func (o *ContentMockObject) Size() int64 {
- if o.unknownSize {
- return -1
- }
- return int64(len(o.content))
- }
- // Hash returns the selected checksum of the file
- // If no checksum is available it returns ""
- func (o *ContentMockObject) Hash(ctx context.Context, t hash.Type) (string, error) {
- hasher, err := hash.NewMultiHasherTypes(hash.NewHashSet(t))
- if err != nil {
- return "", err
- }
- _, err = hasher.Write(o.content)
- if err != nil {
- return "", err
- }
- return hasher.Sums()[t], nil
- }
- // ModTime returns the modification date of the file
- // It should return a best guess if one isn't available
- func (o *ContentMockObject) ModTime(ctx context.Context) time.Time {
- return o.modTime
- }
- // SetModTime sets the metadata on the object to set the modification date
- func (o *ContentMockObject) SetModTime(ctx context.Context, t time.Time) error {
- o.modTime = t
- return nil
- }
- type readCloser struct{ io.Reader }
- func (r *readCloser) Close() error { return nil }
- type readSeekCloser struct{ io.ReadSeeker }
- func (r *readSeekCloser) Close() error { return nil }
- type readRangeSeekCloser struct{ io.ReadSeeker }
- func (r *readRangeSeekCloser) RangeSeek(offset int64, whence int, length int64) (int64, error) {
- return r.ReadSeeker.Seek(offset, whence)
- }
- func (r *readRangeSeekCloser) Close() error { return nil }
- func (m SeekMode) String() string {
- switch m {
- case SeekModeNone:
- return "SeekModeNone"
- case SeekModeRegular:
- return "SeekModeRegular"
- case SeekModeRange:
- return "SeekModeRange"
- default:
- return fmt.Sprintf("SeekModeInvalid(%d)", m)
- }
- }
|