2 Copyright (C) 2012 Carl Hetherington <cth@carlh.net>
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.
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.
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.
21 #include <boost/filesystem.hpp>
22 #include <libxml++/libxml++.h>
28 #include "exceptions.h"
29 #include "subtitle_asset.h"
30 #include "picture_asset.h"
31 #include "sound_asset.h"
33 #include "certificates.h"
35 #define BOOST_TEST_DYN_LINK
36 #define BOOST_TEST_MODULE libdcp_test
37 #include <boost/test/unit_test.hpp>
43 using boost::shared_ptr;
48 return "test/data/32x32_red_square.j2c";
54 return "test/data/1s_24-bit_48k_silence.wav";
58 BOOST_AUTO_TEST_CASE (dcp_test)
62 Kumu::libdcp_test = true;
64 libdcp::Metadata* t = libdcp::Metadata::instance ();
65 t->issuer = "OpenDCP 0.0.25";
66 t->creator = "OpenDCP 0.0.25";
67 t->company_name = "OpenDCP";
68 t->product_name = "OpenDCP";
69 t->product_version = "0.0.25";
70 t->issue_date = "2012-07-17T04:45:18+00:00";
71 boost::filesystem::remove_all ("build/test/foo");
72 boost::filesystem::create_directories ("build/test/foo");
73 libdcp::DCP d ("build/test/foo");
74 shared_ptr<libdcp::CPL> cpl (new libdcp::CPL ("build/test/foo", "A Test DCP", libdcp::FEATURE, 24, 24));
76 shared_ptr<libdcp::MonoPictureAsset> mp (new libdcp::MonoPictureAsset (
88 shared_ptr<libdcp::SoundAsset> ms (new libdcp::SoundAsset (
99 cpl->add_reel (shared_ptr<libdcp::Reel> (new libdcp::Reel (mp, ms, shared_ptr<libdcp::SubtitleAsset> ())));
105 BOOST_AUTO_TEST_CASE (error_test)
107 libdcp::DCP d ("build/test/fred");
109 p.push_back ("frobozz");
111 BOOST_CHECK_THROW (new libdcp::MonoPictureAsset (p, "build/test/fred", "video.mxf", &d.Progress, 24, 24, 32, 32, false), libdcp::FileError);
112 BOOST_CHECK_THROW (new libdcp::SoundAsset (p, "build/test/fred", "audio.mxf", &d.Progress, 24, 24, false), libdcp::FileError);
115 BOOST_AUTO_TEST_CASE (read_dcp)
117 libdcp::DCP d ("test/ref/DCP/foo");
120 list<shared_ptr<const libdcp::CPL> > cpls = d.cpls ();
121 BOOST_CHECK_EQUAL (cpls.size(), 1);
123 BOOST_CHECK_EQUAL (cpls.front()->name(), "A Test DCP");
124 BOOST_CHECK_EQUAL (cpls.front()->content_kind(), libdcp::FEATURE);
125 BOOST_CHECK_EQUAL (cpls.front()->frames_per_second(), 24);
126 BOOST_CHECK_EQUAL (cpls.front()->length(), 24);
129 BOOST_AUTO_TEST_CASE (subtitles1)
131 libdcp::SubtitleAsset subs ("test/data", "subs1.xml");
133 BOOST_CHECK_EQUAL (subs.language(), "French");
135 list<shared_ptr<libdcp::Subtitle> > s = subs.subtitles_at (libdcp::Time (0, 0, 6, 1));
136 BOOST_CHECK_EQUAL (s.size(), 1);
137 BOOST_CHECK_EQUAL (*(s.front().get()), libdcp::Subtitle (
140 libdcp::Color (255, 255, 255),
142 libdcp::Time (0, 0, 5, 198),
143 libdcp::Time (0, 0, 7, 115),
146 "My jacket was Idi Amin's",
148 libdcp::Color (0, 0, 0),
149 libdcp::Time (0, 0, 0, 1),
150 libdcp::Time (0, 0, 0, 1)
153 s = subs.subtitles_at (libdcp::Time (0, 0, 7, 190));
154 BOOST_CHECK_EQUAL (s.size(), 2);
155 BOOST_CHECK_EQUAL (*(s.front().get()), libdcp::Subtitle (
158 libdcp::Color (255, 255, 255),
160 libdcp::Time (0, 0, 7, 177),
161 libdcp::Time (0, 0, 11, 31),
164 "My corset was H.M. The Queen's",
166 libdcp::Color (0, 0, 0),
167 libdcp::Time (0, 0, 0, 1),
168 libdcp::Time (0, 0, 0, 1)
170 BOOST_CHECK_EQUAL (*(s.back().get()), libdcp::Subtitle (
173 libdcp::Color (255, 255, 255),
175 libdcp::Time (0, 0, 7, 177),
176 libdcp::Time (0, 0, 11, 31),
179 "My large wonderbra",
181 libdcp::Color (0, 0, 0),
182 libdcp::Time (0, 0, 0, 1),
183 libdcp::Time (0, 0, 0, 1)
186 s = subs.subtitles_at (libdcp::Time (0, 0, 11, 95));
187 BOOST_CHECK_EQUAL (s.size(), 1);
188 BOOST_CHECK_EQUAL (*(s.back().get()), libdcp::Subtitle (
191 libdcp::Color (255, 255, 255),
193 libdcp::Time (0, 0, 11, 94),
194 libdcp::Time (0, 0, 13, 63),
197 "Once belonged to the Shah",
199 libdcp::Color (0, 0, 0),
200 libdcp::Time (0, 0, 0, 1),
201 libdcp::Time (0, 0, 0, 1)
204 s = subs.subtitles_at (libdcp::Time (0, 0, 14, 42));
205 BOOST_CHECK_EQUAL (s.size(), 1);
206 BOOST_CHECK_EQUAL (*(s.back().get()), libdcp::Subtitle (
209 libdcp::Color (255, 255, 255),
211 libdcp::Time (0, 0, 13, 104),
212 libdcp::Time (0, 0, 15, 177),
215 "And these are Roy Hattersley's jeans",
217 libdcp::Color (0, 0, 0),
218 libdcp::Time (0, 0, 0, 1),
219 libdcp::Time (0, 0, 0, 1)
223 BOOST_AUTO_TEST_CASE (subtitles2)
225 libdcp::SubtitleAsset subs ("test/data", "subs2.xml");
227 list<shared_ptr<libdcp::Subtitle> > s = subs.subtitles_at (libdcp::Time (0, 0, 42, 100));
228 BOOST_CHECK_EQUAL (s.size(), 2);
229 BOOST_CHECK_EQUAL (*(s.front().get()), libdcp::Subtitle (
232 libdcp::Color (255, 255, 255),
234 libdcp::Time (0, 0, 41, 62),
235 libdcp::Time (0, 0, 43, 52),
238 "At afternoon tea with John Peel",
240 libdcp::Color (0, 0, 0),
241 libdcp::Time (0, 0, 0, 0),
242 libdcp::Time (0, 0, 0, 0)
244 BOOST_CHECK_EQUAL (*(s.back().get()), libdcp::Subtitle (
247 libdcp::Color (255, 255, 255),
249 libdcp::Time (0, 0, 41, 62),
250 libdcp::Time (0, 0, 43, 52),
253 "I enquired if his accent was real",
255 libdcp::Color (0, 0, 0),
256 libdcp::Time (0, 0, 0, 0),
257 libdcp::Time (0, 0, 0, 0)
260 s = subs.subtitles_at (libdcp::Time (0, 0, 50, 50));
261 BOOST_CHECK_EQUAL (s.size(), 2);
262 BOOST_CHECK_EQUAL (*(s.front().get()), libdcp::Subtitle (
265 libdcp::Color (255, 255, 255),
267 libdcp::Time (0, 0, 50, 42),
268 libdcp::Time (0, 0, 52, 21),
271 "He said \"out of the house",
273 libdcp::Color (0, 0, 0),
274 libdcp::Time (0, 0, 0, 0),
275 libdcp::Time (0, 0, 0, 0)
277 BOOST_CHECK_EQUAL (*(s.back().get()), libdcp::Subtitle (
280 libdcp::Color (255, 255, 255),
282 libdcp::Time (0, 0, 50, 42),
283 libdcp::Time (0, 0, 52, 21),
286 "I'm incredibly scouse",
288 libdcp::Color (0, 0, 0),
289 libdcp::Time (0, 0, 0, 0),
290 libdcp::Time (0, 0, 0, 0)
293 s = subs.subtitles_at (libdcp::Time (0, 1, 2, 300));
294 BOOST_CHECK_EQUAL (s.size(), 2);
295 BOOST_CHECK_EQUAL (*(s.front().get()), libdcp::Subtitle (
298 libdcp::Color (255, 255, 255),
300 libdcp::Time (0, 1, 2, 208),
301 libdcp::Time (0, 1, 4, 10),
304 "At home it depends how I feel.\"",
306 libdcp::Color (0, 0, 0),
307 libdcp::Time (0, 0, 0, 0),
308 libdcp::Time (0, 0, 0, 0)
310 BOOST_CHECK_EQUAL (*(s.back().get()), libdcp::Subtitle (
313 libdcp::Color (255, 255, 255),
315 libdcp::Time (0, 1, 2, 208),
316 libdcp::Time (0, 1, 4, 10),
319 "I spent a long weekend in Brighton",
321 libdcp::Color (0, 0, 0),
322 libdcp::Time (0, 0, 0, 0),
323 libdcp::Time (0, 0, 0, 0)
326 s = subs.subtitles_at (libdcp::Time (0, 1, 15, 50));
327 BOOST_CHECK_EQUAL (s.size(), 2);
328 BOOST_CHECK_EQUAL (*(s.front().get()), libdcp::Subtitle (
331 libdcp::Color (255, 255, 255),
333 libdcp::Time (0, 1, 15, 42),
334 libdcp::Time (0, 1, 16, 42),
337 "With the legendary Miss Enid Blyton",
339 libdcp::Color (0, 0, 0),
340 libdcp::Time (0, 0, 0, 0),
341 libdcp::Time (0, 0, 0, 0)
343 BOOST_CHECK_EQUAL (*(s.back().get()), libdcp::Subtitle (
346 libdcp::Color (255, 255, 255),
348 libdcp::Time (0, 1, 15, 42),
349 libdcp::Time (0, 1, 16, 42),
352 "She said \"you be Noddy",
354 libdcp::Color (0, 0, 0),
355 libdcp::Time (0, 0, 0, 0),
356 libdcp::Time (0, 0, 0, 0)
359 s = subs.subtitles_at (libdcp::Time (0, 1, 27, 200));
360 BOOST_CHECK_EQUAL (s.size(), 2);
361 BOOST_CHECK_EQUAL (*(s.front().get()), libdcp::Subtitle (
364 libdcp::Color (255, 255, 255),
366 libdcp::Time (0, 1, 27, 115),
367 libdcp::Time (0, 1, 28, 208),
370 "That curious creature the Sphinx",
372 libdcp::Color (0, 0, 0),
373 libdcp::Time (0, 0, 0, 0),
374 libdcp::Time (0, 0, 0, 0)
376 BOOST_CHECK_EQUAL (*(s.back().get()), libdcp::Subtitle (
379 libdcp::Color (255, 255, 255),
381 libdcp::Time (0, 1, 27, 115),
382 libdcp::Time (0, 1, 28, 208),
385 "Is smarter than anyone thinks",
387 libdcp::Color (0, 0, 0),
388 libdcp::Time (0, 0, 0, 0),
389 libdcp::Time (0, 0, 0, 0)
392 s = subs.subtitles_at (libdcp::Time (0, 1, 42, 300));
393 BOOST_CHECK_EQUAL (s.size(), 2);
394 BOOST_CHECK_EQUAL (*(s.front().get()), libdcp::Subtitle (
397 libdcp::Color (255, 255, 255),
399 libdcp::Time (0, 1, 42, 229),
400 libdcp::Time (0, 1, 45, 62),
403 "It sits there and smirks",
405 libdcp::Color (0, 0, 0),
406 libdcp::Time (0, 0, 0, 0),
407 libdcp::Time (0, 0, 0, 0)
409 BOOST_CHECK_EQUAL (*(s.back().get()), libdcp::Subtitle (
412 libdcp::Color (255, 255, 255),
414 libdcp::Time (0, 1, 42, 229),
415 libdcp::Time (0, 1, 45, 62),
418 "And you don't think it works",
420 libdcp::Color (0, 0, 0),
421 libdcp::Time (0, 0, 0, 0),
422 libdcp::Time (0, 0, 0, 0)
425 s = subs.subtitles_at (libdcp::Time (0, 1, 45, 200));
426 BOOST_CHECK_EQUAL (s.size(), 2);
427 BOOST_CHECK_EQUAL (*(s.front().get()), libdcp::Subtitle (
430 libdcp::Color (255, 255, 255),
432 libdcp::Time (0, 1, 45, 146),
433 libdcp::Time (0, 1, 47, 94),
436 "Then when you're not looking, it winks.",
438 libdcp::Color (0, 0, 0),
439 libdcp::Time (0, 0, 0, 0),
440 libdcp::Time (0, 0, 0, 0)
442 BOOST_CHECK_EQUAL (*(s.back().get()), libdcp::Subtitle (
445 libdcp::Color (255, 255, 255),
447 libdcp::Time (0, 1, 45, 146),
448 libdcp::Time (0, 1, 47, 94),
451 "When it snows you will find Sister Sledge",
453 libdcp::Color (0, 0, 0),
454 libdcp::Time (0, 0, 0, 0),
455 libdcp::Time (0, 0, 0, 0)
458 s = subs.subtitles_at (libdcp::Time (0, 1, 47, 249));
459 BOOST_CHECK_EQUAL (s.size(), 2);
460 BOOST_CHECK_EQUAL (*(s.front().get()), libdcp::Subtitle (
463 libdcp::Color (255, 255, 255),
465 libdcp::Time (0, 1, 47, 146),
466 libdcp::Time (0, 1, 48, 167),
469 "Out mooning, at night, on the ledge",
471 libdcp::Color (0, 0, 0),
472 libdcp::Time (0, 0, 0, 0),
473 libdcp::Time (0, 0, 0, 0)
475 BOOST_CHECK_EQUAL (*(s.back().get()), libdcp::Subtitle (
478 libdcp::Color (255, 255, 255),
480 libdcp::Time (0, 1, 47, 146),
481 libdcp::Time (0, 1, 48, 167),
486 libdcp::Color (0, 0, 0),
487 libdcp::Time (0, 0, 0, 0),
488 libdcp::Time (0, 0, 0, 0)
491 s = subs.subtitles_at (libdcp::Time (0, 2, 6, 210));
492 BOOST_CHECK_EQUAL (s.size(), 2);
493 BOOST_CHECK_EQUAL (*(s.front().get()), libdcp::Subtitle (
496 libdcp::Color (255, 255, 255),
498 libdcp::Time (0, 2, 5, 208),
499 libdcp::Time (0, 2, 7, 31),
504 libdcp::Color (0, 0, 0),
505 libdcp::Time (0, 0, 0, 0),
506 libdcp::Time (0, 0, 0, 0)
508 BOOST_CHECK_EQUAL (*(s.back().get()), libdcp::Subtitle (
511 libdcp::Color (255, 255, 255),
513 libdcp::Time (0, 2, 5, 208),
514 libdcp::Time (0, 2, 7, 31),
519 libdcp::Color (0, 0, 0),
520 libdcp::Time (0, 0, 0, 0),
521 libdcp::Time (0, 0, 0, 0)
528 BOOST_AUTO_TEST_CASE (dcp_time)
530 libdcp::Time t (977143, 24);
532 BOOST_CHECK_EQUAL (t.t, 73);
533 BOOST_CHECK_EQUAL (t.s, 34);
534 BOOST_CHECK_EQUAL (t.m, 18);
535 BOOST_CHECK_EQUAL (t.h, 11);
536 BOOST_CHECK_EQUAL (t.to_string(), "11:18:34:73");
537 BOOST_CHECK_EQUAL (t.to_ticks(), 1017923);
539 libdcp::Time a (3, 2, 3, 4);
540 libdcp::Time b (2, 3, 4, 5);
542 libdcp::Time r = a - b;
543 BOOST_CHECK_EQUAL (r.h, 0);
544 BOOST_CHECK_EQUAL (r.m, 58);
545 BOOST_CHECK_EQUAL (r.s, 58);
546 BOOST_CHECK_EQUAL (r.t, 249);
547 BOOST_CHECK_EQUAL (r.to_string(), "0:58:58:249");
548 BOOST_CHECK_EQUAL (r.to_ticks(), 88699);
550 a = libdcp::Time (1, 58, 56, 240);
551 b = libdcp::Time (1, 7, 12, 120);
553 BOOST_CHECK_EQUAL (r.h, 3);
554 BOOST_CHECK_EQUAL (r.m, 6);
555 BOOST_CHECK_EQUAL (r.s, 9);
556 BOOST_CHECK_EQUAL (r.t, 110);
557 BOOST_CHECK_EQUAL (r.to_string(), "3:6:9:110");
558 BOOST_CHECK_EQUAL (r.to_ticks(), 279335);
560 a = libdcp::Time (24, 12, 6, 3);
561 b = libdcp::Time (16, 8, 4, 2);
562 BOOST_CHECK_CLOSE (a / b, 1.5, 1e-5);
565 BOOST_AUTO_TEST_CASE (color)
567 libdcp::Color c ("FFFF0000");
569 BOOST_CHECK_EQUAL (c.r, 255);
570 BOOST_CHECK_EQUAL (c.g, 0);
571 BOOST_CHECK_EQUAL (c.b, 0);
572 BOOST_CHECK_EQUAL (c.to_argb_string(), "FFFF0000");
574 c = libdcp::Color ("FF00FF00");
576 BOOST_CHECK_EQUAL (c.r, 0);
577 BOOST_CHECK_EQUAL (c.g, 255);
578 BOOST_CHECK_EQUAL (c.b, 0);
579 BOOST_CHECK_EQUAL (c.to_argb_string(), "FF00FF00");
581 c = libdcp::Color ("FF0000FF");
583 BOOST_CHECK_EQUAL (c.r, 0);
584 BOOST_CHECK_EQUAL (c.g, 0);
585 BOOST_CHECK_EQUAL (c.b, 255);
586 BOOST_CHECK_EQUAL (c.to_argb_string(), "FF0000FF");
590 BOOST_AUTO_TEST_CASE (encryption)
592 Kumu::libdcp_test = true;
594 libdcp::Metadata* t = libdcp::Metadata::instance ();
595 t->issuer = "OpenDCP 0.0.25";
596 t->creator = "OpenDCP 0.0.25";
597 t->company_name = "OpenDCP";
598 t->product_name = "OpenDCP";
599 t->product_version = "0.0.25";
600 t->issue_date = "2012-07-17T04:45:18+00:00";
601 boost::filesystem::remove_all ("build/test/bar");
602 boost::filesystem::create_directories ("build/test/bar");
603 libdcp::DCP d ("build/test/bar");
604 d.set_encrypted (true);
605 d.set_certificates (libdcp::CertificateChain ("test/data/certificate_chain"));
606 d.set_signer_key ("test/data/signer.key");
607 shared_ptr<libdcp::CPL> cpl (new libdcp::CPL ("build/test/bar", "A Test DCP", libdcp::FEATURE, 24, 24));
609 shared_ptr<libdcp::MonoPictureAsset> mp (new libdcp::MonoPictureAsset (
621 shared_ptr<libdcp::SoundAsset> ms (new libdcp::SoundAsset (
632 cpl->add_reel (shared_ptr<libdcp::Reel> (new libdcp::Reel (mp, ms, shared_ptr<libdcp::SubtitleAsset> ())));
637 cpl->make_kdm(d.certificates(), d.signer_key(), d.certificates().leaf())->write_to_file_formatted ("build/test/bar.kdm.xml", "UTF-8");
640 BOOST_AUTO_TEST_CASE (certificates)
642 libdcp::CertificateChain c ("test/data/certificate_chain");
643 BOOST_CHECK_EQUAL (c._certificates.size(), 3);
647 "/O=example.org/OU=example.org/CN=.smpte-430-2.ROOT.NOT_FOR_PRODUCTION/dnQualifier=rTeK7x+nopFkyphflooz6p2ZM7A="
651 libdcp::Certificate::name_for_xml (c.root()->issuer()),
652 "dnQualifier=rTeK7x\\+nopFkyphflooz6p2ZM7A=,CN=.smpte-430-2.ROOT.NOT_FOR_PRODUCTION,OU=example.org,O=example.org"
655 BOOST_CHECK_EQUAL (c.root()->serial(), "5");
658 libdcp::Certificate::name_for_xml (c.root()->subject()),
659 "dnQualifier=rTeK7x\\+nopFkyphflooz6p2ZM7A=,CN=.smpte-430-2.ROOT.NOT_FOR_PRODUCTION,OU=example.org,O=example.org"