Files
tapir/cmd/tapir/format_test.go
T
mathiasandClaude Opus 4.8 d3498898c0 feat(cli): add read-only list and show subcommands
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>
2026-06-02 20:58:09 +02:00

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 ""
}