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 std::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;
128 dump_notes (list<dcp::VerificationNote> const & notes)
130 BOOST_FOREACH (dcp::VerificationNote i, notes) {
131 std::cout << dcp::note_to_string(i) << "\n";
136 /* Check DCP as-is (should be OK) */
137 BOOST_AUTO_TEST_CASE (verify_test1)
140 vector<boost::filesystem::path> directories = setup (1, 1);
141 list<dcp::VerificationNote> notes = dcp::verify (directories, &stage, &progress, xsd_test);
143 boost::filesystem::path const cpl_file = "build/test/verify_test1/cpl_81fb54df-e1bf-4647-8788-ea7ba154375b.xml";
144 boost::filesystem::path const pkl_file = "build/test/verify_test1/pkl_cd49971e-bf4c-4594-8474-54ebef09a40c.xml";
145 boost::filesystem::path const assetmap_file = "build/test/verify_test1/ASSETMAP.xml";
147 list<pair<string, optional<boost::filesystem::path> > >::const_iterator st = stages.begin();
148 BOOST_CHECK_EQUAL (st->first, "Checking DCP");
149 BOOST_REQUIRE (st->second);
150 BOOST_CHECK_EQUAL (st->second.get(), boost::filesystem::canonical("build/test/verify_test1"));
152 BOOST_CHECK_EQUAL (st->first, "Checking CPL");
153 BOOST_REQUIRE (st->second);
154 BOOST_CHECK_EQUAL (st->second.get(), boost::filesystem::canonical(cpl_file));
156 BOOST_CHECK_EQUAL (st->first, "Checking reel");
157 BOOST_REQUIRE (!st->second);
159 BOOST_CHECK_EQUAL (st->first, "Checking picture asset hash");
160 BOOST_REQUIRE (st->second);
161 BOOST_CHECK_EQUAL (st->second.get(), boost::filesystem::canonical("build/test/verify_test1/video.mxf"));
163 BOOST_CHECK_EQUAL (st->first, "Checking picture frame sizes");
164 BOOST_REQUIRE (st->second);
165 BOOST_CHECK_EQUAL (st->second.get(), boost::filesystem::canonical("build/test/verify_test1/video.mxf"));
167 BOOST_CHECK_EQUAL (st->first, "Checking sound asset hash");
168 BOOST_REQUIRE (st->second);
169 BOOST_CHECK_EQUAL (st->second.get(), boost::filesystem::canonical("build/test/verify_test1/audio.mxf"));
171 BOOST_CHECK_EQUAL (st->first, "Checking PKL");
172 BOOST_REQUIRE (st->second);
173 BOOST_CHECK_EQUAL (st->second.get(), boost::filesystem::canonical(pkl_file));
175 BOOST_CHECK_EQUAL (st->first, "Checking ASSETMAP");
176 BOOST_REQUIRE (st->second);
177 BOOST_CHECK_EQUAL (st->second.get(), boost::filesystem::canonical(assetmap_file));
179 BOOST_REQUIRE (st == stages.end());
181 BOOST_CHECK_EQUAL (notes.size(), 0);
184 /* Corrupt the MXFs and check that this is spotted */
185 BOOST_AUTO_TEST_CASE (verify_test2)
187 vector<boost::filesystem::path> directories = setup (1, 2);
189 FILE* mod = fopen("build/test/verify_test2/video.mxf", "r+b");
191 fseek (mod, 4096, SEEK_SET);
193 fwrite (&x, sizeof(x), 1, mod);
196 mod = fopen("build/test/verify_test2/audio.mxf", "r+b");
198 BOOST_REQUIRE_EQUAL (fseek(mod, -64, SEEK_END), 0);
199 BOOST_REQUIRE (fwrite (&x, sizeof(x), 1, mod) == 1);
202 list<dcp::VerificationNote> notes;
204 dcp::ASDCPErrorSuspender sus;
205 notes = dcp::verify (directories, &stage, &progress, xsd_test);
208 BOOST_REQUIRE_EQUAL (notes.size(), 2);
209 BOOST_CHECK_EQUAL (notes.front().type(), dcp::VerificationNote::VERIFY_ERROR);
210 BOOST_CHECK_EQUAL (notes.front().code(), dcp::VerificationNote::PICTURE_HASH_INCORRECT);
211 BOOST_CHECK_EQUAL (notes.back().type(), dcp::VerificationNote::VERIFY_ERROR);
212 BOOST_CHECK_EQUAL (notes.back().code(), dcp::VerificationNote::SOUND_HASH_INCORRECT);
215 /* Corrupt the hashes in the PKL and check that the disagreement between CPL and PKL is spotted */
216 BOOST_AUTO_TEST_CASE (verify_test3)
218 vector<boost::filesystem::path> directories = setup (1, 3);
221 Editor e ("build/test/verify_test3/pkl_cd49971e-bf4c-4594-8474-54ebef09a40c.xml");
222 e.replace ("<Hash>", "<Hash>x");
225 list<dcp::VerificationNote> notes = dcp::verify (directories, &stage, &progress, xsd_test);
227 BOOST_REQUIRE_EQUAL (notes.size(), 6);
228 list<dcp::VerificationNote>::const_iterator i = notes.begin();
229 BOOST_CHECK_EQUAL (i->type(), dcp::VerificationNote::VERIFY_ERROR);
230 BOOST_CHECK_EQUAL (i->code(), dcp::VerificationNote::CPL_HASH_INCORRECT);
232 BOOST_CHECK_EQUAL (i->type(), dcp::VerificationNote::VERIFY_ERROR);
233 BOOST_CHECK_EQUAL (i->code(), dcp::VerificationNote::PKL_CPL_PICTURE_HASHES_DISAGREE);
235 BOOST_CHECK_EQUAL (i->type(), dcp::VerificationNote::VERIFY_ERROR);
236 BOOST_CHECK_EQUAL (i->code(), dcp::VerificationNote::PKL_CPL_SOUND_HASHES_DISAGREE);
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);
244 BOOST_CHECK_EQUAL (i->type(), dcp::VerificationNote::VERIFY_ERROR);
245 BOOST_CHECK_EQUAL (i->code(), dcp::VerificationNote::XML_VALIDATION_ERROR);
249 /* Corrupt the ContentKind in the CPL */
250 BOOST_AUTO_TEST_CASE (verify_test4)
252 vector<boost::filesystem::path> directories = setup (1, 4);
255 Editor e ("build/test/verify_test4/cpl_81fb54df-e1bf-4647-8788-ea7ba154375b.xml");
256 e.replace ("<ContentKind>", "<ContentKind>x");
259 list<dcp::VerificationNote> notes = dcp::verify (directories, &stage, &progress, xsd_test);
261 BOOST_REQUIRE_EQUAL (notes.size(), 1);
262 BOOST_CHECK_EQUAL (notes.front().code(), dcp::VerificationNote::GENERAL_READ);
263 BOOST_CHECK_EQUAL (*notes.front().note(), "Bad content kind 'xfeature'");
267 boost::filesystem::path
270 return dcp::String::compose("build/test/verify_test%1/cpl_81fb54df-e1bf-4647-8788-ea7ba154375b.xml", n);
274 boost::filesystem::path
277 return dcp::String::compose("build/test/verify_test%1/pkl_cd49971e-bf4c-4594-8474-54ebef09a40c.xml", n);
281 boost::filesystem::path
284 return dcp::String::compose("build/test/verify_test%1/ASSETMAP.xml", n);
288 void check_after_replace (int n, boost::function<boost::filesystem::path (int)> file, string from, string to, dcp::VerificationNote::Code code1)
290 vector<boost::filesystem::path> directories = setup (1, n);
294 e.replace (from, to);
297 list<dcp::VerificationNote> notes = dcp::verify (directories, &stage, &progress, xsd_test);
299 BOOST_REQUIRE_EQUAL (notes.size(), 1);
300 BOOST_CHECK_EQUAL (notes.front().code(), code1);
304 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)
306 vector<boost::filesystem::path> directories = setup (1, n);
310 e.replace (from, to);
313 list<dcp::VerificationNote> notes = dcp::verify (directories, &stage, &progress, xsd_test);
315 BOOST_REQUIRE_EQUAL (notes.size(), 2);
316 BOOST_CHECK_EQUAL (notes.front().code(), code1);
317 BOOST_CHECK_EQUAL (notes.back().code(), code2);
321 void check_after_replace (
322 int n, boost::function<boost::filesystem::path (int)> file,
325 dcp::VerificationNote::Code code1,
326 dcp::VerificationNote::Code code2,
327 dcp::VerificationNote::Code code3
330 vector<boost::filesystem::path> directories = setup (1, n);
334 e.replace (from, to);
337 list<dcp::VerificationNote> notes = dcp::verify (directories, &stage, &progress, xsd_test);
339 BOOST_REQUIRE_EQUAL (notes.size(), 3);
340 list<dcp::VerificationNote>::const_iterator i = notes.begin ();
341 BOOST_CHECK_EQUAL (i->code(), code1);
343 BOOST_CHECK_EQUAL (i->code(), code2);
345 BOOST_CHECK_EQUAL (i->code(), code3);
349 BOOST_AUTO_TEST_CASE (verify_test5)
351 check_after_replace (
353 "<FrameRate>24 1", "<FrameRate>99 1",
354 dcp::VerificationNote::CPL_HASH_INCORRECT,
355 dcp::VerificationNote::INVALID_PICTURE_FRAME_RATE
360 BOOST_AUTO_TEST_CASE (verify_test6)
362 vector<boost::filesystem::path> directories = setup (1, 6);
364 boost::filesystem::remove ("build/test/verify_test6/video.mxf");
365 list<dcp::VerificationNote> notes = dcp::verify (directories, &stage, &progress, xsd_test);
367 BOOST_REQUIRE_EQUAL (notes.size(), 1);
368 BOOST_CHECK_EQUAL (notes.front().type(), dcp::VerificationNote::VERIFY_ERROR);
369 BOOST_CHECK_EQUAL (notes.front().code(), dcp::VerificationNote::MISSING_ASSET);
373 boost::filesystem::path
376 return dcp::String::compose("build/test/verify_test%1/ASSETMAP.xml", n);
379 /* Empty asset filename in ASSETMAP */
380 BOOST_AUTO_TEST_CASE (verify_test7)
382 check_after_replace (
384 "<Path>video.mxf</Path>", "<Path></Path>",
385 dcp::VerificationNote::EMPTY_ASSET_PATH
389 /* Mismatched standard */
390 BOOST_AUTO_TEST_CASE (verify_test8)
392 check_after_replace (
394 "http://www.smpte-ra.org/schemas/429-7/2006/CPL", "http://www.digicine.com/PROTO-ASDCP-CPL-20040511#",
395 dcp::VerificationNote::MISMATCHED_STANDARD,
396 dcp::VerificationNote::XML_VALIDATION_ERROR,
397 dcp::VerificationNote::CPL_HASH_INCORRECT
401 /* Badly formatted <Id> in CPL */
402 BOOST_AUTO_TEST_CASE (verify_test9)
404 /* There's no CPL_HASH_INCORRECT error here because it can't find the correct hash by ID (since the ID is wrong) */
405 check_after_replace (
407 "<Id>urn:uuid:81fb54df-e1bf-4647-8788-ea7ba154375b", "<Id>urn:uuid:81fb54df-e1bf-4647-8788-ea7ba154375",
408 dcp::VerificationNote::XML_VALIDATION_ERROR
412 /* Badly formatted <IssueDate> in CPL */
413 BOOST_AUTO_TEST_CASE (verify_test10)
415 check_after_replace (
417 "<IssueDate>", "<IssueDate>x",
418 dcp::VerificationNote::XML_VALIDATION_ERROR,
419 dcp::VerificationNote::CPL_HASH_INCORRECT
423 /* Badly-formatted <Id> in PKL */
424 BOOST_AUTO_TEST_CASE (verify_test11)
426 check_after_replace (
428 "<Id>urn:uuid:cd4", "<Id>urn:uuid:xd4",
429 dcp::VerificationNote::XML_VALIDATION_ERROR
433 /* Badly-formatted <Id> in ASSETMAP */
434 BOOST_AUTO_TEST_CASE (verify_test12)
436 check_after_replace (
438 "<Id>urn:uuid:63c", "<Id>urn:uuid:x3c",
439 dcp::VerificationNote::XML_VALIDATION_ERROR
443 /* Basic test of an Interop DCP */
444 BOOST_AUTO_TEST_CASE (verify_test13)
447 vector<boost::filesystem::path> directories = setup (3, 13);
448 list<dcp::VerificationNote> notes = dcp::verify (directories, &stage, &progress, xsd_test);
450 boost::filesystem::path const cpl_file = "build/test/verify_test13/cpl_cbfd2bc0-21cf-4a8f-95d8-9cddcbe51296.xml";
451 boost::filesystem::path const pkl_file = "build/test/verify_test13/pkl_d87a950c-bd6f-41f6-90cc-56ccd673e131.xml";
452 boost::filesystem::path const assetmap_file = "build/test/verify_test13/ASSETMAP";
454 list<pair<string, optional<boost::filesystem::path> > >::const_iterator st = stages.begin();
455 BOOST_CHECK_EQUAL (st->first, "Checking DCP");
456 BOOST_REQUIRE (st->second);
457 BOOST_CHECK_EQUAL (st->second.get(), boost::filesystem::canonical("build/test/verify_test13"));
459 BOOST_CHECK_EQUAL (st->first, "Checking CPL");
460 BOOST_REQUIRE (st->second);
461 BOOST_CHECK_EQUAL (st->second.get(), boost::filesystem::canonical(cpl_file));
463 BOOST_CHECK_EQUAL (st->first, "Checking reel");
464 BOOST_REQUIRE (!st->second);
466 BOOST_CHECK_EQUAL (st->first, "Checking picture asset hash");
467 BOOST_REQUIRE (st->second);
468 BOOST_CHECK_EQUAL (st->second.get(), boost::filesystem::canonical("build/test/verify_test13/j2c_c6035f97-b07d-4e1c-944d-603fc2ddc242.mxf"));
470 BOOST_CHECK_EQUAL (st->first, "Checking picture frame sizes");
471 BOOST_REQUIRE (st->second);
472 BOOST_CHECK_EQUAL (st->second.get(), boost::filesystem::canonical("build/test/verify_test13/j2c_c6035f97-b07d-4e1c-944d-603fc2ddc242.mxf"));
474 BOOST_CHECK_EQUAL (st->first, "Checking sound asset hash");
475 BOOST_REQUIRE (st->second);
476 BOOST_CHECK_EQUAL (st->second.get(), boost::filesystem::canonical("build/test/verify_test13/pcm_69cf9eaf-9a99-4776-b022-6902208626c3.mxf"));
478 BOOST_CHECK_EQUAL (st->first, "Checking PKL");
479 BOOST_REQUIRE (st->second);
480 BOOST_CHECK_EQUAL (st->second.get(), boost::filesystem::canonical(pkl_file));
482 BOOST_CHECK_EQUAL (st->first, "Checking ASSETMAP");
483 BOOST_REQUIRE (st->second);
484 BOOST_CHECK_EQUAL (st->second.get(), boost::filesystem::canonical(assetmap_file));
486 BOOST_REQUIRE (st == stages.end());
488 BOOST_REQUIRE_EQUAL (notes.size(), 1U);
489 list<dcp::VerificationNote>::const_iterator i = notes.begin ();
490 BOOST_CHECK_EQUAL (i->type(), dcp::VerificationNote::VERIFY_BV21_ERROR);
491 BOOST_CHECK_EQUAL (i->code(), dcp::VerificationNote::NOT_SMPTE);
494 /* DCP with a short asset */
495 BOOST_AUTO_TEST_CASE (verify_test14)
497 vector<boost::filesystem::path> directories = setup (8, 14);
498 list<dcp::VerificationNote> notes = dcp::verify (directories, &stage, &progress, xsd_test);
500 BOOST_REQUIRE_EQUAL (notes.size(), 5);
501 list<dcp::VerificationNote>::const_iterator i = notes.begin ();
502 BOOST_CHECK_EQUAL (i->code(), dcp::VerificationNote::NOT_SMPTE);
504 BOOST_CHECK_EQUAL (i->code(), dcp::VerificationNote::DURATION_TOO_SMALL);
506 BOOST_CHECK_EQUAL (i->code(), dcp::VerificationNote::INTRINSIC_DURATION_TOO_SMALL);
508 BOOST_CHECK_EQUAL (i->code(), dcp::VerificationNote::DURATION_TOO_SMALL);
510 BOOST_CHECK_EQUAL (i->code(), dcp::VerificationNote::INTRINSIC_DURATION_TOO_SMALL);
517 dcp_from_frame (dcp::ArrayData const& frame, boost::filesystem::path dir)
519 shared_ptr<dcp::MonoPictureAsset> asset(new dcp::MonoPictureAsset(dcp::Fraction(24, 1), dcp::SMPTE));
520 boost::filesystem::create_directories (dir);
521 shared_ptr<dcp::PictureAssetWriter> writer = asset->start_write (dir / "pic.mxf", true);
522 for (int i = 0; i < 24; ++i) {
523 writer->write (frame.data(), frame.size());
527 shared_ptr<dcp::ReelAsset> reel_asset(new dcp::ReelMonoPictureAsset(asset, 0));
528 shared_ptr<dcp::Reel> reel(new dcp::Reel());
529 reel->add (reel_asset);
530 shared_ptr<dcp::CPL> cpl(new dcp::CPL("hello", dcp::FEATURE));
532 shared_ptr<dcp::DCP> dcp(new dcp::DCP(dir));
534 dcp->write_xml (dcp::SMPTE);
538 /* DCP with an over-sized JPEG2000 frame */
539 BOOST_AUTO_TEST_CASE (verify_test15)
541 int const too_big = 1302083 * 2;
543 /* Compress a black image */
544 shared_ptr<dcp::OpenJPEGImage> image = black_image ();
545 dcp::ArrayData frame = dcp::compress_j2k (image, 100000000, 24, false, false);
546 BOOST_REQUIRE (frame.size() < too_big);
548 /* Place it in a bigger block with some zero padding at the end */
549 dcp::ArrayData oversized_frame(too_big);
550 memcpy (oversized_frame.data(), frame.data(), frame.size());
551 memset (oversized_frame.data() + frame.size(), 0, too_big - frame.size());
553 boost::filesystem::path const dir("build/test/verify_test15");
554 boost::filesystem::remove_all (dir);
555 dcp_from_frame (oversized_frame, dir);
557 vector<boost::filesystem::path> dirs;
558 dirs.push_back (dir);
559 list<dcp::VerificationNote> notes = dcp::verify (dirs, &stage, &progress, xsd_test);
560 BOOST_REQUIRE_EQUAL (notes.size(), 1);
561 BOOST_CHECK_EQUAL (notes.front().code(), dcp::VerificationNote::PICTURE_FRAME_TOO_LARGE);
565 /* DCP with a nearly over-sized JPEG2000 frame */
566 BOOST_AUTO_TEST_CASE (verify_test16)
568 int const nearly_too_big = 1302083 * 0.98;
570 /* Compress a black image */
571 shared_ptr<dcp::OpenJPEGImage> image = black_image ();
572 dcp::ArrayData frame = dcp::compress_j2k (image, 100000000, 24, false, false);
573 BOOST_REQUIRE (frame.size() < nearly_too_big);
575 /* Place it in a bigger block with some zero padding at the end */
576 dcp::ArrayData oversized_frame(nearly_too_big);
577 memcpy (oversized_frame.data(), frame.data(), frame.size());
578 memset (oversized_frame.data() + frame.size(), 0, nearly_too_big - frame.size());
580 boost::filesystem::path const dir("build/test/verify_test16");
581 boost::filesystem::remove_all (dir);
582 dcp_from_frame (oversized_frame, dir);
584 vector<boost::filesystem::path> dirs;
585 dirs.push_back (dir);
586 list<dcp::VerificationNote> notes = dcp::verify (dirs, &stage, &progress, xsd_test);
587 BOOST_REQUIRE_EQUAL (notes.size(), 1);
588 BOOST_CHECK_EQUAL (notes.front().code(), dcp::VerificationNote::PICTURE_FRAME_NEARLY_TOO_LARGE);
592 /* DCP with a within-range JPEG2000 frame */
593 BOOST_AUTO_TEST_CASE (verify_test17)
595 /* Compress a black image */
596 shared_ptr<dcp::OpenJPEGImage> image = black_image ();
597 dcp::ArrayData frame = dcp::compress_j2k (image, 100000000, 24, false, false);
598 BOOST_REQUIRE (frame.size() < 230000000 / (24 * 8));
600 boost::filesystem::path const dir("build/test/verify_test17");
601 boost::filesystem::remove_all (dir);
602 dcp_from_frame (frame, dir);
604 vector<boost::filesystem::path> dirs;
605 dirs.push_back (dir);
606 list<dcp::VerificationNote> notes = dcp::verify (dirs, &stage, &progress, xsd_test);
607 BOOST_REQUIRE_EQUAL (notes.size(), 0);
611 /* DCP with valid Interop subtitles */
612 BOOST_AUTO_TEST_CASE (verify_test18)
614 boost::filesystem::path const dir("build/test/verify_test18");
615 boost::filesystem::remove_all (dir);
616 boost::filesystem::create_directories (dir);
617 boost::filesystem::copy_file ("test/data/subs1.xml", dir / "subs.xml");
618 shared_ptr<dcp::InteropSubtitleAsset> asset(new dcp::InteropSubtitleAsset(dir / "subs.xml"));
619 shared_ptr<dcp::ReelAsset> reel_asset(new dcp::ReelSubtitleAsset(asset, dcp::Fraction(24, 1), 16 * 24, 0));
620 shared_ptr<dcp::Reel> reel(new dcp::Reel());
621 reel->add (reel_asset);
622 shared_ptr<dcp::CPL> cpl(new dcp::CPL("hello", dcp::FEATURE));
624 shared_ptr<dcp::DCP> dcp(new dcp::DCP(dir));
626 dcp->write_xml (dcp::INTEROP);
628 vector<boost::filesystem::path> dirs;
629 dirs.push_back (dir);
630 list<dcp::VerificationNote> notes = dcp::verify (dirs, &stage, &progress, xsd_test);
631 BOOST_REQUIRE_EQUAL (notes.size(), 1U);
632 list<dcp::VerificationNote>::const_iterator i = notes.begin ();
633 BOOST_CHECK_EQUAL (i->code(), dcp::VerificationNote::NOT_SMPTE);
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);
662 BOOST_REQUIRE_EQUAL (notes.size(), 3);
663 list<dcp::VerificationNote>::const_iterator i = notes.begin ();
664 BOOST_CHECK_EQUAL (i->code(), dcp::VerificationNote::NOT_SMPTE);
666 BOOST_CHECK_EQUAL (i->code(), dcp::VerificationNote::XML_VALIDATION_ERROR);
668 BOOST_CHECK_EQUAL (i->code(), dcp::VerificationNote::XML_VALIDATION_ERROR);
673 /* DCP with valid SMPTE subtitles */
674 BOOST_AUTO_TEST_CASE (verify_test20)
676 boost::filesystem::path const dir("build/test/verify_test20");
677 boost::filesystem::remove_all (dir);
678 boost::filesystem::create_directories (dir);
679 boost::filesystem::copy_file ("test/data/subs.mxf", dir / "subs.mxf");
680 shared_ptr<dcp::SMPTESubtitleAsset> asset(new dcp::SMPTESubtitleAsset(dir / "subs.mxf"));
681 shared_ptr<dcp::ReelAsset> reel_asset(new dcp::ReelSubtitleAsset(asset, dcp::Fraction(24, 1), 16 * 24, 0));
682 shared_ptr<dcp::Reel> reel(new dcp::Reel());
683 reel->add (reel_asset);
684 shared_ptr<dcp::CPL> cpl(new dcp::CPL("hello", dcp::FEATURE));
686 shared_ptr<dcp::DCP> dcp(new dcp::DCP(dir));
688 dcp->write_xml (dcp::SMPTE);
690 vector<boost::filesystem::path> dirs;
691 dirs.push_back (dir);
692 list<dcp::VerificationNote> notes = dcp::verify (dirs, &stage, &progress, xsd_test);
693 BOOST_REQUIRE_EQUAL (notes.size(), 0);
697 /* DCP with broken SMPTE subtitles */
698 BOOST_AUTO_TEST_CASE (verify_test21)
700 boost::filesystem::path const dir("build/test/verify_test21");
701 boost::filesystem::remove_all (dir);
702 boost::filesystem::create_directories (dir);
703 boost::filesystem::copy_file ("test/data/broken_smpte.mxf", dir / "subs.mxf");
704 shared_ptr<dcp::SMPTESubtitleAsset> asset(new dcp::SMPTESubtitleAsset(dir / "subs.mxf"));
705 shared_ptr<dcp::ReelAsset> reel_asset(new dcp::ReelSubtitleAsset(asset, dcp::Fraction(24, 1), 16 * 24, 0));
706 shared_ptr<dcp::Reel> reel(new dcp::Reel());
707 reel->add (reel_asset);
708 shared_ptr<dcp::CPL> cpl(new dcp::CPL("hello", dcp::FEATURE));
710 shared_ptr<dcp::DCP> dcp(new dcp::DCP(dir));
712 dcp->write_xml (dcp::SMPTE);
714 vector<boost::filesystem::path> dirs;
715 dirs.push_back (dir);
716 list<dcp::VerificationNote> notes = dcp::verify (dirs, &stage, &progress, xsd_test);
717 BOOST_REQUIRE_EQUAL (notes.size(), 2);
718 BOOST_CHECK_EQUAL (notes.front().code(), dcp::VerificationNote::XML_VALIDATION_ERROR);
719 BOOST_CHECK_EQUAL (notes.back().code(), dcp::VerificationNote::XML_VALIDATION_ERROR);
724 BOOST_AUTO_TEST_CASE (verify_test22)
726 boost::filesystem::path const ov_dir("build/test/verify_test22_ov");
727 boost::filesystem::remove_all (ov_dir);
728 boost::filesystem::create_directories (ov_dir);
730 shared_ptr<dcp::OpenJPEGImage> image = black_image ();
731 dcp::ArrayData frame = dcp::compress_j2k (image, 100000000, 24, false, false);
732 BOOST_REQUIRE (frame.size() < 230000000 / (24 * 8));
733 dcp_from_frame (frame, ov_dir);
735 dcp::DCP ov (ov_dir);
738 boost::filesystem::path const vf_dir("build/test/verify_test22_vf");
739 boost::filesystem::remove_all (vf_dir);
740 boost::filesystem::create_directories (vf_dir);
742 shared_ptr<dcp::Reel> reel(new dcp::Reel());
743 reel->add (ov.cpls().front()->reels().front()->main_picture());
744 shared_ptr<dcp::CPL> cpl(new dcp::CPL("hello", dcp::FEATURE));
746 dcp::DCP vf (vf_dir);
748 vf.write_xml (dcp::SMPTE);
750 vector<boost::filesystem::path> dirs;
751 dirs.push_back (vf_dir);
752 list<dcp::VerificationNote> notes = dcp::verify (dirs, &stage, &progress, xsd_test);
753 BOOST_REQUIRE_EQUAL (notes.size(), 1);
754 BOOST_CHECK_EQUAL (notes.front().code(), dcp::VerificationNote::EXTERNAL_ASSET);
758 /* DCP with valid CompositionMetadataAsset */
759 BOOST_AUTO_TEST_CASE (verify_test23)
761 boost::filesystem::path const dir("build/test/verify_test23");
762 boost::filesystem::remove_all (dir);
763 boost::filesystem::create_directories (dir);
765 boost::filesystem::copy_file ("test/data/subs.mxf", dir / "subs.mxf");
766 shared_ptr<dcp::SMPTESubtitleAsset> asset(new dcp::SMPTESubtitleAsset(dir / "subs.mxf"));
767 shared_ptr<dcp::ReelAsset> reel_asset(new dcp::ReelSubtitleAsset(asset, dcp::Fraction(24, 1), 16 * 24, 0));
769 shared_ptr<dcp::Reel> reel(new dcp::Reel());
770 reel->add (reel_asset);
771 shared_ptr<dcp::CPL> cpl(new dcp::CPL("hello", dcp::FEATURE));
773 cpl->set_main_sound_configuration ("L,C,R,Lfe,-,-");
774 cpl->set_main_sound_sample_rate (48000);
775 cpl->set_main_picture_stored_area (dcp::Size(1998, 1080));
776 cpl->set_main_picture_active_area (dcp::Size(1440, 1080));
780 dcp.write_xml (dcp::SMPTE);
782 vector<boost::filesystem::path> dirs;
783 dirs.push_back (dir);
784 list<dcp::VerificationNote> notes = dcp::verify (dirs, &stage, &progress, xsd_test);
788 boost::filesystem::path find_cpl (boost::filesystem::path dir)
790 for (boost::filesystem::directory_iterator i = boost::filesystem::directory_iterator(dir); i != boost::filesystem::directory_iterator(); i++) {
791 if (boost::starts_with(i->path().filename().string(), "cpl_")) {
796 BOOST_REQUIRE (false);
797 return boost::filesystem::path();
801 /* DCP with invalid CompositionMetadataAsset */
802 BOOST_AUTO_TEST_CASE (verify_test24)
804 boost::filesystem::path const dir("build/test/verify_test24");
805 boost::filesystem::remove_all (dir);
806 boost::filesystem::create_directories (dir);
808 shared_ptr<dcp::Reel> reel(new dcp::Reel());
809 reel->add (black_picture_asset(dir));
810 shared_ptr<dcp::CPL> cpl(new dcp::CPL("hello", dcp::FEATURE));
812 cpl->set_main_sound_configuration ("L,C,R,Lfe,-,-");
813 cpl->set_main_sound_sample_rate (48000);
814 cpl->set_main_picture_stored_area (dcp::Size(1998, 1080));
815 cpl->set_main_picture_active_area (dcp::Size(1440, 1080));
819 dcp.write_xml (dcp::SMPTE);
822 Editor e (find_cpl("build/test/verify_test24"));
823 e.replace ("MainSound", "MainSoundX");
826 vector<boost::filesystem::path> dirs;
827 dirs.push_back (dir);
828 list<dcp::VerificationNote> notes = dcp::verify (dirs, &stage, &progress, xsd_test);
829 BOOST_REQUIRE_EQUAL (notes.size(), 4);
831 list<dcp::VerificationNote>::const_iterator i = notes.begin ();
832 BOOST_CHECK_EQUAL (i->code(), dcp::VerificationNote::XML_VALIDATION_ERROR);
834 BOOST_CHECK_EQUAL (i->code(), dcp::VerificationNote::XML_VALIDATION_ERROR);
836 BOOST_CHECK_EQUAL (i->code(), dcp::VerificationNote::XML_VALIDATION_ERROR);
838 BOOST_CHECK_EQUAL (i->code(), dcp::VerificationNote::CPL_HASH_INCORRECT);
843 /* DCP with invalid CompositionMetadataAsset */
844 BOOST_AUTO_TEST_CASE (verify_test25)
846 boost::filesystem::path const dir("build/test/verify_test25");
847 boost::filesystem::remove_all (dir);
848 boost::filesystem::create_directories (dir);
850 boost::filesystem::copy_file ("test/data/subs.mxf", dir / "subs.mxf");
851 shared_ptr<dcp::SMPTESubtitleAsset> asset(new dcp::SMPTESubtitleAsset(dir / "subs.mxf"));
852 shared_ptr<dcp::ReelAsset> reel_asset(new dcp::ReelSubtitleAsset(asset, dcp::Fraction(24, 1), 16 * 24, 0));
854 shared_ptr<dcp::Reel> reel(new dcp::Reel());
855 reel->add (reel_asset);
856 shared_ptr<dcp::CPL> cpl(new dcp::CPL("hello", dcp::FEATURE));
858 cpl->set_main_sound_configuration ("L,C,R,Lfe,-,-");
859 cpl->set_main_sound_sample_rate (48000);
860 cpl->set_main_picture_stored_area (dcp::Size(1998, 1080));
861 cpl->set_main_picture_active_area (dcp::Size(1440, 1080));
865 dcp.write_xml (dcp::SMPTE);
868 Editor e (find_cpl("build/test/verify_test25"));
869 e.replace ("</MainPictureActiveArea>", "</MainPictureActiveArea><BadTag></BadTag>");
872 vector<boost::filesystem::path> dirs;
873 dirs.push_back (dir);
874 list<dcp::VerificationNote> notes = dcp::verify (dirs, &stage, &progress, xsd_test);