Skip to content

Commit

Permalink
Add format sub command (#24)
Browse files Browse the repository at this point in the history
  • Loading branch information
corvus-ch authored Aug 29, 2022
1 parent 78c5f8f commit c4a7cd7
Show file tree
Hide file tree
Showing 12 changed files with 447 additions and 41 deletions.
43 changes: 43 additions & 0 deletions format/action.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
package format

import (
"fmt"
"io"

"github.com/bketelsen/logr"
)

// DoFormat applies a format to a given input.
func DoFormat(cfg Config, log logr.Logger) (result error) {
reader, err := cfg.Input()
if err != nil {
return fmt.Errorf("failed to open input: %v", err)
}

if closer, ok := reader.(io.Closer); ok {
defer closer.Close()
}

formats, err := cfg.Formats()
if err != nil {
return fmt.Errorf("failed to setup output formatting: %v", err)
}

factory := NewFactory(formats, false, log)
defer func() {
if err := factory.Close(); err != nil && result == nil {
result = err
}
}()

writer, err := factory.Create(0)
if err != nil {
return fmt.Errorf("failed to setup output writer: %v", err)
}

if _, err := io.Copy(writer, reader); nil != err {
result = fmt.Errorf("failed to process data: %v", err)
}

return
}
90 changes: 90 additions & 0 deletions format/action_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,90 @@
package format_test

import (
"bytes"
"fmt"
"io/ioutil"
"os"
"path/filepath"
"testing"

"github.com/corvus-ch/horcrux/format"
"github.com/corvus-ch/horcrux/format/raw"
"github.com/corvus-ch/horcrux/input"
"github.com/corvus-ch/logr/buffered"
"github.com/pkg/errors"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/mock"
)

func TestFormat(t *testing.T) {
dir := createDir(t)
defer os.RemoveAll(dir)

f := raw.New(input.NewStreamInput(outputStem(dir, raw.Name)))
cfg := NewConfig(t.Name(), f)
log := buffered.New(1)

err := format.DoFormat(cfg, log)

assert.Nil(t, err)
mock.AssertExpectationsForObjects(t, cfg)

files, _ := filepath.Glob(fmt.Sprintf("%s.*", outputStem(dir, raw.Name)))

assert.Empty(t, log.Buf())
assert.Len(t, files, 1)
}

var errorTests = []struct {
name string
setup func(t *testing.T, cfg *Config, dir string)
output string
}{
{"input", func(t *testing.T, cfg *Config, _ string) {
cfg.On("Input").Maybe().Return(nil, errors.New("input error"))
}, "failed to open input: input error"},

{"formats", func(t *testing.T, cfg *Config, _ string) {
cfg.On("Input").Return(bytes.NewBufferString(t.Name()), nil)
cfg.On("Formats").Return(nil, errors.New("format error"))
}, "failed to setup output formatting: format error"},

{"copy", func(t *testing.T, cfg *Config, dir string) {
f, _ := os.Open(t.Name())
cfg.On("Input").Return(f, nil)
cfg.On("InputInfo").Maybe().Return(input.NewStreamInput(outputStem(dir, raw.Name)))
cfg.On("Formats").Maybe().Return([]format.Format{raw.New(input.NewStreamInput(outputStem(dir, raw.Name)))}, nil)
}, "failed to process data: invalid argument"},
}

func TestErrors(t *testing.T) {
for _, test := range errorTests {
t.Run(test.name, func(t *testing.T) {
dir := createDir(t)
defer os.RemoveAll(dir)
cfg := &Config{}
log := buffered.New(1)
test.setup(t, cfg, dir)

err := format.DoFormat(cfg, log)

assert.Error(t, err, test.output)
assert.Empty(t, log.Buf())
mock.AssertExpectationsForObjects(t, cfg)
})
}
}

func createDir(t *testing.T) string {
dir, err := ioutil.TempDir("", "horcrux_create")
if err != nil {
t.Error(err)
}

return dir
}

func outputStem(dir, format string) string {
return fmt.Sprintf("%s/%s", dir, format)
}
14 changes: 14 additions & 0 deletions format/config.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
package format

import (
"io"

"github.com/corvus-ch/horcrux/input"
)

// Config define the configuration input required for creating an output format.
type Config interface {
Input() (io.Reader, error)
InputInfo() input.Input
Formats() ([]Format, error)
}
49 changes: 49 additions & 0 deletions format/config_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
package format_test

import (
"bytes"
"io"

"github.com/corvus-ch/horcrux/format"
"github.com/corvus-ch/horcrux/input"
"github.com/stretchr/testify/mock"
)

type Config struct {
mock.Mock
}

func NewConfig(name string, f format.Format) *Config {
cfg := &Config{}
cfg.On("Input").Maybe().Return(bytes.NewBufferString(name), nil)
cfg.On("InputInfo").Maybe().Return(input.NewStreamInput(""))
cfg.On("Formats").Maybe().Return([]format.Format{f}, nil)

return cfg
}

func (c *Config) Input() (io.Reader, error) {
args := c.Called()
r := args.Get(0)
if r == nil {
return nil, args.Error(1)
}

return r.(io.Reader), args.Error(1)
}

func (c *Config) InputInfo() input.Input {
args := c.Called()

return args.Get(0).(input.Input)
}

func (c *Config) Formats() ([]format.Format, error) {
args := c.Called()
f := args.Get(0)
if f == nil {
return nil, args.Error(1)
}

return f.([]format.Format), args.Error(1)
}
2 changes: 2 additions & 0 deletions internal/app.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ package internal
import (
"github.com/bketelsen/logr"
"github.com/corvus-ch/horcrux/create"
"github.com/corvus-ch/horcrux/format"
"github.com/corvus-ch/horcrux/restore"
"github.com/corvus-ch/logr/writer_adapter"
"gopkg.in/alecthomas/kingpin.v2"
Expand All @@ -14,6 +15,7 @@ func App(log logr.Logger) *kingpin.Application {
app.UsageWriter(w)
app.ErrorWriter(w)
RegisterCreateCommand(app, log, create.Create)
RegisterFormatCommand(app, log, format.DoFormat)
RegisterRestoreCommand(app, log, restore.Restore)

return app
Expand Down
1 change: 1 addition & 0 deletions internal/app_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ var appTests = []struct {
}{
{"default", []string{"help"}},
{"create", []string{"help", "create"}},
{"format", []string{"help", "format"}},
{"restore", []string{"help", "restore"}},
}

Expand Down
48 changes: 7 additions & 41 deletions internal/create_test.go
Original file line number Diff line number Diff line change
@@ -1,15 +1,11 @@
package internal_test

import (
"io/ioutil"
"os"
"testing"

"github.com/bketelsen/logr"
"github.com/corvus-ch/horcrux/create"
"github.com/corvus-ch/horcrux/format/raw"
"github.com/corvus-ch/horcrux/format/text"
"github.com/corvus-ch/horcrux/format/zbase32"
"github.com/corvus-ch/horcrux/internal"
"github.com/corvus-ch/logr/buffered"
"github.com/stretchr/testify/assert"
Expand Down Expand Up @@ -82,25 +78,13 @@ func TestCreateCommand_Parts(t *testing.T) {
}

func TestCreateCommand_Input(t *testing.T) {
file, err := ioutil.TempFile("", t.Name())
if err != nil {
t.Fatal(err)
}
file := tmpFile(t)
defer os.Remove(file.Name())
tests := []struct {
name string
args []string
file *os.File
}{
{"default", []string{"create"}, os.Stdin},
{"stdin", []string{"create", "--", "-"}, os.Stdin},
{"file", []string{"create", "--", file.Name()}, file},
}
for _, test := range tests {
t.Run(test.name, func(t *testing.T) {
for name, test := range newInputTests("create", file) {
t.Run(name, func(t *testing.T) {
assertCreateAction(t, test.args, func(cfg create.Config, _ logr.Logger) error {
reader, err := cfg.Input()
assert.Nil(t, err)
assert.NoError(t, err)
assert.Equal(t, test.file.Name(), reader.(*os.File).Name())
return nil
})
Expand All @@ -109,28 +93,10 @@ func TestCreateCommand_Input(t *testing.T) {
}

func TestCreateCommand_Formats(t *testing.T) {
tests := []struct {
name string
args []string
formats []string
}{
{"default", []string{"create"}, []string{text.Name}},
{"single", []string{"create", "-f", "raw"}, []string{raw.Name}},
{"multiple", []string{"create", "-f", "raw", "-f", "zbase32"}, []string{raw.Name, zbase32.Name}},
}
for _, test := range tests {
t.Run(test.name, func(t *testing.T) {
for name, test := range newFormatsTests("create") {
t.Run(name, func(t *testing.T) {
assertCreateAction(t, test.args, func(cfg create.Config, _ logr.Logger) error {
formats, err := cfg.Formats()
if err != nil {
t.Fatal(err)
}
if len(test.formats) != len(formats) {
t.Fatalf("expected %d formats, got %d", len(test.formats), len(formats))
}
for i, name := range test.formats {
assert.Equal(t, name, formats[i].Name())
}
assertFormats(t, cfg, test.formats)
return nil
})
})
Expand Down
3 changes: 3 additions & 0 deletions internal/fixtures/TestApp/default.golden
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,9 @@ ERROR
ERROR create [<flags>] [<input>]
ERROR create a new set of horcruxes
ERROR
ERROR format [<flags>] [<input>]
ERROR formats input the same way as create would do without doing the split
ERROR
ERROR restore [<flags>] <files>...
ERROR restores your valuable data from a set of horcruxes
ERROR
Expand Down
13 changes: 13 additions & 0 deletions internal/fixtures/TestApp/format.golden
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
ERROR usage: horcrux format [<flags>] [<input>]
ERROR
ERROR formats input the same way as create would do without doing the split
ERROR
ERROR Flags:
ERROR --help Show context-sensitive help (also try --help-long and
ERROR --help-man).
ERROR -f, --format=text ... the output formats
ERROR -o, --output=OUTPUT name stem for the output files
ERROR
ERROR Args:
ERROR [<input>] the input file
ERROR
Loading

0 comments on commit c4a7cd7

Please sign in to comment.