From c62559d0f9c1cbd6eb6dd313f05dec800435fb50 Mon Sep 17 00:00:00 2001 From: Gabriel <45315755+gm0stache@users.noreply.github.com> Date: Sun, 28 Jan 2024 19:00:52 +0100 Subject: [PATCH] refactor: restructure code to enhance testability --- cmd/mkf/main.go | 26 ++++++---- go.mod | 2 + go.sum | 4 ++ internal/fspath/filecreator.go | 25 ++++++++++ internal/fspath/filecreator_test.go | 47 +++++++++++++++++++ internal/{pathspltr => fspath}/pathspltr.go | 8 ++-- .../{pathspltr => fspath}/pathspltr_test.go | 4 +- 7 files changed, 101 insertions(+), 15 deletions(-) create mode 100644 internal/fspath/filecreator.go create mode 100644 internal/fspath/filecreator_test.go rename internal/{pathspltr => fspath}/pathspltr.go (53%) rename internal/{pathspltr => fspath}/pathspltr_test.go (93%) diff --git a/cmd/mkf/main.go b/cmd/mkf/main.go index 0218cc6..a2b22bc 100644 --- a/cmd/mkf/main.go +++ b/cmd/mkf/main.go @@ -2,29 +2,37 @@ package main import ( "fmt" + "io/fs" "os" - "github.com/gm0stache/utils/internal/pathspltr" + "github.com/gm0stache/utils/internal/fspath" ) const ( default_dir_permissons_code = 0700 ) +type RealFsCreator struct { +} + +func (rc *RealFsCreator) MkdirAll(path string, perm fs.FileMode) error { + return os.MkdirAll(path, perm) +} + +func (rc *RealFsCreator) Create(name string) error { + _, err := os.Create(name) + return err +} + func main() { args := os.Args if len(args) != 2 { - fmt.Println("invalid invocation. Usage: mkf file_path") + fmt.Println("invalid invocation.\nusage: mkf file_path") os.Exit(-1) } + creator := RealFsCreator{} filePath := args[1] - pathComponents := pathspltr.GetFilePathParts(filePath) - err := os.MkdirAll(pathComponents.DirPath, default_dir_permissons_code) - if err != nil { - fmt.Printf("Error:\n%s", err.Error()) - os.Exit(-1) - } - _, err = os.Create(filePath) + err := fspath.CreateFile(&creator, filePath) if err != nil { fmt.Printf("Error:\n%s", err.Error()) os.Exit(-1) diff --git a/go.mod b/go.mod index 572ba39..717112f 100644 --- a/go.mod +++ b/go.mod @@ -7,5 +7,7 @@ require github.com/stretchr/testify v1.8.4 require ( github.com/davecgh/go-spew v1.1.1 // indirect github.com/pmezard/go-difflib v1.0.0 // indirect + github.com/spf13/afero v1.11.0 // indirect + golang.org/x/text v0.14.0 // indirect gopkg.in/yaml.v3 v3.0.1 // indirect ) diff --git a/go.sum b/go.sum index fa4b6e6..35d59fd 100644 --- a/go.sum +++ b/go.sum @@ -2,8 +2,12 @@ github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= +github.com/spf13/afero v1.11.0 h1:WJQKhtpdm3v2IzqG8VMqrr6Rf3UYpEF239Jy9wNepM8= +github.com/spf13/afero v1.11.0/go.mod h1:GH9Y3pIexgf1MTIWtNGyogA5MwRIDXGUr+hbWNoBjkY= github.com/stretchr/testify v1.8.4 h1:CcVxjf3Q8PM0mHUKJCdn+eZZtm5yQwehR5yeSVQQcUk= github.com/stretchr/testify v1.8.4/go.mod h1:sz/lmYIOXD/1dqDmKjjqLyZ2RngseejIcXlSw2iwfAo= +golang.org/x/text v0.14.0 h1:ScX5w1eTa3QqT8oi6+ziP7dTV1S2+ALU0bI+0zXKWiQ= +golang.org/x/text v0.14.0/go.mod h1:18ZOQIKpY8NJVqYksKHtTdi31H5itFRjB5/qKTNYzSU= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405 h1:yhCVgyC4o1eVCa2tZl7eS0r+SDo693bJlVdllGtEeKM= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA= diff --git a/internal/fspath/filecreator.go b/internal/fspath/filecreator.go new file mode 100644 index 0000000..d26e9d0 --- /dev/null +++ b/internal/fspath/filecreator.go @@ -0,0 +1,25 @@ +package fspath + +import ( + "io/fs" +) + +const ( + default_dir_permissons_code = 0700 +) + +type FsCreator interface { + MkdirAll(path string, perm fs.FileMode) error + Create(name string) error +} + +// CreateFile creates all missing parent dir's in the file and the file itself. +func CreateFile(creator FsCreator, path string) error { + pathComponents := getPathComponents(path) + err := creator.MkdirAll(pathComponents.DirPath, default_dir_permissons_code) + if err != nil { + return err + } + err = creator.Create(path) + return err +} diff --git a/internal/fspath/filecreator_test.go b/internal/fspath/filecreator_test.go new file mode 100644 index 0000000..e33db7a --- /dev/null +++ b/internal/fspath/filecreator_test.go @@ -0,0 +1,47 @@ +package fspath + +import ( + "io/fs" + "testing" + + "github.com/spf13/afero" + "github.com/stretchr/testify/assert" +) + +type fakeFsCreator struct { + fs *afero.MemMapFs +} + +func (rc *fakeFsCreator) MkdirAll(path string, perm fs.FileMode) error { + return rc.fs.MkdirAll(path, perm) +} + +func (rc *fakeFsCreator) Create(name string) error { + _, err := rc.fs.Create(name) + return err +} + +func TestFsCreator(t *testing.T) { + cases := map[string]string{ + "simple file": "./exampleDir/example.txt", + "dotfile, relative to user dir": "~/.config/.vimrc", + "multi-dot-file, deeply nested": "./test/test/test/testing.dev.env", + } + + // arrange + fakeFS := fakeFsCreator{ + fs: new(afero.MemMapFs), + } + + for name, path := range cases { + t.Run(name, func(t *testing.T) { + // act + err := CreateFile(&fakeFS, path) + + // assert + assert.NoError(t, err) + // fileExists, _ := fakeFS.fs.Exists(path) + // assert.True(t, fileExists, "file should be created") + }) + } +} diff --git a/internal/pathspltr/pathspltr.go b/internal/fspath/pathspltr.go similarity index 53% rename from internal/pathspltr/pathspltr.go rename to internal/fspath/pathspltr.go index f554a83..9b34953 100644 --- a/internal/pathspltr/pathspltr.go +++ b/internal/fspath/pathspltr.go @@ -1,16 +1,16 @@ -package pathspltr +package fspath import ( "path/filepath" ) -type PathComponent struct { +type pathComponents struct { Filename string DirPath string } -func GetFilePathParts(path string) PathComponent { - return PathComponent{ +func getPathComponents(path string) pathComponents { + return pathComponents{ Filename: filepath.Base(path), DirPath: filepath.Dir(path), } diff --git a/internal/pathspltr/pathspltr_test.go b/internal/fspath/pathspltr_test.go similarity index 93% rename from internal/pathspltr/pathspltr_test.go rename to internal/fspath/pathspltr_test.go index 56446e1..fd64736 100644 --- a/internal/pathspltr/pathspltr_test.go +++ b/internal/fspath/pathspltr_test.go @@ -1,4 +1,4 @@ -package pathspltr +package fspath import ( "testing" @@ -37,7 +37,7 @@ func TestFilePathSplitting(t *testing.T) { for testname, testData := range cases { t.Run(testname, func(t *testing.T) { // act - pathComponents := GetFilePathParts(testData.givenPath) + pathComponents := getPathComponents(testData.givenPath) // assert assert.EqualValues(t, pathComponents.DirPath, testData.expectedDirPath)