Truncate files on Write

master
Nick Krichevsky 2019-03-16 19:04:40 -04:00
parent edc451f9c6
commit 0158f7e1ed
2 changed files with 26 additions and 12 deletions

View File

@ -10,18 +10,19 @@ import (
const pasteFileMode = 0644
// ReadWriteSeekCloser implements reading, writing, seeking, and closing
type ReadWriteSeekCloser interface {
// TruncatableFile implements reading, writing, seeking, truncation, and closing
type TruncatableFile interface {
Truncate(size int64) error
io.ReadWriteSeeker
io.Closer
}
// Paster holds a single paste from the system
// Implements io.ReadWriteCloser
// Implements TruncatableFile
type Paster struct {
Paste repository.Paste
pasteDir string
file ReadWriteSeekCloser
file TruncatableFile
}
func (p *Paster) getPath() string {
@ -56,11 +57,6 @@ func (p *Paster) prepareAndDo(buffer []byte, action func([]byte) (int, error)) (
}
}
_, err := p.file.Seek(0, io.SeekStart)
if err != nil {
return 0, err
}
return action(buffer)
}
@ -76,6 +72,16 @@ func (p *Paster) Read(buffer []byte) (int, error) {
func (p *Paster) Write(contents []byte) (int, error) {
// Wrap in closure to handle the nil file case
return p.prepareAndDo(contents, func(buffer []byte) (int, error) {
// Start writing at the beginning.
_, err := p.file.Seek(0, io.SeekStart)
if err != nil {
return 0, err
}
err = p.file.Truncate(0)
if err != nil {
return 0, err
}
return p.file.Write(buffer)
})
}

View File

@ -26,6 +26,12 @@ func (file *MockFile) Write(buffer []byte) (int, error) {
return args.Int(0), args.Error(1)
}
func (file *MockFile) Truncate(size int64) error {
args := file.Called(size)
return args.Error(0)
}
func (file *MockFile) Seek(offset int64, whence int) (int64, error) {
args := file.Called(offset, whence)
@ -64,10 +70,10 @@ func TestRead(t *testing.T) {
buffer[i] = byte(char)
}
}).Once()
// Ensure we seek to the start of the file
mockFile.On("Seek", int64(0), 0).Return(int64(0), nil).Once()
mockFile.AssertNotCalled(t, "Seek")
mockFile.AssertNotCalled(t, "Close")
mockFile.AssertNotCalled(t, "Write")
mockFile.AssertNotCalled(t, "Truncate")
paster.Read(readBuffer)
mockFile.AssertExpectations(t)
@ -82,6 +88,7 @@ func TestWrite(t *testing.T) {
mockFile.On("Write", testPaste).Return(len(testPaste), nil).Once()
// Ensure we seek to the start of the file
mockFile.On("Seek", int64(0), 0).Return(int64(0), nil).Once()
mockFile.On("Truncate", int64(0)).Return(nil).Once()
mockFile.AssertNotCalled(t, "Close")
paster.Write(testPaste)
@ -93,7 +100,8 @@ func TestClose(t *testing.T) {
mockFile := paster.file.(*MockFile)
mockFile.On("Close").Return(nil).Once()
mockFile.AssertNotCalled(t, "Close")
mockFile.AssertNotCalled(t, "Write")
mockFile.AssertNotCalled(t, "Truncate")
mockFile.AssertNotCalled(t, "Seek")
mockFile.AssertNotCalled(t, "Read")
// If we write to the file on close, that isn't the worst thing in the world and we won't enforce it being a problem