package render import ( "strings" "testing" ) func TestMarkdownRendererDefaultTranscriptShape(t *testing.T) { transcript := Transcript{ Schema: "seriatim-intermediate", Metadata: Metadata{ Application: "seriatim", Version: "v-test", }, Segments: []Segment{ {ID: 1, Start: 1, End: 4, Speaker: "Eric", Text: "Hello there."}, {ID: 2, Start: 5, End: 8, Speaker: "Mike", Text: "Welcome back, everyone."}, }, } output, err := MarkdownRenderer{}.Render(transcript, Options{ Title: "Transcript", IncludeTimestamps: true, }) if err != nil { t.Fatalf("render markdown: %v", err) } if !strings.Contains(output, "# Transcript") { t.Fatalf("expected title in output:\n%s", output) } if !strings.Contains(output, "[00:00:01–00:00:04] **Eric:** Hello there.") { t.Fatalf("expected first segment in output:\n%s", output) } if !strings.Contains(output, "[00:00:05–00:00:08] **Mike:** Welcome back, everyone.") { t.Fatalf("expected second segment in output:\n%s", output) } } func TestMarkdownRendererWithoutTimestamps(t *testing.T) { transcript := Transcript{ Segments: []Segment{ {ID: 1, Start: 1, End: 4, Speaker: "Eric", Text: "Hello."}, }, } output, err := MarkdownRenderer{}.Render(transcript, Options{ Title: "Transcript", IncludeTimestamps: false, }) if err != nil { t.Fatalf("render markdown: %v", err) } if strings.Contains(output, "[00:00:01") { t.Fatalf("timestamps should be omitted:\n%s", output) } if !strings.Contains(output, "**Eric:** Hello.") { t.Fatalf("expected speaker/text line:\n%s", output) } } func TestMarkdownRendererWithSegmentIDs(t *testing.T) { transcript := Transcript{ Segments: []Segment{ {ID: 17, Start: 1, End: 4, Speaker: "Eric", Text: "Hello."}, }, } output, err := MarkdownRenderer{}.Render(transcript, Options{ Title: "Transcript", IncludeTimestamps: true, IncludeSegmentIDs: true, }) if err != nil { t.Fatalf("render markdown: %v", err) } if !strings.Contains(output, "[#17]") { t.Fatalf("expected segment ID in output:\n%s", output) } } func TestMarkdownRendererMetadataOnlyWhenRequested(t *testing.T) { transcript := Transcript{ Schema: "seriatim-full", Metadata: Metadata{ Application: "seriatim", Version: "v-test", }, } withMetadata, err := MarkdownRenderer{}.Render(transcript, Options{ Title: "Transcript", IncludeMetadata: true, }) if err != nil { t.Fatalf("render with metadata: %v", err) } if !strings.Contains(withMetadata, "- Application: seriatim") { t.Fatalf("expected metadata block:\n%s", withMetadata) } withoutMetadata, err := MarkdownRenderer{}.Render(transcript, Options{Title: "Transcript"}) if err != nil { t.Fatalf("render without metadata: %v", err) } if strings.Contains(withoutMetadata, "- Application: seriatim") { t.Fatalf("metadata should be omitted:\n%s", withoutMetadata) } } func TestMarkdownRendererEscapesUserProvidedMarkdown(t *testing.T) { transcript := Transcript{ Schema: "seriatim-intermediate", Metadata: Metadata{ Application: "seriatim *cli*", Version: "v[test]", }, Segments: []Segment{ { ID: 1, Start: 1, End: 2, Speaker: "Dr. *A_[1]", Text: "Use *literal* [link](target) and `code` \\ slash!", }, { ID: 2, Start: 2, End: 3, Speaker: "Narrator", Text: "_aside_ with | pipe", Categories: []string{"background"}, }, }, } output, err := MarkdownRenderer{}.Render(transcript, Options{ Title: "# Planning [notes]", IncludeTimestamps: false, IncludeMetadata: true, }) if err != nil { t.Fatalf("render markdown: %v", err) } assertContains(t, output, "# \\# Planning \\[notes\\]") assertContains(t, output, "- Application: seriatim \\*cli\\*") assertContains(t, output, "- Version: v\\[test\\]") assertContains(t, output, "**Dr. \\*A\\_\\[1\\]:** Use \\*literal\\* \\[link\\]\\(target\\) and \\`code\\` \\\\ slash\\!") assertContains(t, output, "**Narrator:** *\\_aside\\_ with \\| pipe*") } func TestMarkdownRendererCategoryHintItalicsAndUnknownCategories(t *testing.T) { transcript := Transcript{ Segments: []Segment{ {ID: 1, Start: 1, End: 2, Speaker: "A", Text: "bg", Categories: []string{"background"}}, {ID: 2, Start: 2, End: 3, Speaker: "B", Text: "bc", Categories: []string{"backchannel"}}, {ID: 3, Start: 3, End: 4, Speaker: "C", Text: "fill", Categories: []string{"filler"}}, {ID: 4, Start: 4, End: 5, Speaker: "D", Text: "plain", Categories: []string{"unknown-tag"}}, }, } output, err := MarkdownRenderer{}.Render(transcript, Options{ Title: "Transcript", IncludeTimestamps: false, }) if err != nil { t.Fatalf("render markdown: %v", err) } if !strings.Contains(output, "**A:** *bg*") { t.Fatalf("expected background italics:\n%s", output) } if !strings.Contains(output, "**B:** *bc*") { t.Fatalf("expected backchannel italics:\n%s", output) } if !strings.Contains(output, "**C:** *fill*") { t.Fatalf("expected filler italics:\n%s", output) } if !strings.Contains(output, "**D:** plain") { t.Fatalf("expected unknown category to be ignored:\n%s", output) } } func TestMarkdownRendererIsDeterministic(t *testing.T) { transcript := Transcript{ Schema: "seriatim-intermediate", Metadata: Metadata{ Application: "seriatim", Version: "v-test", }, Segments: []Segment{ {ID: 1, Start: 1.2, End: 4.4, Speaker: "Eric", Text: "Hello there.", Categories: []string{"unknown-tag"}}, {ID: 2, Start: 65.1, End: 68.8, Speaker: "Mike", Text: "Yeah.", Categories: []string{"backchannel"}}, }, } opts := Options{ Title: "Transcript", IncludeTimestamps: true, IncludeSegmentIDs: true, IncludeMetadata: true, } first, err := MarkdownRenderer{}.Render(transcript, opts) if err != nil { t.Fatalf("first render failed: %v", err) } second, err := MarkdownRenderer{}.Render(transcript, opts) if err != nil { t.Fatalf("second render failed: %v", err) } if first != second { t.Fatalf("render output is not deterministic:\nfirst:\n%s\nsecond:\n%s", first, second) } if !strings.Contains(first, "[00:00:01–00:00:04] [#1] **Eric:** Hello there.") { t.Fatalf("expected HH:MM:SS timestamp formatting:\n%s", first) } if !strings.Contains(first, "[00:01:05–00:01:09] [#2] **Mike:** *Yeah.*") { t.Fatalf("expected HH:MM:SS timestamp formatting:\n%s", first) } } func assertContains(t *testing.T, value string, want string) { t.Helper() if !strings.Contains(value, want) { t.Fatalf("expected output to contain %q:\n%s", want, value) } }