Files
projax/web/gitea_test.go
mAi 4e919babed refactor(timeline): consume internal/aggregate/
Phase 5a slice B. Replace web/timeline.go's hand-rolled fan-out + day
grouping with calls into the aggregator package.

- web/timeline.go: collectTimelineTodos + collectTimelineEvents +
  in-line day grouping deleted. buildTimeline now calls
  aggregator.Todos/Events/Docs/Creations, decorates each typed row
  with the template-friendly TimelineRow shape (PER, StartLabel,
  DurationHint), then hands rows to aggregate.BuildTimelineDays for
  sorting + sticky-pill markers + far-future fade.
- web/timeline.go: TimelineRow / TimelineDay are now type aliases for
  the aggregate package's versions (Phase 5a slice A introduced them
  with the same flat-field layout the templates already address).
- web/server.go: new Server.Aggregator() factory builds a fresh
  *aggregate.Aggregator wired to the server's current CalDAV/Gitea
  deps (so main.go can install those after web.New without a re-init
  hook).
- web/{gitea,dashboard,gitea_writeback,gitea_test}.go: issueCache
  methods capitalised (Get/Set/Invalidate) so the aggregator's
  IssueCache interface accepts *web.issueCache directly. No behaviour
  change.

All web/timeline_*test.go pass unmodified — the refactor preserves
output shape and template field paths.

Task: t-projax-5a-aggregator
2026-05-22 00:05:14 +02:00

67 lines
1.6 KiB
Go

package web
import (
"testing"
"time"
"github.com/m/projax/gitea"
)
func TestIssueCacheTTL(t *testing.T) {
c := newIssueCache(50 * time.Millisecond)
c.Set("k", []gitea.Issue{{Number: 1, Title: "a"}})
if got, ok := c.Get("k"); !ok || len(got) != 1 {
t.Fatalf("immediate get: ok=%v got=%v", ok, got)
}
time.Sleep(80 * time.Millisecond)
if _, ok := c.Get("k"); ok {
t.Errorf("expected miss after TTL, got hit")
}
}
func TestRelativeTime(t *testing.T) {
now := time.Date(2026, 5, 15, 12, 0, 0, 0, time.UTC)
for _, tc := range []struct {
offset time.Duration
want string
}{
{-30 * time.Second, "just now"},
{-5 * time.Minute, "5m ago"},
{-3 * time.Hour, "3h ago"},
{-30 * time.Hour, "yesterday"},
{-5 * 24 * time.Hour, "5d ago"},
} {
got := relativeTime(now, now.Add(tc.offset))
if got != tc.want {
t.Errorf("offset=%v got %q want %q", tc.offset, got, tc.want)
}
}
}
func TestToViewPreservesFields(t *testing.T) {
in := []gitea.Issue{
{
Number: 7,
Title: "x",
State: "open",
Labels: []string{"bug"},
Assignees: []string{"a"},
Milestone: "M",
HTMLURL: "https://example/7",
UpdatedAt: time.Date(2026, 5, 14, 12, 0, 0, 0, time.UTC),
},
}
now := time.Date(2026, 5, 15, 12, 0, 0, 0, time.UTC)
got := toView(in, now)
if len(got) != 1 {
t.Fatalf("expected 1, got %d", len(got))
}
v := got[0]
if v.Number != 7 || v.Title != "x" || v.HTMLURL != "https://example/7" {
t.Errorf("field mismatch: %+v", v)
}
if v.UpdatedRel != "yesterday" {
t.Errorf("UpdatedRel = %q, want yesterday", v.UpdatedRel)
}
}