fs: improve ChunkedReader
- make Close permanent and return errors afterwards - use RangeSeek from the wrapped reader if present - add a limit to chunk growth - correct RangeSeek interface behavior - add tests
This commit is contained in:
parent
fe25cb9c54
commit
9fdf273614
3 changed files with 320 additions and 29 deletions
|
@ -2,7 +2,9 @@
|
|||
package mockobject
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"errors"
|
||||
"fmt"
|
||||
"io"
|
||||
"time"
|
||||
|
||||
|
@ -15,6 +17,11 @@ 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)
|
||||
|
@ -69,3 +76,105 @@ func (o Object) Update(in io.Reader, src fs.ObjectInfo, options ...fs.OpenOption
|
|||
func (o Object) Remove() 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}
|
||||
|
||||
type contentMockObject struct {
|
||||
Object
|
||||
content []byte
|
||||
seekMode SeekMode
|
||||
}
|
||||
|
||||
// WithContent returns a fs.Object with the given content.
|
||||
func (o Object) WithContent(content []byte, mode SeekMode) fs.Object {
|
||||
return &contentMockObject{
|
||||
Object: o,
|
||||
content: content,
|
||||
seekMode: mode,
|
||||
}
|
||||
}
|
||||
|
||||
func (o *contentMockObject) Open(options ...fs.OpenOption) (io.ReadCloser, error) {
|
||||
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(o.Size())
|
||||
default:
|
||||
if option.Mandatory() {
|
||||
return nil, fmt.Errorf("Unsupported mandatory option: %v", option)
|
||||
}
|
||||
}
|
||||
}
|
||||
if limit == -1 || offset+limit > o.Size() {
|
||||
limit = o.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())
|
||||
}
|
||||
}
|
||||
func (o *contentMockObject) Size() int64 {
|
||||
return int64(len(o.content))
|
||||
}
|
||||
|
||||
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)
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue