297 lines
8.5 KiB
Go
297 lines
8.5 KiB
Go
package sync
|
|
|
|
import (
|
|
"os"
|
|
"path/filepath"
|
|
"strings"
|
|
"testing"
|
|
)
|
|
|
|
func TestSyncLyrics(t *testing.T) {
|
|
// Create temporary test directory
|
|
tempDir := t.TempDir()
|
|
|
|
// Test cases for different format combinations
|
|
testCases := []struct {
|
|
name string
|
|
sourceContent string
|
|
sourceExt string
|
|
targetContent string
|
|
targetExt string
|
|
expectedError bool
|
|
validateOutput func(t *testing.T, filePath string)
|
|
}{
|
|
{
|
|
name: "LRC to LRC sync",
|
|
sourceContent: `[ti:Source LRC]
|
|
[ar:Test Artist]
|
|
|
|
[00:01.00]This is line one.
|
|
[00:05.00]This is line two.
|
|
[00:09.50]This is line three.
|
|
`,
|
|
sourceExt: "lrc",
|
|
targetContent: `[ti:Target LRC]
|
|
[ar:Different Artist]
|
|
|
|
[00:10.00]This is line one with different timing.
|
|
[00:20.00]This is line two with different timing.
|
|
[00:30.00]This is line three with different timing.
|
|
`,
|
|
targetExt: "lrc",
|
|
expectedError: false,
|
|
validateOutput: func(t *testing.T, filePath string) {
|
|
content, err := os.ReadFile(filePath)
|
|
if err != nil {
|
|
t.Fatalf("Failed to read output file: %v", err)
|
|
}
|
|
|
|
contentStr := string(content)
|
|
|
|
// Should contain target title but source timings
|
|
if !strings.Contains(contentStr, "[ti:Target LRC]") {
|
|
t.Errorf("Output should preserve target title, got: %s", contentStr)
|
|
}
|
|
if !strings.Contains(contentStr, "[ar:Different Artist]") {
|
|
t.Errorf("Output should preserve target artist, got: %s", contentStr)
|
|
}
|
|
|
|
// Should have source timings
|
|
if !strings.Contains(contentStr, "[00:01.000]") {
|
|
t.Errorf("Output should have source timing [00:01.000], got: %s", contentStr)
|
|
}
|
|
|
|
// Should have target content
|
|
if !strings.Contains(contentStr, "This is line one with different timing.") {
|
|
t.Errorf("Output should preserve target content, got: %s", contentStr)
|
|
}
|
|
},
|
|
},
|
|
{
|
|
name: "SRT to SRT sync",
|
|
sourceContent: `1
|
|
00:00:01,000 --> 00:00:04,000
|
|
This is line one.
|
|
|
|
2
|
|
00:00:05,000 --> 00:00:08,000
|
|
This is line two.
|
|
|
|
3
|
|
00:00:09,000 --> 00:00:12,000
|
|
This is line three.
|
|
`,
|
|
sourceExt: "srt",
|
|
targetContent: `1
|
|
00:01:00,000 --> 00:01:03,000
|
|
This is target line one.
|
|
|
|
2
|
|
00:01:05,000 --> 00:01:08,000
|
|
This is target line two.
|
|
|
|
3
|
|
00:01:10,000 --> 00:01:13,000
|
|
This is target line three.
|
|
`,
|
|
targetExt: "srt",
|
|
expectedError: false,
|
|
validateOutput: func(t *testing.T, filePath string) {
|
|
content, err := os.ReadFile(filePath)
|
|
if err != nil {
|
|
t.Fatalf("Failed to read output file: %v", err)
|
|
}
|
|
|
|
contentStr := string(content)
|
|
|
|
// Should have source timings but target content
|
|
if !strings.Contains(contentStr, "00:00:01,000 -->") {
|
|
t.Errorf("Output should have source timing 00:00:01,000, got: %s", contentStr)
|
|
}
|
|
|
|
// Check target content is preserved
|
|
if !strings.Contains(contentStr, "This is target line one.") {
|
|
t.Errorf("Output should preserve target content, got: %s", contentStr)
|
|
}
|
|
|
|
// Check identifiers are sequential
|
|
if !strings.Contains(contentStr, "1\n00:00:01,000") {
|
|
t.Errorf("Output should have sequential identifiers starting with 1, got: %s", contentStr)
|
|
}
|
|
},
|
|
},
|
|
{
|
|
name: "VTT to VTT sync",
|
|
sourceContent: `WEBVTT
|
|
|
|
1
|
|
00:00:01.000 --> 00:00:04.000
|
|
This is line one.
|
|
|
|
2
|
|
00:00:05.000 --> 00:00:08.000
|
|
This is line two.
|
|
|
|
3
|
|
00:00:09.000 --> 00:00:12.000
|
|
This is line three.
|
|
`,
|
|
sourceExt: "vtt",
|
|
targetContent: `WEBVTT - Target Title
|
|
|
|
1
|
|
00:01:00.000 --> 00:01:03.000 align:start position:10%
|
|
This is target line one.
|
|
|
|
2
|
|
00:01:05.000 --> 00:01:08.000 align:middle
|
|
This is target line two.
|
|
|
|
3
|
|
00:01:10.000 --> 00:01:13.000
|
|
This is target line three.
|
|
`,
|
|
targetExt: "vtt",
|
|
expectedError: false,
|
|
validateOutput: func(t *testing.T, filePath string) {
|
|
content, err := os.ReadFile(filePath)
|
|
if err != nil {
|
|
t.Fatalf("Failed to read output file: %v", err)
|
|
}
|
|
|
|
contentStr := string(content)
|
|
|
|
// Should preserve VTT title
|
|
if !strings.Contains(contentStr, "WEBVTT - Target Title") {
|
|
t.Errorf("Output should preserve target title, got: %s", contentStr)
|
|
}
|
|
|
|
// Should have source timings but target content and settings
|
|
if !strings.Contains(contentStr, "00:00:01.000 -->") {
|
|
t.Errorf("Output should have source timing 00:00:01.000, got: %s", contentStr)
|
|
}
|
|
|
|
// Should preserve styling cue settings
|
|
if !strings.Contains(contentStr, "align:start position:10%") {
|
|
t.Errorf("Output should preserve cue settings, got: %s", contentStr)
|
|
}
|
|
|
|
// Check target content is preserved
|
|
if !strings.Contains(contentStr, "This is target line one.") {
|
|
t.Errorf("Output should preserve target content, got: %s", contentStr)
|
|
}
|
|
},
|
|
},
|
|
{
|
|
name: "ASS to ASS sync",
|
|
sourceContent: `[Script Info]
|
|
ScriptType: v4.00+
|
|
PlayResX: 640
|
|
PlayResY: 480
|
|
Timer: 100.0000
|
|
Title: Source ASS File
|
|
|
|
[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
|
|
|
|
[Events]
|
|
Format: Layer, Start, End, Style, Name, MarginL, MarginR, MarginV, Effect, Text
|
|
Dialogue: 0,0:00:01.00,0:00:04.00,Default,,0,0,0,,Source line one.
|
|
Dialogue: 0,0:00:05.00,0:00:08.00,Default,,0,0,0,,Source line two.
|
|
Dialogue: 0,0:00:09.00,0:00:12.00,Default,,0,0,0,,Source line three.
|
|
`,
|
|
sourceExt: "ass",
|
|
targetContent: `[Script Info]
|
|
ScriptType: v4.00+
|
|
PlayResX: 640
|
|
PlayResY: 480
|
|
Timer: 100.0000
|
|
Title: Target ASS File
|
|
|
|
[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: Alternate,Arial,20,&H0000FFFF,&H000000FF,&H00000000,&H00000000,0,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:01:00.00,0:01:03.00,Default,,0,0,0,,Target line one.
|
|
Dialogue: 0,0:01:05.00,0:01:08.00,Alternate,,0,0,0,,Target line two.
|
|
Dialogue: 0,0:01:10.00,0:01:13.00,Default,,0,0,0,,Target line three.
|
|
`,
|
|
targetExt: "ass",
|
|
expectedError: false,
|
|
validateOutput: func(t *testing.T, filePath string) {
|
|
content, err := os.ReadFile(filePath)
|
|
if err != nil {
|
|
t.Fatalf("Failed to read output file: %v", err)
|
|
}
|
|
|
|
contentStr := string(content)
|
|
|
|
// Should have source timings but target content
|
|
if !strings.Contains(contentStr, "0:00:01.00") {
|
|
t.Errorf("Output should have source timing 0:00:01.00, got: %s", contentStr)
|
|
}
|
|
|
|
// Check target content is preserved
|
|
if !strings.Contains(contentStr, "Target line one.") {
|
|
t.Errorf("Output should preserve target content, got: %s", contentStr)
|
|
}
|
|
|
|
// Check target styles are preserved
|
|
if !strings.Contains(contentStr, "Style: Alternate") {
|
|
t.Errorf("Output should preserve target styles, got: %s", contentStr)
|
|
}
|
|
|
|
// Check target title is preserved
|
|
if !strings.Contains(contentStr, "Title: Target ASS File") {
|
|
t.Errorf("Output should preserve target title, got: %s", contentStr)
|
|
}
|
|
},
|
|
},
|
|
{
|
|
name: "Unsupported format combination",
|
|
sourceContent: `[00:01.00]This is line one.`,
|
|
sourceExt: "lrc",
|
|
targetContent: `1\n00:00:01,000 --> 00:00:04,000\nThis is line one.`,
|
|
targetExt: "srt",
|
|
expectedError: true,
|
|
validateOutput: func(t *testing.T, filePath string) {
|
|
// Not needed for error case
|
|
},
|
|
},
|
|
}
|
|
|
|
for _, tc := range testCases {
|
|
t.Run(tc.name, func(t *testing.T) {
|
|
sourceFile := filepath.Join(tempDir, "source."+tc.sourceExt)
|
|
targetFile := filepath.Join(tempDir, "target."+tc.targetExt)
|
|
|
|
// Write test files
|
|
if err := os.WriteFile(sourceFile, []byte(tc.sourceContent), 0644); err != nil {
|
|
t.Fatalf("Failed to write source file: %v", err)
|
|
}
|
|
|
|
if err := os.WriteFile(targetFile, []byte(tc.targetContent), 0644); err != nil {
|
|
t.Fatalf("Failed to write target file: %v", err)
|
|
}
|
|
|
|
// Run SyncLyrics
|
|
err := SyncLyrics(sourceFile, targetFile)
|
|
|
|
// Check error status
|
|
if tc.expectedError && err == nil {
|
|
t.Errorf("Expected error but got nil")
|
|
} else if !tc.expectedError && err != nil {
|
|
t.Errorf("Unexpected error: %v", err)
|
|
}
|
|
|
|
// If no error is expected, validate the output
|
|
if !tc.expectedError && err == nil {
|
|
tc.validateOutput(t, targetFile)
|
|
}
|
|
})
|
|
}
|
|
}
|