diff options
author | T <t@tjp.lol> | 2025-09-29 15:04:44 -0600 |
---|---|---|
committer | T <t@tjp.lol> | 2025-09-30 11:40:45 -0600 |
commit | 7ba68d333bc20b5795ccfd3870546a05eee60470 (patch) | |
tree | 12dc4b017803b7d01844fd42b9e3be281cbbd986 /internal/actions/archive_test.go | |
parent | bce8dbb58165e443902d9dae3909225ef42630c4 (diff) |
Diffstat (limited to 'internal/actions/archive_test.go')
-rw-r--r-- | internal/actions/archive_test.go | 618 |
1 files changed, 618 insertions, 0 deletions
diff --git a/internal/actions/archive_test.go b/internal/actions/archive_test.go new file mode 100644 index 0000000..d205703 --- /dev/null +++ b/internal/actions/archive_test.go @@ -0,0 +1,618 @@ +package actions + +import ( + "context" + "database/sql" + "fmt" + "testing" + + "git.tjp.lol/punchcard/internal/database" + "git.tjp.lol/punchcard/internal/queries" +) + +func setupTestDB(t *testing.T) (*queries.Queries, func()) { + db, err := sql.Open("sqlite", ":memory:") + if err != nil { + t.Fatalf("Failed to open in-memory sqlite db: %v", err) + } + if err := database.InitializeDB(db); err != nil { + t.Fatalf("Failed to initialize in-memory sqlite db: %v", err) + } + q := queries.New(db) + + cleanup := func() { + if err := q.DBTX().(*sql.DB).Close(); err != nil { + t.Logf("error closing database: %v", err) + } + } + + return q, cleanup +} + +func TestArchiveClient(t *testing.T) { + tests := []struct { + name string + setupData func(*queries.Queries) int64 + expectError bool + }{ + { + name: "archive existing client", + setupData: func(q *queries.Queries) int64 { + client, _ := q.CreateClient(context.Background(), queries.CreateClientParams{ + Name: "TestClient", + }) + return client.ID + }, + expectError: false, + }, + { + name: "archive already archived client", + setupData: func(q *queries.Queries) int64 { + client, _ := q.CreateClient(context.Background(), queries.CreateClientParams{ + Name: "AlreadyArchived", + }) + _ = q.ArchiveClient(context.Background(), client.ID) + return client.ID + }, + expectError: false, + }, + } + + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + q, cleanup := setupTestDB(t) + defer cleanup() + + a := New(q) + clientID := tt.setupData(q) + + err := a.ArchiveClient(context.Background(), clientID) + + if tt.expectError && err == nil { + t.Errorf("Expected error but got none") + } + if !tt.expectError && err != nil { + t.Errorf("Unexpected error: %v", err) + } + + if !tt.expectError { + client, err := a.FindClient(context.Background(), fmt.Sprintf("%d", clientID)) + if err != nil { + t.Fatalf("Failed to find client: %v", err) + } + if client.Archived == 0 { + t.Errorf("Expected client to be archived") + } + } + }) + } +} + +func TestUnarchiveClient(t *testing.T) { + tests := []struct { + name string + setupData func(*queries.Queries) int64 + expectError bool + }{ + { + name: "unarchive archived client", + setupData: func(q *queries.Queries) int64 { + client, _ := q.CreateClient(context.Background(), queries.CreateClientParams{ + Name: "ArchivedClient", + }) + _ = q.ArchiveClient(context.Background(), client.ID) + return client.ID + }, + expectError: false, + }, + { + name: "unarchive already active client", + setupData: func(q *queries.Queries) int64 { + client, _ := q.CreateClient(context.Background(), queries.CreateClientParams{ + Name: "ActiveClient", + }) + return client.ID + }, + expectError: false, + }, + } + + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + q, cleanup := setupTestDB(t) + defer cleanup() + + a := New(q) + clientID := tt.setupData(q) + + err := a.UnarchiveClient(context.Background(), clientID) + + if tt.expectError && err == nil { + t.Errorf("Expected error but got none") + } + if !tt.expectError && err != nil { + t.Errorf("Unexpected error: %v", err) + } + + if !tt.expectError { + client, err := a.FindClient(context.Background(), fmt.Sprintf("%d", clientID)) + if err != nil { + t.Fatalf("Failed to find client: %v", err) + } + if client.Archived != 0 { + t.Errorf("Expected client to not be archived") + } + } + }) + } +} + +func TestArchiveProject(t *testing.T) { + tests := []struct { + name string + setupData func(*queries.Queries) int64 + expectError bool + }{ + { + name: "archive existing project", + setupData: func(q *queries.Queries) int64 { + client, _ := q.CreateClient(context.Background(), queries.CreateClientParams{ + Name: "TestClient", + }) + project, _ := q.CreateProject(context.Background(), queries.CreateProjectParams{ + Name: "TestProject", + ClientID: client.ID, + }) + return project.ID + }, + expectError: false, + }, + { + name: "archive already archived project", + setupData: func(q *queries.Queries) int64 { + client, _ := q.CreateClient(context.Background(), queries.CreateClientParams{ + Name: "TestClient", + }) + project, _ := q.CreateProject(context.Background(), queries.CreateProjectParams{ + Name: "AlreadyArchived", + ClientID: client.ID, + }) + _ = q.ArchiveProject(context.Background(), project.ID) + return project.ID + }, + expectError: false, + }, + } + + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + q, cleanup := setupTestDB(t) + defer cleanup() + + a := New(q) + projectID := tt.setupData(q) + + err := a.ArchiveProject(context.Background(), projectID) + + if tt.expectError && err == nil { + t.Errorf("Expected error but got none") + } + if !tt.expectError && err != nil { + t.Errorf("Unexpected error: %v", err) + } + + if !tt.expectError { + project, err := a.FindProject(context.Background(), fmt.Sprintf("%d", projectID)) + if err != nil { + t.Fatalf("Failed to find project: %v", err) + } + if project.Archived == 0 { + t.Errorf("Expected project to be archived") + } + } + }) + } +} + +func TestUnarchiveProject(t *testing.T) { + tests := []struct { + name string + setupData func(*queries.Queries) int64 + expectError bool + }{ + { + name: "unarchive archived project", + setupData: func(q *queries.Queries) int64 { + client, _ := q.CreateClient(context.Background(), queries.CreateClientParams{ + Name: "TestClient", + }) + project, _ := q.CreateProject(context.Background(), queries.CreateProjectParams{ + Name: "ArchivedProject", + ClientID: client.ID, + }) + _ = q.ArchiveProject(context.Background(), project.ID) + return project.ID + }, + expectError: false, + }, + { + name: "unarchive already active project", + setupData: func(q *queries.Queries) int64 { + client, _ := q.CreateClient(context.Background(), queries.CreateClientParams{ + Name: "TestClient", + }) + project, _ := q.CreateProject(context.Background(), queries.CreateProjectParams{ + Name: "ActiveProject", + ClientID: client.ID, + }) + return project.ID + }, + expectError: false, + }, + } + + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + q, cleanup := setupTestDB(t) + defer cleanup() + + a := New(q) + projectID := tt.setupData(q) + + err := a.UnarchiveProject(context.Background(), projectID) + + if tt.expectError && err == nil { + t.Errorf("Expected error but got none") + } + if !tt.expectError && err != nil { + t.Errorf("Unexpected error: %v", err) + } + + if !tt.expectError { + project, err := a.FindProject(context.Background(), fmt.Sprintf("%d", projectID)) + if err != nil { + t.Fatalf("Failed to find project: %v", err) + } + if project.Archived != 0 { + t.Errorf("Expected project to not be archived") + } + } + }) + } +} + +func TestPunchInWithArchivedClient(t *testing.T) { + tests := []struct { + name string + setupData func(*queries.Queries) (clientName string) + autoUnarchive bool + expectError bool + errorType error + }{ + { + name: "punch in on archived client without auto-unarchive returns error", + setupData: func(q *queries.Queries) string { + client, _ := q.CreateClient(context.Background(), queries.CreateClientParams{ + Name: "ArchivedClient", + }) + _ = q.ArchiveClient(context.Background(), client.ID) + return client.Name + }, + autoUnarchive: false, + expectError: true, + errorType: ErrArchivedClient, + }, + { + name: "punch in on archived client with auto-unarchive succeeds", + setupData: func(q *queries.Queries) string { + client, _ := q.CreateClient(context.Background(), queries.CreateClientParams{ + Name: "ArchivedClient", + }) + _ = q.ArchiveClient(context.Background(), client.ID) + return client.Name + }, + autoUnarchive: true, + expectError: false, + }, + { + name: "punch in on active client succeeds", + setupData: func(q *queries.Queries) string { + client, _ := q.CreateClient(context.Background(), queries.CreateClientParams{ + Name: "ActiveClient", + }) + return client.Name + }, + autoUnarchive: false, + expectError: false, + }, + } + + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + q, cleanup := setupTestDB(t) + defer cleanup() + + a := New(q) + clientName := tt.setupData(q) + + session, err := a.PunchIn(context.Background(), clientName, "", "", nil, tt.autoUnarchive) + + if tt.expectError { + if err == nil { + t.Errorf("Expected error but got none") + } else if tt.errorType != nil && err != tt.errorType { + t.Errorf("Expected error %v, got %v", tt.errorType, err) + } + return + } + + if err != nil { + t.Errorf("Unexpected error: %v", err) + } + + if session == nil { + t.Fatalf("Expected session but got nil") + } + + if tt.autoUnarchive { + client, err := a.FindClient(context.Background(), clientName) + if err != nil { + t.Fatalf("Failed to find client: %v", err) + } + if client.Archived != 0 { + t.Errorf("Expected client to be unarchived after auto-unarchive") + } + } + }) + } +} + +func TestPunchInWithArchivedProject(t *testing.T) { + tests := []struct { + name string + setupData func(*queries.Queries) (projectName string) + autoUnarchive bool + expectError bool + errorType error + }{ + { + name: "punch in on archived project without auto-unarchive returns error", + setupData: func(q *queries.Queries) string { + client, _ := q.CreateClient(context.Background(), queries.CreateClientParams{ + Name: "TestClient", + }) + project, _ := q.CreateProject(context.Background(), queries.CreateProjectParams{ + Name: "ArchivedProject", + ClientID: client.ID, + }) + _ = q.ArchiveProject(context.Background(), project.ID) + return project.Name + }, + autoUnarchive: false, + expectError: true, + errorType: ErrArchivedProject, + }, + { + name: "punch in on archived project with auto-unarchive succeeds", + setupData: func(q *queries.Queries) string { + client, _ := q.CreateClient(context.Background(), queries.CreateClientParams{ + Name: "TestClient", + }) + project, _ := q.CreateProject(context.Background(), queries.CreateProjectParams{ + Name: "ArchivedProject", + ClientID: client.ID, + }) + _ = q.ArchiveProject(context.Background(), project.ID) + return project.Name + }, + autoUnarchive: true, + expectError: false, + }, + { + name: "punch in on active project succeeds", + setupData: func(q *queries.Queries) string { + client, _ := q.CreateClient(context.Background(), queries.CreateClientParams{ + Name: "TestClient", + }) + project, _ := q.CreateProject(context.Background(), queries.CreateProjectParams{ + Name: "ActiveProject", + ClientID: client.ID, + }) + return project.Name + }, + autoUnarchive: false, + expectError: false, + }, + } + + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + q, cleanup := setupTestDB(t) + defer cleanup() + + a := New(q) + projectName := tt.setupData(q) + + session, err := a.PunchIn(context.Background(), "", projectName, "", nil, tt.autoUnarchive) + + if tt.expectError { + if err == nil { + t.Errorf("Expected error but got none") + } else if tt.errorType != nil && err != tt.errorType { + t.Errorf("Expected error %v, got %v", tt.errorType, err) + } + return + } + + if err != nil { + t.Errorf("Unexpected error: %v", err) + } + + if session == nil { + t.Fatalf("Expected session but got nil") + } + + if tt.autoUnarchive { + project, err := a.FindProject(context.Background(), projectName) + if err != nil { + t.Fatalf("Failed to find project: %v", err) + } + if project.Archived != 0 { + t.Errorf("Expected project to be unarchived after auto-unarchive") + } + } + }) + } +} + +func TestPunchInMostRecentWithArchivedClient(t *testing.T) { + tests := []struct { + name string + setupData func(*queries.Queries) + autoUnarchive bool + expectError bool + errorType error + }{ + { + name: "punch in most recent with archived client without auto-unarchive returns error", + setupData: func(q *queries.Queries) { + client, _ := q.CreateClient(context.Background(), queries.CreateClientParams{ + Name: "ArchivedClient", + }) + _, _ = q.CreateTimeEntry(context.Background(), queries.CreateTimeEntryParams{ + ClientID: client.ID, + }) + _, _ = q.StopTimeEntry(context.Background()) + _ = q.ArchiveClient(context.Background(), client.ID) + }, + autoUnarchive: false, + expectError: true, + errorType: ErrArchivedClient, + }, + { + name: "punch in most recent with archived client with auto-unarchive succeeds", + setupData: func(q *queries.Queries) { + client, _ := q.CreateClient(context.Background(), queries.CreateClientParams{ + Name: "ArchivedClient", + }) + _, _ = q.CreateTimeEntry(context.Background(), queries.CreateTimeEntryParams{ + ClientID: client.ID, + }) + _, _ = q.StopTimeEntry(context.Background()) + _ = q.ArchiveClient(context.Background(), client.ID) + }, + autoUnarchive: true, + expectError: false, + }, + } + + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + q, cleanup := setupTestDB(t) + defer cleanup() + + a := New(q) + tt.setupData(q) + + session, err := a.PunchInMostRecent(context.Background(), "", nil, tt.autoUnarchive) + + if tt.expectError { + if err == nil { + t.Errorf("Expected error but got none") + } else if tt.errorType != nil && err != tt.errorType { + t.Errorf("Expected error %v, got %v", tt.errorType, err) + } + return + } + + if err != nil { + t.Errorf("Unexpected error: %v", err) + } + + if session == nil { + t.Fatalf("Expected session but got nil") + } + }) + } +} + +func TestPunchInMostRecentWithArchivedProject(t *testing.T) { + tests := []struct { + name string + setupData func(*queries.Queries) + autoUnarchive bool + expectError bool + errorType error + }{ + { + name: "punch in most recent with archived project without auto-unarchive returns error", + setupData: func(q *queries.Queries) { + client, _ := q.CreateClient(context.Background(), queries.CreateClientParams{ + Name: "TestClient", + }) + project, _ := q.CreateProject(context.Background(), queries.CreateProjectParams{ + Name: "ArchivedProject", + ClientID: client.ID, + }) + _, _ = q.CreateTimeEntry(context.Background(), queries.CreateTimeEntryParams{ + ClientID: client.ID, + ProjectID: sql.NullInt64{Int64: project.ID, Valid: true}, + }) + _, _ = q.StopTimeEntry(context.Background()) + _ = q.ArchiveProject(context.Background(), project.ID) + }, + autoUnarchive: false, + expectError: true, + errorType: ErrArchivedProject, + }, + { + name: "punch in most recent with archived project with auto-unarchive succeeds", + setupData: func(q *queries.Queries) { + client, _ := q.CreateClient(context.Background(), queries.CreateClientParams{ + Name: "TestClient", + }) + project, _ := q.CreateProject(context.Background(), queries.CreateProjectParams{ + Name: "ArchivedProject", + ClientID: client.ID, + }) + _, _ = q.CreateTimeEntry(context.Background(), queries.CreateTimeEntryParams{ + ClientID: client.ID, + ProjectID: sql.NullInt64{Int64: project.ID, Valid: true}, + }) + _, _ = q.StopTimeEntry(context.Background()) + _ = q.ArchiveProject(context.Background(), project.ID) + }, + autoUnarchive: true, + expectError: false, + }, + } + + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + q, cleanup := setupTestDB(t) + defer cleanup() + + a := New(q) + tt.setupData(q) + + session, err := a.PunchInMostRecent(context.Background(), "", nil, tt.autoUnarchive) + + if tt.expectError { + if err == nil { + t.Errorf("Expected error but got none") + } else if tt.errorType != nil && err != tt.errorType { + t.Errorf("Expected error %v, got %v", tt.errorType, err) + } + return + } + + if err != nil { + t.Errorf("Unexpected error: %v", err) + } + + if session == nil { + t.Fatalf("Expected session but got nil") + } + }) + } +} |