github.com/xhghs/rclone@v1.51.1-0.20200430155106-e186a28cced8/fstest/mockobject/mockobject.go (about)

     1  // Package mockobject provides a mock object which can be created from a string
     2  package mockobject
     3  
     4  import (
     5  	"bytes"
     6  	"context"
     7  	"errors"
     8  	"fmt"
     9  	"io"
    10  	"time"
    11  
    12  	"github.com/rclone/rclone/fs"
    13  	"github.com/rclone/rclone/fs/hash"
    14  )
    15  
    16  var errNotImpl = errors.New("not implemented")
    17  
    18  // Object is a mock fs.Object useful for testing
    19  type Object string
    20  
    21  // New returns mock fs.Object useful for testing
    22  func New(name string) Object {
    23  	return Object(name)
    24  }
    25  
    26  // String returns a description of the Object
    27  func (o Object) String() string {
    28  	return string(o)
    29  }
    30  
    31  // Fs returns read only access to the Fs that this object is part of
    32  func (o Object) Fs() fs.Info {
    33  	return nil
    34  }
    35  
    36  // Remote returns the remote path
    37  func (o Object) Remote() string {
    38  	return string(o)
    39  }
    40  
    41  // Hash returns the selected checksum of the file
    42  // If no checksum is available it returns ""
    43  func (o Object) Hash(ctx context.Context, t hash.Type) (string, error) {
    44  	return "", errNotImpl
    45  }
    46  
    47  // ModTime returns the modification date of the file
    48  // It should return a best guess if one isn't available
    49  func (o Object) ModTime(ctx context.Context) (t time.Time) {
    50  	return t
    51  }
    52  
    53  // Size returns the size of the file
    54  func (o Object) Size() int64 { return 0 }
    55  
    56  // Storable says whether this object can be stored
    57  func (o Object) Storable() bool {
    58  	return true
    59  }
    60  
    61  // SetModTime sets the metadata on the object to set the modification date
    62  func (o Object) SetModTime(ctx context.Context, t time.Time) error {
    63  	return errNotImpl
    64  }
    65  
    66  // Open opens the file for read.  Call Close() on the returned io.ReadCloser
    67  func (o Object) Open(ctx context.Context, options ...fs.OpenOption) (io.ReadCloser, error) {
    68  	return nil, errNotImpl
    69  }
    70  
    71  // Update in to the object with the modTime given of the given size
    72  func (o Object) Update(ctx context.Context, in io.Reader, src fs.ObjectInfo, options ...fs.OpenOption) error {
    73  	return errNotImpl
    74  }
    75  
    76  // Remove this object
    77  func (o Object) Remove(ctx context.Context) error {
    78  	return errNotImpl
    79  }
    80  
    81  // SeekMode specifies the optional Seek interface for the ReadCloser returned by Open
    82  type SeekMode int
    83  
    84  const (
    85  	// SeekModeNone specifies no seek interface
    86  	SeekModeNone SeekMode = iota
    87  	// SeekModeRegular specifies the regular io.Seek interface
    88  	SeekModeRegular
    89  	// SeekModeRange specifies the fs.RangeSeek interface
    90  	SeekModeRange
    91  )
    92  
    93  // SeekModes contains all valid SeekMode's
    94  var SeekModes = []SeekMode{SeekModeNone, SeekModeRegular, SeekModeRange}
    95  
    96  // ContentMockObject mocks an fs.Object and has content
    97  type ContentMockObject struct {
    98  	Object
    99  	content     []byte
   100  	seekMode    SeekMode
   101  	f           fs.Fs
   102  	unknownSize bool
   103  }
   104  
   105  // WithContent returns a fs.Object with the given content.
   106  func (o Object) WithContent(content []byte, mode SeekMode) *ContentMockObject {
   107  	return &ContentMockObject{
   108  		Object:   o,
   109  		content:  content,
   110  		seekMode: mode,
   111  	}
   112  }
   113  
   114  // SetFs sets the return value of the Fs() call
   115  func (o *ContentMockObject) SetFs(f fs.Fs) {
   116  	o.f = f
   117  }
   118  
   119  // SetUnknownSize makes the mock object return -1 for size if true
   120  func (o *ContentMockObject) SetUnknownSize(unknownSize bool) {
   121  	o.unknownSize = true
   122  }
   123  
   124  // Fs returns read only access to the Fs that this object is part of
   125  //
   126  // This is nil unless SetFs has been called
   127  func (o *ContentMockObject) Fs() fs.Info {
   128  	return o.f
   129  }
   130  
   131  // Open opens the file for read.  Call Close() on the returned io.ReadCloser
   132  func (o *ContentMockObject) Open(ctx context.Context, options ...fs.OpenOption) (io.ReadCloser, error) {
   133  	size := int64(len(o.content))
   134  	var offset, limit int64 = 0, -1
   135  	for _, option := range options {
   136  		switch x := option.(type) {
   137  		case *fs.SeekOption:
   138  			offset = x.Offset
   139  		case *fs.RangeOption:
   140  			offset, limit = x.Decode(size)
   141  		default:
   142  			if option.Mandatory() {
   143  				return nil, fmt.Errorf("Unsupported mandatory option: %v", option)
   144  			}
   145  		}
   146  	}
   147  	if limit == -1 || offset+limit > size {
   148  		limit = size - offset
   149  	}
   150  
   151  	var r *bytes.Reader
   152  	if o.seekMode == SeekModeNone {
   153  		r = bytes.NewReader(o.content[offset : offset+limit])
   154  	} else {
   155  		r = bytes.NewReader(o.content)
   156  		_, err := r.Seek(offset, io.SeekStart)
   157  		if err != nil {
   158  			return nil, err
   159  		}
   160  	}
   161  	switch o.seekMode {
   162  	case SeekModeNone:
   163  		return &readCloser{r}, nil
   164  	case SeekModeRegular:
   165  		return &readSeekCloser{r}, nil
   166  	case SeekModeRange:
   167  		return &readRangeSeekCloser{r}, nil
   168  	default:
   169  		return nil, errors.New(o.seekMode.String())
   170  	}
   171  }
   172  
   173  // Size returns the size of the file
   174  func (o *ContentMockObject) Size() int64 {
   175  	if o.unknownSize {
   176  		return -1
   177  	}
   178  	return int64(len(o.content))
   179  }
   180  
   181  type readCloser struct{ io.Reader }
   182  
   183  func (r *readCloser) Close() error { return nil }
   184  
   185  type readSeekCloser struct{ io.ReadSeeker }
   186  
   187  func (r *readSeekCloser) Close() error { return nil }
   188  
   189  type readRangeSeekCloser struct{ io.ReadSeeker }
   190  
   191  func (r *readRangeSeekCloser) RangeSeek(offset int64, whence int, length int64) (int64, error) {
   192  	return r.ReadSeeker.Seek(offset, whence)
   193  }
   194  
   195  func (r *readRangeSeekCloser) Close() error { return nil }
   196  
   197  func (m SeekMode) String() string {
   198  	switch m {
   199  	case SeekModeNone:
   200  		return "SeekModeNone"
   201  	case SeekModeRegular:
   202  		return "SeekModeRegular"
   203  	case SeekModeRange:
   204  		return "SeekModeRange"
   205  	default:
   206  		return fmt.Sprintf("SeekModeInvalid(%d)", m)
   207  	}
   208  }