package sqlite import ( "path/filepath" "testing" "task/internal/ticket" ) func TestTicketKeysSequential(t *testing.T) { db, err := Open(filepath.Join(t.TempDir(), "keys.db"), []byte("test-secret")) if err != nil { t.Fatal(err) } defer db.Close() ps := NewProjectStore(db) p, err := ps.Create("", "Task Master") if err != nil { t.Fatal(err) } if p.Code != "TAS" { t.Fatalf("code=%q want TAS", p.Code) } ts := NewTicketStore(db) a, err := ts.Create(ticket.Ticket{Title: "One", ProjectID: p.ID}) if err != nil { t.Fatal(err) } b, err := ts.Create(ticket.Ticket{Title: "Two", ProjectID: p.ID}) if err != nil { t.Fatal(err) } if a.Key != "TAS-1" || a.Number != 1 { t.Fatalf("first=%+v", a) } if b.Key != "TAS-2" || b.Number != 2 { t.Fatalf("second=%+v", b) } got, err := ts.Get(a.ID) if err != nil || got.Key != "TAS-1" { t.Fatalf("get=%+v err=%v", got, err) } // Update must preserve key. got.Title = "One*" if err := ts.Update(got); err != nil { t.Fatal(err) } got, _ = ts.Get(a.ID) if got.Key != "TAS-1" || got.Title != "One*" { t.Fatalf("after update=%+v", got) } } func TestTicketKeyBackfill(t *testing.T) { path := filepath.Join(t.TempDir(), "backfill.db") db, err := Open(path, []byte("test-secret")) if err != nil { t.Fatal(err) } // Insert legacy-shaped rows as if pre-migration (columns exist after Open). _, err = db.SQL.Exec(`INSERT INTO projects(id, name, code, ticket_seq, created_at, updated_at) VALUES('p1', 'Inbox', '', 0, '2020-01-01T00:00:00Z', '2020-01-01T00:00:00Z')`) if err != nil { t.Fatal(err) } _, err = db.SQL.Exec(`INSERT INTO tickets(id, title, description, status, project_id, created_at, updated_at, source, external_id, external_url, synced_at, number, key) VALUES('t1', 'Old', '', 'todo', 'p1', '2020-01-02T00:00:00Z', '2020-01-02T00:00:00Z', '', '', '', '', NULL, '')`) if err != nil { t.Fatal(err) } if err := db.backfillTicketKeys(); err != nil { t.Fatal(err) } var code string var seq int if err := db.SQL.QueryRow(`SELECT code, ticket_seq FROM projects WHERE id='p1'`).Scan(&code, &seq); err != nil { t.Fatal(err) } if code != "INB" || seq != 1 { t.Fatalf("project code=%q seq=%d", code, seq) } var key string var num int if err := db.SQL.QueryRow(`SELECT key, number FROM tickets WHERE id='t1'`).Scan(&key, &num); err != nil { t.Fatal(err) } if key != "INB-1" || num != 1 { t.Fatalf("ticket key=%q num=%d", key, num) } _ = db.Close() } func TestMoveReassignsKey(t *testing.T) { db, err := Open(filepath.Join(t.TempDir(), "move.db"), []byte("test-secret")) if err != nil { t.Fatal(err) } defer db.Close() ps := NewProjectStore(db) a, err := ps.Create("", "Alpha") if err != nil { t.Fatal(err) } b, err := ps.Create("", "Beta") if err != nil { t.Fatal(err) } ts := NewTicketStore(db) tk, err := ts.Create(ticket.Ticket{Title: "Move me", ProjectID: a.ID}) if err != nil { t.Fatal(err) } moved, err := ts.Move(tk.ID, b.ID) if err != nil { t.Fatal(err) } if moved.ProjectID != b.ID || moved.Key != b.Code+"-1" { t.Fatalf("moved=%+v betaCode=%s", moved, b.Code) } }