Skip to content

Commit

Permalink
test(luna): define a testing memory-fs (#35)
Browse files Browse the repository at this point in the history
  • Loading branch information
plastikfan committed Oct 25, 2024
1 parent 966de20 commit 1ec2a1e
Show file tree
Hide file tree
Showing 5 changed files with 256 additions and 106 deletions.
105 changes: 0 additions & 105 deletions internal/laboratory/traverse-fs.go

This file was deleted.

13 changes: 13 additions & 0 deletions luna/luna-suite_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
package luna_test

import (
"testing"

. "github.com/onsi/ginkgo/v2" //nolint:revive // ok
. "github.com/onsi/gomega" //nolint:revive // ok
)

func TestLuna(t *testing.T) {
RegisterFailHandler(Fail)
RunSpecs(t, "Luna Suite")
}
178 changes: 178 additions & 0 deletions luna/mem-fs.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,178 @@
package luna

import (
"io/fs"
"os"
"strings"
"testing/fstest"

nef "github.com/snivilised/nefilim"
lab "github.com/snivilised/nefilim/internal/laboratory"
"github.com/snivilised/nefilim/internal/third/lo"
)

// MemFS is a memory fs based on fstest.MapFS intended to be used in
// unit tests. Clients can embed and override the methods defined here
// without having to provide a full implementation from scratch.
type MemFS struct {
fstest.MapFS
}

var (
_ nef.UniversalFS = (*MemFS)(nil)
)

func NewMemFS() *MemFS {
return &MemFS{
MapFS: fstest.MapFS{},
}
}

func (f *MemFS) FileExists(name string) bool {
if mapFile, found := f.MapFS[name]; found && !mapFile.Mode.IsDir() {
return true
}

return false
}

func (f *MemFS) DirectoryExists(name string) bool {
if mapFile, found := f.MapFS[name]; found && mapFile.Mode.IsDir() {
return true
}

return false
}

func (f *MemFS) Create(name string) (*os.File, error) {
if _, err := f.Stat(name); err == nil {
return nil, fs.ErrExist
}

file := &fstest.MapFile{
Mode: lab.Perms.File,
}

f.MapFS[name] = file
// TODO: this needs a resolution using a file interface
// rather than using os.File which is a struct not an
// interface
dummy := &os.File{}

return dummy, nil
}

func (f *MemFS) MakeDir(name string, perm os.FileMode) error {
if !fs.ValidPath(name) {
return nef.NewInvalidPathError("MakeDir", name)
}

if _, found := f.MapFS[name]; !found {
f.MapFS[name] = &fstest.MapFile{
Mode: perm | os.ModeDir,
}
}

return nil
}

func (f *MemFS) MakeDirAll(name string, perm os.FileMode) error {
if !fs.ValidPath(name) {
return nef.NewInvalidPathError("MakeDirAll", name)
}

segments := strings.Split(name, "/")

_ = lo.Reduce(segments,
func(acc []string, s string, _ int) []string {
acc = append(acc, s)
path := strings.Join(acc, "/")

if _, found := f.MapFS[path]; !found {
f.MapFS[path] = &fstest.MapFile{
Mode: perm | os.ModeDir,
}
}

return acc
}, []string{},
)

return nil
}

// Ensure is not currently implemented on MemFS
func (f *MemFS) Ensure(_ nef.PathAs) (string, error) {
return "", nil
}

// Move is not currently implemented on MemFS
func (f *MemFS) Move(_, _ string) error {
return nil
}

// Change is not currently implemented on MemFS
func (f *MemFS) Change(_, _ string) error {
return nil
}

// Copy is not currently implemented on MemFS
func (f *MemFS) Copy(_, _ string) error {
return nil
}

func (f *MemFS) CopyFS(_ string, _ fs.FS) error {
return nil
}

// Remove removes the named file or (empty) directory.
// If there is an error, it will be of type *PathError.
func (f *MemFS) Remove(name string) error {
if _, found := f.MapFS[name]; found {
delete(f.MapFS, name)
return nil
}

return os.ErrNotExist
}

func (f *MemFS) RemoveAll(path string) error {
keys := lo.Keys(f.MapFS)
matched := lo.Filter(keys, func(item string, _ int) bool {
return strings.HasPrefix(item, path)
})

if len(matched) == 0 {
return os.ErrNotExist
}

for _, item := range matched {
delete(f.MapFS, item)
}

return nil
}

func (f *MemFS) Rename(from, to string) error {
if item, found := f.MapFS[from]; found {
delete(f.MapFS, from)
f.MapFS[to] = item

return nil
}

return os.ErrNotExist
}

func (f *MemFS) WriteFile(name string, data []byte, perm os.FileMode) error {
if _, err := f.Stat(name); err == nil {
return fs.ErrExist
}

f.MapFS[name] = &fstest.MapFile{
Data: data,
Mode: perm,
}

return nil
}
63 changes: 63 additions & 0 deletions luna/mem-fs_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,63 @@
package luna_test

import (
"os"

. "github.com/onsi/ginkgo/v2" //nolint:revive // ok
. "github.com/onsi/gomega" //nolint:revive // ok

nef "github.com/snivilised/nefilim"
lab "github.com/snivilised/nefilim/internal/laboratory"
"github.com/snivilised/nefilim/luna"
)

var (
data = []byte("some content")
)

var _ = Describe("MemFs", func() {
var fS nef.UniversalFS

BeforeEach(func() {
fS = luna.NewMemFS()
})

Context("Remove", func() {
When("given: item exists", func() {
It("🧪 should: remove item", func() {
path := "widgets/foo.txt"
Expect(fS.WriteFile(path, data, lab.Perms.File)).To(Succeed())
Expect(fS.Remove(path)).To(Succeed())
Expect(fS.FileExists(path)).To(BeFalse())
})
})

When("given: item does NOT exist", func() {
It("🧪 should: return error", func() {
path := "missing/foo.txt"
Expect(fS.Remove(path)).To(MatchError(os.ErrNotExist),
"expected error os.ErrNotExist",
)
})
})
})

Context("RemoveAll", func() {
When("given: some items exist", func() {
It("🧪 should: remove only matching item", func() {
foo := "a/b/foo.txt"
Expect(fS.WriteFile(foo, data, lab.Perms.File)).To(Succeed())
bar := "a/b/bar.txt"
Expect(fS.WriteFile(bar, data, lab.Perms.File)).To(Succeed())
baz := "bin/baz.txt"
Expect(fS.WriteFile(baz, data, lab.Perms.File)).To(Succeed())
path := "a/b"

Expect(fS.RemoveAll(path)).To(Succeed(), "failed to remove all in path")
Expect(fS.FileExists(foo)).To(BeFalse(), "foo should not exist")
Expect(fS.FileExists(bar)).To(BeFalse(), "bar should not exist")
Expect(fS.FileExists(baz)).To(BeTrue(), "baz should still exist")
})
})
})
})
3 changes: 2 additions & 1 deletion scripts/coverage-exclusion-list.txt
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
github.com/snivilised/nefilim/luna
github.com/snivilised/nefilim/fs-absolute.go
github.com/snivilised/nefilim/internal/third
github.com/snivilised/nefilim/internal/laboratory/
github.com/snivilised/nefilim/internal/laboratory

0 comments on commit 1ec2a1e

Please sign in to comment.