2 Copyright (C) 2018-2020 Carl Hetherington <cth@carlh.net>
4 This file is part of libdcp.
6 libdcp is free software; you can redistribute it and/or modify
7 it under the terms of the GNU General Public License as published by
8 the Free Software Foundation; either version 2 of the License, or
9 (at your option) any later version.
11 libdcp is distributed in the hope that it will be useful,
12 but WITHOUT ANY WARRANTY; without even the implied warranty of
13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 GNU General Public License for more details.
16 You should have received a copy of the GNU General Public License
17 along with libdcp. If not, see <http://www.gnu.org/licenses/>.
19 In addition, as a special exception, the copyright holders give
20 permission to link the code of portions of this program with the
21 OpenSSL library under certain conditions as described in each
22 individual source file, and distribute linked combinations
25 You must obey the GNU General Public License in all respects
26 for all of the code used other than OpenSSL. If you modify
27 file(s) with this exception, you may extend this exception to your
28 version of the file(s), but you are not obligated to do so. If you
29 do not wish to do so, delete this exception statement from your
30 version. If you delete this exception statement from all source
31 files in the program, then also delete it here.
38 #include "reel_mono_picture_asset.h"
41 #include "openjpeg_image.h"
42 #include "mono_picture_asset.h"
43 #include "mono_picture_asset_writer.h"
44 #include "interop_subtitle_asset.h"
45 #include "smpte_subtitle_asset.h"
46 #include "reel_subtitle_asset.h"
47 #include "compose.hpp"
49 #include <boost/test/unit_test.hpp>
50 #include <boost/foreach.hpp>
51 #include <boost/algorithm/string.hpp>
60 using boost::optional;
61 using boost::shared_ptr;
64 static list<pair<string, optional<boost::filesystem::path> > > stages;
67 stage (string s, optional<boost::filesystem::path> p)
69 stages.push_back (make_pair (s, p));
78 static vector<boost::filesystem::path>
79 setup (int reference_number, int verify_test_number)
81 boost::filesystem::remove_all (dcp::String::compose("build/test/verify_test%1", verify_test_number));
82 boost::filesystem::create_directory (dcp::String::compose("build/test/verify_test%1", verify_test_number));
83 for (boost::filesystem::directory_iterator i(dcp::String::compose("test/ref/DCP/dcp_test%1", reference_number)); i != boost::filesystem::directory_iterator(); ++i) {
84 boost::filesystem::copy_file (i->path(), dcp::String::compose("build/test/verify_test%1", verify_test_number) / i->path().filename());
87 vector<boost::filesystem::path> directories;
88 directories.push_back (dcp::String::compose("build/test/verify_test%1", verify_test_number));
94 /** Class that can alter a file by searching and replacing strings within it.
95 * On destruction modifies the file whose name was given to the constructor.
100 Editor (boost::filesystem::path path)
103 _content = dcp::file_to_string (_path);
108 FILE* f = fopen(_path.string().c_str(), "w");
110 fwrite (_content.c_str(), _content.length(), 1, f);
114 void replace (string a, string b)
116 boost::algorithm::replace_all (_content, a, b);
120 boost::filesystem::path _path;
121 std::string _content;
126 dump_notes (list<dcp::VerificationNote> const & notes)
128 BOOST_FOREACH (dcp::VerificationNote i, notes) {
129 std::cout << dcp::note_to_string(i) << "\n";
133 /* Check DCP as-is (should be OK) */
134 BOOST_AUTO_TEST_CASE (verify_test1)
137 vector<boost::filesystem::path> directories = setup (1, 1);
138 list<dcp::VerificationNote> notes = dcp::verify (directories, &stage, &progress, xsd_test);
140 boost::filesystem::path const cpl_file = "build/test/verify_test1/cpl_81fb54df-e1bf-4647-8788-ea7ba154375b.xml";
141 boost::filesystem::path const pkl_file = "build/test/verify_test1/pkl_18be072e-5a0f-44e1-b2eb-c8a52ae12789.xml";
142 boost::filesystem::path const assetmap_file = "build/test/verify_test1/ASSETMAP.xml";
144 list<pair<string, optional<boost::filesystem::path> > >::const_iterator st = stages.begin();
145 BOOST_CHECK_EQUAL (st->first, "Checking DCP");
146 BOOST_REQUIRE (st->second);
147 BOOST_CHECK_EQUAL (st->second.get(), boost::filesystem::canonical("build/test/verify_test1"));
149 BOOST_CHECK_EQUAL (st->first, "Checking CPL");
150 BOOST_REQUIRE (st->second);
151 BOOST_CHECK_EQUAL (st->second.get(), boost::filesystem::canonical(cpl_file));
153 BOOST_CHECK_EQUAL (st->first, "Checking reel");
154 BOOST_REQUIRE (!st->second);
156 BOOST_CHECK_EQUAL (st->first, "Checking picture asset hash");
157 BOOST_REQUIRE (st->second);
158 BOOST_CHECK_EQUAL (st->second.get(), boost::filesystem::canonical("build/test/verify_test1/video.mxf"));
160 BOOST_CHECK_EQUAL (st->first, "Checking picture frame sizes");
161 BOOST_REQUIRE (st->second);
162 BOOST_CHECK_EQUAL (st->second.get(), boost::filesystem::canonical("build/test/verify_test1/video.mxf"));
164 BOOST_CHECK_EQUAL (st->first, "Checking sound asset hash");
165 BOOST_REQUIRE (st->second);
166 BOOST_CHECK_EQUAL (st->second.get(), boost::filesystem::canonical("build/test/verify_test1/audio.mxf"));
168 BOOST_CHECK_EQUAL (st->first, "Checking PKL");
169 BOOST_REQUIRE (st->second);
170 BOOST_CHECK_EQUAL (st->second.get(), boost::filesystem::canonical(pkl_file));
172 BOOST_CHECK_EQUAL (st->first, "Checking ASSETMAP");
173 BOOST_REQUIRE (st->second);
174 BOOST_CHECK_EQUAL (st->second.get(), boost::filesystem::canonical(assetmap_file));
176 BOOST_REQUIRE (st == stages.end());
180 BOOST_CHECK_EQUAL (notes.size(), 0);
183 /* Corrupt the MXFs and check that this is spotted */
184 BOOST_AUTO_TEST_CASE (verify_test2)
186 vector<boost::filesystem::path> directories = setup (1, 2);
188 FILE* mod = fopen("build/test/verify_test2/video.mxf", "r+b");
190 fseek (mod, 4096, SEEK_SET);
192 fwrite (&x, sizeof(x), 1, mod);
195 mod = fopen("build/test/verify_test2/audio.mxf", "r+b");
197 fseek (mod, 4096, SEEK_SET);
198 BOOST_REQUIRE (fwrite (&x, sizeof(x), 1, mod) == 1);
201 list<dcp::VerificationNote> notes = dcp::verify (directories, &stage, &progress, xsd_test);
203 BOOST_REQUIRE_EQUAL (notes.size(), 2);
204 BOOST_CHECK_EQUAL (notes.front().type(), dcp::VerificationNote::VERIFY_ERROR);
205 BOOST_CHECK_EQUAL (notes.front().code(), dcp::VerificationNote::PICTURE_HASH_INCORRECT);
206 BOOST_CHECK_EQUAL (notes.back().type(), dcp::VerificationNote::VERIFY_ERROR);
207 BOOST_CHECK_EQUAL (notes.back().code(), dcp::VerificationNote::SOUND_HASH_INCORRECT);
210 /* Corrupt the hashes in the PKL and check that the disagreement between CPL and PKL is spotted */
211 BOOST_AUTO_TEST_CASE (verify_test3)
213 vector<boost::filesystem::path> directories = setup (1, 3);
216 Editor e ("build/test/verify_test3/pkl_18be072e-5a0f-44e1-b2eb-c8a52ae12789.xml");
217 e.replace ("<Hash>", "<Hash>x");
220 list<dcp::VerificationNote> notes = dcp::verify (directories, &stage, &progress, xsd_test);
224 BOOST_REQUIRE_EQUAL (notes.size(), 6);
225 list<dcp::VerificationNote>::const_iterator i = notes.begin();
226 BOOST_CHECK_EQUAL (i->type(), dcp::VerificationNote::VERIFY_ERROR);
227 BOOST_CHECK_EQUAL (i->code(), dcp::VerificationNote::CPL_HASH_INCORRECT);
229 BOOST_CHECK_EQUAL (i->type(), dcp::VerificationNote::VERIFY_ERROR);
230 BOOST_CHECK_EQUAL (i->code(), dcp::VerificationNote::PKL_CPL_PICTURE_HASHES_DISAGREE);
232 BOOST_CHECK_EQUAL (i->type(), dcp::VerificationNote::VERIFY_ERROR);
233 BOOST_CHECK_EQUAL (i->code(), dcp::VerificationNote::PKL_CPL_SOUND_HASHES_DISAGREE);
235 BOOST_CHECK_EQUAL (i->type(), dcp::VerificationNote::VERIFY_ERROR);
236 BOOST_CHECK_EQUAL (i->code(), dcp::VerificationNote::XML_VALIDATION_ERROR);
238 BOOST_CHECK_EQUAL (i->type(), dcp::VerificationNote::VERIFY_ERROR);
239 BOOST_CHECK_EQUAL (i->code(), dcp::VerificationNote::XML_VALIDATION_ERROR);
241 BOOST_CHECK_EQUAL (i->type(), dcp::VerificationNote::VERIFY_ERROR);
242 BOOST_CHECK_EQUAL (i->code(), dcp::VerificationNote::XML_VALIDATION_ERROR);
246 /* Corrupt the ContentKind in the CPL */
247 BOOST_AUTO_TEST_CASE (verify_test4)
249 vector<boost::filesystem::path> directories = setup (1, 4);
252 Editor e ("build/test/verify_test4/cpl_81fb54df-e1bf-4647-8788-ea7ba154375b.xml");
253 e.replace ("<ContentKind>", "<ContentKind>x");
256 list<dcp::VerificationNote> notes = dcp::verify (directories, &stage, &progress, xsd_test);
258 BOOST_REQUIRE_EQUAL (notes.size(), 1);
259 BOOST_CHECK_EQUAL (notes.front().code(), dcp::VerificationNote::GENERAL_READ);
260 BOOST_CHECK_EQUAL (*notes.front().note(), "Bad content kind 'xfeature'");
264 boost::filesystem::path
267 return dcp::String::compose("build/test/verify_test%1/cpl_81fb54df-e1bf-4647-8788-ea7ba154375b.xml", n);
271 boost::filesystem::path
274 return dcp::String::compose("build/test/verify_test%1/pkl_18be072e-5a0f-44e1-b2eb-c8a52ae12789.xml", n);
278 boost::filesystem::path
281 return dcp::String::compose("build/test/verify_test%1/ASSETMAP.xml", n);
285 void check_after_replace (int n, boost::function<boost::filesystem::path (int)> file, string from, string to, dcp::VerificationNote::Code code1)
287 vector<boost::filesystem::path> directories = setup (1, n);
291 e.replace (from, to);
294 list<dcp::VerificationNote> notes = dcp::verify (directories, &stage, &progress, xsd_test);
298 BOOST_REQUIRE_EQUAL (notes.size(), 1);
299 BOOST_CHECK_EQUAL (notes.front().code(), code1);
303 void check_after_replace (int n, boost::function<boost::filesystem::path (int)> file, string from, string to, dcp::VerificationNote::Code code1, dcp::VerificationNote::Code code2)
305 vector<boost::filesystem::path> directories = setup (1, n);
309 e.replace (from, to);
312 list<dcp::VerificationNote> notes = dcp::verify (directories, &stage, &progress, xsd_test);
316 BOOST_REQUIRE_EQUAL (notes.size(), 2);
317 BOOST_CHECK_EQUAL (notes.front().code(), code1);
318 BOOST_CHECK_EQUAL (notes.back().code(), code2);
322 void check_after_replace (
323 int n, boost::function<boost::filesystem::path (int)> file,
326 dcp::VerificationNote::Code code1,
327 dcp::VerificationNote::Code code2,
328 dcp::VerificationNote::Code code3
331 vector<boost::filesystem::path> directories = setup (1, n);
335 e.replace (from, to);
338 list<dcp::VerificationNote> notes = dcp::verify (directories, &stage, &progress, xsd_test);
342 BOOST_REQUIRE_EQUAL (notes.size(), 3);
343 list<dcp::VerificationNote>::const_iterator i = notes.begin ();
344 BOOST_CHECK_EQUAL (i->code(), code1);
346 BOOST_CHECK_EQUAL (i->code(), code2);
348 BOOST_CHECK_EQUAL (i->code(), code3);
352 BOOST_AUTO_TEST_CASE (verify_test5)
354 check_after_replace (
356 "<FrameRate>24 1", "<FrameRate>99 1",
357 dcp::VerificationNote::CPL_HASH_INCORRECT,
358 dcp::VerificationNote::INVALID_PICTURE_FRAME_RATE
363 BOOST_AUTO_TEST_CASE (verify_test6)
365 vector<boost::filesystem::path> directories = setup (1, 6);
367 boost::filesystem::remove ("build/test/verify_test6/video.mxf");
368 list<dcp::VerificationNote> notes = dcp::verify (directories, &stage, &progress, xsd_test);
370 BOOST_REQUIRE_EQUAL (notes.size(), 1);
371 BOOST_CHECK_EQUAL (notes.front().type(), dcp::VerificationNote::VERIFY_ERROR);
372 BOOST_CHECK_EQUAL (notes.front().code(), dcp::VerificationNote::MISSING_ASSET);
376 boost::filesystem::path
379 return dcp::String::compose("build/test/verify_test%1/ASSETMAP.xml", n);
382 /* Empty asset filename in ASSETMAP */
383 BOOST_AUTO_TEST_CASE (verify_test7)
385 check_after_replace (
387 "<Path>video.mxf</Path>", "<Path></Path>",
388 dcp::VerificationNote::EMPTY_ASSET_PATH
392 /* Mismatched standard */
393 BOOST_AUTO_TEST_CASE (verify_test8)
395 check_after_replace (
397 "http://www.smpte-ra.org/schemas/429-7/2006/CPL", "http://www.digicine.com/PROTO-ASDCP-CPL-20040511#",
398 dcp::VerificationNote::MISMATCHED_STANDARD,
399 dcp::VerificationNote::XML_VALIDATION_ERROR,
400 dcp::VerificationNote::CPL_HASH_INCORRECT
404 /* Badly formatted <Id> in CPL */
405 BOOST_AUTO_TEST_CASE (verify_test9)
407 /* There's no CPL_HASH_INCORRECT error here because it can't find the correct hash by ID (since the ID is wrong) */
408 check_after_replace (
410 "<Id>urn:uuid:81fb54df-e1bf-4647-8788-ea7ba154375b", "<Id>urn:uuid:81fb54df-e1bf-4647-8788-ea7ba154375",
411 dcp::VerificationNote::XML_VALIDATION_ERROR
415 /* Badly formatted <IssueDate> in CPL */
416 BOOST_AUTO_TEST_CASE (verify_test10)
418 check_after_replace (
420 "<IssueDate>", "<IssueDate>x",
421 dcp::VerificationNote::XML_VALIDATION_ERROR,
422 dcp::VerificationNote::CPL_HASH_INCORRECT
426 /* Badly-formatted <Id> in PKL */
427 BOOST_AUTO_TEST_CASE (verify_test11)
429 check_after_replace (
431 "<Id>urn:uuid:18b", "<Id>urn:uuid:x8b",
432 dcp::VerificationNote::XML_VALIDATION_ERROR
436 /* Badly-formatted <Id> in ASSETMAP */
437 BOOST_AUTO_TEST_CASE (verify_test12)
439 check_after_replace (
441 "<Id>urn:uuid:ae8", "<Id>urn:uuid:xe8",
442 dcp::VerificationNote::XML_VALIDATION_ERROR
446 /* Basic test of an Interop DCP */
447 BOOST_AUTO_TEST_CASE (verify_test13)
450 vector<boost::filesystem::path> directories = setup (3, 13);
451 list<dcp::VerificationNote> notes = dcp::verify (directories, &stage, &progress, xsd_test);
453 boost::filesystem::path const cpl_file = "build/test/verify_test13/cpl_cbfd2bc0-21cf-4a8f-95d8-9cddcbe51296.xml";
454 boost::filesystem::path const pkl_file = "build/test/verify_test13/pkl_d87a950c-bd6f-41f6-90cc-56ccd673e131.xml";
455 boost::filesystem::path const assetmap_file = "build/test/verify_test13/ASSETMAP";
457 list<pair<string, optional<boost::filesystem::path> > >::const_iterator st = stages.begin();
458 BOOST_CHECK_EQUAL (st->first, "Checking DCP");
459 BOOST_REQUIRE (st->second);
460 BOOST_CHECK_EQUAL (st->second.get(), boost::filesystem::canonical("build/test/verify_test13"));
462 BOOST_CHECK_EQUAL (st->first, "Checking CPL");
463 BOOST_REQUIRE (st->second);
464 BOOST_CHECK_EQUAL (st->second.get(), boost::filesystem::canonical(cpl_file));
466 BOOST_CHECK_EQUAL (st->first, "Checking reel");
467 BOOST_REQUIRE (!st->second);
469 BOOST_CHECK_EQUAL (st->first, "Checking picture asset hash");
470 BOOST_REQUIRE (st->second);
471 BOOST_CHECK_EQUAL (st->second.get(), boost::filesystem::canonical("build/test/verify_test13/j2c_c6035f97-b07d-4e1c-944d-603fc2ddc242.mxf"));
473 BOOST_CHECK_EQUAL (st->first, "Checking picture frame sizes");
474 BOOST_REQUIRE (st->second);
475 BOOST_CHECK_EQUAL (st->second.get(), boost::filesystem::canonical("build/test/verify_test13/j2c_c6035f97-b07d-4e1c-944d-603fc2ddc242.mxf"));
477 BOOST_CHECK_EQUAL (st->first, "Checking sound asset hash");
478 BOOST_REQUIRE (st->second);
479 BOOST_CHECK_EQUAL (st->second.get(), boost::filesystem::canonical("build/test/verify_test13/pcm_69cf9eaf-9a99-4776-b022-6902208626c3.mxf"));
481 BOOST_CHECK_EQUAL (st->first, "Checking PKL");
482 BOOST_REQUIRE (st->second);
483 BOOST_CHECK_EQUAL (st->second.get(), boost::filesystem::canonical(pkl_file));
485 BOOST_CHECK_EQUAL (st->first, "Checking ASSETMAP");
486 BOOST_REQUIRE (st->second);
487 BOOST_CHECK_EQUAL (st->second.get(), boost::filesystem::canonical(assetmap_file));
489 BOOST_REQUIRE (st == stages.end());
493 BOOST_CHECK_EQUAL (notes.size(), 0);
496 /* DCP with a short asset */
497 BOOST_AUTO_TEST_CASE (verify_test14)
499 vector<boost::filesystem::path> directories = setup (8, 14);
500 list<dcp::VerificationNote> notes = dcp::verify (directories, &stage, &progress, xsd_test);
504 BOOST_REQUIRE_EQUAL (notes.size(), 4);
505 list<dcp::VerificationNote>::const_iterator i = notes.begin ();
506 BOOST_CHECK_EQUAL (i->code(), dcp::VerificationNote::DURATION_TOO_SMALL);
508 BOOST_CHECK_EQUAL (i->code(), dcp::VerificationNote::INTRINSIC_DURATION_TOO_SMALL);
510 BOOST_CHECK_EQUAL (i->code(), dcp::VerificationNote::DURATION_TOO_SMALL);
512 BOOST_CHECK_EQUAL (i->code(), dcp::VerificationNote::INTRINSIC_DURATION_TOO_SMALL);
519 dcp_from_frame (dcp::Data const& frame, boost::filesystem::path dir)
521 shared_ptr<dcp::MonoPictureAsset> asset(new dcp::MonoPictureAsset(dcp::Fraction(24, 1), dcp::SMPTE));
522 boost::filesystem::create_directories (dir);
523 shared_ptr<dcp::PictureAssetWriter> writer = asset->start_write (dir / "pic.mxf", true);
524 for (int i = 0; i < 24; ++i) {
525 writer->write (frame.data().get(), frame.size());
529 shared_ptr<dcp::ReelAsset> reel_asset(new dcp::ReelMonoPictureAsset(asset, 0));
530 shared_ptr<dcp::Reel> reel(new dcp::Reel());
531 reel->add (reel_asset);
532 shared_ptr<dcp::CPL> cpl(new dcp::CPL("hello", dcp::FEATURE));
534 shared_ptr<dcp::DCP> dcp(new dcp::DCP(dir));
536 dcp->write_xml (dcp::SMPTE);
540 /* DCP with an over-sized JPEG2000 frame */
541 BOOST_AUTO_TEST_CASE (verify_test15)
543 int const too_big = 1302083 * 2;
545 /* Compress a black image */
546 shared_ptr<dcp::OpenJPEGImage> image = black_image ();
547 dcp::Data frame = dcp::compress_j2k (image, 100000000, 24, false, false);
548 BOOST_REQUIRE (frame.size() < too_big);
550 /* Place it in a bigger block with some zero padding at the end */
551 dcp::Data oversized_frame(too_big);
552 memcpy (oversized_frame.data().get(), frame.data().get(), frame.size());
553 memset (oversized_frame.data().get() + frame.size(), 0, too_big - frame.size());
555 boost::filesystem::path const dir("build/test/verify_test15");
556 boost::filesystem::remove_all (dir);
557 dcp_from_frame (oversized_frame, dir);
559 vector<boost::filesystem::path> dirs;
560 dirs.push_back (dir);
561 list<dcp::VerificationNote> notes = dcp::verify (dirs, &stage, &progress, xsd_test);
562 BOOST_REQUIRE_EQUAL (notes.size(), 1);
563 BOOST_CHECK_EQUAL (notes.front().code(), dcp::VerificationNote::PICTURE_FRAME_TOO_LARGE);
567 /* DCP with a nearly over-sized JPEG2000 frame */
568 BOOST_AUTO_TEST_CASE (verify_test16)
570 int const nearly_too_big = 1302083 * 0.98;
572 /* Compress a black image */
573 shared_ptr<dcp::OpenJPEGImage> image = black_image ();
574 dcp::Data frame = dcp::compress_j2k (image, 100000000, 24, false, false);
575 BOOST_REQUIRE (frame.size() < nearly_too_big);
577 /* Place it in a bigger block with some zero padding at the end */
578 dcp::Data oversized_frame(nearly_too_big);
579 memcpy (oversized_frame.data().get(), frame.data().get(), frame.size());
580 memset (oversized_frame.data().get() + frame.size(), 0, nearly_too_big - frame.size());
582 boost::filesystem::path const dir("build/test/verify_test16");
583 boost::filesystem::remove_all (dir);
584 dcp_from_frame (oversized_frame, dir);
586 vector<boost::filesystem::path> dirs;
587 dirs.push_back (dir);
588 list<dcp::VerificationNote> notes = dcp::verify (dirs, &stage, &progress, xsd_test);
589 BOOST_REQUIRE_EQUAL (notes.size(), 1);
590 BOOST_CHECK_EQUAL (notes.front().code(), dcp::VerificationNote::PICTURE_FRAME_NEARLY_TOO_LARGE);
594 /* DCP with a within-range JPEG2000 frame */
595 BOOST_AUTO_TEST_CASE (verify_test17)
597 /* Compress a black image */
598 shared_ptr<dcp::OpenJPEGImage> image = black_image ();
599 dcp::Data frame = dcp::compress_j2k (image, 100000000, 24, false, false);
600 BOOST_REQUIRE (frame.size() < 230000000 / (24 * 8));
602 boost::filesystem::path const dir("build/test/verify_test17");
603 boost::filesystem::remove_all (dir);
604 dcp_from_frame (frame, dir);
606 vector<boost::filesystem::path> dirs;
607 dirs.push_back (dir);
608 list<dcp::VerificationNote> notes = dcp::verify (dirs, &stage, &progress, xsd_test);
609 BOOST_REQUIRE_EQUAL (notes.size(), 0);
613 /* DCP with valid Interop subtitles */
614 BOOST_AUTO_TEST_CASE (verify_test18)
616 boost::filesystem::path const dir("build/test/verify_test18");
617 boost::filesystem::remove_all (dir);
618 boost::filesystem::create_directories (dir);
619 boost::filesystem::copy_file ("test/data/subs1.xml", dir / "subs.xml");
620 shared_ptr<dcp::InteropSubtitleAsset> asset(new dcp::InteropSubtitleAsset(dir / "subs.xml"));
621 shared_ptr<dcp::ReelAsset> reel_asset(new dcp::ReelSubtitleAsset(asset, dcp::Fraction(24, 1), 16 * 24, 0));
622 shared_ptr<dcp::Reel> reel(new dcp::Reel());
623 reel->add (reel_asset);
624 shared_ptr<dcp::CPL> cpl(new dcp::CPL("hello", dcp::FEATURE));
626 shared_ptr<dcp::DCP> dcp(new dcp::DCP(dir));
628 dcp->write_xml (dcp::INTEROP);
630 vector<boost::filesystem::path> dirs;
631 dirs.push_back (dir);
632 list<dcp::VerificationNote> notes = dcp::verify (dirs, &stage, &progress, xsd_test);
633 BOOST_REQUIRE_EQUAL (notes.size(), 0);
637 /* DCP with broken Interop subtitles */
638 BOOST_AUTO_TEST_CASE (verify_test19)
640 boost::filesystem::path const dir("build/test/verify_test19");
641 boost::filesystem::remove_all (dir);
642 boost::filesystem::create_directories (dir);
643 boost::filesystem::copy_file ("test/data/subs1.xml", dir / "subs.xml");
644 shared_ptr<dcp::InteropSubtitleAsset> asset(new dcp::InteropSubtitleAsset(dir / "subs.xml"));
645 shared_ptr<dcp::ReelAsset> reel_asset(new dcp::ReelSubtitleAsset(asset, dcp::Fraction(24, 1), 16 * 24, 0));
646 shared_ptr<dcp::Reel> reel(new dcp::Reel());
647 reel->add (reel_asset);
648 shared_ptr<dcp::CPL> cpl(new dcp::CPL("hello", dcp::FEATURE));
650 shared_ptr<dcp::DCP> dcp(new dcp::DCP(dir));
652 dcp->write_xml (dcp::INTEROP);
655 Editor e (dir / "subs.xml");
656 e.replace ("</ReelNumber>", "</ReelNumber><Foo></Foo>");
659 vector<boost::filesystem::path> dirs;
660 dirs.push_back (dir);
661 list<dcp::VerificationNote> notes = dcp::verify (dirs, &stage, &progress, xsd_test);
663 BOOST_REQUIRE_EQUAL (notes.size(), 2);
664 BOOST_CHECK_EQUAL (notes.front().code(), dcp::VerificationNote::XML_VALIDATION_ERROR);
665 BOOST_CHECK_EQUAL (notes.back().code(), dcp::VerificationNote::XML_VALIDATION_ERROR);
669 /* DCP with valid SMPTE subtitles */
670 BOOST_AUTO_TEST_CASE (verify_test20)
672 boost::filesystem::path const dir("build/test/verify_test20");
673 boost::filesystem::remove_all (dir);
674 boost::filesystem::create_directories (dir);
675 boost::filesystem::copy_file ("test/data/subs.mxf", dir / "subs.mxf");
676 shared_ptr<dcp::SMPTESubtitleAsset> asset(new dcp::SMPTESubtitleAsset(dir / "subs.mxf"));
677 shared_ptr<dcp::ReelAsset> reel_asset(new dcp::ReelSubtitleAsset(asset, dcp::Fraction(24, 1), 16 * 24, 0));
678 shared_ptr<dcp::Reel> reel(new dcp::Reel());
679 reel->add (reel_asset);
680 shared_ptr<dcp::CPL> cpl(new dcp::CPL("hello", dcp::FEATURE));
682 shared_ptr<dcp::DCP> dcp(new dcp::DCP(dir));
684 dcp->write_xml (dcp::SMPTE);
686 vector<boost::filesystem::path> dirs;
687 dirs.push_back (dir);
688 list<dcp::VerificationNote> notes = dcp::verify (dirs, &stage, &progress, xsd_test);
690 BOOST_REQUIRE_EQUAL (notes.size(), 0);
694 /* DCP with broken SMPTE subtitles */
695 BOOST_AUTO_TEST_CASE (verify_test21)
697 boost::filesystem::path const dir("build/test/verify_test21");
698 boost::filesystem::remove_all (dir);
699 boost::filesystem::create_directories (dir);
700 boost::filesystem::copy_file ("test/data/broken_smpte.mxf", dir / "subs.mxf");
701 shared_ptr<dcp::SMPTESubtitleAsset> asset(new dcp::SMPTESubtitleAsset(dir / "subs.mxf"));
702 shared_ptr<dcp::ReelAsset> reel_asset(new dcp::ReelSubtitleAsset(asset, dcp::Fraction(24, 1), 16 * 24, 0));
703 shared_ptr<dcp::Reel> reel(new dcp::Reel());
704 reel->add (reel_asset);
705 shared_ptr<dcp::CPL> cpl(new dcp::CPL("hello", dcp::FEATURE));
707 shared_ptr<dcp::DCP> dcp(new dcp::DCP(dir));
709 dcp->write_xml (dcp::SMPTE);
711 vector<boost::filesystem::path> dirs;
712 dirs.push_back (dir);
713 list<dcp::VerificationNote> notes = dcp::verify (dirs, &stage, &progress, xsd_test);
715 BOOST_REQUIRE_EQUAL (notes.size(), 2);
716 BOOST_CHECK_EQUAL (notes.front().code(), dcp::VerificationNote::XML_VALIDATION_ERROR);
717 BOOST_CHECK_EQUAL (notes.back().code(), dcp::VerificationNote::XML_VALIDATION_ERROR);
722 BOOST_AUTO_TEST_CASE (verify_test22)
724 boost::filesystem::path const ov_dir("build/test/verify_test22_ov");
725 boost::filesystem::remove_all (ov_dir);
726 boost::filesystem::create_directories (ov_dir);
728 shared_ptr<dcp::OpenJPEGImage> image = black_image ();
729 dcp::Data frame = dcp::compress_j2k (image, 100000000, 24, false, false);
730 BOOST_REQUIRE (frame.size() < 230000000 / (24 * 8));
731 dcp_from_frame (frame, ov_dir);
733 dcp::DCP ov (ov_dir);
736 boost::filesystem::path const vf_dir("build/test/verify_test22_vf");
737 boost::filesystem::remove_all (vf_dir);
738 boost::filesystem::create_directories (vf_dir);
740 shared_ptr<dcp::Reel> reel(new dcp::Reel());
741 reel->add (ov.cpls().front()->reels().front()->main_picture());
742 shared_ptr<dcp::CPL> cpl(new dcp::CPL("hello", dcp::FEATURE));
744 dcp::DCP vf (vf_dir);
746 vf.write_xml (dcp::SMPTE);
748 vector<boost::filesystem::path> dirs;
749 dirs.push_back (vf_dir);
750 list<dcp::VerificationNote> notes = dcp::verify (dirs, &stage, &progress, xsd_test);
752 BOOST_REQUIRE_EQUAL (notes.size(), 1);
753 BOOST_CHECK_EQUAL (notes.front().code(), dcp::VerificationNote::EXTERNAL_ASSET);