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"
48 #include <boost/test/unit_test.hpp>
49 #include <boost/foreach.hpp>
50 #include <boost/algorithm/string.hpp>
59 using boost::optional;
60 using boost::shared_ptr;
63 static list<pair<string, optional<boost::filesystem::path> > > stages;
64 static int next_verify_test_number = 1;
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, next_verify_test_number);
138 list<dcp::VerificationNote> notes = dcp::verify (directories, &stage, &progress, "xsd");
140 boost::filesystem::path const cpl_file = dcp::String::compose("build/test/verify_test%1/cpl_81fb54df-e1bf-4647-8788-ea7ba154375b.xml", next_verify_test_number);
141 boost::filesystem::path const pkl_file = dcp::String::compose("build/test/verify_test1/pkl_ae8a9818-872a-4f86-8493-11dfdea03e09.xml", next_verify_test_number);
142 boost::filesystem::path const assetmap_file = dcp::String::compose("build/test/verify_test1/ASSETMAP.xml", next_verify_test_number);
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(dcp::String::compose("build/test/verify_test%1", next_verify_test_number)));
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(dcp::String::compose("build/test/verify_test%1/video.mxf", next_verify_test_number)));
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(dcp::String::compose("build/test/verify_test%1/video.mxf", next_verify_test_number)));
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(dcp::String::compose("build/test/verify_test%1/audio.mxf", next_verify_test_number)));
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);
182 next_verify_test_number++;
185 /* Corrupt the MXFs and check that this is spotted */
186 BOOST_AUTO_TEST_CASE (verify_test2)
188 vector<boost::filesystem::path> directories = setup (1, next_verify_test_number++);
190 FILE* mod = fopen("build/test/verify_test2/video.mxf", "r+b");
192 fseek (mod, 4096, SEEK_SET);
194 fwrite (&x, sizeof(x), 1, mod);
197 mod = fopen("build/test/verify_test2/audio.mxf", "r+b");
199 fseek (mod, 4096, SEEK_SET);
200 BOOST_REQUIRE (fwrite (&x, sizeof(x), 1, mod) == 1);
203 list<dcp::VerificationNote> notes = dcp::verify (directories, &stage, &progress, "xsd");
205 BOOST_REQUIRE_EQUAL (notes.size(), 2);
206 BOOST_CHECK_EQUAL (notes.front().type(), dcp::VerificationNote::VERIFY_ERROR);
207 BOOST_CHECK_EQUAL (notes.front().code(), dcp::VerificationNote::PICTURE_HASH_INCORRECT);
208 BOOST_CHECK_EQUAL (notes.back().type(), dcp::VerificationNote::VERIFY_ERROR);
209 BOOST_CHECK_EQUAL (notes.back().code(), dcp::VerificationNote::SOUND_HASH_INCORRECT);
212 /* Corrupt the hashes in the PKL and check that the disagreement between CPL and PKL is spotted */
213 BOOST_AUTO_TEST_CASE (verify_test3)
215 vector<boost::filesystem::path> directories = setup (1, next_verify_test_number++);
218 Editor e ("build/test/verify_test3/pkl_ae8a9818-872a-4f86-8493-11dfdea03e09.xml");
219 e.replace ("<Hash>", "<Hash>x");
222 list<dcp::VerificationNote> notes = dcp::verify (directories, &stage, &progress, "xsd");
226 BOOST_REQUIRE_EQUAL (notes.size(), 6);
227 list<dcp::VerificationNote>::const_iterator i = notes.begin();
228 BOOST_CHECK_EQUAL (i->type(), dcp::VerificationNote::VERIFY_ERROR);
229 BOOST_CHECK_EQUAL (i->code(), dcp::VerificationNote::CPL_HASH_INCORRECT);
231 BOOST_CHECK_EQUAL (i->type(), dcp::VerificationNote::VERIFY_ERROR);
232 BOOST_CHECK_EQUAL (i->code(), dcp::VerificationNote::PKL_CPL_PICTURE_HASHES_DISAGREE);
234 BOOST_CHECK_EQUAL (i->type(), dcp::VerificationNote::VERIFY_ERROR);
235 BOOST_CHECK_EQUAL (i->code(), dcp::VerificationNote::PKL_CPL_SOUND_HASHES_DISAGREE);
237 BOOST_CHECK_EQUAL (i->type(), dcp::VerificationNote::VERIFY_ERROR);
238 BOOST_CHECK_EQUAL (i->code(), dcp::VerificationNote::XML_VALIDATION_ERROR);
240 BOOST_CHECK_EQUAL (i->type(), dcp::VerificationNote::VERIFY_ERROR);
241 BOOST_CHECK_EQUAL (i->code(), dcp::VerificationNote::XML_VALIDATION_ERROR);
243 BOOST_CHECK_EQUAL (i->type(), dcp::VerificationNote::VERIFY_ERROR);
244 BOOST_CHECK_EQUAL (i->code(), dcp::VerificationNote::XML_VALIDATION_ERROR);
248 /* Corrupt the ContentKind in the CPL */
249 BOOST_AUTO_TEST_CASE (verify_test4)
251 vector<boost::filesystem::path> directories = setup (1, next_verify_test_number++);
254 Editor e ("build/test/verify_test4/cpl_81fb54df-e1bf-4647-8788-ea7ba154375b.xml");
255 e.replace ("<ContentKind>", "<ContentKind>x");
258 list<dcp::VerificationNote> notes = dcp::verify (directories, &stage, &progress, "xsd");
260 BOOST_REQUIRE_EQUAL (notes.size(), 1);
261 BOOST_CHECK_EQUAL (notes.front().code(), dcp::VerificationNote::GENERAL_READ);
262 BOOST_CHECK_EQUAL (*notes.front().note(), "Bad content kind 'xfeature'");
266 boost::filesystem::path
269 return dcp::String::compose("build/test/verify_test%1/cpl_81fb54df-e1bf-4647-8788-ea7ba154375b.xml", n);
273 boost::filesystem::path
276 return dcp::String::compose("build/test/verify_test%1/pkl_ae8a9818-872a-4f86-8493-11dfdea03e09.xml", n);
280 boost::filesystem::path
283 return dcp::String::compose("build/test/verify_test%1/ASSETMAP.xml", n);
287 void check_after_replace (int n, boost::function<boost::filesystem::path (int)> file, string from, string to, dcp::VerificationNote::Code code1)
289 vector<boost::filesystem::path> directories = setup (1, n);
293 e.replace (from, to);
296 list<dcp::VerificationNote> notes = dcp::verify (directories, &stage, &progress, "xsd");
300 BOOST_REQUIRE_EQUAL (notes.size(), 1);
301 BOOST_CHECK_EQUAL (notes.front().code(), code1);
305 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)
307 vector<boost::filesystem::path> directories = setup (1, n);
311 e.replace (from, to);
314 list<dcp::VerificationNote> notes = dcp::verify (directories, &stage, &progress, "xsd");
318 BOOST_REQUIRE_EQUAL (notes.size(), 2);
319 BOOST_CHECK_EQUAL (notes.front().code(), code1);
320 BOOST_CHECK_EQUAL (notes.back().code(), code2);
324 void check_after_replace (
325 int n, boost::function<boost::filesystem::path (int)> file,
328 dcp::VerificationNote::Code code1,
329 dcp::VerificationNote::Code code2,
330 dcp::VerificationNote::Code code3
333 vector<boost::filesystem::path> directories = setup (1, n);
337 e.replace (from, to);
340 list<dcp::VerificationNote> notes = dcp::verify (directories, &stage, &progress, "xsd");
344 BOOST_REQUIRE_EQUAL (notes.size(), 3);
345 list<dcp::VerificationNote>::const_iterator i = notes.begin ();
346 BOOST_CHECK_EQUAL (i->code(), code1);
348 BOOST_CHECK_EQUAL (i->code(), code2);
350 BOOST_CHECK_EQUAL (i->code(), code3);
354 BOOST_AUTO_TEST_CASE (verify_test5)
356 check_after_replace (
357 next_verify_test_number++, &cpl,
358 "<FrameRate>24 1", "<FrameRate>99 1",
359 dcp::VerificationNote::CPL_HASH_INCORRECT,
360 dcp::VerificationNote::INVALID_PICTURE_FRAME_RATE
365 BOOST_AUTO_TEST_CASE (verify_test6)
367 vector<boost::filesystem::path> directories = setup (1, next_verify_test_number++);
369 boost::filesystem::remove ("build/test/verify_test6/video.mxf");
370 list<dcp::VerificationNote> notes = dcp::verify (directories, &stage, &progress, "xsd");
372 BOOST_REQUIRE_EQUAL (notes.size(), 1);
373 BOOST_CHECK_EQUAL (notes.front().type(), dcp::VerificationNote::VERIFY_ERROR);
374 BOOST_CHECK_EQUAL (notes.front().code(), dcp::VerificationNote::MISSING_ASSET);
378 boost::filesystem::path
381 return dcp::String::compose("build/test/verify_test%1/ASSETMAP.xml", n);
384 /* Empty asset filename in ASSETMAP */
385 BOOST_AUTO_TEST_CASE (verify_test7)
387 check_after_replace (
388 next_verify_test_number++, &assetmap,
389 "<Path>video.mxf</Path>", "<Path></Path>",
390 dcp::VerificationNote::EMPTY_ASSET_PATH
394 /* Mismatched standard */
395 BOOST_AUTO_TEST_CASE (verify_test8)
397 check_after_replace (
398 next_verify_test_number++, &cpl,
399 "http://www.smpte-ra.org/schemas/429-7/2006/CPL", "http://www.digicine.com/PROTO-ASDCP-CPL-20040511#",
400 dcp::VerificationNote::MISMATCHED_STANDARD,
401 dcp::VerificationNote::XML_VALIDATION_ERROR,
402 dcp::VerificationNote::CPL_HASH_INCORRECT
406 /* Badly formatted <Id> in CPL */
407 BOOST_AUTO_TEST_CASE (verify_test9)
409 /* There's no CPL_HASH_INCORRECT error here because it can't find the correct hash by ID (since the ID is wrong) */
410 check_after_replace (
411 next_verify_test_number++, &cpl,
412 "<Id>urn:uuid:81fb54df-e1bf-4647-8788-ea7ba154375b", "<Id>urn:uuid:81fb54df-e1bf-4647-8788-ea7ba154375",
413 dcp::VerificationNote::XML_VALIDATION_ERROR
417 /* Badly formatted <IssueDate> in CPL */
418 BOOST_AUTO_TEST_CASE (verify_test10)
420 check_after_replace (
421 next_verify_test_number++, &cpl,
422 "<IssueDate>", "<IssueDate>x",
423 dcp::VerificationNote::XML_VALIDATION_ERROR,
424 dcp::VerificationNote::CPL_HASH_INCORRECT
428 /* Badly-formatted <Id> in PKL */
429 BOOST_AUTO_TEST_CASE (verify_test11)
431 check_after_replace (
432 next_verify_test_number++, &pkl,
433 "<Id>urn:uuid:ae8", "<Id>urn:uuid:xe8",
434 dcp::VerificationNote::XML_VALIDATION_ERROR
438 /* Badly-formatted <Id> in ASSETMAP */
439 BOOST_AUTO_TEST_CASE (verify_test12)
441 check_after_replace (
442 next_verify_test_number++, &asset_map,
443 "<Id>urn:uuid:74e", "<Id>urn:uuid:x4e",
444 dcp::VerificationNote::XML_VALIDATION_ERROR
448 /* Basic test of an Interop DCP */
449 BOOST_AUTO_TEST_CASE (verify_test13)
452 vector<boost::filesystem::path> directories = setup (3, next_verify_test_number);
453 list<dcp::VerificationNote> notes = dcp::verify (directories, &stage, &progress, "xsd");
455 boost::filesystem::path const cpl_file = dcp::String::compose("build/test/verify_test%1/cpl_cbfd2bc0-21cf-4a8f-95d8-9cddcbe51296.xml", next_verify_test_number);
456 boost::filesystem::path const pkl_file = dcp::String::compose("build/test/verify_test%1/pkl_d87a950c-bd6f-41f6-90cc-56ccd673e131.xml", next_verify_test_number);
457 boost::filesystem::path const assetmap_file = dcp::String::compose("build/test/verify_test%1/ASSETMAP", next_verify_test_number);
459 list<pair<string, optional<boost::filesystem::path> > >::const_iterator st = stages.begin();
460 BOOST_CHECK_EQUAL (st->first, "Checking DCP");
461 BOOST_REQUIRE (st->second);
462 BOOST_CHECK_EQUAL (st->second.get(), boost::filesystem::canonical(dcp::String::compose("build/test/verify_test%1", next_verify_test_number)));
464 BOOST_CHECK_EQUAL (st->first, "Checking CPL");
465 BOOST_REQUIRE (st->second);
466 BOOST_CHECK_EQUAL (st->second.get(), boost::filesystem::canonical(cpl_file));
468 BOOST_CHECK_EQUAL (st->first, "Checking reel");
469 BOOST_REQUIRE (!st->second);
471 BOOST_CHECK_EQUAL (st->first, "Checking picture asset hash");
472 BOOST_REQUIRE (st->second);
473 BOOST_CHECK_EQUAL (st->second.get(), boost::filesystem::canonical(dcp::String::compose("build/test/verify_test%1/j2c_c6035f97-b07d-4e1c-944d-603fc2ddc242.mxf", next_verify_test_number)));
475 BOOST_CHECK_EQUAL (st->first, "Checking picture frame sizes");
476 BOOST_REQUIRE (st->second);
477 BOOST_CHECK_EQUAL (st->second.get(), boost::filesystem::canonical(dcp::String::compose("build/test/verify_test%1/j2c_c6035f97-b07d-4e1c-944d-603fc2ddc242.mxf", next_verify_test_number)));
479 BOOST_CHECK_EQUAL (st->first, "Checking sound asset hash");
480 BOOST_REQUIRE (st->second);
481 BOOST_CHECK_EQUAL (st->second.get(), boost::filesystem::canonical(dcp::String::compose("build/test/verify_test%1/pcm_69cf9eaf-9a99-4776-b022-6902208626c3.mxf", next_verify_test_number)));
483 BOOST_CHECK_EQUAL (st->first, "Checking PKL");
484 BOOST_REQUIRE (st->second);
485 BOOST_CHECK_EQUAL (st->second.get(), boost::filesystem::canonical(pkl_file));
487 BOOST_CHECK_EQUAL (st->first, "Checking ASSETMAP");
488 BOOST_REQUIRE (st->second);
489 BOOST_CHECK_EQUAL (st->second.get(), boost::filesystem::canonical(assetmap_file));
491 BOOST_REQUIRE (st == stages.end());
495 BOOST_CHECK_EQUAL (notes.size(), 0);
497 next_verify_test_number++;
500 /* DCP with a short asset */
501 BOOST_AUTO_TEST_CASE (verify_test14)
503 vector<boost::filesystem::path> directories = setup (8, next_verify_test_number);
504 list<dcp::VerificationNote> notes = dcp::verify (directories, &stage, &progress, "xsd");
508 BOOST_REQUIRE_EQUAL (notes.size(), 4);
509 list<dcp::VerificationNote>::const_iterator i = notes.begin ();
510 BOOST_CHECK_EQUAL (i->code(), dcp::VerificationNote::DURATION_TOO_SMALL);
512 BOOST_CHECK_EQUAL (i->code(), dcp::VerificationNote::INTRINSIC_DURATION_TOO_SMALL);
514 BOOST_CHECK_EQUAL (i->code(), dcp::VerificationNote::DURATION_TOO_SMALL);
516 BOOST_CHECK_EQUAL (i->code(), dcp::VerificationNote::INTRINSIC_DURATION_TOO_SMALL);
518 next_verify_test_number++;
523 shared_ptr<dcp::OpenJPEGImage>
526 shared_ptr<dcp::OpenJPEGImage> image(new dcp::OpenJPEGImage(dcp::Size(1998, 1080)));
527 int const pixels = 1998 * 1080;
528 for (int i = 0; i < 3; ++i) {
529 memset (image->data(i), 0, pixels * sizeof(int));
537 dcp_from_frame (dcp::Data const& frame, boost::filesystem::path dir)
539 shared_ptr<dcp::MonoPictureAsset> asset(new dcp::MonoPictureAsset(dcp::Fraction(24, 1), dcp::SMPTE));
540 boost::filesystem::create_directories (dir);
541 shared_ptr<dcp::PictureAssetWriter> writer = asset->start_write (dir / "pic.mxf", true);
542 for (int i = 0; i < 24; ++i) {
543 writer->write (frame.data().get(), frame.size());
547 shared_ptr<dcp::ReelAsset> reel_asset(new dcp::ReelMonoPictureAsset(asset, 0));
548 shared_ptr<dcp::Reel> reel(new dcp::Reel());
549 reel->add (reel_asset);
550 shared_ptr<dcp::CPL> cpl(new dcp::CPL("hello", dcp::FEATURE));
552 shared_ptr<dcp::DCP> dcp(new dcp::DCP(dir));
554 dcp->write_xml (dcp::SMPTE);
558 /* DCP with an over-sized JPEG2000 frame */
559 BOOST_AUTO_TEST_CASE (verify_test15)
561 int const too_big = 1302083 * 2;
563 /* Compress a black image */
564 shared_ptr<dcp::OpenJPEGImage> image = black_image ();
565 dcp::Data frame = dcp::compress_j2k (image, 100000000, 24, false, false);
566 BOOST_REQUIRE (frame.size() < too_big);
568 /* Place it in a bigger block with some zero padding at the end */
569 dcp::Data oversized_frame(too_big);
570 memcpy (oversized_frame.data().get(), frame.data().get(), frame.size());
571 memset (oversized_frame.data().get() + frame.size(), 0, too_big - frame.size());
573 boost::filesystem::path const dir("build/test/verify_test15");
574 boost::filesystem::remove_all (dir);
575 dcp_from_frame (oversized_frame, dir);
577 vector<boost::filesystem::path> dirs;
578 dirs.push_back (dir);
579 list<dcp::VerificationNote> notes = dcp::verify (dirs, &stage, &progress, "xsd");
580 BOOST_REQUIRE_EQUAL (notes.size(), 1);
581 BOOST_CHECK_EQUAL (notes.front().code(), dcp::VerificationNote::PICTURE_FRAME_TOO_LARGE);
585 /* DCP with a nearly over-sized JPEG2000 frame */
586 BOOST_AUTO_TEST_CASE (verify_test16)
588 int const nearly_too_big = 1302083 * 0.98;
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() < nearly_too_big);
595 /* Place it in a bigger block with some zero padding at the end */
596 dcp::Data oversized_frame(nearly_too_big);
597 memcpy (oversized_frame.data().get(), frame.data().get(), frame.size());
598 memset (oversized_frame.data().get() + frame.size(), 0, nearly_too_big - frame.size());
600 boost::filesystem::path const dir("build/test/verify_test16");
601 boost::filesystem::remove_all (dir);
602 dcp_from_frame (oversized_frame, dir);
604 vector<boost::filesystem::path> dirs;
605 dirs.push_back (dir);
606 list<dcp::VerificationNote> notes = dcp::verify (dirs, &stage, &progress, "xsd");
607 BOOST_REQUIRE_EQUAL (notes.size(), 1);
608 BOOST_CHECK_EQUAL (notes.front().code(), dcp::VerificationNote::PICTURE_FRAME_NEARLY_TOO_LARGE);
612 /* DCP with a within-range JPEG2000 frame */
613 BOOST_AUTO_TEST_CASE (verify_test17)
615 /* Compress a black image */
616 shared_ptr<dcp::OpenJPEGImage> image = black_image ();
617 dcp::Data frame = dcp::compress_j2k (image, 100000000, 24, false, false);
618 BOOST_REQUIRE (frame.size() < 230000000 / (24 * 8));
620 boost::filesystem::path const dir("build/test/verify_test17");
621 boost::filesystem::remove_all (dir);
622 dcp_from_frame (frame, dir);
624 vector<boost::filesystem::path> dirs;
625 dirs.push_back (dir);
626 list<dcp::VerificationNote> notes = dcp::verify (dirs, &stage, &progress, "xsd");
627 BOOST_REQUIRE_EQUAL (notes.size(), 0);
631 /* DCP with valid Interop subtitles */
632 BOOST_AUTO_TEST_CASE (verify_test18)
634 boost::filesystem::path const dir("build/test/verify_test18");
635 boost::filesystem::remove_all (dir);
636 boost::filesystem::create_directories (dir);
637 boost::filesystem::copy_file ("test/data/subs1.xml", dir / "subs.xml");
638 shared_ptr<dcp::InteropSubtitleAsset> asset(new dcp::InteropSubtitleAsset(dir / "subs.xml"));
639 shared_ptr<dcp::ReelAsset> reel_asset(new dcp::ReelSubtitleAsset(asset, dcp::Fraction(24, 1), 16 * 24, 0));
640 shared_ptr<dcp::Reel> reel(new dcp::Reel());
641 reel->add (reel_asset);
642 shared_ptr<dcp::CPL> cpl(new dcp::CPL("hello", dcp::FEATURE));
644 shared_ptr<dcp::DCP> dcp(new dcp::DCP(dir));
646 dcp->write_xml (dcp::INTEROP);
648 vector<boost::filesystem::path> dirs;
649 dirs.push_back (dir);
650 list<dcp::VerificationNote> notes = dcp::verify (dirs, &stage, &progress, "xsd");
651 BOOST_REQUIRE_EQUAL (notes.size(), 0);
655 /* DCP with broken Interop subtitles */
656 BOOST_AUTO_TEST_CASE (verify_test19)
658 boost::filesystem::path const dir("build/test/verify_test19");
659 boost::filesystem::remove_all (dir);
660 boost::filesystem::create_directories (dir);
661 boost::filesystem::copy_file ("test/data/subs1.xml", dir / "subs.xml");
662 shared_ptr<dcp::InteropSubtitleAsset> asset(new dcp::InteropSubtitleAsset(dir / "subs.xml"));
663 shared_ptr<dcp::ReelAsset> reel_asset(new dcp::ReelSubtitleAsset(asset, dcp::Fraction(24, 1), 16 * 24, 0));
664 shared_ptr<dcp::Reel> reel(new dcp::Reel());
665 reel->add (reel_asset);
666 shared_ptr<dcp::CPL> cpl(new dcp::CPL("hello", dcp::FEATURE));
668 shared_ptr<dcp::DCP> dcp(new dcp::DCP(dir));
670 dcp->write_xml (dcp::INTEROP);
673 Editor e (dir / "subs.xml");
674 e.replace ("</ReelNumber>", "</ReelNumber><Foo></Foo>");
677 vector<boost::filesystem::path> dirs;
678 dirs.push_back (dir);
679 list<dcp::VerificationNote> notes = dcp::verify (dirs, &stage, &progress, "xsd");
681 BOOST_REQUIRE_EQUAL (notes.size(), 2);
682 BOOST_CHECK_EQUAL (notes.front().code(), dcp::VerificationNote::XML_VALIDATION_ERROR);
683 BOOST_CHECK_EQUAL (notes.back().code(), dcp::VerificationNote::XML_VALIDATION_ERROR);
687 /* DCP with valid SMPTE subtitles */
688 BOOST_AUTO_TEST_CASE (verify_test20)
690 boost::filesystem::path const dir("build/test/verify_test20");
691 boost::filesystem::remove_all (dir);
692 boost::filesystem::create_directories (dir);
693 boost::filesystem::copy_file ("test/data/subs.mxf", dir / "subs.mxf");
694 shared_ptr<dcp::SMPTESubtitleAsset> asset(new dcp::SMPTESubtitleAsset(dir / "subs.mxf"));
695 shared_ptr<dcp::ReelAsset> reel_asset(new dcp::ReelSubtitleAsset(asset, dcp::Fraction(24, 1), 16 * 24, 0));
696 shared_ptr<dcp::Reel> reel(new dcp::Reel());
697 reel->add (reel_asset);
698 shared_ptr<dcp::CPL> cpl(new dcp::CPL("hello", dcp::FEATURE));
700 shared_ptr<dcp::DCP> dcp(new dcp::DCP(dir));
702 dcp->write_xml (dcp::SMPTE);
704 vector<boost::filesystem::path> dirs;
705 dirs.push_back (dir);
706 list<dcp::VerificationNote> notes = dcp::verify (dirs, &stage, &progress, "xsd");
708 BOOST_REQUIRE_EQUAL (notes.size(), 0);
712 /* DCP with broken SMPTE subtitles */
713 BOOST_AUTO_TEST_CASE (verify_test21)
715 boost::filesystem::path const dir("build/test/verify_test21");
716 boost::filesystem::remove_all (dir);
717 boost::filesystem::create_directories (dir);
718 boost::filesystem::copy_file ("test/data/broken_smpte.mxf", dir / "subs.mxf");
719 shared_ptr<dcp::SMPTESubtitleAsset> asset(new dcp::SMPTESubtitleAsset(dir / "subs.mxf"));
720 shared_ptr<dcp::ReelAsset> reel_asset(new dcp::ReelSubtitleAsset(asset, dcp::Fraction(24, 1), 16 * 24, 0));
721 shared_ptr<dcp::Reel> reel(new dcp::Reel());
722 reel->add (reel_asset);
723 shared_ptr<dcp::CPL> cpl(new dcp::CPL("hello", dcp::FEATURE));
725 shared_ptr<dcp::DCP> dcp(new dcp::DCP(dir));
727 dcp->write_xml (dcp::SMPTE);
729 vector<boost::filesystem::path> dirs;
730 dirs.push_back (dir);
731 list<dcp::VerificationNote> notes = dcp::verify (dirs, &stage, &progress, "xsd");
733 BOOST_REQUIRE_EQUAL (notes.size(), 2);
734 BOOST_CHECK_EQUAL (notes.front().code(), dcp::VerificationNote::XML_VALIDATION_ERROR);
735 BOOST_CHECK_EQUAL (notes.back().code(), dcp::VerificationNote::XML_VALIDATION_ERROR);
740 BOOST_AUTO_TEST_CASE (verify_test22)
742 boost::filesystem::path const ov_dir("build/test/verify_test22_ov");
743 boost::filesystem::remove_all (ov_dir);
744 boost::filesystem::create_directories (ov_dir);
746 shared_ptr<dcp::OpenJPEGImage> image = black_image ();
747 dcp::Data frame = dcp::compress_j2k (image, 100000000, 24, false, false);
748 BOOST_REQUIRE (frame.size() < 230000000 / (24 * 8));
749 dcp_from_frame (frame, ov_dir);
751 dcp::DCP ov (ov_dir);
754 boost::filesystem::path const vf_dir("build/test/verify_test22_vf");
755 boost::filesystem::remove_all (vf_dir);
756 boost::filesystem::create_directories (vf_dir);
758 shared_ptr<dcp::Reel> reel(new dcp::Reel());
759 reel->add (ov.cpls().front()->reels().front()->main_picture());
760 shared_ptr<dcp::CPL> cpl(new dcp::CPL("hello", dcp::FEATURE));
762 dcp::DCP vf (vf_dir);
764 vf.write_xml (dcp::SMPTE);
766 vector<boost::filesystem::path> dirs;
767 dirs.push_back (vf_dir);
768 list<dcp::VerificationNote> notes = dcp::verify (dirs, &stage, &progress, "xsd");
770 BOOST_REQUIRE_EQUAL (notes.size(), 1);
771 BOOST_CHECK_EQUAL (notes.front().code(), dcp::VerificationNote::EXTERNAL_ASSET);