Tidy subrip parsing a bit and fix failure to persist
[libsub.git] / test / subrip_reader_test.cc
1 /*
2     Copyright (C) 2014-2015 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 "collect.h"
24 #include <boost/test/unit_test.hpp>
25 #include <boost/filesystem.hpp>
26 #include <fstream>
27 #include <cmath>
28 #include <iostream>
29
30 using std::list;
31 using std::cerr;
32 using std::ifstream;
33 using std::vector;
34 using std::fabs;
35
36 /* Test reading of a Subrip file */
37 BOOST_AUTO_TEST_CASE (subrip_reader_test)
38 {
39         FILE* f = fopen ("test/data/test.srt", "r");
40         sub::SubripReader reader (f);
41         fclose (f);
42         list<sub::Subtitle> subs = sub::collect<std::list<sub::Subtitle> > (reader.subtitles ());
43
44         list<sub::Subtitle>::iterator i = subs.begin ();
45
46
47         /* First subtitle */
48
49         BOOST_CHECK (i != subs.end ());
50         BOOST_CHECK_EQUAL (i->from, sub::Time::from_hms (0, 0, 41, 90));
51         BOOST_CHECK_EQUAL (i->to, sub::Time::from_hms (0, 0, 42, 210));
52
53         list<sub::Line>::iterator j = i->lines.begin ();
54         BOOST_CHECK (j != i->lines.end ());
55         BOOST_CHECK_EQUAL (j->blocks.size(), 1);
56         sub::Block b = j->blocks.front ();
57         BOOST_CHECK_EQUAL (b.text, "This is a subtitle");
58         BOOST_CHECK_EQUAL (b.font.get(), "Arial");
59         BOOST_CHECK_EQUAL (b.font_size.points().get(), 48);
60         BOOST_CHECK_EQUAL (b.bold, false);
61         BOOST_CHECK_EQUAL (b.italic, false);
62         BOOST_CHECK_EQUAL (b.underline, false);
63         BOOST_CHECK_EQUAL (j->vertical_position.line.get(), 0);
64         BOOST_CHECK_EQUAL (j->vertical_position.reference.get(), sub::TOP_OF_SUBTITLE);
65         ++j;
66
67         BOOST_CHECK (j != i->lines.end ());
68         BOOST_CHECK_EQUAL (j->blocks.size(), 1);
69         b = j->blocks.front ();
70         BOOST_CHECK_EQUAL (b.text, "and that's a line break");
71         BOOST_CHECK_EQUAL (b.font.get(), "Arial");
72         BOOST_CHECK_EQUAL (b.font_size.points().get(), 48);
73         BOOST_CHECK_EQUAL (b.bold, false);
74         BOOST_CHECK_EQUAL (b.italic, false);
75         BOOST_CHECK_EQUAL (b.underline, false);
76         BOOST_CHECK_EQUAL (j->vertical_position.line.get(), 1);
77         BOOST_CHECK_EQUAL (j->vertical_position.reference.get(), sub::TOP_OF_SUBTITLE);
78         ++i;
79
80
81         /* Second subtitle */
82
83         BOOST_CHECK (i != subs.end ());
84         BOOST_CHECK_EQUAL (i->from, sub::Time::from_hms (0, 1, 1, 10));
85         BOOST_CHECK_EQUAL (i->to, sub::Time::from_hms (0, 1, 2, 100));
86
87         BOOST_CHECK_EQUAL (i->lines.size(), 1);
88         sub::Line l = i->lines.front ();
89         BOOST_CHECK_EQUAL (l.blocks.size(), 7);
90         BOOST_CHECK_EQUAL (l.vertical_position.line.get(), 0);
91         BOOST_CHECK_EQUAL (l.vertical_position.reference.get(), sub::TOP_OF_SUBTITLE);
92
93         list<sub::Block>::iterator k = l.blocks.begin ();
94
95         BOOST_CHECK (k != l.blocks.end ());
96         BOOST_CHECK_EQUAL (k->text, "This is some ");
97         BOOST_CHECK_EQUAL (k->font.get(), "Arial");
98         BOOST_CHECK_EQUAL (k->font_size.points().get(), 48);
99         BOOST_CHECK_EQUAL (k->bold, false);
100         BOOST_CHECK_EQUAL (k->italic, false);
101         BOOST_CHECK_EQUAL (k->underline, false);
102         ++k;
103
104         BOOST_CHECK (k != l.blocks.end ());
105         BOOST_CHECK_EQUAL (k->text, "bold");
106         BOOST_CHECK_EQUAL (k->font.get(), "Arial");
107         BOOST_CHECK_EQUAL (k->font_size.points().get(), 48);
108         BOOST_CHECK_EQUAL (k->bold, true);
109         BOOST_CHECK_EQUAL (k->italic, false);
110         BOOST_CHECK_EQUAL (k->underline, false);
111         ++k;
112
113         BOOST_CHECK (k != l.blocks.end ());
114         BOOST_CHECK_EQUAL (k->text, " and some ");
115         BOOST_CHECK_EQUAL (k->font.get(), "Arial");
116         BOOST_CHECK_EQUAL (k->font_size.points().get(), 48);
117         BOOST_CHECK_EQUAL (k->bold, false);
118         BOOST_CHECK_EQUAL (k->italic, false);
119         BOOST_CHECK_EQUAL (k->underline, false);
120         ++k;
121
122         BOOST_CHECK (k != l.blocks.end ());
123         BOOST_CHECK_EQUAL (k->text, "bold italic");
124         BOOST_CHECK_EQUAL (k->font.get(), "Arial");
125         BOOST_CHECK_EQUAL (k->font_size.points().get(), 48);
126         BOOST_CHECK_EQUAL (k->bold, true);
127         BOOST_CHECK_EQUAL (k->italic, true);
128         BOOST_CHECK_EQUAL (k->underline, false);
129         ++k;
130
131         BOOST_CHECK (k != l.blocks.end ());
132         BOOST_CHECK_EQUAL (k->text, " and some ");
133         BOOST_CHECK_EQUAL (k->font.get(), "Arial");
134         BOOST_CHECK_EQUAL (k->font_size.points().get(), 48);
135         BOOST_CHECK_EQUAL (k->bold, false);
136         BOOST_CHECK_EQUAL (k->italic, false);
137         BOOST_CHECK_EQUAL (k->underline, false);
138         ++k;
139
140         BOOST_CHECK (k != l.blocks.end ());
141         BOOST_CHECK_EQUAL (k->text, "underlined");
142         BOOST_CHECK_EQUAL (k->font.get(), "Arial");
143         BOOST_CHECK_EQUAL (k->font_size.points().get(), 48);
144         BOOST_CHECK_EQUAL (k->bold, false);
145         BOOST_CHECK_EQUAL (k->italic, false);
146         BOOST_CHECK_EQUAL (k->underline, true);
147         ++k;
148
149         BOOST_CHECK (k != l.blocks.end ());
150         BOOST_CHECK_EQUAL (k->text, ".");
151         BOOST_CHECK_EQUAL (k->font.get(), "Arial");
152         BOOST_CHECK_EQUAL (k->font_size.points().get(), 48);
153         BOOST_CHECK_EQUAL (k->bold, false);
154         BOOST_CHECK_EQUAL (k->italic, false);
155         BOOST_CHECK_EQUAL (k->underline, false);
156         ++k;
157
158         BOOST_CHECK (k == l.blocks.end ());
159 }
160
161 /* Test reading of another Subrip file */
162 BOOST_AUTO_TEST_CASE (subrip_reader_test2)
163 {
164         FILE* f = fopen ("test/data/test2.srt", "r");
165         sub::SubripReader reader (f);
166         fclose (f);
167         list<sub::Subtitle> subs = sub::collect<list<sub::Subtitle> > (reader.subtitles ());
168
169         list<sub::Subtitle>::const_iterator i = subs.begin();
170
171         BOOST_CHECK (i != subs.end ());
172         BOOST_CHECK_EQUAL (i->from, sub::Time::from_hms (0, 1, 49, 200));
173         BOOST_CHECK_EQUAL (i->to, sub::Time::from_hms (0, 1, 52, 351));
174         BOOST_CHECK_EQUAL (i->lines.size(), 2);
175         BOOST_CHECK_EQUAL (i->lines.front().blocks.front().text, "This is a subtitle, and it goes ");
176         BOOST_CHECK_EQUAL (i->lines.back().blocks.front().text, "over two lines.");
177
178         ++i;
179         BOOST_CHECK (i != subs.end ());
180         BOOST_CHECK_EQUAL (i->from, sub::Time::from_hms (0, 1, 52, 440));
181         BOOST_CHECK_EQUAL (i->to, sub::Time::from_hms (0, 1, 54, 351));
182         BOOST_CHECK_EQUAL (i->lines.size(), 1);
183         BOOST_CHECK_EQUAL (i->lines.front().blocks.front().text, "We have emboldened this");
184         BOOST_CHECK_EQUAL (i->lines.front().blocks.front().bold, true);
185
186         ++i;
187         BOOST_CHECK (i != subs.end ());
188         BOOST_CHECK_EQUAL (i->from, sub::Time::from_hms (0, 1, 54, 440));
189         BOOST_CHECK_EQUAL (i->to, sub::Time::from_hms (0, 1, 56, 590));
190         BOOST_CHECK_EQUAL (i->lines.size(), 1);
191         BOOST_CHECK_EQUAL (i->lines.front().blocks.front().text, "And italicised this.");
192         BOOST_CHECK_EQUAL (i->lines.front().blocks.front().italic, true);
193
194         ++i;
195         BOOST_CHECK (i != subs.end ());
196         BOOST_CHECK_EQUAL (i->from, sub::Time::from_hms (0, 1, 56, 680));
197         BOOST_CHECK_EQUAL (i->to, sub::Time::from_hms (0, 1, 58, 955));
198         BOOST_CHECK_EQUAL (i->lines.size(), 1);
199         BOOST_CHECK_EQUAL (i->lines.front().blocks.front().text, "Shall I compare thee to a summers' day?");
200
201         ++i;
202         BOOST_CHECK (i != subs.end ());
203         BOOST_CHECK_EQUAL (i->from, sub::Time::from_hms (0, 2, 0, 840));
204         BOOST_CHECK_EQUAL (i->to, sub::Time::from_hms (0, 2, 3, 400));
205         BOOST_CHECK_EQUAL (i->lines.size(), 1);
206         BOOST_CHECK_EQUAL (i->lines.front().blocks.front().text, "Is this a dagger I see before me?");
207
208         ++i;
209         BOOST_CHECK (i != subs.end ());
210         BOOST_CHECK_EQUAL (i->from, sub::Time::from_hms (0, 3, 54, 560));
211         BOOST_CHECK_EQUAL (i->to, sub::Time::from_hms (0, 3, 56, 471));
212         BOOST_CHECK_EQUAL (i->lines.size(), 1);
213         BOOST_CHECK_EQUAL (i->lines.front().blocks.front().text, "Hello world.");
214
215         ++i;
216         BOOST_CHECK (i != subs.end ());
217         BOOST_CHECK_EQUAL (i->from, sub::Time::from_hms (0, 4, 50, 123));
218         BOOST_CHECK_EQUAL (i->to, sub::Time::from_hms (0, 4, 55, 23));
219         BOOST_CHECK_EQUAL (i->lines.size(), 2);
220         BOOST_CHECK_EQUAL (i->lines.front().blocks.front().text, "Some italics over");
221         BOOST_CHECK_EQUAL (i->lines.front().blocks.front().italic, true);
222         BOOST_CHECK_EQUAL (i->lines.back().blocks.front().text, "multiple lines");
223         BOOST_CHECK_EQUAL (i->lines.back().blocks.front().italic, true);
224
225         ++i;
226         BOOST_CHECK (i == subs.end ());
227 }
228
229 /** Test SubripReader::convert_line */
230 BOOST_AUTO_TEST_CASE (subrip_reader_convert_line_test)
231 {
232         sub::SubripReader r;
233
234         sub::RawSubtitle rs;
235         r.convert_line ("Hello world", rs);
236         BOOST_CHECK_EQUAL (r._subs.size(), 1);
237         BOOST_CHECK_EQUAL (r._subs.front().text, "Hello world");
238         r._subs.clear ();
239
240         rs = sub::RawSubtitle();
241         r.convert_line ("<b>Hello world</b>", rs);
242         BOOST_CHECK_EQUAL (r._subs.size(), 1);
243         BOOST_CHECK_EQUAL (r._subs.front().text, "Hello world");
244         BOOST_CHECK_EQUAL (r._subs.front().bold, true);
245         r._subs.clear ();
246
247         rs = sub::RawSubtitle();
248         r.convert_line ("<i>Hello world</i>", rs);
249         BOOST_CHECK_EQUAL (r._subs.size(), 1);
250         BOOST_CHECK_EQUAL (r._subs.front().text, "Hello world");
251         BOOST_CHECK_EQUAL (r._subs.front().italic, true);
252         r._subs.clear ();
253
254         rs = sub::RawSubtitle();
255         r.convert_line ("<u>Hello world</u>", rs);
256         BOOST_CHECK_EQUAL (r._subs.size(), 1);
257         BOOST_CHECK_EQUAL (r._subs.front().text, "Hello world");
258         BOOST_CHECK_EQUAL (r._subs.front().underline, true);
259         r._subs.clear ();
260
261         rs = sub::RawSubtitle();
262         r.convert_line ("{b}Hello world{/b}", rs);
263         BOOST_CHECK_EQUAL (r._subs.size(), 1);
264         BOOST_CHECK_EQUAL (r._subs.front().text, "Hello world");
265         BOOST_CHECK_EQUAL (r._subs.front().bold, true);
266         r._subs.clear ();
267
268         rs = sub::RawSubtitle();
269         r.convert_line ("{i}Hello world{/i}", rs);
270         BOOST_CHECK_EQUAL (r._subs.size(), 1);
271         BOOST_CHECK_EQUAL (r._subs.front().text, "Hello world");
272         BOOST_CHECK_EQUAL (r._subs.front().italic, true);
273         r._subs.clear ();
274
275         rs = sub::RawSubtitle();
276         r.convert_line ("{u}Hello world{/u}", rs);
277         BOOST_CHECK_EQUAL (r._subs.size(), 1);
278         BOOST_CHECK_EQUAL (r._subs.front().text, "Hello world");
279         BOOST_CHECK_EQUAL (r._subs.front().underline, true);
280         r._subs.clear ();
281
282         rs = sub::RawSubtitle();
283         r.convert_line ("<b>This is <i>nesting</i> of subtitles</b>", rs);
284         BOOST_CHECK_EQUAL (r._subs.size(), 3);
285         list<sub::RawSubtitle>::iterator i = r._subs.begin ();
286         BOOST_CHECK_EQUAL (i->text, "This is ");
287         BOOST_CHECK_EQUAL (i->bold, true);
288         BOOST_CHECK_EQUAL (i->italic, false);
289         ++i;
290         BOOST_CHECK_EQUAL (i->text, "nesting");
291         BOOST_CHECK_EQUAL (i->bold, true);
292         BOOST_CHECK_EQUAL (i->italic, true);
293         ++i;
294         BOOST_CHECK_EQUAL (i->text, " of subtitles");
295         BOOST_CHECK_EQUAL (i->bold, true);
296         BOOST_CHECK_EQUAL (i->italic, false);
297         ++i;
298         r._subs.clear ();
299
300         rs = sub::RawSubtitle();
301         r.convert_line ("<font color=\"#ff00ff\">simple color</font>", rs);
302         BOOST_CHECK_EQUAL (r._subs.size(), 1);
303         BOOST_CHECK_EQUAL (r._subs.front().text, "simple color");
304         BOOST_CHECK_EQUAL (r._subs.front().bold, false);
305         BOOST_CHECK_CLOSE (r._subs.front().colour.r, 1, 0.1);
306         BOOST_CHECK (fabs (r._subs.front().colour.g) < 0.01);
307         BOOST_CHECK_CLOSE (r._subs.front().colour.b, 1, 0.1);
308         r._subs.clear ();
309
310         rs = sub::RawSubtitle();
311         r.convert_line ("<font color=\"#ff0000\">some red text <b>in bold</b></font>", rs);
312         BOOST_CHECK_EQUAL (r._subs.size(), 2);
313         i = r._subs.begin ();
314         BOOST_CHECK_EQUAL (i->text, "some red text ");
315         BOOST_CHECK_EQUAL (i->bold, false);
316         BOOST_CHECK_CLOSE (i->colour.r, 1, 0.1);
317         BOOST_CHECK (fabs (i->colour.g) < 0.01);
318         BOOST_CHECK (fabs (i->colour.b) < 0.01);
319         ++i;
320         BOOST_CHECK_EQUAL (i->text, "in bold");
321         BOOST_CHECK_EQUAL (i->bold, true);
322         BOOST_CHECK_CLOSE (i->colour.r, 1, 0.1);
323         BOOST_CHECK (fabs (i->colour.g) < 0.01);
324         BOOST_CHECK (fabs (i->colour.b) < 0.01);
325         r._subs.clear ();
326
327         rs = sub::RawSubtitle();
328         r.convert_line ("<font color=\"#0000ff\">some blue text <b>in bold</b></font>", rs);
329         BOOST_CHECK_EQUAL (r._subs.size(), 2);
330         i = r._subs.begin ();
331         BOOST_CHECK_EQUAL (i->text, "some blue text ");
332         BOOST_CHECK_EQUAL (i->bold, false);
333         BOOST_CHECK (fabs (i->colour.r) < 0.01);
334         BOOST_CHECK (fabs (i->colour.g) < 0.01);
335         BOOST_CHECK_CLOSE (i->colour.b, 1, 0.1);
336         ++i;
337         BOOST_CHECK_EQUAL (i->text, "in bold");
338         BOOST_CHECK_EQUAL (i->bold, true);
339         BOOST_CHECK (fabs (i->colour.r) < 0.01);
340         BOOST_CHECK (fabs (i->colour.g) < 0.01);
341         BOOST_CHECK_CLOSE (i->colour.b, 1, 0.1);
342         r._subs.clear ();
343 }
344
345 /** Test SubripReader::convert_time */
346 BOOST_AUTO_TEST_CASE (subrip_reader_convert_time_test)
347 {
348         BOOST_CHECK_EQUAL (sub::SubripReader::convert_time ("00:03:10,500"), sub::Time::from_hms (0, 3, 10, 500));
349         BOOST_CHECK_EQUAL (sub::SubripReader::convert_time ("04:19:51,782"), sub::Time::from_hms (4, 19, 51, 782));
350 }
351
352 static void
353 test (boost::filesystem::path p)
354 {
355         p = private_test / p;
356         FILE* f = fopen (p.string().c_str(), "r");
357         BOOST_CHECK (f);
358         if (!f) {
359                 cerr << p << " not found.\n";
360                 return;
361         }
362         sub::SubripReader r (f);
363         fclose (f);
364 }
365
366 /** Test of reading some typical .srt files */
367 BOOST_AUTO_TEST_CASE (subrip_read_test)
368 {
369         test ("sintel_en.srt");
370         test ("sintel_fr.srt");
371         test ("Fight.Club.1999.720p.BRRip.x264-x0r.srt");
372 }