298 lines
8.6 KiB
Go
298 lines
8.6 KiB
Go
package schema
|
|
|
|
import (
|
|
"os"
|
|
"testing"
|
|
)
|
|
|
|
func TestParseSourceTranscriptJSON_BareArray(t *testing.T) {
|
|
raw, err := os.ReadFile("testdata/transcript_bare_array.json")
|
|
if err != nil {
|
|
t.Fatalf("failed to read test fixture: %v", err)
|
|
}
|
|
|
|
transcript, err := ParseSourceTranscriptJSON(raw)
|
|
if err != nil {
|
|
t.Fatalf("ParseSourceTranscriptJSON failed: %v", err)
|
|
}
|
|
|
|
if len(transcript.Segments) != 2 {
|
|
t.Fatalf("expected 2 segments, got %d", len(transcript.Segments))
|
|
}
|
|
|
|
s1 := transcript.Segments[0]
|
|
if *s1.ID != 1 {
|
|
t.Errorf("expected segment[0].id = 1, got %d", *s1.ID)
|
|
}
|
|
if s1.Speaker != "Alice" {
|
|
t.Errorf("expected segment[0].speaker = Alice, got %q", s1.Speaker)
|
|
}
|
|
if s1.Start != 0.0 {
|
|
t.Errorf("expected segment[0].start = 0.0, got %g", s1.Start)
|
|
}
|
|
if s1.End != 1.5 {
|
|
t.Errorf("expected segment[0].end = 1.5, got %g", s1.End)
|
|
}
|
|
if s1.Text != "Hello world." {
|
|
t.Errorf("expected segment[0].text = Hello world., got %q", s1.Text)
|
|
}
|
|
if s1.Categories != nil {
|
|
t.Errorf("expected segment[0].categories = nil, got %v", s1.Categories)
|
|
}
|
|
|
|
s2 := transcript.Segments[1]
|
|
if *s2.ID != 2 {
|
|
t.Errorf("expected segment[1].id = 2, got %d", *s2.ID)
|
|
}
|
|
if len(s2.Categories) != 1 || s2.Categories[0] != "greeting" {
|
|
t.Errorf("expected segment[1].categories = [greeting], got %v", s2.Categories)
|
|
}
|
|
}
|
|
|
|
func TestParseSourceTranscriptJSON_ObjectWithSegments(t *testing.T) {
|
|
raw, err := os.ReadFile("testdata/transcript_object.json")
|
|
if err != nil {
|
|
t.Fatalf("failed to read test fixture: %v", err)
|
|
}
|
|
|
|
transcript, err := ParseSourceTranscriptJSON(raw)
|
|
if err != nil {
|
|
t.Fatalf("ParseSourceTranscriptJSON failed: %v", err)
|
|
}
|
|
|
|
if len(transcript.Segments) != 2 {
|
|
t.Fatalf("expected 2 segments, got %d", len(transcript.Segments))
|
|
}
|
|
|
|
if *transcript.Segments[0].ID != 1 {
|
|
t.Errorf("expected segment[0].id = 1, got %d", *transcript.Segments[0].ID)
|
|
}
|
|
}
|
|
|
|
func TestParseSourceTranscriptJSON_MalformedJSON(t *testing.T) {
|
|
raw, err := os.ReadFile("testdata/transcript_malformed.json")
|
|
if err != nil {
|
|
t.Fatalf("failed to read test fixture: %v", err)
|
|
}
|
|
|
|
_, err = ParseSourceTranscriptJSON(raw)
|
|
if err == nil {
|
|
t.Fatal("expected error for malformed JSON, got nil")
|
|
}
|
|
|
|
var parseErr *ParseError
|
|
if parseErr, ok := err.(*ParseError); !ok {
|
|
t.Errorf("expected *ParseError, got %T", err)
|
|
} else if parseErr.Message != "transcript is not valid JSON" {
|
|
t.Errorf("expected 'transcript is not valid JSON', got %q", parseErr.Message)
|
|
}
|
|
}
|
|
|
|
func TestParseSourceTranscriptJSON_EmptySpeaker(t *testing.T) {
|
|
raw, err := os.ReadFile("testdata/transcript_empty_speaker.json")
|
|
if err != nil {
|
|
t.Fatalf("failed to read test fixture: %v", err)
|
|
}
|
|
|
|
_, err = ParseSourceTranscriptJSON(raw)
|
|
if err == nil {
|
|
t.Fatal("expected error for empty speaker, got nil")
|
|
}
|
|
|
|
assertValidationError(t, err, "speaker", "must not be empty")
|
|
}
|
|
|
|
func TestParseSourceTranscriptJSON_EmptyText(t *testing.T) {
|
|
raw, err := os.ReadFile("testdata/transcript_empty_text.json")
|
|
if err != nil {
|
|
t.Fatalf("failed to read test fixture: %v", err)
|
|
}
|
|
|
|
_, err = ParseSourceTranscriptJSON(raw)
|
|
if err == nil {
|
|
t.Fatal("expected error for empty text, got nil")
|
|
}
|
|
|
|
assertValidationError(t, err, "text", "must not be empty")
|
|
}
|
|
|
|
func TestParseSourceTranscriptJSON_InvalidTimes(t *testing.T) {
|
|
raw, err := os.ReadFile("testdata/transcript_invalid_times.json")
|
|
if err != nil {
|
|
t.Fatalf("failed to read test fixture: %v", err)
|
|
}
|
|
|
|
_, err = ParseSourceTranscriptJSON(raw)
|
|
if err == nil {
|
|
t.Fatal("expected error for invalid times, got nil")
|
|
}
|
|
|
|
assertValidationErrorContains(t, err, "end", "must be greater than or equal to start")
|
|
}
|
|
|
|
func TestParseSourceTranscriptJSON_DuplicateIDs(t *testing.T) {
|
|
raw, err := os.ReadFile("testdata/transcript_duplicate_ids.json")
|
|
if err != nil {
|
|
t.Fatalf("failed to read test fixture: %v", err)
|
|
}
|
|
|
|
_, err = ParseSourceTranscriptJSON(raw)
|
|
if err == nil {
|
|
t.Fatal("expected error for duplicate IDs, got nil")
|
|
}
|
|
|
|
assertValidationErrorContains(t, err, "id", "duplicate id")
|
|
}
|
|
|
|
func TestParseSourceTranscriptJSON_EmptyArray(t *testing.T) {
|
|
raw, err := os.ReadFile("testdata/transcript_empty_array.json")
|
|
if err != nil {
|
|
t.Fatalf("failed to read test fixture: %v", err)
|
|
}
|
|
|
|
_, err = ParseSourceTranscriptJSON(raw)
|
|
if err == nil {
|
|
t.Fatal("expected error for empty array, got nil")
|
|
}
|
|
|
|
var parseErr *ParseError
|
|
if parseErr, ok := err.(*ParseError); !ok {
|
|
t.Errorf("expected *ParseError, got %T", err)
|
|
} else if parseErr.Message != "transcript must contain at least one segment" {
|
|
t.Errorf("expected 'transcript must contain at least one segment', got %q", parseErr.Message)
|
|
}
|
|
}
|
|
|
|
func TestParseTranscriptJSON_NonSequentialID(t *testing.T) {
|
|
raw, err := os.ReadFile("testdata/transcript_non_sequential_id.json")
|
|
if err != nil {
|
|
t.Fatalf("failed to read test fixture: %v", err)
|
|
}
|
|
|
|
_, err = ParseTranscriptJSON(raw)
|
|
if err == nil {
|
|
t.Fatal("expected error for non-sequential ID, got nil")
|
|
}
|
|
|
|
assertValidationErrorContains(t, err, "id", "must be sequential")
|
|
}
|
|
|
|
func TestParseTranscriptJSONLenient_AssignsSequentialIDs(t *testing.T) {
|
|
raw, err := os.ReadFile("testdata/transcript_no_ids.json")
|
|
if err != nil {
|
|
t.Fatalf("failed to read test fixture: %v", err)
|
|
}
|
|
|
|
transcript, err := ParseTranscriptJSONLenient(raw)
|
|
if err != nil {
|
|
t.Fatalf("ParseTranscriptJSONLenient failed: %v", err)
|
|
}
|
|
|
|
if len(transcript.Segments) != 2 {
|
|
t.Fatalf("expected 2 segments, got %d", len(transcript.Segments))
|
|
}
|
|
|
|
if transcript.Segments[0].ID != 1 {
|
|
t.Errorf("expected segment[0].id = 1, got %d", transcript.Segments[0].ID)
|
|
}
|
|
if transcript.Segments[1].ID != 2 {
|
|
t.Errorf("expected segment[1].id = 2, got %d", transcript.Segments[1].ID)
|
|
}
|
|
}
|
|
|
|
func TestParseSourceTranscriptJSON_UnsupportedTopLevelShape(t *testing.T) {
|
|
raw := []byte(`"just a string"`)
|
|
|
|
_, err := ParseSourceTranscriptJSON(raw)
|
|
if err == nil {
|
|
t.Fatal("expected error for unsupported top-level shape, got nil")
|
|
}
|
|
|
|
var parseErr *ParseError
|
|
if parseErr, ok := err.(*ParseError); !ok {
|
|
t.Errorf("expected *ParseError, got %T", err)
|
|
} else if parseErr.Message != "transcript must be a JSON array or an object with a segments array" {
|
|
t.Errorf("expected unsupported shape message, got %q", parseErr.Message)
|
|
}
|
|
}
|
|
|
|
func TestParseSourceTranscriptJSON_ObjectWithoutSegments(t *testing.T) {
|
|
raw := []byte(`{"metadata": {"version": "1.0"}}`)
|
|
|
|
_, err := ParseSourceTranscriptJSON(raw)
|
|
if err == nil {
|
|
t.Fatal("expected error for object without segments, got nil")
|
|
}
|
|
|
|
var parseErr *ParseError
|
|
if parseErr, ok := err.(*ParseError); !ok {
|
|
t.Errorf("expected *ParseError, got %T", err)
|
|
} else if parseErr.Message != "transcript object must contain a segments array" {
|
|
t.Errorf("expected 'transcript object must contain a segments array', got %q", parseErr.Message)
|
|
}
|
|
}
|
|
|
|
func TestTranscriptToJSON(t *testing.T) {
|
|
transcript := &Transcript{
|
|
Segments: []Segment{
|
|
{ID: 1, Speaker: "Alice", Start: 0.0, End: 1.5, Text: "Hello world."},
|
|
{ID: 2, Speaker: "Bob", Start: 2.0, End: 3.5, Text: "Hi there.", Categories: []string{"greeting"}},
|
|
},
|
|
}
|
|
|
|
raw, err := TranscriptToJSON(transcript)
|
|
if err != nil {
|
|
t.Fatalf("TranscriptToJSON failed: %v", err)
|
|
}
|
|
|
|
parsed, err := ParseTranscriptJSON(raw)
|
|
if err != nil {
|
|
t.Fatalf("failed to parse round-trip JSON: %v", err)
|
|
}
|
|
|
|
if len(parsed.Segments) != 2 {
|
|
t.Fatalf("expected 2 segments after round-trip, got %d", len(parsed.Segments))
|
|
}
|
|
|
|
if parsed.Segments[0].Speaker != "Alice" {
|
|
t.Errorf("expected segment[0].speaker = Alice, got %q", parsed.Segments[0].Speaker)
|
|
}
|
|
if len(parsed.Segments[1].Categories) != 1 || parsed.Segments[1].Categories[0] != "greeting" {
|
|
t.Errorf("expected segment[1].categories = [greeting], got %v", parsed.Segments[1].Categories)
|
|
}
|
|
}
|
|
|
|
func assertValidationError(t *testing.T, err error, fieldContains, messageContains string) {
|
|
t.Helper()
|
|
|
|
var valErr *ValidationError
|
|
if valErr, ok := err.(*ValidationError); !ok {
|
|
t.Errorf("expected *ValidationError, got %T", err)
|
|
return
|
|
}
|
|
|
|
if fieldContains != "" && valErr.Field == "" {
|
|
t.Errorf("expected field to contain %q, got empty field", fieldContains)
|
|
}
|
|
if messageContains != "" && valErr.Message == "" {
|
|
t.Errorf("expected message to contain %q, got empty message", messageContains)
|
|
}
|
|
}
|
|
|
|
func assertValidationErrorContains(t *testing.T, err error, fieldContains, messageContains string) {
|
|
t.Helper()
|
|
|
|
var valErr *ValidationError
|
|
if valErr, ok := err.(*ValidationError); !ok {
|
|
t.Errorf("expected *ValidationError, got %T", err)
|
|
return
|
|
}
|
|
|
|
if fieldContains != "" && valErr.Field == "" {
|
|
t.Errorf("expected field to contain %q, got empty field", fieldContains)
|
|
}
|
|
if messageContains != "" && valErr.Message == "" {
|
|
t.Errorf("expected message to contain %q, got empty message", messageContains)
|
|
}
|
|
}
|