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 69af970
Show file tree
Hide file tree
Showing 6 changed files with 208 additions and 56 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)
}
32 changes: 20 additions & 12 deletions linker.go
Original file line number Diff line number Diff line change
@@ -1,20 +1,21 @@
package main

import (
"fmt"
"os"
"path"
"path/filepath"
)

type Linker struct {
outputer IOutputer
fs MkdirSymlinker
os OS
}

func NewLinker(outputer IOutputer, fs MkdirSymlinker) Linker {
func NewLinker(outputer IOutputer, os OS) Linker {
return Linker{
outputer: outputer,
fs: fs,
os: os,
}
}

Expand Down Expand Up @@ -71,19 +72,26 @@ func needBackup(dest string) (bool, error) {
return false, nil
}

// backup copies existing destination file to backup dir.
func backup(dest string, destAbs string, backupDir string) error {
// Move moves oldpath to newpath, creating target directories if need.
func (l *Linker) Move(oldpath, newpath string) error {
// todo: if dry-run, just print

dir := path.Dir(backupDir + "/" + dest)
err := os.MkdirAll(dir, 0700)
// check if destination file exists
exists, err := IsExists(l.os, oldpath)
if err != nil {
return err
}
if !exists {
return fmt.Errorf("File %s not exists", oldpath)
}

err = l.os.MkdirAll(path.Dir(newpath), 0700)
if err != nil {
return err
}

backupPath := backupDir + "/" + dest
outputer.OutVerbose(" → backup %s to %s", destAbs, backupPath)
err = os.Rename(destAbs, backupPath)
l.outputer.OutVerbose(" → backup %s to %s", oldpath, newpath)
err = l.os.Rename(oldpath, newpath)
return err
}

Expand Down Expand Up @@ -112,11 +120,11 @@ func backupCopy(filename, backupDir string) error {
func (l *Linker) SetSymlink(srcAbs string, destAbs string) error {

dir := path.Dir(destAbs)
if err := l.fs.MkdirAll(dir, 0700); err != nil {
if err := l.os.MkdirAll(dir, 0700); err != nil {
return err
}

if err := l.fs.Symlink(srcAbs, destAbs); err != nil {
if err := l.os.Symlink(srcAbs, destAbs); err != nil {
return err
}

Expand Down
88 changes: 63 additions & 25 deletions linker_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -117,23 +117,61 @@ func TestNeedBackup(t *testing.T) {
assert.False(t, actual)
}

func TestBackup(t *testing.T) {

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

dest := "new"
destAbs := "/tmp/dotbro/linker/TestBackup/new"
backupDir := "/tmp/dotbro/linker/TestBackup/backup"
func TestMove(t *testing.T) {
cases := []struct {
os *FakeOS
oldpath string
newpath 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,
},
oldpath: "/path/dest",
expectedError: errors.New("File /path/dest not exists"),
},
{
// Failure when MkdirAll fails
os: &FakeOS{
IsNotExistResult: false,
MkdirAllError: errors.New("MkdirAll error"),
},
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,
},
}

err := backup(dest, destAbs, backupDir)
assert.Error(t, err)
for _, c := range cases {
linker := NewLinker(&FakeOutputer{}, c.os)
err := linker.Move(c.oldpath, c.newpath)

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 Expand Up @@ -176,33 +214,33 @@ func (o *FakeOutputer) OutError(format string, v ...interface{}) {

func TestNewLinker(t *testing.T) {
cases := []struct {
mkdirSymlinker *FakeMkdirSymlinker
os *FakeOS
srcAbs string
destAbs string
expectedError error
}{
{
mkdirSymlinker: &FakeMkdirSymlinker{
&FakeDirMaker{MkdirAllError: nil},
&FakeSymlinker{SymlinkError: nil},
os: &FakeOS{
MkdirAllError: nil,
SymlinkError: nil,
},
srcAbs: "/src/path",
destAbs: "/dest/path",
expectedError: nil,
},
{
mkdirSymlinker: &FakeMkdirSymlinker{
&FakeDirMaker{MkdirAllError: errors.New("Permission denied")},
&FakeSymlinker{SymlinkError: nil},
os: &FakeOS{
MkdirAllError: errors.New("Permission denied"),
SymlinkError: nil,
},
srcAbs: "/src/path",
destAbs: "/dest/path",
expectedError: errors.New("Permission denied"),
},
{
mkdirSymlinker: &FakeMkdirSymlinker{
&FakeDirMaker{MkdirAllError: nil},
&FakeSymlinker{SymlinkError: errors.New("File exists")},
os: &FakeOS{
MkdirAllError: nil,
SymlinkError: errors.New("File exists"),
},
srcAbs: "/src/path",
destAbs: "/dest/path",
Expand All @@ -211,7 +249,7 @@ func TestNewLinker(t *testing.T) {
}

for _, c := range cases {
linker := NewLinker(&FakeOutputer{}, c.mkdirSymlinker)
linker := NewLinker(&FakeOutputer{}, c.os)

err := linker.SetSymlink(c.srcAbs, c.destAbs)
if !reflect.DeepEqual(err, c.expectedError) {
Expand Down

0 comments on commit 69af970

Please sign in to comment.