summaryrefslogtreecommitdiff
path: root/internal/commands/in_test.go
diff options
context:
space:
mode:
Diffstat (limited to 'internal/commands/in_test.go')
-rw-r--r--internal/commands/in_test.go187
1 files changed, 187 insertions, 0 deletions
diff --git a/internal/commands/in_test.go b/internal/commands/in_test.go
index 7d11a29..b0a0960 100644
--- a/internal/commands/in_test.go
+++ b/internal/commands/in_test.go
@@ -5,6 +5,7 @@ import (
"database/sql"
"strings"
"testing"
+ "time"
"git.tjp.lol/punchcard/internal/queries"
)
@@ -564,3 +565,189 @@ func TestFindFunctions(t *testing.T) {
})
}
}
+
+func TestInCommandTimezoneHandling(t *testing.T) {
+ // Test that punch in commands store timestamps in UTC regardless of system timezone
+ tests := []struct {
+ name string
+ setupData func(*queries.Queries) (clientID int64)
+ args []string
+ expectError bool
+ }{
+ {
+ name: "punch in stores UTC timestamp regardless of system timezone",
+ setupData: func(q *queries.Queries) int64 {
+ client, _ := q.CreateClient(context.Background(), queries.CreateClientParams{
+ Name: "TimezoneTestClient",
+ })
+ return client.ID
+ },
+ args: []string{"in", "-c", "TimezoneTestClient", "Working across timezones"},
+ expectError: false,
+ },
+ }
+
+ for _, tt := range tests {
+ t.Run(tt.name, func(t *testing.T) {
+ q, cleanup := setupTestDB(t)
+ defer cleanup()
+
+ clientID := tt.setupData(q)
+
+ // Execute command
+ _, 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
+ }
+
+ // Verify the time entry was created and has UTC timestamp
+ activeEntry, err := q.GetActiveTimeEntry(context.Background())
+ if err != nil {
+ t.Fatalf("Failed to get active time entry: %v", err)
+ }
+
+ // Verify that the stored timestamp is in UTC (Location should be UTC)
+ if activeEntry.StartTime.Location() != time.UTC {
+ t.Errorf("Expected start time to be in UTC, got location: %v", activeEntry.StartTime.Location())
+ }
+
+ // Verify client ID matches
+ if activeEntry.ClientID != clientID {
+ t.Errorf("Expected client ID %d, got %d", clientID, activeEntry.ClientID)
+ }
+
+ // Verify description was stored
+ if !activeEntry.Description.Valid || activeEntry.Description.String != "Working across timezones" {
+ t.Errorf("Expected description 'Working across timezones', got %v", activeEntry.Description)
+ }
+ })
+ }
+}
+
+func TestInCommandDSTTransition(t *testing.T) {
+ // Test punch in behavior during DST transitions
+ // Note: This test focuses on verifying UTC storage, actual DST testing would require
+ // mocking system time which is complex with the current architecture
+
+ tests := []struct {
+ name string
+ setupData func(*queries.Queries) (clientID int64)
+ args []string
+ }{
+ {
+ name: "punch in during potential DST transition stores UTC",
+ setupData: func(q *queries.Queries) int64 {
+ client, _ := q.CreateClient(context.Background(), queries.CreateClientParams{
+ Name: "DSTTestClient",
+ })
+ return client.ID
+ },
+ args: []string{"in", "-c", "DSTTestClient", "DST transition work"},
+ },
+ }
+
+ for _, tt := range tests {
+ t.Run(tt.name, func(t *testing.T) {
+ q, cleanup := setupTestDB(t)
+ defer cleanup()
+
+ clientID := tt.setupData(q)
+
+ // Execute command
+ _, err := executeCommandWithDB(t, q, tt.args...)
+ if err != nil {
+ t.Fatalf("Unexpected error: %v", err)
+ }
+
+ // Verify entry was created in UTC
+ activeEntry, err := q.GetActiveTimeEntry(context.Background())
+ if err != nil {
+ t.Fatalf("Failed to get active time entry: %v", err)
+ }
+
+ if activeEntry.StartTime.Location() != time.UTC {
+ t.Errorf("Expected UTC timezone, got: %v", activeEntry.StartTime.Location())
+ }
+
+ if activeEntry.ClientID != clientID {
+ t.Errorf("Expected client ID %d, got %d", clientID, activeEntry.ClientID)
+ }
+ })
+ }
+}
+
+func TestInCommandCopyFromRecentWithTimezone(t *testing.T) {
+ // Test that copying from most recent entry works correctly across timezone scenarios
+ tests := []struct {
+ name string
+ setupData func(*queries.Queries) error
+ args []string
+ }{
+ {
+ name: "copy most recent entry maintains timezone independence",
+ setupData: func(q *queries.Queries) error {
+ // Create client
+ client, err := q.CreateClient(context.Background(), queries.CreateClientParams{
+ Name: "RecentTestClient",
+ })
+ if err != nil {
+ return err
+ }
+
+ // Create and immediately stop a time entry to have a "most recent"
+ _, err = q.CreateTimeEntry(context.Background(), queries.CreateTimeEntryParams{
+ Description: sql.NullString{String: "Previous work", Valid: true},
+ ClientID: client.ID,
+ })
+ if err != nil {
+ return err
+ }
+
+ _, err = q.StopTimeEntry(context.Background())
+ return err
+ },
+ args: []string{"in"}, // No flags - should copy most recent
+ },
+ }
+
+ for _, tt := range tests {
+ t.Run(tt.name, func(t *testing.T) {
+ q, cleanup := setupTestDB(t)
+ defer cleanup()
+
+ if err := tt.setupData(q); err != nil {
+ t.Fatalf("Failed to setup test data: %v", err)
+ }
+
+ // Execute command
+ output, err := executeCommandWithDB(t, q, tt.args...)
+ if err != nil {
+ t.Fatalf("Unexpected error: %v", err)
+ }
+
+ // Verify it found and copied the recent entry
+ if !strings.Contains(output, "Started timer") || !strings.Contains(output, "RecentTestClient") {
+ t.Errorf("Expected output to indicate copying recent entry, got: %s", output)
+ }
+
+ // Verify the new entry is stored in UTC
+ activeEntry, err := q.GetActiveTimeEntry(context.Background())
+ if err != nil {
+ t.Fatalf("Failed to get active time entry: %v", err)
+ }
+
+ if activeEntry.StartTime.Location() != time.UTC {
+ t.Errorf("Expected new entry to be in UTC, got: %v", activeEntry.StartTime.Location())
+ }
+ })
+ }
+}