Complete foundational data layer with repository implementation
- Add GORM dependencies for SQLite and PostgreSQL - Create domain models (User, Session, File) with common errors - Implement repository interfaces and database layer with migrations - Update WebApp to bootstrap with database and repositories - Add comprehensive unit tests for repository methods - Update config structure to support multiple database drivers - Extend AGENTS.md with debugging principles and dependency rules
This commit is contained in:
195
internal/repository/file_test.go
Normal file
195
internal/repository/file_test.go
Normal file
@@ -0,0 +1,195 @@
|
||||
package repository
|
||||
|
||||
import (
|
||||
"context"
|
||||
"testing"
|
||||
|
||||
"gorm.io/driver/sqlite"
|
||||
"gorm.io/gorm"
|
||||
|
||||
"github.com/dhao2001/mygo/internal/model"
|
||||
)
|
||||
|
||||
func setupFileRepo(t *testing.T) FileRepository {
|
||||
t.Helper()
|
||||
|
||||
db, err := gorm.Open(sqlite.Open(":memory:"), &gorm.Config{})
|
||||
if err != nil {
|
||||
t.Fatalf("open db: %v", err)
|
||||
}
|
||||
if err := db.AutoMigrate(&model.File{}); err != nil {
|
||||
t.Fatalf("migrate: %v", err)
|
||||
}
|
||||
|
||||
return NewFileRepository(db)
|
||||
}
|
||||
|
||||
func TestFileRepository_Create(t *testing.T) {
|
||||
repo := setupFileRepo(t)
|
||||
ctx := context.Background()
|
||||
|
||||
file := &model.File{
|
||||
ID: "file-1",
|
||||
UserID: "user-1",
|
||||
Name: "test.txt",
|
||||
Size: 1024,
|
||||
}
|
||||
|
||||
if err := repo.Create(ctx, file); err != nil {
|
||||
t.Fatalf("Create = %v", err)
|
||||
}
|
||||
}
|
||||
|
||||
func TestFileRepository_FindByID(t *testing.T) {
|
||||
repo := setupFileRepo(t)
|
||||
ctx := context.Background()
|
||||
|
||||
file := &model.File{
|
||||
ID: "file-1",
|
||||
UserID: "user-1",
|
||||
Name: "test.txt",
|
||||
}
|
||||
if err := repo.Create(ctx, file); err != nil {
|
||||
t.Fatalf("Create = %v", err)
|
||||
}
|
||||
|
||||
found, err := repo.FindByID(ctx, "file-1")
|
||||
if err != nil {
|
||||
t.Fatalf("FindByID = %v", err)
|
||||
}
|
||||
if found.Name != "test.txt" {
|
||||
t.Errorf("name = %q, want %q", found.Name, "test.txt")
|
||||
}
|
||||
}
|
||||
|
||||
func TestFileRepository_FindByIDNotFound(t *testing.T) {
|
||||
repo := setupFileRepo(t)
|
||||
ctx := context.Background()
|
||||
|
||||
_, err := repo.FindByID(ctx, "nonexistent")
|
||||
if err != model.ErrNotFound {
|
||||
t.Fatalf("expected ErrNotFound, got %v", err)
|
||||
}
|
||||
}
|
||||
|
||||
func TestFileRepository_FindByUserID(t *testing.T) {
|
||||
repo := setupFileRepo(t)
|
||||
ctx := context.Background()
|
||||
|
||||
files := []*model.File{
|
||||
{ID: "f-1", UserID: "user-1", Name: "a.txt"},
|
||||
{ID: "f-2", UserID: "user-1", Name: "b.txt"},
|
||||
{ID: "f-3", UserID: "user-2", Name: "c.txt"},
|
||||
}
|
||||
for _, f := range files {
|
||||
if err := repo.Create(ctx, f); err != nil {
|
||||
t.Fatalf("Create = %v", err)
|
||||
}
|
||||
}
|
||||
|
||||
result, total, err := repo.FindByUserID(ctx, "user-1", 0, 10)
|
||||
if err != nil {
|
||||
t.Fatalf("FindByUserID = %v", err)
|
||||
}
|
||||
if len(result) != 2 {
|
||||
t.Errorf("len(result) = %d, want 2", len(result))
|
||||
}
|
||||
if total != 2 {
|
||||
t.Errorf("total = %d, want 2", total)
|
||||
}
|
||||
}
|
||||
|
||||
func TestFileRepository_FindByParentID(t *testing.T) {
|
||||
repo := setupFileRepo(t)
|
||||
ctx := context.Background()
|
||||
|
||||
parentID := "dir-1"
|
||||
files := []*model.File{
|
||||
{ID: "f-1", UserID: "user-1", ParentID: &parentID, Name: "a.txt"},
|
||||
{ID: "f-2", UserID: "user-1", ParentID: &parentID, Name: "b.txt"},
|
||||
{ID: "f-3", UserID: "user-1", Name: "c.txt"},
|
||||
}
|
||||
for _, f := range files {
|
||||
if err := repo.Create(ctx, f); err != nil {
|
||||
t.Fatalf("Create = %v", err)
|
||||
}
|
||||
}
|
||||
|
||||
children, err := repo.FindByParentID(ctx, "user-1", &parentID)
|
||||
if err != nil {
|
||||
t.Fatalf("FindByParentID = %v", err)
|
||||
}
|
||||
if len(children) != 2 {
|
||||
t.Errorf("len(children) = %d, want 2", len(children))
|
||||
}
|
||||
}
|
||||
|
||||
func TestFileRepository_FindByParentIDNull(t *testing.T) {
|
||||
repo := setupFileRepo(t)
|
||||
ctx := context.Background()
|
||||
|
||||
parentID := "dir-1"
|
||||
files := []*model.File{
|
||||
{ID: "f-1", UserID: "user-1", ParentID: &parentID, Name: "a.txt"},
|
||||
{ID: "f-2", UserID: "user-1", Name: "root.txt"},
|
||||
}
|
||||
for _, f := range files {
|
||||
if err := repo.Create(ctx, f); err != nil {
|
||||
t.Fatalf("Create = %v", err)
|
||||
}
|
||||
}
|
||||
|
||||
children, err := repo.FindByParentID(ctx, "user-1", nil)
|
||||
if err != nil {
|
||||
t.Fatalf("FindByParentID(nil) = %v", err)
|
||||
}
|
||||
if len(children) != 1 {
|
||||
t.Errorf("len(children) = %d, want 1", len(children))
|
||||
}
|
||||
}
|
||||
|
||||
func TestFileRepository_Update(t *testing.T) {
|
||||
repo := setupFileRepo(t)
|
||||
ctx := context.Background()
|
||||
|
||||
file := &model.File{ID: "file-1", UserID: "user-1", Name: "original.txt"}
|
||||
if err := repo.Create(ctx, file); err != nil {
|
||||
t.Fatalf("Create = %v", err)
|
||||
}
|
||||
|
||||
file.Name = "renamed.txt"
|
||||
file.Size = 2048
|
||||
if err := repo.Update(ctx, file); err != nil {
|
||||
t.Fatalf("Update = %v", err)
|
||||
}
|
||||
|
||||
found, err := repo.FindByID(ctx, "file-1")
|
||||
if err != nil {
|
||||
t.Fatalf("FindByID = %v", err)
|
||||
}
|
||||
if found.Name != "renamed.txt" {
|
||||
t.Errorf("name = %q, want %q", found.Name, "renamed.txt")
|
||||
}
|
||||
if found.Size != 2048 {
|
||||
t.Errorf("size = %d, want %d", found.Size, 2048)
|
||||
}
|
||||
}
|
||||
|
||||
func TestFileRepository_Delete(t *testing.T) {
|
||||
repo := setupFileRepo(t)
|
||||
ctx := context.Background()
|
||||
|
||||
file := &model.File{ID: "file-1", UserID: "user-1", Name: "test.txt"}
|
||||
if err := repo.Create(ctx, file); err != nil {
|
||||
t.Fatalf("Create = %v", err)
|
||||
}
|
||||
|
||||
if err := repo.Delete(ctx, "file-1"); err != nil {
|
||||
t.Fatalf("Delete = %v", err)
|
||||
}
|
||||
|
||||
_, err := repo.FindByID(ctx, "file-1")
|
||||
if err != model.ErrNotFound {
|
||||
t.Fatalf("expected ErrNotFound after delete, got %v", err)
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user