tapir list — table of stored summaries (date, title|id, channel, AI, fallback), recent-first. tapir show <video-id> — full summary with highlights and takeaways. DSN + user id from TAPIR_DB_DSN/TAPIR_USER_ID, never hardcoded. main.go gains a minimal os.Args[1] dispatcher kept flat so Worker F's auth/run cases union cleanly at merge. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
131 lines
3.6 KiB
Go
131 lines
3.6 KiB
Go
package main
|
|
|
|
import (
|
|
"strings"
|
|
"testing"
|
|
"time"
|
|
|
|
"github.com/stretchr/testify/require"
|
|
|
|
"gitea.d-ma.be/mathias/tapir/internal/adapters/store"
|
|
)
|
|
|
|
func TestFormatListColumnsAndOrdering(t *testing.T) {
|
|
rows := []store.SummaryRow{
|
|
{
|
|
VideoID: "vid-newer",
|
|
Title: "Newer Title",
|
|
Channel: "youtube",
|
|
AIProvider: "anthropic",
|
|
PublishedAt: time.Date(2026, 2, 1, 0, 0, 0, 0, time.UTC),
|
|
},
|
|
{
|
|
VideoID: "vid-older",
|
|
Title: "Older Title",
|
|
Channel: "youtube",
|
|
AIProvider: "local",
|
|
FallbackUsed: true,
|
|
PublishedAt: time.Date(2026, 1, 1, 0, 0, 0, 0, time.UTC),
|
|
},
|
|
}
|
|
|
|
var b strings.Builder
|
|
require.NoError(t, formatList(&b, rows))
|
|
out := b.String()
|
|
|
|
require.Contains(t, out, "DATE")
|
|
require.Contains(t, out, "TITLE")
|
|
require.Contains(t, out, "CHANNEL")
|
|
require.Contains(t, out, "FALLBACK")
|
|
require.Contains(t, out, "Newer Title")
|
|
require.Contains(t, out, "2026-02-01")
|
|
require.Contains(t, out, "anthropic")
|
|
|
|
// formatList preserves caller ordering (the store query sorts recent-first).
|
|
require.Less(t, strings.Index(out, "Newer Title"), strings.Index(out, "Older Title"))
|
|
|
|
// fallback flag rendered per row.
|
|
older := lineContaining(t, out, "Older Title")
|
|
require.Contains(t, older, "yes")
|
|
newer := lineContaining(t, out, "Newer Title")
|
|
require.Contains(t, newer, "no")
|
|
}
|
|
|
|
func TestFormatListFallsBackToVideoIDWhenNoTitle(t *testing.T) {
|
|
rows := []store.SummaryRow{{VideoID: "raw-video-id", CreatedAt: time.Date(2026, 3, 1, 0, 0, 0, 0, time.UTC)}}
|
|
|
|
var b strings.Builder
|
|
require.NoError(t, formatList(&b, rows))
|
|
out := b.String()
|
|
|
|
require.Contains(t, out, "raw-video-id", "missing title falls back to video id")
|
|
require.Contains(t, out, "2026-03-01", "missing publish date falls back to created_at")
|
|
}
|
|
|
|
func TestFormatListEmpty(t *testing.T) {
|
|
var b strings.Builder
|
|
require.NoError(t, formatList(&b, nil))
|
|
require.Contains(t, b.String(), "no summaries yet")
|
|
}
|
|
|
|
func TestFormatShowFullSummary(t *testing.T) {
|
|
row := store.SummaryRow{
|
|
VideoID: "vid-1",
|
|
Title: "Deep Dive",
|
|
Channel: "youtube",
|
|
URL: "https://example/watch",
|
|
PublishedAt: time.Date(2026, 5, 2, 0, 0, 0, 0, time.UTC),
|
|
Summary: "The core argument.",
|
|
Highlights: []string{"first point", "second point"},
|
|
Takeaways: []string{"do this"},
|
|
AIProvider: "local",
|
|
AIModel: "qwen",
|
|
FallbackUsed: true,
|
|
}
|
|
|
|
var b strings.Builder
|
|
require.NoError(t, formatShow(&b, row))
|
|
out := b.String()
|
|
|
|
require.Contains(t, out, "Deep Dive")
|
|
require.Contains(t, out, "2026-05-02")
|
|
require.Contains(t, out, "https://example/watch")
|
|
require.Contains(t, out, "vid-1")
|
|
require.Contains(t, out, "local/qwen")
|
|
require.Contains(t, out, "fallback")
|
|
require.Contains(t, out, "The core argument.")
|
|
require.Contains(t, out, "first point")
|
|
require.Contains(t, out, "second point")
|
|
require.Contains(t, out, "do this")
|
|
}
|
|
|
|
func TestFormatShowOmitsEmptySections(t *testing.T) {
|
|
row := store.SummaryRow{
|
|
VideoID: "vid-2",
|
|
Summary: "Body only.",
|
|
AIProvider: "local",
|
|
}
|
|
|
|
var b strings.Builder
|
|
require.NoError(t, formatShow(&b, row))
|
|
out := b.String()
|
|
|
|
require.Contains(t, out, "vid-2", "no title -> falls back to video id")
|
|
require.Contains(t, out, "Body only.")
|
|
require.NotContains(t, out, "Highlights:")
|
|
require.NotContains(t, out, "Takeaways:")
|
|
require.NotContains(t, out, "URL:")
|
|
require.NotContains(t, out, "Channel:")
|
|
}
|
|
|
|
func lineContaining(t *testing.T, text, needle string) string {
|
|
t.Helper()
|
|
for _, ln := range strings.Split(text, "\n") {
|
|
if strings.Contains(ln, needle) {
|
|
return ln
|
|
}
|
|
}
|
|
t.Fatalf("no line containing %q in:\n%s", needle, text)
|
|
return ""
|
|
}
|