Skip to content

Commit

Permalink
Change cmd.Config to context and use it to maintain file pointers
Browse files Browse the repository at this point in the history
  • Loading branch information
aswinkarthik committed Oct 8, 2019
1 parent 1381196 commit ce93ef9
Show file tree
Hide file tree
Showing 5 changed files with 142 additions and 75 deletions.
62 changes: 55 additions & 7 deletions cmd/config.go
Original file line number Diff line number Diff line change
Expand Up @@ -8,26 +8,28 @@ import (
"github.com/aswinkarthik/csvdiff/pkg/digest"
)

// Config is to store all command line Flags.
type Config struct {
// Context is to store all command line Flags.
type Context struct {
PrimaryKeyPositions []int
ValueColumnPositions []int
IncludeColumnPositions []int
Format string
BaseFilename string
DeltaFilename string
baseFile afero.File
deltaFile afero.File
}

// GetPrimaryKeys is to return the --primary-key flags as digest.Positions array.
func (c *Config) GetPrimaryKeys() digest.Positions {
func (c *Context) GetPrimaryKeys() digest.Positions {
if len(c.PrimaryKeyPositions) > 0 {
return c.PrimaryKeyPositions
}
return []int{0}
}

// GetValueColumns is to return the --columns flags as digest.Positions array.
func (c *Config) GetValueColumns() digest.Positions {
func (c *Context) GetValueColumns() digest.Positions {
if len(c.ValueColumnPositions) > 0 {
return c.ValueColumnPositions
}
Expand All @@ -36,16 +38,16 @@ func (c *Config) GetValueColumns() digest.Positions {

// GetIncludeColumnPositions is to return the --include flags as digest.Positions array.
// If empty, it is value columns
func (c Config) GetIncludeColumnPositions() digest.Positions {
func (c Context) GetIncludeColumnPositions() digest.Positions {
if len(c.IncludeColumnPositions) > 0 {
return c.IncludeColumnPositions
}
return c.GetValueColumns()
}

// Validate validates the config object
// Validate validates the context object
// and returns error if not valid.
func (c *Config) Validate(fs afero.Fs) error {
func (c *Context) Validate(fs afero.Fs) error {
{
// format validation

Expand Down Expand Up @@ -94,3 +96,49 @@ func (c *Config) Validate(fs afero.Fs) error {

return nil
}

// BaseDigestConfig creates a digest.Context from cmd.Context
// that is needed to start the diff process
func (c *Context) BaseDigestConfig(fs afero.Fs) (digest.Config, error) {
baseFile, err := fs.Open(c.BaseFilename)
if err != nil {
return digest.Config{}, err
}

c.baseFile = baseFile

return digest.Config{
Reader: baseFile,
Value: c.ValueColumnPositions,
Key: c.PrimaryKeyPositions,
Include: c.IncludeColumnPositions,
}, nil
}

// DeltaDigestConfig creates a digest.Context from cmd.Context
// that is needed to start the diff process
func (c *Context) DeltaDigestConfig(fs afero.Fs) (digest.Config, error) {
deltaFile, err := fs.Open(c.DeltaFilename)
if err != nil {
return digest.Config{}, err
}

c.baseFile = deltaFile

return digest.Config{
Reader: deltaFile,
Value: c.ValueColumnPositions,
Key: c.PrimaryKeyPositions,
Include: c.IncludeColumnPositions,
}, nil
}

// Close all file handles
func (c *Context) Close() {
if c.baseFile != nil {
_ = c.baseFile.Close()
}
if c.deltaFile != nil {
_ = c.deltaFile.Close()
}
}
70 changes: 54 additions & 16 deletions cmd/config_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -11,28 +11,36 @@ import (
)

func TestPrimaryKeyPositions(t *testing.T) {
config := cmd.Config{PrimaryKeyPositions: []int{0, 1}}
config := cmd.Context{PrimaryKeyPositions: []int{0, 1}}
assert.Equal(t, digest.Positions([]int{0, 1}), config.GetPrimaryKeys())

config = cmd.Config{PrimaryKeyPositions: []int{}}
config = cmd.Context{PrimaryKeyPositions: []int{}}
assert.Equal(t, digest.Positions([]int{0}), config.GetPrimaryKeys())

config = cmd.Config{}
config = cmd.Context{}
assert.Equal(t, digest.Positions([]int{0}), config.GetPrimaryKeys())
}

func TestValueColumnPositions(t *testing.T) {
config := cmd.Config{ValueColumnPositions: []int{0, 1}}
config := cmd.Context{ValueColumnPositions: []int{0, 1}}
assert.Equal(t, digest.Positions([]int{0, 1}), config.GetValueColumns())

config = cmd.Config{ValueColumnPositions: []int{}}
config = cmd.Context{ValueColumnPositions: []int{}}
assert.Equal(t, digest.Positions([]int{}), config.GetValueColumns())

config = cmd.Config{}
config = cmd.Context{}
assert.Equal(t, digest.Positions([]int{}), config.GetValueColumns())
}

func TestConfigValidate(t *testing.T) {
validConfig := func(t *testing.T, fs afero.Fs) *cmd.Context {
_, err := fs.Create("/base.csv")
assert.NoError(t, err)
_, err = fs.Create("/delta.csv")
assert.NoError(t, err)
return &cmd.Context{Format: "json", BaseFilename: "/base.csv", DeltaFilename: "/delta.csv"}
}

t.Run("should validate format", func(t *testing.T) {
fs := afero.NewMemMapFs()

Expand All @@ -54,7 +62,7 @@ func TestConfigValidate(t *testing.T) {
t.Run("should validate base file existence", func(t *testing.T) {
fs := afero.NewMemMapFs()

config := &cmd.Config{Format: "json", BaseFilename: "/base.csv", DeltaFilename: "/delta.csv"}
config := &cmd.Context{Format: "json", BaseFilename: "/base.csv", DeltaFilename: "/delta.csv"}
err := config.Validate(fs)
assert.EqualError(t, err, "base-file /base.csv does not exits")
})
Expand All @@ -64,15 +72,15 @@ func TestConfigValidate(t *testing.T) {
err := fs.Mkdir("/base.csv", os.ModePerm)
assert.NoError(t, err)

config := &cmd.Config{Format: "json", BaseFilename: "/base.csv", DeltaFilename: "/delta.csv"}
config := &cmd.Context{Format: "json", BaseFilename: "/base.csv", DeltaFilename: "/delta.csv"}
err = config.Validate(fs)
assert.EqualError(t, err, "base-file /base.csv should be a file")

_, err = fs.Create("/valid-base.csv")
err = fs.Mkdir("/delta.csv", os.ModePerm)
assert.NoError(t, err)

config = &cmd.Config{Format: "json", BaseFilename: "/valid-base.csv", DeltaFilename: "/delta.csv"}
config = &cmd.Context{Format: "json", BaseFilename: "/valid-base.csv", DeltaFilename: "/delta.csv"}
err = config.Validate(fs)
assert.EqualError(t, err, "delta-file /delta.csv should be a file")
})
Expand All @@ -84,16 +92,46 @@ func TestConfigValidate(t *testing.T) {
_, err = fs.Create("/delta.csv")
assert.NoError(t, err)

config := &cmd.Config{Format: "json", BaseFilename: "/base.csv", DeltaFilename: "/delta.csv"}
config := &cmd.Context{Format: "json", BaseFilename: "/base.csv", DeltaFilename: "/delta.csv"}
err = config.Validate(fs)
assert.NoError(t, err)
})
}

func validConfig(t *testing.T, fs afero.Fs) *cmd.Config {
_, err := fs.Create("/base.csv")
assert.NoError(t, err)
_, err = fs.Create("/delta.csv")
assert.NoError(t, err)
return &cmd.Config{Format: "json", BaseFilename: "/base.csv", DeltaFilename: "/delta.csv"}
func TestConfig_DigestConfig(t *testing.T) {
t.Run("should create digest ctx", func(t *testing.T) {
fs := afero.NewMemMapFs()
_, err := fs.Create("/base.csv")
assert.NoError(t, err)
_, err = fs.Create("/delta.csv")
assert.NoError(t, err)

valueColumns := digest.Positions{0, 1, 2}
primaryColumns := digest.Positions{0, 1}
includeColumns := digest.Positions{2}
config := &cmd.Context{
Format: "json",
BaseFilename: "/base.csv",
DeltaFilename: "/delta.csv",
ValueColumnPositions: valueColumns,
PrimaryKeyPositions: primaryColumns,
IncludeColumnPositions: includeColumns,
}

baseConfig, err := config.BaseDigestConfig(fs)

assert.NoError(t, err)
assert.NotNil(t, baseConfig.Reader)
assert.Equal(t, baseConfig.Value, valueColumns)
assert.Equal(t, baseConfig.Key, primaryColumns)
assert.Equal(t, baseConfig.Include, includeColumns)

deltaConfig, err := config.DeltaDigestConfig(fs)

assert.NoError(t, err)
assert.NotNil(t, deltaConfig.Reader)
assert.Equal(t, deltaConfig.Value, valueColumns)
assert.Equal(t, deltaConfig.Key, primaryColumns)
assert.Equal(t, deltaConfig.Include, includeColumns)
})
}
22 changes: 11 additions & 11 deletions cmd/formatter.go
Original file line number Diff line number Diff line change
Expand Up @@ -24,18 +24,18 @@ var allFormats = []string{rowmark, jsonFormat, legacyJSONFormat, lineDiff, wordD
type Formatter struct {
stdout io.Writer
stderr io.Writer
config Config
ctx Context
}

// NewFormatter can be used to create a new formatter
func NewFormatter(stdout, stderr io.Writer, config Config) *Formatter {
return &Formatter{stdout: stdout, stderr: stderr, config: config}
func NewFormatter(stdout, stderr io.Writer, ctx Context) *Formatter {
return &Formatter{stdout: stdout, stderr: stderr, ctx: ctx}
}

// Format can be used to format the differences based on config
// Format can be used to format the differences based on ctx
// to appropriate writers
func (f *Formatter) Format(diff digest.Differences) error {
switch f.config.Format {
switch f.ctx.Format {
case legacyJSONFormat:
return f.legacyJSON(diff)
case jsonFormat:
Expand Down Expand Up @@ -63,7 +63,7 @@ func (f *Formatter) legacyJSON(diff digest.Differences) error {
Deletions []string
}

includes := f.config.GetIncludeColumnPositions()
includes := f.ctx.GetIncludeColumnPositions()

additions := make([]string, 0, len(diff.Additions))
for _, addition := range diff.Additions {
Expand Down Expand Up @@ -99,7 +99,7 @@ func (f *Formatter) legacyJSON(diff digest.Differences) error {
// JSONFormatter formats diff to as a JSON Object
// { "Additions": [...], "Modifications": [{ "Original": [...], "Current": [...]}]}
func (f *Formatter) json(diff digest.Differences) error {
includes := f.config.GetIncludeColumnPositions()
includes := f.ctx.GetIncludeColumnPositions()

additions := make([]string, 0, len(diff.Additions))
for _, addition := range diff.Additions {
Expand Down Expand Up @@ -151,7 +151,7 @@ func (f *Formatter) rowMark(diff digest.Differences) error {
_, _ = fmt.Fprintf(f.stderr, "Deletions %d\n", len(diff.Deletions))
_, _ = fmt.Fprintf(f.stderr, "Rows:\n")

includes := f.config.GetIncludeColumnPositions()
includes := f.ctx.GetIncludeColumnPositions()

additions := make([]string, 0, len(diff.Additions))
for _, addition := range diff.Additions {
Expand Down Expand Up @@ -185,7 +185,7 @@ func (f *Formatter) rowMark(diff digest.Differences) error {

// lineDiff is git-style line diff
func (f *Formatter) lineDiff(diff digest.Differences) error {
includes := f.config.GetIncludeColumnPositions()
includes := f.ctx.GetIncludeColumnPositions()

blue := color.New(color.FgBlue).FprintfFunc()
red := color.New(color.FgRed).FprintfFunc()
Expand Down Expand Up @@ -219,9 +219,9 @@ func (f *Formatter) colorWords(diff digest.Differences) error {
}

func (f *Formatter) wordLevelDiffs(diff digest.Differences, deletionFormat, additionFormat string) error {
includes := f.config.GetIncludeColumnPositions()
includes := f.ctx.GetIncludeColumnPositions()
if len(includes) <= 0 {
includes = f.config.GetValueColumns()
includes = f.ctx.GetValueColumns()
}
blue := color.New(color.FgBlue).SprintfFunc()
red := color.New(color.FgRed).SprintfFunc()
Expand Down
16 changes: 8 additions & 8 deletions cmd/formatter_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,7 @@ func TestLegacyJSONFormat(t *testing.T) {
var stdout bytes.Buffer
var stderr bytes.Buffer

formatter := cmd.NewFormatter(&stdout, &stderr, cmd.Config{Format: "legacy-json"})
formatter := cmd.NewFormatter(&stdout, &stderr, cmd.Context{Format: "legacy-json"})

err := formatter.Format(diff)
assert.NoError(t, err)
Expand Down Expand Up @@ -62,7 +62,7 @@ func TestJSONFormat(t *testing.T) {
var stdout bytes.Buffer
var stderr bytes.Buffer

formatter := cmd.NewFormatter(&stdout, &stderr, cmd.Config{Format: "json"})
formatter := cmd.NewFormatter(&stdout, &stderr, cmd.Context{Format: "json"})

err := formatter.Format(diff)
assert.NoError(t, err)
Expand All @@ -87,7 +87,7 @@ Rows:
var stdout bytes.Buffer
var stderr bytes.Buffer

formatter := cmd.NewFormatter(&stdout, &stderr, cmd.Config{Format: "rowmark"})
formatter := cmd.NewFormatter(&stdout, &stderr, cmd.Context{Format: "rowmark"})

err := formatter.Format(diff)

Expand Down Expand Up @@ -120,7 +120,7 @@ func TestLineDiff(t *testing.T) {
var stdout bytes.Buffer
var stderr bytes.Buffer

formatter := cmd.NewFormatter(&stdout, &stderr, cmd.Config{Format: "diff"})
formatter := cmd.NewFormatter(&stdout, &stderr, cmd.Context{Format: "diff"})

err := formatter.Format(diff)

Expand Down Expand Up @@ -148,7 +148,7 @@ func TestWordDiff(t *testing.T) {
var stdout bytes.Buffer
var stderr bytes.Buffer

formatter := cmd.NewFormatter(&stdout, &stderr, cmd.Config{Format: "word-diff"})
formatter := cmd.NewFormatter(&stdout, &stderr, cmd.Context{Format: "word-diff"})

err := formatter.Format(diff)

Expand Down Expand Up @@ -177,7 +177,7 @@ func TestWordDiff(t *testing.T) {
var stdout bytes.Buffer
var stderr bytes.Buffer

formatter := cmd.NewFormatter(&stdout, &stderr, cmd.Config{
formatter := cmd.NewFormatter(&stdout, &stderr, cmd.Context{
Format: "word-diff",
IncludeColumnPositions: digest.Positions{0},
})
Expand Down Expand Up @@ -209,7 +209,7 @@ deletions
var stdout bytes.Buffer
var stderr bytes.Buffer

formatter := cmd.NewFormatter(&stdout, &stderr, cmd.Config{Format: "color-words"})
formatter := cmd.NewFormatter(&stdout, &stderr, cmd.Context{Format: "color-words"})

err := formatter.Format(diff)

Expand All @@ -220,7 +220,7 @@ deletions

func TestWrongFormatter(t *testing.T) {
diff := digest.Differences{}
formatter := cmd.NewFormatter(nil, nil, cmd.Config{Format: "random-str"})
formatter := cmd.NewFormatter(nil, nil, cmd.Context{Format: "random-str"})

err := formatter.Format(diff)

Expand Down
Loading

0 comments on commit ce93ef9

Please sign in to comment.