summaryrefslogtreecommitdiff
path: root/internal/commands/add_client_test.go
diff options
context:
space:
mode:
Diffstat (limited to 'internal/commands/add_client_test.go')
-rw-r--r--internal/commands/add_client_test.go175
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)
+ }
+ }
+ })
+ }
+}