Add transcript passthrough processing

This commit is contained in:
2026-05-10 23:27:54 +00:00
parent 8f3c2ec5fd
commit 2cf2d390da
6 changed files with 173 additions and 28 deletions

View File

@@ -2,7 +2,11 @@ package cli
import (
"bytes"
"errors"
"encoding/json"
"io"
"os"
"path/filepath"
"reflect"
"strings"
"testing"
)
@@ -96,7 +100,7 @@ func TestRunProcessMissingTranscriptPath(t *testing.T) {
var stdout bytes.Buffer
var stderr bytes.Buffer
exitCode := Run([]string{"process", "--glossary", "glossary.yaml"}, &stdout, &stderr)
exitCode := Run([]string{"process", "--glossary", fixturePath("tiny_glossary.yaml")}, &stdout, &stderr)
if exitCode == 0 {
t.Fatalf("expected nonzero exit code")
}
@@ -112,7 +116,7 @@ func TestRunProcessMissingGlossary(t *testing.T) {
var stdout bytes.Buffer
var stderr bytes.Buffer
exitCode := Run([]string{"process", "transcript.json"}, &stdout, &stderr)
exitCode := Run([]string{"process", fixturePath("tiny_transcript.json")}, &stdout, &stderr)
if exitCode == 0 {
t.Fatalf("expected nonzero exit code")
}
@@ -124,38 +128,82 @@ func TestRunProcessMissingGlossary(t *testing.T) {
}
}
func TestRunProcessInvalidCLIConfig(t *testing.T) {
func TestRunProcessUnreadableTranscript(t *testing.T) {
var stdout bytes.Buffer
var stderr bytes.Buffer
exitCode := Run([]string{"process", "transcript.json", "--glossary", "glossary.yaml", "--work-dir-retention", "invalid"}, &stdout, &stderr)
if exitCode != 2 {
t.Fatalf("expected exit code 2, got %d", exitCode)
missingTranscript := filepath.Join(t.TempDir(), "missing.json")
exitCode := Run([]string{"process", missingTranscript, "--glossary", fixturePath("tiny_glossary.yaml")}, &stdout, &stderr)
if exitCode == 0 {
t.Fatalf("expected nonzero exit code")
}
if stdout.Len() != 0 {
t.Fatalf("expected empty stdout, got %q", stdout.String())
}
if !strings.Contains(stderr.String(), "invalid CLI configuration") {
t.Fatalf("expected invalid config error, got %q", stderr.String())
if !strings.Contains(stderr.String(), "failed to read transcript file") {
t.Fatalf("expected unreadable transcript error, got %q", stderr.String())
}
}
func TestRunProcessNotImplemented(t *testing.T) {
func TestRunProcessMalformedTranscriptJSON(t *testing.T) {
var stdout bytes.Buffer
var stderr bytes.Buffer
exitCode := Run([]string{"process", "transcript.json", "--glossary", "glossary.yaml"}, &stdout, &stderr)
if exitCode != 1 {
t.Fatalf("expected exit code 1 for not-implemented process, got %d", exitCode)
exitCode := Run([]string{"process", fixturePath("malformed_transcript.json"), "--glossary", fixturePath("tiny_glossary.yaml")}, &stdout, &stderr)
if exitCode == 0 {
t.Fatalf("expected nonzero exit code")
}
if stdout.Len() != 0 {
t.Fatalf("expected empty stdout, got %q", stdout.String())
}
if !strings.Contains(stderr.String(), processNotImplementedMessage) {
t.Fatalf("expected not-implemented message in stderr, got %q", stderr.String())
if !strings.Contains(stderr.String(), "transcript file is not valid JSON") {
t.Fatalf("expected malformed transcript error, got %q", stderr.String())
}
}
func TestRunProcessOutputToFile(t *testing.T) {
var stdout bytes.Buffer
var stderr bytes.Buffer
transcriptPath := fixturePath("tiny_transcript.json")
glossaryPath := fixturePath("tiny_glossary.yaml")
outputPath := filepath.Join(t.TempDir(), "corrected.json")
exitCode := Run([]string{"process", transcriptPath, "--glossary", glossaryPath, "--output", outputPath}, &stdout, &stderr)
if exitCode != 0 {
t.Fatalf("expected exit code 0, got %d with stderr %q", exitCode, stderr.String())
}
if stdout.Len() != 0 {
t.Fatalf("expected empty stdout when --output is used, got %q", stdout.String())
}
if stderr.Len() != 0 {
t.Fatalf("expected empty stderr on success, got %q", stderr.String())
}
inputBytes := readFile(t, transcriptPath)
outputBytes := readFile(t, outputPath)
assertJSONSemanticallyEqual(t, inputBytes, outputBytes)
}
func TestRunProcessOutputToStdout(t *testing.T) {
var stdout bytes.Buffer
var stderr bytes.Buffer
transcriptPath := fixturePath("tiny_transcript.json")
glossaryPath := fixturePath("tiny_glossary.yaml")
exitCode := Run([]string{"process", transcriptPath, "--glossary", glossaryPath}, &stdout, &stderr)
if exitCode != 0 {
t.Fatalf("expected exit code 0, got %d with stderr %q", exitCode, stderr.String())
}
if stderr.Len() != 0 {
t.Fatalf("expected empty stderr on success, got %q", stderr.String())
}
inputBytes := readFile(t, transcriptPath)
assertJSONSemanticallyEqual(t, inputBytes, stdout.Bytes())
}
func TestRunProcessCLIOverridesEnvironment(t *testing.T) {
var stdout bytes.Buffer
var stderr bytes.Buffer
@@ -163,11 +211,15 @@ func TestRunProcessCLIOverridesEnvironment(t *testing.T) {
t.Setenv("AUDITA_MODEL", "env-model")
t.Setenv("AUDITA_VALIDATION_LLM_CONCURRENCY", "2")
transcriptPath := fixturePath("tiny_transcript.json")
glossaryPath := fixturePath("tiny_glossary.yaml")
var captured processInvocation
originalRunner := processRunner
processRunner = func(inv processInvocation) error {
processRunner = func(inv processInvocation, output io.Writer) error {
_ = output
captured = inv
return errors.New(processNotImplementedMessage)
return nil
}
t.Cleanup(func() {
processRunner = originalRunner
@@ -175,17 +227,17 @@ func TestRunProcessCLIOverridesEnvironment(t *testing.T) {
exitCode := Run([]string{
"process",
"transcript.json",
transcriptPath,
"--glossary",
"glossary.yaml",
glossaryPath,
"--model",
"cli-model",
"--validation-llm-concurrency",
"5",
}, &stdout, &stderr)
if exitCode != 1 {
t.Fatalf("expected exit code 1 for not implemented, got %d", exitCode)
if exitCode != 0 {
t.Fatalf("expected exit code 0, got %d", exitCode)
}
if captured.Config.PrimaryLLM.Model != "cli-model" {
t.Fatalf("expected CLI model override, got %q", captured.Config.PrimaryLLM.Model)
@@ -193,7 +245,39 @@ func TestRunProcessCLIOverridesEnvironment(t *testing.T) {
if captured.Config.ValidationLLM.Concurrency == nil || *captured.Config.ValidationLLM.Concurrency != 5 {
t.Fatalf("expected CLI validation concurrency override, got %#v", captured.Config.ValidationLLM.Concurrency)
}
if captured.GlossaryPath != "glossary.yaml" {
if captured.GlossaryPath != glossaryPath {
t.Fatalf("unexpected glossary path: %q", captured.GlossaryPath)
}
}
func fixturePath(name string) string {
return filepath.Join("testdata", name)
}
func readFile(t *testing.T, path string) []byte {
t.Helper()
data, err := os.ReadFile(path)
if err != nil {
t.Fatalf("failed to read file %q: %v", path, err)
}
return data
}
func assertJSONSemanticallyEqual(t *testing.T, expected []byte, actual []byte) {
t.Helper()
if !json.Valid(actual) {
t.Fatalf("actual output is not valid JSON: %q", string(actual))
}
var expectedValue any
var actualValue any
if err := json.Unmarshal(expected, &expectedValue); err != nil {
t.Fatalf("failed to unmarshal expected JSON: %v", err)
}
if err := json.Unmarshal(actual, &actualValue); err != nil {
t.Fatalf("failed to unmarshal actual JSON: %v", err)
}
if !reflect.DeepEqual(expectedValue, actualValue) {
t.Fatalf("JSON content mismatch: expected %q got %q", string(expected), string(actual))
}
}