sub-cli/internal/format/ass/converter_test.go
2025-04-23 19:22:41 +08:00

210 lines
6.4 KiB
Go

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")
}
}