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;
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_18be072e-5a0f-44e1-b2eb-c8a52ae12789.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 fseek (mod, 4096, SEEK_SET);
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_18be072e-5a0f-44e1-b2eb-c8a52ae12789.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_18be072e-5a0f-44e1-b2eb-c8a52ae12789.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:18b", "<Id>urn:uuid:x8b",
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:ae8", "<Id>urn:uuid:xe8",
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_CHECK_EQUAL (notes.size(), 0);
491 /* DCP with a short asset */
492 BOOST_AUTO_TEST_CASE (verify_test14)
494 vector<boost::filesystem::path> directories = setup (8, 14);
495 list<dcp::VerificationNote> notes = dcp::verify (directories, &stage, &progress, xsd_test);
497 BOOST_REQUIRE_EQUAL (notes.size(), 4);
498 list<dcp::VerificationNote>::const_iterator i = notes.begin ();
499 BOOST_CHECK_EQUAL (i->code(), dcp::VerificationNote::DURATION_TOO_SMALL);
501 BOOST_CHECK_EQUAL (i->code(), dcp::VerificationNote::INTRINSIC_DURATION_TOO_SMALL);
503 BOOST_CHECK_EQUAL (i->code(), dcp::VerificationNote::DURATION_TOO_SMALL);
505 BOOST_CHECK_EQUAL (i->code(), dcp::VerificationNote::INTRINSIC_DURATION_TOO_SMALL);
512 dcp_from_frame (dcp::Data const& frame, boost::filesystem::path dir)
514 shared_ptr<dcp::MonoPictureAsset> asset(new dcp::MonoPictureAsset(dcp::Fraction(24, 1), dcp::SMPTE));
515 boost::filesystem::create_directories (dir);
516 shared_ptr<dcp::PictureAssetWriter> writer = asset->start_write (dir / "pic.mxf", true);
517 for (int i = 0; i < 24; ++i) {
518 writer->write (frame.data().get(), frame.size());
522 shared_ptr<dcp::ReelAsset> reel_asset(new dcp::ReelMonoPictureAsset(asset, 0));
523 shared_ptr<dcp::Reel> reel(new dcp::Reel());
524 reel->add (reel_asset);
525 shared_ptr<dcp::CPL> cpl(new dcp::CPL("hello", dcp::FEATURE));
527 shared_ptr<dcp::DCP> dcp(new dcp::DCP(dir));
529 dcp->write_xml (dcp::SMPTE);
533 /* DCP with an over-sized JPEG2000 frame */
534 BOOST_AUTO_TEST_CASE (verify_test15)
536 int const too_big = 1302083 * 2;
538 /* Compress a black image */
539 shared_ptr<dcp::OpenJPEGImage> image = black_image ();
540 dcp::Data frame = dcp::compress_j2k (image, 100000000, 24, false, false);
541 BOOST_REQUIRE (frame.size() < too_big);
543 /* Place it in a bigger block with some zero padding at the end */
544 dcp::Data oversized_frame(too_big);
545 memcpy (oversized_frame.data().get(), frame.data().get(), frame.size());
546 memset (oversized_frame.data().get() + frame.size(), 0, too_big - frame.size());
548 boost::filesystem::path const dir("build/test/verify_test15");
549 boost::filesystem::remove_all (dir);
550 dcp_from_frame (oversized_frame, dir);
552 vector<boost::filesystem::path> dirs;
553 dirs.push_back (dir);
554 list<dcp::VerificationNote> notes = dcp::verify (dirs, &stage, &progress, xsd_test);
555 BOOST_REQUIRE_EQUAL (notes.size(), 1);
556 BOOST_CHECK_EQUAL (notes.front().code(), dcp::VerificationNote::PICTURE_FRAME_TOO_LARGE);
560 /* DCP with a nearly over-sized JPEG2000 frame */
561 BOOST_AUTO_TEST_CASE (verify_test16)
563 int const nearly_too_big = 1302083 * 0.98;
565 /* Compress a black image */
566 shared_ptr<dcp::OpenJPEGImage> image = black_image ();
567 dcp::Data frame = dcp::compress_j2k (image, 100000000, 24, false, false);
568 BOOST_REQUIRE (frame.size() < nearly_too_big);
570 /* Place it in a bigger block with some zero padding at the end */
571 dcp::Data oversized_frame(nearly_too_big);
572 memcpy (oversized_frame.data().get(), frame.data().get(), frame.size());
573 memset (oversized_frame.data().get() + frame.size(), 0, nearly_too_big - frame.size());
575 boost::filesystem::path const dir("build/test/verify_test16");
576 boost::filesystem::remove_all (dir);
577 dcp_from_frame (oversized_frame, dir);
579 vector<boost::filesystem::path> dirs;
580 dirs.push_back (dir);
581 list<dcp::VerificationNote> notes = dcp::verify (dirs, &stage, &progress, xsd_test);
582 BOOST_REQUIRE_EQUAL (notes.size(), 1);
583 BOOST_CHECK_EQUAL (notes.front().code(), dcp::VerificationNote::PICTURE_FRAME_NEARLY_TOO_LARGE);
587 /* DCP with a within-range JPEG2000 frame */
588 BOOST_AUTO_TEST_CASE (verify_test17)
590 /* Compress a black image */
591 shared_ptr<dcp::OpenJPEGImage> image = black_image ();
592 dcp::Data frame = dcp::compress_j2k (image, 100000000, 24, false, false);
593 BOOST_REQUIRE (frame.size() < 230000000 / (24 * 8));
595 boost::filesystem::path const dir("build/test/verify_test17");
596 boost::filesystem::remove_all (dir);
597 dcp_from_frame (frame, dir);
599 vector<boost::filesystem::path> dirs;
600 dirs.push_back (dir);
601 list<dcp::VerificationNote> notes = dcp::verify (dirs, &stage, &progress, xsd_test);
602 BOOST_REQUIRE_EQUAL (notes.size(), 0);
606 /* DCP with valid Interop subtitles */
607 BOOST_AUTO_TEST_CASE (verify_test18)
609 boost::filesystem::path const dir("build/test/verify_test18");
610 boost::filesystem::remove_all (dir);
611 boost::filesystem::create_directories (dir);
612 boost::filesystem::copy_file ("test/data/subs1.xml", dir / "subs.xml");
613 shared_ptr<dcp::InteropSubtitleAsset> asset(new dcp::InteropSubtitleAsset(dir / "subs.xml"));
614 shared_ptr<dcp::ReelAsset> reel_asset(new dcp::ReelSubtitleAsset(asset, dcp::Fraction(24, 1), 16 * 24, 0));
615 shared_ptr<dcp::Reel> reel(new dcp::Reel());
616 reel->add (reel_asset);
617 shared_ptr<dcp::CPL> cpl(new dcp::CPL("hello", dcp::FEATURE));
619 shared_ptr<dcp::DCP> dcp(new dcp::DCP(dir));
621 dcp->write_xml (dcp::INTEROP);
623 vector<boost::filesystem::path> dirs;
624 dirs.push_back (dir);
625 list<dcp::VerificationNote> notes = dcp::verify (dirs, &stage, &progress, xsd_test);
626 BOOST_REQUIRE_EQUAL (notes.size(), 0);
630 /* DCP with broken Interop subtitles */
631 BOOST_AUTO_TEST_CASE (verify_test19)
633 boost::filesystem::path const dir("build/test/verify_test19");
634 boost::filesystem::remove_all (dir);
635 boost::filesystem::create_directories (dir);
636 boost::filesystem::copy_file ("test/data/subs1.xml", dir / "subs.xml");
637 shared_ptr<dcp::InteropSubtitleAsset> asset(new dcp::InteropSubtitleAsset(dir / "subs.xml"));
638 shared_ptr<dcp::ReelAsset> reel_asset(new dcp::ReelSubtitleAsset(asset, dcp::Fraction(24, 1), 16 * 24, 0));
639 shared_ptr<dcp::Reel> reel(new dcp::Reel());
640 reel->add (reel_asset);
641 shared_ptr<dcp::CPL> cpl(new dcp::CPL("hello", dcp::FEATURE));
643 shared_ptr<dcp::DCP> dcp(new dcp::DCP(dir));
645 dcp->write_xml (dcp::INTEROP);
648 Editor e (dir / "subs.xml");
649 e.replace ("</ReelNumber>", "</ReelNumber><Foo></Foo>");
652 vector<boost::filesystem::path> dirs;
653 dirs.push_back (dir);
654 list<dcp::VerificationNote> notes = dcp::verify (dirs, &stage, &progress, xsd_test);
655 BOOST_REQUIRE_EQUAL (notes.size(), 2);
656 BOOST_CHECK_EQUAL (notes.front().code(), dcp::VerificationNote::XML_VALIDATION_ERROR);
657 BOOST_CHECK_EQUAL (notes.back().code(), dcp::VerificationNote::XML_VALIDATION_ERROR);
661 /* DCP with valid SMPTE subtitles */
662 BOOST_AUTO_TEST_CASE (verify_test20)
664 boost::filesystem::path const dir("build/test/verify_test20");
665 boost::filesystem::remove_all (dir);
666 boost::filesystem::create_directories (dir);
667 boost::filesystem::copy_file ("test/data/subs.mxf", dir / "subs.mxf");
668 shared_ptr<dcp::SMPTESubtitleAsset> asset(new dcp::SMPTESubtitleAsset(dir / "subs.mxf"));
669 shared_ptr<dcp::ReelAsset> reel_asset(new dcp::ReelSubtitleAsset(asset, dcp::Fraction(24, 1), 16 * 24, 0));
670 shared_ptr<dcp::Reel> reel(new dcp::Reel());
671 reel->add (reel_asset);
672 shared_ptr<dcp::CPL> cpl(new dcp::CPL("hello", dcp::FEATURE));
674 shared_ptr<dcp::DCP> dcp(new dcp::DCP(dir));
676 dcp->write_xml (dcp::SMPTE);
678 vector<boost::filesystem::path> dirs;
679 dirs.push_back (dir);
680 list<dcp::VerificationNote> notes = dcp::verify (dirs, &stage, &progress, xsd_test);
681 BOOST_REQUIRE_EQUAL (notes.size(), 0);
685 /* DCP with broken SMPTE subtitles */
686 BOOST_AUTO_TEST_CASE (verify_test21)
688 boost::filesystem::path const dir("build/test/verify_test21");
689 boost::filesystem::remove_all (dir);
690 boost::filesystem::create_directories (dir);
691 boost::filesystem::copy_file ("test/data/broken_smpte.mxf", dir / "subs.mxf");
692 shared_ptr<dcp::SMPTESubtitleAsset> asset(new dcp::SMPTESubtitleAsset(dir / "subs.mxf"));
693 shared_ptr<dcp::ReelAsset> reel_asset(new dcp::ReelSubtitleAsset(asset, dcp::Fraction(24, 1), 16 * 24, 0));
694 shared_ptr<dcp::Reel> reel(new dcp::Reel());
695 reel->add (reel_asset);
696 shared_ptr<dcp::CPL> cpl(new dcp::CPL("hello", dcp::FEATURE));
698 shared_ptr<dcp::DCP> dcp(new dcp::DCP(dir));
700 dcp->write_xml (dcp::SMPTE);
702 vector<boost::filesystem::path> dirs;
703 dirs.push_back (dir);
704 list<dcp::VerificationNote> notes = dcp::verify (dirs, &stage, &progress, xsd_test);
705 BOOST_REQUIRE_EQUAL (notes.size(), 2);
706 BOOST_CHECK_EQUAL (notes.front().code(), dcp::VerificationNote::XML_VALIDATION_ERROR);
707 BOOST_CHECK_EQUAL (notes.back().code(), dcp::VerificationNote::XML_VALIDATION_ERROR);
712 BOOST_AUTO_TEST_CASE (verify_test22)
714 boost::filesystem::path const ov_dir("build/test/verify_test22_ov");
715 boost::filesystem::remove_all (ov_dir);
716 boost::filesystem::create_directories (ov_dir);
718 shared_ptr<dcp::OpenJPEGImage> image = black_image ();
719 dcp::Data frame = dcp::compress_j2k (image, 100000000, 24, false, false);
720 BOOST_REQUIRE (frame.size() < 230000000 / (24 * 8));
721 dcp_from_frame (frame, ov_dir);
723 dcp::DCP ov (ov_dir);
726 boost::filesystem::path const vf_dir("build/test/verify_test22_vf");
727 boost::filesystem::remove_all (vf_dir);
728 boost::filesystem::create_directories (vf_dir);
730 shared_ptr<dcp::Reel> reel(new dcp::Reel());
731 reel->add (ov.cpls().front()->reels().front()->main_picture());
732 shared_ptr<dcp::CPL> cpl(new dcp::CPL("hello", dcp::FEATURE));
734 dcp::DCP vf (vf_dir);
736 vf.write_xml (dcp::SMPTE);
738 vector<boost::filesystem::path> dirs;
739 dirs.push_back (vf_dir);
740 list<dcp::VerificationNote> notes = dcp::verify (dirs, &stage, &progress, xsd_test);
741 BOOST_REQUIRE_EQUAL (notes.size(), 1);
742 BOOST_CHECK_EQUAL (notes.front().code(), dcp::VerificationNote::EXTERNAL_ASSET);