Skip to content

Commit

Permalink
Introduce afero.Fs to do basefile and deltafile validation
Browse files Browse the repository at this point in the history
  • Loading branch information
aswinkarthik committed Oct 8, 2019
1 parent bc535ee commit 1381196
Show file tree
Hide file tree
Showing 6 changed files with 139 additions and 24 deletions.
54 changes: 48 additions & 6 deletions cmd/config.go
Original file line number Diff line number Diff line change
@@ -1,7 +1,8 @@
package cmd

import (
"errors"
"fmt"
"github.com/spf13/afero"
"strings"

"github.com/aswinkarthik/csvdiff/pkg/digest"
Expand All @@ -13,6 +14,8 @@ type Config struct {
ValueColumnPositions []int
IncludeColumnPositions []int
Format string
BaseFilename string
DeltaFilename string
}

// GetPrimaryKeys is to return the --primary-key flags as digest.Positions array.
Expand Down Expand Up @@ -42,13 +45,52 @@ func (c Config) GetIncludeColumnPositions() digest.Positions {

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

for _, format := range allFormats {
if strings.ToLower(c.Format) == format {
return nil
formatFound := false
for _, format := range allFormats {
if strings.ToLower(c.Format) == format {
formatFound = true
}
}
if !formatFound {
return fmt.Errorf("specified format is not valid")
}
}

{
// base-file validation

if exists, err := afero.Exists(fs, c.BaseFilename); err != nil {
return fmt.Errorf("error reading base-file %s: %v", c.BaseFilename, err)
} else if !exists {
return fmt.Errorf("base-file %s does not exits", c.BaseFilename)
}

if isDir, err := afero.IsDir(fs, c.BaseFilename); err != nil {
return fmt.Errorf("error reading base-file %s: %v", c.BaseFilename, err)
} else if isDir {
return fmt.Errorf("base-file %s should be a file", c.BaseFilename)
}
}

{
// delta file validation

if exists, err := afero.Exists(fs, c.DeltaFilename); err != nil {
return fmt.Errorf("error reading delta-file %s: %v", c.DeltaFilename, err)
} else if !exists {
return fmt.Errorf("delta-file %s does not exits", c.DeltaFilename)
}

if isDir, err := afero.IsDir(fs, c.DeltaFilename); err != nil {
return fmt.Errorf("error reading delta-file %s: %v", c.DeltaFilename, err)
} else if isDir {
return fmt.Errorf("delta-file %s should be a file", c.DeltaFilename)
}
}

return errors.New("Specified format is not valid")
return nil
}
70 changes: 62 additions & 8 deletions cmd/config_test.go
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
package cmd_test

import (
"github.com/spf13/afero"
"os"
"testing"

"github.com/aswinkarthik/csvdiff/cmd"
Expand Down Expand Up @@ -31,15 +33,67 @@ func TestValueColumnPositions(t *testing.T) {
}

func TestConfigValidate(t *testing.T) {
config := &cmd.Config{}
assert.Error(t, config.Validate())
t.Run("should validate format", func(t *testing.T) {
fs := afero.NewMemMapFs()

config = &cmd.Config{Format: "rowmark"}
assert.NoError(t, config.Validate())
config := validConfig(t, fs)

config = &cmd.Config{Format: "rowMARK"}
assert.NoError(t, config.Validate())
config.Format = ""
assert.Error(t, config.Validate(fs))

config = &cmd.Config{Format: "json"}
assert.NoError(t, config.Validate())
config.Format = "rowmark"
assert.NoError(t, config.Validate(fs))

config.Format = "rowMARK"
assert.NoError(t, config.Validate(fs))

config.Format = "json"
assert.NoError(t, config.Validate(fs))
})

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"}
err := config.Validate(fs)
assert.EqualError(t, err, "base-file /base.csv does not exits")
})

t.Run("should validate if base file or delta file is a file", func(t *testing.T) {
fs := afero.NewMemMapFs()
err := fs.Mkdir("/base.csv", os.ModePerm)
assert.NoError(t, err)

config := &cmd.Config{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"}
err = config.Validate(fs)
assert.EqualError(t, err, "delta-file /delta.csv should be a file")
})

t.Run("should validate if both base and delta file exist", 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)

config := &cmd.Config{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"}
}
35 changes: 26 additions & 9 deletions cmd/root.go
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@ package cmd
import (
"fmt"
"github.com/fatih/color"
"github.com/spf13/afero"
"io"
"os"
"strings"
Expand Down Expand Up @@ -64,20 +65,36 @@ Most suitable for csv files created from database tables`,
if timed {
defer timeTrack(time.Now(), "csvdiff")
}
fs := afero.NewOsFs()

baseFile := newReadCloser(args[0])
defer baseFile.Close()
deltaFile := newReadCloser(args[1])
defer deltaFile.Close()
baseFilename := args[0]
deltaFilename := args[1]

baseFile, err := newReadCloser(baseFilename)
if err != nil {
return fmt.Errorf("error opening base-file %s: %v", baseFilename, err)
}

deltaFile, err := newReadCloser(deltaFilename)
if err != nil {
return fmt.Errorf("error opening delta-file %s: %v", deltaFilename, err)
}

defer func() {
_ = baseFile.Close()
_ = deltaFile.Close()
}()

config := Config{
IncludeColumnPositions: includeColumnPositions,
Format: format,
PrimaryKeyPositions: primaryKeyPositions,
ValueColumnPositions: valueColumnPositions,
BaseFilename: baseFilename,
DeltaFilename: deltaFilename,
}

if err := config.Validate(); err != nil {
if err := config.Validate(fs); err != nil {
return err
}

Expand Down Expand Up @@ -151,16 +168,16 @@ func init() {
rootCmd.Flags().BoolVarP(&timed, "time", "", false, "Measure time")
}

func newReadCloser(filename string) io.ReadCloser {
func newReadCloser(filename string) (io.ReadCloser, error) {
file, err := os.Open(filename)
if err != nil {
panic(err)
return nil, err
}

return file
return file, nil
}

func timeTrack(start time.Time, name string) {
elapsed := time.Since(start)
fmt.Fprintln(os.Stderr, fmt.Sprintf("%s took %s", name, elapsed))
_, _ = fmt.Fprintln(os.Stderr, fmt.Sprintf("%s took %s", name, elapsed))
}
1 change: 1 addition & 0 deletions go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ require (
github.com/fatih/color v1.7.0
github.com/mattn/go-colorable v0.1.2 // indirect
github.com/spaolacci/murmur3 v1.1.0 // indirect
github.com/spf13/afero v1.1.2
github.com/spf13/cobra v0.0.5
github.com/stretchr/testify v1.3.0
golang.org/x/sys v0.0.0-20190804053845-51ab0e2deafa // indirect
Expand Down
2 changes: 2 additions & 0 deletions go.sum
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,7 @@ github.com/spaolacci/murmur3 v0.0.0-20180118202830-f09979ecbc72 h1:qLC7fQah7D6K1
github.com/spaolacci/murmur3 v0.0.0-20180118202830-f09979ecbc72/go.mod h1:JwIasOWyU6f++ZhiEuf87xNszmSA2myDM2Kzu9HwQUA=
github.com/spaolacci/murmur3 v1.1.0 h1:7c1g84S4BPRrfL5Xrdp6fOJ206sU9y293DDHaoy0bLI=
github.com/spaolacci/murmur3 v1.1.0/go.mod h1:JwIasOWyU6f++ZhiEuf87xNszmSA2myDM2Kzu9HwQUA=
github.com/spf13/afero v1.1.2 h1:m8/z1t7/fwjysjQRYbP0RD+bUIF/8tJwPdEZsI83ACI=
github.com/spf13/afero v1.1.2/go.mod h1:j4pytiNVoe2o6bmDsKpLACNPDBIoEAkihy7loJ1B0CQ=
github.com/spf13/cast v1.3.0/go.mod h1:Qx5cxh0v+4UWYiBimWS+eyWzqEqokIECu5etghLkUJE=
github.com/spf13/cobra v0.0.5 h1:f0B+LkLX6DtmRH1isoNA9VTtNUK9K8xYd28JNNfOv/s=
Expand All @@ -55,6 +56,7 @@ golang.org/x/sys v0.0.0-20190222072716-a9d3bda3a223 h1:DH4skfRX4EBpamg7iV4ZlCpbl
golang.org/x/sys v0.0.0-20190222072716-a9d3bda3a223/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
golang.org/x/sys v0.0.0-20190804053845-51ab0e2deafa h1:KIDDMLT1O0Nr7TSxp8xM5tJcdn8tgyAONntO829og1M=
golang.org/x/sys v0.0.0-20190804053845-51ab0e2deafa/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/text v0.3.0 h1:g61tztE5qeGQ89tm6NTjjM9VPIm088od1l6aSorWRWg=
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
1 change: 0 additions & 1 deletion pkg/digest/config.go
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,6 @@ import "io"
// Key: The primary key positions
// Value: The Value positions that needs to be compared for diff
// Include: Include these positions in output. It is Value positions by default.
// KeepSource: return the source and target string if diff is computed
type Config struct {
Key Positions
Value Positions
Expand Down

0 comments on commit 1381196

Please sign in to comment.