151 lines
4.5 KiB
Go
151 lines
4.5 KiB
Go
package main
|
|
|
|
import (
|
|
"os"
|
|
"path/filepath"
|
|
"reflect"
|
|
"strings"
|
|
"testing"
|
|
)
|
|
|
|
func TestParseSRT(t *testing.T) {
|
|
src := "\uFEFF1\r\n00:00:01,000 --> 00:00:02,500\r\nHello\r\n<i>world</i>\r\n\r\n" +
|
|
"3\r\n00:00:05,5 --> 00:00:06.25 X1:10 X2:20\r\nSecond\r\n" + // short ms, dot, position
|
|
"2\r\n00:00:03,000 --> 00:00:04,000\r\n Missing blank line before \r\n\r\n\r\n" +
|
|
"4\n00:00:07,000 --> 00:00:07,000\nzero length\n\n" +
|
|
"5\n01:02,000 --> 01:03,000\nno hours\n\n" +
|
|
"not a cue\n"
|
|
got := parseSRT(decodeText([]byte(src)))
|
|
want := []Cue{
|
|
{1, 2.5, "Hello\n<i>world</i>"},
|
|
{3, 4, "Missing blank line before"},
|
|
{5.5, 6.25, "Second"},
|
|
{62, 63, "no hours"},
|
|
}
|
|
if !reflect.DeepEqual(got, want) {
|
|
t.Fatalf("parseSRT:\n got %+v\nwant %+v", got, want)
|
|
}
|
|
}
|
|
|
|
func TestDecodeText(t *testing.T) {
|
|
for name, tc := range map[string]struct {
|
|
in []byte
|
|
want string
|
|
}{
|
|
"utf8": {[]byte("caf\u00e9"), "caf\u00e9"},
|
|
"utf8 bom": {[]byte("\xEF\xBB\xBFcaf\u00e9"), "caf\u00e9"},
|
|
"utf16le": {[]byte{0xFF, 0xFE, 'h', 0, 0xE9, 0}, "h\u00e9"},
|
|
"utf16be": {[]byte{0xFE, 0xFF, 0, 'h', 0, 0xE9}, "h\u00e9"},
|
|
"cp1252": {[]byte("\x93caf\xe9\x94 \x80"), "\u201ccaf\u00e9\u201d \u20ac"},
|
|
} {
|
|
if got := decodeText(tc.in); got != tc.want {
|
|
t.Errorf("%s: got %q, want %q", name, got, tc.want)
|
|
}
|
|
}
|
|
}
|
|
|
|
func TestWriteClipCaptions(t *testing.T) {
|
|
cues := []Cue{
|
|
{0.5, 1.5, "before"},
|
|
{9, 11, "spans In"},
|
|
{12.0333, 13, "inside"},
|
|
{19, 25, "spans Out"},
|
|
{30, 31, "after"},
|
|
}
|
|
clips := []clipJob{{in: 10, out: 20, cues: cues}, {in: 40, out: 50, cues: cues}, {in: 0, out: 5}}
|
|
dir, err := writeClipCaptions(clips)
|
|
if dir != "" {
|
|
defer os.RemoveAll(dir)
|
|
}
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
if clips[1].captions != "" || clips[2].captions != "" {
|
|
t.Errorf("clips without captions in range got files: %q, %q", clips[1].captions, clips[2].captions)
|
|
}
|
|
b, err := os.ReadFile(clips[0].captions)
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
want := "1\n00:00:00,000 --> 00:00:01,000\nspans In\n\n" +
|
|
"2\n00:00:02,033 --> 00:00:03,000\ninside\n\n" +
|
|
"3\n00:00:09,000 --> 00:00:10,000\nspans Out\n\n"
|
|
if string(b) != want {
|
|
t.Errorf("clip captions:\n got %q\nwant %q", b, want)
|
|
}
|
|
if again := parseSRT(string(b)); len(again) != 3 {
|
|
t.Errorf("written file parses into %d cues, want 3", len(again))
|
|
}
|
|
}
|
|
|
|
func TestSRTTime(t *testing.T) {
|
|
for sec, want := range map[float64]string{
|
|
0: "00:00:00,000",
|
|
1.0333333: "00:00:01,033",
|
|
2.9999: "00:00:02,999", // rounds down, like the subtitles filter
|
|
0.1 + 0.2: "00:00:00,300", // but not below float noise
|
|
3723.5: "01:02:03,500",
|
|
36000.0005: "10:00:00,000",
|
|
} {
|
|
if got := srtTime(sec); got != want {
|
|
t.Errorf("srtTime(%v) = %s, want %s", sec, got, want)
|
|
}
|
|
}
|
|
}
|
|
|
|
func TestFilterArg(t *testing.T) {
|
|
// Both parsers turn a backslash followed by any character into that
|
|
// character, so undoing the two levels must give back the original.
|
|
unescape := func(s string) string {
|
|
var b strings.Builder
|
|
for i := 0; i < len(s); i++ {
|
|
if s[i] == '\\' && i+1 < len(s) {
|
|
i++
|
|
}
|
|
b.WriteByte(s[i])
|
|
}
|
|
return b.String()
|
|
}
|
|
for _, s := range []string{
|
|
`/tmp/vibedit-captions-1/clip_0001.srt`,
|
|
`C:\Users\Zoë O'Brien\AppData\Local\Temp\vibedit-captions-1\clip_0001.srt`,
|
|
`/weird/[dir];a,b:c'd\e/clip.srt`,
|
|
`Fontsize=16,BorderStyle=3,OutlineColour=&H00000000`,
|
|
} {
|
|
esc := filterArg(s)
|
|
if got := unescape(unescape(esc)); got != s {
|
|
t.Errorf("filterArg(%q) = %q, which unescapes to %q", s, esc, got)
|
|
}
|
|
// After the graph level, no character that ends the option value may
|
|
// be left unescaped.
|
|
lvl1 := unescape(esc)
|
|
for i := 0; i < len(lvl1); i++ {
|
|
if lvl1[i] == '\\' {
|
|
i++
|
|
} else if strings.IndexByte(`':`, lvl1[i]) >= 0 {
|
|
t.Errorf("filterArg(%q): unescaped %q at option level: %q", s, lvl1[i], lvl1)
|
|
}
|
|
}
|
|
}
|
|
if got := filterArg(`C:\a,b`); got != `C\\:\\\\a\,b` {
|
|
t.Errorf("filterArg(`C:\\a,b`) = %s", got)
|
|
}
|
|
}
|
|
|
|
func TestCaptionFilter(t *testing.T) {
|
|
dir := t.TempDir()
|
|
srt := filepath.Join(dir, "clip_0001.srt")
|
|
for _, tc := range []struct {
|
|
w, h int
|
|
want string
|
|
}{
|
|
{1920, 1080, "PlayResX=512\\,PlayResY=288\\,ScaledBorderAndShadow=yes\\,Fontsize=16\\,"},
|
|
{1080, 1920, "PlayResX=288\\,PlayResY=512\\,ScaledBorderAndShadow=yes\\,Fontsize=16\\,"},
|
|
} {
|
|
got := captionFilter(srt, outFormat{W: tc.w, H: tc.h, CaptionSize: "medium", CaptionStyle: "box"})
|
|
if !strings.HasPrefix(got, "subtitles=filename=") || !strings.Contains(got, ":force_style="+tc.want+"BorderStyle=3") {
|
|
t.Errorf("%dx%d: %s", tc.w, tc.h, got)
|
|
}
|
|
}
|
|
}
|