summaryrefslogtreecommitdiff
path: root/internal/commands/archive_test.go
diff options
context:
space:
mode:
authorT <t@tjp.lol>2025-09-29 15:04:44 -0600
committerT <t@tjp.lol>2025-09-30 11:40:45 -0600
commit7ba68d333bc20b5795ccfd3870546a05eee60470 (patch)
tree12dc4b017803b7d01844fd42b9e3be281cbbd986 /internal/commands/archive_test.go
parentbce8dbb58165e443902d9dae3909225ef42630c4 (diff)
Support for archiving clients and projects.HEADmain
Diffstat (limited to 'internal/commands/archive_test.go')
-rw-r--r--internal/commands/archive_test.go517
1 files changed, 517 insertions, 0 deletions
diff --git a/internal/commands/archive_test.go b/internal/commands/archive_test.go
new file mode 100644
index 0000000..ae9ce1f
--- /dev/null
+++ b/internal/commands/archive_test.go
@@ -0,0 +1,517 @@
+package commands
+
+import (
+ "context"
+ "strings"
+ "testing"
+
+ "git.tjp.lol/punchcard/internal/queries"
+)
+
+func TestArchiveCommand(t *testing.T) {
+ tests := []struct {
+ name string
+ setupData func(*queries.Queries) (clientID, projectID int64)
+ args []string
+ expectedOutputs []string
+ expectError bool
+ errorContains string
+ }{
+ {
+ name: "archive client by name",
+ setupData: func(q *queries.Queries) (int64, int64) {
+ client, _ := q.CreateClient(context.Background(), queries.CreateClientParams{
+ Name: "TestClient",
+ })
+ return client.ID, 0
+ },
+ args: []string{"archive", "--client", "TestClient"},
+ expectedOutputs: []string{"Archived client: TestClient"},
+ expectError: false,
+ },
+ {
+ name: "archive client by ID",
+ setupData: func(q *queries.Queries) (int64, int64) {
+ client, _ := q.CreateClient(context.Background(), queries.CreateClientParams{
+ Name: "ClientByID",
+ })
+ return client.ID, 0
+ },
+ args: []string{"archive", "--client", "1"},
+ expectedOutputs: []string{"Archived client: ClientByID"},
+ expectError: false,
+ },
+ {
+ name: "archive project by name",
+ setupData: func(q *queries.Queries) (int64, int64) {
+ client, _ := q.CreateClient(context.Background(), queries.CreateClientParams{
+ Name: "TestClient",
+ })
+ project, _ := q.CreateProject(context.Background(), queries.CreateProjectParams{
+ Name: "TestProject",
+ ClientID: client.ID,
+ })
+ return client.ID, project.ID
+ },
+ args: []string{"archive", "--project", "TestProject"},
+ expectedOutputs: []string{"Archived project: TestProject"},
+ expectError: false,
+ },
+ {
+ name: "archive project by ID",
+ setupData: func(q *queries.Queries) (int64, int64) {
+ client, _ := q.CreateClient(context.Background(), queries.CreateClientParams{
+ Name: "TestClient",
+ })
+ project, _ := q.CreateProject(context.Background(), queries.CreateProjectParams{
+ Name: "ProjectByID",
+ ClientID: client.ID,
+ })
+ return client.ID, project.ID
+ },
+ args: []string{"archive", "--project", "1"},
+ expectedOutputs: []string{"Archived project: ProjectByID"},
+ expectError: false,
+ },
+ {
+ name: "archive without flags returns error",
+ setupData: func(q *queries.Queries) (int64, int64) { return 0, 0 },
+ args: []string{"archive"},
+ expectError: true,
+ errorContains: "either --client or --project must be specified",
+ },
+ {
+ name: "archive with both client and project flags returns error",
+ setupData: func(q *queries.Queries) (int64, int64) {
+ client, _ := q.CreateClient(context.Background(), queries.CreateClientParams{
+ Name: "TestClient",
+ })
+ project, _ := q.CreateProject(context.Background(), queries.CreateProjectParams{
+ Name: "TestProject",
+ ClientID: client.ID,
+ })
+ return client.ID, project.ID
+ },
+ args: []string{"archive", "--client", "TestClient", "--project", "TestProject"},
+ expectError: true,
+ errorContains: "cannot specify both --client and --project",
+ },
+ {
+ name: "archive nonexistent client returns error",
+ setupData: func(q *queries.Queries) (int64, int64) { return 0, 0 },
+ args: []string{"archive", "--client", "NonexistentClient"},
+ expectError: true,
+ errorContains: "failed to find client",
+ },
+ {
+ name: "archive nonexistent project returns error",
+ setupData: func(q *queries.Queries) (int64, int64) { return 0, 0 },
+ args: []string{"archive", "--project", "NonexistentProject"},
+ expectError: true,
+ errorContains: "failed to find project",
+ },
+ {
+ name: "archive already archived client succeeds",
+ setupData: func(q *queries.Queries) (int64, int64) {
+ client, _ := q.CreateClient(context.Background(), queries.CreateClientParams{
+ Name: "AlreadyArchived",
+ })
+ _ = q.ArchiveClient(context.Background(), client.ID)
+ return client.ID, 0
+ },
+ args: []string{"archive", "--client", "AlreadyArchived"},
+ expectedOutputs: []string{"Archived client: AlreadyArchived"},
+ expectError: false,
+ },
+ {
+ name: "archive client using short flag",
+ setupData: func(q *queries.Queries) (int64, int64) {
+ client, _ := q.CreateClient(context.Background(), queries.CreateClientParams{
+ Name: "ShortFlagClient",
+ })
+ return client.ID, 0
+ },
+ args: []string{"archive", "-c", "ShortFlagClient"},
+ expectedOutputs: []string{"Archived client: ShortFlagClient"},
+ expectError: false,
+ },
+ {
+ name: "archive project using short flag",
+ setupData: func(q *queries.Queries) (int64, int64) {
+ client, _ := q.CreateClient(context.Background(), queries.CreateClientParams{
+ Name: "TestClient",
+ })
+ project, _ := q.CreateProject(context.Background(), queries.CreateProjectParams{
+ Name: "ShortFlagProject",
+ ClientID: client.ID,
+ })
+ return client.ID, project.ID
+ },
+ args: []string{"archive", "-p", "ShortFlagProject"},
+ expectedOutputs: []string{"Archived project: ShortFlagProject"},
+ expectError: false,
+ },
+ }
+
+ for _, tt := range tests {
+ t.Run(tt.name, func(t *testing.T) {
+ q, cleanup := setupTestDB(t)
+ defer cleanup()
+
+ tt.setupData(q)
+
+ output, err := executeCommandWithDB(t, q, tt.args...)
+
+ if tt.expectError {
+ if err == nil {
+ t.Errorf("Expected error but got none")
+ } else if tt.errorContains != "" && !strings.Contains(err.Error(), tt.errorContains) {
+ t.Errorf("Expected error to contain %q, got %q", tt.errorContains, err.Error())
+ }
+ return
+ }
+
+ if err != nil {
+ t.Errorf("Unexpected error: %v", err)
+ return
+ }
+
+ found := false
+ for _, expectedOutput := range tt.expectedOutputs {
+ if strings.Contains(output, expectedOutput) {
+ found = true
+ break
+ }
+ }
+
+ if !found {
+ t.Errorf("Expected output to contain one of %v, got %q", tt.expectedOutputs, output)
+ }
+ })
+ }
+}
+
+func TestUnarchiveCommand(t *testing.T) {
+ tests := []struct {
+ name string
+ setupData func(*queries.Queries) (clientID, projectID int64)
+ args []string
+ expectedOutputs []string
+ expectError bool
+ errorContains string
+ }{
+ {
+ name: "unarchive client by name",
+ setupData: func(q *queries.Queries) (int64, int64) {
+ client, _ := q.CreateClient(context.Background(), queries.CreateClientParams{
+ Name: "ArchivedClient",
+ })
+ _ = q.ArchiveClient(context.Background(), client.ID)
+ return client.ID, 0
+ },
+ args: []string{"unarchive", "--client", "ArchivedClient"},
+ expectedOutputs: []string{"Unarchived client: ArchivedClient"},
+ expectError: false,
+ },
+ {
+ name: "unarchive client by ID",
+ setupData: func(q *queries.Queries) (int64, int64) {
+ client, _ := q.CreateClient(context.Background(), queries.CreateClientParams{
+ Name: "ClientByID",
+ })
+ _ = q.ArchiveClient(context.Background(), client.ID)
+ return client.ID, 0
+ },
+ args: []string{"unarchive", "--client", "1"},
+ expectedOutputs: []string{"Unarchived client: ClientByID"},
+ expectError: false,
+ },
+ {
+ name: "unarchive project by name",
+ setupData: func(q *queries.Queries) (int64, 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 client.ID, project.ID
+ },
+ args: []string{"unarchive", "--project", "ArchivedProject"},
+ expectedOutputs: []string{"Unarchived project: ArchivedProject"},
+ expectError: false,
+ },
+ {
+ name: "unarchive project by ID",
+ setupData: func(q *queries.Queries) (int64, int64) {
+ client, _ := q.CreateClient(context.Background(), queries.CreateClientParams{
+ Name: "TestClient",
+ })
+ project, _ := q.CreateProject(context.Background(), queries.CreateProjectParams{
+ Name: "ProjectByID",
+ ClientID: client.ID,
+ })
+ _ = q.ArchiveProject(context.Background(), project.ID)
+ return client.ID, project.ID
+ },
+ args: []string{"unarchive", "--project", "1"},
+ expectedOutputs: []string{"Unarchived project: ProjectByID"},
+ expectError: false,
+ },
+ {
+ name: "unarchive without flags returns error",
+ setupData: func(q *queries.Queries) (int64, int64) { return 0, 0 },
+ args: []string{"unarchive"},
+ expectError: true,
+ errorContains: "either --client or --project must be specified",
+ },
+ {
+ name: "unarchive with both client and project flags returns error",
+ setupData: func(q *queries.Queries) (int64, int64) {
+ client, _ := q.CreateClient(context.Background(), queries.CreateClientParams{
+ Name: "TestClient",
+ })
+ project, _ := q.CreateProject(context.Background(), queries.CreateProjectParams{
+ Name: "TestProject",
+ ClientID: client.ID,
+ })
+ _ = q.ArchiveClient(context.Background(), client.ID)
+ _ = q.ArchiveProject(context.Background(), project.ID)
+ return client.ID, project.ID
+ },
+ args: []string{"unarchive", "--client", "TestClient", "--project", "TestProject"},
+ expectError: true,
+ errorContains: "cannot specify both --client and --project",
+ },
+ {
+ name: "unarchive nonexistent client returns error",
+ setupData: func(q *queries.Queries) (int64, int64) { return 0, 0 },
+ args: []string{"unarchive", "--client", "NonexistentClient"},
+ expectError: true,
+ errorContains: "failed to find client",
+ },
+ {
+ name: "unarchive nonexistent project returns error",
+ setupData: func(q *queries.Queries) (int64, int64) { return 0, 0 },
+ args: []string{"unarchive", "--project", "NonexistentProject"},
+ expectError: true,
+ errorContains: "failed to find project",
+ },
+ {
+ name: "unarchive already active client succeeds",
+ setupData: func(q *queries.Queries) (int64, int64) {
+ client, _ := q.CreateClient(context.Background(), queries.CreateClientParams{
+ Name: "ActiveClient",
+ })
+ return client.ID, 0
+ },
+ args: []string{"unarchive", "--client", "ActiveClient"},
+ expectedOutputs: []string{"Unarchived client: ActiveClient"},
+ expectError: false,
+ },
+ {
+ name: "unarchive client using short flag",
+ setupData: func(q *queries.Queries) (int64, int64) {
+ client, _ := q.CreateClient(context.Background(), queries.CreateClientParams{
+ Name: "ShortFlagClient",
+ })
+ _ = q.ArchiveClient(context.Background(), client.ID)
+ return client.ID, 0
+ },
+ args: []string{"unarchive", "-c", "ShortFlagClient"},
+ expectedOutputs: []string{"Unarchived client: ShortFlagClient"},
+ expectError: false,
+ },
+ {
+ name: "unarchive project using short flag",
+ setupData: func(q *queries.Queries) (int64, int64) {
+ client, _ := q.CreateClient(context.Background(), queries.CreateClientParams{
+ Name: "TestClient",
+ })
+ project, _ := q.CreateProject(context.Background(), queries.CreateProjectParams{
+ Name: "ShortFlagProject",
+ ClientID: client.ID,
+ })
+ _ = q.ArchiveProject(context.Background(), project.ID)
+ return client.ID, project.ID
+ },
+ args: []string{"unarchive", "-p", "ShortFlagProject"},
+ expectedOutputs: []string{"Unarchived project: ShortFlagProject"},
+ expectError: false,
+ },
+ }
+
+ for _, tt := range tests {
+ t.Run(tt.name, func(t *testing.T) {
+ q, cleanup := setupTestDB(t)
+ defer cleanup()
+
+ tt.setupData(q)
+
+ output, err := executeCommandWithDB(t, q, tt.args...)
+
+ if tt.expectError {
+ if err == nil {
+ t.Errorf("Expected error but got none")
+ } else if tt.errorContains != "" && !strings.Contains(err.Error(), tt.errorContains) {
+ t.Errorf("Expected error to contain %q, got %q", tt.errorContains, err.Error())
+ }
+ return
+ }
+
+ if err != nil {
+ t.Errorf("Unexpected error: %v", err)
+ return
+ }
+
+ found := false
+ for _, expectedOutput := range tt.expectedOutputs {
+ if strings.Contains(output, expectedOutput) {
+ found = true
+ break
+ }
+ }
+
+ if !found {
+ t.Errorf("Expected output to contain one of %v, got %q", tt.expectedOutputs, output)
+ }
+ })
+ }
+}
+
+func TestArchiveStateVerification(t *testing.T) {
+ tests := []struct {
+ name string
+ setupData func(*queries.Queries) (entityID int64, isClient bool)
+ archiveAction func(*queries.Queries, int64)
+ verifyFunc func(*testing.T, *queries.Queries, int64, bool)
+ }{
+ {
+ name: "client is archived after archive command",
+ setupData: func(q *queries.Queries) (int64, bool) {
+ client, _ := q.CreateClient(context.Background(), queries.CreateClientParams{
+ Name: "TestClient",
+ })
+ return client.ID, true
+ },
+ archiveAction: func(q *queries.Queries, id int64) {
+ _ = q.ArchiveClient(context.Background(), id)
+ },
+ verifyFunc: func(t *testing.T, q *queries.Queries, id int64, isClient bool) {
+ clients, err := q.FindClient(context.Background(), queries.FindClientParams{
+ ID: id,
+ })
+ if err != nil {
+ t.Fatalf("Failed to find client: %v", err)
+ }
+ if len(clients) != 1 {
+ t.Fatalf("Expected 1 client, got %d", len(clients))
+ }
+ if clients[0].Archived == 0 {
+ t.Errorf("Expected client to be archived")
+ }
+ },
+ },
+ {
+ name: "project is archived after archive command",
+ setupData: func(q *queries.Queries) (int64, bool) {
+ client, _ := q.CreateClient(context.Background(), queries.CreateClientParams{
+ Name: "TestClient",
+ })
+ project, _ := q.CreateProject(context.Background(), queries.CreateProjectParams{
+ Name: "TestProject",
+ ClientID: client.ID,
+ })
+ return project.ID, false
+ },
+ archiveAction: func(q *queries.Queries, id int64) {
+ _ = q.ArchiveProject(context.Background(), id)
+ },
+ verifyFunc: func(t *testing.T, q *queries.Queries, id int64, isClient bool) {
+ projects, err := q.FindProject(context.Background(), queries.FindProjectParams{
+ ID: id,
+ })
+ if err != nil {
+ t.Fatalf("Failed to find project: %v", err)
+ }
+ if len(projects) != 1 {
+ t.Fatalf("Expected 1 project, got %d", len(projects))
+ }
+ if projects[0].Archived == 0 {
+ t.Errorf("Expected project to be archived")
+ }
+ },
+ },
+ {
+ name: "client is unarchived after unarchive command",
+ setupData: func(q *queries.Queries) (int64, bool) {
+ client, _ := q.CreateClient(context.Background(), queries.CreateClientParams{
+ Name: "ArchivedClient",
+ })
+ _ = q.ArchiveClient(context.Background(), client.ID)
+ return client.ID, true
+ },
+ archiveAction: func(q *queries.Queries, id int64) {
+ _ = q.UnarchiveClient(context.Background(), id)
+ },
+ verifyFunc: func(t *testing.T, q *queries.Queries, id int64, isClient bool) {
+ clients, err := q.FindClient(context.Background(), queries.FindClientParams{
+ ID: id,
+ })
+ if err != nil {
+ t.Fatalf("Failed to find client: %v", err)
+ }
+ if len(clients) != 1 {
+ t.Fatalf("Expected 1 client, got %d", len(clients))
+ }
+ if clients[0].Archived != 0 {
+ t.Errorf("Expected client to not be archived")
+ }
+ },
+ },
+ {
+ name: "project is unarchived after unarchive command",
+ setupData: func(q *queries.Queries) (int64, bool) {
+ 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, false
+ },
+ archiveAction: func(q *queries.Queries, id int64) {
+ _ = q.UnarchiveProject(context.Background(), id)
+ },
+ verifyFunc: func(t *testing.T, q *queries.Queries, id int64, isClient bool) {
+ projects, err := q.FindProject(context.Background(), queries.FindProjectParams{
+ ID: id,
+ })
+ if err != nil {
+ t.Fatalf("Failed to find project: %v", err)
+ }
+ if len(projects) != 1 {
+ t.Fatalf("Expected 1 project, got %d", len(projects))
+ }
+ if projects[0].Archived != 0 {
+ t.Errorf("Expected project to not be archived")
+ }
+ },
+ },
+ }
+
+ for _, tt := range tests {
+ t.Run(tt.name, func(t *testing.T) {
+ q, cleanup := setupTestDB(t)
+ defer cleanup()
+
+ entityID, isClient := tt.setupData(q)
+ tt.archiveAction(q, entityID)
+ tt.verifyFunc(t, q, entityID, isClient)
+ })
+ }
+}