package ass import ( "os" "path/filepath" "strings" "testing" "sub-cli/internal/model" ) func TestConvertToSubtitle(t *testing.T) { // Create test ASS file content := `[Script Info] ScriptType: v4.00+ Title: Test ASS File PlayResX: 640 PlayResY: 480 [V4+ Styles] Format: Name, Fontname, Fontsize, PrimaryColour, SecondaryColour, OutlineColour, BackColour, Bold, Italic, Underline, StrikeOut, ScaleX, ScaleY, Spacing, Angle, BorderStyle, Outline, Shadow, Alignment, MarginL, MarginR, MarginV, Encoding Style: Default,Arial,20,&H00FFFFFF,&H000000FF,&H00000000,&H00000000,0,0,0,0,100,100,0,0,1,2,2,2,10,10,10,1 Style: Bold,Arial,20,&H00FFFFFF,&H000000FF,&H00000000,&H00000000,1,0,0,0,100,100,0,0,1,2,2,2,10,10,10,1 [Events] Format: Layer, Start, End, Style, Name, MarginL, MarginR, MarginV, Effect, Text Dialogue: 0,0:00:01.00,0:00:04.00,Default,Character,10,20,30,Fade,This is the first subtitle line. Dialogue: 1,0:00:05.00,0:00:08.00,Bold,Character,15,25,35,,This is the second subtitle line with bold style. Comment: 0,0:00:09.00,0:00:12.00,Default,,0,0,0,,This is a comment. ` tempDir := t.TempDir() testFile := filepath.Join(tempDir, "convert_test.ass") if err := os.WriteFile(testFile, []byte(content), 0644); err != nil { t.Fatalf("Failed to create test file: %v", err) } // Test conversion to Subtitle subtitle, err := ConvertToSubtitle(testFile) if err != nil { t.Fatalf("ConvertToSubtitle failed: %v", err) } // Verify results if subtitle.Format != "ass" { t.Errorf("Format should be 'ass', got '%s'", subtitle.Format) } if subtitle.Title != "Test ASS File" { t.Errorf("Title should be 'Test ASS File', got '%s'", subtitle.Title) } // Only dialogue events should be converted if len(subtitle.Entries) != 2 { t.Errorf("Expected 2 subtitle entries, got %d", len(subtitle.Entries)) } else { // Check first entry if subtitle.Entries[0].Text != "This is the first subtitle line." { t.Errorf("First entry text mismatch: got '%s'", subtitle.Entries[0].Text) } if subtitle.Entries[0].StartTime.Seconds != 1 || subtitle.Entries[0].EndTime.Seconds != 4 { t.Errorf("First entry timing mismatch: got %+v - %+v", subtitle.Entries[0].StartTime, subtitle.Entries[0].EndTime) } // Check style conversion if subtitle.Entries[0].Styles["style"] != "Default" { t.Errorf("First entry style mismatch: got '%s'", subtitle.Entries[0].Styles["style"]) } // Check metadata conversion if subtitle.Entries[0].Metadata["Layer"] != "0" { t.Errorf("First entry layer mismatch: got '%s'", subtitle.Entries[0].Metadata["Layer"]) } if subtitle.Entries[0].Metadata["Name"] != "Character" { t.Errorf("First entry name mismatch: got '%s'", subtitle.Entries[0].Metadata["Name"]) } if subtitle.Entries[0].Metadata["MarginL"] != "10" || subtitle.Entries[0].Metadata["MarginR"] != "20" || subtitle.Entries[0].Metadata["MarginV"] != "30" { t.Errorf("First entry margins mismatch: got L=%s, R=%s, V=%s", subtitle.Entries[0].Metadata["MarginL"], subtitle.Entries[0].Metadata["MarginR"], subtitle.Entries[0].Metadata["MarginV"]) } if subtitle.Entries[0].Metadata["Effect"] != "Fade" { t.Errorf("First entry effect mismatch: got '%s'", subtitle.Entries[0].Metadata["Effect"]) } // Check second entry (Bold style) if subtitle.Entries[1].Styles["style"] != "Bold" { t.Errorf("Second entry style mismatch: got '%s'", subtitle.Entries[1].Styles["style"]) } if subtitle.Entries[1].Metadata["Layer"] != "1" { t.Errorf("Second entry layer mismatch: got '%s'", subtitle.Entries[1].Metadata["Layer"]) } } } func TestConvertFromSubtitle(t *testing.T) { // Create test subtitle subtitle := model.NewSubtitle() subtitle.Format = "ass" subtitle.Title = "Test Conversion" // Create entries entry1 := model.SubtitleEntry{ Index: 1, StartTime: model.Timestamp{Seconds: 1}, EndTime: model.Timestamp{Seconds: 4}, Text: "This is the first subtitle line.", Styles: map[string]string{"style": "Default"}, Metadata: map[string]string{ "Layer": "0", "Name": "Character", "MarginL": "10", "MarginR": "20", "MarginV": "30", "Effect": "Fade", }, } entry2 := model.SubtitleEntry{ Index: 2, StartTime: model.Timestamp{Seconds: 5}, EndTime: model.Timestamp{Seconds: 8}, Text: "This is the second subtitle line.", Styles: map[string]string{"bold": "1"}, } subtitle.Entries = append(subtitle.Entries, entry1, entry2) // Convert back to ASS tempDir := t.TempDir() outputFile := filepath.Join(tempDir, "convert_back.ass") err := ConvertFromSubtitle(subtitle, outputFile) if err != nil { t.Fatalf("ConvertFromSubtitle failed: %v", err) } // Read the generated file content, err := os.ReadFile(outputFile) if err != nil { t.Fatalf("Failed to read generated file: %v", err) } contentStr := string(content) // Verify file content if !strings.Contains(contentStr, "Title: Test Conversion") { t.Errorf("Missing or incorrect title in generated file") } // Check that both entries were converted correctly if !strings.Contains(contentStr, "Dialogue: 0,0:00:01.00,0:00:04.00,Default,Character,10,20,30,Fade,This is the first subtitle line.") { t.Errorf("First entry not converted correctly") } // Check that bold style was created and applied if !strings.Contains(contentStr, "Style: Bold") { t.Errorf("Bold style not created") } if !strings.Contains(contentStr, "Dialogue: 0,0:00:05.00,0:00:08.00,Bold") { t.Errorf("Second entry not converted with Bold style") } // Parse the file again to check structure assFile, err := Parse(outputFile) if err != nil { t.Fatalf("Failed to parse the generated file: %v", err) } if len(assFile.Events) != 2 { t.Errorf("Expected 2 events, got %d", len(assFile.Events)) } // Check style conversion var boldStyleFound bool for _, style := range assFile.Styles { if style.Name == "Bold" { boldStyleFound = true break } } if !boldStyleFound { t.Errorf("Bold style not found in generated file") } } func TestConvertToSubtitle_FileError(t *testing.T) { // Test non-existent file _, err := ConvertToSubtitle("/nonexistent/file.ass") if err == nil { t.Error("Converting non-existent file should return an error") } } func TestConvertFromSubtitle_FileError(t *testing.T) { // Test invalid path subtitle := model.NewSubtitle() err := ConvertFromSubtitle(subtitle, "/nonexistent/directory/file.ass") if err == nil { t.Error("Converting to invalid path should return an error") } }