Implement files test

This commit is contained in:
2024-11-19 21:44:06 +01:00
parent 2fe642ac61
commit de2c9a6d0c

View File

@@ -1,60 +1,395 @@
// Package storage_test provides tests for the storage package.
package storage_test package storage_test
import ( import (
"io/fs"
"novamd/internal/storage" "novamd/internal/storage"
"novamd/internal/testutils" "path/filepath"
"testing" "testing"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
) )
func TestListFilesRecursively(t *testing.T) { // TestFileNode ensures FileNode structs are created correctly
tests := []testutils.TestCase{ func TestFileNode(t *testing.T) {
testCases := []struct {
name string // name of the test case
node storage.FileNode
want storage.FileNode
}{
{ {
Name: "empty workspace returns empty list", name: "file without children",
Setup: func(t *testing.T, fixtures any) { node: storage.FileNode{
fs := fixtures.(*MapFS) ID: "test.md",
require.NoError(t, fs.MkdirAll("/test/root/1/1", 0755)) Name: "test.md",
Path: "test.md",
}, },
Fixtures: NewMapFS(), want: storage.FileNode{
Validate: func(t *testing.T, result any, err error) { ID: "test.md",
require.NoError(t, err) Name: "test.md",
files := result.([]storage.FileNode) Path: "test.md",
assert.Empty(t, files)
}, },
}, },
{ {
Name: "lists files and directories correctly", name: "directory with children",
Setup: func(t *testing.T, fixtures any) { node: storage.FileNode{
fs := fixtures.(*MapFS) ID: "dir",
err := fs.WriteFile("/test/root/1/1/file1.md", []byte("content1"), 0644) Name: "dir",
require.NoError(t, err, "Failed to write file1.md") Path: "dir",
Children: []storage.FileNode{
err = fs.WriteFile("/test/root/1/1/dir/file2.md", []byte("content2"), 0644) {
require.NoError(t, err, "Failed to write file2.md") ID: "dir/file1.md",
Name: "file1.md",
Path: "dir/file1.md",
},
},
}, },
Fixtures: NewMapFS(), want: storage.FileNode{
Validate: func(t *testing.T, result any, err error) { ID: "dir",
require.NoError(t, err) Name: "dir",
files := result.([]storage.FileNode) Path: "dir",
require.Len(t, files, 2) Children: []storage.FileNode{
assert.Equal(t, "dir", files[0].Name) {
assert.Equal(t, "file1.md", files[1].Name) ID: "dir/file1.md",
assert.Len(t, files[0].Children, 1) Name: "file1.md",
assert.Equal(t, "file2.md", files[0].Children[0].Name) Path: "dir/file1.md",
},
},
}, },
}, },
} }
for _, tc := range tests { for _, tc := range testCases {
t.Run(tc.Name, func(t *testing.T) { t.Run(tc.name, func(t *testing.T) {
fs := tc.Fixtures.(*MapFS) got := tc.node // Now we're testing the actual node structure
srv := storage.NewServiceWithFS("/test/root", fs)
tc.Setup(t, tc.Fixtures) if got.ID != tc.want.ID {
files, err := srv.ListFilesRecursively(1, 1) t.Errorf("ID = %v, want %v", got.ID, tc.want.ID)
tc.Validate(t, files, err) }
if got.Name != tc.want.Name {
t.Errorf("Name = %v, want %v", got.Name, tc.want.Name)
}
if got.Path != tc.want.Path {
t.Errorf("Path = %v, want %v", got.Path, tc.want.Path)
}
if len(got.Children) != len(tc.want.Children) {
t.Errorf("len(Children) = %v, want %v", len(got.Children), len(tc.want.Children))
}
// Add deep comparison of children if they exist
if len(got.Children) > 0 {
for i := range got.Children {
if got.Children[i].ID != tc.want.Children[i].ID {
t.Errorf("Children[%d].ID = %v, want %v", i, got.Children[i].ID, tc.want.Children[i].ID)
}
if got.Children[i].Name != tc.want.Children[i].Name {
t.Errorf("Children[%d].Name = %v, want %v", i, got.Children[i].Name, tc.want.Children[i].Name)
}
if got.Children[i].Path != tc.want.Children[i].Path {
t.Errorf("Children[%d].Path = %v, want %v", i, got.Children[i].Path, tc.want.Children[i].Path)
}
}
}
})
}
}
func TestListFilesRecursively(t *testing.T) {
mockFS := NewMockFS()
s := storage.NewServiceWithFS("test-root", mockFS)
t.Run("empty directory", func(t *testing.T) {
mockFS.ReadDirReturns = map[string]struct {
entries []fs.DirEntry
err error
}{
"test-root/1/1": {
entries: []fs.DirEntry{},
err: nil,
},
}
files, err := s.ListFilesRecursively(1, 1)
if err != nil {
t.Fatalf("unexpected error: %v", err)
}
if len(files) != 0 {
t.Errorf("expected empty file list, got %v", files)
}
})
t.Run("directory with files", func(t *testing.T) {
mockFS.ReadDirReturns = map[string]struct {
entries []fs.DirEntry
err error
}{
"test-root/1/1": {
entries: []fs.DirEntry{
NewMockDirEntry("file1.md", false),
NewMockDirEntry("file2.md", false),
},
err: nil,
},
}
files, err := s.ListFilesRecursively(1, 1)
if err != nil {
t.Fatalf("unexpected error: %v", err)
}
if len(files) != 2 {
t.Errorf("expected 2 files, got %d", len(files))
}
})
t.Run("nested directories", func(t *testing.T) {
mockFS.ReadDirReturns = map[string]struct {
entries []fs.DirEntry
err error
}{
"test-root/1/1": {
entries: []fs.DirEntry{
NewMockDirEntry("dir1", true),
NewMockDirEntry("file1.md", false),
},
err: nil,
},
"test-root/1/1/dir1": {
entries: []fs.DirEntry{
NewMockDirEntry("file2.md", false),
},
err: nil,
},
}
files, err := s.ListFilesRecursively(1, 1)
if err != nil {
t.Fatalf("unexpected error: %v", err)
}
if len(files) != 2 { // dir1 and file1.md
t.Errorf("expected 2 entries at root, got %d", len(files))
}
// Find directory and check its children
var dirFound bool
for _, f := range files {
if f.Name == "dir1" {
dirFound = true
if len(f.Children) != 1 {
t.Errorf("expected 1 child in dir1, got %d", len(f.Children))
}
}
}
if !dirFound {
t.Error("directory 'dir1' not found in results")
}
})
}
func TestGetFileContent(t *testing.T) {
mockFS := NewMockFS()
s := storage.NewServiceWithFS("test-root", mockFS)
testCases := []struct {
name string
userID int
workspaceID int
filePath string
mockData []byte
mockErr error
wantErr bool
}{
{
name: "successful read",
userID: 1,
workspaceID: 1,
filePath: "test.md",
mockData: []byte("test content"),
mockErr: nil,
wantErr: false,
},
{
name: "file not found",
userID: 1,
workspaceID: 1,
filePath: "nonexistent.md",
mockData: nil,
mockErr: fs.ErrNotExist,
wantErr: true,
},
{
name: "invalid path",
userID: 1,
workspaceID: 1,
filePath: "../../../etc/passwd",
mockData: nil,
mockErr: nil,
wantErr: true,
},
}
for _, tc := range testCases {
t.Run(tc.name, func(t *testing.T) {
expectedPath := filepath.Join("test-root", "1", "1", tc.filePath)
mockFS.ReadFileReturns[expectedPath] = struct {
data []byte
err error
}{tc.mockData, tc.mockErr}
content, err := s.GetFileContent(tc.userID, tc.workspaceID, tc.filePath)
if tc.wantErr {
if err == nil {
t.Error("expected error, got nil")
}
return
}
if err != nil {
t.Fatalf("unexpected error: %v", err)
}
if string(content) != string(tc.mockData) {
t.Errorf("content = %q, want %q", content, tc.mockData)
}
if mockFS.ReadCalls[expectedPath] != 1 {
t.Errorf("expected 1 read call for %s, got %d", expectedPath, mockFS.ReadCalls[expectedPath])
}
})
}
}
func TestSaveFile(t *testing.T) {
mockFS := NewMockFS()
s := storage.NewServiceWithFS("test-root", mockFS)
testCases := []struct {
name string
userID int
workspaceID int
filePath string
content []byte
mockErr error
wantErr bool
}{
{
name: "successful save",
userID: 1,
workspaceID: 1,
filePath: "test.md",
content: []byte("test content"),
mockErr: nil,
wantErr: false,
},
{
name: "invalid path",
userID: 1,
workspaceID: 1,
filePath: "../../../etc/passwd",
content: []byte("test content"),
mockErr: nil,
wantErr: true,
},
{
name: "write error",
userID: 1,
workspaceID: 1,
filePath: "test.md",
content: []byte("test content"),
mockErr: fs.ErrPermission,
wantErr: true,
},
}
for _, tc := range testCases {
t.Run(tc.name, func(t *testing.T) {
mockFS.WriteFileError = tc.mockErr
err := s.SaveFile(tc.userID, tc.workspaceID, tc.filePath, tc.content)
if tc.wantErr {
if err == nil {
t.Error("expected error, got nil")
}
return
}
if err != nil {
t.Fatalf("unexpected error: %v", err)
}
expectedPath := filepath.Join("test-root", "1", "1", tc.filePath)
if content, ok := mockFS.WriteCalls[expectedPath]; ok {
if string(content) != string(tc.content) {
t.Errorf("written content = %q, want %q", content, tc.content)
}
} else {
t.Error("expected write call not made")
}
})
}
}
func TestDeleteFile(t *testing.T) {
mockFS := NewMockFS()
s := storage.NewServiceWithFS("test-root", mockFS)
testCases := []struct {
name string
userID int
workspaceID int
filePath string
mockErr error
wantErr bool
}{
{
name: "successful delete",
userID: 1,
workspaceID: 1,
filePath: "test.md",
mockErr: nil,
wantErr: false,
},
{
name: "invalid path",
userID: 1,
workspaceID: 1,
filePath: "../../../etc/passwd",
mockErr: nil,
wantErr: true,
},
{
name: "file not found",
userID: 1,
workspaceID: 1,
filePath: "nonexistent.md",
mockErr: fs.ErrNotExist,
wantErr: true,
},
}
for _, tc := range testCases {
t.Run(tc.name, func(t *testing.T) {
mockFS.RemoveError = tc.mockErr
err := s.DeleteFile(tc.userID, tc.workspaceID, tc.filePath)
if tc.wantErr {
if err == nil {
t.Error("expected error, got nil")
}
return
}
if err != nil {
t.Fatalf("unexpected error: %v", err)
}
expectedPath := filepath.Join("test-root", "1", "1", tc.filePath)
found := false
for _, p := range mockFS.RemoveCalls {
if p == expectedPath {
found = true
break
}
}
if !found {
t.Error("expected delete call not made")
}
}) })
} }
} }