package cli import ( "bytes" "os" "strings" "testing" "gitea.maximumdirect.net/eric/seriatim/internal/config" ) func TestRenderCommandIsRecognized(t *testing.T) { cmd := NewRootCommand() cmd.SetArgs([]string{"render", "--help"}) if err := cmd.Execute(); err != nil { t.Fatalf("render command should be recognized: %v", err) } } func TestRootHelpIncludesRender(t *testing.T) { cmd := NewRootCommand() var out bytes.Buffer cmd.SetOut(&out) cmd.SetErr(&out) cmd.SetArgs([]string{"--help"}) if err := cmd.Execute(); err != nil { t.Fatalf("help failed: %v", err) } if !strings.Contains(out.String(), "render") { t.Fatalf("root help missing render command:\n%s", out.String()) } } func TestRenderEndToEndMarkdownOutput(t *testing.T) { dir := t.TempDir() input := writeJSONFile(t, dir, "input.json", `{ "metadata": { "application": "seriatim", "version": "v-test", "output_schema": "seriatim-intermediate" }, "segments": [ {"id": 1, "start": 1, "end": 4, "speaker": "Eric", "text": "Hello there."}, {"id": 2, "start": 5, "end": 8, "speaker": "Mike", "text": "Yeah.", "categories": ["backchannel"]} ] }`) output := writeJSONFile(t, dir, "output.md", "") err := executeRender( "--input-file", input, "--output-file", output, "--format", config.RenderFormatMarkdown, "--title", "Transcript", ) if err != nil { t.Fatalf("render failed: %v", err) } data := readFile(t, output) if !strings.Contains(data, "# Transcript") { t.Fatalf("missing title:\n%s", data) } if !strings.Contains(data, "[00:00:01–00:00:04] **Eric:** Hello there.") { t.Fatalf("missing first segment:\n%s", data) } if !strings.Contains(data, "[00:00:05–00:00:08] **Mike:** *Yeah.*") { t.Fatalf("missing italicized backchannel segment:\n%s", data) } } func TestRenderRejectsUnsupportedFormat(t *testing.T) { dir := t.TempDir() input := writeJSONFile(t, dir, "input.json", `{"metadata":{"application":"seriatim","version":"v-test","output_schema":"seriatim-minimal"},"segments":[]}`) output := writeJSONFile(t, dir, "output.md", "") err := executeRender( "--input-file", input, "--output-file", output, "--format", "txt", ) if err == nil { t.Fatal("expected format error") } if !strings.Contains(err.Error(), "--format must be") { t.Fatalf("unexpected error: %v", err) } } func TestRenderRejectsMalformedAndRawInput(t *testing.T) { dir := t.TempDir() output := writeJSONFile(t, dir, "output.md", "") malformed := writeJSONFile(t, dir, "malformed.json", `{"metadata":`) err := executeRender( "--input-file", malformed, "--output-file", output, "--format", config.RenderFormatMarkdown, ) if err == nil { t.Fatal("expected malformed input error") } if !strings.Contains(err.Error(), "input JSON is malformed") { t.Fatalf("unexpected malformed input error: %v", err) } raw := writeJSONFile(t, dir, "raw.json", `{"segments":[{"id":0,"start":0.1,"end":1.1,"text":"hello","words":[{"word":"hello"}]}]}`) err = executeRender( "--input-file", raw, "--output-file", output, "--format", config.RenderFormatMarkdown, ) if err == nil { t.Fatal("expected artifact validation error") } if !strings.Contains(err.Error(), "not a valid seriatim output artifact") { t.Fatalf("unexpected raw input error: %v", err) } } func TestRenderSupportsMinimalIntermediateAndFullInputs(t *testing.T) { tests := []struct { name string content string }{ { name: "minimal", content: `{ "metadata": { "application": "seriatim", "version": "v-test", "output_schema": "seriatim-minimal" }, "segments": [{"id":1,"start":1,"end":2,"speaker":"A","text":"one"}] }`, }, { name: "intermediate", content: `{ "metadata": { "application": "seriatim", "version": "v-test", "output_schema": "seriatim-intermediate" }, "segments": [{"id":1,"start":1,"end":2,"speaker":"A","text":"one","categories":["filler"]}] }`, }, { name: "full", content: `{ "metadata": { "application": "seriatim", "version": "v-test", "input_reader": "json-files", "input_files": ["input.json"], "preprocessing_modules": [], "postprocessing_modules": [], "output_modules": ["json"] }, "segments": [{ "id":1, "source":"input.json", "source_segment_index":0, "speaker":"A", "start":1, "end":2, "text":"one" }], "overlap_groups": [] }`, }, } for _, test := range tests { t.Run(test.name, func(t *testing.T) { dir := t.TempDir() input := writeJSONFile(t, dir, "input.json", test.content) output := writeJSONFile(t, dir, "output.md", "") err := executeRender( "--input-file", input, "--output-file", output, "--format", config.RenderFormatMarkdown, ) if err != nil { t.Fatalf("render failed: %v", err) } data := readFile(t, output) if !strings.Contains(data, "**A:**") { t.Fatalf("missing rendered segment for %s input:\n%s", test.name, data) } }) } } func executeRender(args ...string) error { cmd := NewRootCommand() cmd.SetArgs(append([]string{"render"}, args...)) return cmd.Execute() } func readFile(t *testing.T, path string) string { t.Helper() data, err := os.ReadFile(path) if err != nil { t.Fatalf("read %s: %v", path, err) } return string(data) }