Support MarginL and MarginR in SSA subtitles (DoM #2811).
[libsub.git] / test / subrip_reader_test.cc
1 /*
2     Copyright (C) 2014-2020 Carl Hetherington <cth@carlh.net>
3
4     This program is free software; you can redistribute it and/or modify
5     it under the terms of the GNU General Public License as published by
6     the Free Software Foundation; either version 2 of the License, or
7     (at your option) any later version.
8
9     This program 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
12     GNU General Public License for more details.
13
14     You should have received a copy of the GNU General Public License
15     along with this program; if not, write to the Free Software
16     Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
17
18 */
19
20 #include "subrip_reader.h"
21 #include "subtitle.h"
22 #include "test.h"
23 #include "exceptions.h"
24 #include "collect.h"
25 #include <boost/test/unit_test.hpp>
26 #include <boost/filesystem.hpp>
27 #include <cmath>
28 #include <iostream>
29 #include <cstdio>
30
31 using std::cerr;
32 using std::vector;
33 using std::fabs;
34
35 /* Test reading of a Subrip file */
36 BOOST_AUTO_TEST_CASE (subrip_reader_test)
37 {
38         FILE* f = fopen ("test/data/test.srt", "r");
39         sub::SubripReader reader (f);
40         fclose (f);
41         auto subs = sub::collect<std::vector<sub::Subtitle>> (reader.subtitles());
42
43         auto i = subs.begin ();
44
45
46         /* First subtitle */
47
48         BOOST_CHECK (i != subs.end ());
49         BOOST_CHECK_EQUAL (i->from, sub::Time::from_hms (0, 0, 41, 90));
50         BOOST_CHECK_EQUAL (i->to, sub::Time::from_hms (0, 0, 42, 210));
51
52         auto j = i->lines.begin();
53         BOOST_CHECK (j != i->lines.end ());
54         BOOST_CHECK_EQUAL (j->blocks.size(), 1);
55         auto b = j->blocks.front();
56         BOOST_CHECK_EQUAL (b.text, "This is a subtitle");
57         /* No font is specified by subrip, so none should be seen here */
58         BOOST_CHECK (!b.font);
59         BOOST_CHECK (!b.font_size.specified());
60         BOOST_CHECK_EQUAL (b.bold, false);
61         BOOST_CHECK_EQUAL (b.italic, false);
62         BOOST_CHECK_EQUAL (b.underline, false);
63         BOOST_REQUIRE (j->vertical_position.line);
64         BOOST_CHECK_EQUAL (j->vertical_position.line.get(), 0);
65         BOOST_CHECK_EQUAL (j->vertical_position.reference.get(), sub::TOP_OF_SUBTITLE);
66         ++j;
67
68         BOOST_CHECK (j != i->lines.end ());
69         BOOST_CHECK_EQUAL (j->blocks.size(), 1);
70         b = j->blocks.front ();
71         BOOST_CHECK_EQUAL (b.text, "and that's a line break");
72         /* No font is specified by subrip, so none should be seen here */
73         BOOST_CHECK (!b.font);
74         BOOST_CHECK (!b.font_size.specified());
75         BOOST_CHECK_EQUAL (b.bold, false);
76         BOOST_CHECK_EQUAL (b.italic, false);
77         BOOST_CHECK_EQUAL (b.underline, false);
78         BOOST_REQUIRE (j->vertical_position.line);
79         BOOST_CHECK_EQUAL (j->vertical_position.line.get(), 1);
80         BOOST_CHECK_EQUAL (j->vertical_position.reference.get(), sub::TOP_OF_SUBTITLE);
81         ++i;
82
83
84         /* Second subtitle */
85
86         BOOST_CHECK (i != subs.end ());
87         BOOST_CHECK_EQUAL (i->from, sub::Time::from_hms (0, 1, 1, 10));
88         BOOST_CHECK_EQUAL (i->to, sub::Time::from_hms (0, 1, 2, 100));
89
90         BOOST_CHECK_EQUAL (i->lines.size(), 1);
91         sub::Line l = i->lines.front ();
92         BOOST_CHECK_EQUAL (l.blocks.size(), 7);
93         BOOST_CHECK_EQUAL (l.vertical_position.line.get(), 0);
94         BOOST_CHECK_EQUAL (l.vertical_position.reference.get(), sub::TOP_OF_SUBTITLE);
95
96         auto k = l.blocks.begin();
97
98         BOOST_CHECK (k != l.blocks.end ());
99         BOOST_CHECK_EQUAL (k->text, "This is some ");
100         /* No font is specified by subrip, so none should be seen here */
101         BOOST_CHECK (!b.font);
102         BOOST_CHECK (!b.font_size.specified());
103         BOOST_CHECK_EQUAL (k->bold, false);
104         BOOST_CHECK_EQUAL (k->italic, false);
105         BOOST_CHECK_EQUAL (k->underline, false);
106         ++k;
107
108         BOOST_CHECK (k != l.blocks.end ());
109         BOOST_CHECK_EQUAL (k->text, "bold");
110         /* No font is specified by subrip, so none should be seen here */
111         BOOST_CHECK (!b.font);
112         BOOST_CHECK (!b.font_size.specified());
113         BOOST_CHECK_EQUAL (k->bold, true);
114         BOOST_CHECK_EQUAL (k->italic, false);
115         BOOST_CHECK_EQUAL (k->underline, false);
116         ++k;
117
118         BOOST_CHECK (k != l.blocks.end ());
119         BOOST_CHECK_EQUAL (k->text, " and some ");
120         /* No font is specified by subrip, so none should be seen here */
121         BOOST_CHECK (!b.font);
122         BOOST_CHECK (!b.font_size.specified());
123         BOOST_CHECK_EQUAL (k->bold, false);
124         BOOST_CHECK_EQUAL (k->italic, false);
125         BOOST_CHECK_EQUAL (k->underline, false);
126         ++k;
127
128         BOOST_CHECK (k != l.blocks.end ());
129         BOOST_CHECK_EQUAL (k->text, "bold italic");
130         /* No font is specified by subrip, so none should be seen here */
131         BOOST_CHECK (!b.font);
132         BOOST_CHECK (!b.font_size.specified());
133         BOOST_CHECK_EQUAL (k->bold, true);
134         BOOST_CHECK_EQUAL (k->italic, true);
135         BOOST_CHECK_EQUAL (k->underline, false);
136         ++k;
137
138         BOOST_CHECK (k != l.blocks.end ());
139         BOOST_CHECK_EQUAL (k->text, " and some ");
140         /* No font is specified by subrip, so none should be seen here */
141         BOOST_CHECK (!b.font);
142         BOOST_CHECK (!b.font_size.specified());
143         BOOST_CHECK_EQUAL (k->bold, false);
144         BOOST_CHECK_EQUAL (k->italic, false);
145         BOOST_CHECK_EQUAL (k->underline, false);
146         ++k;
147
148         BOOST_CHECK (k != l.blocks.end ());
149         BOOST_CHECK_EQUAL (k->text, "underlined");
150         /* No font is specified by subrip, so none should be seen here */
151         BOOST_CHECK (!b.font);
152         BOOST_CHECK (!b.font_size.specified());
153         BOOST_CHECK_EQUAL (k->bold, false);
154         BOOST_CHECK_EQUAL (k->italic, false);
155         BOOST_CHECK_EQUAL (k->underline, true);
156         ++k;
157
158         BOOST_CHECK (k != l.blocks.end ());
159         BOOST_CHECK_EQUAL (k->text, ".");
160         /* No font is specified by subrip, so none should be seen here */
161         BOOST_CHECK (!b.font);
162         BOOST_CHECK (!b.font_size.specified());
163         BOOST_CHECK_EQUAL (k->bold, false);
164         BOOST_CHECK_EQUAL (k->italic, false);
165         BOOST_CHECK_EQUAL (k->underline, false);
166         ++k;
167
168         BOOST_CHECK (k == l.blocks.end ());
169 }
170
171 /* Test reading of another Subrip file */
172 BOOST_AUTO_TEST_CASE (subrip_reader_test2)
173 {
174         FILE* f = fopen ("test/data/test2.srt", "r");
175         sub::SubripReader reader (f);
176         fclose (f);
177         auto subs = sub::collect<vector<sub::Subtitle>> (reader.subtitles());
178
179         auto i = subs.begin();
180
181         BOOST_CHECK (i != subs.end ());
182         BOOST_CHECK_EQUAL (i->from, sub::Time::from_hms (0, 1, 49, 200));
183         BOOST_CHECK_EQUAL (i->to, sub::Time::from_hms (0, 1, 52, 351));
184         BOOST_CHECK_EQUAL (i->lines.size(), 2);
185         BOOST_CHECK_EQUAL (i->lines.front().blocks.front().text, "This is a subtitle, and it goes ");
186         BOOST_CHECK_EQUAL (i->lines.back().blocks.front().text, "over two lines.");
187
188         ++i;
189         BOOST_CHECK (i != subs.end ());
190         BOOST_CHECK_EQUAL (i->from, sub::Time::from_hms (0, 1, 52, 440));
191         BOOST_CHECK_EQUAL (i->to, sub::Time::from_hms (0, 1, 54, 351));
192         BOOST_CHECK_EQUAL (i->lines.size(), 1);
193         BOOST_CHECK_EQUAL (i->lines.front().blocks.front().text, "We have emboldened this");
194         BOOST_CHECK_EQUAL (i->lines.front().blocks.front().bold, true);
195
196         ++i;
197         BOOST_CHECK (i != subs.end ());
198         BOOST_CHECK_EQUAL (i->from, sub::Time::from_hms (0, 1, 54, 440));
199         BOOST_CHECK_EQUAL (i->to, sub::Time::from_hms (0, 1, 56, 590));
200         BOOST_CHECK_EQUAL (i->lines.size(), 1);
201         BOOST_CHECK_EQUAL (i->lines.front().blocks.front().text, "And italicised this.");
202         BOOST_CHECK_EQUAL (i->lines.front().blocks.front().italic, true);
203
204         ++i;
205         BOOST_CHECK (i != subs.end ());
206         BOOST_CHECK_EQUAL (i->from, sub::Time::from_hms (0, 1, 56, 680));
207         BOOST_CHECK_EQUAL (i->to, sub::Time::from_hms (0, 1, 58, 955));
208         BOOST_CHECK_EQUAL (i->lines.size(), 1);
209         BOOST_CHECK_EQUAL (i->lines.front().blocks.front().text, "Shall I compare thee to a summers' day?");
210
211         ++i;
212         BOOST_CHECK (i != subs.end ());
213         BOOST_CHECK_EQUAL (i->from, sub::Time::from_hms (0, 2, 0, 840));
214         BOOST_CHECK_EQUAL (i->to, sub::Time::from_hms (0, 2, 3, 400));
215         BOOST_CHECK_EQUAL (i->lines.size(), 1);
216         BOOST_CHECK_EQUAL (i->lines.front().blocks.front().text, "Is this a dagger I see before me?");
217
218         ++i;
219         BOOST_CHECK (i != subs.end ());
220         BOOST_CHECK_EQUAL (i->from, sub::Time::from_hms (0, 3, 54, 560));
221         BOOST_CHECK_EQUAL (i->to, sub::Time::from_hms (0, 3, 56, 471));
222         BOOST_CHECK_EQUAL (i->lines.size(), 1);
223         BOOST_CHECK_EQUAL (i->lines.front().blocks.front().text, "Hello world.");
224
225         ++i;
226         BOOST_CHECK (i != subs.end ());
227         BOOST_CHECK_EQUAL (i->from, sub::Time::from_hms (0, 4, 50, 123));
228         BOOST_CHECK_EQUAL (i->to, sub::Time::from_hms (0, 4, 55, 23));
229         BOOST_CHECK_EQUAL (i->lines.size(), 2);
230         BOOST_CHECK_EQUAL (i->lines.front().blocks.front().text, "Some italics over");
231         BOOST_CHECK_EQUAL (i->lines.front().blocks.front().italic, true);
232         BOOST_CHECK_EQUAL (i->lines.back().blocks.front().text, "multiple lines");
233         BOOST_CHECK_EQUAL (i->lines.back().blocks.front().italic, true);
234
235         ++i;
236         BOOST_CHECK (i == subs.end ());
237 }
238
239 /** Test SubripReader::convert_line */
240 BOOST_AUTO_TEST_CASE (subrip_reader_convert_line_test)
241 {
242         sub::SubripReader r;
243
244         sub::RawSubtitle rs;
245         r.convert_line ("Hello world", rs);
246         BOOST_CHECK_EQUAL (r._subs.size(), 1);
247         BOOST_CHECK_EQUAL (r._subs.front().text, "Hello world");
248         r._subs.clear ();
249
250         rs = sub::RawSubtitle();
251         r.convert_line ("<b>Hello world</b>", rs);
252         BOOST_CHECK_EQUAL (r._subs.size(), 1);
253         BOOST_CHECK_EQUAL (r._subs.front().text, "Hello world");
254         BOOST_CHECK_EQUAL (r._subs.front().bold, true);
255         r._subs.clear ();
256
257         rs = sub::RawSubtitle();
258         r.convert_line ("<i>Hello world</i>", rs);
259         BOOST_CHECK_EQUAL (r._subs.size(), 1);
260         BOOST_CHECK_EQUAL (r._subs.front().text, "Hello world");
261         BOOST_CHECK_EQUAL (r._subs.front().italic, true);
262         r._subs.clear ();
263
264         rs = sub::RawSubtitle();
265         r.convert_line ("<u>Hello world</u>", rs);
266         BOOST_CHECK_EQUAL (r._subs.size(), 1);
267         BOOST_CHECK_EQUAL (r._subs.front().text, "Hello world");
268         BOOST_CHECK_EQUAL (r._subs.front().underline, true);
269         r._subs.clear ();
270
271         rs = sub::RawSubtitle();
272         r.convert_line ("{b}Hello world{/b}", rs);
273         BOOST_CHECK_EQUAL (r._subs.size(), 1);
274         BOOST_CHECK_EQUAL (r._subs.front().text, "Hello world");
275         BOOST_CHECK_EQUAL (r._subs.front().bold, true);
276         r._subs.clear ();
277
278         rs = sub::RawSubtitle();
279         r.convert_line ("{i}Hello world{/i}", rs);
280         BOOST_CHECK_EQUAL (r._subs.size(), 1);
281         BOOST_CHECK_EQUAL (r._subs.front().text, "Hello world");
282         BOOST_CHECK_EQUAL (r._subs.front().italic, true);
283         r._subs.clear ();
284
285         rs = sub::RawSubtitle();
286         r.convert_line ("{u}Hello world{/u}", rs);
287         BOOST_CHECK_EQUAL (r._subs.size(), 1);
288         BOOST_CHECK_EQUAL (r._subs.front().text, "Hello world");
289         BOOST_CHECK_EQUAL (r._subs.front().underline, true);
290         r._subs.clear ();
291
292         rs = sub::RawSubtitle();
293         r.convert_line ("<b>This is <i>nesting</i> of subtitles</b>", rs);
294         BOOST_CHECK_EQUAL (r._subs.size(), 3);
295         auto i = r._subs.begin();
296         BOOST_CHECK_EQUAL (i->text, "This is ");
297         BOOST_CHECK_EQUAL (i->bold, true);
298         BOOST_CHECK_EQUAL (i->italic, false);
299         ++i;
300         BOOST_CHECK_EQUAL (i->text, "nesting");
301         BOOST_CHECK_EQUAL (i->bold, true);
302         BOOST_CHECK_EQUAL (i->italic, true);
303         ++i;
304         BOOST_CHECK_EQUAL (i->text, " of subtitles");
305         BOOST_CHECK_EQUAL (i->bold, true);
306         BOOST_CHECK_EQUAL (i->italic, false);
307         ++i;
308         r._subs.clear ();
309
310         rs = sub::RawSubtitle();
311         r.convert_line ("<B>This is <I>nesting</I> of subtitles</B>", rs);
312         BOOST_CHECK_EQUAL (r._subs.size(), 3);
313         i = r._subs.begin();
314         BOOST_CHECK_EQUAL (i->text, "This is ");
315         BOOST_CHECK_EQUAL (i->bold, true);
316         BOOST_CHECK_EQUAL (i->italic, false);
317         ++i;
318         BOOST_CHECK_EQUAL (i->text, "nesting");
319         BOOST_CHECK_EQUAL (i->bold, true);
320         BOOST_CHECK_EQUAL (i->italic, true);
321         ++i;
322         BOOST_CHECK_EQUAL (i->text, " of subtitles");
323         BOOST_CHECK_EQUAL (i->bold, true);
324         BOOST_CHECK_EQUAL (i->italic, false);
325         ++i;
326         r._subs.clear ();
327
328         rs = sub::RawSubtitle();
329         r.convert_line ("<font color=\"#ff00ff\">simple color</font>", rs);
330         BOOST_CHECK_EQUAL (r._subs.size(), 1);
331         BOOST_CHECK_EQUAL (r._subs.front().text, "simple color");
332         BOOST_CHECK_EQUAL (r._subs.front().bold, false);
333         BOOST_CHECK_CLOSE (r._subs.front().colour.r, 1, 0.1);
334         BOOST_CHECK (fabs (r._subs.front().colour.g) < 0.01);
335         BOOST_CHECK_CLOSE (r._subs.front().colour.b, 1, 0.1);
336         r._subs.clear ();
337
338         /* single quotes are apparently also allowed */
339         rs = sub::RawSubtitle();
340         r.convert_line("<font color=\'#ff00ff\'>simple color</font>", rs);
341         BOOST_CHECK_EQUAL(r._subs.size(), 1);
342         BOOST_CHECK_EQUAL(r._subs.front().text, "simple color");
343         BOOST_CHECK_EQUAL(r._subs.front().bold, false);
344         BOOST_CHECK_CLOSE(r._subs.front().colour.r, 1, 0.1);
345         BOOST_CHECK(fabs(r._subs.front().colour.g) < 0.01);
346         BOOST_CHECK_CLOSE(r._subs.front().colour.b, 1, 0.1);
347         r._subs.clear();
348
349         rs = sub::RawSubtitle();
350         r.convert_line ("<font color=\"#FF00FF\">simple color in capitals</font>", rs);
351         BOOST_CHECK_EQUAL (r._subs.size(), 1);
352         BOOST_CHECK_EQUAL (r._subs.front().text, "simple color in capitals");
353         BOOST_CHECK_EQUAL (r._subs.front().bold, false);
354         BOOST_CHECK_CLOSE (r._subs.front().colour.r, 1, 0.1);
355         BOOST_CHECK (fabs (r._subs.front().colour.g) < 0.01);
356         BOOST_CHECK_CLOSE (r._subs.front().colour.b, 1, 0.1);
357         r._subs.clear ();
358
359         rs = sub::RawSubtitle();
360         r.convert_line ("<font color=\"#ff0000\">some red text <b>in bold</b></font>", rs);
361         BOOST_CHECK_EQUAL (r._subs.size(), 2);
362         i = r._subs.begin ();
363         BOOST_CHECK_EQUAL (i->text, "some red text ");
364         BOOST_CHECK_EQUAL (i->bold, false);
365         BOOST_CHECK_CLOSE (i->colour.r, 1, 0.1);
366         BOOST_CHECK (fabs (i->colour.g) < 0.01);
367         BOOST_CHECK (fabs (i->colour.b) < 0.01);
368         ++i;
369         BOOST_CHECK_EQUAL (i->text, "in bold");
370         BOOST_CHECK_EQUAL (i->bold, true);
371         BOOST_CHECK_CLOSE (i->colour.r, 1, 0.1);
372         BOOST_CHECK (fabs (i->colour.g) < 0.01);
373         BOOST_CHECK (fabs (i->colour.b) < 0.01);
374         r._subs.clear ();
375
376         rs = sub::RawSubtitle();
377         r.convert_line ("<Font color=\"#ff0000\">some red text <b>in bold</b></font>", rs);
378         BOOST_CHECK_EQUAL (r._subs.size(), 2);
379         i = r._subs.begin ();
380         BOOST_CHECK_EQUAL (i->text, "some red text ");
381         BOOST_CHECK_EQUAL (i->bold, false);
382         BOOST_CHECK_CLOSE (i->colour.r, 1, 0.1);
383         BOOST_CHECK (fabs (i->colour.g) < 0.01);
384         BOOST_CHECK (fabs (i->colour.b) < 0.01);
385         ++i;
386         BOOST_CHECK_EQUAL (i->text, "in bold");
387         BOOST_CHECK_EQUAL (i->bold, true);
388         BOOST_CHECK_CLOSE (i->colour.r, 1, 0.1);
389         BOOST_CHECK (fabs (i->colour.g) < 0.01);
390         BOOST_CHECK (fabs (i->colour.b) < 0.01);
391         r._subs.clear ();
392
393         rs = sub::RawSubtitle();
394         r.convert_line ("<font color=\"#0000ff\">some blue text <b>in bold</b></font>", rs);
395         BOOST_CHECK_EQUAL (r._subs.size(), 2);
396         i = r._subs.begin ();
397         BOOST_CHECK_EQUAL (i->text, "some blue text ");
398         BOOST_CHECK_EQUAL (i->bold, false);
399         BOOST_CHECK (fabs (i->colour.r) < 0.01);
400         BOOST_CHECK (fabs (i->colour.g) < 0.01);
401         BOOST_CHECK_CLOSE (i->colour.b, 1, 0.1);
402         ++i;
403         BOOST_CHECK_EQUAL (i->text, "in bold");
404         BOOST_CHECK_EQUAL (i->bold, true);
405         BOOST_CHECK (fabs (i->colour.r) < 0.01);
406         BOOST_CHECK (fabs (i->colour.g) < 0.01);
407         BOOST_CHECK_CLOSE (i->colour.b, 1, 0.1);
408         r._subs.clear ();
409
410         rs = sub::RawSubtitle();
411         r.convert_line("<font color=\"#0000ffdd\">some blue text with alpha</font>", rs);
412         BOOST_CHECK_EQUAL(r._subs.size(), 1);
413         i = r._subs.begin();
414         BOOST_CHECK_EQUAL(i->text, "some blue text with alpha");
415         BOOST_CHECK_EQUAL(i->bold, false);
416         BOOST_CHECK(fabs(i->colour.r) < 0.01);
417         BOOST_CHECK(fabs(i->colour.g) < 0.01);
418         BOOST_CHECK_CLOSE(i->colour.b, 1, 0.1);
419         r._subs.clear();
420
421         rs = sub::RawSubtitle();
422         r.convert_line ("<< angle brackets but no HTML >>", rs);
423         BOOST_CHECK_EQUAL (r._subs.size(), 1);
424         i = r._subs.begin ();
425         BOOST_CHECK_EQUAL (i->text, "<< angle brackets but no HTML >>");
426         r._subs.clear();
427 }
428
429 /** Test SubripReader::convert_time */
430 BOOST_AUTO_TEST_CASE (subrip_reader_convert_time_test)
431 {
432         sub::SubripReader reader;
433         auto t = reader.convert_time("00:03:10,500", ",");
434         BOOST_REQUIRE(t);
435         BOOST_CHECK_EQUAL(*t, sub::Time::from_hms(0, 3, 10, 500));
436         t = reader.convert_time("04:19:51,782", ",");
437         BOOST_REQUIRE(t);
438         BOOST_CHECK_EQUAL(*t, sub::Time::from_hms(4, 19, 51, 782));
439 }
440
441 static void
442 test (boost::filesystem::path p)
443 {
444         p = private_test / p;
445         FILE* f = fopen (p.string().c_str(), "r");
446         BOOST_CHECK (f);
447         if (!f) {
448                 cerr << p << " not found.\n";
449                 return;
450         }
451         sub::SubripReader r (f);
452         fclose (f);
453 }
454
455 static void
456 test_throw (boost::filesystem::path p)
457 {
458         p = private_test / p;
459         FILE* f = fopen (p.string().c_str(), "r");
460         BOOST_CHECK (f);
461         if (!f) {
462                 cerr << p << " not found.\n";
463                 return;
464         }
465         BOOST_CHECK_THROW (sub::SubripReader r(f), sub::SubripError);
466         fclose (f);
467 }
468
469 /** Test of reading some typical .srt files */
470 BOOST_AUTO_TEST_CASE (subrip_read_test)
471 {
472         test ("sintel_en.srt");
473         test ("sintel_fr.srt");
474         test ("FC.srt");
475         test ("EU13.srt");
476         test ("Subtitulos_H_eng.srt");
477         test ("SWING.srt");
478         test_throw ("subtitulo1.srt");
479 }
480
481 #define SUB_START(f, t) \
482         BOOST_REQUIRE (i != subs.end ()); \
483         BOOST_CHECK_EQUAL (i->from, f); \
484         BOOST_CHECK_EQUAL (i->to, t); \
485         j = i->lines.begin ();
486
487 #define LINE(p)                                                 \
488         BOOST_REQUIRE (j != i->lines.end ()); \
489         BOOST_CHECK (j->vertical_position.line); \
490         BOOST_CHECK_EQUAL (j->vertical_position.line.get(), p); \
491         BOOST_CHECK (j->vertical_position.reference); \
492         BOOST_CHECK_EQUAL (j->vertical_position.reference.get(), sub::TOP_OF_SUBTITLE); \
493         k = j->blocks.begin (); \
494         ++j;
495
496 #define BLOCK(t, f, s, b, i, u) \
497         BOOST_REQUIRE (k != j->blocks.end ()); \
498         BOOST_CHECK_EQUAL (k->text, t); \
499         BOOST_CHECK_EQUAL (k->bold, b); \
500         BOOST_CHECK_EQUAL (k->italic, i); \
501         BOOST_CHECK_EQUAL (k->underline, u); \
502         ++k;
503
504 #define SUB_END() \
505         ++i;
506
507 /** Test reading of another .srt file */
508 BOOST_AUTO_TEST_CASE (subrip_reader_test3)
509 {
510         boost::filesystem::path p = private_test / "DCP-o-matic_test_subs_1.srt";
511         FILE* f = fopen (p.string().c_str(), "r");
512         sub::SubripReader reader (f);
513         fclose (f);
514         auto subs = sub::collect<std::vector<sub::Subtitle>> (reader.subtitles());
515
516         auto i = subs.begin ();
517         vector<sub::Line>::iterator j;
518         vector<sub::Block>::iterator k;
519
520         BOOST_REQUIRE (i != subs.end ());
521
522         SUB_START (sub::Time::from_hms (0, 0, 0, 76), sub::Time::from_hms (0, 0, 1, 116));
523         LINE (0);
524         BLOCK ("This line is normal", "Arial", 30, false, false, false);
525         LINE (1);
526         BLOCK ("This line is bold", "Arial", 30, true, false, false);
527         SUB_END ();
528
529         SUB_START (sub::Time::from_hms (0, 0, 1, 206), sub::Time::from_hms (0, 0, 2, 246));
530         LINE (0);
531         BLOCK ("This line is bold", "Arial", 30, true, false, false);
532         LINE (1);
533         BLOCK ("This line is normal", "Arial", 30, false, false, false);
534         SUB_END ();
535
536         SUB_START (sub::Time::from_hms (0, 0, 2, 308), sub::Time::from_hms (0, 0, 3, 380));
537         LINE (0);
538         BLOCK ("This line is bold", "Arial", 30, true, false, false);
539         LINE (1);
540         BLOCK ("This line is italic", "Arial", 30, false, true, false);
541         SUB_END ();
542
543         SUB_START (sub::Time::from_hms (0, 0, 3, 404), sub::Time::from_hms (0, 0, 4, 484));
544         LINE (0);
545         BLOCK ("This line is italic", "Arial", 30, false, true, false);
546         LINE (1);
547         BLOCK ("This line is bold", "Arial", 30, true, false, false);
548         SUB_END ();
549
550         SUB_START (sub::Time::from_hms (0, 0, 4, 519), sub::Time::from_hms (0, 0, 5, 604));
551         LINE (0);
552         BLOCK ("Last three words are ", "Arial", 30, false, false, false);
553         BLOCK ("bold AND italic", "Arial", 30, true, true, false);
554         LINE (1);
555         BLOCK ("Last three words are ", "Arial", 30, false, false, false);
556         BLOCK ("italic AND bold", "Arial", 30, true, true, false);
557         SUB_END ();
558
559         SUB_START (sub::Time::from_hms (0, 0, 5, 628), sub::Time::from_hms (0, 0, 6, 712));
560         LINE (0);
561         BLOCK ("Last three words are ", "Arial", 30, false, false, false);
562         BLOCK ("bold AND italic", "Arial", 30, true, true, false);
563         LINE (1);
564         BLOCK ("First three words", "Arial", 30, true, true, false);
565         BLOCK (" are italic AND bold", "Arial", 30, false, false, false);
566         SUB_END ();
567
568         SUB_START (sub::Time::from_hms (0, 0, 6, 736), sub::Time::from_hms (0, 0, 8, 31));
569         LINE (0);
570         BLOCK ("Last three words are ", "Arial", 30, false, false, false);
571         BLOCK ("bold AND italic", "Arial", 30, true, true, false);
572         LINE (1);
573         BLOCK ("This line is normal", "Arial", 30, false, false, false);
574         SUB_END ();
575
576         SUB_START (sub::Time::from_hms (0, 0, 8, 94), sub::Time::from_hms (0, 0, 9, 211));
577         LINE (0);
578         BLOCK ("Both lines are bold AND italic", "Arial", 30, true, true, false);
579         LINE (1);
580         BLOCK ("Both lines are bold AND italic", "Arial", 30, true, true, false);
581         SUB_END ();
582 }
583
584 /** Test reading of a .srt file with RTL text */
585 BOOST_AUTO_TEST_CASE (subrip_reader_test4)
586 {
587         boost::filesystem::path p = private_test / "rtl.srt";
588         FILE* f = fopen (p.string().c_str(), "r");
589         sub::SubripReader reader (f);
590         fclose (f);
591         auto subs = sub::collect<std::vector<sub::Subtitle>>(reader.subtitles());
592
593         auto i = subs.begin();
594         std::cout << i->lines.front().blocks.front().text << "\n";
595
596         std::string const t = i->lines.front().blocks.front().text;
597         for (size_t i = 0; i < t.length() - 2; ++i) {
598                 /* Check that unicode U+202B (right-to-left embedding) has been stripped */
599                 unsigned char const a = t[i];
600                 unsigned char const b = t[i+1];
601                 unsigned char const c = t[i+2];
602                 BOOST_CHECK ((a != 0xe2 || b != 0x80 || c != 0xab));
603         }
604
605         BOOST_CHECK (t == "- \"(دريه فابينار)\"");
606 }
607
608 /** Test <font color="rgba(255,255,255,255)"> */
609 BOOST_AUTO_TEST_CASE (subrip_reader_test5)
610 {
611         sub::RawSubtitle rs;
612         sub::SubripReader r;
613         r.convert_line ("<font color=\"rgba(255,128,64,15)\">Foo bar</font>", rs);
614         BOOST_REQUIRE_EQUAL (r._subs.size(), 1);
615         BOOST_CHECK_EQUAL (r._subs.front().text, "Foo bar");
616         BOOST_CHECK_CLOSE (r._subs.front().colour.r, 255.0 / 255, 0.1);
617         BOOST_CHECK_CLOSE (r._subs.front().colour.g, 128.0 / 255, 0.1);
618         BOOST_CHECK_CLOSE (r._subs.front().colour.b, 64.0 / 255, 0.1);
619         r._subs.clear ();
620
621         rs = sub::RawSubtitle ();
622         r.convert_line ("<font color=\"rgba(1, 2 , 3, 4)\">Foo bar</font>", rs);
623         BOOST_REQUIRE_EQUAL (r._subs.size(), 1);
624         BOOST_CHECK_EQUAL (r._subs.front().text, "Foo bar");
625         BOOST_CHECK_CLOSE (r._subs.front().colour.r, 1.0 / 255, 0.1);
626         BOOST_CHECK_CLOSE (r._subs.front().colour.g, 2.0 / 255, 0.1);
627         BOOST_CHECK_CLOSE (r._subs.front().colour.b, 3.0 / 255, 0.1);
628 }
629
630
631 /** Test alignment */
632 BOOST_AUTO_TEST_CASE (subrip_reader_test6)
633 {
634         sub::RawSubtitle rs;
635         rs.vertical_position.line = 0;
636         rs.vertical_position.reference = sub::TOP_OF_SUBTITLE;
637         sub::SubripReader r;
638         r.convert_line ("Hello world", rs);
639         BOOST_REQUIRE_EQUAL (r._subs.size(), 1);
640         BOOST_CHECK_EQUAL (r._subs.front().text, "Hello world");
641         BOOST_REQUIRE (r._subs.front().vertical_position.line);
642         BOOST_CHECK_EQUAL (r._subs.front().vertical_position.line.get(), 0);
643         BOOST_REQUIRE (r._subs.front().vertical_position.reference);
644         BOOST_CHECK_EQUAL (r._subs.front().vertical_position.reference.get(), sub::TOP_OF_SUBTITLE);
645         r._subs.clear ();
646
647         rs = sub::RawSubtitle ();
648         rs.vertical_position.line = 0;
649         r.convert_line ("{\\an1}Hello", rs);
650         BOOST_REQUIRE_EQUAL (r._subs.size(), 1);
651         BOOST_CHECK_EQUAL (r._subs.front().text, "Hello");
652         BOOST_REQUIRE (r._subs.front().vertical_position.line);
653         BOOST_CHECK_EQUAL (r._subs.front().vertical_position.line.get(), 0);
654         BOOST_REQUIRE (r._subs.front().vertical_position.reference);
655         BOOST_CHECK_EQUAL (r._subs.front().vertical_position.reference.get(), sub::BOTTOM_OF_SCREEN);
656         BOOST_CHECK_EQUAL (r._subs.front().horizontal_position.proportional, 0);
657         BOOST_CHECK_EQUAL (r._subs.front().horizontal_position.reference, sub::LEFT_OF_SCREEN);
658         r._subs.clear ();
659
660         rs = sub::RawSubtitle ();
661         rs.vertical_position.line = 0;
662         r.convert_line ("{\\an2}to", rs);
663         BOOST_REQUIRE_EQUAL (r._subs.size(), 1);
664         BOOST_CHECK_EQUAL (r._subs.front().text, "to");
665         BOOST_REQUIRE (r._subs.front().vertical_position.line);
666         BOOST_CHECK_EQUAL (r._subs.front().vertical_position.line.get(), 0);
667         BOOST_REQUIRE (r._subs.front().vertical_position.reference);
668         BOOST_CHECK_EQUAL (r._subs.front().vertical_position.reference.get(), sub::BOTTOM_OF_SCREEN);
669         BOOST_CHECK_EQUAL (r._subs.front().horizontal_position.proportional, 0);
670         BOOST_CHECK_EQUAL (r._subs.front().horizontal_position.reference, sub::HORIZONTAL_CENTRE_OF_SCREEN);
671         r._subs.clear ();
672
673         rs = sub::RawSubtitle ();
674         rs.vertical_position.line = 0;
675         r.convert_line ("{\\an3}you", rs);
676         BOOST_CHECK_EQUAL (r._subs.front().text, "you");
677         BOOST_REQUIRE (r._subs.front().vertical_position.line);
678         BOOST_CHECK_EQUAL (r._subs.front().vertical_position.line.get(), 0);
679         BOOST_REQUIRE (r._subs.front().vertical_position.reference);
680         BOOST_CHECK_EQUAL (r._subs.front().vertical_position.reference.get(), sub::BOTTOM_OF_SCREEN);
681         BOOST_CHECK_EQUAL (r._subs.front().horizontal_position.proportional, 0);
682         BOOST_CHECK_EQUAL (r._subs.front().horizontal_position.reference, sub::RIGHT_OF_SCREEN);
683         r._subs.clear ();
684 }
685
686
687 BOOST_AUTO_TEST_CASE(subrip_with_unicode_line_separator_test)
688 {
689         auto f = fopen ("test/data/newline.srt", "r");
690         BOOST_REQUIRE(f);
691         sub::SubripReader reader(f);
692         fclose(f);
693         auto subs = sub::collect<std::vector<sub::Subtitle>>(reader.subtitles());
694
695         BOOST_REQUIRE_EQUAL(subs.size(), 2U);
696
697         BOOST_REQUIRE_EQUAL(subs[0].lines.size(), 2U);
698         BOOST_REQUIRE_EQUAL(subs[0].lines[0].blocks.size(), 1U);
699         BOOST_CHECK_EQUAL(subs[0].lines[0].blocks[0].text, "Du fühlst dich danach besser.");
700         BOOST_REQUIRE_EQUAL(subs[0].lines[1].blocks.size(), 1U);
701         BOOST_CHECK_EQUAL(subs[0].lines[1].blocks[0].text, "Okay, Kleiner?");
702
703         BOOST_REQUIRE_EQUAL(subs[1].lines.size(), 2U);
704         BOOST_REQUIRE_EQUAL(subs[1].lines[0].blocks.size(), 1U);
705         BOOST_CHECK_EQUAL(subs[1].lines[0].blocks[0].text, "Sie kann es nicht machen");
706         BOOST_REQUIRE_EQUAL(subs[1].lines[1].blocks.size(), 1U);
707         BOOST_CHECK_EQUAL(subs[1].lines[1].blocks[0].text, "wenn du dich bewegst.");
708 }
709