Skip to content

Commit

Permalink
Rework backup() tests
Browse files Browse the repository at this point in the history
  • Loading branch information
hypnoglow committed Jan 27, 2017
1 parent 2b63138 commit 592f400
Show file tree
Hide file tree
Showing 6 changed files with 186 additions and 29 deletions.
5 changes: 3 additions & 2 deletions docopt.go
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,8 @@ import "github.com/docopt/docopt-go"

const version = "0.2.0"

func parseArguments() (map[string]interface{}, error) {
// ParseArguments parses arguments, that were passed to the dotbro, by docopt.
func ParseArguments(argv []string) (map[string]interface{}, error) {
usage := `dotbro - simple yet effective dotfiles manager.
Usage:
Expand All @@ -27,5 +28,5 @@ Other options:
-V --version Show version.
`

return docopt.Parse(usage, nil, true, "dotbro "+version, false)
return docopt.Parse(usage, argv, true, "dotbro "+version, false)
}
10 changes: 10 additions & 0 deletions docopt_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
package main

import "testing"

func TestParseArguments(t *testing.T) {
_, err := ParseArguments([]string{"--quiet"})
if err != nil {
t.Fatalf("Error parsing arguments: %v", err.Error())
}
}
114 changes: 103 additions & 11 deletions fs.go
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,19 @@ package main

import "os"

// Intefaces

type OS interface {
MkdirAll(path string, perm os.FileMode) error

Symlink(oldname, newname string) error

Stat(name string) (os.FileInfo, error)
IsNotExist(err error) bool

Rename(oldpath, newpath string) error
}

type DirMaker interface {
MkdirAll(path string, perm os.FileMode) error
}
Expand All @@ -17,18 +30,51 @@ type Stater interface {
IsNotExist(err error) bool
}

type FakeMkdirSymlinker struct {
*FakeDirMaker
*FakeSymlinker
type MkdirSymlinker interface {
DirMaker
Symlinker
}

type StatDirMaker interface {
Stater
DirMaker
}

type Renamer interface {
Rename(oldpath, newpath string) error
}

// Fake implementation of interface

type FakeOS struct {
MkdirAllError error
SymlinkError error
StatFileInfo os.FileInfo
StatError error
IsNotExistResult bool
RenameError error
}

func (f *FakeOS) MkdirAll(path string, perm os.FileMode) error {
return f.MkdirAllError
}

func (f *FakeOS) Symlink(oldname, newname string) error {
return f.SymlinkError
}

func (f *FakeOS) Stat(name string) (os.FileInfo, error) {
return f.StatFileInfo, f.StatError
}

func (f *FakeOS) IsNotExist(err error) bool {
return f.IsNotExistResult
}

func (f *FakeOS) Rename(oldname, newname string) error {
return f.RenameError
}

type FakeDirMaker struct {
MkdirAllError error
}
Expand Down Expand Up @@ -59,13 +105,48 @@ func (f *FakeStater) IsNotExist(err error) bool {
return f.IsNotExistResult
}

type MkdirSymlinker interface {
DirMaker
Symlinker
type FakeMkdirSymlinker struct {
*FakeDirMaker
*FakeSymlinker
}

type FakeStatDirMaker struct {
*FakeStater
*FakeDirMaker
}

type FakeRenamer struct {
RenameError error
}

func (f *FakeRenamer) Rename(oldpath, newpath string) error {
return f.RenameError
}

// Actual implementation of interface using os package.

type OSFS struct{}

func (f *OSFS) MkdirAll(path string, perm os.FileMode) error {
return os.MkdirAll(path, perm)
}

func (f *OSFS) Symlink(oldname, newname string) error {
return os.Symlink(oldname, newname)
}

func (s *OSFS) Stat(name string) (os.FileInfo, error) {
return os.Stat(name)
}

func (s *OSFS) IsNotExist(err error) bool {
return os.IsNotExist(err)
}

func (f *OSFS) Rename(oldpath, newpath string) error {
return os.Rename(oldpath, newpath)
}

type OsDirMaker struct {
}

Expand All @@ -79,11 +160,6 @@ func (f *OsSymlinker) Symlink(oldname, newname string) error {
return os.Symlink(oldname, newname)
}

type OsMkdirSymlinker struct {
*OsDirMaker
*OsSymlinker
}

type OsStater struct{}

func (s *OsStater) Stat(name string) (os.FileInfo, error) {
Expand All @@ -93,3 +169,19 @@ func (s *OsStater) Stat(name string) (os.FileInfo, error) {
func (s *OsStater) IsNotExist(err error) bool {
return os.IsNotExist(err)
}

type OsMkdirSymlinker struct {
*OsDirMaker
*OsSymlinker
}

type OsStatDirMaker struct {
*OsStater
*OsDirMaker
}

type OsRenamer struct{}

func (f *OsRenamer) Rename(oldpath, newpath string) error {
return os.Rename(oldpath, newpath)
}
14 changes: 12 additions & 2 deletions linker.go
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
package main

import (
"fmt"
"os"
"path"
"path/filepath"
Expand Down Expand Up @@ -72,11 +73,20 @@ func needBackup(dest string) (bool, error) {
}

// backup copies existing destination file to backup dir.
func backup(dest string, destAbs string, backupDir string) error {
func backup(dest string, destAbs string, backupDir string, os OS, outputer IOutputer) error {
// todo: if dry-run, just print

// check if destination file exists
exists, err := IsExists(os, destAbs)
if err != nil {
return err
}
if !exists {
return fmt.Errorf("File %s not exists", destAbs)
}

dir := path.Dir(backupDir + "/" + dest)
err := os.MkdirAll(dir, 0700)
err = os.MkdirAll(dir, 0700)
if err != nil {
return err
}
Expand Down
65 changes: 53 additions & 12 deletions linker_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -118,22 +118,63 @@ func TestNeedBackup(t *testing.T) {
}

func TestBackup(t *testing.T) {
cases := []struct {
os *FakeOS
dest string
destAbs string
backupDir string
expectedError error
}{
{
// Failure when IsExists fails
os: &FakeOS{
StatError: errors.New("Some error"),
},
expectedError: errors.New("Some error"),
},
{
// Failure when dest file not exists
os: &FakeOS{
IsNotExistResult: true,
},
destAbs: "/path/dest",
expectedError: errors.New("File /path/dest not exists"),
},
{
// Failure when MkdirAll fails
os: &FakeOS{
IsNotExistResult: false,
MkdirAllError: errors.New("MkdirAll error"),
},
//destAbs: "/path/dest",
expectedError: errors.New("MkdirAll error"),
},
{
// Failure when Rename fails
os: &FakeOS{
IsNotExistResult: false,
RenameError: errors.New("Rename error"),
},
expectedError: errors.New("Rename error"),
},
{
// Success
os: &FakeOS{
IsNotExistResult: false,
},
expectedError: nil,
},
}

os.RemoveAll("/tmp/dotbro") // Cleanup

dest := "new"
destAbs := "/tmp/dotbro/linker/TestBackup/new"
backupDir := "/tmp/dotbro/linker/TestBackup/backup"
outputer := new(FakeOutputer)

err := backup(dest, destAbs, backupDir)
assert.Error(t, err)
for _, c := range cases {
err := backup(c.dest, c.destAbs, c.backupDir, c.os, outputer)

err = os.MkdirAll(destAbs, 0700)
if err != nil {
t.Fatal(err)
if !reflect.DeepEqual(err, c.expectedError) {
t.Errorf("Expected err to be %v but it was %v\n", c.expectedError, err)
}
}
err = backup(dest, destAbs, backupDir)
assert.Empty(t, err)
}

func TestBackupCopy(t *testing.T) {
Expand Down
7 changes: 5 additions & 2 deletions main.go
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,10 @@ var outputer Outputer
var (
osStater = new(OsStater)
osDirMaker = new(OsDirMaker)
osStatDirMaker = new(OsStatDirMaker)
osMkdirSymlinker = new(OsMkdirSymlinker)
osRenamer = new(OsRenamer)
osfs = new(OSFS)
)

func main() {
Expand All @@ -28,7 +31,7 @@ func main() {

// Parse arguments

args, err := parseArguments()
args, err := ParseArguments(nil)
if err != nil {
outputer.OutError("Error parsing aruments: %s", err)
exit(1)
Expand Down Expand Up @@ -302,7 +305,7 @@ func installDotfile(src, dest string, linker Linker, config *Configuration, srcD
}

if needBackup {
err = backup(dest, destAbs, config.Directories.Backup)
err = backup(dest, destAbs, config.Directories.Backup, osfs, &outputer)
if err != nil {
outputer.OutError("Error backuping file %s: %s", destAbs, err)
exit(1)
Expand Down

0 comments on commit 592f400

Please sign in to comment.