| package git_tm |
| |
| import ( |
| "context" |
| "os" |
| "path/filepath" |
| "testing" |
| "time" |
| |
| "github.com/iomodo/staff/git" |
| "github.com/iomodo/staff/tm" |
| "github.com/stretchr/testify/assert" |
| "github.com/stretchr/testify/require" |
| ) |
| |
| // Test helper functions |
| func setupTestDir(t *testing.T) (string, func()) { |
| tempDir, err := os.MkdirTemp("", "git-task-manager-test") |
| require.NoError(t, err) |
| |
| cleanup := func() { |
| os.RemoveAll(tempDir) |
| } |
| |
| return tempDir, cleanup |
| } |
| |
| func createTestTaskManager(t *testing.T, repoPath string) (*GitTaskManager, git.GitInterface) { |
| // Initialize git repository |
| gitImpl := git.DefaultGit(repoPath) |
| ctx := context.Background() |
| |
| err := gitImpl.Init(ctx, repoPath) |
| require.NoError(t, err) |
| |
| // Set up git user config for commits |
| userConfig := git.UserConfig{ |
| Name: "Test User", |
| Email: "test@example.com", |
| } |
| err = gitImpl.SetUserConfig(ctx, userConfig) |
| require.NoError(t, err) |
| |
| gtm := NewGitTaskManager(gitImpl, repoPath) |
| return gtm, gitImpl |
| } |
| |
| // Test cases |
| func TestNewGitTaskManager(t *testing.T) { |
| tempDir, cleanup := setupTestDir(t) |
| defer cleanup() |
| |
| gitImpl := git.DefaultGit(tempDir) |
| gtm := NewGitTaskManager(gitImpl, tempDir) |
| |
| assert.NotNil(t, gtm) |
| assert.Equal(t, gitImpl, gtm.git) |
| assert.Equal(t, tempDir, gtm.repoPath) |
| assert.Equal(t, filepath.Join(tempDir, "tasks"), gtm.tasksDir) |
| } |
| |
| func TestEnsureTasksDir(t *testing.T) { |
| tempDir, cleanup := setupTestDir(t) |
| defer cleanup() |
| |
| gtm, _ := createTestTaskManager(t, tempDir) |
| |
| // Test creating tasks directory |
| err := gtm.ensureTasksDir() |
| assert.NoError(t, err) |
| |
| // Verify directory exists |
| _, err = os.Stat(gtm.tasksDir) |
| assert.NoError(t, err) |
| |
| // Test creating again (should not error) |
| err = gtm.ensureTasksDir() |
| assert.NoError(t, err) |
| } |
| |
| func TestGenerateTaskID(t *testing.T) { |
| tempDir, cleanup := setupTestDir(t) |
| defer cleanup() |
| |
| gtm, _ := createTestTaskManager(t, tempDir) |
| |
| id1 := gtm.generateTaskID() |
| id2 := gtm.generateTaskID() |
| |
| assert.NotEmpty(t, id1) |
| assert.NotEmpty(t, id2) |
| assert.NotEqual(t, id1, id2) |
| assert.Contains(t, id1, "task-") |
| } |
| |
| func TestTaskToMarkdown(t *testing.T) { |
| tempDir, cleanup := setupTestDir(t) |
| defer cleanup() |
| |
| gtm, _ := createTestTaskManager(t, tempDir) |
| |
| now := time.Now() |
| dueDate := now.Add(24 * time.Hour) |
| completedAt := now.Add(12 * time.Hour) |
| |
| task := &tm.Task{ |
| ID: "test-task-123", |
| Title: "Test Task", |
| Description: "This is a test task", |
| Owner: tm.Owner{ |
| ID: "user123", |
| Name: "Test User", |
| }, |
| Status: tm.StatusToDo, |
| Priority: tm.PriorityHigh, |
| CreatedAt: now, |
| UpdatedAt: now, |
| DueDate: &dueDate, |
| CompletedAt: &completedAt, |
| } |
| |
| markdown, err := gtm.taskToMarkdown(task) |
| assert.NoError(t, err) |
| assert.NotEmpty(t, markdown) |
| assert.Contains(t, markdown, "---") |
| assert.Contains(t, markdown, "id: test-task-123") |
| assert.Contains(t, markdown, "title: Test Task") |
| assert.Contains(t, markdown, "description: This is a test task") |
| assert.Contains(t, markdown, "owner_id: user123") |
| assert.Contains(t, markdown, "owner_name: Test User") |
| assert.Contains(t, markdown, "status: todo") |
| assert.Contains(t, markdown, "priority: high") |
| assert.Contains(t, markdown, "# Task Description") |
| assert.Contains(t, markdown, "This is a test task") |
| } |
| |
| func TestParseTaskFromMarkdown(t *testing.T) { |
| tempDir, cleanup := setupTestDir(t) |
| defer cleanup() |
| |
| gtm, _ := createTestTaskManager(t, tempDir) |
| |
| markdown := `--- |
| id: test-task-123 |
| title: Test Task |
| description: This is a test task |
| owner_id: user123 |
| owner_name: Test User |
| status: todo |
| priority: high |
| created_at: 2023-01-01T00:00:00Z |
| updated_at: 2023-01-01T00:00:00Z |
| due_date: 2023-01-02T00:00:00Z |
| completed_at: 2023-01-01T12:00:00Z |
| --- |
| |
| # Task Description |
| |
| This is a test task |
| ` |
| |
| task, err := gtm.parseTaskFromMarkdown(markdown) |
| assert.NoError(t, err) |
| assert.NotNil(t, task) |
| assert.Equal(t, "test-task-123", task.ID) |
| assert.Equal(t, "Test Task", task.Title) |
| assert.Equal(t, "This is a test task", task.Description) |
| assert.Equal(t, "user123", task.Owner.ID) |
| assert.Equal(t, "Test User", task.Owner.Name) |
| assert.Equal(t, tm.StatusToDo, task.Status) |
| assert.Equal(t, tm.PriorityHigh, task.Priority) |
| } |
| |
| func TestParseTaskFromMarkdownInvalid(t *testing.T) { |
| tempDir, cleanup := setupTestDir(t) |
| defer cleanup() |
| |
| gtm, _ := createTestTaskManager(t, tempDir) |
| |
| // Test invalid markdown format |
| invalidMarkdown := "This is not valid markdown" |
| |
| task, err := gtm.parseTaskFromMarkdown(invalidMarkdown) |
| assert.Error(t, err) |
| assert.Nil(t, task) |
| assert.Contains(t, err.Error(), "invalid markdown format") |
| } |
| |
| func TestWriteAndReadTaskFile(t *testing.T) { |
| tempDir, cleanup := setupTestDir(t) |
| defer cleanup() |
| |
| gtm, _ := createTestTaskManager(t, tempDir) |
| |
| // Ensure tasks directory exists |
| err := gtm.ensureTasksDir() |
| require.NoError(t, err) |
| |
| // Create test task |
| task := &tm.Task{ |
| ID: "test-task-123", |
| Title: "Test Task", |
| Description: "This is a test task", |
| Owner: tm.Owner{ |
| ID: "user123", |
| Name: "Test User", |
| }, |
| Status: tm.StatusToDo, |
| Priority: tm.PriorityHigh, |
| CreatedAt: time.Now(), |
| UpdatedAt: time.Now(), |
| } |
| |
| // Write task file |
| err = gtm.writeTaskFile(task) |
| assert.NoError(t, err) |
| |
| // Verify file exists |
| filePath := filepath.Join(gtm.tasksDir, task.ID+".md") |
| _, err = os.Stat(filePath) |
| assert.NoError(t, err) |
| |
| // Read task file |
| readTask, err := gtm.readTaskFile(task.ID) |
| assert.NoError(t, err) |
| assert.NotNil(t, readTask) |
| assert.Equal(t, task.ID, readTask.ID) |
| assert.Equal(t, task.Title, readTask.Title) |
| assert.Equal(t, task.Description, readTask.Description) |
| assert.Equal(t, task.Owner.ID, readTask.Owner.ID) |
| assert.Equal(t, task.Owner.Name, readTask.Owner.Name) |
| assert.Equal(t, task.Status, readTask.Status) |
| assert.Equal(t, task.Priority, readTask.Priority) |
| } |
| |
| func TestReadTaskFileNotFound(t *testing.T) { |
| tempDir, cleanup := setupTestDir(t) |
| defer cleanup() |
| |
| gtm, _ := createTestTaskManager(t, tempDir) |
| |
| // Try to read non-existent task |
| task, err := gtm.readTaskFile("non-existent-task") |
| assert.Error(t, err) |
| assert.Nil(t, task) |
| assert.Equal(t, tm.ErrTaskNotFound, err) |
| } |
| |
| func TestListTaskFiles(t *testing.T) { |
| tempDir, cleanup := setupTestDir(t) |
| defer cleanup() |
| |
| gtm, _ := createTestTaskManager(t, tempDir) |
| |
| // Ensure tasks directory exists |
| err := gtm.ensureTasksDir() |
| require.NoError(t, err) |
| |
| // Create some test task files |
| taskIDs := []string{"task-1", "task-2", "task-3"} |
| for _, id := range taskIDs { |
| task := &tm.Task{ |
| ID: id, |
| Title: "Test Task " + id, |
| Description: "Test task description", |
| Owner: tm.Owner{ |
| ID: "user123", |
| Name: "Test User", |
| }, |
| Status: tm.StatusToDo, |
| Priority: tm.PriorityMedium, |
| CreatedAt: time.Now(), |
| UpdatedAt: time.Now(), |
| } |
| err = gtm.writeTaskFile(task) |
| require.NoError(t, err) |
| } |
| |
| // Create a non-task file |
| nonTaskFile := filepath.Join(gtm.tasksDir, "readme.txt") |
| err = os.WriteFile(nonTaskFile, []byte("This is not a task"), 0644) |
| require.NoError(t, err) |
| |
| // List task files |
| taskFiles, err := gtm.listTaskFiles() |
| assert.NoError(t, err) |
| assert.Len(t, taskFiles, 3) |
| |
| // Verify all task IDs are present |
| for _, id := range taskIDs { |
| assert.Contains(t, taskFiles, id) |
| } |
| } |
| |
| func TestListTaskFilesEmpty(t *testing.T) { |
| tempDir, cleanup := setupTestDir(t) |
| defer cleanup() |
| |
| gtm, _ := createTestTaskManager(t, tempDir) |
| |
| // List task files in non-existent directory |
| taskFiles, err := gtm.listTaskFiles() |
| assert.NoError(t, err) |
| assert.Empty(t, taskFiles) |
| } |
| |
| func TestCommitTaskChange(t *testing.T) { |
| tempDir, cleanup := setupTestDir(t) |
| defer cleanup() |
| |
| gtm, gitImpl := createTestTaskManager(t, tempDir) |
| |
| // Create a test task file first |
| task := &tm.Task{ |
| ID: "test-task-123", |
| Title: "Test Task", |
| Description: "Test description", |
| Owner: tm.Owner{ |
| ID: "user123", |
| Name: "Test User", |
| }, |
| Status: tm.StatusToDo, |
| Priority: tm.PriorityMedium, |
| CreatedAt: time.Now(), |
| UpdatedAt: time.Now(), |
| } |
| |
| err := gtm.ensureTasksDir() |
| require.NoError(t, err) |
| err = gtm.writeTaskFile(task) |
| require.NoError(t, err) |
| |
| // Test successful commit |
| err = gtm.commitTaskChange("test-task-123", "created") |
| assert.NoError(t, err) |
| |
| // Verify commit was created |
| ctx := context.Background() |
| commits, err := gitImpl.Log(ctx, git.LogOptions{MaxCount: 1}) |
| assert.NoError(t, err) |
| if len(commits) > 0 { |
| assert.Contains(t, commits[0].Message, "test-task-123") |
| assert.Contains(t, commits[0].Message, "created") |
| } |
| } |
| |
| func TestCreateTask(t *testing.T) { |
| tempDir, cleanup := setupTestDir(t) |
| defer cleanup() |
| |
| gtm, gitImpl := createTestTaskManager(t, tempDir) |
| |
| ctx := context.Background() |
| req := &tm.TaskCreateRequest{ |
| Title: "New Test Task", |
| Description: "This is a new test task", |
| OwnerID: "user123", |
| Priority: tm.PriorityHigh, |
| } |
| |
| task, err := gtm.CreateTask(ctx, req) |
| assert.NoError(t, err) |
| assert.NotNil(t, task) |
| |
| // Verify task properties |
| assert.NotEmpty(t, task.ID) |
| assert.Contains(t, task.ID, "task-") |
| assert.Equal(t, req.Title, task.Title) |
| assert.Equal(t, req.Description, task.Description) |
| assert.Equal(t, req.OwnerID, task.Owner.ID) |
| assert.Equal(t, req.OwnerID, task.Owner.Name) // TODO: Should look up actual name |
| assert.Equal(t, tm.StatusToDo, task.Status) |
| assert.Equal(t, req.Priority, task.Priority) |
| assert.False(t, task.CreatedAt.IsZero()) |
| assert.False(t, task.UpdatedAt.IsZero()) |
| |
| // Verify git commit was created |
| commits, err := gitImpl.Log(ctx, git.LogOptions{MaxCount: 1}) |
| assert.NoError(t, err) |
| if len(commits) > 0 { |
| assert.Contains(t, commits[0].Message, task.ID) |
| assert.Contains(t, commits[0].Message, "created") |
| } |
| } |
| |
| func TestCreateTaskInvalidData(t *testing.T) { |
| tempDir, cleanup := setupTestDir(t) |
| defer cleanup() |
| |
| gtm, _ := createTestTaskManager(t, tempDir) |
| |
| ctx := context.Background() |
| |
| // Test empty title |
| req := &tm.TaskCreateRequest{ |
| Title: "", |
| OwnerID: "user123", |
| } |
| |
| task, err := gtm.CreateTask(ctx, req) |
| assert.Error(t, err) |
| assert.Nil(t, task) |
| assert.Equal(t, tm.ErrInvalidTaskData, err) |
| |
| // Test empty owner ID |
| req = &tm.TaskCreateRequest{ |
| Title: "Valid Title", |
| OwnerID: "", |
| } |
| |
| task, err = gtm.CreateTask(ctx, req) |
| assert.Error(t, err) |
| assert.Nil(t, task) |
| assert.Equal(t, tm.ErrInvalidOwner, err) |
| } |
| |
| func TestGetTask(t *testing.T) { |
| tempDir, cleanup := setupTestDir(t) |
| defer cleanup() |
| |
| gtm, _ := createTestTaskManager(t, tempDir) |
| |
| // Create a test task |
| task := &tm.Task{ |
| ID: "test-task-123", |
| Title: "Test Task", |
| Description: "Test task description", |
| Owner: tm.Owner{ |
| ID: "user123", |
| Name: "Test User", |
| }, |
| Status: tm.StatusToDo, |
| Priority: tm.PriorityMedium, |
| CreatedAt: time.Now(), |
| UpdatedAt: time.Now(), |
| } |
| |
| err := gtm.ensureTasksDir() |
| require.NoError(t, err) |
| err = gtm.writeTaskFile(task) |
| require.NoError(t, err) |
| |
| // Get the task |
| ctx := context.Background() |
| retrievedTask, err := gtm.GetTask(ctx, task.ID) |
| assert.NoError(t, err) |
| assert.NotNil(t, retrievedTask) |
| assert.Equal(t, task.ID, retrievedTask.ID) |
| assert.Equal(t, task.Title, retrievedTask.Title) |
| } |
| |
| func TestGetTaskNotFound(t *testing.T) { |
| tempDir, cleanup := setupTestDir(t) |
| defer cleanup() |
| |
| gtm, _ := createTestTaskManager(t, tempDir) |
| |
| ctx := context.Background() |
| task, err := gtm.GetTask(ctx, "non-existent-task") |
| assert.Error(t, err) |
| assert.Nil(t, task) |
| assert.Equal(t, tm.ErrTaskNotFound, err) |
| } |
| |
| func TestUpdateTask(t *testing.T) { |
| tempDir, cleanup := setupTestDir(t) |
| defer cleanup() |
| |
| gtm, gitImpl := createTestTaskManager(t, tempDir) |
| |
| // Create a test task |
| originalTask := &tm.Task{ |
| ID: "test-task-123", |
| Title: "Original Title", |
| Description: "Original description", |
| Owner: tm.Owner{ |
| ID: "user123", |
| Name: "Original User", |
| }, |
| Status: tm.StatusToDo, |
| Priority: tm.PriorityLow, |
| CreatedAt: time.Now().Add(-time.Hour), |
| UpdatedAt: time.Now().Add(-time.Hour), |
| } |
| |
| err := gtm.ensureTasksDir() |
| require.NoError(t, err) |
| err = gtm.writeTaskFile(originalTask) |
| require.NoError(t, err) |
| |
| // Commit the initial task |
| err = gtm.commitTaskChange(originalTask.ID, "created") |
| require.NoError(t, err) |
| |
| // Update the task |
| ctx := context.Background() |
| newTitle := "Updated Title" |
| newDescription := "Updated description" |
| newStatus := tm.StatusInProgress |
| newPriority := tm.PriorityHigh |
| newOwnerID := "user456" |
| |
| req := &tm.TaskUpdateRequest{ |
| Title: &newTitle, |
| Description: &newDescription, |
| Status: &newStatus, |
| Priority: &newPriority, |
| OwnerID: &newOwnerID, |
| } |
| |
| updatedTask, err := gtm.UpdateTask(ctx, originalTask.ID, req) |
| assert.NoError(t, err) |
| assert.NotNil(t, updatedTask) |
| |
| // Verify updated properties |
| assert.Equal(t, newTitle, updatedTask.Title) |
| assert.Equal(t, newDescription, updatedTask.Description) |
| assert.Equal(t, newStatus, updatedTask.Status) |
| assert.Equal(t, newPriority, updatedTask.Priority) |
| assert.Equal(t, newOwnerID, updatedTask.Owner.ID) |
| assert.Equal(t, newOwnerID, updatedTask.Owner.Name) |
| |
| // Verify timestamps were updated |
| assert.True(t, updatedTask.UpdatedAt.After(originalTask.UpdatedAt)) |
| |
| // Verify git commit was created |
| commits, err := gitImpl.Log(ctx, git.LogOptions{MaxCount: 2}) |
| assert.NoError(t, err) |
| if len(commits) > 0 { |
| assert.Contains(t, commits[0].Message, "updated") |
| } |
| } |
| |
| func TestUpdateTaskNotFound(t *testing.T) { |
| tempDir, cleanup := setupTestDir(t) |
| defer cleanup() |
| |
| gtm, _ := createTestTaskManager(t, tempDir) |
| |
| ctx := context.Background() |
| newTitle := "Updated Title" |
| req := &tm.TaskUpdateRequest{ |
| Title: &newTitle, |
| } |
| |
| task, err := gtm.UpdateTask(ctx, "non-existent-task", req) |
| assert.Error(t, err) |
| assert.Nil(t, task) |
| assert.Equal(t, tm.ErrTaskNotFound, err) |
| } |
| |
| func TestUpdateTaskNoChanges(t *testing.T) { |
| tempDir, cleanup := setupTestDir(t) |
| defer cleanup() |
| |
| gtm, _ := createTestTaskManager(t, tempDir) |
| |
| // Create a test task |
| originalTask := &tm.Task{ |
| ID: "test-task-123", |
| Title: "Test Task", |
| Description: "Test description", |
| Owner: tm.Owner{ |
| ID: "user123", |
| Name: "Test User", |
| }, |
| Status: tm.StatusToDo, |
| Priority: tm.PriorityMedium, |
| CreatedAt: time.Now().Add(-time.Hour), |
| UpdatedAt: time.Now().Add(-time.Hour), |
| } |
| |
| err := gtm.ensureTasksDir() |
| require.NoError(t, err) |
| err = gtm.writeTaskFile(originalTask) |
| require.NoError(t, err) |
| |
| // Update with no changes |
| ctx := context.Background() |
| req := &tm.TaskUpdateRequest{} |
| |
| updatedTask, err := gtm.UpdateTask(ctx, originalTask.ID, req) |
| assert.NoError(t, err) |
| assert.NotNil(t, updatedTask) |
| |
| // Verify no changes were made |
| assert.Equal(t, originalTask.Title, updatedTask.Title) |
| assert.Equal(t, originalTask.Description, updatedTask.Description) |
| assert.Equal(t, originalTask.Status, updatedTask.Status) |
| assert.Equal(t, originalTask.Priority, updatedTask.Priority) |
| assert.Equal(t, originalTask.Owner.ID, updatedTask.Owner.ID) |
| } |
| |
| func TestUpdateTaskStatusTimestamps(t *testing.T) { |
| tempDir, cleanup := setupTestDir(t) |
| defer cleanup() |
| |
| gtm, _ := createTestTaskManager(t, tempDir) |
| |
| // Create a test task |
| task := &tm.Task{ |
| ID: "test-task-123", |
| Title: "Test Task", |
| Description: "Test description", |
| Owner: tm.Owner{ |
| ID: "user123", |
| Name: "Test User", |
| }, |
| Status: tm.StatusToDo, |
| Priority: tm.PriorityMedium, |
| CreatedAt: time.Now().Add(-time.Hour), |
| UpdatedAt: time.Now().Add(-time.Hour), |
| } |
| |
| err := gtm.ensureTasksDir() |
| require.NoError(t, err) |
| err = gtm.writeTaskFile(task) |
| require.NoError(t, err) |
| |
| ctx := context.Background() |
| |
| // Test completing a task |
| completedStatus := tm.StatusCompleted |
| req := &tm.TaskUpdateRequest{ |
| Status: &completedStatus, |
| } |
| |
| updatedTask, err := gtm.UpdateTask(ctx, task.ID, req) |
| assert.NoError(t, err) |
| assert.NotNil(t, updatedTask) |
| assert.Equal(t, tm.StatusCompleted, updatedTask.Status) |
| assert.NotNil(t, updatedTask.CompletedAt) |
| |
| // Test archiving a task |
| archivedStatus := tm.StatusArchived |
| req = &tm.TaskUpdateRequest{ |
| Status: &archivedStatus, |
| } |
| |
| updatedTask, err = gtm.UpdateTask(ctx, task.ID, req) |
| assert.NoError(t, err) |
| assert.NotNil(t, updatedTask) |
| assert.Equal(t, tm.StatusArchived, updatedTask.Status) |
| assert.NotNil(t, updatedTask.ArchivedAt) |
| } |
| |
| func TestArchiveTask(t *testing.T) { |
| tempDir, cleanup := setupTestDir(t) |
| defer cleanup() |
| |
| gtm, _ := createTestTaskManager(t, tempDir) |
| |
| // Create a test task |
| task := &tm.Task{ |
| ID: "test-task-123", |
| Title: "Test Task", |
| Description: "Test description", |
| Owner: tm.Owner{ |
| ID: "user123", |
| Name: "Test User", |
| }, |
| Status: tm.StatusToDo, |
| Priority: tm.PriorityMedium, |
| CreatedAt: time.Now().Add(-time.Hour), |
| UpdatedAt: time.Now().Add(-time.Hour), |
| } |
| |
| err := gtm.ensureTasksDir() |
| require.NoError(t, err) |
| err = gtm.writeTaskFile(task) |
| require.NoError(t, err) |
| |
| // Archive the task |
| ctx := context.Background() |
| err = gtm.ArchiveTask(ctx, task.ID) |
| assert.NoError(t, err) |
| |
| // Verify task was archived |
| archivedTask, err := gtm.GetTask(ctx, task.ID) |
| assert.NoError(t, err) |
| assert.Equal(t, tm.StatusArchived, archivedTask.Status) |
| assert.NotNil(t, archivedTask.ArchivedAt) |
| } |
| |
| func TestStartTask(t *testing.T) { |
| tempDir, cleanup := setupTestDir(t) |
| defer cleanup() |
| |
| gtm, _ := createTestTaskManager(t, tempDir) |
| |
| // Create a test task |
| task := &tm.Task{ |
| ID: "test-task-123", |
| Title: "Test Task", |
| Description: "Test description", |
| Owner: tm.Owner{ |
| ID: "user123", |
| Name: "Test User", |
| }, |
| Status: tm.StatusToDo, |
| Priority: tm.PriorityMedium, |
| CreatedAt: time.Now().Add(-time.Hour), |
| UpdatedAt: time.Now().Add(-time.Hour), |
| } |
| |
| err := gtm.ensureTasksDir() |
| require.NoError(t, err) |
| err = gtm.writeTaskFile(task) |
| require.NoError(t, err) |
| |
| // Start the task |
| ctx := context.Background() |
| startedTask, err := gtm.StartTask(ctx, task.ID) |
| assert.NoError(t, err) |
| assert.NotNil(t, startedTask) |
| assert.Equal(t, tm.StatusInProgress, startedTask.Status) |
| } |
| |
| func TestCompleteTask(t *testing.T) { |
| tempDir, cleanup := setupTestDir(t) |
| defer cleanup() |
| |
| gtm, _ := createTestTaskManager(t, tempDir) |
| |
| // Create a test task |
| task := &tm.Task{ |
| ID: "test-task-123", |
| Title: "Test Task", |
| Description: "Test description", |
| Owner: tm.Owner{ |
| ID: "user123", |
| Name: "Test User", |
| }, |
| Status: tm.StatusInProgress, |
| Priority: tm.PriorityMedium, |
| CreatedAt: time.Now().Add(-time.Hour), |
| UpdatedAt: time.Now().Add(-time.Hour), |
| } |
| |
| err := gtm.ensureTasksDir() |
| require.NoError(t, err) |
| err = gtm.writeTaskFile(task) |
| require.NoError(t, err) |
| |
| // Complete the task |
| ctx := context.Background() |
| completedTask, err := gtm.CompleteTask(ctx, task.ID) |
| assert.NoError(t, err) |
| assert.NotNil(t, completedTask) |
| assert.Equal(t, tm.StatusCompleted, completedTask.Status) |
| assert.NotNil(t, completedTask.CompletedAt) |
| } |
| |
| func TestListTasks(t *testing.T) { |
| tempDir, cleanup := setupTestDir(t) |
| defer cleanup() |
| |
| gtm, _ := createTestTaskManager(t, tempDir) |
| |
| // Create test tasks |
| tasks := []*tm.Task{ |
| { |
| ID: "task-1", |
| Title: "Task 1", |
| Description: "First task", |
| Owner: tm.Owner{ID: "user1", Name: "User 1"}, |
| Status: tm.StatusToDo, |
| Priority: tm.PriorityHigh, |
| CreatedAt: time.Now().Add(-2 * time.Hour), |
| UpdatedAt: time.Now().Add(-2 * time.Hour), |
| }, |
| { |
| ID: "task-2", |
| Title: "Task 2", |
| Description: "Second task", |
| Owner: tm.Owner{ID: "user2", Name: "User 2"}, |
| Status: tm.StatusInProgress, |
| Priority: tm.PriorityMedium, |
| CreatedAt: time.Now().Add(-1 * time.Hour), |
| UpdatedAt: time.Now().Add(-1 * time.Hour), |
| }, |
| { |
| ID: "task-3", |
| Title: "Task 3", |
| Description: "Third task", |
| Owner: tm.Owner{ID: "user1", Name: "User 1"}, |
| Status: tm.StatusCompleted, |
| Priority: tm.PriorityLow, |
| CreatedAt: time.Now(), |
| UpdatedAt: time.Now(), |
| }, |
| } |
| |
| err := gtm.ensureTasksDir() |
| require.NoError(t, err) |
| |
| for _, task := range tasks { |
| err = gtm.writeTaskFile(task) |
| require.NoError(t, err) |
| } |
| |
| ctx := context.Background() |
| |
| // Test listing all tasks |
| taskList, err := gtm.ListTasks(ctx, nil, 0, 10) |
| assert.NoError(t, err) |
| assert.NotNil(t, taskList) |
| assert.Len(t, taskList.Tasks, 3) |
| assert.Equal(t, 3, taskList.TotalCount) |
| assert.Equal(t, 0, taskList.Page) |
| assert.Equal(t, 10, taskList.PageSize) |
| assert.False(t, taskList.HasMore) |
| |
| // Test pagination |
| taskList, err = gtm.ListTasks(ctx, nil, 0, 2) |
| assert.NoError(t, err) |
| assert.Len(t, taskList.Tasks, 2) |
| assert.Equal(t, 3, taskList.TotalCount) |
| assert.True(t, taskList.HasMore) |
| |
| // Test filtering by owner |
| ownerFilter := &tm.TaskFilter{OwnerID: stringPtr("user1")} |
| taskList, err = gtm.ListTasks(ctx, ownerFilter, 0, 10) |
| assert.NoError(t, err) |
| assert.Len(t, taskList.Tasks, 2) |
| |
| // Test filtering by status |
| statusFilter := &tm.TaskFilter{Status: taskStatusPtr(tm.StatusToDo)} |
| taskList, err = gtm.ListTasks(ctx, statusFilter, 0, 10) |
| assert.NoError(t, err) |
| assert.Len(t, taskList.Tasks, 1) |
| assert.Equal(t, "task-1", taskList.Tasks[0].ID) |
| |
| // Test filtering by priority |
| priorityFilter := &tm.TaskFilter{Priority: taskPriorityPtr(tm.PriorityHigh)} |
| taskList, err = gtm.ListTasks(ctx, priorityFilter, 0, 10) |
| assert.NoError(t, err) |
| assert.Len(t, taskList.Tasks, 1) |
| assert.Equal(t, "task-1", taskList.Tasks[0].ID) |
| } |
| |
| func TestGetTasksByOwner(t *testing.T) { |
| tempDir, cleanup := setupTestDir(t) |
| defer cleanup() |
| |
| gtm, _ := createTestTaskManager(t, tempDir) |
| |
| // Create test tasks |
| tasks := []*tm.Task{ |
| { |
| ID: "task-1", |
| Title: "Task 1", |
| Owner: tm.Owner{ID: "user1", Name: "User 1"}, |
| Status: tm.StatusToDo, |
| Priority: tm.PriorityHigh, |
| CreatedAt: time.Now().Add(-2 * time.Hour), |
| UpdatedAt: time.Now().Add(-2 * time.Hour), |
| }, |
| { |
| ID: "task-2", |
| Title: "Task 2", |
| Owner: tm.Owner{ID: "user2", Name: "User 2"}, |
| Status: tm.StatusInProgress, |
| Priority: tm.PriorityMedium, |
| CreatedAt: time.Now().Add(-1 * time.Hour), |
| UpdatedAt: time.Now().Add(-1 * time.Hour), |
| }, |
| { |
| ID: "task-3", |
| Title: "Task 3", |
| Owner: tm.Owner{ID: "user1", Name: "User 1"}, |
| Status: tm.StatusCompleted, |
| Priority: tm.PriorityLow, |
| CreatedAt: time.Now(), |
| UpdatedAt: time.Now(), |
| }, |
| } |
| |
| err := gtm.ensureTasksDir() |
| require.NoError(t, err) |
| |
| for _, task := range tasks { |
| err = gtm.writeTaskFile(task) |
| require.NoError(t, err) |
| } |
| |
| ctx := context.Background() |
| |
| // Get tasks by owner |
| taskList, err := gtm.GetTasksByOwner(ctx, "user1", 0, 10) |
| assert.NoError(t, err) |
| assert.NotNil(t, taskList) |
| assert.Len(t, taskList.Tasks, 2) |
| |
| for _, task := range taskList.Tasks { |
| assert.Equal(t, "user1", task.Owner.ID) |
| } |
| } |
| |
| func TestGetTasksByStatus(t *testing.T) { |
| tempDir, cleanup := setupTestDir(t) |
| defer cleanup() |
| |
| gtm, _ := createTestTaskManager(t, tempDir) |
| |
| // Create test tasks |
| tasks := []*tm.Task{ |
| { |
| ID: "task-1", |
| Title: "Task 1", |
| Owner: tm.Owner{ID: "user1", Name: "User 1"}, |
| Status: tm.StatusToDo, |
| Priority: tm.PriorityHigh, |
| CreatedAt: time.Now().Add(-2 * time.Hour), |
| UpdatedAt: time.Now().Add(-2 * time.Hour), |
| }, |
| { |
| ID: "task-2", |
| Title: "Task 2", |
| Owner: tm.Owner{ID: "user2", Name: "User 2"}, |
| Status: tm.StatusInProgress, |
| Priority: tm.PriorityMedium, |
| CreatedAt: time.Now().Add(-1 * time.Hour), |
| UpdatedAt: time.Now().Add(-1 * time.Hour), |
| }, |
| { |
| ID: "task-3", |
| Title: "Task 3", |
| Owner: tm.Owner{ID: "user1", Name: "User 1"}, |
| Status: tm.StatusCompleted, |
| Priority: tm.PriorityLow, |
| CreatedAt: time.Now(), |
| UpdatedAt: time.Now(), |
| }, |
| } |
| |
| err := gtm.ensureTasksDir() |
| require.NoError(t, err) |
| |
| for _, task := range tasks { |
| err = gtm.writeTaskFile(task) |
| require.NoError(t, err) |
| } |
| |
| ctx := context.Background() |
| |
| // Get tasks by status |
| taskList, err := gtm.GetTasksByStatus(ctx, tm.StatusToDo, 0, 10) |
| assert.NoError(t, err) |
| assert.NotNil(t, taskList) |
| assert.Len(t, taskList.Tasks, 1) |
| assert.Equal(t, tm.StatusToDo, taskList.Tasks[0].Status) |
| } |
| |
| func TestGetTasksByPriority(t *testing.T) { |
| tempDir, cleanup := setupTestDir(t) |
| defer cleanup() |
| |
| gtm, _ := createTestTaskManager(t, tempDir) |
| |
| // Create test tasks |
| tasks := []*tm.Task{ |
| { |
| ID: "task-1", |
| Title: "Task 1", |
| Owner: tm.Owner{ID: "user1", Name: "User 1"}, |
| Status: tm.StatusToDo, |
| Priority: tm.PriorityHigh, |
| CreatedAt: time.Now().Add(-2 * time.Hour), |
| UpdatedAt: time.Now().Add(-2 * time.Hour), |
| }, |
| { |
| ID: "task-2", |
| Title: "Task 2", |
| Owner: tm.Owner{ID: "user2", Name: "User 2"}, |
| Status: tm.StatusInProgress, |
| Priority: tm.PriorityMedium, |
| CreatedAt: time.Now().Add(-1 * time.Hour), |
| UpdatedAt: time.Now().Add(-1 * time.Hour), |
| }, |
| { |
| ID: "task-3", |
| Title: "Task 3", |
| Owner: tm.Owner{ID: "user1", Name: "User 1"}, |
| Status: tm.StatusCompleted, |
| Priority: tm.PriorityLow, |
| CreatedAt: time.Now(), |
| UpdatedAt: time.Now(), |
| }, |
| } |
| |
| err := gtm.ensureTasksDir() |
| require.NoError(t, err) |
| |
| for _, task := range tasks { |
| err = gtm.writeTaskFile(task) |
| require.NoError(t, err) |
| } |
| |
| ctx := context.Background() |
| |
| // Get tasks by priority |
| taskList, err := gtm.GetTasksByPriority(ctx, tm.PriorityHigh, 0, 10) |
| assert.NoError(t, err) |
| assert.NotNil(t, taskList) |
| assert.Len(t, taskList.Tasks, 1) |
| assert.Equal(t, tm.PriorityHigh, taskList.Tasks[0].Priority) |
| } |
| |
| // Helper functions for creating pointers to string, TaskStatus, and TaskPriority |
| func stringPtr(s string) *string { |
| return &s |
| } |
| |
| func taskStatusPtr(status tm.TaskStatus) *tm.TaskStatus { |
| return &status |
| } |
| |
| func taskPriorityPtr(priority tm.TaskPriority) *tm.TaskPriority { |
| return &priority |
| } |