mirror of
https://github.com/lordmathis/lemma.git
synced 2025-11-06 16:04:23 +00:00
Implement files test
This commit is contained in:
@@ -1,60 +1,395 @@
|
||||
// Package storage_test provides tests for the storage package.
|
||||
package storage_test
|
||||
|
||||
import (
|
||||
"io/fs"
|
||||
"novamd/internal/storage"
|
||||
"novamd/internal/testutils"
|
||||
"path/filepath"
|
||||
"testing"
|
||||
|
||||
"github.com/stretchr/testify/assert"
|
||||
"github.com/stretchr/testify/require"
|
||||
)
|
||||
|
||||
func TestListFilesRecursively(t *testing.T) {
|
||||
tests := []testutils.TestCase{
|
||||
// TestFileNode ensures FileNode structs are created correctly
|
||||
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",
|
||||
Setup: func(t *testing.T, fixtures any) {
|
||||
fs := fixtures.(*MapFS)
|
||||
require.NoError(t, fs.MkdirAll("/test/root/1/1", 0755))
|
||||
name: "file without children",
|
||||
node: storage.FileNode{
|
||||
ID: "test.md",
|
||||
Name: "test.md",
|
||||
Path: "test.md",
|
||||
},
|
||||
Fixtures: NewMapFS(),
|
||||
Validate: func(t *testing.T, result any, err error) {
|
||||
require.NoError(t, err)
|
||||
files := result.([]storage.FileNode)
|
||||
assert.Empty(t, files)
|
||||
want: storage.FileNode{
|
||||
ID: "test.md",
|
||||
Name: "test.md",
|
||||
Path: "test.md",
|
||||
},
|
||||
},
|
||||
{
|
||||
Name: "lists files and directories correctly",
|
||||
Setup: func(t *testing.T, fixtures any) {
|
||||
fs := fixtures.(*MapFS)
|
||||
err := fs.WriteFile("/test/root/1/1/file1.md", []byte("content1"), 0644)
|
||||
require.NoError(t, err, "Failed to write file1.md")
|
||||
|
||||
err = fs.WriteFile("/test/root/1/1/dir/file2.md", []byte("content2"), 0644)
|
||||
require.NoError(t, err, "Failed to write file2.md")
|
||||
name: "directory with children",
|
||||
node: storage.FileNode{
|
||||
ID: "dir",
|
||||
Name: "dir",
|
||||
Path: "dir",
|
||||
Children: []storage.FileNode{
|
||||
{
|
||||
ID: "dir/file1.md",
|
||||
Name: "file1.md",
|
||||
Path: "dir/file1.md",
|
||||
},
|
||||
},
|
||||
},
|
||||
want: storage.FileNode{
|
||||
ID: "dir",
|
||||
Name: "dir",
|
||||
Path: "dir",
|
||||
Children: []storage.FileNode{
|
||||
{
|
||||
ID: "dir/file1.md",
|
||||
Name: "file1.md",
|
||||
Path: "dir/file1.md",
|
||||
},
|
||||
},
|
||||
Fixtures: NewMapFS(),
|
||||
Validate: func(t *testing.T, result any, err error) {
|
||||
require.NoError(t, err)
|
||||
files := result.([]storage.FileNode)
|
||||
require.Len(t, files, 2)
|
||||
assert.Equal(t, "dir", files[0].Name)
|
||||
assert.Equal(t, "file1.md", files[1].Name)
|
||||
assert.Len(t, files[0].Children, 1)
|
||||
assert.Equal(t, "file2.md", files[0].Children[0].Name)
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
for _, tc := range tests {
|
||||
t.Run(tc.Name, func(t *testing.T) {
|
||||
fs := tc.Fixtures.(*MapFS)
|
||||
srv := storage.NewServiceWithFS("/test/root", fs)
|
||||
tc.Setup(t, tc.Fixtures)
|
||||
files, err := srv.ListFilesRecursively(1, 1)
|
||||
tc.Validate(t, files, err)
|
||||
for _, tc := range testCases {
|
||||
t.Run(tc.name, func(t *testing.T) {
|
||||
got := tc.node // Now we're testing the actual node structure
|
||||
|
||||
if got.ID != tc.want.ID {
|
||||
t.Errorf("ID = %v, want %v", got.ID, tc.want.ID)
|
||||
}
|
||||
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")
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user