Files
go-astisub/subtitles_test.go

366 lines
14 KiB
Go
Raw Permalink Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
package astisub_test
import (
"bytes"
"os"
"testing"
"time"
"github.com/asticode/go-astisub"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
)
func TestLine_Text(t *testing.T) {
var l = astisub.Line{Items: []astisub.LineItem{{Text: "1"}, {Text: "2"}, {Text: "3"}}}
assert.Equal(t, "123", l.String())
}
func assertSubtitleItems(t *testing.T, i *astisub.Subtitles) {
// No format
assert.Len(t, i.Items, 6)
assert.Equal(t, time.Minute+39*time.Second, i.Items[0].StartAt)
assert.Equal(t, time.Minute+41*time.Second+40*time.Millisecond, i.Items[0].EndAt)
assert.Equal(t, "(deep rumbling)", i.Items[0].Lines[0].String())
assert.Equal(t, 2*time.Minute+4*time.Second+80*time.Millisecond, i.Items[1].StartAt)
assert.Equal(t, 2*time.Minute+7*time.Second+120*time.Millisecond, i.Items[1].EndAt)
assert.Equal(t, "MAN:", i.Items[1].Lines[0].String())
assert.Equal(t, "How did we end up here?", i.Items[1].Lines[1].String())
assert.Equal(t, 2*time.Minute+12*time.Second+160*time.Millisecond, i.Items[2].StartAt)
assert.Equal(t, 2*time.Minute+15*time.Second+200*time.Millisecond, i.Items[2].EndAt)
assert.Equal(t, "This place is horrible.", i.Items[2].Lines[0].String())
assert.Equal(t, 2*time.Minute+20*time.Second+240*time.Millisecond, i.Items[3].StartAt)
assert.Equal(t, 2*time.Minute+22*time.Second+280*time.Millisecond, i.Items[3].EndAt)
assert.Equal(t, "Smells like balls.", i.Items[3].Lines[0].String())
assert.Equal(t, 2*time.Minute+28*time.Second+320*time.Millisecond, i.Items[4].StartAt)
assert.Equal(t, 2*time.Minute+31*time.Second+360*time.Millisecond, i.Items[4].EndAt)
assert.Equal(t, "We don't belong", i.Items[4].Lines[0].String())
assert.Equal(t, "in this shithole.", i.Items[4].Lines[1].String())
assert.Equal(t, 2*time.Minute+31*time.Second+400*time.Millisecond, i.Items[5].StartAt)
assert.Equal(t, 2*time.Minute+33*time.Second+440*time.Millisecond, i.Items[5].EndAt)
assert.Equal(t, "(computer playing", i.Items[5].Lines[0].String())
assert.Equal(t, "electronic melody)", i.Items[5].Lines[1].String())
}
func mockSubtitles() *astisub.Subtitles {
return &astisub.Subtitles{Items: []*astisub.Item{{EndAt: 3 * time.Second, StartAt: time.Second, Lines: []astisub.Line{{Items: []astisub.LineItem{{Text: "subtitle-1"}}}}}, {EndAt: 7 * time.Second, StartAt: 3 * time.Second, Lines: []astisub.Line{{Items: []astisub.LineItem{{Text: "subtitle-2"}}}}}}}
}
func TestSubtitles_Add(t *testing.T) {
var s = mockSubtitles()
s.Add(time.Second)
assert.Len(t, s.Items, 2)
assert.Equal(t, 2*time.Second, s.Items[0].StartAt)
assert.Equal(t, 4*time.Second, s.Items[0].EndAt)
assert.Equal(t, 2*time.Second, s.Items[0].StartAt)
assert.Equal(t, 4*time.Second, s.Items[0].EndAt)
s.Add(-3 * time.Second)
assert.Len(t, s.Items, 2)
assert.Equal(t, time.Duration(0), s.Items[0].StartAt)
assert.Equal(t, time.Second, s.Items[0].EndAt)
s.Add(-2 * time.Second)
assert.Len(t, s.Items, 1)
assert.Equal(t, "subtitle-2", s.Items[0].Lines[0].Items[0].Text)
}
func TestSubtitles_Duration(t *testing.T) {
assert.Equal(t, time.Duration(0), astisub.Subtitles{}.Duration())
assert.Equal(t, 7*time.Second, mockSubtitles().Duration())
}
func TestSubtitles_IsEmpty(t *testing.T) {
assert.True(t, astisub.Subtitles{}.IsEmpty())
assert.False(t, mockSubtitles().IsEmpty())
}
func TestSubtitles_ForceDuration(t *testing.T) {
var s = mockSubtitles()
s.ForceDuration(10*time.Second, false)
assert.Len(t, s.Items, 2)
s = mockSubtitles()
s.ForceDuration(10*time.Second, true)
assert.Len(t, s.Items, 3)
assert.Equal(t, 10*time.Second, s.Items[2].EndAt)
assert.Equal(t, 10*time.Second-time.Millisecond, s.Items[2].StartAt)
assert.Equal(t, []astisub.Line{{Items: []astisub.LineItem{{Text: "..."}}}}, s.Items[2].Lines)
s.Items[2].StartAt = 7 * time.Second
s.Items[2].EndAt = 12 * time.Second
s.ForceDuration(10*time.Second, true)
assert.Len(t, s.Items, 3)
assert.Equal(t, 10*time.Second, s.Items[2].EndAt)
assert.Equal(t, 7*time.Second, s.Items[2].StartAt)
}
func TestSubtitles_Fragment(t *testing.T) {
// Init
var s = mockSubtitles()
// Fragment
s.Fragment(2 * time.Second)
assert.Len(t, s.Items, 5)
assert.Equal(t, time.Second, s.Items[0].StartAt)
assert.Equal(t, 2*time.Second, s.Items[0].EndAt)
assert.Equal(t, []astisub.Line{{Items: []astisub.LineItem{{Text: "subtitle-1"}}}}, s.Items[0].Lines)
assert.Equal(t, 2*time.Second, s.Items[1].StartAt)
assert.Equal(t, 3*time.Second, s.Items[1].EndAt)
assert.Equal(t, []astisub.Line{{Items: []astisub.LineItem{{Text: "subtitle-1"}}}}, s.Items[1].Lines)
assert.Equal(t, 3*time.Second, s.Items[2].StartAt)
assert.Equal(t, 4*time.Second, s.Items[2].EndAt)
assert.Equal(t, []astisub.Line{{Items: []astisub.LineItem{{Text: "subtitle-2"}}}}, s.Items[2].Lines)
assert.Equal(t, 4*time.Second, s.Items[3].StartAt)
assert.Equal(t, 6*time.Second, s.Items[3].EndAt)
assert.Equal(t, []astisub.Line{{Items: []astisub.LineItem{{Text: "subtitle-2"}}}}, s.Items[3].Lines)
assert.Equal(t, 6*time.Second, s.Items[4].StartAt)
assert.Equal(t, 7*time.Second, s.Items[4].EndAt)
assert.Equal(t, []astisub.Line{{Items: []astisub.LineItem{{Text: "subtitle-2"}}}}, s.Items[4].Lines)
// Unfragment
s.Items = append(s.Items[:4], append([]*astisub.Item{{EndAt: 5 * time.Second, Lines: []astisub.Line{{Items: []astisub.LineItem{{Text: "subtitle-3"}}}}, StartAt: 4 * time.Second}}, s.Items[4:]...)...)
s.Unfragment()
assert.Len(t, s.Items, 3)
assert.Equal(t, "subtitle-1", s.Items[0].String())
assert.Equal(t, time.Second, s.Items[0].StartAt)
assert.Equal(t, 3*time.Second, s.Items[0].EndAt)
assert.Equal(t, "subtitle-2", s.Items[1].String())
assert.Equal(t, 3*time.Second, s.Items[1].StartAt)
assert.Equal(t, 7*time.Second, s.Items[1].EndAt)
assert.Equal(t, "subtitle-3", s.Items[2].String())
assert.Equal(t, 4*time.Second, s.Items[2].StartAt)
assert.Equal(t, 5*time.Second, s.Items[2].EndAt)
}
func TestSubtitles_Unfragment(t *testing.T) {
itemText := func(s string) []astisub.Line {
return []astisub.Line{{Items: []astisub.LineItem{{Text: s}}}}
}
items := []*astisub.Item{{
Lines: itemText("subtitle-1"),
StartAt: 1 * time.Second,
EndAt: 2 * time.Second,
}, {
Lines: itemText("subtitle-2"),
StartAt: 2 * time.Second,
EndAt: 5 * time.Second,
}, {
Lines: itemText("subtitle-3"),
StartAt: 3 * time.Second,
EndAt: 4 * time.Second,
}, {
// gap and nested within first subtitle-2; should not override end time
Lines: itemText("subtitle-2"),
StartAt: 3 * time.Second,
EndAt: 4 * time.Second,
}, {
Lines: itemText("subtitle-3"),
// gap and start time equals previous end time
StartAt: 4 * time.Second,
EndAt: 5 * time.Second,
}, {
// should not be combined
Lines: itemText("subtitle-3"),
StartAt: 6 * time.Second,
EndAt: 7 * time.Second,
}, {
// test correcting for out-of-orderness
Lines: itemText("subtitle-1"),
StartAt: 0 * time.Second,
EndAt: 3 * time.Second,
}}
s := &astisub.Subtitles{Items: items}
s.Unfragment()
expected := []astisub.Item{{
Lines: itemText("subtitle-1"),
StartAt: 0 * time.Second,
EndAt: 3 * time.Second,
}, {
Lines: itemText("subtitle-2"),
StartAt: 2 * time.Second,
EndAt: 5 * time.Second,
}, {
Lines: itemText("subtitle-3"),
StartAt: 3 * time.Second,
EndAt: 5 * time.Second,
}, {
Lines: itemText("subtitle-3"),
StartAt: 6 * time.Second,
EndAt: 7 * time.Second,
}}
assert.Equal(t, len(expected), len(s.Items))
for i := range expected {
assert.Equal(t, expected[i], *s.Items[i])
}
}
func TestSubtitles_Merge(t *testing.T) {
var s1 = &astisub.Subtitles{Items: []*astisub.Item{{EndAt: 3 * time.Second, StartAt: time.Second}, {EndAt: 8 * time.Second, StartAt: 5 * time.Second}, {EndAt: 12 * time.Second, StartAt: 10 * time.Second}}, Regions: map[string]*astisub.Region{"region_0": {ID: "region_0"}, "region_1": {ID: "region_1"}}, Styles: map[string]*astisub.Style{"style_0": {ID: "style_0"}, "style_1": {ID: "style_1"}}}
var s2 = &astisub.Subtitles{Items: []*astisub.Item{{EndAt: 4 * time.Second, StartAt: 2 * time.Second}, {EndAt: 7 * time.Second, StartAt: 6 * time.Second}, {EndAt: 11 * time.Second, StartAt: 9 * time.Second}, {EndAt: 14 * time.Second, StartAt: 13 * time.Second}}, Regions: map[string]*astisub.Region{"region_1": {ID: "region_1"}, "region_2": {ID: "region_2"}}, Styles: map[string]*astisub.Style{"style_1": {ID: "style_1"}, "style_2": {ID: "style_2"}}}
s1.Merge(s2)
assert.Len(t, s1.Items, 7)
assert.Equal(t, &astisub.Item{EndAt: 3 * time.Second, StartAt: time.Second}, s1.Items[0])
assert.Equal(t, &astisub.Item{EndAt: 4 * time.Second, StartAt: 2 * time.Second}, s1.Items[1])
assert.Equal(t, &astisub.Item{EndAt: 8 * time.Second, StartAt: 5 * time.Second}, s1.Items[2])
assert.Equal(t, &astisub.Item{EndAt: 7 * time.Second, StartAt: 6 * time.Second}, s1.Items[3])
assert.Equal(t, &astisub.Item{EndAt: 11 * time.Second, StartAt: 9 * time.Second}, s1.Items[4])
assert.Equal(t, &astisub.Item{EndAt: 12 * time.Second, StartAt: 10 * time.Second}, s1.Items[5])
assert.Equal(t, &astisub.Item{EndAt: 14 * time.Second, StartAt: 13 * time.Second}, s1.Items[6])
assert.Equal(t, len(s1.Regions), 3)
assert.Equal(t, len(s1.Styles), 3)
}
func TestSubtitles_Optimize(t *testing.T) {
var s = &astisub.Subtitles{
Items: []*astisub.Item{
{Region: &astisub.Region{ID: "1"}},
{Style: &astisub.Style{ID: "1"}},
{Lines: []astisub.Line{{Items: []astisub.LineItem{{Style: &astisub.Style{ID: "2"}}}}}},
},
Regions: map[string]*astisub.Region{
"1": {ID: "1", Style: &astisub.Style{ID: "3"}},
"2": {ID: "2", Style: &astisub.Style{ID: "4"}},
},
Styles: map[string]*astisub.Style{
"1": {ID: "1"},
"2": {ID: "2"},
"3": {ID: "3"},
"4": {ID: "4"},
"5": {ID: "5"},
},
}
s.Optimize()
assert.Len(t, s.Regions, 1)
assert.Len(t, s.Styles, 3)
}
func TestSubtitles_Order(t *testing.T) {
var s = &astisub.Subtitles{Items: []*astisub.Item{{StartAt: 4 * time.Second, EndAt: 5 * time.Second}, {StartAt: 2 * time.Second, EndAt: 3 * time.Second}, {StartAt: 3 * time.Second, EndAt: 4 * time.Second}, {StartAt: time.Second, EndAt: 2 * time.Second}}}
s.Order()
assert.Equal(t, time.Second, s.Items[0].StartAt)
assert.Equal(t, 2*time.Second, s.Items[0].EndAt)
assert.Equal(t, 2*time.Second, s.Items[1].StartAt)
assert.Equal(t, 3*time.Second, s.Items[1].EndAt)
assert.Equal(t, 3*time.Second, s.Items[2].StartAt)
assert.Equal(t, 4*time.Second, s.Items[2].EndAt)
assert.Equal(t, 4*time.Second, s.Items[3].StartAt)
assert.Equal(t, 5*time.Second, s.Items[3].EndAt)
}
func TestSubtitles_RemoveStyling(t *testing.T) {
s := &astisub.Subtitles{
Items: []*astisub.Item{
{
Lines: []astisub.Line{{
Items: []astisub.LineItem{{
InlineStyle: &astisub.StyleAttributes{},
Style: &astisub.Style{},
}},
}},
InlineStyle: &astisub.StyleAttributes{},
Region: &astisub.Region{},
Style: &astisub.Style{},
},
},
Regions: map[string]*astisub.Region{"region": {}},
Styles: map[string]*astisub.Style{"style": {}},
}
s.RemoveStyling()
assert.Equal(t, &astisub.Subtitles{
Items: []*astisub.Item{
{
Lines: []astisub.Line{{
Items: []astisub.LineItem{{}},
}},
},
},
Regions: map[string]*astisub.Region{},
Styles: map[string]*astisub.Style{},
}, s)
}
func TestSubtitles_ApplyLinearCorrection(t *testing.T) {
s := &astisub.Subtitles{Items: []*astisub.Item{
{
EndAt: 2 * time.Second,
StartAt: 1 * time.Second,
},
{
EndAt: 5 * time.Second,
StartAt: 3 * time.Second,
},
{
EndAt: 10 * time.Second,
StartAt: 7 * time.Second,
},
}}
s.ApplyLinearCorrection(3*time.Second, 5*time.Second, 5*time.Second, 8*time.Second)
require.Equal(t, 2*time.Second, s.Items[0].StartAt)
require.Equal(t, 3500*time.Millisecond, s.Items[0].EndAt)
require.Equal(t, 5*time.Second, s.Items[1].StartAt)
require.Equal(t, 8*time.Second, s.Items[1].EndAt)
require.Equal(t, 11*time.Second, s.Items[2].StartAt)
require.Equal(t, 15500*time.Millisecond, s.Items[2].EndAt)
}
func TestHTMLEntity(t *testing.T) {
exts := []string{"srt", "vtt"}
for _, ext := range exts {
// Read input with entities
s, err := astisub.OpenFile("./testdata/example-in-html-entities." + ext)
assert.NoError(t, err)
assert.Len(t, s.Items, 3)
assert.Equal(t, 331*time.Millisecond, s.Items[0].StartAt)
assert.Equal(t, 3*time.Second+750*time.Millisecond, s.Items[0].EndAt)
assert.Equal(t, "The man in black fled across the desert, \u00A0", s.Items[0].Lines[0].String())
assert.Equal(t, "& the gunslinger followed.", s.Items[0].Lines[1].String())
assert.Equal(t, 4*time.Second+101*time.Millisecond, s.Items[1].StartAt)
assert.Equal(t, 5*time.Second+430*time.Millisecond, s.Items[1].EndAt)
assert.Equal(t, "Go,\u00A0then,", s.Items[1].Lines[0].String())
assert.Equal(t, 6*time.Second+331*time.Millisecond, s.Items[2].StartAt)
assert.Equal(t, 9*time.Second+675*time.Millisecond, s.Items[2].EndAt)
assert.Equal(t, "there are other < worlds than these.", s.Items[2].Lines[0].String())
//Write to srt
w := &bytes.Buffer{}
c, err := os.ReadFile("./testdata/example-out-html-entities.srt")
assert.NoError(t, err)
err = s.WriteToSRT(w)
assert.NoError(t, err)
assert.Equal(t, string(c), w.String())
//Write WebVTT
w = &bytes.Buffer{}
c, err = os.ReadFile("./testdata/example-out-html-entities.vtt")
assert.NoError(t, err)
err = s.WriteToWebVTT(w)
assert.NoError(t, err)
assert.Equal(t, string(c), w.String())
}
}
func TestNewScanner(t *testing.T) {
exts := []string{"vtt", "srt", "ssa"}
for _, ext := range exts {
s, err := astisub.OpenFile("./testdata/example-in-carriage-return." + ext)
assert.NoError(t, err)
assert.Len(t, s.Items, 3)
assert.Equal(t, time.Duration(0), s.Items[0].StartAt)
assert.Equal(t, 3*time.Second+766*time.Millisecond, s.Items[0].EndAt)
assert.Equal(t, "Did one of the last stories strike you as", s.Items[0].Lines[0].String())
assert.Equal(t, "more interesting than the other?", s.Items[0].Lines[1].String())
assert.Equal(t, 3*time.Second+767*time.Millisecond, s.Items[1].StartAt)
assert.Equal(t, 10*time.Second+732*time.Millisecond, s.Items[1].EndAt)
assert.Equal(t, "That's true. You don’t often find 632", s.Items[1].Lines[0].String())
assert.Equal(t, "pieces of gum stuck on a sidewalk", s.Items[1].Lines[1].String())
assert.Equal(t, 10*time.Second+733*time.Millisecond, s.Items[2].StartAt)
assert.Equal(t, 14*time.Second+66*time.Millisecond, s.Items[2].EndAt)
assert.Equal(t, "at a busy bus stop or anywhere", s.Items[2].Lines[0].String())
assert.Equal(t, "else for that matter.", s.Items[2].Lines[1].String())
}
}