package ticket_test import ( "path/filepath" "testing" "time" "task/internal/ticket" ) func TestJSONTimeStoreRoundTrip(t *testing.T) { dir := t.TempDir() store := ticket.NewJSONTimeStore(dir) created, err := store.Create(ticket.TimeEntry{ TicketID: "t1", ProjectID: "inbox", Start: time.Now().UTC().Add(-time.Hour), End: time.Now().UTC(), Duration: time.Hour, Source: ticket.SourceManual, }) if err != nil { t.Fatal(err) } if created.ID == "" { t.Fatal("expected id") } list, err := store.List() if err != nil || len(list) != 1 { t.Fatalf("list: %v len=%d", err, len(list)) } sum, err := store.SumByTicket("t1") if err != nil || sum != time.Hour { t.Fatalf("sum: %v %v", err, sum) } timer := &ticket.ActiveTimer{TicketID: "t1", ProjectID: "inbox", StartedAt: time.Now().UTC()} if err := store.SaveActiveTimer(timer); err != nil { t.Fatal(err) } loaded, err := store.LoadActiveTimer() if err != nil || loaded == nil || loaded.TicketID != "t1" { t.Fatalf("load timer: %v %+v", err, loaded) } if err := store.SaveActiveTimer(nil); err != nil { t.Fatal(err) } if loaded, err = store.LoadActiveTimer(); err != nil || loaded != nil { t.Fatalf("cleared timer: %v %+v", err, loaded) } updated := created updated.Duration = 90 * time.Minute if err := store.Update(updated); err != nil { t.Fatal(err) } list, err = store.ListByTicket("t1") if err != nil || len(list) != 1 || list[0].Duration != 90*time.Minute { t.Fatalf("after update: %v %+v", err, list) } if err := store.Delete(created.ID); err != nil { t.Fatal(err) } list, err = store.List() if err != nil || len(list) != 0 { t.Fatalf("after delete: %v len=%d path=%s", err, len(list), filepath.Join(dir, "time_entries.json")) } } func TestJSONTimeStoreDeleteByProject(t *testing.T) { dir := t.TempDir() store := ticket.NewJSONTimeStore(dir) for _, e := range []ticket.TimeEntry{ {TicketID: "a", ProjectID: "p1", Duration: time.Hour, Source: ticket.SourceManual}, {TicketID: "b", ProjectID: "p1", Duration: time.Minute, Source: ticket.SourceManual}, {TicketID: "c", ProjectID: "p2", Duration: 30 * time.Minute, Source: ticket.SourceManual}, } { if _, err := store.Create(e); err != nil { t.Fatal(err) } } if err := store.DeleteByProject("p1"); err != nil { t.Fatal(err) } list, err := store.List() if err != nil || len(list) != 1 || list[0].ProjectID != "p2" { t.Fatalf("after DeleteByProject: %v %+v", err, list) } } func TestJSONTimeStoreRetargetTicket(t *testing.T) { dir := t.TempDir() store := ticket.NewJSONTimeStore(dir) if _, err := store.Create(ticket.TimeEntry{ TicketID: "t1", ProjectID: "old", Duration: time.Hour, Source: ticket.SourceManual, }); err != nil { t.Fatal(err) } if _, err := store.Create(ticket.TimeEntry{ TicketID: "t2", ProjectID: "old", Duration: time.Minute, Source: ticket.SourceManual, }); err != nil { t.Fatal(err) } if err := store.RetargetTicket("t1", "new"); err != nil { t.Fatal(err) } list, err := store.List() if err != nil { t.Fatal(err) } for _, e := range list { switch e.TicketID { case "t1": if e.ProjectID != "new" { t.Fatalf("t1 project=%q", e.ProjectID) } case "t2": if e.ProjectID != "old" { t.Fatalf("t2 project=%q", e.ProjectID) } } } }