summaryrefslogtreecommitdiff
path: root/internal/commands/add_project_test.go
diff options
context:
space:
mode:
Diffstat (limited to 'internal/commands/add_project_test.go')
-rw-r--r--internal/commands/add_project_test.go198
1 files changed, 198 insertions, 0 deletions
diff --git a/internal/commands/add_project_test.go b/internal/commands/add_project_test.go
new file mode 100644
index 0000000..c41bd5c
--- /dev/null
+++ b/internal/commands/add_project_test.go
@@ -0,0 +1,198 @@
+package commands
+
+import (
+ "context"
+ "database/sql"
+ "testing"
+
+ "punchcard/internal/queries"
+)
+
+func TestAddProjectCommand(t *testing.T) {
+ tests := []struct {
+ name string
+ setupClient bool
+ clientName string
+ clientEmail string
+ args []string
+ expectedOutput string
+ expectError bool
+ }{
+ {
+ name: "add project with client name",
+ setupClient: true,
+ clientName: "TestCorp",
+ clientEmail: "test@testcorp.com",
+ args: []string{"add", "project", "Website Redesign", "-c", "TestCorp"},
+ expectedOutput: "Created project: Website Redesign for client TestCorp (ID: 1)\n",
+ expectError: false,
+ },
+ {
+ name: "add project with client ID",
+ setupClient: true,
+ clientName: "TechSolutions",
+ clientEmail: "contact@techsolutions.com",
+ args: []string{"add", "project", "Mobile App", "-c", "1"},
+ expectedOutput: "Created project: Mobile App for client TechSolutions (ID: 1)\n",
+ expectError: false,
+ },
+ {
+ name: "add project with nonexistent client name",
+ setupClient: false,
+ args: []string{"add", "project", "Test Project", "-c", "NonexistentClient"},
+ expectError: true,
+ },
+ {
+ name: "add project with nonexistent client ID",
+ setupClient: false,
+ args: []string{"add", "project", "Test Project", "-c", "999"},
+ expectError: true,
+ },
+ {
+ name: "add project with no arguments",
+ setupClient: false,
+ args: []string{"add", "project"},
+ expectError: true,
+ },
+ {
+ name: "add project with only name",
+ setupClient: false,
+ args: []string{"add", "project", "Test Project"},
+ expectError: true,
+ },
+ {
+ name: "add project with too many arguments",
+ setupClient: true,
+ clientName: "TestCorp",
+ args: []string{"add", "project", "name", "extra", "-c", "TestCorp"},
+ expectError: true,
+ },
+ {
+ name: "add project with billable rate",
+ setupClient: true,
+ clientName: "BillableClient",
+ clientEmail: "billing@client.com",
+ args: []string{"add", "project", "Premium Project", "-c", "BillableClient", "-r", "175.25"},
+ expectedOutput: "Created project: Premium Project for client BillableClient (ID: 1)\n",
+ expectError: false,
+ },
+ }
+
+ for _, tt := range tests {
+ t.Run(tt.name, func(t *testing.T) {
+ q, cleanup := setupTestDB(t)
+ defer cleanup()
+
+ if tt.setupClient {
+ _, err := q.CreateClient(context.Background(), queries.CreateClientParams{
+ Name: tt.clientName,
+ Email: sql.NullString{String: tt.clientEmail, Valid: tt.clientEmail != ""},
+ BillableRate: sql.NullInt64{},
+ })
+ if err != nil {
+ t.Fatalf("Failed to setup test client: %v", err)
+ }
+ }
+
+ output, err := executeCommandWithDB(t, q, tt.args...)
+
+ if tt.expectError {
+ if err == nil {
+ t.Errorf("Expected error but got none")
+ }
+ return
+ }
+
+ if err != nil {
+ t.Errorf("Unexpected error: %v", err)
+ return
+ }
+
+ if output != tt.expectedOutput {
+ t.Errorf("Expected output %q, got %q", tt.expectedOutput, output)
+ }
+ })
+ }
+}
+
+func TestAddProjectBillableRateStorage(t *testing.T) {
+ tests := []struct {
+ name string
+ args []string
+ expectedRate *int64 // nil means NULL in database, values in cents
+ expectError bool
+ }{
+ {
+ name: "project without billable rate stores NULL",
+ args: []string{"add", "project", "NoRateProject", "-c", "testclient"},
+ expectedRate: nil,
+ expectError: false,
+ },
+ {
+ name: "project with zero billable rate stores NULL",
+ args: []string{"add", "project", "ZeroRateProject", "-c", "testclient", "--hourly-rate", "0"},
+ expectedRate: nil,
+ expectError: false,
+ },
+ {
+ name: "project with billable rate stores value",
+ args: []string{"add", "project", "RateProject", "-c", "testclient", "--hourly-rate", "225.50"},
+ expectedRate: func() *int64 { f := int64(22550); return &f }(), // $225.50 = 22550 cents
+ expectError: false,
+ },
+ }
+
+ for _, tt := range tests {
+ t.Run(tt.name, func(t *testing.T) {
+ q, cleanup := setupTestDB(t)
+ defer cleanup()
+
+ _, err := q.CreateClient(context.Background(), queries.CreateClientParams{
+ Name: "testclient",
+ Email: sql.NullString{},
+ BillableRate: sql.NullInt64{},
+ })
+ if err != nil {
+ t.Fatalf("Failed to setup test client: %v", err)
+ }
+
+ _, err = executeCommandWithDB(t, q, tt.args...)
+
+ if tt.expectError {
+ if err == nil {
+ t.Errorf("Expected error but got none")
+ }
+ return
+ }
+
+ if err != nil {
+ t.Errorf("Unexpected error: %v", err)
+ return
+ }
+
+ projects, err := q.FindProject(context.Background(), queries.FindProjectParams{
+ ID: 1,
+ Name: "",
+ })
+ if err != nil {
+ t.Fatalf("Failed to query created project: %v", err)
+ }
+ if len(projects) != 1 {
+ t.Fatalf("Expected 1 project, got %d", len(projects))
+ }
+
+ project := projects[0]
+ if tt.expectedRate == nil {
+ if project.BillableRate.Valid {
+ t.Errorf("Expected NULL billable_rate, got %d", project.BillableRate.Int64)
+ }
+ } else {
+ if !project.BillableRate.Valid {
+ t.Errorf("Expected billable_rate %d, got NULL", *tt.expectedRate)
+ } else if project.BillableRate.Int64 != *tt.expectedRate {
+ t.Errorf("Expected billable_rate %d, got %d", *tt.expectedRate, project.BillableRate.Int64)
+ }
+ }
+ })
+ }
+}