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