• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /* GStreamer unit tests for subparse
2  * Copyright (C) 2006-2008 Tim-Philipp Müller <tim centricular net>
3  *
4  * This library is free software; you can redistribute it and/or
5  * modify it under the terms of the GNU Library General Public
6  * License as published by the Free Software Foundation; either
7  * version 2 of the License, or (at your option) any later version.
8  *
9  * This library is distributed in the hope that it will be useful,
10  * but WITHOUT ANY WARRANTY; without even the implied warranty of
11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
12  * Library General Public License for more details.
13  *
14  * You should have received a copy of the GNU Library General Public
15  * License along with this library; if not, write to the
16  * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor,
17  * Boston, MA 02110-1301, USA.
18  */
19 
20 #ifdef HAVE_CONFIG_H
21 # include <config.h>
22 #endif
23 
24 #include <gst/check/gstcheck.h>
25 
26 #include <string.h>
27 
28 static GstStaticPadTemplate sinktemplate = GST_STATIC_PAD_TEMPLATE ("sink",
29     GST_PAD_SINK,
30     GST_PAD_ALWAYS,
31     GST_STATIC_CAPS ("text/x-raw, format = { pango-markup, utf8 }")
32     );
33 static GstStaticPadTemplate srctemplate = GST_STATIC_PAD_TEMPLATE ("src",
34     GST_PAD_SRC,
35     GST_PAD_ALWAYS,
36     GST_STATIC_CAPS ("ANY")
37     );
38 
39 static GstElement *subparse;
40 static GstPad *mysrcpad, *mysinkpad;
41 
42 static GstBuffer *
buffer_from_static_string(const gchar * s)43 buffer_from_static_string (const gchar * s)
44 {
45   GstBuffer *buf;
46   gsize len;
47 
48   len = strlen (s);
49 
50   buf = gst_buffer_new ();
51   gst_buffer_append_memory (buf,
52       gst_memory_new_wrapped (GST_MEMORY_FLAG_READONLY,
53           (gpointer) s, len, 0, len, NULL, NULL));
54 
55   return buf;
56 }
57 
58 typedef struct
59 {
60   const gchar *in;
61   GstClockTime from_ts;
62   GstClockTime to_ts;
63   const gchar *out;
64 } SubParseInputChunk;
65 
66 static SubParseInputChunk srt_input[] = {
67   {
68         "1\n00:00:01,000 --> 00:00:02,000\nOne\n\n",
69       1 * GST_SECOND, 2 * GST_SECOND, "One"}, {
70         "2\n00:00:02,000 --> 00:00:03,000\nTwo\n\n",
71       2 * GST_SECOND, 3 * GST_SECOND, "Two"}, {
72         "3\n00:00:03,000 --> 00:00:04,000\nThree\n\n",
73       3 * GST_SECOND, 4 * GST_SECOND, "Three"}, {
74         "4\n00:00:04,000 --> 00:00:05,000\nFour\n\n",
75       4 * GST_SECOND, 5 * GST_SECOND, "Four"}, {
76         "5\n00:00:05,000 --> 00:00:06,000\nFive\n\n",
77       5 * GST_SECOND, 6 * GST_SECOND, "Five"}, {
78         /* markup should be preserved */
79         "6\n00:00:06,000 --> 00:00:07,000\n<i>Six</i>\n\n",
80       6 * GST_SECOND, 7 * GST_SECOND, "<i>Six</i>"}, {
81         /* open markup tags should be closed */
82         "7\n00:00:07,000 --> 00:00:08,000\n<i>Seven\n\n",
83       7 * GST_SECOND, 8 * GST_SECOND, "<i>Seven</i>"}, {
84         /* open markup tags should be closed (II) */
85         "8\n00:00:08,000 --> 00:00:09,000\n<b><i>Eight\n\n",
86       8 * GST_SECOND, 9 * GST_SECOND, "<b><i>Eight</i></b>"}, {
87         /* broken markup should be fixed */
88         "9\n00:00:09,000 --> 00:00:10,000\n</b>\n\n",
89       9 * GST_SECOND, 10 * GST_SECOND, ""}, {
90         "10\n00:00:10,000 --> 00:00:11,000\n</b></i>\n\n",
91       10 * GST_SECOND, 11 * GST_SECOND, ""}, {
92         "11\n00:00:11,000 --> 00:00:12,000\n<i>xyz</b></i>\n\n",
93       11 * GST_SECOND, 12 * GST_SECOND, "<i>xyz</i>"}, {
94         "12\n00:00:12,000 --> 00:00:13,000\n<i>xyz</b>\n\n",
95       12 * GST_SECOND, 13 * GST_SECOND, "<i>xyz</i>"}, {
96         "13\n00:00:13,000 --> 00:00:14,000\n<i><i><i><i><i><i><i><i><i><i><i><i><i><i><i><i><i><i><i><i><i><i><i><i><i><i><i><i><i><i><i><i><i>Keep them comiiiiiing\n\n",
97         13 * GST_SECOND, 14 * GST_SECOND,
98       "<i><i><i><i><i><i><i><i><i><i><i><i><i><i><i><i><i><i><i><i><i><i><i><i><i><i><i><i><i><i><i><i><i>Keep them comiiiiiing</i></i></i></i></i></i></i></i></i></i></i></i></i></i></i></i></i></i></i></i></i></i></i></i></i></i></i></i></i></i></i></i></i>"}, {
99         /* skip a few chunk numbers here, the numbers shouldn't matter */
100         "24\n00:01:00,000 --> 00:02:00,000\nYep, still here\n\n",
101       60 * GST_SECOND, 120 * GST_SECOND, "Yep, still here"}, {
102         /* make sure stuff is escaped properly, but allowed markup stays intact */
103         "25\n00:03:00,000 --> 00:04:00,000\ngave <i>Rock & Roll</i> to\n\n",
104       180 * GST_SECOND, 240 * GST_SECOND, "gave <i>Rock &amp; Roll</i> to"}, {
105         "26\n00:04:00,000 --> 00:05:00,000\n<i>Rock & Roll</i>\n\n",
106       240 * GST_SECOND, 300 * GST_SECOND, "<i>Rock &amp; Roll</i>"}, {
107         "27\n00:06:00,000 --> 00:08:00,000\nRock & Roll\n\n",
108       360 * GST_SECOND, 480 * GST_SECOND, "Rock &amp; Roll"}, {
109         "28\n00:10:00,000 --> 00:11:00,000\n"
110         "<font \"#0000FF\"><joj>This is </xxx>in blue but <5</font>\n\n",
111       600 * GST_SECOND, 660 * GST_SECOND, "This is in blue but &lt;5"}, {
112         /* closing tags should be recognised properly even if there's a space */
113         "29\n00:11:00,000 --> 00:12:00,000\n" "<i>italics</ i>\n\n",
114       660 * GST_SECOND, 720 * GST_SECOND, "<i>italics</i>"}, {
115         /* closing tags should be escaped and fixed up if not recognised */
116         "30\n00:12:00,000 --> 00:12:01,000\n" "<i>italics</ x>\n\n",
117       720 * GST_SECOND, 721 * GST_SECOND, "<i>italics&lt;/ x&gt;</i>"},
118 };
119 
120 /* starts with chunk number 0 (not exactly according to spec) */
121 static SubParseInputChunk srt_input0[] = {
122   {
123         "0\n00:00:01,000 --> 00:00:02,000\nOne\n\n",
124       1 * GST_SECOND, 2 * GST_SECOND, "One"}, {
125         "1\n00:00:02,000 --> 00:00:03,000\nTwo\n\n",
126       2 * GST_SECOND, 3 * GST_SECOND, "Two"}, {
127         "2\n00:00:03,000 --> 00:00:04,000\nThree\n\n",
128       3 * GST_SECOND, 4 * GST_SECOND, "Three"}
129 };
130 
131 /* has spaces instead of doubled zeroes (not exactly according to spec) */
132 static SubParseInputChunk srt_input1[] = {
133   {
134         "1\n 0: 0:26, 26 --> 0: 0:28, 17\nI cant see.\n\n",
135         26 * GST_SECOND + 26 * GST_MSECOND,
136       28 * GST_SECOND + 17 * GST_MSECOND, "I cant see."},
137   {
138         "2\n 0: 0:30, 30 --> 0: 0:33, 22\nI really cant see.\n\n",
139         30 * GST_SECOND + 30 * GST_MSECOND,
140       33 * GST_SECOND + 22 * GST_MSECOND, "I really cant see."},
141   {
142         "3\n 0: 0:40, 40 --> 0: 0:44, 44\nI still cant see anything.\n\n",
143         40 * GST_SECOND + 40 * GST_MSECOND,
144       44 * GST_SECOND + 44 * GST_MSECOND, "I still cant see anything."}
145 };
146 
147 /* has UTF-8 BOM at the start */
148 static SubParseInputChunk srt_input2[] = {
149   {
150         "\xef\xbb\xbf" "1\n00:00:00,000 --> 00:00:03,50\nJust testing.\n\n",
151       0, 3 * GST_SECOND + 500 * GST_MSECOND, "Just testing."}
152 };
153 
154 /* starts with chunk number 0 and has less than three digits after the comma
155  * and a few extra spaces before the arrow or at the end of the line */
156 static SubParseInputChunk srt_input3[] = {
157   {
158         "0\n00:00:01,0 --> 00:00:02,0\nOne\n\n",
159       1000 * GST_MSECOND, 2000 * GST_MSECOND, "One"}, {
160         "1\n00:00:02,5   --> 00:00:03,  5 \nTwo\n\n",
161       2500 * GST_MSECOND, 3005 * GST_MSECOND, "Two"}, {
162         "2\n00:00:03, 9 --> 00:00:04,0   \nThree\n\n",
163       3090 * GST_MSECOND, 4000 * GST_MSECOND, "Three"}
164 };
165 
166 /* Some WebVTT chunks, this format is similar to SRT but should be
167  * parsed differently nonetheless, the WebVTT tags should be stripped
168  * off. */
169 static SubParseInputChunk srt_input4[] = {
170   {
171         "1\n00:00:01,000 --> 00:00:02,000\n<v>some text\n\n",
172       1 * GST_SECOND, 2 * GST_SECOND, "some text"}
173   ,
174   {
175         "1\n00:00:01,000 --> 00:00:02,000\n<b.loud>some text\n\n",
176       1 * GST_SECOND, 2 * GST_SECOND, "<b>some text</b>"}
177   ,
178   {
179         "1\n00:00:01,000 --> 00:00:02,000\n<ruby>base text<rt>annotation</rt></ruby>\n\n",
180         1 * GST_SECOND, 2 * GST_SECOND,
181       "base textannotation"}
182   ,
183 };
184 
185 /* Test broken timestamp */
186 static SubParseInputChunk srt_input5[] = {
187   {
188         "1\n00:00:01,000 --> 00:00:02,000\n<v>some text\n\n",
189       1 * GST_SECOND, 2 * GST_SECOND, "some text"}
190   ,
191   {
192         "2\n00:02:00,000 --> 00:03:0\n<v>some other text\n\n3\n00:00:03,000 --> 00:00:04,000\n<v>some more text\n\n",
193       3 * GST_SECOND, 4 * GST_SECOND, "some more text"}
194   ,
195 };
196 
197 /* Test with no newline at the end */
198 static SubParseInputChunk srt_input6[] = {
199   {
200         "1\n00:00:01,000 --> 00:00:02,000\nLast cue, no newline at the end",
201       1 * GST_SECOND, 2 * GST_SECOND, "Last cue, no newline at the end"}
202   ,
203 };
204 
205 
206 static void
setup_subparse(void)207 setup_subparse (void)
208 {
209   GstSegment segment;
210   subparse = gst_check_setup_element ("subparse");
211 
212   mysrcpad = gst_check_setup_src_pad (subparse, &srctemplate);
213   mysinkpad = gst_check_setup_sink_pad (subparse, &sinktemplate);
214 
215   gst_pad_set_active (mysrcpad, TRUE);
216 
217   gst_segment_init (&segment, GST_FORMAT_BYTES);
218   gst_pad_push_event (mysrcpad, gst_event_new_stream_start ("test"));
219   gst_pad_push_event (mysrcpad, gst_event_new_segment (&segment));
220   gst_pad_set_active (mysinkpad, TRUE);
221 
222   fail_unless_equals_int (gst_element_set_state (subparse, GST_STATE_PLAYING),
223       GST_STATE_CHANGE_SUCCESS);
224 }
225 
226 static void
teardown_subparse(void)227 teardown_subparse (void)
228 {
229   GST_DEBUG ("cleaning up");
230 
231   g_list_foreach (buffers, (GFunc) gst_mini_object_unref, NULL);
232   g_list_free (buffers);
233   buffers = NULL;
234 
235   gst_pad_set_active (mysrcpad, FALSE);
236   gst_pad_set_active (mysinkpad, FALSE);
237   gst_check_teardown_sink_pad (subparse);
238   gst_check_teardown_src_pad (subparse);
239   gst_check_teardown_element (subparse);
240   subparse = NULL;
241   mysrcpad = NULL;
242   mysinkpad = NULL;
243 }
244 
245 static void
test_srt_do_test(SubParseInputChunk * input,guint start_idx,guint num)246 test_srt_do_test (SubParseInputChunk * input, guint start_idx, guint num)
247 {
248   guint n;
249   GstCaps *outcaps;
250 
251   GST_LOG ("srt test: start_idx = %u, num = %u", start_idx, num);
252 
253   setup_subparse ();
254 
255   for (n = start_idx; n < start_idx + num; ++n) {
256     GstBuffer *buf;
257 
258     buf = buffer_from_static_string (input[n].in);
259     fail_unless_equals_int (gst_pad_push (mysrcpad, buf), GST_FLOW_OK);
260   }
261 
262   gst_pad_push_event (mysrcpad, gst_event_new_eos ());
263 
264   fail_unless_equals_int (g_list_length (buffers), num);
265 
266   outcaps = gst_pad_get_current_caps (mysinkpad);
267 
268   for (n = start_idx; n < start_idx + num; ++n) {
269     const GstStructure *buffer_caps_struct;
270     GstBuffer *buf;
271     GstMapInfo map;
272 
273     buf = g_list_nth_data (buffers, n - start_idx);
274     fail_unless (buf != NULL);
275     fail_unless (GST_BUFFER_TIMESTAMP_IS_VALID (buf), NULL);
276     fail_unless (GST_BUFFER_DURATION_IS_VALID (buf), NULL);
277     fail_unless_equals_uint64 (GST_BUFFER_TIMESTAMP (buf), input[n].from_ts);
278     fail_unless_equals_uint64 (GST_BUFFER_DURATION (buf),
279         input[n].to_ts - input[n].from_ts);
280 
281     gst_buffer_map (buf, &map, GST_MAP_READ);
282     /* can be NULL */
283     if (map.data != NULL) {
284       /* shouldn't have trailing newline characters */
285       fail_if (map.size > 0 && map.data[map.size - 1] == '\n');
286       /* shouldn't include NUL-terminator in data size */
287       fail_if (map.size > 0 && map.data[map.size - 1] == '\0');
288       /* but should still have a  NUL-terminator behind the declared data */
289       fail_unless_equals_int (map.data[map.size], '\0');
290       /* make sure out string matches expected string */
291       fail_unless_equals_string ((gchar *) map.data, input[n].out);
292     }
293     gst_buffer_unmap (buf, &map);
294     /* check caps */
295     fail_unless (outcaps != NULL);
296     buffer_caps_struct = gst_caps_get_structure (outcaps, 0);
297     fail_unless (gst_structure_has_name (buffer_caps_struct, "text/x-raw"));
298     fail_unless_equals_string (gst_structure_get_string (buffer_caps_struct,
299             "format"), "pango-markup");
300   }
301   gst_caps_unref (outcaps);
302 
303   teardown_subparse ();
304 }
305 
306 static void
test_vtt_do_test(SubParseInputChunk * input,guint start_idx,guint num)307 test_vtt_do_test (SubParseInputChunk * input, guint start_idx, guint num)
308 {
309   guint n;
310 
311   GST_LOG ("vtt test: start_idx = %u, num = %u", start_idx, num);
312 
313   setup_subparse ();
314 
315   for (n = start_idx; n < start_idx + num; ++n) {
316     GstBuffer *buf;
317     gchar *data = g_strconcat ("WEBVTT FILE\n", input[n].in, NULL);
318     buf = buffer_from_static_string (data);
319     fail_unless_equals_int (gst_pad_push (mysrcpad, buf), GST_FLOW_OK);
320     g_free (data);
321   }
322 
323   gst_pad_push_event (mysrcpad, gst_event_new_eos ());
324 
325   fail_unless_equals_int (g_list_length (buffers), num);
326 
327   for (n = start_idx; n < start_idx + num; ++n) {
328     const GstStructure *buffer_caps_struct;
329     GstMapInfo map;
330     GstBuffer *buf;
331     GstCaps *outcaps;
332     gchar *out;
333     guint out_size;
334 
335     buf = g_list_nth_data (buffers, n - start_idx);
336     fail_unless (buf != NULL);
337     fail_unless (GST_BUFFER_TIMESTAMP_IS_VALID (buf), NULL);
338     fail_unless (GST_BUFFER_DURATION_IS_VALID (buf), NULL);
339     fail_unless_equals_uint64 (GST_BUFFER_TIMESTAMP (buf), input[n].from_ts);
340     fail_unless_equals_uint64 (GST_BUFFER_DURATION (buf),
341         input[n].to_ts - input[n].from_ts);
342     fail_unless (gst_buffer_map (buf, &map, GST_MAP_READ));
343     out = (gchar *) map.data;
344 
345     out_size = gst_buffer_get_size (buf);
346     /* shouldn't have trailing newline characters */
347     fail_if (out_size > 0 && out[out_size - 1] == '\n');
348     /* shouldn't include NUL-terminator in data size */
349     fail_if (out_size > 0 && out[out_size - 1] == '\0');
350     /* but should still have a  NUL-terminator behind the declared data */
351     fail_unless_equals_int (out[out_size], '\0');
352     /* make sure out string matches expected string */
353     fail_unless_equals_string (out, input[n].out);
354 
355     gst_buffer_unmap (buf, &map);
356 
357     /* check caps */
358     outcaps = gst_pad_get_current_caps (mysinkpad);
359     fail_unless (outcaps != NULL);
360     buffer_caps_struct = gst_caps_get_structure (outcaps, 0);
361     fail_unless_equals_string (gst_structure_get_name (buffer_caps_struct),
362         "text/x-raw");
363     fail_unless_equals_string (gst_structure_get_string (buffer_caps_struct,
364             "format"), "pango-markup");
365     gst_caps_unref (outcaps);
366   }
367 
368   teardown_subparse ();
369 }
370 
GST_START_TEST(test_srt)371 GST_START_TEST (test_srt)
372 {
373   test_srt_do_test (srt_input, 0, G_N_ELEMENTS (srt_input));
374 
375   /* make sure everything works fine if we don't start with chunk 1 */
376   test_srt_do_test (srt_input, 1, G_N_ELEMENTS (srt_input) - 1);
377   test_srt_do_test (srt_input, 2, G_N_ELEMENTS (srt_input) - 2);
378   test_srt_do_test (srt_input, 3, G_N_ELEMENTS (srt_input) - 3);
379   test_srt_do_test (srt_input, 4, G_N_ELEMENTS (srt_input) - 4);
380 
381   /* try with empty input, immediate EOS */
382   test_srt_do_test (srt_input, 5, G_N_ELEMENTS (srt_input) - 5);
383 
384   /* try with chunk number 0 (which is not exactly according to spec) */
385   test_srt_do_test (srt_input0, 0, G_N_ELEMENTS (srt_input0));
386 
387   /* try with spaces instead of doubled zeroes (which is not exactly according to spec) */
388   test_srt_do_test (srt_input1, 0, G_N_ELEMENTS (srt_input1));
389 
390   /* try with UTF-8 BOM at the start */
391   test_srt_do_test (srt_input2, 0, G_N_ELEMENTS (srt_input2));
392 
393   /* try with fewer than three post-comma digits, and some extra spaces */
394   test_srt_do_test (srt_input3, 0, G_N_ELEMENTS (srt_input3));
395 
396   /* try with some WebVTT chunks */
397   test_srt_do_test (srt_input4, 0, G_N_ELEMENTS (srt_input4));
398 
399   /* try with some broken/cut-off timestamp */
400   test_srt_do_test (srt_input5, 0, G_N_ELEMENTS (srt_input5));
401 
402   /* try without an empty line at the end */
403   test_srt_do_test (srt_input6, 0, G_N_ELEMENTS (srt_input6));
404 }
405 
406 GST_END_TEST;
407 
408 
GST_START_TEST(test_webvtt)409 GST_START_TEST (test_webvtt)
410 {
411   SubParseInputChunk webvtt_input[] = {
412     {
413           "1\n00:00:01.000 --> 00:00:02.000 D:vertical T:50%\nOne\n\n",
414         1 * GST_SECOND, 2 * GST_SECOND, "One"}
415     ,
416     {
417           "1\n00:00:01.000 --> 00:00:02.000 D:vertical   T:50%\nOne\n\n",
418         1 * GST_SECOND, 2 * GST_SECOND, "One"}
419     ,
420     {
421           "1\n00:00:01.000 --> 00:00:02.000 D:vertical\tT:50%\nOne\n\n",
422         1 * GST_SECOND, 2 * GST_SECOND, "One"}
423     ,
424     {
425           "1\n00:00:01.000 --> 00:00:02.000 D:vertical-lr\nOne\n\n",
426         1 * GST_SECOND, 2 * GST_SECOND, "One"}
427     ,
428     {
429           "1\n00:00:01.000 --> 00:00:02.000 L:-123\nOne\n\n",
430         1 * GST_SECOND, 2 * GST_SECOND, "One"}
431     ,
432     {
433           "1\n00:00:01.000 --> 00:00:02.000 L:123\nOne\n\n",
434         1 * GST_SECOND, 2 * GST_SECOND, "One"}
435     ,
436     {
437           "1\n00:00:01.000 --> 00:00:02.000 L:12%\nOne\n\n",
438         1 * GST_SECOND, 2 * GST_SECOND, "One"}
439     ,
440     {
441           "1\n00:00:01.000 --> 00:00:02.000 L:12% S:35% A:start\nOne\n\n",
442         1 * GST_SECOND, 2 * GST_SECOND, "One"}
443     ,
444     {
445           "1\n00:00:01.000 --> 00:00:02.000 A:middle\nOne\n\n",
446         1 * GST_SECOND, 2 * GST_SECOND, "One"}
447     ,
448     {
449           "1\n00:00:01.000 --> 00:00:02.000 A:end\nOne\n\n",
450         1 * GST_SECOND, 2 * GST_SECOND, "One"}
451     ,
452     {
453           "1\n00:00:01.000 --> 00:00:02.000\nOne & Two\n\n",
454         1 * GST_SECOND, 2 * GST_SECOND, "One &amp; Two"}
455     ,
456     {
457           "1\n00:00:01.000 --> 00:00:02.000\nOne < Two\n\n",
458         1 * GST_SECOND, 2 * GST_SECOND, "One &lt; Two"}
459     ,
460     {
461           "1\n00:00:01.000 --> 00:00:02.000\n<v Spoke>Live long and prosper\n\n",
462         1 * GST_SECOND, 2 * GST_SECOND, "<v Spoke>Live long and prosper</v>"}
463     ,
464     {
465           "1\n00:00:01.000 --> 00:00:02.000\n<v The Joker>HAHAHA\n\n",
466         1 * GST_SECOND, 2 * GST_SECOND, "<v The Joker>HAHAHA</v>"}
467     ,
468     {
469           "1\n00:00:01.000 --> 00:00:02.000\n<c.someclass>some text\n\n",
470         1 * GST_SECOND, 2 * GST_SECOND, "<c.someclass>some text</c>"}
471     ,
472     {
473           "1\n00:00:01.000 --> 00:00:02.000\n<b.loud>some text\n\n",
474         1 * GST_SECOND, 2 * GST_SECOND, "<b.loud>some text</b>"}
475     ,
476     {
477           "1\n00:00:01.000 --> 00:00:02.000\n<ruby>base text<rt>annotation</rt></ruby>\n\n",
478           1 * GST_SECOND, 2 * GST_SECOND,
479         "<ruby>base text<rt>annotation</rt></ruby>"}
480     ,
481     {
482           "1\n00:00:01.000 --> 00:00:03.000\nOne... <00:00:00,200>Two... <00:00:00,500>Three...\n\n",
483           1 * GST_SECOND, 3 * GST_SECOND,
484         "One... &lt;00:00:00,200&gt;Two... &lt;00:00:00,500&gt;Three..."}
485     ,
486     {"1\n00:00:02.000 --> 00:00:03.000\nHello\nWorld\n\n",
487         2 * GST_SECOND, 3 * GST_SECOND, "Hello\nWorld"}
488     ,
489   };
490 
491   /* Test with no newline at the end */
492   SubParseInputChunk webvtt_input2[] = {
493     {
494           "1\n00:00:01,000 --> 00:00:02,000\nLast cue, no newline at the end",
495         1 * GST_SECOND, 2 * GST_SECOND, "Last cue, no newline at the end"}
496     ,
497   };
498 
499   test_vtt_do_test (webvtt_input, 0, G_N_ELEMENTS (webvtt_input));
500   test_vtt_do_test (webvtt_input2, 0, G_N_ELEMENTS (webvtt_input2));
501 }
502 
503 GST_END_TEST;
504 
505 static void
do_test(SubParseInputChunk * input,guint num,const gchar * format)506 do_test (SubParseInputChunk * input, guint num, const gchar * format)
507 {
508   guint n;
509   GstCaps *outcaps;
510 
511   setup_subparse ();
512 
513   for (n = 0; n < num; ++n) {
514     GstBuffer *buf;
515 
516     buf = buffer_from_static_string (input[n].in);
517     fail_unless_equals_int (gst_pad_push (mysrcpad, buf), GST_FLOW_OK);
518   }
519 
520   gst_pad_push_event (mysrcpad, gst_event_new_eos ());
521 
522   fail_unless_equals_int (g_list_length (buffers), num);
523 
524   outcaps = gst_pad_get_current_caps (mysinkpad);
525 
526   for (n = 0; n < num; ++n) {
527     const GstStructure *buffer_caps_struct;
528     GstBuffer *buf;
529     GstMapInfo map;
530 
531     buf = g_list_nth_data (buffers, n);
532     fail_unless (buf != NULL);
533 
534     /* check timestamp */
535     fail_unless (GST_BUFFER_TIMESTAMP_IS_VALID (buf), NULL);
536     fail_unless_equals_uint64 (GST_BUFFER_TIMESTAMP (buf), input[n].from_ts);
537 
538     /* might not be able to put a duration on the last buffer */
539     if (input[n].to_ts != GST_CLOCK_TIME_NONE) {
540       /* check duration */
541       fail_unless (GST_BUFFER_DURATION_IS_VALID (buf), NULL);
542       fail_unless_equals_uint64 (GST_BUFFER_DURATION (buf),
543           input[n].to_ts - input[n].from_ts);
544     }
545 
546     gst_buffer_map (buf, &map, GST_MAP_READ);
547     /* can be NULL */
548     if (map.data != NULL) {
549       /* shouldn't have trailing newline characters */
550       fail_if (map.size > 0 && map.data[map.size - 1] == '\n');
551       /* shouldn't include NUL-terminator in data size */
552       fail_if (map.size > 0 && map.data[map.size - 1] == '\0');
553       /* but should still have a  NUL-terminator behind the declared data */
554       fail_unless_equals_int (map.data[map.size], '\0');
555       /* make sure out string matches expected string */
556       fail_unless_equals_string ((gchar *) map.data, input[n].out);
557     }
558     gst_buffer_unmap (buf, &map);
559     /* check caps */
560     fail_unless (outcaps != NULL);
561     buffer_caps_struct = gst_caps_get_structure (outcaps, 0);
562     fail_unless (gst_structure_has_name (buffer_caps_struct, "text/x-raw"));
563     fail_unless_equals_string (gst_structure_get_string (buffer_caps_struct,
564             "format"), format);
565   }
566   gst_caps_unref (outcaps);
567 
568   teardown_subparse ();
569 }
570 
571 static void
test_tmplayer_do_test(SubParseInputChunk * input,guint num)572 test_tmplayer_do_test (SubParseInputChunk * input, guint num)
573 {
574   do_test (input, num, "utf8");
575 }
576 
577 static void
test_microdvd_do_test(SubParseInputChunk * input,guint num)578 test_microdvd_do_test (SubParseInputChunk * input, guint num)
579 {
580   do_test (input, num, "pango-markup");
581 }
582 
GST_START_TEST(test_tmplayer_multiline)583 GST_START_TEST (test_tmplayer_multiline)
584 {
585   static SubParseInputChunk tmplayer_multiline_input[] = {
586     {
587           "00:00:10,1=This is the Earth at a time\n"
588           "00:00:10,2=when the dinosaurs roamed...\n" "00:00:13,1=\n",
589           10 * GST_SECOND, 13 * GST_SECOND,
590         "This is the Earth at a time\nwhen the dinosaurs roamed..."}, {
591           "00:00:14,1=a lush and fertile planet.\n" "00:00:16,1=\n",
592           14 * GST_SECOND, 16 * GST_SECOND,
593         "a lush and fertile planet."}
594   };
595 
596   test_tmplayer_do_test (tmplayer_multiline_input,
597       G_N_ELEMENTS (tmplayer_multiline_input));
598 }
599 
600 GST_END_TEST;
601 
GST_START_TEST(test_tmplayer_multiline_with_bogus_lines)602 GST_START_TEST (test_tmplayer_multiline_with_bogus_lines)
603 {
604   static SubParseInputChunk tmplayer_multiline_b_input[] = {
605     {
606           "00:00:10,1=This is the Earth at a time\n"
607           "Yooboo wabahablablahuguug bogus line hello test 1-2-3-4\n"
608           "00:00:10,2=when the dinosaurs roamed...\n" "00:00:13,1=\n",
609           10 * GST_SECOND, 13 * GST_SECOND,
610         "This is the Earth at a time\nwhen the dinosaurs roamed..."}, {
611           "00:00:14,1=a lush and fertile planet.\n" "00:00:16,1=\n",
612           14 * GST_SECOND, 16 * GST_SECOND,
613         "a lush and fertile planet."}
614   };
615 
616   test_tmplayer_do_test (tmplayer_multiline_b_input,
617       G_N_ELEMENTS (tmplayer_multiline_b_input));
618 }
619 
620 GST_END_TEST;
621 
GST_START_TEST(test_tmplayer_style1)622 GST_START_TEST (test_tmplayer_style1)
623 {
624   static SubParseInputChunk tmplayer_style1_input[] = {
625     {
626           "00:00:10:This is the Earth at a time|when the dinosaurs roamed...\n"
627           "00:00:13:\n",
628           10 * GST_SECOND, 13 * GST_SECOND,
629         "This is the Earth at a time\nwhen the dinosaurs roamed..."}, {
630           "00:00:14:a lush and fertile planet.\n" "00:00:16:\n",
631           14 * GST_SECOND, 16 * GST_SECOND,
632         "a lush and fertile planet."}
633   };
634 
635   test_tmplayer_do_test (tmplayer_style1_input,
636       G_N_ELEMENTS (tmplayer_style1_input));
637 }
638 
639 GST_END_TEST;
640 
GST_START_TEST(test_tmplayer_style2)641 GST_START_TEST (test_tmplayer_style2)
642 {
643   static SubParseInputChunk tmplayer_style2_input[] = {
644     {
645           "00:00:10=This is the Earth at a time|when the dinosaurs roamed...\n"
646           "00:00:13=\n",
647           10 * GST_SECOND, 13 * GST_SECOND,
648         "This is the Earth at a time\nwhen the dinosaurs roamed..."}, {
649           "00:00:14=a lush and fertile planet.\n" "00:00:16=\n",
650           14 * GST_SECOND, 16 * GST_SECOND,
651         "a lush and fertile planet."}
652   };
653 
654   test_tmplayer_do_test (tmplayer_style2_input,
655       G_N_ELEMENTS (tmplayer_style2_input));
656 }
657 
658 GST_END_TEST;
659 
GST_START_TEST(test_tmplayer_style3)660 GST_START_TEST (test_tmplayer_style3)
661 {
662   static SubParseInputChunk tmplayer_style3_input[] = {
663     {
664           "0:00:10:This is the Earth at a time|when the dinosaurs roamed...\n"
665           "0:00:13:\n",
666           10 * GST_SECOND, 13 * GST_SECOND,
667         "This is the Earth at a time\nwhen the dinosaurs roamed..."}, {
668           "0:00:14:a lush and fertile planet.\n" "0:00:16:\n",
669           14 * GST_SECOND, 16 * GST_SECOND,
670         "a lush and fertile planet."}
671   };
672 
673   test_tmplayer_do_test (tmplayer_style3_input,
674       G_N_ELEMENTS (tmplayer_style3_input));
675 }
676 
677 GST_END_TEST;
678 
679 /* also tests the max_duration stuff (see second-last chunk which is supposed
680  * to be clipped to 5s duration) */
GST_START_TEST(test_tmplayer_style3b)681 GST_START_TEST (test_tmplayer_style3b)
682 {
683   static SubParseInputChunk tmplayer_style3b_input[] = {
684     {
685           "0:00:10:This is the Earth at a time|when the dinosaurs roamed...\n",
686           10 * GST_SECOND, 14 * GST_SECOND,
687         "This is the Earth at a time\nwhen the dinosaurs roamed..."}, {
688           "0:00:14:a lush and fertile planet.\n",
689           14 * GST_SECOND, 16 * GST_SECOND,
690         "a lush and fertile planet."}, {
691           "0:00:16:And they liked it a lot.\n",
692         16 * GST_SECOND, (16 + 5) * GST_SECOND, "And they liked it a lot."}, {
693           "0:00:30:Last line.",
694         30 * GST_SECOND, GST_CLOCK_TIME_NONE, "Last line."}
695   };
696 
697   test_tmplayer_do_test (tmplayer_style3b_input,
698       G_N_ELEMENTS (tmplayer_style3b_input));
699 }
700 
701 GST_END_TEST;
702 
GST_START_TEST(test_tmplayer_style4)703 GST_START_TEST (test_tmplayer_style4)
704 {
705   static SubParseInputChunk tmplayer_style4_input[] = {
706     {
707           "0:00:10=This is the Earth at a time|when the dinosaurs roamed...\n"
708           "0:00:13=\n",
709           10 * GST_SECOND, 13 * GST_SECOND,
710         "This is the Earth at a time\nwhen the dinosaurs roamed..."}, {
711           "0:00:14=a lush and fertile planet.\n" "0:00:16=\n",
712           14 * GST_SECOND, 16 * GST_SECOND,
713         "a lush and fertile planet."}
714   };
715 
716   test_tmplayer_do_test (tmplayer_style4_input,
717       G_N_ELEMENTS (tmplayer_style4_input));
718 }
719 
720 GST_END_TEST;
721 
GST_START_TEST(test_tmplayer_style4_with_bogus_lines)722 GST_START_TEST (test_tmplayer_style4_with_bogus_lines)
723 {
724   static SubParseInputChunk tmplayer_style4b_input[] = {
725     {
726           "0:00:10=This is the Earth at a time|when the dinosaurs roamed...\n"
727           "# This is a bogus line with a comment and should just be skipped\n"
728           "0:00:13=\n",
729           10 * GST_SECOND, 13 * GST_SECOND,
730         "This is the Earth at a time\nwhen the dinosaurs roamed..."}, {
731           "0:00:14=a lush and fertile planet.\n"
732           "                                                            \n"
733           "0:00:16=\n",
734           14 * GST_SECOND, 16 * GST_SECOND,
735         "a lush and fertile planet."}
736   };
737 
738   test_tmplayer_do_test (tmplayer_style4b_input,
739       G_N_ELEMENTS (tmplayer_style4b_input));
740 }
741 
742 GST_END_TEST;
743 
GST_START_TEST(test_microdvd_with_italics)744 GST_START_TEST (test_microdvd_with_italics)
745 {
746   static SubParseInputChunk microdvd_italics[] = {
747     {
748           "{1}{1}25.000 movie info: XVID  608x256 25.0fps 699.0 MB|"
749           "/SubEdit b.4060(http://subedit.com.pl)/\n"
750           "{100}{200}/italics/|not italics\n",
751           4 * GST_SECOND, 8 * GST_SECOND,
752         "<span style=\"italic\">italics</span>\n" "<span>not italics</span>"}
753   };
754 
755   test_microdvd_do_test (microdvd_italics, G_N_ELEMENTS (microdvd_italics));
756 }
757 
758 GST_END_TEST;
759 
GST_START_TEST(test_microdvd_with_fps)760 GST_START_TEST (test_microdvd_with_fps)
761 {
762   static SubParseInputChunk microdvd_input[] = {
763     {
764           "{1}{1}12.500\n{100}{200}- Hi, Eddie.|- Hiya, Scotty.\n",
765           8 * GST_SECOND, 16 * GST_SECOND,
766         "<span>- Hi, Eddie.</span>\n<span>- Hiya, Scotty.</span>"}, {
767           "{1250}{1350}- Cold enough for you?|- Well, I'm only faintly alive. "
768           "It's 25 below\n",
769           100 * GST_SECOND, 108 * GST_SECOND,
770         "<span>- Cold enough for you?</span>\n"
771           "<span>- Well, I&apos;m only faintly alive. It&apos;s 25 below</span>"}
772   };
773 
774   test_microdvd_do_test (microdvd_input, G_N_ELEMENTS (microdvd_input));
775 
776   /* and the same with ',' instead of '.' as floating point divider */
777   microdvd_input[0].in =
778       "{1}{1}12,500\n{100}{200}- Hi, Eddie.|- Hiya, Scotty.\n";
779   test_microdvd_do_test (microdvd_input, G_N_ELEMENTS (microdvd_input));
780 }
781 
782 GST_END_TEST;
783 
GST_START_TEST(test_mpl2)784 GST_START_TEST (test_mpl2)
785 {
786   SubParseInputChunk mpl2_input[] = {
787     {
788           "[123][456] This is the Earth at a time|when the dinosaurs roamed\n",
789           (123 * GST_SECOND) / 10, (456 * GST_SECOND) / 10,
790         "This is the Earth at a time\nwhen the dinosaurs roamed"}, {
791           "[1234][5678]a lush and fertile planet.\n",
792           (1234 * GST_SECOND) / 10, (5678 * GST_SECOND) / 10,
793         "a lush and fertile planet."}, {
794           "[12345][27890] /Italic|Normal\n",
795           (12345 * GST_SECOND) / 10, (27890 * GST_SECOND) / 10,
796         "<i>Italic</i>\nNormal"}, {
797           "[32345][37890]/Italic|/Italic\n",
798           (32345 * GST_SECOND) / 10, (37890 * GST_SECOND) / 10,
799         "<i>Italic</i>\n<i>Italic</i>"}, {
800           "[42345][47890] Normal|/Italic",
801           (42345 * GST_SECOND) / 10, (47890 * GST_SECOND) / 10,
802         "Normal\n<i>Italic</i>"}
803   };
804 
805   do_test (mpl2_input, G_N_ELEMENTS (mpl2_input), "pango-markup");
806 }
807 
808 GST_END_TEST;
809 
GST_START_TEST(test_subviewer)810 GST_START_TEST (test_subviewer)
811 {
812   SubParseInputChunk subviewer_input[] = {
813     {
814           "[INFORMATION]\n"
815           "[TITLE]xxxxxxxxxx\n"
816           "[AUTHOR]xxxxxxxx\n"
817           "[SOURCE]xxxxxxxxxxxxxxxx\n"
818           "[FILEPATH]\n"
819           "[DELAY]0\n"
820           "[COMMENT]\n"
821           "[END INFORMATION]\n"
822           "[SUBTITLE]\n"
823           "[COLF]&HFFFFFF,[STYLE]bd,[SIZE]18,[FONT]Arial\n"
824           "00:00:41.00,00:00:44.40\n"
825           "The Age of Gods was closing.\n"
826           "Eternity had come to an end.\n"
827           "\n", 41 * GST_SECOND, 44 * GST_SECOND + 40 * GST_MSECOND,
828         "The Age of Gods was closing.\nEternity had come to an end."}, {
829           "00:00:55.00,00:00:58.40\n"
830           "The heavens shook as the armies\n"
831           "of Falis, God of Light...\n\n", 55 * GST_SECOND,
832           58 * GST_SECOND + 40 * GST_MSECOND,
833         "The heavens shook as the armies\nof Falis, God of Light..."}
834   };
835 
836   do_test (subviewer_input, G_N_ELEMENTS (subviewer_input), "utf8");
837 }
838 
839 GST_END_TEST;
840 
GST_START_TEST(test_subviewer2)841 GST_START_TEST (test_subviewer2)
842 {
843   SubParseInputChunk subviewer2_input[] = {
844     {
845           "[INFORMATION]\n"
846           "[TITLE]xxxxxxxxxx\n"
847           "[AUTHOR]xxxxxxxxxx\n"
848           "[SOURCE]xxxxxxxxxx\n"
849           "[PRG]\n"
850           "[FILEPATH]\n"
851           "[DELAY]0\n"
852           "[CD TRACK]0\n"
853           "[COMMENT]\n"
854           "[END INFORMATION]\n"
855           "[SUBTITLE]\n"
856           "[COLF]&H00FFFF,[STYLE]no,[SIZE]12,[FONT]Courier New\n"
857           "00:00:07.00,00:00:11.91\n"
858           "THERE IS A PLACE ON EARTH WHERE IT[br]IS STILL THE MORNING OF LIFE...\n\n",
859           7 * GST_SECOND, 11 * GST_SECOND + 91 * GST_MSECOND,
860         "THERE IS A PLACE ON EARTH WHERE IT\nIS STILL THE MORNING OF LIFE..."}, {
861           "00:00:12.48,00:00:15.17\n"
862           "AND THE GREAT HERDS RUN FREE.[br]SO WHAT?!\n\n",
863           12 * GST_SECOND + 48 * GST_MSECOND,
864           15 * GST_SECOND + 17 * GST_MSECOND,
865         "AND THE GREAT HERDS RUN FREE.\nSO WHAT?!"}
866   };
867 
868   do_test (subviewer2_input, G_N_ELEMENTS (subviewer2_input), "utf8");
869 }
870 
871 GST_END_TEST;
872 
GST_START_TEST(test_dks)873 GST_START_TEST (test_dks)
874 {
875   SubParseInputChunk dks_input[] = {
876     {
877           "[00:00:07]THERE IS A PLACE ON EARTH WHERE IT[br]IS STILL THE MORNING OF LIFE...\n[00:00:12]\n",
878           7 * GST_SECOND, 12 * GST_SECOND,
879         "THERE IS A PLACE ON EARTH WHERE IT\nIS STILL THE MORNING OF LIFE..."}, {
880           "[00:00:13]AND THE GREAT HERDS RUN FREE.[br]SO WHAT?!\n[00:00:15]\n",
881           13 * GST_SECOND, 15 * GST_SECOND,
882         "AND THE GREAT HERDS RUN FREE.\nSO WHAT?!"}
883   };
884 
885   do_test (dks_input, G_N_ELEMENTS (dks_input), "utf8");
886 }
887 
888 GST_END_TEST;
889 
GST_START_TEST(test_sami)890 GST_START_TEST (test_sami)
891 {
892   SubParseInputChunk sami_input[] = {
893     {"<SAMI>\n"
894           "<HEAD>\n"
895           "    <TITLE>Subtitle</TITLE>\n"
896           "    <STYLE TYPE=\"text/css\">\n"
897           "    <!--\n"
898           "        P {margin-left:8pt; margin-right:8pt; margin-bottom:2pt; margin-top:2pt; text-align:center; font-size:12pt; font-weight:normal; color:black;}\n"
899           "        .CC {Name:English; lang:en-AU; SAMIType:CC;}\n"
900           "        #STDPrn {Name:Standard Print;}\n"
901           "        #LargePrn {Name:Large Print; font-size:24pt;}\n"
902           "        #SmallPrn {Name:Small Print; font-size:16pt;}\n"
903           "    -->\n"
904           "    </Style>\n"
905           "</HEAD>\n"
906           "<BODY>\n"
907           "    <SYNC Start=1000>\n"
908           "        <P Class=CC>\n"
909           "            This is a comment.<br>\n"
910           "            This is a second comment.\n",
911           1000 * GST_MSECOND, 2000 * GST_MSECOND,
912         "This is a comment.\nThis is a second comment."},
913     {"    <SYNC Start=2000>\n"
914           "        <P Class=CC>\n"
915           "            This is a third comment.<br>\n"
916           "            This is a fourth comment.\n" "</BODY>\n" "</SAMI>\n",
917           2000 * GST_MSECOND, GST_CLOCK_TIME_NONE,
918         "This is a third comment.\nThis is a fourth comment."}
919   };
920 
921   do_test (sami_input, G_N_ELEMENTS (sami_input), "pango-markup");
922 }
923 
924 GST_END_TEST;
925 
GST_START_TEST(test_sami_xml_entities)926 GST_START_TEST (test_sami_xml_entities)
927 {
928   SubParseInputChunk sami_input[] = {
929     {"<SAMI>\n"
930           "<BODY>\n"
931           "    <SYNC Start=1000>\n"
932           "        <P Class=CC>\n" "            &lt;Hello&gt; &amp;\n",
933           1000 * GST_MSECOND, 2000 * GST_MSECOND,
934         "&lt;Hello&gt; &amp;"},
935     {"    <SYNC Start=2000>\n"
936           "        <P Class=CC>\n"
937           "            &quot;World&apos;\n" "</BODY>\n" "</SAMI>\n",
938           2000 * GST_MSECOND, GST_CLOCK_TIME_NONE,
939         "&quot;World&apos;"}
940 
941   };
942 
943   do_test (sami_input, G_N_ELEMENTS (sami_input), "pango-markup");
944 }
945 
946 GST_END_TEST;
947 
GST_START_TEST(test_sami_html_entities)948 GST_START_TEST (test_sami_html_entities)
949 {
950   SubParseInputChunk sami_input[] = {
951     {"<SAMI>\n"
952           "<BODY>\n"
953           "    <SYNC Start=1000>\n"
954           "        <P Class=CC>\n" "            &nbsp; &plusmn; &acute;\n",
955           1000 * GST_MSECOND, 2000 * GST_MSECOND,
956         "\xc2\xa0 \xc2\xb1 \xc2\xb4"},
957     {"    <SYNC Start=2000>\n"
958           "        <P Class=CC>\n" "            &Alpha; &omega;\n",
959           2000 * GST_MSECOND, 3000 * GST_MSECOND,
960         "\xce\x91 \xcf\x89"},
961     {"    <SYNC Start=3000>\n"
962           "        <P Class=CC>\n"
963           "            &#xa0; &#177; &#180;\n" "</BODY>\n" "</SAMI>\n",
964           3000 * GST_MSECOND, GST_CLOCK_TIME_NONE,
965         "\xc2\xa0 \xc2\xb1 \xc2\xb4"}
966   };
967 
968   do_test (sami_input, G_N_ELEMENTS (sami_input), "pango-markup");
969 }
970 
971 GST_END_TEST;
972 
GST_START_TEST(test_sami_bad_entities)973 GST_START_TEST (test_sami_bad_entities)
974 {
975   SubParseInputChunk sami_input[] = {
976     {"<SAMI>\n"
977           "<BODY>\n"
978           "    <SYNC Start=1000>\n"
979           "        <P Class=CC>\n" "            &nbsp &\n",
980           1000 * GST_MSECOND, 2000 * GST_MSECOND,
981         "\xc2\xa0 &amp;"},
982     {"    <SYNC Start=2000>\n"
983           "        <P Class=CC>\n"
984           "            &#xa0 &#177 &#180;\n" "</BODY>\n" "</SAMI>\n",
985           2000 * GST_MSECOND, GST_CLOCK_TIME_NONE,
986         "\xc2\xa0 \xc2\xb1 \xc2\xb4"}
987   };
988 
989   do_test (sami_input, G_N_ELEMENTS (sami_input), "pango-markup");
990 }
991 
992 GST_END_TEST;
993 
GST_START_TEST(test_sami_comment)994 GST_START_TEST (test_sami_comment)
995 {
996   SubParseInputChunk sami_input[] = {
997     {"<SAMI>\n"
998           "<!--\n"
999           "=======\n"
1000           "foo bar\n"
1001           "=======\n"
1002           "-->\n"
1003           "<BODY>\n"
1004           "    <SYNC Start=1000>\n"
1005           "        <P Class=\"C====\">\n" "            &nbsp &\n",
1006           1000 * GST_MSECOND, 2000 * GST_MSECOND,
1007         "\xc2\xa0 &amp;"},
1008     {"    <SYNC Start=2000>\n"
1009           "        <P Class=CC>\n"
1010           "            &#xa0 &#177 &#180;\n" "</BODY>\n" "</SAMI>\n",
1011           2000 * GST_MSECOND, GST_CLOCK_TIME_NONE,
1012         "\xc2\xa0 \xc2\xb1 \xc2\xb4"}
1013   };
1014 
1015   do_test (sami_input, G_N_ELEMENTS (sami_input), "pango-markup");
1016 }
1017 
1018 GST_END_TEST;
1019 
GST_START_TEST(test_lrc)1020 GST_START_TEST (test_lrc)
1021 {
1022   SubParseInputChunk lrc_input[] = {
1023     {"[ar:123]\n" "[ti:Title]\n" "[al:Album]\n" "[00:02.23]Line 1\n",
1024           2230 * GST_MSECOND, GST_CLOCK_TIME_NONE,
1025         "Line 1"},
1026     {"[00:05.10]Line 2\n",
1027           5100 * GST_MSECOND, GST_CLOCK_TIME_NONE,
1028         "Line 2"},
1029     {"[00:06.123]Line 3\n",
1030           6123 * GST_MSECOND, GST_CLOCK_TIME_NONE,
1031         "Line 3"}
1032   };
1033 
1034   do_test (lrc_input, G_N_ELEMENTS (lrc_input), "utf8");
1035 }
1036 
1037 GST_END_TEST;
1038 
1039 /* TODO:
1040  *  - add/modify tests so that lines aren't dogfed to the parsers in complete
1041  *    lines or sets of complete lines, but rather in random chunks
1042  */
1043 
1044 static Suite *
subparse_suite(void)1045 subparse_suite (void)
1046 {
1047   Suite *s = suite_create ("subparse");
1048   TCase *tc_chain = tcase_create ("general");
1049 
1050   suite_add_tcase (s, tc_chain);
1051 
1052   tcase_add_test (tc_chain, test_srt);
1053   tcase_add_test (tc_chain, test_webvtt);
1054   tcase_add_test (tc_chain, test_tmplayer_multiline);
1055   tcase_add_test (tc_chain, test_tmplayer_multiline_with_bogus_lines);
1056   tcase_add_test (tc_chain, test_tmplayer_style1);
1057   tcase_add_test (tc_chain, test_tmplayer_style2);
1058   tcase_add_test (tc_chain, test_tmplayer_style3);
1059   tcase_add_test (tc_chain, test_tmplayer_style3b);
1060   tcase_add_test (tc_chain, test_tmplayer_style4);
1061   tcase_add_test (tc_chain, test_tmplayer_style4_with_bogus_lines);
1062   tcase_add_test (tc_chain, test_microdvd_with_fps);
1063   tcase_add_test (tc_chain, test_microdvd_with_italics);
1064   tcase_add_test (tc_chain, test_mpl2);
1065   tcase_add_test (tc_chain, test_subviewer);
1066   tcase_add_test (tc_chain, test_subviewer2);
1067   tcase_add_test (tc_chain, test_dks);
1068   tcase_add_test (tc_chain, test_sami);
1069   tcase_add_test (tc_chain, test_sami_xml_entities);
1070   tcase_add_test (tc_chain, test_sami_html_entities);
1071   tcase_add_test (tc_chain, test_sami_bad_entities);
1072   tcase_add_test (tc_chain, test_sami_comment);
1073   tcase_add_test (tc_chain, test_lrc);
1074   return s;
1075 }
1076 
1077 GST_CHECK_MAIN (subparse);
1078