diff options
Diffstat (limited to 'internal/commands/add_client_test.go')
-rw-r--r-- | internal/commands/add_client_test.go | 175 |
1 files changed, 175 insertions, 0 deletions
diff --git a/internal/commands/add_client_test.go b/internal/commands/add_client_test.go new file mode 100644 index 0000000..23c6e71 --- /dev/null +++ b/internal/commands/add_client_test.go @@ -0,0 +1,175 @@ +package commands + +import ( + "context" + "testing" + + "punchcard/internal/queries" +) + +func TestAddClientCommand(t *testing.T) { + tests := []struct { + name string + args []string + expectedOutput string + expectError bool + }{ + { + name: "add client with name only", + args: []string{"add", "client", "TestCorp"}, + expectedOutput: "Created client: TestCorp (ID: 1)\n", + expectError: false, + }, + { + name: "add client with name and email", + args: []string{"add", "client", "TechSolutions", "contact@techsolutions.com"}, + expectedOutput: "Created client: TechSolutions <contact@techsolutions.com> (ID: 1)\n", + expectError: false, + }, + { + name: "add client with embedded email in name", + args: []string{"add", "client", "StartupXYZ <hello@startupxyz.io>"}, + expectedOutput: "Created client: StartupXYZ <hello@startupxyz.io> (ID: 1)\n", + expectError: false, + }, + { + name: "add client with both embedded and separate email (prefer separate)", + args: []string{"add", "client", "GlobalInc <old@global.com>", "new@global.com"}, + expectedOutput: "Created client: GlobalInc <new@global.com> (ID: 1)\n", + expectError: false, + }, + { + name: "add client with email format in email arg", + args: []string{"add", "client", "BigCorp", "Contact Person <contact@bigcorp.com>"}, + expectedOutput: "Created client: BigCorp <contact@bigcorp.com> (ID: 1)\n", + expectError: false, + }, + { + name: "add client with no arguments", + args: []string{"add", "client"}, + expectError: true, + }, + { + name: "add client with too many arguments", + args: []string{"add", "client", "name", "email", "extra"}, + expectError: true, + }, + { + name: "add client with billable rate", + args: []string{"add", "client", "BillableClient", "--hourly-rate", "150.50"}, + expectedOutput: "Created client: BillableClient (ID: 1)\n", + expectError: false, + }, + { + name: "add client with email and billable rate", + args: []string{"add", "client", "PremiumClient", "premium@example.com", "--hourly-rate", "200.75"}, + expectedOutput: "Created client: PremiumClient <premium@example.com> (ID: 1)\n", + expectError: false, + }, + } + + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + q, cleanup := setupTestDB(t) + defer cleanup() + + // Execute command + output, err := executeCommandWithDB(t, q, tt.args...) + + // Check error expectation + 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 tt.expectedOutput != "" && output != tt.expectedOutput { + t.Errorf("expected output %q, got %q", tt.expectedOutput, output) + } + }) + } +} + +func ptrval(i int64) *int64 { + return &i +} + +func TestAddClientBillableRateStorage(t *testing.T) { + tests := []struct { + name string + args []string + expectedRate *int64 // nil means NULL in database, values in cents + expectError bool + }{ + { + name: "client without billable rate stores NULL", + args: []string{"add", "client", "NoRateClient"}, + expectedRate: nil, + expectError: false, + }, + { + name: "client with zero billable rate stores NULL", + args: []string{"add", "client", "ZeroRateClient", "--hourly-rate", "0"}, + expectedRate: nil, + expectError: false, + }, + { + name: "client with billable rate stores value", + args: []string{"add", "client", "RateClient", "--hourly-rate", "125.75"}, + expectedRate: ptrval(12575), // $125.75 = 12575 cents + expectError: false, + }, + } + + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + q, cleanup := setupTestDB(t) + defer cleanup() + + _, 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 + } + + clientName := tt.args[2] // "add", "client", "<name>" + clients, err := q.FindClient(context.Background(), queries.FindClientParams{ + ID: 0, + Name: clientName, + }) + if err != nil { + t.Fatalf("Failed to query created client: %v", err) + } + if len(clients) != 1 { + t.Fatalf("Expected 1 client, got %d", len(clients)) + } + + client := clients[0] + if tt.expectedRate == nil { + if client.BillableRate.Valid { + t.Errorf("Expected NULL billable_rate, got %d", client.BillableRate.Int64) + } + } else { + if !client.BillableRate.Valid { + t.Errorf("Expected billable_rate %d, got NULL", *tt.expectedRate) + } else if client.BillableRate.Int64 != *tt.expectedRate { + t.Errorf("Expected billable_rate %d, got %d", *tt.expectedRate, client.BillableRate.Int64) + } + } + }) + } +} |