Skip to content

Commit

Permalink
Refactor formatting differences
Browse files Browse the repository at this point in the history
  • Loading branch information
aswinkarthik committed Feb 28, 2019
1 parent 8016dff commit 1b4a540
Show file tree
Hide file tree
Showing 5 changed files with 68 additions and 99 deletions.
25 changes: 0 additions & 25 deletions cmd/config.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,6 @@ package cmd

import (
"errors"
"os"
"strings"

"github.com/aswinkarthik/csvdiff/pkg/digest"
Expand Down Expand Up @@ -60,27 +59,3 @@ func (c *Config) Validate() error {

return errors.New("Specified format is not valid")
}

const (
rowmark = "rowmark"
jsonFormat = "json"
diffFormat = "diff"
)

// Formatter instantiates a new formatted
// based on config.Format
func (c *Config) Formatter() Formatter {
format := strings.ToLower(c.Format)

switch format {
case jsonFormat:
return &JSONFormatter{
Stdout: os.Stdout,
}
default:
return &RowMarkFormatter{
Stdout: os.Stdout,
Stderr: os.Stderr,
}
}
}
25 changes: 0 additions & 25 deletions cmd/config_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -45,28 +45,3 @@ func TestConfigValidate(t *testing.T) {
config = &cmd.Config{Format: "json"}
assert.NoError(t, config.Validate())
}

func TestDefaultConfigFormatter(t *testing.T) {
config := &cmd.Config{}

formatter, ok := config.Formatter().(*cmd.RowMarkFormatter)

assert.True(t, ok)
assert.NotNil(t, formatter)
}

func TestConfigFormatter(t *testing.T) {
var config *cmd.Config
var formatter cmd.Formatter
var ok bool

config = &cmd.Config{Format: "rowmark"}
formatter, ok = config.Formatter().(*cmd.RowMarkFormatter)
assert.True(t, ok)
assert.NotNil(t, formatter)

config = &cmd.Config{Format: "json"}
formatter, ok = config.Formatter().(*cmd.JSONFormatter)
assert.True(t, ok)
assert.NotNil(t, formatter)
}
105 changes: 61 additions & 44 deletions cmd/formatter.go
Original file line number Diff line number Diff line change
Expand Up @@ -9,25 +9,47 @@ import (
"github.com/aswinkarthik/csvdiff/pkg/digest"
)

// Formatter defines the interface through which differences
// can be formatted and displayed
type Formatter interface {
Format(digest.Differences) error
const (
rowmark = "rowmark"
jsonFormat = "json"
diffFormat = "diff"
)

// Formatter can print the differences to stdout
// and accompanying metadata to stderr
type Formatter struct {
stdout io.Writer
stderr io.Writer
config Config
}

// RowMarkFormatter formats diff by marking each row as
// ADDED/MODIFIED. It mutates the row and adds as a new column.
type RowMarkFormatter struct {
Stdout io.Writer
Stderr io.Writer
// 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}
}

// Format prints the diff to os.Stdout
func (f *RowMarkFormatter) Format(diff digest.Differences) error {
fmt.Fprintf(f.Stderr, "Additions %d\n", len(diff.Additions))
fmt.Fprintf(f.Stderr, "Modifications %d\n", len(diff.Modifications))
fmt.Fprintf(f.Stderr, "Rows:\n")

// Format can be used to format the differences based on config
// to appropriate writers
func (f *Formatter) Format(diff digest.Differences) error {
switch f.config.Format {
case jsonFormat:
return f.json(diff)
case rowmark:
return f.rowMark(diff)
default:
return fmt.Errorf("formatter not found")
}
}

// JSONFormatter formats diff to as a JSON Object
// { "Additions": [...], "Modifications": [...] }
func (f *Formatter) json(diff digest.Differences) error {
// jsonDifference is a struct to represent legacy JSON format
type jsonDifference struct {
Additions []string
Modifications []string
}

additions := make([]string, 0, len(diff.Additions))
for _, addition := range diff.Additions {
additions = append(additions, strings.Join(addition, ","))
Expand All @@ -38,39 +60,30 @@ func (f *RowMarkFormatter) Format(diff digest.Differences) error {
modifications = append(modifications, strings.Join(modification.Current, ","))
}

for _, added := range additions {
_, err := fmt.Fprintf(f.Stdout, "%s,%s\n", added, "ADDED")
jsonDiff := jsonDifference{Additions: additions, Modifications: modifications}
data, err := json.MarshalIndent(jsonDiff, "", " ")

if err != nil {
return fmt.Errorf("error when formatting additions with RowMark formatter: %v", err)
}
if err != nil {
return fmt.Errorf("error when serializing with JSON formatter: %v", err)
}

for _, modified := range modifications {
_, err := fmt.Fprintf(f.Stdout, "%s,%s\n", modified, "MODIFIED")

if err != nil {
return fmt.Errorf("error when formatting modifications with RowMark formatter: %v", err)
}
_, err = f.stdout.Write(data)

if err != nil {
return fmt.Errorf("error when writing to writer with JSON formatter: %v", err)
}

return nil
}

// JSONFormatter formats diff to as a JSON Object
type JSONFormatter struct {
Stdout io.Writer
}
// RowMarkFormatter formats diff by marking each row as
// ADDED/MODIFIED. It mutates the row and adds as a new column.
func (f *Formatter) rowMark(diff digest.Differences) error {

// JSONDifference is a struct to represent legacy JSON format
type JSONDifference struct {
Additions []string
Modifications []string
}
fmt.Fprintf(f.stderr, "Additions %d\n", len(diff.Additions))
fmt.Fprintf(f.stderr, "Modifications %d\n", len(diff.Modifications))
fmt.Fprintf(f.stderr, "Rows:\n")

// Format prints the diff as a JSON
func (f *JSONFormatter) Format(diff digest.Differences) error {
additions := make([]string, 0, len(diff.Additions))
for _, addition := range diff.Additions {
additions = append(additions, strings.Join(addition, ","))
Expand All @@ -81,17 +94,21 @@ func (f *JSONFormatter) Format(diff digest.Differences) error {
modifications = append(modifications, strings.Join(modification.Current, ","))
}

jsonDiff := JSONDifference{Additions: additions, Modifications: modifications}
data, err := json.MarshalIndent(jsonDiff, "", " ")
for _, added := range additions {
_, err := fmt.Fprintf(f.stdout, "%s,%s\n", added, "ADDED")

if err != nil {
return fmt.Errorf("error when serializing with JSON formatter: %v", err)
if err != nil {
return fmt.Errorf("error when formatting additions with RowMark formatter: %v", err)
}
}

_, err = f.Stdout.Write(data)
for _, modified := range modifications {
_, err := fmt.Fprintf(f.stdout, "%s,%s\n", modified, "MODIFIED")

if err != nil {
return fmt.Errorf("error when formatting modifications with RowMark formatter: %v", err)
}

if err != nil {
return fmt.Errorf("error when writing to writer with JSON formatter: %v", err)
}

return nil
Expand Down
7 changes: 3 additions & 4 deletions cmd/formatter_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,6 @@ import (
)

func TestJSONFormat(t *testing.T) {
var formatter cmd.Formatter
diff := digest.Differences{
Additions: []digest.Addition{[]string{"additions"}},
Modifications: []digest.Modification{digest.Modification{Current: []string{"modification"}}},
Expand All @@ -26,16 +25,16 @@ func TestJSONFormat(t *testing.T) {
}`

var stdout bytes.Buffer
var stderr bytes.Buffer

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

err := formatter.Format(diff)
assert.NoError(t, err)
assert.Equal(t, expected, stdout.String())
}

func TestRowMarkFormatter(t *testing.T) {
var formatter cmd.Formatter
diff := digest.Differences{
Additions: []digest.Addition{[]string{"additions"}},
Modifications: []digest.Modification{digest.Modification{Current: []string{"modification"}}},
Expand All @@ -51,7 +50,7 @@ Rows:
var stdout bytes.Buffer
var stderr bytes.Buffer

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

err := formatter.Format(diff)

Expand Down
5 changes: 4 additions & 1 deletion cmd/root.go
Original file line number Diff line number Diff line change
Expand Up @@ -94,7 +94,10 @@ Most suitable for csv files created from database tables`,
os.Exit(2)
}

config.Formatter().Format(diff)
if err := NewFormatter(os.Stdout, os.Stderr, config).Format(diff); err != nil {
fmt.Fprintf(os.Stderr, "csvdiff failed: %v\n", err)
os.Exit(3)
}

return
},
Expand Down

0 comments on commit 1b4a540

Please sign in to comment.