Automated Action 887703b6a2 Add Go Todo App implementation
This commit adds a complete Go implementation of the Todo application. The
application uses Gin framework for the web server, GORM for database access,
and SQLite for storage.

Key features:
- Todo CRUD operations with the same API endpoints
- Health check endpoint
- Database migrations
- Tests for models, services, and API handlers
- Documentation for the API
- Configurable settings
2025-05-17 22:20:05 +00:00

228 lines
5.0 KiB
Go

package service
import (
"testing"
"github.com/simpletodoapp/go-todo-app/internal/dto"
"github.com/simpletodoapp/go-todo-app/internal/model"
"gorm.io/driver/sqlite"
"gorm.io/gorm"
)
// setupTestDB sets up an in-memory SQLite database for testing
func setupTestDB(t *testing.T) *gorm.DB {
db, err := gorm.Open(sqlite.Open("file::memory:?cache=shared"), &gorm.Config{})
if err != nil {
t.Fatalf("Failed to connect to in-memory database: %v", err)
}
// Auto-migrate the schema
err = db.AutoMigrate(&model.Todo{})
if err != nil {
t.Fatalf("Failed to migrate test database: %v", err)
}
return db
}
// populateTestData adds test data to the database
func populateTestData(t *testing.T, db *gorm.DB) {
todos := []model.Todo{
{
Title: "Test Todo 1",
Description: "Test Description 1",
Completed: false,
},
{
Title: "Test Todo 2",
Description: "Test Description 2",
Completed: true,
},
}
for _, todo := range todos {
if err := db.Create(&todo).Error; err != nil {
t.Fatalf("Failed to create test data: %v", err)
}
}
}
func TestGetTodos(t *testing.T) {
db := setupTestDB(t)
populateTestData(t, db)
service := NewTodoService(db)
// Test getting all todos
todos, err := service.GetTodos(0, 100, nil)
if err != nil {
t.Fatalf("Failed to get todos: %v", err)
}
if len(todos) != 2 {
t.Errorf("Expected 2 todos, got %d", len(todos))
}
// Test filtering by completed
completed := true
todos, err = service.GetTodos(0, 100, &completed)
if err != nil {
t.Fatalf("Failed to get completed todos: %v", err)
}
if len(todos) != 1 {
t.Errorf("Expected 1 completed todo, got %d", len(todos))
}
if !todos[0].Completed {
t.Errorf("Expected todo to be completed, got %t", todos[0].Completed)
}
// Test pagination
todos, err = service.GetTodos(1, 1, nil)
if err != nil {
t.Fatalf("Failed to get paginated todos: %v", err)
}
if len(todos) != 1 {
t.Errorf("Expected 1 todo with pagination, got %d", len(todos))
}
}
func TestCreateTodo(t *testing.T) {
db := setupTestDB(t)
service := NewTodoService(db)
// Create a new todo
todoCreate := dto.TodoCreate{
TodoBase: dto.TodoBase{
Title: "New Todo",
Description: "New Description",
Completed: false,
},
}
todo, err := service.CreateTodo(todoCreate)
if err != nil {
t.Fatalf("Failed to create todo: %v", err)
}
if todo.ID == 0 {
t.Errorf("Expected todo ID to be set, got %d", todo.ID)
}
if todo.Title != "New Todo" {
t.Errorf("Expected title to be 'New Todo', got '%s'", todo.Title)
}
if todo.Description != "New Description" {
t.Errorf("Expected description to be 'New Description', got '%s'", todo.Description)
}
if todo.Completed != false {
t.Errorf("Expected completed to be false, got %t", todo.Completed)
}
}
func TestGetTodoByID(t *testing.T) {
db := setupTestDB(t)
populateTestData(t, db)
service := NewTodoService(db)
// Get a todo by ID
todo, err := service.GetTodoByID(1)
if err != nil {
t.Fatalf("Failed to get todo by ID: %v", err)
}
if todo == nil {
t.Fatalf("Expected todo to be found, got nil")
}
if todo.ID != 1 {
t.Errorf("Expected todo ID to be 1, got %d", todo.ID)
}
// Test non-existent todo
todo, err = service.GetTodoByID(999)
if err != nil {
t.Fatalf("Expected no error for non-existent todo, got %v", err)
}
if todo != nil {
t.Errorf("Expected nil for non-existent todo, got %+v", todo)
}
}
func TestUpdateTodo(t *testing.T) {
db := setupTestDB(t)
populateTestData(t, db)
service := NewTodoService(db)
// Update a todo
title := "Updated Title"
completed := true
todoUpdate := dto.TodoUpdate{
Title: &title,
Completed: &completed,
}
todo, err := service.UpdateTodo(1, todoUpdate)
if err != nil {
t.Fatalf("Failed to update todo: %v", err)
}
if todo.Title != "Updated Title" {
t.Errorf("Expected title to be 'Updated Title', got '%s'", todo.Title)
}
if !todo.Completed {
t.Errorf("Expected completed to be true, got %t", todo.Completed)
}
// Test updating non-existent todo
todo, err = service.UpdateTodo(999, todoUpdate)
if err != nil {
t.Fatalf("Expected no error for non-existent todo, got %v", err)
}
if todo != nil {
t.Errorf("Expected nil for non-existent todo, got %+v", todo)
}
}
func TestDeleteTodo(t *testing.T) {
db := setupTestDB(t)
populateTestData(t, db)
service := NewTodoService(db)
// Delete a todo
deleted, err := service.DeleteTodo(1)
if err != nil {
t.Fatalf("Failed to delete todo: %v", err)
}
if !deleted {
t.Errorf("Expected todo to be deleted")
}
// Try to get the deleted todo
todo, err := service.GetTodoByID(1)
if err != nil {
t.Fatalf("Unexpected error after deletion: %v", err)
}
if todo != nil {
t.Errorf("Expected todo to be nil after deletion, got %+v", todo)
}
// Test deleting non-existent todo
deleted, err = service.DeleteTodo(999)
if err != nil {
t.Fatalf("Expected no error for non-existent todo, got %v", err)
}
if deleted {
t.Errorf("Expected false for deleting non-existent todo, got %t", deleted)
}
}