diff options
Diffstat (limited to 'internal/commands/out_test.go')
-rw-r--r-- | internal/commands/out_test.go | 124 |
1 files changed, 124 insertions, 0 deletions
diff --git a/internal/commands/out_test.go b/internal/commands/out_test.go new file mode 100644 index 0000000..aeb2359 --- /dev/null +++ b/internal/commands/out_test.go @@ -0,0 +1,124 @@ +package commands + +import ( + "context" + "database/sql" + "errors" + "testing" + + "punchcard/internal/queries" +) + +func TestOutCommand(t *testing.T) { + tests := []struct { + name string + setupTimeEntry bool + args []string + expectError bool + expectedOutput string + }{ + { + name: "stop active timer", + setupTimeEntry: true, + args: []string{"out"}, + expectError: false, + expectedOutput: "Timer stopped. Session duration:", + }, + { + name: "no active timer", + setupTimeEntry: false, + args: []string{"out"}, + expectError: true, + }, + { + name: "out command with arguments should fail", + setupTimeEntry: false, + args: []string{"out", "extra"}, + expectError: true, + }, + } + + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + // Setup fresh database for each test + q, cleanup := setupTestDB(t) + defer cleanup() + + // Setup time entry if needed + if tt.setupTimeEntry { + // Create a test client first + client, err := q.CreateClient(context.Background(), queries.CreateClientParams{ + Name: "TestClient", + Email: sql.NullString{String: "test@example.com", Valid: true}, + }) + if err != nil { + t.Fatalf("Failed to setup test client: %v", err) + } + + // Create active time entry + _, err = q.CreateTimeEntry(context.Background(), queries.CreateTimeEntryParams{ + Description: sql.NullString{String: "Test work", Valid: true}, + ClientID: client.ID, + ProjectID: sql.NullInt64{}, + }) + if err != nil { + t.Fatalf("Failed to setup test time entry: %v", err) + } + } + + // 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 + } + + // Check output contains expected text + if tt.expectedOutput != "" { + if len(output) == 0 || output[:len(tt.expectedOutput)] != tt.expectedOutput { + t.Errorf("Expected output to start with %q, got %q", tt.expectedOutput, output) + } + } + + // If we set up a time entry, verify it was stopped + if tt.setupTimeEntry { + // Try to get active time entry - should return no rows + _, err := q.GetActiveTimeEntry(context.Background()) + if !errors.Is(err, sql.ErrNoRows) { + t.Errorf("Expected no active time entry after stopping, but got: %v", err) + } + + // Verify the time entry was updated with an end_time + // We can't directly query by ID with the current queries, but we can check that no active entries exist + } + }) + } +} + +func TestOutCommandErrorType(t *testing.T) { + // Test that the specific ErrNoActiveTimer error is returned + q, cleanup := setupTestDB(t) + defer cleanup() + + // Execute out command with no active timer + _, err := executeCommandWithDB(t, q, "out") + + if err == nil { + t.Fatal("Expected error but got none") + } + + // Check that it's specifically the ErrNoActiveTimer error + if !errors.Is(err, ErrNoActiveTimer) { + t.Errorf("Expected ErrNoActiveTimer, got: %v", err) + } +} + |