feat(ax): apply AX compliance sweep — usage examples and predictable names
- Add // Example: usage comments to all Medium interface methods in io.go - Add // Example: comments to local, s3, sqlite, store, datanode, node medium methods - Rename short variable `n` → `nodeTree` throughout node/node_test.go - Rename short variable `s` → `keyValueStore` in store/store_test.go - Rename counter variable `n` → `count` in store/store_test.go - Rename `m` → `medium` in store/medium_test.go helper - Remove redundant prose comments replaced by usage examples Co-Authored-By: Virgil <virgil@lethean.io>
This commit is contained in:
parent
378fc7c0de
commit
702286a583
10 changed files with 244 additions and 186 deletions
|
|
@ -38,6 +38,8 @@ type Medium struct {
|
|||
lock sync.RWMutex
|
||||
}
|
||||
|
||||
// Example: medium := datanode.New()
|
||||
// Example: _ = medium.Write("jobs/run.log", "started")
|
||||
func New() *Medium {
|
||||
return &Medium{
|
||||
dataNode: borgdatanode.New(),
|
||||
|
|
|
|||
12
io.go
12
io.go
|
|
@ -15,31 +15,43 @@ import (
|
|||
// Example: backup, _ := io.NewSandboxed("/srv/backup")
|
||||
// Example: _ = io.Copy(medium, "data/report.json", backup, "daily/report.json")
|
||||
type Medium interface {
|
||||
// Example: content, _ := medium.Read("config/app.yaml")
|
||||
Read(path string) (string, error)
|
||||
|
||||
// Example: _ = medium.Write("config/app.yaml", "port: 8080")
|
||||
Write(path, content string) error
|
||||
|
||||
// Example: _ = medium.WriteMode("keys/private.key", key, 0600)
|
||||
WriteMode(path, content string, mode fs.FileMode) error
|
||||
|
||||
// Example: _ = medium.EnsureDir("config/app")
|
||||
EnsureDir(path string) error
|
||||
|
||||
// Example: isFile := medium.IsFile("config/app.yaml")
|
||||
IsFile(path string) bool
|
||||
|
||||
// Example: _ = medium.Delete("config/app.yaml")
|
||||
Delete(path string) error
|
||||
|
||||
// Example: _ = medium.DeleteAll("logs/archive")
|
||||
DeleteAll(path string) error
|
||||
|
||||
// Example: _ = medium.Rename("drafts/todo.txt", "archive/todo.txt")
|
||||
Rename(oldPath, newPath string) error
|
||||
|
||||
// Example: entries, _ := medium.List("config")
|
||||
List(path string) ([]fs.DirEntry, error)
|
||||
|
||||
// Example: info, _ := medium.Stat("config/app.yaml")
|
||||
Stat(path string) (fs.FileInfo, error)
|
||||
|
||||
// Example: file, _ := medium.Open("config/app.yaml")
|
||||
Open(path string) (fs.File, error)
|
||||
|
||||
// Example: writer, _ := medium.Create("logs/app.log")
|
||||
Create(path string) (goio.WriteCloser, error)
|
||||
|
||||
// Example: writer, _ := medium.Append("logs/app.log")
|
||||
Append(path string) (goio.WriteCloser, error)
|
||||
|
||||
// Example: reader, _ := medium.ReadStream("logs/app.log")
|
||||
|
|
|
|||
|
|
@ -238,6 +238,7 @@ func (medium *Medium) WriteMode(path, content string, mode fs.FileMode) error {
|
|||
return resultError("local.WriteMode", core.Concat("write failed: ", path), unrestrictedFileSystem.WriteMode(resolvedPath, content, mode))
|
||||
}
|
||||
|
||||
// Example: _ = medium.EnsureDir("config/app")
|
||||
func (medium *Medium) EnsureDir(path string) error {
|
||||
resolvedPath, err := medium.validatePath(path)
|
||||
if err != nil {
|
||||
|
|
@ -246,6 +247,7 @@ func (medium *Medium) EnsureDir(path string) error {
|
|||
return resultError("local.EnsureDir", core.Concat("ensure dir failed: ", path), unrestrictedFileSystem.EnsureDir(resolvedPath))
|
||||
}
|
||||
|
||||
// Example: isDirectory := medium.IsDir("config")
|
||||
func (medium *Medium) IsDir(path string) bool {
|
||||
if path == "" {
|
||||
return false
|
||||
|
|
@ -257,6 +259,7 @@ func (medium *Medium) IsDir(path string) bool {
|
|||
return unrestrictedFileSystem.IsDir(resolvedPath)
|
||||
}
|
||||
|
||||
// Example: isFile := medium.IsFile("config/app.yaml")
|
||||
func (medium *Medium) IsFile(path string) bool {
|
||||
if path == "" {
|
||||
return false
|
||||
|
|
@ -268,6 +271,7 @@ func (medium *Medium) IsFile(path string) bool {
|
|||
return unrestrictedFileSystem.IsFile(resolvedPath)
|
||||
}
|
||||
|
||||
// Example: exists := medium.Exists("config/app.yaml")
|
||||
func (medium *Medium) Exists(path string) bool {
|
||||
resolvedPath, err := medium.validatePath(path)
|
||||
if err != nil {
|
||||
|
|
@ -276,6 +280,7 @@ func (medium *Medium) Exists(path string) bool {
|
|||
return unrestrictedFileSystem.Exists(resolvedPath)
|
||||
}
|
||||
|
||||
// Example: entries, _ := medium.List("config")
|
||||
func (medium *Medium) List(path string) ([]fs.DirEntry, error) {
|
||||
resolvedPath, err := medium.validatePath(path)
|
||||
if err != nil {
|
||||
|
|
@ -284,6 +289,7 @@ func (medium *Medium) List(path string) ([]fs.DirEntry, error) {
|
|||
return resultDirEntries("local.List", core.Concat("list failed: ", path), unrestrictedFileSystem.List(resolvedPath))
|
||||
}
|
||||
|
||||
// Example: info, _ := medium.Stat("config/app.yaml")
|
||||
func (medium *Medium) Stat(path string) (fs.FileInfo, error) {
|
||||
resolvedPath, err := medium.validatePath(path)
|
||||
if err != nil {
|
||||
|
|
@ -292,6 +298,7 @@ func (medium *Medium) Stat(path string) (fs.FileInfo, error) {
|
|||
return resultFileInfo("local.Stat", core.Concat("stat failed: ", path), unrestrictedFileSystem.Stat(resolvedPath))
|
||||
}
|
||||
|
||||
// Example: file, _ := medium.Open("config/app.yaml")
|
||||
func (medium *Medium) Open(path string) (fs.File, error) {
|
||||
resolvedPath, err := medium.validatePath(path)
|
||||
if err != nil {
|
||||
|
|
@ -300,6 +307,7 @@ func (medium *Medium) Open(path string) (fs.File, error) {
|
|||
return resultFile("local.Open", core.Concat("open failed: ", path), unrestrictedFileSystem.Open(resolvedPath))
|
||||
}
|
||||
|
||||
// Example: writer, _ := medium.Create("logs/app.log")
|
||||
func (medium *Medium) Create(path string) (goio.WriteCloser, error) {
|
||||
resolvedPath, err := medium.validatePath(path)
|
||||
if err != nil {
|
||||
|
|
@ -308,6 +316,7 @@ func (medium *Medium) Create(path string) (goio.WriteCloser, error) {
|
|||
return resultWriteCloser("local.Create", core.Concat("create failed: ", path), unrestrictedFileSystem.Create(resolvedPath))
|
||||
}
|
||||
|
||||
// Example: writer, _ := medium.Append("logs/app.log")
|
||||
func (medium *Medium) Append(path string) (goio.WriteCloser, error) {
|
||||
resolvedPath, err := medium.validatePath(path)
|
||||
if err != nil {
|
||||
|
|
@ -326,6 +335,7 @@ func (medium *Medium) WriteStream(path string) (goio.WriteCloser, error) {
|
|||
return medium.Create(path)
|
||||
}
|
||||
|
||||
// Example: _ = medium.Delete("config/app.yaml")
|
||||
func (medium *Medium) Delete(path string) error {
|
||||
resolvedPath, err := medium.validatePath(path)
|
||||
if err != nil {
|
||||
|
|
@ -337,6 +347,7 @@ func (medium *Medium) Delete(path string) error {
|
|||
return resultError("local.Delete", core.Concat("delete failed: ", path), unrestrictedFileSystem.Delete(resolvedPath))
|
||||
}
|
||||
|
||||
// Example: _ = medium.DeleteAll("logs/archive")
|
||||
func (medium *Medium) DeleteAll(path string) error {
|
||||
resolvedPath, err := medium.validatePath(path)
|
||||
if err != nil {
|
||||
|
|
@ -348,6 +359,7 @@ func (medium *Medium) DeleteAll(path string) error {
|
|||
return resultError("local.DeleteAll", core.Concat("delete all failed: ", path), unrestrictedFileSystem.DeleteAll(resolvedPath))
|
||||
}
|
||||
|
||||
// Example: _ = medium.Rename("drafts/todo.txt", "archive/todo.txt")
|
||||
func (medium *Medium) Rename(oldPath, newPath string) error {
|
||||
oldResolvedPath, err := medium.validatePath(oldPath)
|
||||
if err != nil {
|
||||
|
|
|
|||
15
node/node.go
15
node/node.go
|
|
@ -232,6 +232,7 @@ func (node *Node) CopyTo(target coreio.Medium, sourcePath, destPath string) erro
|
|||
return nil
|
||||
}
|
||||
|
||||
// Example: file, _ := nodeTree.Open("config/app.yaml")
|
||||
func (node *Node) Open(name string) (fs.File, error) {
|
||||
name = core.TrimPrefix(name, "/")
|
||||
if dataFile, ok := node.files[name]; ok {
|
||||
|
|
@ -249,6 +250,7 @@ func (node *Node) Open(name string) (fs.File, error) {
|
|||
return nil, core.E("node.Open", core.Concat("path not found: ", name), fs.ErrNotExist)
|
||||
}
|
||||
|
||||
// Example: info, _ := nodeTree.Stat("config/app.yaml")
|
||||
func (node *Node) Stat(name string) (fs.FileInfo, error) {
|
||||
name = core.TrimPrefix(name, "/")
|
||||
if dataFile, ok := node.files[name]; ok {
|
||||
|
|
@ -266,6 +268,7 @@ func (node *Node) Stat(name string) (fs.FileInfo, error) {
|
|||
return nil, core.E("node.Stat", core.Concat("path not found: ", name), fs.ErrNotExist)
|
||||
}
|
||||
|
||||
// Example: entries, _ := nodeTree.ReadDir("config")
|
||||
func (node *Node) ReadDir(name string) ([]fs.DirEntry, error) {
|
||||
name = core.TrimPrefix(name, "/")
|
||||
if name == "." {
|
||||
|
|
@ -314,6 +317,7 @@ func (node *Node) ReadDir(name string) ([]fs.DirEntry, error) {
|
|||
return entries, nil
|
||||
}
|
||||
|
||||
// Example: content, _ := nodeTree.Read("config/app.yaml")
|
||||
func (node *Node) Read(filePath string) (string, error) {
|
||||
filePath = core.TrimPrefix(filePath, "/")
|
||||
file, ok := node.files[filePath]
|
||||
|
|
@ -323,11 +327,13 @@ func (node *Node) Read(filePath string) (string, error) {
|
|||
return string(file.content), nil
|
||||
}
|
||||
|
||||
// Example: _ = nodeTree.Write("config/app.yaml", "port: 8080")
|
||||
func (node *Node) Write(filePath, content string) error {
|
||||
node.AddData(filePath, []byte(content))
|
||||
return nil
|
||||
}
|
||||
|
||||
// Example: _ = nodeTree.WriteMode("keys/private.key", key, 0600)
|
||||
func (node *Node) WriteMode(filePath, content string, mode fs.FileMode) error {
|
||||
return node.Write(filePath, content)
|
||||
}
|
||||
|
|
@ -337,17 +343,20 @@ func (node *Node) EnsureDir(directoryPath string) error {
|
|||
return nil
|
||||
}
|
||||
|
||||
// Example: exists := nodeTree.Exists("config/app.yaml")
|
||||
func (node *Node) Exists(filePath string) bool {
|
||||
_, err := node.Stat(filePath)
|
||||
return err == nil
|
||||
}
|
||||
|
||||
// Example: isFile := nodeTree.IsFile("config/app.yaml")
|
||||
func (node *Node) IsFile(filePath string) bool {
|
||||
filePath = core.TrimPrefix(filePath, "/")
|
||||
_, ok := node.files[filePath]
|
||||
return ok
|
||||
}
|
||||
|
||||
// Example: isDirectory := nodeTree.IsDir("config")
|
||||
func (node *Node) IsDir(filePath string) bool {
|
||||
info, err := node.Stat(filePath)
|
||||
if err != nil {
|
||||
|
|
@ -356,6 +365,7 @@ func (node *Node) IsDir(filePath string) bool {
|
|||
return info.IsDir()
|
||||
}
|
||||
|
||||
// Example: _ = nodeTree.Delete("config/app.yaml")
|
||||
func (node *Node) Delete(filePath string) error {
|
||||
filePath = core.TrimPrefix(filePath, "/")
|
||||
if _, ok := node.files[filePath]; ok {
|
||||
|
|
@ -365,6 +375,7 @@ func (node *Node) Delete(filePath string) error {
|
|||
return core.E("node.Delete", core.Concat("path not found: ", filePath), fs.ErrNotExist)
|
||||
}
|
||||
|
||||
// Example: _ = nodeTree.DeleteAll("logs/archive")
|
||||
func (node *Node) DeleteAll(filePath string) error {
|
||||
filePath = core.TrimPrefix(filePath, "/")
|
||||
|
||||
|
|
@ -388,6 +399,7 @@ func (node *Node) DeleteAll(filePath string) error {
|
|||
return nil
|
||||
}
|
||||
|
||||
// Example: _ = nodeTree.Rename("drafts/todo.txt", "archive/todo.txt")
|
||||
func (node *Node) Rename(oldPath, newPath string) error {
|
||||
oldPath = core.TrimPrefix(oldPath, "/")
|
||||
newPath = core.TrimPrefix(newPath, "/")
|
||||
|
|
@ -403,6 +415,7 @@ func (node *Node) Rename(oldPath, newPath string) error {
|
|||
return nil
|
||||
}
|
||||
|
||||
// Example: entries, _ := nodeTree.List("config")
|
||||
func (node *Node) List(filePath string) ([]fs.DirEntry, error) {
|
||||
filePath = core.TrimPrefix(filePath, "/")
|
||||
if filePath == "" || filePath == "." {
|
||||
|
|
@ -411,11 +424,13 @@ func (node *Node) List(filePath string) ([]fs.DirEntry, error) {
|
|||
return node.ReadDir(filePath)
|
||||
}
|
||||
|
||||
// Example: writer, _ := nodeTree.Create("logs/app.log")
|
||||
func (node *Node) Create(filePath string) (goio.WriteCloser, error) {
|
||||
filePath = core.TrimPrefix(filePath, "/")
|
||||
return &nodeWriter{node: node, path: filePath}, nil
|
||||
}
|
||||
|
||||
// Example: writer, _ := nodeTree.Append("logs/app.log")
|
||||
func (node *Node) Append(filePath string) (goio.WriteCloser, error) {
|
||||
filePath = core.TrimPrefix(filePath, "/")
|
||||
var existing []byte
|
||||
|
|
|
|||
|
|
@ -15,16 +15,16 @@ import (
|
|||
)
|
||||
|
||||
func TestNode_New_Good(t *testing.T) {
|
||||
n := New()
|
||||
require.NotNil(t, n, "New() must not return nil")
|
||||
assert.NotNil(t, n.files, "New() must initialise the files map")
|
||||
nodeTree := New()
|
||||
require.NotNil(t, nodeTree, "New() must not return nil")
|
||||
assert.NotNil(t, nodeTree.files, "New() must initialise the files map")
|
||||
}
|
||||
|
||||
func TestNode_AddData_Good(t *testing.T) {
|
||||
n := New()
|
||||
n.AddData("foo.txt", []byte("foo"))
|
||||
nodeTree := New()
|
||||
nodeTree.AddData("foo.txt", []byte("foo"))
|
||||
|
||||
file, ok := n.files["foo.txt"]
|
||||
file, ok := nodeTree.files["foo.txt"]
|
||||
require.True(t, ok, "file foo.txt should be present")
|
||||
assert.Equal(t, []byte("foo"), file.content)
|
||||
|
||||
|
|
@ -34,38 +34,38 @@ func TestNode_AddData_Good(t *testing.T) {
|
|||
}
|
||||
|
||||
func TestNode_AddData_Bad(t *testing.T) {
|
||||
n := New()
|
||||
nodeTree := New()
|
||||
|
||||
n.AddData("", []byte("data"))
|
||||
assert.Empty(t, n.files, "empty name must not be stored")
|
||||
nodeTree.AddData("", []byte("data"))
|
||||
assert.Empty(t, nodeTree.files, "empty name must not be stored")
|
||||
|
||||
n.AddData("dir/", nil)
|
||||
assert.Empty(t, n.files, "directory entry must not be stored")
|
||||
nodeTree.AddData("dir/", nil)
|
||||
assert.Empty(t, nodeTree.files, "directory entry must not be stored")
|
||||
}
|
||||
|
||||
func TestNode_AddData_EdgeCases_Good(t *testing.T) {
|
||||
t.Run("Overwrite", func(t *testing.T) {
|
||||
n := New()
|
||||
n.AddData("foo.txt", []byte("foo"))
|
||||
n.AddData("foo.txt", []byte("bar"))
|
||||
nodeTree := New()
|
||||
nodeTree.AddData("foo.txt", []byte("foo"))
|
||||
nodeTree.AddData("foo.txt", []byte("bar"))
|
||||
|
||||
file := n.files["foo.txt"]
|
||||
file := nodeTree.files["foo.txt"]
|
||||
assert.Equal(t, []byte("bar"), file.content, "second AddData should overwrite")
|
||||
})
|
||||
|
||||
t.Run("LeadingSlash", func(t *testing.T) {
|
||||
n := New()
|
||||
n.AddData("/hello.txt", []byte("hi"))
|
||||
_, ok := n.files["hello.txt"]
|
||||
nodeTree := New()
|
||||
nodeTree.AddData("/hello.txt", []byte("hi"))
|
||||
_, ok := nodeTree.files["hello.txt"]
|
||||
assert.True(t, ok, "leading slash should be trimmed")
|
||||
})
|
||||
}
|
||||
|
||||
func TestNode_Open_Good(t *testing.T) {
|
||||
n := New()
|
||||
n.AddData("foo.txt", []byte("foo"))
|
||||
nodeTree := New()
|
||||
nodeTree.AddData("foo.txt", []byte("foo"))
|
||||
|
||||
file, err := n.Open("foo.txt")
|
||||
file, err := nodeTree.Open("foo.txt")
|
||||
require.NoError(t, err)
|
||||
defer file.Close()
|
||||
|
||||
|
|
@ -76,17 +76,17 @@ func TestNode_Open_Good(t *testing.T) {
|
|||
}
|
||||
|
||||
func TestNode_Open_Bad(t *testing.T) {
|
||||
n := New()
|
||||
_, err := n.Open("nonexistent.txt")
|
||||
nodeTree := New()
|
||||
_, err := nodeTree.Open("nonexistent.txt")
|
||||
require.Error(t, err)
|
||||
assert.ErrorIs(t, err, fs.ErrNotExist)
|
||||
}
|
||||
|
||||
func TestNode_Open_Directory_Good(t *testing.T) {
|
||||
n := New()
|
||||
n.AddData("bar/baz.txt", []byte("baz"))
|
||||
nodeTree := New()
|
||||
nodeTree.AddData("bar/baz.txt", []byte("baz"))
|
||||
|
||||
file, err := n.Open("bar")
|
||||
file, err := nodeTree.Open("bar")
|
||||
require.NoError(t, err)
|
||||
defer file.Close()
|
||||
|
||||
|
|
@ -99,88 +99,88 @@ func TestNode_Open_Directory_Good(t *testing.T) {
|
|||
}
|
||||
|
||||
func TestNode_Stat_Good(t *testing.T) {
|
||||
n := New()
|
||||
n.AddData("foo.txt", []byte("foo"))
|
||||
n.AddData("bar/baz.txt", []byte("baz"))
|
||||
nodeTree := New()
|
||||
nodeTree.AddData("foo.txt", []byte("foo"))
|
||||
nodeTree.AddData("bar/baz.txt", []byte("baz"))
|
||||
|
||||
info, err := n.Stat("bar/baz.txt")
|
||||
info, err := nodeTree.Stat("bar/baz.txt")
|
||||
require.NoError(t, err)
|
||||
assert.Equal(t, "baz.txt", info.Name())
|
||||
assert.Equal(t, int64(3), info.Size())
|
||||
assert.False(t, info.IsDir())
|
||||
|
||||
dirInfo, err := n.Stat("bar")
|
||||
dirInfo, err := nodeTree.Stat("bar")
|
||||
require.NoError(t, err)
|
||||
assert.True(t, dirInfo.IsDir())
|
||||
assert.Equal(t, "bar", dirInfo.Name())
|
||||
}
|
||||
|
||||
func TestNode_Stat_Bad(t *testing.T) {
|
||||
n := New()
|
||||
_, err := n.Stat("nonexistent")
|
||||
nodeTree := New()
|
||||
_, err := nodeTree.Stat("nonexistent")
|
||||
require.Error(t, err)
|
||||
assert.ErrorIs(t, err, fs.ErrNotExist)
|
||||
}
|
||||
|
||||
func TestNode_Stat_RootDirectory_Good(t *testing.T) {
|
||||
n := New()
|
||||
n.AddData("foo.txt", []byte("foo"))
|
||||
nodeTree := New()
|
||||
nodeTree.AddData("foo.txt", []byte("foo"))
|
||||
|
||||
info, err := n.Stat(".")
|
||||
info, err := nodeTree.Stat(".")
|
||||
require.NoError(t, err)
|
||||
assert.True(t, info.IsDir())
|
||||
assert.Equal(t, ".", info.Name())
|
||||
}
|
||||
|
||||
func TestNode_ReadFile_Good(t *testing.T) {
|
||||
n := New()
|
||||
n.AddData("hello.txt", []byte("hello world"))
|
||||
nodeTree := New()
|
||||
nodeTree.AddData("hello.txt", []byte("hello world"))
|
||||
|
||||
data, err := n.ReadFile("hello.txt")
|
||||
data, err := nodeTree.ReadFile("hello.txt")
|
||||
require.NoError(t, err)
|
||||
assert.Equal(t, []byte("hello world"), data)
|
||||
}
|
||||
|
||||
func TestNode_ReadFile_Bad(t *testing.T) {
|
||||
n := New()
|
||||
_, err := n.ReadFile("missing.txt")
|
||||
nodeTree := New()
|
||||
_, err := nodeTree.ReadFile("missing.txt")
|
||||
require.Error(t, err)
|
||||
assert.ErrorIs(t, err, fs.ErrNotExist)
|
||||
}
|
||||
|
||||
func TestNode_ReadFile_ReturnsCopy_Good(t *testing.T) {
|
||||
n := New()
|
||||
n.AddData("data.bin", []byte("original"))
|
||||
nodeTree := New()
|
||||
nodeTree.AddData("data.bin", []byte("original"))
|
||||
|
||||
data, err := n.ReadFile("data.bin")
|
||||
data, err := nodeTree.ReadFile("data.bin")
|
||||
require.NoError(t, err)
|
||||
data[0] = 'X'
|
||||
|
||||
data2, err := n.ReadFile("data.bin")
|
||||
data2, err := nodeTree.ReadFile("data.bin")
|
||||
require.NoError(t, err)
|
||||
assert.Equal(t, []byte("original"), data2, "ReadFile must return an independent copy")
|
||||
}
|
||||
|
||||
func TestNode_ReadDir_Good(t *testing.T) {
|
||||
n := New()
|
||||
n.AddData("foo.txt", []byte("foo"))
|
||||
n.AddData("bar/baz.txt", []byte("baz"))
|
||||
n.AddData("bar/qux.txt", []byte("qux"))
|
||||
nodeTree := New()
|
||||
nodeTree.AddData("foo.txt", []byte("foo"))
|
||||
nodeTree.AddData("bar/baz.txt", []byte("baz"))
|
||||
nodeTree.AddData("bar/qux.txt", []byte("qux"))
|
||||
|
||||
entries, err := n.ReadDir(".")
|
||||
entries, err := nodeTree.ReadDir(".")
|
||||
require.NoError(t, err)
|
||||
assert.Equal(t, []string{"bar", "foo.txt"}, sortedNames(entries))
|
||||
|
||||
barEntries, err := n.ReadDir("bar")
|
||||
barEntries, err := nodeTree.ReadDir("bar")
|
||||
require.NoError(t, err)
|
||||
assert.Equal(t, []string{"baz.txt", "qux.txt"}, sortedNames(barEntries))
|
||||
}
|
||||
|
||||
func TestNode_ReadDir_Bad(t *testing.T) {
|
||||
n := New()
|
||||
n.AddData("foo.txt", []byte("foo"))
|
||||
nodeTree := New()
|
||||
nodeTree.AddData("foo.txt", []byte("foo"))
|
||||
|
||||
_, err := n.ReadDir("foo.txt")
|
||||
_, err := nodeTree.ReadDir("foo.txt")
|
||||
require.Error(t, err)
|
||||
var pathErr *fs.PathError
|
||||
require.True(t, core.As(err, &pathErr))
|
||||
|
|
@ -188,45 +188,45 @@ func TestNode_ReadDir_Bad(t *testing.T) {
|
|||
}
|
||||
|
||||
func TestNode_ReadDir_IgnoresEmptyEntry_Good(t *testing.T) {
|
||||
n := New()
|
||||
n.AddData("bar/baz.txt", []byte("baz"))
|
||||
n.AddData("empty_dir/", nil)
|
||||
nodeTree := New()
|
||||
nodeTree.AddData("bar/baz.txt", []byte("baz"))
|
||||
nodeTree.AddData("empty_dir/", nil)
|
||||
|
||||
entries, err := n.ReadDir(".")
|
||||
entries, err := nodeTree.ReadDir(".")
|
||||
require.NoError(t, err)
|
||||
assert.Equal(t, []string{"bar"}, sortedNames(entries))
|
||||
}
|
||||
|
||||
func TestNode_Exists_Good(t *testing.T) {
|
||||
n := New()
|
||||
n.AddData("foo.txt", []byte("foo"))
|
||||
n.AddData("bar/baz.txt", []byte("baz"))
|
||||
nodeTree := New()
|
||||
nodeTree.AddData("foo.txt", []byte("foo"))
|
||||
nodeTree.AddData("bar/baz.txt", []byte("baz"))
|
||||
|
||||
assert.True(t, n.Exists("foo.txt"))
|
||||
assert.True(t, n.Exists("bar"))
|
||||
assert.True(t, nodeTree.Exists("foo.txt"))
|
||||
assert.True(t, nodeTree.Exists("bar"))
|
||||
}
|
||||
|
||||
func TestNode_Exists_Bad(t *testing.T) {
|
||||
n := New()
|
||||
assert.False(t, n.Exists("nonexistent"))
|
||||
nodeTree := New()
|
||||
assert.False(t, nodeTree.Exists("nonexistent"))
|
||||
}
|
||||
|
||||
func TestNode_Exists_RootAndEmptyPath_Good(t *testing.T) {
|
||||
n := New()
|
||||
n.AddData("dummy.txt", []byte("dummy"))
|
||||
nodeTree := New()
|
||||
nodeTree.AddData("dummy.txt", []byte("dummy"))
|
||||
|
||||
assert.True(t, n.Exists("."), "root '.' must exist")
|
||||
assert.True(t, n.Exists(""), "empty path (root) must exist")
|
||||
assert.True(t, nodeTree.Exists("."), "root '.' must exist")
|
||||
assert.True(t, nodeTree.Exists(""), "empty path (root) must exist")
|
||||
}
|
||||
|
||||
func TestNode_Walk_Default_Good(t *testing.T) {
|
||||
n := New()
|
||||
n.AddData("foo.txt", []byte("foo"))
|
||||
n.AddData("bar/baz.txt", []byte("baz"))
|
||||
n.AddData("bar/qux.txt", []byte("qux"))
|
||||
nodeTree := New()
|
||||
nodeTree.AddData("foo.txt", []byte("foo"))
|
||||
nodeTree.AddData("bar/baz.txt", []byte("baz"))
|
||||
nodeTree.AddData("bar/qux.txt", []byte("qux"))
|
||||
|
||||
var paths []string
|
||||
err := n.Walk(".", func(p string, d fs.DirEntry, err error) error {
|
||||
err := nodeTree.Walk(".", func(p string, d fs.DirEntry, err error) error {
|
||||
paths = append(paths, p)
|
||||
return nil
|
||||
}, WalkOptions{})
|
||||
|
|
@ -237,10 +237,10 @@ func TestNode_Walk_Default_Good(t *testing.T) {
|
|||
}
|
||||
|
||||
func TestNode_Walk_Default_Bad(t *testing.T) {
|
||||
n := New()
|
||||
nodeTree := New()
|
||||
|
||||
var called bool
|
||||
err := n.Walk("nonexistent", func(p string, d fs.DirEntry, err error) error {
|
||||
err := nodeTree.Walk("nonexistent", func(p string, d fs.DirEntry, err error) error {
|
||||
called = true
|
||||
assert.Error(t, err)
|
||||
assert.ErrorIs(t, err, fs.ErrNotExist)
|
||||
|
|
@ -251,13 +251,13 @@ func TestNode_Walk_Default_Bad(t *testing.T) {
|
|||
}
|
||||
|
||||
func TestNode_Walk_CallbackError_Good(t *testing.T) {
|
||||
n := New()
|
||||
n.AddData("a/b.txt", []byte("b"))
|
||||
n.AddData("a/c.txt", []byte("c"))
|
||||
nodeTree := New()
|
||||
nodeTree.AddData("a/b.txt", []byte("b"))
|
||||
nodeTree.AddData("a/c.txt", []byte("c"))
|
||||
|
||||
walkErr := core.NewError("stop walking")
|
||||
var paths []string
|
||||
err := n.Walk(".", func(p string, d fs.DirEntry, err error) error {
|
||||
err := nodeTree.Walk(".", func(p string, d fs.DirEntry, err error) error {
|
||||
if p == "a/b.txt" {
|
||||
return walkErr
|
||||
}
|
||||
|
|
@ -269,15 +269,15 @@ func TestNode_Walk_CallbackError_Good(t *testing.T) {
|
|||
}
|
||||
|
||||
func TestNode_Walk_Good(t *testing.T) {
|
||||
n := New()
|
||||
n.AddData("root.txt", []byte("root"))
|
||||
n.AddData("a/a1.txt", []byte("a1"))
|
||||
n.AddData("a/b/b1.txt", []byte("b1"))
|
||||
n.AddData("c/c1.txt", []byte("c1"))
|
||||
nodeTree := New()
|
||||
nodeTree.AddData("root.txt", []byte("root"))
|
||||
nodeTree.AddData("a/a1.txt", []byte("a1"))
|
||||
nodeTree.AddData("a/b/b1.txt", []byte("b1"))
|
||||
nodeTree.AddData("c/c1.txt", []byte("c1"))
|
||||
|
||||
t.Run("MaxDepth", func(t *testing.T) {
|
||||
var paths []string
|
||||
err := n.Walk(".", func(p string, d fs.DirEntry, err error) error {
|
||||
err := nodeTree.Walk(".", func(p string, d fs.DirEntry, err error) error {
|
||||
paths = append(paths, p)
|
||||
return nil
|
||||
}, WalkOptions{MaxDepth: 1})
|
||||
|
|
@ -289,7 +289,7 @@ func TestNode_Walk_Good(t *testing.T) {
|
|||
|
||||
t.Run("Filter", func(t *testing.T) {
|
||||
var paths []string
|
||||
err := n.Walk(".", func(p string, d fs.DirEntry, err error) error {
|
||||
err := nodeTree.Walk(".", func(p string, d fs.DirEntry, err error) error {
|
||||
paths = append(paths, p)
|
||||
return nil
|
||||
}, WalkOptions{Filter: func(p string, d fs.DirEntry) bool {
|
||||
|
|
@ -303,7 +303,7 @@ func TestNode_Walk_Good(t *testing.T) {
|
|||
|
||||
t.Run("SkipErrors", func(t *testing.T) {
|
||||
var called bool
|
||||
err := n.Walk("nonexistent", func(p string, d fs.DirEntry, err error) error {
|
||||
err := nodeTree.Walk("nonexistent", func(p string, d fs.DirEntry, err error) error {
|
||||
called = true
|
||||
return err
|
||||
}, WalkOptions{SkipErrors: true})
|
||||
|
|
@ -314,11 +314,11 @@ func TestNode_Walk_Good(t *testing.T) {
|
|||
}
|
||||
|
||||
func TestNode_CopyFile_Good(t *testing.T) {
|
||||
n := New()
|
||||
n.AddData("foo.txt", []byte("foo"))
|
||||
nodeTree := New()
|
||||
nodeTree.AddData("foo.txt", []byte("foo"))
|
||||
|
||||
tmpfile := core.Path(t.TempDir(), "test.txt")
|
||||
err := n.CopyFile("foo.txt", tmpfile, 0644)
|
||||
err := nodeTree.CopyFile("foo.txt", tmpfile, 0644)
|
||||
require.NoError(t, err)
|
||||
|
||||
content, err := coreio.Local.Read(tmpfile)
|
||||
|
|
@ -327,40 +327,40 @@ func TestNode_CopyFile_Good(t *testing.T) {
|
|||
}
|
||||
|
||||
func TestNode_CopyFile_Bad(t *testing.T) {
|
||||
n := New()
|
||||
nodeTree := New()
|
||||
tmpfile := core.Path(t.TempDir(), "test.txt")
|
||||
|
||||
err := n.CopyFile("nonexistent.txt", tmpfile, 0644)
|
||||
err := nodeTree.CopyFile("nonexistent.txt", tmpfile, 0644)
|
||||
assert.Error(t, err)
|
||||
|
||||
n.AddData("foo.txt", []byte("foo"))
|
||||
err = n.CopyFile("foo.txt", "/nonexistent_dir/test.txt", 0644)
|
||||
nodeTree.AddData("foo.txt", []byte("foo"))
|
||||
err = nodeTree.CopyFile("foo.txt", "/nonexistent_dir/test.txt", 0644)
|
||||
assert.Error(t, err)
|
||||
}
|
||||
|
||||
func TestNode_CopyFile_DirectorySource_Bad(t *testing.T) {
|
||||
n := New()
|
||||
n.AddData("bar/baz.txt", []byte("baz"))
|
||||
nodeTree := New()
|
||||
nodeTree.AddData("bar/baz.txt", []byte("baz"))
|
||||
tmpfile := core.Path(t.TempDir(), "test.txt")
|
||||
|
||||
err := n.CopyFile("bar", tmpfile, 0644)
|
||||
err := nodeTree.CopyFile("bar", tmpfile, 0644)
|
||||
assert.Error(t, err)
|
||||
}
|
||||
|
||||
func TestNode_CopyTo_Good(t *testing.T) {
|
||||
n := New()
|
||||
n.AddData("config/app.yaml", []byte("port: 8080"))
|
||||
n.AddData("config/env/app.env", []byte("MODE=test"))
|
||||
nodeTree := New()
|
||||
nodeTree.AddData("config/app.yaml", []byte("port: 8080"))
|
||||
nodeTree.AddData("config/env/app.env", []byte("MODE=test"))
|
||||
|
||||
fileTarget := coreio.NewMemoryMedium()
|
||||
err := n.CopyTo(fileTarget, "config/app.yaml", "backup/app.yaml")
|
||||
err := nodeTree.CopyTo(fileTarget, "config/app.yaml", "backup/app.yaml")
|
||||
require.NoError(t, err)
|
||||
content, err := fileTarget.Read("backup/app.yaml")
|
||||
require.NoError(t, err)
|
||||
assert.Equal(t, "port: 8080", content)
|
||||
|
||||
dirTarget := coreio.NewMemoryMedium()
|
||||
err = n.CopyTo(dirTarget, "config", "backup/config")
|
||||
err = nodeTree.CopyTo(dirTarget, "config", "backup/config")
|
||||
require.NoError(t, err)
|
||||
content, err = dirTarget.Read("backup/config/app.yaml")
|
||||
require.NoError(t, err)
|
||||
|
|
@ -371,35 +371,35 @@ func TestNode_CopyTo_Good(t *testing.T) {
|
|||
}
|
||||
|
||||
func TestNode_CopyTo_Bad(t *testing.T) {
|
||||
n := New()
|
||||
err := n.CopyTo(coreio.NewMemoryMedium(), "missing", "backup/missing")
|
||||
nodeTree := New()
|
||||
err := nodeTree.CopyTo(coreio.NewMemoryMedium(), "missing", "backup/missing")
|
||||
assert.Error(t, err)
|
||||
}
|
||||
|
||||
func TestNode_MediumFacade_Good(t *testing.T) {
|
||||
n := New()
|
||||
nodeTree := New()
|
||||
|
||||
require.NoError(t, n.Write("docs/readme.txt", "hello"))
|
||||
require.NoError(t, n.WriteMode("docs/mode.txt", "mode", 0600))
|
||||
require.NoError(t, n.Write("docs/guide.txt", "guide"))
|
||||
require.NoError(t, n.EnsureDir("ignored"))
|
||||
require.NoError(t, nodeTree.Write("docs/readme.txt", "hello"))
|
||||
require.NoError(t, nodeTree.WriteMode("docs/mode.txt", "mode", 0600))
|
||||
require.NoError(t, nodeTree.Write("docs/guide.txt", "guide"))
|
||||
require.NoError(t, nodeTree.EnsureDir("ignored"))
|
||||
|
||||
value, err := n.Read("docs/readme.txt")
|
||||
value, err := nodeTree.Read("docs/readme.txt")
|
||||
require.NoError(t, err)
|
||||
assert.Equal(t, "hello", value)
|
||||
|
||||
value, err = n.Read("docs/guide.txt")
|
||||
value, err = nodeTree.Read("docs/guide.txt")
|
||||
require.NoError(t, err)
|
||||
assert.Equal(t, "guide", value)
|
||||
|
||||
assert.True(t, n.IsFile("docs/readme.txt"))
|
||||
assert.True(t, n.IsDir("docs"))
|
||||
assert.True(t, nodeTree.IsFile("docs/readme.txt"))
|
||||
assert.True(t, nodeTree.IsDir("docs"))
|
||||
|
||||
entries, err := n.List("docs")
|
||||
entries, err := nodeTree.List("docs")
|
||||
require.NoError(t, err)
|
||||
assert.Equal(t, []string{"guide.txt", "mode.txt", "readme.txt"}, sortedNames(entries))
|
||||
|
||||
file, err := n.Open("docs/readme.txt")
|
||||
file, err := nodeTree.Open("docs/readme.txt")
|
||||
require.NoError(t, err)
|
||||
info, err := file.Stat()
|
||||
require.NoError(t, err)
|
||||
|
|
@ -409,7 +409,7 @@ func TestNode_MediumFacade_Good(t *testing.T) {
|
|||
assert.Nil(t, info.Sys())
|
||||
require.NoError(t, file.Close())
|
||||
|
||||
dir, err := n.Open("docs")
|
||||
dir, err := nodeTree.Open("docs")
|
||||
require.NoError(t, err)
|
||||
dirInfo, err := dir.Stat()
|
||||
require.NoError(t, err)
|
||||
|
|
@ -419,47 +419,47 @@ func TestNode_MediumFacade_Good(t *testing.T) {
|
|||
assert.Nil(t, dirInfo.Sys())
|
||||
require.NoError(t, dir.Close())
|
||||
|
||||
createWriter, err := n.Create("docs/generated.txt")
|
||||
createWriter, err := nodeTree.Create("docs/generated.txt")
|
||||
require.NoError(t, err)
|
||||
_, err = createWriter.Write([]byte("generated"))
|
||||
require.NoError(t, err)
|
||||
require.NoError(t, createWriter.Close())
|
||||
|
||||
appendWriter, err := n.Append("docs/generated.txt")
|
||||
appendWriter, err := nodeTree.Append("docs/generated.txt")
|
||||
require.NoError(t, err)
|
||||
_, err = appendWriter.Write([]byte(" content"))
|
||||
require.NoError(t, err)
|
||||
require.NoError(t, appendWriter.Close())
|
||||
|
||||
streamReader, err := n.ReadStream("docs/generated.txt")
|
||||
streamReader, err := nodeTree.ReadStream("docs/generated.txt")
|
||||
require.NoError(t, err)
|
||||
streamData, err := io.ReadAll(streamReader)
|
||||
require.NoError(t, err)
|
||||
assert.Equal(t, "generated content", string(streamData))
|
||||
require.NoError(t, streamReader.Close())
|
||||
|
||||
writeStream, err := n.WriteStream("docs/stream.txt")
|
||||
writeStream, err := nodeTree.WriteStream("docs/stream.txt")
|
||||
require.NoError(t, err)
|
||||
_, err = writeStream.Write([]byte("stream"))
|
||||
require.NoError(t, err)
|
||||
require.NoError(t, writeStream.Close())
|
||||
|
||||
require.NoError(t, n.Rename("docs/stream.txt", "docs/stream-renamed.txt"))
|
||||
assert.True(t, n.Exists("docs/stream-renamed.txt"))
|
||||
require.NoError(t, nodeTree.Rename("docs/stream.txt", "docs/stream-renamed.txt"))
|
||||
assert.True(t, nodeTree.Exists("docs/stream-renamed.txt"))
|
||||
|
||||
require.NoError(t, n.Delete("docs/stream-renamed.txt"))
|
||||
assert.False(t, n.Exists("docs/stream-renamed.txt"))
|
||||
require.NoError(t, nodeTree.Delete("docs/stream-renamed.txt"))
|
||||
assert.False(t, nodeTree.Exists("docs/stream-renamed.txt"))
|
||||
|
||||
require.NoError(t, n.DeleteAll("docs"))
|
||||
assert.False(t, n.Exists("docs"))
|
||||
require.NoError(t, nodeTree.DeleteAll("docs"))
|
||||
assert.False(t, nodeTree.Exists("docs"))
|
||||
}
|
||||
|
||||
func TestNode_ToTar_Good(t *testing.T) {
|
||||
n := New()
|
||||
n.AddData("foo.txt", []byte("foo"))
|
||||
n.AddData("bar/baz.txt", []byte("baz"))
|
||||
nodeTree := New()
|
||||
nodeTree.AddData("foo.txt", []byte("foo"))
|
||||
nodeTree.AddData("bar/baz.txt", []byte("baz"))
|
||||
|
||||
tarball, err := n.ToTar()
|
||||
tarball, err := nodeTree.ToTar()
|
||||
require.NoError(t, err)
|
||||
require.NotEmpty(t, tarball)
|
||||
|
||||
|
|
@ -500,11 +500,11 @@ func TestNode_FromTar_Good(t *testing.T) {
|
|||
}
|
||||
require.NoError(t, tw.Close())
|
||||
|
||||
n, err := FromTar(buf.Bytes())
|
||||
nodeTree, err := FromTar(buf.Bytes())
|
||||
require.NoError(t, err)
|
||||
|
||||
assert.True(t, n.Exists("foo.txt"), "foo.txt should exist")
|
||||
assert.True(t, n.Exists("bar/baz.txt"), "bar/baz.txt should exist")
|
||||
assert.True(t, nodeTree.Exists("foo.txt"), "foo.txt should exist")
|
||||
assert.True(t, nodeTree.Exists("bar/baz.txt"), "bar/baz.txt should exist")
|
||||
}
|
||||
|
||||
func TestNode_FromTar_Bad(t *testing.T) {
|
||||
|
|
@ -514,41 +514,41 @@ func TestNode_FromTar_Bad(t *testing.T) {
|
|||
}
|
||||
|
||||
func TestNode_TarRoundTrip_Good(t *testing.T) {
|
||||
n1 := New()
|
||||
n1.AddData("a.txt", []byte("alpha"))
|
||||
n1.AddData("b/c.txt", []byte("charlie"))
|
||||
nodeTree1 := New()
|
||||
nodeTree1.AddData("a.txt", []byte("alpha"))
|
||||
nodeTree1.AddData("b/c.txt", []byte("charlie"))
|
||||
|
||||
tarball, err := n1.ToTar()
|
||||
tarball, err := nodeTree1.ToTar()
|
||||
require.NoError(t, err)
|
||||
|
||||
n2, err := FromTar(tarball)
|
||||
nodeTree2, err := FromTar(tarball)
|
||||
require.NoError(t, err)
|
||||
|
||||
data, err := n2.ReadFile("a.txt")
|
||||
data, err := nodeTree2.ReadFile("a.txt")
|
||||
require.NoError(t, err)
|
||||
assert.Equal(t, []byte("alpha"), data)
|
||||
|
||||
data, err = n2.ReadFile("b/c.txt")
|
||||
data, err = nodeTree2.ReadFile("b/c.txt")
|
||||
require.NoError(t, err)
|
||||
assert.Equal(t, []byte("charlie"), data)
|
||||
}
|
||||
|
||||
func TestNode_FSInterface_Good(t *testing.T) {
|
||||
n := New()
|
||||
n.AddData("hello.txt", []byte("world"))
|
||||
nodeTree := New()
|
||||
nodeTree.AddData("hello.txt", []byte("world"))
|
||||
|
||||
var fsys fs.FS = n
|
||||
var fsys fs.FS = nodeTree
|
||||
file, err := fsys.Open("hello.txt")
|
||||
require.NoError(t, err)
|
||||
defer file.Close()
|
||||
|
||||
var statFS fs.StatFS = n
|
||||
var statFS fs.StatFS = nodeTree
|
||||
info, err := statFS.Stat("hello.txt")
|
||||
require.NoError(t, err)
|
||||
assert.Equal(t, "hello.txt", info.Name())
|
||||
assert.Equal(t, int64(5), info.Size())
|
||||
|
||||
var readFS fs.ReadFileFS = n
|
||||
var readFS fs.ReadFileFS = nodeTree
|
||||
data, err := readFS.ReadFile("hello.txt")
|
||||
require.NoError(t, err)
|
||||
assert.Equal(t, []byte("world"), data)
|
||||
|
|
|
|||
5
s3/s3.go
5
s3/s3.go
|
|
@ -119,6 +119,7 @@ func (medium *Medium) objectKey(filePath string) string {
|
|||
return medium.prefix + clean
|
||||
}
|
||||
|
||||
// Example: content, _ := medium.Read("reports/daily.txt")
|
||||
func (medium *Medium) Read(filePath string) (string, error) {
|
||||
key := medium.objectKey(filePath)
|
||||
if key == "" {
|
||||
|
|
@ -141,6 +142,7 @@ func (medium *Medium) Read(filePath string) (string, error) {
|
|||
return string(data), nil
|
||||
}
|
||||
|
||||
// Example: _ = medium.Write("reports/daily.txt", "done")
|
||||
func (medium *Medium) Write(filePath, content string) error {
|
||||
key := medium.objectKey(filePath)
|
||||
if key == "" {
|
||||
|
|
@ -184,6 +186,7 @@ func (medium *Medium) IsFile(filePath string) bool {
|
|||
return err == nil
|
||||
}
|
||||
|
||||
// Example: _ = medium.Delete("reports/daily.txt")
|
||||
func (medium *Medium) Delete(filePath string) error {
|
||||
key := medium.objectKey(filePath)
|
||||
if key == "" {
|
||||
|
|
@ -470,6 +473,7 @@ func (medium *Medium) Append(filePath string) (goio.WriteCloser, error) {
|
|||
}, nil
|
||||
}
|
||||
|
||||
// Example: reader, _ := medium.ReadStream("reports/daily.txt")
|
||||
func (medium *Medium) ReadStream(filePath string) (goio.ReadCloser, error) {
|
||||
key := medium.objectKey(filePath)
|
||||
if key == "" {
|
||||
|
|
@ -486,6 +490,7 @@ func (medium *Medium) ReadStream(filePath string) (goio.ReadCloser, error) {
|
|||
return out.Body, nil
|
||||
}
|
||||
|
||||
// Example: writer, _ := medium.WriteStream("reports/daily.txt")
|
||||
func (medium *Medium) WriteStream(filePath string) (goio.WriteCloser, error) {
|
||||
return medium.Create(filePath)
|
||||
}
|
||||
|
|
|
|||
|
|
@ -88,6 +88,7 @@ func normaliseEntryPath(filePath string) string {
|
|||
return core.TrimPrefix(clean, "/")
|
||||
}
|
||||
|
||||
// Example: content, _ := medium.Read("config/app.yaml")
|
||||
func (medium *Medium) Read(filePath string) (string, error) {
|
||||
key := normaliseEntryPath(filePath)
|
||||
if key == "" {
|
||||
|
|
@ -111,6 +112,7 @@ func (medium *Medium) Read(filePath string) (string, error) {
|
|||
return string(content), nil
|
||||
}
|
||||
|
||||
// Example: _ = medium.Write("config/app.yaml", "port: 8080")
|
||||
func (medium *Medium) Write(filePath, content string) error {
|
||||
return medium.WriteMode(filePath, content, 0644)
|
||||
}
|
||||
|
|
@ -151,6 +153,7 @@ func (medium *Medium) EnsureDir(filePath string) error {
|
|||
return nil
|
||||
}
|
||||
|
||||
// Example: isFile := medium.IsFile("config/app.yaml")
|
||||
func (medium *Medium) IsFile(filePath string) bool {
|
||||
key := normaliseEntryPath(filePath)
|
||||
if key == "" {
|
||||
|
|
@ -401,6 +404,7 @@ func (medium *Medium) List(filePath string) ([]fs.DirEntry, error) {
|
|||
return entries, nil
|
||||
}
|
||||
|
||||
// Example: info, _ := medium.Stat("config/app.yaml")
|
||||
func (medium *Medium) Stat(filePath string) (fs.FileInfo, error) {
|
||||
key := normaliseEntryPath(filePath)
|
||||
if key == "" {
|
||||
|
|
@ -431,6 +435,7 @@ func (medium *Medium) Stat(filePath string) (fs.FileInfo, error) {
|
|||
}, nil
|
||||
}
|
||||
|
||||
// Example: file, _ := medium.Open("config/app.yaml")
|
||||
func (medium *Medium) Open(filePath string) (fs.File, error) {
|
||||
key := normaliseEntryPath(filePath)
|
||||
if key == "" {
|
||||
|
|
@ -462,6 +467,7 @@ func (medium *Medium) Open(filePath string) (fs.File, error) {
|
|||
}, nil
|
||||
}
|
||||
|
||||
// Example: writer, _ := medium.Create("logs/app.log")
|
||||
func (medium *Medium) Create(filePath string) (goio.WriteCloser, error) {
|
||||
key := normaliseEntryPath(filePath)
|
||||
if key == "" {
|
||||
|
|
@ -473,6 +479,7 @@ func (medium *Medium) Create(filePath string) (goio.WriteCloser, error) {
|
|||
}, nil
|
||||
}
|
||||
|
||||
// Example: writer, _ := medium.Append("logs/app.log")
|
||||
func (medium *Medium) Append(filePath string) (goio.WriteCloser, error) {
|
||||
key := normaliseEntryPath(filePath)
|
||||
if key == "" {
|
||||
|
|
@ -494,6 +501,7 @@ func (medium *Medium) Append(filePath string) (goio.WriteCloser, error) {
|
|||
}, nil
|
||||
}
|
||||
|
||||
// Example: reader, _ := medium.ReadStream("logs/app.log")
|
||||
func (medium *Medium) ReadStream(filePath string) (goio.ReadCloser, error) {
|
||||
key := normaliseEntryPath(filePath)
|
||||
if key == "" {
|
||||
|
|
@ -518,10 +526,12 @@ func (medium *Medium) ReadStream(filePath string) (goio.ReadCloser, error) {
|
|||
return goio.NopCloser(bytes.NewReader(content)), nil
|
||||
}
|
||||
|
||||
// Example: writer, _ := medium.WriteStream("logs/app.log")
|
||||
func (medium *Medium) WriteStream(filePath string) (goio.WriteCloser, error) {
|
||||
return medium.Create(filePath)
|
||||
}
|
||||
|
||||
// Example: exists := medium.Exists("config/app.yaml")
|
||||
func (medium *Medium) Exists(filePath string) bool {
|
||||
key := normaliseEntryPath(filePath)
|
||||
if key == "" {
|
||||
|
|
@ -538,6 +548,7 @@ func (medium *Medium) Exists(filePath string) bool {
|
|||
return count > 0
|
||||
}
|
||||
|
||||
// Example: isDirectory := medium.IsDir("config")
|
||||
func (medium *Medium) IsDir(filePath string) bool {
|
||||
key := normaliseEntryPath(filePath)
|
||||
if key == "" {
|
||||
|
|
|
|||
|
|
@ -11,10 +11,10 @@ import (
|
|||
|
||||
func newTestKeyValueMedium(t *testing.T) *Medium {
|
||||
t.Helper()
|
||||
m, err := NewMedium(Options{Path: ":memory:"})
|
||||
medium, err := NewMedium(Options{Path: ":memory:"})
|
||||
require.NoError(t, err)
|
||||
t.Cleanup(func() { m.Close() })
|
||||
return m
|
||||
t.Cleanup(func() { medium.Close() })
|
||||
return medium
|
||||
}
|
||||
|
||||
func TestKeyValueMedium_ReadWrite_Good(t *testing.T) {
|
||||
|
|
|
|||
|
|
@ -18,6 +18,7 @@ type Store struct {
|
|||
database *sql.DB
|
||||
}
|
||||
|
||||
// Example: keyValueStore, _ := store.New(store.Options{Path: ":memory:"})
|
||||
type Options struct {
|
||||
Path string
|
||||
}
|
||||
|
|
|
|||
|
|
@ -10,17 +10,17 @@ import (
|
|||
func newTestStore(t *testing.T) *Store {
|
||||
t.Helper()
|
||||
|
||||
s, err := New(Options{Path: ":memory:"})
|
||||
keyValueStore, err := New(Options{Path: ":memory:"})
|
||||
require.NoError(t, err)
|
||||
t.Cleanup(func() {
|
||||
require.NoError(t, s.Close())
|
||||
require.NoError(t, keyValueStore.Close())
|
||||
})
|
||||
return s
|
||||
return keyValueStore
|
||||
}
|
||||
|
||||
func TestStore_New_Options_Good(t *testing.T) {
|
||||
s := newTestStore(t)
|
||||
assert.NotNil(t, s)
|
||||
keyValueStore := newTestStore(t)
|
||||
assert.NotNil(t, keyValueStore)
|
||||
}
|
||||
|
||||
func TestStore_New_Options_Bad(t *testing.T) {
|
||||
|
|
@ -29,86 +29,86 @@ func TestStore_New_Options_Bad(t *testing.T) {
|
|||
}
|
||||
|
||||
func TestStore_SetGet_Good(t *testing.T) {
|
||||
s := newTestStore(t)
|
||||
keyValueStore := newTestStore(t)
|
||||
|
||||
err := s.Set("config", "theme", "dark")
|
||||
err := keyValueStore.Set("config", "theme", "dark")
|
||||
require.NoError(t, err)
|
||||
|
||||
val, err := s.Get("config", "theme")
|
||||
val, err := keyValueStore.Get("config", "theme")
|
||||
require.NoError(t, err)
|
||||
assert.Equal(t, "dark", val)
|
||||
}
|
||||
|
||||
func TestStore_Get_NotFound_Bad(t *testing.T) {
|
||||
s := newTestStore(t)
|
||||
keyValueStore := newTestStore(t)
|
||||
|
||||
_, err := s.Get("config", "missing")
|
||||
_, err := keyValueStore.Get("config", "missing")
|
||||
assert.ErrorIs(t, err, NotFoundError)
|
||||
}
|
||||
|
||||
func TestStore_Delete_Good(t *testing.T) {
|
||||
s := newTestStore(t)
|
||||
keyValueStore := newTestStore(t)
|
||||
|
||||
_ = s.Set("config", "key", "val")
|
||||
err := s.Delete("config", "key")
|
||||
_ = keyValueStore.Set("config", "key", "val")
|
||||
err := keyValueStore.Delete("config", "key")
|
||||
require.NoError(t, err)
|
||||
|
||||
_, err = s.Get("config", "key")
|
||||
_, err = keyValueStore.Get("config", "key")
|
||||
assert.ErrorIs(t, err, NotFoundError)
|
||||
}
|
||||
|
||||
func TestStore_Count_Good(t *testing.T) {
|
||||
s := newTestStore(t)
|
||||
keyValueStore := newTestStore(t)
|
||||
|
||||
_ = s.Set("group", "a", "1")
|
||||
_ = s.Set("group", "b", "2")
|
||||
_ = s.Set("other", "c", "3")
|
||||
_ = keyValueStore.Set("group", "a", "1")
|
||||
_ = keyValueStore.Set("group", "b", "2")
|
||||
_ = keyValueStore.Set("other", "c", "3")
|
||||
|
||||
n, err := s.Count("group")
|
||||
count, err := keyValueStore.Count("group")
|
||||
require.NoError(t, err)
|
||||
assert.Equal(t, 2, n)
|
||||
assert.Equal(t, 2, count)
|
||||
}
|
||||
|
||||
func TestStore_DeleteGroup_Good(t *testing.T) {
|
||||
s := newTestStore(t)
|
||||
keyValueStore := newTestStore(t)
|
||||
|
||||
_ = s.Set("group", "a", "1")
|
||||
_ = s.Set("group", "b", "2")
|
||||
err := s.DeleteGroup("group")
|
||||
_ = keyValueStore.Set("group", "a", "1")
|
||||
_ = keyValueStore.Set("group", "b", "2")
|
||||
err := keyValueStore.DeleteGroup("group")
|
||||
require.NoError(t, err)
|
||||
|
||||
n, _ := s.Count("group")
|
||||
assert.Equal(t, 0, n)
|
||||
count, _ := keyValueStore.Count("group")
|
||||
assert.Equal(t, 0, count)
|
||||
}
|
||||
|
||||
func TestStore_GetAll_Good(t *testing.T) {
|
||||
s := newTestStore(t)
|
||||
keyValueStore := newTestStore(t)
|
||||
|
||||
_ = s.Set("group", "a", "1")
|
||||
_ = s.Set("group", "b", "2")
|
||||
_ = s.Set("other", "c", "3")
|
||||
_ = keyValueStore.Set("group", "a", "1")
|
||||
_ = keyValueStore.Set("group", "b", "2")
|
||||
_ = keyValueStore.Set("other", "c", "3")
|
||||
|
||||
all, err := s.GetAll("group")
|
||||
all, err := keyValueStore.GetAll("group")
|
||||
require.NoError(t, err)
|
||||
assert.Equal(t, map[string]string{"a": "1", "b": "2"}, all)
|
||||
}
|
||||
|
||||
func TestStore_GetAll_Empty_Good(t *testing.T) {
|
||||
s := newTestStore(t)
|
||||
keyValueStore := newTestStore(t)
|
||||
|
||||
all, err := s.GetAll("empty")
|
||||
all, err := keyValueStore.GetAll("empty")
|
||||
require.NoError(t, err)
|
||||
assert.Empty(t, all)
|
||||
}
|
||||
|
||||
func TestStore_Render_Good(t *testing.T) {
|
||||
s := newTestStore(t)
|
||||
keyValueStore := newTestStore(t)
|
||||
|
||||
_ = s.Set("user", "pool", "pool.lthn.io:3333")
|
||||
_ = s.Set("user", "wallet", "iz...")
|
||||
_ = keyValueStore.Set("user", "pool", "pool.lthn.io:3333")
|
||||
_ = keyValueStore.Set("user", "wallet", "iz...")
|
||||
|
||||
tmpl := `{"pool":"{{ .pool }}","wallet":"{{ .wallet }}"}`
|
||||
out, err := s.Render(tmpl, "user")
|
||||
out, err := keyValueStore.Render(tmpl, "user")
|
||||
require.NoError(t, err)
|
||||
assert.Contains(t, out, "pool.lthn.io:3333")
|
||||
assert.Contains(t, out, "iz...")
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue