X-Git-Url: https://git.carlh.net/gitweb/?a=blobdiff_plain;f=test%2Fverify_test.cc;h=34707b1f7a7df426b6501c2d819e39482b9761d3;hb=cb4759c178e3229796e8139f3f21a230532a7499;hp=d7d9aaaec335184c2e285de14f45aec76aede82e;hpb=113f1062f131577cb169fe1516d49d1f79fa16cf;p=libdcp.git diff --git a/test/verify_test.cc b/test/verify_test.cc index d7d9aaae..34707b1f 100644 --- a/test/verify_test.cc +++ b/test/verify_test.cc @@ -83,19 +83,49 @@ static string filename_to_id(boost::filesystem::path path) return path.string().substr(4, path.string().length() - 8); } -static boost::filesystem::path const dcp_test1_pkl = find_file("test/ref/DCP/dcp_test1", "pkl_").filename(); -static string const dcp_test1_pkl_id = filename_to_id(dcp_test1_pkl); +static +boost::filesystem::path +dcp_test1_pkl() +{ + return find_file("test/ref/DCP/dcp_test1", "pkl_").filename(); +} + +static +string +dcp_test1_pkl_id() +{ + return filename_to_id(dcp_test1_pkl()); +} + +static +boost::filesystem::path +dcp_test1_cpl() +{ + return find_file("test/ref/DCP/dcp_test1", "cpl_").filename(); +} -static boost::filesystem::path const dcp_test1_cpl = find_file("test/ref/DCP/dcp_test1", "cpl_").filename(); -static string const dcp_test1_cpl_id = filename_to_id(dcp_test1_cpl); +static +string +dcp_test1_cpl_id() +{ + return filename_to_id(dcp_test1_cpl()); +} static string const dcp_test1_asset_map_id = "017b3de4-6dda-408d-b19b-6711354b0bc3"; -static boost::filesystem::path const encryption_test_cpl = find_file("test/ref/DCP/encryption_test", "cpl_").filename(); -static string const encryption_test_cpl_id = filename_to_id(encryption_test_cpl); +static +string +encryption_test_cpl_id() +{ + return filename_to_id(find_file("test/ref/DCP/encryption_test", "cpl_").filename()); +} -static boost::filesystem::path const encryption_test_pkl = find_file("test/ref/DCP/encryption_test", "pkl_").filename(); -static string const encryption_test_pkl_id = filename_to_id(encryption_test_pkl); +static +string +encryption_test_pkl_id() +{ + return filename_to_id(find_file("test/ref/DCP/encryption_test", "pkl_").filename()); +} static void stage (string s, optional p) @@ -167,9 +197,9 @@ LIBDCP_ENABLE_WARNINGS static void -check_verify_result (vector dir, vector test_notes) +check_verify_result(vector dir, vector kdm, vector test_notes) { - auto notes = dcp::verify({dir}, &stage, &progress, {}, xsd_test); + auto notes = dcp::verify({dir}, kdm, &stage, &progress, {}, xsd_test); std::sort (notes.begin(), notes.end()); std::sort (test_notes.begin(), test_notes.end()); @@ -177,24 +207,28 @@ check_verify_result (vector dir, vector test_notes) for (auto i: notes) { message += " " + note_to_string(i) + "\n"; message += dcp::String::compose( - " [%1 %2 %3 %4 %5]\n", + " [%1 %2 %3 %4 %5 %6 %7]\n", static_cast(i.type()), static_cast(i.code()), i.note().get_value_or(""), i.file().get_value_or(""), - i.line().get_value_or(0) + i.line().get_value_or(0), + i.reference_hash().get_value_or(""), + i.calculated_hash().get_value_or("") ); } message += "Expected:\n"; for (auto i: test_notes) { message += " " + note_to_string(i) + "\n"; message += dcp::String::compose( - " [%1 %2 %3 %4 %5]\n", + " [%1 %2 %3 %4 %5 %6 %7]\n", static_cast(i.type()), static_cast(i.code()), i.note().get_value_or(""), i.file().get_value_or(""), - i.line().get_value_or(0) + i.line().get_value_or(0), + i.reference_hash().get_value_or(""), + i.calculated_hash().get_value_or("") ); } @@ -217,7 +251,7 @@ check_verify_result_after_replace (string suffix, boost::function e.replace (from, to); } - auto notes = dcp::verify({dir}, &stage, &progress, {}, xsd_test); + auto notes = dcp::verify({dir}, {}, &stage, &progress, {}, xsd_test); BOOST_REQUIRE_EQUAL (notes.size(), codes.size()); auto i = notes.begin(); @@ -239,14 +273,36 @@ add_font(shared_ptr asset) } +class HashCalculator +{ +public: + HashCalculator(boost::filesystem::path path) + : _path(path) + , _old_hash(dcp::make_digest(path, [](int64_t, int64_t) {})) + {} + + std::string old_hash() const { + return _old_hash; + } + + std::string new_hash() const { + return dcp::make_digest(_path, [](int64_t, int64_t) {}); + } + +private: + boost::filesystem::path _path; + std::string _old_hash; +}; + + BOOST_AUTO_TEST_CASE (verify_no_error) { stages.clear (); auto dir = setup (1, "no_error"); - auto notes = dcp::verify({dir}, &stage, &progress, {}, xsd_test); + auto notes = dcp::verify({dir}, {}, &stage, &progress, {}, xsd_test); - path const cpl_file = dir / dcp_test1_cpl; - path const pkl_file = dir / dcp_test1_pkl; + path const cpl_file = dir / dcp_test1_cpl(); + path const pkl_file = dir / dcp_test1_pkl(); path const assetmap_file = dir / "ASSETMAP.xml"; auto st = stages.begin(); @@ -280,8 +336,7 @@ BOOST_AUTO_TEST_CASE (verify_no_error) BOOST_CHECK_EQUAL (st->first, "Checking PKL"); BOOST_REQUIRE (st->second); BOOST_CHECK_EQUAL (st->second.get(), canonical(pkl_file)); - ++st; - BOOST_CHECK_EQUAL (st->first, "Checking ASSETMAP"); + ++st; BOOST_CHECK_EQUAL (st->first, "Checking ASSETMAP"); BOOST_REQUIRE (st->second); BOOST_CHECK_EQUAL (st->second.get(), canonical(assetmap_file)); ++st; @@ -298,26 +353,33 @@ BOOST_AUTO_TEST_CASE (verify_incorrect_picture_sound_hash) auto dir = setup (1, "incorrect_picture_sound_hash"); auto video_path = path(dir / "video.mxf"); + HashCalculator video_calc(video_path); auto mod = fopen(video_path.string().c_str(), "r+b"); BOOST_REQUIRE (mod); - fseek (mod, 4096, SEEK_SET); + BOOST_REQUIRE_EQUAL(fseek(mod, -16, SEEK_END), 0); int x = 42; - fwrite (&x, sizeof(x), 1, mod); + BOOST_REQUIRE(fwrite(&x, sizeof(x), 1, mod) == 1); fclose (mod); auto audio_path = path(dir / "audio.mxf"); + HashCalculator audio_calc(audio_path); mod = fopen(audio_path.string().c_str(), "r+b"); BOOST_REQUIRE (mod); - BOOST_REQUIRE_EQUAL (fseek(mod, -64, SEEK_END), 0); + BOOST_REQUIRE_EQUAL(fseek(mod, 0, SEEK_END), 0); BOOST_REQUIRE (fwrite (&x, sizeof(x), 1, mod) == 1); fclose (mod); dcp::ASDCPErrorSuspender sus; check_verify_result ( { dir }, + {}, { - { dcp::VerificationNote::Type::ERROR, dcp::VerificationNote::Code::INCORRECT_PICTURE_HASH, canonical(video_path) }, - { dcp::VerificationNote::Type::ERROR, dcp::VerificationNote::Code::INCORRECT_SOUND_HASH, canonical(audio_path) }, + dcp::VerificationNote( + dcp::VerificationNote::Type::ERROR, dcp::VerificationNote::Code::INCORRECT_PICTURE_HASH, canonical(video_path) + ).set_reference_hash(video_calc.old_hash()).set_calculated_hash(video_calc.new_hash()), + dcp::VerificationNote( + dcp::VerificationNote::Type::ERROR, dcp::VerificationNote::Code::INCORRECT_SOUND_HASH, canonical(audio_path) + ).set_reference_hash(audio_calc.old_hash()).set_calculated_hash(audio_calc.new_hash()), }); } @@ -328,20 +390,25 @@ BOOST_AUTO_TEST_CASE (verify_mismatched_picture_sound_hashes) auto dir = setup (1, "mismatched_picture_sound_hashes"); + HashCalculator calc(dir / dcp_test1_cpl()); + { - Editor e (dir / dcp_test1_pkl); + Editor e (dir / dcp_test1_pkl()); e.replace ("", "x"); } check_verify_result ( { dir }, + {}, { - { dcp::VerificationNote::Type::ERROR, dcp::VerificationNote::Code::MISMATCHED_CPL_HASHES, dcp_test1_cpl_id, canonical(dir / dcp_test1_cpl) }, + dcp::VerificationNote( + dcp::VerificationNote::Type::ERROR, dcp::VerificationNote::Code::MISMATCHED_CPL_HASHES, dcp_test1_cpl_id(), canonical(dir / dcp_test1_cpl()) + ).set_reference_hash("x" + calc.old_hash()).set_calculated_hash(calc.old_hash()), { dcp::VerificationNote::Type::ERROR, dcp::VerificationNote::Code::MISMATCHED_PICTURE_HASHES, canonical(dir / "video.mxf") }, { dcp::VerificationNote::Type::ERROR, dcp::VerificationNote::Code::MISMATCHED_SOUND_HASHES, canonical(dir / "audio.mxf") }, - { dcp::VerificationNote::Type::ERROR, dcp::VerificationNote::Code::INVALID_XML, "value 'xKcJb7S2K5cNm8RG4kfQD5FTeS0A=' is invalid Base64-encoded binary", canonical(dir / dcp_test1_pkl), 28 }, - { dcp::VerificationNote::Type::ERROR, dcp::VerificationNote::Code::INVALID_XML, "value 'xtfX1mVIKJCVr1m7Y32Nzxf0+Rpw=' is invalid Base64-encoded binary", canonical(dir / dcp_test1_pkl), 12 }, - { dcp::VerificationNote::Type::ERROR, dcp::VerificationNote::Code::INVALID_XML, "value 'xwUmt8G+cFFKMGt0ueS9+F1S4uhc=' is invalid Base64-encoded binary", canonical(dir / dcp_test1_pkl), 20 }, + { dcp::VerificationNote::Type::ERROR, dcp::VerificationNote::Code::INVALID_XML, "value 'x3M7YTgvFKXXMEGLkIbV4miC90FE=' is invalid Base64-encoded binary", canonical(dir / dcp_test1_pkl()), 28 }, + { dcp::VerificationNote::Type::ERROR, dcp::VerificationNote::Code::INVALID_XML, "value 'xskI+5b/9LA/y6h0mcyxysJYanxI=' is invalid Base64-encoded binary", canonical(dir / dcp_test1_pkl()), 12 }, + { dcp::VerificationNote::Type::ERROR, dcp::VerificationNote::Code::INVALID_XML, "value 'xvsVjRV9vhTBPUWfE/TT1o2vdQsI=' is invalid Base64-encoded binary", canonical(dir / dcp_test1_pkl()), 20 }, }); } @@ -350,15 +417,20 @@ BOOST_AUTO_TEST_CASE (verify_failed_read_content_kind) { auto dir = setup (1, "failed_read_content_kind"); + HashCalculator calc(dir / dcp_test1_cpl()); + { - Editor e (dir / dcp_test1_cpl); + Editor e (dir / dcp_test1_cpl()); e.replace ("", "x"); } check_verify_result ( { dir }, + {}, { - { dcp::VerificationNote::Type::ERROR, dcp::VerificationNote::Code::MISMATCHED_CPL_HASHES, dcp_test1_cpl_id, canonical(dir / dcp_test1_cpl) }, + dcp::VerificationNote( + dcp::VerificationNote::Type::ERROR, dcp::VerificationNote::Code::MISMATCHED_CPL_HASHES, dcp_test1_cpl_id(), canonical(dir / dcp_test1_cpl()) + ).set_reference_hash(calc.old_hash()).set_calculated_hash(calc.new_hash()), { dcp::VerificationNote::Type::ERROR, dcp::VerificationNote::Code::INVALID_CONTENT_KIND, string("xtrailer") } }); } @@ -368,7 +440,7 @@ static path cpl (string suffix) { - return dcp::String::compose("build/test/verify_test%1/%2", suffix, dcp_test1_cpl); + return dcp::String::compose("build/test/verify_test%1/%2", suffix, dcp_test1_cpl()); } @@ -376,7 +448,7 @@ static path pkl (string suffix) { - return dcp::String::compose("build/test/verify_test%1/%2", suffix, dcp_test1_pkl); + return dcp::String::compose("build/test/verify_test%1/%2", suffix, dcp_test1_pkl()); } @@ -404,6 +476,7 @@ BOOST_AUTO_TEST_CASE (verify_missing_asset) remove (dir / "video.mxf"); check_verify_result ( { dir }, + {}, { { dcp::VerificationNote::Type::ERROR, dcp::VerificationNote::Code::MISSING_ASSET, canonical(dir) / "video.mxf" } }); @@ -462,8 +535,8 @@ BOOST_AUTO_TEST_CASE (verify_invalid_xml_pkl_id) { check_verify_result_after_replace ( "invalid_xml_pkl_id", &pkl, - "urn:uuid:" + dcp_test1_pkl_id.substr(0, 3), - "urn:uuid:x" + dcp_test1_pkl_id.substr(1, 2), + "urn:uuid:" + dcp_test1_pkl_id().substr(0, 3), + "urn:uuid:x" + dcp_test1_pkl_id().substr(1, 2), { dcp::VerificationNote::Code::INVALID_XML } ); } @@ -484,7 +557,7 @@ BOOST_AUTO_TEST_CASE (verify_invalid_standard) { stages.clear (); auto dir = setup (3, "verify_invalid_standard"); - auto notes = dcp::verify({dir}, &stage, &progress, {}, xsd_test); + auto notes = dcp::verify({dir}, {}, &stage, &progress, {}, xsd_test); path const cpl_file = dir / "cpl_cbfd2bc0-21cf-4a8f-95d8-9cddcbe51296.xml"; path const pkl_file = dir / "pkl_d87a950c-bd6f-41f6-90cc-56ccd673e131.xml"; @@ -541,15 +614,27 @@ BOOST_AUTO_TEST_CASE (verify_invalid_standard) BOOST_AUTO_TEST_CASE (verify_invalid_duration) { auto dir = setup (8, "invalid_duration"); + + dcp::DCP dcp(dir); + dcp.read(); + BOOST_REQUIRE(dcp.cpls().size() == 1); + auto cpl = dcp.cpls()[0]; + check_verify_result ( { dir }, + {}, { { dcp::VerificationNote::Type::BV21_ERROR, dcp::VerificationNote::Code::INVALID_STANDARD }, { dcp::VerificationNote::Type::ERROR, dcp::VerificationNote::Code::INVALID_DURATION, string("d7576dcb-a361-4139-96b8-267f5f8d7f91") }, { dcp::VerificationNote::Type::ERROR, dcp::VerificationNote::Code::INVALID_INTRINSIC_DURATION, string("d7576dcb-a361-4139-96b8-267f5f8d7f91") }, { dcp::VerificationNote::Type::ERROR, dcp::VerificationNote::Code::INVALID_DURATION, string("a2a87f5d-b749-4a7e-8d0c-9d48a4abf626") }, { dcp::VerificationNote::Type::ERROR, dcp::VerificationNote::Code::INVALID_INTRINSIC_DURATION, string("a2a87f5d-b749-4a7e-8d0c-9d48a4abf626") }, - { dcp::VerificationNote::Type::BV21_ERROR, dcp::VerificationNote::Code::INVALID_JPEG2000_GUARD_BITS_FOR_2K, string("2") } + { dcp::VerificationNote::Type::BV21_ERROR, dcp::VerificationNote::Code::INVALID_JPEG2000_GUARD_BITS_FOR_2K, string("2") }, + dcp::VerificationNote( + dcp::VerificationNote::Type::WARNING, + dcp::VerificationNote::Code::EMPTY_CONTENT_VERSION_LABEL_TEXT, + cpl->file().get() + ).set_id("d74fda30-d5f4-4c5f-870f-ebc089d97eb7") }); } @@ -589,13 +674,28 @@ BOOST_AUTO_TEST_CASE (verify_invalid_picture_frame_size_in_bytes) prepare_directory (dir); auto cpl = dcp_from_frame (oversized_frame, dir); - check_verify_result ( - { dir }, - { - { dcp::VerificationNote::Type::ERROR, dcp::VerificationNote::Code::INVALID_JPEG2000_CODESTREAM, string("missing marker start byte") }, - { dcp::VerificationNote::Type::ERROR, dcp::VerificationNote::Code::INVALID_PICTURE_FRAME_SIZE_IN_BYTES, canonical(dir / "pic.mxf") }, - { dcp::VerificationNote::Type::BV21_ERROR, dcp::VerificationNote::Code::MISSING_CPL_METADATA, cpl->id(), cpl->file().get() } - }); + vector expected; + for (auto i = 0; i < 24; ++i) { + expected.push_back( + dcp::VerificationNote( + dcp::VerificationNote::Type::ERROR, dcp::VerificationNote::Code::INVALID_JPEG2000_CODESTREAM, string("missing marker start byte") + ).set_frame(i).set_frame_rate(24) + ); + } + + for (auto i = 0; i < 24; ++i) { + expected.push_back( + dcp::VerificationNote( + dcp::VerificationNote::Type::ERROR, dcp::VerificationNote::Code::INVALID_PICTURE_FRAME_SIZE_IN_BYTES, canonical(dir / "pic.mxf") + ).set_frame(i).set_frame_rate(24) + ); + } + + expected.push_back( + { dcp::VerificationNote::Type::BV21_ERROR, dcp::VerificationNote::Code::MISSING_CPL_METADATA, cpl->id(), cpl->file().get() } + ); + + check_verify_result({ dir }, {}, expected); } @@ -617,13 +717,29 @@ BOOST_AUTO_TEST_CASE (verify_nearly_invalid_picture_frame_size_in_bytes) prepare_directory (dir); auto cpl = dcp_from_frame (oversized_frame, dir); - check_verify_result ( - { dir }, - { - { dcp::VerificationNote::Type::ERROR, dcp::VerificationNote::Code::INVALID_JPEG2000_CODESTREAM, string("missing marker start byte") }, - { dcp::VerificationNote::Type::WARNING, dcp::VerificationNote::Code::NEARLY_INVALID_PICTURE_FRAME_SIZE_IN_BYTES, canonical(dir / "pic.mxf") }, - { dcp::VerificationNote::Type::BV21_ERROR, dcp::VerificationNote::Code::MISSING_CPL_METADATA, cpl->id(), cpl->file().get() } - }); + vector expected; + + for (auto i = 0; i < 24; ++i) { + expected.push_back( + dcp::VerificationNote( + dcp::VerificationNote::Type::ERROR, dcp::VerificationNote::Code::INVALID_JPEG2000_CODESTREAM, string("missing marker start byte") + ).set_frame(i).set_frame_rate(24) + ); + } + + for (auto i = 0; i < 24; ++i) { + expected.push_back( + dcp::VerificationNote( + dcp::VerificationNote::Type::WARNING, dcp::VerificationNote::Code::NEARLY_INVALID_PICTURE_FRAME_SIZE_IN_BYTES, canonical(dir / "pic.mxf") + ).set_frame(i).set_frame_rate(24) + ); + } + + expected.push_back( + { dcp::VerificationNote::Type::BV21_ERROR, dcp::VerificationNote::Code::MISSING_CPL_METADATA, cpl->id(), cpl->file().get() } + ); + + check_verify_result ({ dir }, {}, expected); } @@ -638,7 +754,7 @@ BOOST_AUTO_TEST_CASE (verify_valid_picture_frame_size_in_bytes) prepare_directory (dir); auto cpl = dcp_from_frame (frame, dir); - check_verify_result ({ dir }, {{ dcp::VerificationNote::Type::BV21_ERROR, dcp::VerificationNote::Code::MISSING_CPL_METADATA, cpl->id(), cpl->file().get() }}); + check_verify_result({ dir }, {}, {{ dcp::VerificationNote::Type::BV21_ERROR, dcp::VerificationNote::Code::MISSING_CPL_METADATA, cpl->id(), cpl->file().get() }}); } @@ -652,7 +768,28 @@ BOOST_AUTO_TEST_CASE (verify_valid_interop_subtitles) write_dcp_with_single_asset (dir, reel_asset, dcp::Standard::INTEROP); check_verify_result ( - {dir}, { + {dir}, + {}, + { + { dcp::VerificationNote::Type::BV21_ERROR, dcp::VerificationNote::Code::INVALID_STANDARD }, + { dcp::VerificationNote::Type::ERROR, dcp::VerificationNote::Code::MISSING_FONT, string{"theFontId"} } + }); +} + + +BOOST_AUTO_TEST_CASE(verify_catch_missing_font_file_with_interop_ccap) +{ + path const dir("build/test/verify_catch_missing_font_file_with_interop_ccap"); + prepare_directory(dir); + copy_file("test/data/subs1.xml", dir / "ccap.xml"); + auto asset = make_shared(dir / "ccap.xml"); + auto reel_asset = make_shared(asset, dcp::Fraction(24, 1), 16 * 24, 0); + write_dcp_with_single_asset(dir, reel_asset, dcp::Standard::INTEROP); + + check_verify_result ( + {dir}, + {}, + { { dcp::VerificationNote::Type::BV21_ERROR, dcp::VerificationNote::Code::INVALID_STANDARD }, { dcp::VerificationNote::Type::ERROR, dcp::VerificationNote::Code::MISSING_FONT, string{"theFontId"} } }); @@ -677,6 +814,7 @@ BOOST_AUTO_TEST_CASE (verify_invalid_interop_subtitles) check_verify_result ( { dir }, + {}, { { dcp::VerificationNote::Type::BV21_ERROR, dcp::VerificationNote::Code::INVALID_STANDARD }, { dcp::VerificationNote::Type::ERROR, dcp::VerificationNote::Code::INVALID_XML, string("no declaration found for element 'Foo'"), path(), 5 }, @@ -703,6 +841,7 @@ BOOST_AUTO_TEST_CASE(verify_interop_subtitle_asset_with_no_subtitles) check_verify_result ( { dir }, + {}, { { dcp::VerificationNote::Type::BV21_ERROR, dcp::VerificationNote::Code::INVALID_STANDARD }, { dcp::VerificationNote::Type::ERROR, dcp::VerificationNote::Code::MISSING_SUBTITLE, asset->id(), boost::filesystem::canonical(asset->file().get()) }, @@ -723,6 +862,7 @@ BOOST_AUTO_TEST_CASE(verify_interop_subtitle_asset_with_single_space_subtitle) check_verify_result ( { dir }, + {}, { { dcp::VerificationNote::Type::BV21_ERROR, dcp::VerificationNote::Code::INVALID_STANDARD }, { dcp::VerificationNote::Type::ERROR, dcp::VerificationNote::Code::MISSING_FONT, string{"Arial"} } @@ -742,6 +882,7 @@ BOOST_AUTO_TEST_CASE (verify_valid_smpte_subtitles) check_verify_result( {dir}, + {}, { { dcp::VerificationNote::Type::BV21_ERROR, dcp::VerificationNote::Code::MISSING_CPL_METADATA, cpl->id(), cpl->file().get() }, { dcp::VerificationNote::Type::WARNING, dcp::VerificationNote::Code::INVALID_SUBTITLE_ISSUE_DATE, string{"2021-04-14T13:19:14.000+02:00"} }, @@ -764,6 +905,7 @@ BOOST_AUTO_TEST_CASE (verify_invalid_smpte_subtitles) check_verify_result ( { dir }, + {}, { { dcp::VerificationNote::Type::ERROR, dcp::VerificationNote::Code::INVALID_XML, string("no declaration found for element 'Foo'"), path(), 2 }, { @@ -792,6 +934,7 @@ BOOST_AUTO_TEST_CASE (verify_empty_text_node_in_subtitles) check_verify_result ( { dir }, + {}, { { dcp::VerificationNote::Type::WARNING, dcp::VerificationNote::Code::EMPTY_TEXT }, { dcp::VerificationNote::Type::WARNING, dcp::VerificationNote::Code::INVALID_SUBTITLE_FIRST_TEXT_TIME }, @@ -815,6 +958,7 @@ BOOST_AUTO_TEST_CASE (verify_empty_text_node_in_subtitles_with_child_nodes) check_verify_result ( { dir }, + {}, { { dcp::VerificationNote::Type::BV21_ERROR, dcp::VerificationNote::Code::INVALID_STANDARD }, { dcp::VerificationNote::Type::ERROR, dcp::VerificationNote::Code::MISSING_FONT, string{"font0"} } @@ -834,6 +978,7 @@ BOOST_AUTO_TEST_CASE (verify_empty_text_node_in_subtitles_with_empty_child_nodes check_verify_result ( { dir }, + {}, { { dcp::VerificationNote::Type::ERROR, dcp::VerificationNote::Code::MISSING_SUBTITLE, asset->id(), boost::filesystem::canonical(asset->file().get()) }, { dcp::VerificationNote::Type::BV21_ERROR, dcp::VerificationNote::Code::INVALID_STANDARD }, @@ -864,6 +1009,7 @@ BOOST_AUTO_TEST_CASE (verify_external_asset) check_verify_result ( { vf_dir }, + {}, { { dcp::VerificationNote::Type::WARNING, dcp::VerificationNote::Code::EXTERNAL_ASSET, picture->asset()->id() }, { dcp::VerificationNote::Type::BV21_ERROR, dcp::VerificationNote::Code::MISSING_CPL_METADATA, cpl->id(), cpl->file().get() } @@ -958,6 +1104,8 @@ BOOST_AUTO_TEST_CASE (verify_invalid_cpl_metadata_bad_tag) dcp.set_annotation_text("hello"); dcp.write_xml(); + HashCalculator calc(find_cpl(dir)); + { Editor e (find_cpl(dir)); e.replace ("MainSound", "MainSoundX"); @@ -965,6 +1113,7 @@ BOOST_AUTO_TEST_CASE (verify_invalid_cpl_metadata_bad_tag) check_verify_result ( { dir }, + {}, { { dcp::VerificationNote::Type::ERROR, dcp::VerificationNote::Code::INVALID_XML, string("no declaration found for element 'meta:MainSoundXConfiguration'"), canonical(cpl->file().get()), 50 }, { dcp::VerificationNote::Type::ERROR, dcp::VerificationNote::Code::INVALID_XML, string("no declaration found for element 'meta:MainSoundXSampleRate'"), canonical(cpl->file().get()), 51 }, @@ -980,7 +1129,9 @@ BOOST_AUTO_TEST_CASE (verify_invalid_cpl_metadata_bad_tag) canonical(cpl->file().get()), 71 }, - { dcp::VerificationNote::Type::ERROR, dcp::VerificationNote::Code::MISMATCHED_CPL_HASHES, cpl->id(), canonical(cpl->file().get()) }, + dcp::VerificationNote( + dcp::VerificationNote::Type::ERROR, dcp::VerificationNote::Code::MISMATCHED_CPL_HASHES, cpl->id(), canonical(cpl->file().get()) + ).set_reference_hash(calc.old_hash()).set_calculated_hash(calc.new_hash()) }); } @@ -1012,6 +1163,7 @@ BOOST_AUTO_TEST_CASE (verify_invalid_cpl_metadata_missing_tag) check_verify_result ( { dir }, + {}, {{ dcp::VerificationNote::Type::ERROR, dcp::VerificationNote::Code::FAILED_READ, string("missing XML tag Width in MainPictureStoredArea") }} ); } @@ -1031,6 +1183,7 @@ BOOST_AUTO_TEST_CASE (verify_invalid_language1) check_verify_result ( { dir }, + {}, { { dcp::VerificationNote::Type::BV21_ERROR, dcp::VerificationNote::Code::INVALID_LANGUAGE, string("badlang") }, { dcp::VerificationNote::Type::BV21_ERROR, dcp::VerificationNote::Code::INVALID_LANGUAGE, string("wrong-andbad") }, @@ -1054,6 +1207,7 @@ BOOST_AUTO_TEST_CASE (verify_invalid_language2) check_verify_result ( {dir}, + {}, { { dcp::VerificationNote::Type::BV21_ERROR, dcp::VerificationNote::Code::INVALID_LANGUAGE, string("badlang") }, { dcp::VerificationNote::Type::BV21_ERROR, dcp::VerificationNote::Code::INVALID_LANGUAGE, string("wrong-andbad") }, @@ -1096,6 +1250,7 @@ BOOST_AUTO_TEST_CASE (verify_invalid_language3) check_verify_result ( { dir }, + {}, { { dcp::VerificationNote::Type::BV21_ERROR, dcp::VerificationNote::Code::INVALID_LANGUAGE, string("this-is-wrong") }, { dcp::VerificationNote::Type::BV21_ERROR, dcp::VerificationNote::Code::INVALID_LANGUAGE, string("andso-is-this") }, @@ -1156,7 +1311,7 @@ check_picture_size (int width, int height, int frame_rate, bool three_d) d->set_annotation_text("A Test DCP"); d->write_xml(); - return dcp::verify({dcp_path}, &stage, &progress, {}, xsd_test); + return dcp::verify({dcp_path}, {}, &stage, &progress, {}, xsd_test); } @@ -1277,7 +1432,8 @@ add_test_subtitle (shared_ptr asset, int start_frame, int en dcp::Colour(), dcp::Time(), dcp::Time(), - 0 + 0, + std::vector() ) ); } @@ -1300,6 +1456,7 @@ BOOST_AUTO_TEST_CASE (verify_invalid_closed_caption_xml_size_in_bytes) check_verify_result ( { dir }, + {}, { { dcp::VerificationNote::Type::BV21_ERROR, dcp::VerificationNote::Code::MISSING_SUBTITLE_START_TIME, canonical(dir / "subs.mxf") }, { @@ -1344,8 +1501,9 @@ verify_timed_text_asset_too_large (string name) check_verify_result ( { dir }, + {}, { - { dcp::VerificationNote::Type::BV21_ERROR, dcp::VerificationNote::Code::INVALID_TIMED_TEXT_SIZE_IN_BYTES, string("121695488"), canonical(dir / "subs.mxf") }, + { dcp::VerificationNote::Type::BV21_ERROR, dcp::VerificationNote::Code::INVALID_TIMED_TEXT_SIZE_IN_BYTES, string("121698284"), canonical(dir / "subs.mxf") }, { dcp::VerificationNote::Type::BV21_ERROR, dcp::VerificationNote::Code::INVALID_TIMED_TEXT_FONT_SIZE_IN_BYTES, string("121634816"), canonical(dir / "subs.mxf") }, { dcp::VerificationNote::Type::BV21_ERROR, dcp::VerificationNote::Code::MISSING_SUBTITLE_START_TIME, canonical(dir / "subs.mxf") }, { dcp::VerificationNote::Type::WARNING, dcp::VerificationNote::Code::INVALID_SUBTITLE_FIRST_TEXT_TIME }, @@ -1401,6 +1559,7 @@ BOOST_AUTO_TEST_CASE (verify_missing_subtitle_language) check_verify_result ( { dir }, + {}, { { dcp::VerificationNote::Type::BV21_ERROR, dcp::VerificationNote::Code::MISSING_SUBTITLE_LANGUAGE, canonical(dir / "subs.mxf") }, { dcp::VerificationNote::Type::WARNING, dcp::VerificationNote::Code::INVALID_SUBTITLE_FIRST_TEXT_TIME } @@ -1439,6 +1598,7 @@ BOOST_AUTO_TEST_CASE (verify_mismatched_subtitle_languages) check_verify_result ( { path }, + {}, { { dcp::VerificationNote::Type::BV21_ERROR, dcp::VerificationNote::Code::MISSING_SUBTITLE_START_TIME, canonical(path / "subs1.mxf") }, { dcp::VerificationNote::Type::BV21_ERROR, dcp::VerificationNote::Code::MISSING_SUBTITLE_START_TIME, canonical(path / "subs2.mxf") }, @@ -1478,6 +1638,7 @@ BOOST_AUTO_TEST_CASE (verify_multiple_closed_caption_languages_allowed) check_verify_result ( { path }, + {}, { { dcp::VerificationNote::Type::BV21_ERROR, dcp::VerificationNote::Code::MISSING_SUBTITLE_START_TIME, canonical(path / "subs1.mxf") }, { dcp::VerificationNote::Type::BV21_ERROR, dcp::VerificationNote::Code::MISSING_SUBTITLE_START_TIME, canonical(path / "subs2.mxf") } @@ -1525,6 +1686,7 @@ BOOST_AUTO_TEST_CASE (verify_missing_subtitle_start_time) check_verify_result ( { dir }, + {}, { { dcp::VerificationNote::Type::BV21_ERROR, dcp::VerificationNote::Code::MISSING_SUBTITLE_START_TIME, canonical(dir / "subs.mxf") }, { dcp::VerificationNote::Type::WARNING, dcp::VerificationNote::Code::INVALID_SUBTITLE_FIRST_TEXT_TIME } @@ -1573,6 +1735,7 @@ BOOST_AUTO_TEST_CASE (verify_invalid_subtitle_start_time) check_verify_result ( { dir }, + {}, { { dcp::VerificationNote::Type::BV21_ERROR, dcp::VerificationNote::Code::INVALID_SUBTITLE_START_TIME, canonical(dir / "subs.mxf") }, { dcp::VerificationNote::Type::WARNING, dcp::VerificationNote::Code::INVALID_SUBTITLE_FIRST_TEXT_TIME } @@ -1601,7 +1764,7 @@ public: template shared_ptr -dcp_with_text (path dir, vector subs) +dcp_with_text(path dir, vector subs, optional key = boost::none, optional key_id = boost::none) { prepare_directory (dir); auto asset = make_shared(); @@ -1610,6 +1773,10 @@ dcp_with_text (path dir, vector subs) add_test_subtitle (asset, i.in, i.out, i.v_position, i.v_align, i.text); } asset->set_language (dcp::LanguageTag("de-DE")); + if (key && key_id) { + asset->set_key(*key); + asset->set_key_id(*key_id); + } add_font(asset); asset->write (dir / "subs.mxf"); @@ -1662,6 +1829,7 @@ BOOST_AUTO_TEST_CASE (verify_invalid_subtitle_first_text_time) auto cpl = dcp_with_text (dir, {{ 4 * 24 - 1, 5 * 24 }}); check_verify_result ( { dir }, + {}, { { dcp::VerificationNote::Type::WARNING, dcp::VerificationNote::Code::INVALID_SUBTITLE_FIRST_TEXT_TIME }, { dcp::VerificationNote::Type::BV21_ERROR, dcp::VerificationNote::Code::MISSING_CPL_METADATA, cpl->id(), cpl->file().get() } @@ -1675,7 +1843,7 @@ BOOST_AUTO_TEST_CASE (verify_valid_subtitle_first_text_time) auto const dir = path("build/test/verify_valid_subtitle_first_text_time"); /* Just late enough */ auto cpl = dcp_with_text (dir, {{ 4 * 24, 5 * 24 }}); - check_verify_result ({dir}, {{ dcp::VerificationNote::Type::BV21_ERROR, dcp::VerificationNote::Code::MISSING_CPL_METADATA, cpl->id(), cpl->file().get() }}); + check_verify_result({dir}, {}, {{ dcp::VerificationNote::Type::BV21_ERROR, dcp::VerificationNote::Code::MISSING_CPL_METADATA, cpl->id(), cpl->file().get() }}); } @@ -1720,7 +1888,7 @@ BOOST_AUTO_TEST_CASE (verify_valid_subtitle_first_text_time_on_second_reel) dcp->set_annotation_text("hello"); dcp->write_xml(); - check_verify_result ({dir}, {{ dcp::VerificationNote::Type::BV21_ERROR, dcp::VerificationNote::Code::MISSING_CPL_METADATA, cpl->id(), cpl->file().get() }}); + check_verify_result({dir}, {}, {{ dcp::VerificationNote::Type::BV21_ERROR, dcp::VerificationNote::Code::MISSING_CPL_METADATA, cpl->id(), cpl->file().get() }}); } @@ -1735,6 +1903,7 @@ BOOST_AUTO_TEST_CASE (verify_invalid_subtitle_spacing) }); check_verify_result ( {dir}, + {}, { { dcp::VerificationNote::Type::WARNING, dcp::VerificationNote::Code::INVALID_SUBTITLE_SPACING }, { dcp::VerificationNote::Type::BV21_ERROR, dcp::VerificationNote::Code::MISSING_CPL_METADATA, cpl->id(), cpl->file().get() } @@ -1751,7 +1920,7 @@ BOOST_AUTO_TEST_CASE (verify_valid_subtitle_spacing) { 4 * 24, 5 * 24 }, { 5 * 24 + 16, 8 * 24 }, }); - check_verify_result ({dir}, {{ dcp::VerificationNote::Type::BV21_ERROR, dcp::VerificationNote::Code::MISSING_CPL_METADATA, cpl->id(), cpl->file().get() }}); + check_verify_result({dir}, {}, {{ dcp::VerificationNote::Type::BV21_ERROR, dcp::VerificationNote::Code::MISSING_CPL_METADATA, cpl->id(), cpl->file().get() }}); } @@ -1761,6 +1930,7 @@ BOOST_AUTO_TEST_CASE (verify_invalid_subtitle_duration) auto cpl = dcp_with_text (dir, {{ 4 * 24, 4 * 24 + 1 }}); check_verify_result ( {dir}, + {}, { { dcp::VerificationNote::Type::WARNING, dcp::VerificationNote::Code::INVALID_SUBTITLE_DURATION }, { dcp::VerificationNote::Type::BV21_ERROR, dcp::VerificationNote::Code::MISSING_CPL_METADATA, cpl->id(), cpl->file().get() } @@ -1772,7 +1942,7 @@ BOOST_AUTO_TEST_CASE (verify_valid_subtitle_duration) { auto const dir = path("build/test/verify_valid_subtitle_duration"); auto cpl = dcp_with_text (dir, {{ 4 * 24, 4 * 24 + 17 }}); - check_verify_result ({dir}, {{ dcp::VerificationNote::Type::BV21_ERROR, dcp::VerificationNote::Code::MISSING_CPL_METADATA, cpl->id(), cpl->file().get() }}); + check_verify_result({dir}, {}, {{ dcp::VerificationNote::Type::BV21_ERROR, dcp::VerificationNote::Code::MISSING_CPL_METADATA, cpl->id(), cpl->file().get() }}); } @@ -1791,6 +1961,7 @@ BOOST_AUTO_TEST_CASE (verify_subtitle_overlapping_reel_boundary) auto cpl = write_dcp_with_single_asset (dir, reel_asset); check_verify_result ( {dir}, + {}, { { dcp::VerificationNote::Type::BV21_ERROR, dcp::VerificationNote::Code::MISMATCHED_TIMED_TEXT_DURATION , "72 96", boost::filesystem::canonical(asset->file().get()) }, { dcp::VerificationNote::Type::WARNING, dcp::VerificationNote::Code::INVALID_SUBTITLE_FIRST_TEXT_TIME }, @@ -1814,6 +1985,7 @@ BOOST_AUTO_TEST_CASE (verify_invalid_subtitle_line_count1) }); check_verify_result ( {dir}, + {}, { { dcp::VerificationNote::Type::WARNING, dcp::VerificationNote::Code::INVALID_SUBTITLE_LINE_COUNT }, { dcp::VerificationNote::Type::BV21_ERROR, dcp::VerificationNote::Code::MISSING_CPL_METADATA, cpl->id(), cpl->file().get() } @@ -1831,7 +2003,7 @@ BOOST_AUTO_TEST_CASE (verify_valid_subtitle_line_count1) { 96, 200, 0.1, dcp::VAlign::CENTER, "have" }, { 96, 200, 0.2, dcp::VAlign::CENTER, "four" }, }); - check_verify_result ({dir}, {{ dcp::VerificationNote::Type::BV21_ERROR, dcp::VerificationNote::Code::MISSING_CPL_METADATA, cpl->id(), cpl->file().get() }}); + check_verify_result({dir}, {}, {{ dcp::VerificationNote::Type::BV21_ERROR, dcp::VerificationNote::Code::MISSING_CPL_METADATA, cpl->id(), cpl->file().get() }}); } @@ -1848,6 +2020,7 @@ BOOST_AUTO_TEST_CASE (verify_invalid_subtitle_line_count2) }); check_verify_result ( {dir}, + {}, { { dcp::VerificationNote::Type::WARNING, dcp::VerificationNote::Code::INVALID_SUBTITLE_LINE_COUNT }, { dcp::VerificationNote::Type::BV21_ERROR, dcp::VerificationNote::Code::MISSING_CPL_METADATA, cpl->id(), cpl->file().get() } @@ -1866,7 +2039,7 @@ BOOST_AUTO_TEST_CASE (verify_valid_subtitle_line_count2) { 150, 180, 0.2, dcp::VAlign::CENTER, "four" }, { 190, 250, 0.3, dcp::VAlign::CENTER, "lines" } }); - check_verify_result ({dir}, {{ dcp::VerificationNote::Type::BV21_ERROR, dcp::VerificationNote::Code::MISSING_CPL_METADATA, cpl->id(), cpl->file().get() }}); + check_verify_result({dir}, {}, {{ dcp::VerificationNote::Type::BV21_ERROR, dcp::VerificationNote::Code::MISSING_CPL_METADATA, cpl->id(), cpl->file().get() }}); } @@ -1880,6 +2053,7 @@ BOOST_AUTO_TEST_CASE (verify_invalid_subtitle_line_length1) }); check_verify_result ( {dir}, + {}, { { dcp::VerificationNote::Type::WARNING, dcp::VerificationNote::Code::NEARLY_INVALID_SUBTITLE_LINE_LENGTH }, { dcp::VerificationNote::Type::BV21_ERROR, dcp::VerificationNote::Code::MISSING_CPL_METADATA, cpl->id(), cpl->file().get() } @@ -1897,6 +2071,7 @@ BOOST_AUTO_TEST_CASE (verify_invalid_subtitle_line_length2) }); check_verify_result ( {dir}, + {}, { { dcp::VerificationNote::Type::WARNING, dcp::VerificationNote::Code::INVALID_SUBTITLE_LINE_LENGTH }, { dcp::VerificationNote::Type::BV21_ERROR, dcp::VerificationNote::Code::MISSING_CPL_METADATA, cpl->id(), cpl->file().get() } @@ -1917,6 +2092,7 @@ BOOST_AUTO_TEST_CASE (verify_valid_closed_caption_line_count1) }); check_verify_result ( {dir}, + {}, { { dcp::VerificationNote::Type::BV21_ERROR, dcp::VerificationNote::Code::INVALID_CLOSED_CAPTION_LINE_COUNT}, { dcp::VerificationNote::Type::BV21_ERROR, dcp::VerificationNote::Code::MISSING_CPL_METADATA, cpl->id(), cpl->file().get() } @@ -1934,7 +2110,7 @@ BOOST_AUTO_TEST_CASE (verify_valid_closed_caption_line_count2) { 96, 200, 0.1, dcp::VAlign::CENTER, "have" }, { 96, 200, 0.2, dcp::VAlign::CENTER, "four" }, }); - check_verify_result ({dir}, {{ dcp::VerificationNote::Type::BV21_ERROR, dcp::VerificationNote::Code::MISSING_CPL_METADATA, cpl->id(), cpl->file().get() }}); + check_verify_result({dir}, {}, {{ dcp::VerificationNote::Type::BV21_ERROR, dcp::VerificationNote::Code::MISSING_CPL_METADATA, cpl->id(), cpl->file().get() }}); } @@ -1951,6 +2127,7 @@ BOOST_AUTO_TEST_CASE (verify_invalid_closed_caption_line_count3) }); check_verify_result ( {dir}, + {}, { { dcp::VerificationNote::Type::BV21_ERROR, dcp::VerificationNote::Code::INVALID_CLOSED_CAPTION_LINE_COUNT}, { dcp::VerificationNote::Type::BV21_ERROR, dcp::VerificationNote::Code::MISSING_CPL_METADATA, cpl->id(), cpl->file().get() } @@ -1969,7 +2146,7 @@ BOOST_AUTO_TEST_CASE (verify_valid_closed_caption_line_count4) { 150, 180, 0.2, dcp::VAlign::CENTER, "four" }, { 190, 250, 0.3, dcp::VAlign::CENTER, "lines" } }); - check_verify_result ({dir}, {{ dcp::VerificationNote::Type::BV21_ERROR, dcp::VerificationNote::Code::MISSING_CPL_METADATA, cpl->id(), cpl->file().get() }}); + check_verify_result({dir}, {}, {{ dcp::VerificationNote::Type::BV21_ERROR, dcp::VerificationNote::Code::MISSING_CPL_METADATA, cpl->id(), cpl->file().get() }}); } @@ -1983,6 +2160,7 @@ BOOST_AUTO_TEST_CASE (verify_valid_closed_caption_line_length) }); check_verify_result ( {dir}, + {}, { { dcp::VerificationNote::Type::BV21_ERROR, dcp::VerificationNote::Code::MISSING_CPL_METADATA, cpl->id(), cpl->file().get() } }); @@ -1999,6 +2177,7 @@ BOOST_AUTO_TEST_CASE (verify_invalid_closed_caption_line_length) }); check_verify_result ( {dir}, + {}, { { dcp::VerificationNote::Type::BV21_ERROR, dcp::VerificationNote::Code::INVALID_CLOSED_CAPTION_LINE_LENGTH }, { dcp::VerificationNote::Type::BV21_ERROR, dcp::VerificationNote::Code::MISSING_CPL_METADATA, cpl->id(), cpl->file().get() } @@ -2018,6 +2197,7 @@ BOOST_AUTO_TEST_CASE (verify_mismatched_closed_caption_valign1) }); check_verify_result ( {dir}, + {}, { { dcp::VerificationNote::Type::BV21_ERROR, dcp::VerificationNote::Code::MISSING_CPL_METADATA, cpl->id(), cpl->file().get() } }); @@ -2036,6 +2216,7 @@ BOOST_AUTO_TEST_CASE (verify_mismatched_closed_caption_valign2) }); check_verify_result ( {dir}, + {}, { { dcp::VerificationNote::Type::ERROR, dcp::VerificationNote::Code::MISMATCHED_CLOSED_CAPTION_VALIGN }, { dcp::VerificationNote::Type::BV21_ERROR, dcp::VerificationNote::Code::MISSING_CPL_METADATA, cpl->id(), cpl->file().get() } @@ -2055,6 +2236,7 @@ BOOST_AUTO_TEST_CASE (verify_incorrect_closed_caption_ordering1) }); check_verify_result ( {dir}, + {}, { { dcp::VerificationNote::Type::BV21_ERROR, dcp::VerificationNote::Code::MISSING_CPL_METADATA, cpl->id(), cpl->file().get() } }); @@ -2073,6 +2255,7 @@ BOOST_AUTO_TEST_CASE (verify_incorrect_closed_caption_ordering2) }); check_verify_result ( {dir}, + {}, { { dcp::VerificationNote::Type::BV21_ERROR, dcp::VerificationNote::Code::MISSING_CPL_METADATA, cpl->id(), cpl->file().get() } }); @@ -2085,6 +2268,7 @@ BOOST_AUTO_TEST_CASE (verify_incorrect_closed_caption_ordering3) auto cpl = dcp_with_text_from_file (dir, "test/data/verify_incorrect_closed_caption_ordering3.xml"); check_verify_result ( {dir}, + {}, { { dcp::VerificationNote::Type::ERROR, dcp::VerificationNote::Code::INCORRECT_CLOSED_CAPTION_ORDERING }, { dcp::VerificationNote::Type::BV21_ERROR, dcp::VerificationNote::Code::MISSING_CPL_METADATA, cpl->id(), cpl->file().get() } @@ -2098,6 +2282,7 @@ BOOST_AUTO_TEST_CASE (verify_incorrect_closed_caption_ordering4) auto cpl = dcp_with_text_from_file (dir, "test/data/verify_incorrect_closed_caption_ordering4.xml"); check_verify_result ( {dir}, + {}, { { dcp::VerificationNote::Type::BV21_ERROR, dcp::VerificationNote::Code::MISSING_CPL_METADATA, cpl->id(), cpl->file().get() } }); @@ -2127,6 +2312,7 @@ BOOST_AUTO_TEST_CASE (verify_invalid_sound_frame_rate) check_verify_result ( {dir}, + {}, { { dcp::VerificationNote::Type::BV21_ERROR, dcp::VerificationNote::Code::INVALID_SOUND_FRAME_RATE, string("96000"), canonical(dir / "audiofoo.mxf") }, { dcp::VerificationNote::Type::BV21_ERROR, dcp::VerificationNote::Code::MISSING_CPL_METADATA, cpl->id(), cpl->file().get() }, @@ -2144,6 +2330,8 @@ BOOST_AUTO_TEST_CASE (verify_missing_cpl_annotation_text) auto const cpl = dcp->cpls()[0]; + HashCalculator calc(cpl->file().get()); + { BOOST_REQUIRE (cpl->file()); Editor e(cpl->file().get()); @@ -2152,9 +2340,12 @@ BOOST_AUTO_TEST_CASE (verify_missing_cpl_annotation_text) check_verify_result ( {dir}, + {}, { { dcp::VerificationNote::Type::BV21_ERROR, dcp::VerificationNote::Code::MISSING_CPL_ANNOTATION_TEXT, cpl->id(), canonical(cpl->file().get()) }, - { dcp::VerificationNote::Type::ERROR, dcp::VerificationNote::Code::MISMATCHED_CPL_HASHES, cpl->id(), canonical(cpl->file().get()) } + dcp::VerificationNote( + dcp::VerificationNote::Type::ERROR, dcp::VerificationNote::Code::MISMATCHED_CPL_HASHES, cpl->id(), canonical(cpl->file().get()) + ).set_reference_hash(calc.old_hash()).set_calculated_hash(calc.new_hash()) }); } @@ -2168,6 +2359,8 @@ BOOST_AUTO_TEST_CASE (verify_mismatched_cpl_annotation_text) BOOST_REQUIRE_EQUAL (dcp->cpls().size(), 1U); auto const cpl = dcp->cpls()[0]; + HashCalculator calc(cpl->file().get()); + { BOOST_REQUIRE (cpl->file()); Editor e(cpl->file().get()); @@ -2176,9 +2369,12 @@ BOOST_AUTO_TEST_CASE (verify_mismatched_cpl_annotation_text) check_verify_result ( {dir}, + {}, { { dcp::VerificationNote::Type::WARNING, dcp::VerificationNote::Code::MISMATCHED_CPL_ANNOTATION_TEXT, cpl->id(), canonical(cpl->file().get()) }, - { dcp::VerificationNote::Type::ERROR, dcp::VerificationNote::Code::MISMATCHED_CPL_HASHES, cpl->id(), canonical(cpl->file().get()) } + dcp::VerificationNote( + dcp::VerificationNote::Type::ERROR, dcp::VerificationNote::Code::MISMATCHED_CPL_HASHES, cpl->id(), canonical(cpl->file().get()) + ).set_reference_hash(calc.old_hash()).set_calculated_hash(calc.new_hash()) }); } @@ -2207,6 +2403,7 @@ BOOST_AUTO_TEST_CASE (verify_mismatched_asset_duration) check_verify_result ( {dir}, + {}, { { dcp::VerificationNote::Type::BV21_ERROR, dcp::VerificationNote::Code::MISMATCHED_ASSET_DURATION }, { dcp::VerificationNote::Type::BV21_ERROR, dcp::VerificationNote::Code::MISSING_CPL_METADATA, cpl->id(), canonical(cpl->file().get()) } @@ -2234,8 +2431,8 @@ verify_subtitles_must_be_in_all_reels_check (path dir, bool add_to_reel1, bool a auto reel_subs = make_shared(subs, dcp::Fraction(24, 1), reel_length, 0); auto reel1 = make_shared( - make_shared(simple_picture(dir, "", reel_length), 0), - make_shared(simple_sound(dir, "", dcp::MXFMetadata(), "en-US", reel_length), 0) + make_shared(simple_picture(dir, "1", reel_length), 0), + make_shared(simple_sound(dir, "1", dcp::MXFMetadata(), "en-US", reel_length), 0) ); if (add_to_reel1) { @@ -2249,8 +2446,8 @@ verify_subtitles_must_be_in_all_reels_check (path dir, bool add_to_reel1, bool a cpl->add (reel1); auto reel2 = make_shared( - make_shared(simple_picture(dir, "", reel_length), 0), - make_shared(simple_sound(dir, "", dcp::MXFMetadata(), "en-US", reel_length), 0) + make_shared(simple_picture(dir, "2", reel_length), 0), + make_shared(simple_sound(dir, "2", dcp::MXFMetadata(), "en-US", reel_length), 0) ); if (add_to_reel2) { @@ -2278,6 +2475,7 @@ BOOST_AUTO_TEST_CASE (verify_missing_main_subtitle_from_some_reels) auto cpl = verify_subtitles_must_be_in_all_reels_check (dir, true, false); check_verify_result ( { dir }, + {}, { { dcp::VerificationNote::Type::BV21_ERROR, dcp::VerificationNote::Code::MISSING_MAIN_SUBTITLE_FROM_SOME_REELS }, { dcp::VerificationNote::Type::BV21_ERROR, dcp::VerificationNote::Code::MISSING_CPL_METADATA, cpl->id(), cpl->file().get() }, @@ -2288,13 +2486,13 @@ BOOST_AUTO_TEST_CASE (verify_missing_main_subtitle_from_some_reels) { path dir ("build/test/verify_subtitles_must_be_in_all_reels2"); auto cpl = verify_subtitles_must_be_in_all_reels_check (dir, true, true); - check_verify_result ({dir}, {{ dcp::VerificationNote::Type::BV21_ERROR, dcp::VerificationNote::Code::MISSING_CPL_METADATA, cpl->id(), cpl->file().get() }}); + check_verify_result({dir}, {}, {{ dcp::VerificationNote::Type::BV21_ERROR, dcp::VerificationNote::Code::MISSING_CPL_METADATA, cpl->id(), cpl->file().get() }}); } { path dir ("build/test/verify_subtitles_must_be_in_all_reels1"); auto cpl = verify_subtitles_must_be_in_all_reels_check (dir, false, false); - check_verify_result ({dir}, {{ dcp::VerificationNote::Type::BV21_ERROR, dcp::VerificationNote::Code::MISSING_CPL_METADATA, cpl->id(), cpl->file().get() }}); + check_verify_result({dir}, {}, {{ dcp::VerificationNote::Type::BV21_ERROR, dcp::VerificationNote::Code::MISSING_CPL_METADATA, cpl->id(), cpl->file().get() }}); } } @@ -2317,8 +2515,8 @@ verify_closed_captions_must_be_in_all_reels_check (path dir, int caps_in_reel1, subs->write (dir / "subs.mxf"); auto reel1 = make_shared( - make_shared(simple_picture(dir, "", reel_length), 0), - make_shared(simple_sound(dir, "", dcp::MXFMetadata(), "en-US", reel_length), 0) + make_shared(simple_picture(dir, "1", reel_length), 0), + make_shared(simple_sound(dir, "1", dcp::MXFMetadata(), "en-US", reel_length), 0) ); for (int i = 0; i < caps_in_reel1; ++i) { @@ -2332,8 +2530,8 @@ verify_closed_captions_must_be_in_all_reels_check (path dir, int caps_in_reel1, cpl->add (reel1); auto reel2 = make_shared( - make_shared(simple_picture(dir, "", reel_length), 0), - make_shared(simple_sound(dir, "", dcp::MXFMetadata(), "en-US", reel_length), 0) + make_shared(simple_picture(dir, "2", reel_length), 0), + make_shared(simple_sound(dir, "2", dcp::MXFMetadata(), "en-US", reel_length), 0) ); for (int i = 0; i < caps_in_reel2; ++i) { @@ -2361,6 +2559,7 @@ BOOST_AUTO_TEST_CASE (verify_mismatched_closed_caption_asset_counts) auto cpl = verify_closed_captions_must_be_in_all_reels_check (dir, 3, 4); check_verify_result ( {dir}, + {}, { { dcp::VerificationNote::Type::BV21_ERROR, dcp::VerificationNote::Code::MISMATCHED_CLOSED_CAPTION_ASSET_COUNTS }, { dcp::VerificationNote::Type::BV21_ERROR, dcp::VerificationNote::Code::MISSING_CPL_METADATA, cpl->id(), cpl->file().get() } @@ -2370,13 +2569,13 @@ BOOST_AUTO_TEST_CASE (verify_mismatched_closed_caption_asset_counts) { path dir ("build/test/verify_closed_captions_must_be_in_all_reels2"); auto cpl = verify_closed_captions_must_be_in_all_reels_check (dir, 4, 4); - check_verify_result ({dir}, {{ dcp::VerificationNote::Type::BV21_ERROR, dcp::VerificationNote::Code::MISSING_CPL_METADATA, cpl->id(), cpl->file().get() }}); + check_verify_result({dir}, {}, {{ dcp::VerificationNote::Type::BV21_ERROR, dcp::VerificationNote::Code::MISSING_CPL_METADATA, cpl->id(), cpl->file().get() }}); } { path dir ("build/test/verify_closed_captions_must_be_in_all_reels3"); auto cpl = verify_closed_captions_must_be_in_all_reels_check (dir, 0, 0); - check_verify_result ({dir}, {{ dcp::VerificationNote::Type::BV21_ERROR, dcp::VerificationNote::Code::MISSING_CPL_METADATA, cpl->id(), cpl->file().get() }}); + check_verify_result({dir}, {}, {{ dcp::VerificationNote::Type::BV21_ERROR, dcp::VerificationNote::Code::MISSING_CPL_METADATA, cpl->id(), cpl->file().get() }}); } } @@ -2417,6 +2616,7 @@ verify_text_entry_point_check (path dir, dcp::VerificationNote::Code code, boost check_verify_result ( {dir}, + {}, { { dcp::VerificationNote::Type::BV21_ERROR, code, subs->id() }, { dcp::VerificationNote::Type::BV21_ERROR, dcp::VerificationNote::Code::MISSING_CPL_METADATA, cpl->id(), cpl->file().get() }, @@ -2474,6 +2674,8 @@ BOOST_AUTO_TEST_CASE (verify_missing_hash) BOOST_REQUIRE (cpl->reels()[0]->main_picture()); auto asset_id = cpl->reels()[0]->main_picture()->id(); + HashCalculator calc(cpl->file().get()); + { BOOST_REQUIRE (cpl->file()); Editor e(cpl->file().get()); @@ -2482,8 +2684,11 @@ BOOST_AUTO_TEST_CASE (verify_missing_hash) check_verify_result ( {dir}, + {}, { - { dcp::VerificationNote::Type::ERROR, dcp::VerificationNote::Code::MISMATCHED_CPL_HASHES, cpl->id(), cpl->file().get() }, + dcp::VerificationNote( + dcp::VerificationNote::Type::ERROR, dcp::VerificationNote::Code::MISMATCHED_CPL_HASHES, cpl->id(), cpl->file().get() + ).set_reference_hash(calc.old_hash()).set_calculated_hash(calc.new_hash()), { dcp::VerificationNote::Type::BV21_ERROR, dcp::VerificationNote::Code::MISSING_HASH, asset_id } }); } @@ -2506,7 +2711,7 @@ verify_markers_test ( dcp->cpls()[0]->reels()[0]->add(markers_asset); dcp->write_xml(); - check_verify_result ({dir}, test_notes); + check_verify_result({dir}, {}, test_notes); } @@ -2602,7 +2807,7 @@ BOOST_AUTO_TEST_CASE (verify_missing_cpl_metadata_version_number) cpl->unset_version_number(); dcp->write_xml(); - check_verify_result ({dir}, {{ dcp::VerificationNote::Type::BV21_ERROR, dcp::VerificationNote::Code::MISSING_CPL_METADATA_VERSION_NUMBER, cpl->id(), cpl->file().get() }}); + check_verify_result({dir}, {}, {{ dcp::VerificationNote::Type::BV21_ERROR, dcp::VerificationNote::Code::MISSING_CPL_METADATA_VERSION_NUMBER, cpl->id(), cpl->file().get() }}); } @@ -2615,6 +2820,8 @@ BOOST_AUTO_TEST_CASE (verify_missing_extension_metadata1) BOOST_REQUIRE_EQUAL (dcp->cpls().size(), 1U); auto cpl = dcp->cpls()[0]; + HashCalculator calc(cpl->file().get()); + { Editor e (cpl->file().get()); e.delete_lines ("", ""); @@ -2622,8 +2829,11 @@ BOOST_AUTO_TEST_CASE (verify_missing_extension_metadata1) check_verify_result ( {dir}, + {}, { - { dcp::VerificationNote::Type::ERROR, dcp::VerificationNote::Code::MISMATCHED_CPL_HASHES, cpl->id(), cpl->file().get() }, + dcp::VerificationNote( + dcp::VerificationNote::Type::ERROR, dcp::VerificationNote::Code::MISMATCHED_CPL_HASHES, cpl->id(), cpl->file().get() + ).set_reference_hash(calc.old_hash()).set_calculated_hash(calc.new_hash()), { dcp::VerificationNote::Type::BV21_ERROR, dcp::VerificationNote::Code::MISSING_EXTENSION_METADATA, cpl->id(), cpl->file().get() } }); } @@ -2637,6 +2847,8 @@ BOOST_AUTO_TEST_CASE (verify_missing_extension_metadata2) auto cpl = dcp->cpls()[0]; + HashCalculator calc(cpl->file().get()); + { Editor e (cpl->file().get()); e.delete_lines ("", ""); @@ -2644,8 +2856,11 @@ BOOST_AUTO_TEST_CASE (verify_missing_extension_metadata2) check_verify_result ( {dir}, + {}, { - { dcp::VerificationNote::Type::ERROR, dcp::VerificationNote::Code::MISMATCHED_CPL_HASHES, cpl->id(), cpl->file().get() }, + dcp::VerificationNote( + dcp::VerificationNote::Type::ERROR, dcp::VerificationNote::Code::MISMATCHED_CPL_HASHES, cpl->id(), cpl->file().get() + ).set_reference_hash(calc.old_hash()).set_calculated_hash(calc.new_hash()), { dcp::VerificationNote::Type::BV21_ERROR, dcp::VerificationNote::Code::MISSING_EXTENSION_METADATA, cpl->id(), cpl->file().get() } }); } @@ -2659,6 +2874,8 @@ BOOST_AUTO_TEST_CASE (verify_invalid_xml_cpl_extension_metadata3) auto const cpl = dcp->cpls()[0]; + HashCalculator calc(cpl->file().get()); + { Editor e (cpl->file().get()); e.replace ("A", "A"); @@ -2667,10 +2884,13 @@ BOOST_AUTO_TEST_CASE (verify_invalid_xml_cpl_extension_metadata3) check_verify_result ( {dir}, + {}, { { dcp::VerificationNote::Type::ERROR, dcp::VerificationNote::Code::INVALID_XML, string("no declaration found for element 'meta:NameX'"), cpl->file().get(), 70 }, { dcp::VerificationNote::Type::ERROR, dcp::VerificationNote::Code::INVALID_XML, string("element 'meta:NameX' is not allowed for content model '(Name,PropertyList?,)'"), cpl->file().get(), 77 }, - { dcp::VerificationNote::Type::ERROR, dcp::VerificationNote::Code::MISMATCHED_CPL_HASHES, cpl->id(), cpl->file().get() }, + dcp::VerificationNote( + dcp::VerificationNote::Type::ERROR, dcp::VerificationNote::Code::MISMATCHED_CPL_HASHES, cpl->id(), cpl->file().get() + ).set_reference_hash(calc.old_hash()).set_calculated_hash(calc.new_hash()), }); } @@ -2683,6 +2903,8 @@ BOOST_AUTO_TEST_CASE (verify_invalid_extension_metadata1) auto cpl = dcp->cpls()[0]; + HashCalculator calc(cpl->file().get()); + { Editor e (cpl->file().get()); e.replace ("Application", "Fred"); @@ -2690,8 +2912,11 @@ BOOST_AUTO_TEST_CASE (verify_invalid_extension_metadata1) check_verify_result ( {dir}, + {}, { - { dcp::VerificationNote::Type::ERROR, dcp::VerificationNote::Code::MISMATCHED_CPL_HASHES, cpl->id(), cpl->file().get() }, + dcp::VerificationNote( + dcp::VerificationNote::Type::ERROR, dcp::VerificationNote::Code::MISMATCHED_CPL_HASHES, cpl->id(), cpl->file().get() + ).set_reference_hash(calc.old_hash()).set_calculated_hash(calc.new_hash()), { dcp::VerificationNote::Type::BV21_ERROR, dcp::VerificationNote::Code::INVALID_EXTENSION_METADATA, string(" should be 'Application'"), cpl->file().get() }, }); } @@ -2705,6 +2930,8 @@ BOOST_AUTO_TEST_CASE (verify_invalid_extension_metadata2) auto cpl = dcp->cpls()[0]; + HashCalculator calc(cpl->file().get()); + { Editor e (cpl->file().get()); e.replace ("DCP Constraints Profile", "Fred"); @@ -2712,8 +2939,11 @@ BOOST_AUTO_TEST_CASE (verify_invalid_extension_metadata2) check_verify_result ( {dir}, + {}, { - { dcp::VerificationNote::Type::ERROR, dcp::VerificationNote::Code::MISMATCHED_CPL_HASHES, cpl->id(), cpl->file().get() }, + dcp::VerificationNote( + dcp::VerificationNote::Type::ERROR, dcp::VerificationNote::Code::MISMATCHED_CPL_HASHES, cpl->id(), cpl->file().get() + ).set_reference_hash(calc.old_hash()).set_calculated_hash(calc.new_hash()), { dcp::VerificationNote::Type::BV21_ERROR, dcp::VerificationNote::Code::INVALID_EXTENSION_METADATA, string(" property should be 'DCP Constraints Profile'"), cpl->file().get() }, }); } @@ -2727,6 +2957,8 @@ BOOST_AUTO_TEST_CASE (verify_invalid_xml_cpl_extension_metadata6) auto const cpl = dcp->cpls()[0]; + HashCalculator calc(cpl->file().get()); + { Editor e (cpl->file().get()); e.replace ("", ""); @@ -2735,10 +2967,13 @@ BOOST_AUTO_TEST_CASE (verify_invalid_xml_cpl_extension_metadata6) check_verify_result ( {dir}, + {}, { { dcp::VerificationNote::Type::ERROR, dcp::VerificationNote::Code::INVALID_XML, string("no declaration found for element 'meta:ValueX'"), cpl->file().get(), 74 }, { dcp::VerificationNote::Type::ERROR, dcp::VerificationNote::Code::INVALID_XML, string("element 'meta:ValueX' is not allowed for content model '(Name,Value)'"), cpl->file().get(), 75 }, - { dcp::VerificationNote::Type::ERROR, dcp::VerificationNote::Code::MISMATCHED_CPL_HASHES, cpl->id(), cpl->file().get() }, + dcp::VerificationNote( + dcp::VerificationNote::Type::ERROR, dcp::VerificationNote::Code::MISMATCHED_CPL_HASHES, cpl->id(), cpl->file().get() + ).set_reference_hash(calc.old_hash()).set_calculated_hash(calc.new_hash()), }); } @@ -2751,6 +2986,8 @@ BOOST_AUTO_TEST_CASE (verify_invalid_xml_cpl_extension_metadata7) auto const cpl = dcp->cpls()[0]; + HashCalculator calc(cpl->file().get()); + { Editor e (cpl->file().get()); e.replace ("SMPTE-RDD-52:2020-Bv2.1", "Fred"); @@ -2758,8 +2995,11 @@ BOOST_AUTO_TEST_CASE (verify_invalid_xml_cpl_extension_metadata7) check_verify_result ( {dir}, + {}, { - { dcp::VerificationNote::Type::ERROR, dcp::VerificationNote::Code::MISMATCHED_CPL_HASHES, cpl->id(), cpl->file().get() }, + dcp::VerificationNote( + dcp::VerificationNote::Type::ERROR, dcp::VerificationNote::Code::MISMATCHED_CPL_HASHES, cpl->id(), cpl->file().get() + ).set_reference_hash(calc.old_hash()).set_calculated_hash(calc.new_hash()), { dcp::VerificationNote::Type::BV21_ERROR, dcp::VerificationNote::Code::INVALID_EXTENSION_METADATA, string(" property should be 'SMPTE-RDD-52:2020-Bv2.1'"), cpl->file().get() }, }); } @@ -2773,6 +3013,8 @@ BOOST_AUTO_TEST_CASE (verify_invalid_xml_cpl_extension_metadata8) auto const cpl = dcp->cpls()[0]; + HashCalculator calc(cpl->file().get()); + { Editor e (cpl->file().get()); e.replace ("", ""); @@ -2781,10 +3023,13 @@ BOOST_AUTO_TEST_CASE (verify_invalid_xml_cpl_extension_metadata8) check_verify_result ( {dir}, + {}, { { dcp::VerificationNote::Type::ERROR, dcp::VerificationNote::Code::INVALID_XML, string("no declaration found for element 'meta:PropertyX'"), cpl->file().get(), 72 }, { dcp::VerificationNote::Type::ERROR, dcp::VerificationNote::Code::INVALID_XML, string("element 'meta:PropertyX' is not allowed for content model '(Property+)'"), cpl->file().get(), 76 }, - { dcp::VerificationNote::Type::ERROR, dcp::VerificationNote::Code::MISMATCHED_CPL_HASHES, cpl->id(), cpl->file().get() }, + dcp::VerificationNote( + dcp::VerificationNote::Type::ERROR, dcp::VerificationNote::Code::MISMATCHED_CPL_HASHES, cpl->id(), cpl->file().get() + ).set_reference_hash(calc.old_hash()).set_calculated_hash(calc.new_hash()), }); } @@ -2797,6 +3042,8 @@ BOOST_AUTO_TEST_CASE (verify_invalid_xml_cpl_extension_metadata9) auto const cpl = dcp->cpls()[0]; + HashCalculator calc(cpl->file().get()); + { Editor e (cpl->file().get()); e.replace ("", ""); @@ -2805,10 +3052,13 @@ BOOST_AUTO_TEST_CASE (verify_invalid_xml_cpl_extension_metadata9) check_verify_result ( {dir}, + {}, { { dcp::VerificationNote::Type::ERROR, dcp::VerificationNote::Code::INVALID_XML, string("no declaration found for element 'meta:PropertyListX'"), cpl->file().get(), 71 }, { dcp::VerificationNote::Type::ERROR, dcp::VerificationNote::Code::INVALID_XML, string("element 'meta:PropertyListX' is not allowed for content model '(Name,PropertyList?,)'"), cpl->file().get(), 77 }, - { dcp::VerificationNote::Type::ERROR, dcp::VerificationNote::Code::MISMATCHED_CPL_HASHES, cpl->id(), cpl->file().get() }, + dcp::VerificationNote( + dcp::VerificationNote::Type::ERROR, dcp::VerificationNote::Code::MISMATCHED_CPL_HASHES, cpl->id(), cpl->file().get() + ).set_reference_hash(calc.old_hash()).set_calculated_hash(calc.new_hash()), }); } @@ -2822,8 +3072,10 @@ BOOST_AUTO_TEST_CASE (verify_unsigned_cpl_with_encrypted_content) copy_file (i.path(), dir / i.path().filename()); } - path const pkl = dir / ( "pkl_" + encryption_test_pkl_id + ".xml" ); - path const cpl = dir / ( "cpl_" + encryption_test_cpl_id + ".xml"); + path const pkl = dir / ( "pkl_" + encryption_test_pkl_id() + ".xml" ); + path const cpl = dir / ( "cpl_" + encryption_test_cpl_id() + ".xml"); + + HashCalculator calc(cpl); { Editor e (cpl); @@ -2832,15 +3084,18 @@ BOOST_AUTO_TEST_CASE (verify_unsigned_cpl_with_encrypted_content) check_verify_result ( {dir}, + {}, { - { dcp::VerificationNote::Type::ERROR, dcp::VerificationNote::Code::MISMATCHED_CPL_HASHES, encryption_test_cpl_id, canonical(cpl) }, - { dcp::VerificationNote::Type::BV21_ERROR, dcp::VerificationNote::Code::MISMATCHED_PKL_ANNOTATION_TEXT_WITH_CPL, encryption_test_pkl_id, canonical(pkl), }, + dcp::VerificationNote( + dcp::VerificationNote::Type::ERROR, dcp::VerificationNote::Code::MISMATCHED_CPL_HASHES, encryption_test_cpl_id(), canonical(cpl) + ).set_reference_hash(calc.old_hash()).set_calculated_hash(calc.new_hash()), + { dcp::VerificationNote::Type::BV21_ERROR, dcp::VerificationNote::Code::MISMATCHED_PKL_ANNOTATION_TEXT_WITH_CPL, encryption_test_pkl_id(), canonical(pkl), }, { dcp::VerificationNote::Type::BV21_ERROR, dcp::VerificationNote::Code::MISSING_FFEC_IN_FEATURE }, { dcp::VerificationNote::Type::BV21_ERROR, dcp::VerificationNote::Code::MISSING_FFMC_IN_FEATURE }, { dcp::VerificationNote::Type::WARNING, dcp::VerificationNote::Code::MISSING_FFOC }, { dcp::VerificationNote::Type::WARNING, dcp::VerificationNote::Code::MISSING_LFOC }, - { dcp::VerificationNote::Type::BV21_ERROR, dcp::VerificationNote::Code::MISSING_CPL_METADATA, encryption_test_cpl_id, canonical(cpl) }, - { dcp::VerificationNote::Type::BV21_ERROR, dcp::VerificationNote::Code::UNSIGNED_CPL_WITH_ENCRYPTED_CONTENT, encryption_test_cpl_id, canonical(cpl) } + { dcp::VerificationNote::Type::BV21_ERROR, dcp::VerificationNote::Code::MISSING_CPL_METADATA, encryption_test_cpl_id(), canonical(cpl) }, + { dcp::VerificationNote::Type::BV21_ERROR, dcp::VerificationNote::Code::UNSIGNED_CPL_WITH_ENCRYPTED_CONTENT, encryption_test_cpl_id(), canonical(cpl) } }); } @@ -2853,8 +3108,8 @@ BOOST_AUTO_TEST_CASE (verify_unsigned_pkl_with_encrypted_content) copy_file (i.path(), dir / i.path().filename()); } - path const cpl = dir / ("cpl_" + encryption_test_cpl_id + ".xml"); - path const pkl = dir / ("pkl_" + encryption_test_pkl_id + ".xml"); + path const cpl = dir / ("cpl_" + encryption_test_cpl_id() + ".xml"); + path const pkl = dir / ("pkl_" + encryption_test_pkl_id() + ".xml"); { Editor e (pkl); e.delete_lines (""); @@ -2862,14 +3117,15 @@ BOOST_AUTO_TEST_CASE (verify_unsigned_pkl_with_encrypted_content) check_verify_result ( {dir}, + {}, { - { dcp::VerificationNote::Type::BV21_ERROR, dcp::VerificationNote::Code::MISMATCHED_PKL_ANNOTATION_TEXT_WITH_CPL, encryption_test_pkl_id, canonical(pkl) }, + { dcp::VerificationNote::Type::BV21_ERROR, dcp::VerificationNote::Code::MISMATCHED_PKL_ANNOTATION_TEXT_WITH_CPL, encryption_test_pkl_id(), canonical(pkl) }, { dcp::VerificationNote::Type::BV21_ERROR, dcp::VerificationNote::Code::MISSING_FFEC_IN_FEATURE }, { dcp::VerificationNote::Type::BV21_ERROR, dcp::VerificationNote::Code::MISSING_FFMC_IN_FEATURE }, { dcp::VerificationNote::Type::WARNING, dcp::VerificationNote::Code::MISSING_FFOC }, { dcp::VerificationNote::Type::WARNING, dcp::VerificationNote::Code::MISSING_LFOC }, - { dcp::VerificationNote::Type::BV21_ERROR, dcp::VerificationNote::Code::MISSING_CPL_METADATA, encryption_test_cpl_id, canonical(cpl) }, - { dcp::VerificationNote::Type::BV21_ERROR, dcp::VerificationNote::Code::UNSIGNED_PKL_WITH_ENCRYPTED_CONTENT, encryption_test_pkl_id, canonical(pkl) }, + { dcp::VerificationNote::Type::BV21_ERROR, dcp::VerificationNote::Code::MISSING_CPL_METADATA, encryption_test_cpl_id(), canonical(cpl) }, + { dcp::VerificationNote::Type::BV21_ERROR, dcp::VerificationNote::Code::UNSIGNED_PKL_WITH_ENCRYPTED_CONTENT, encryption_test_pkl_id(), canonical(pkl) }, }); } @@ -2883,11 +3139,11 @@ BOOST_AUTO_TEST_CASE (verify_unsigned_pkl_with_unencrypted_content) } { - Editor e (dir / dcp_test1_pkl); + Editor e (dir / dcp_test1_pkl()); e.delete_lines (""); } - check_verify_result ({dir}, {}); + check_verify_result({dir}, {}, {}); } @@ -2952,6 +3208,7 @@ BOOST_AUTO_TEST_CASE (verify_partially_encrypted) check_verify_result ( {dir}, + {}, { {dcp::VerificationNote::Type::BV21_ERROR, dcp::VerificationNote::Code::PARTIALLY_ENCRYPTED}, }); @@ -2964,7 +3221,7 @@ BOOST_AUTO_TEST_CASE (verify_jpeg2000_codestream_2k) dcp::MonoPictureAsset picture (find_file(private_test / "data" / "JourneyToJah_TLR-1_F_EN-DE-FR_CH_51_2K_LOK_20140225_DGL_SMPTE_OV", "j2c.mxf")); auto reader = picture.start_read (); auto frame = reader->get_frame (0); - verify_j2k(frame, 0, 24, notes); + verify_j2k(frame, 0, 0, 24, notes); BOOST_REQUIRE_EQUAL (notes.size(), 0U); } @@ -2975,7 +3232,7 @@ BOOST_AUTO_TEST_CASE (verify_jpeg2000_codestream_4k) dcp::MonoPictureAsset picture (find_file(private_test / "data" / "sul", "TLR")); auto reader = picture.start_read (); auto frame = reader->get_frame (0); - verify_j2k(frame, 0, 24, notes); + verify_j2k(frame, 0, 0, 24, notes); BOOST_REQUIRE_EQUAL (notes.size(), 0U); } @@ -2990,7 +3247,7 @@ BOOST_AUTO_TEST_CASE (verify_jpeg2000_codestream_libdcp) dcp::MonoPictureAsset picture (find_file(dir, "video")); auto reader = picture.start_read (); auto frame = reader->get_frame (0); - verify_j2k(frame, 0, 24, notes); + verify_j2k(frame, 0, 0, 24, notes); BOOST_REQUIRE_EQUAL (notes.size(), 0U); } @@ -3051,6 +3308,7 @@ BOOST_AUTO_TEST_CASE (verify_mismatched_subtitle_resource_id) check_verify_result ( { dir }, + {}, { { dcp::VerificationNote::Type::BV21_ERROR, dcp::VerificationNote::Code::MISMATCHED_TIMED_TEXT_DURATION , "240 0", boost::filesystem::canonical(subs_mxf) }, { dcp::VerificationNote::Type::BV21_ERROR, dcp::VerificationNote::Code::MISMATCHED_TIMED_TEXT_RESOURCE_ID }, @@ -3116,6 +3374,7 @@ BOOST_AUTO_TEST_CASE (verify_incorrect_timed_text_id) check_verify_result ( { dir }, + {}, { { dcp::VerificationNote::Type::BV21_ERROR, dcp::VerificationNote::Code::MISMATCHED_TIMED_TEXT_DURATION , "240 0", boost::filesystem::canonical(subs_mxf) }, { dcp::VerificationNote::Type::BV21_ERROR, dcp::VerificationNote::Code::INCORRECT_TIMED_TEXT_ASSET_ID }, @@ -3131,6 +3390,7 @@ BOOST_AUTO_TEST_CASE (verify_threed_marked_as_twod) { check_verify_result ( { private_test / "data" / "xm" }, + {}, { { dcp::VerificationNote::Type::WARNING, @@ -3152,6 +3412,8 @@ BOOST_AUTO_TEST_CASE (verify_unexpected_things_in_main_markers) auto dcp = make_simple (dir, 1, 24); dcp->write_xml(); + HashCalculator calc(find_cpl(dir)); + { Editor e (find_cpl(dir)); e.insert( @@ -3164,8 +3426,11 @@ BOOST_AUTO_TEST_CASE (verify_unexpected_things_in_main_markers) check_verify_result ( { dir }, + {}, { - { dcp::VerificationNote::Type::ERROR, dcp::VerificationNote::Code::MISMATCHED_CPL_HASHES, cpl.id(), canonical(find_cpl(dir)) }, + dcp::VerificationNote( + dcp::VerificationNote::Type::ERROR, dcp::VerificationNote::Code::MISMATCHED_CPL_HASHES, cpl.id(), canonical(find_cpl(dir)) + ).set_reference_hash(calc.old_hash()).set_calculated_hash(calc.new_hash()), { dcp::VerificationNote::Type::ERROR, dcp::VerificationNote::Code::UNEXPECTED_ENTRY_POINT }, { dcp::VerificationNote::Type::ERROR, dcp::VerificationNote::Code::UNEXPECTED_DURATION }, }); @@ -3179,6 +3444,8 @@ BOOST_AUTO_TEST_CASE(verify_invalid_content_kind) auto dcp = make_simple (dir, 1, 24); dcp->write_xml(); + HashCalculator calc(find_cpl(dir)); + { Editor e(find_cpl(dir)); e.replace("trailer", "trip"); @@ -3188,8 +3455,11 @@ BOOST_AUTO_TEST_CASE(verify_invalid_content_kind) check_verify_result ( { dir }, + {}, { - { dcp::VerificationNote::Type::ERROR, dcp::VerificationNote::Code::MISMATCHED_CPL_HASHES, cpl.id(), canonical(find_cpl(dir)) }, + dcp::VerificationNote( + dcp::VerificationNote::Type::ERROR, dcp::VerificationNote::Code::MISMATCHED_CPL_HASHES, cpl.id(), canonical(find_cpl(dir)) + ).set_reference_hash(calc.old_hash()).set_calculated_hash(calc.new_hash()), { dcp::VerificationNote::Type::ERROR, dcp::VerificationNote::Code::INVALID_CONTENT_KIND, string("trip") } }); @@ -3203,6 +3473,8 @@ BOOST_AUTO_TEST_CASE(verify_valid_content_kind) auto dcp = make_simple (dir, 1, 24); dcp->write_xml(); + HashCalculator calc(find_cpl(dir)); + { Editor e(find_cpl(dir)); e.replace("trailer", "trip"); @@ -3212,8 +3484,11 @@ BOOST_AUTO_TEST_CASE(verify_valid_content_kind) check_verify_result ( { dir }, + {}, { - { dcp::VerificationNote::Type::ERROR, dcp::VerificationNote::Code::MISMATCHED_CPL_HASHES, cpl.id(), canonical(find_cpl(dir)) }, + dcp::VerificationNote( + dcp::VerificationNote::Type::ERROR, dcp::VerificationNote::Code::MISMATCHED_CPL_HASHES, cpl.id(), canonical(find_cpl(dir)) + ).set_reference_hash(calc.old_hash()).set_calculated_hash(calc.new_hash()), }); } @@ -3228,6 +3503,8 @@ BOOST_AUTO_TEST_CASE(verify_invalid_main_picture_active_area_1) auto constexpr area = ""; + HashCalculator calc(find_cpl(dir)); + { Editor e(find_cpl(dir)); e.delete_lines_after(area, 2); @@ -3240,8 +3517,11 @@ BOOST_AUTO_TEST_CASE(verify_invalid_main_picture_active_area_1) check_verify_result( { dir }, + {}, { - { dcp::VerificationNote::Type::ERROR, dcp::VerificationNote::Code::MISMATCHED_CPL_HASHES, cpl.id(), canonical(find_cpl(dir)) }, + dcp::VerificationNote( + dcp::VerificationNote::Type::ERROR, dcp::VerificationNote::Code::MISMATCHED_CPL_HASHES, cpl.id(), canonical(find_cpl(dir)) + ).set_reference_hash(calc.old_hash()).set_calculated_hash(calc.new_hash()), { dcp::VerificationNote::Type::ERROR, dcp::VerificationNote::Code::INVALID_MAIN_PICTURE_ACTIVE_AREA, "width 1997 is not a multiple of 2", canonical(find_cpl(dir)) }, { dcp::VerificationNote::Type::ERROR, dcp::VerificationNote::Code::INVALID_MAIN_PICTURE_ACTIVE_AREA, "height 4080 is bigger than the asset height 1080", canonical(find_cpl(dir)) }, }); @@ -3257,6 +3537,8 @@ BOOST_AUTO_TEST_CASE(verify_invalid_main_picture_active_area_2) auto constexpr area = ""; + HashCalculator calc(find_cpl(dir)); + { Editor e(find_cpl(dir)); e.delete_lines_after(area, 2); @@ -3269,8 +3551,11 @@ BOOST_AUTO_TEST_CASE(verify_invalid_main_picture_active_area_2) check_verify_result( { dir }, + {}, { - { dcp::VerificationNote::Type::ERROR, dcp::VerificationNote::Code::MISMATCHED_CPL_HASHES, cpl.id(), canonical(find_cpl(dir)) }, + dcp::VerificationNote( + dcp::VerificationNote::Type::ERROR, dcp::VerificationNote::Code::MISMATCHED_CPL_HASHES, cpl.id(), canonical(find_cpl(dir)) + ).set_reference_hash(calc.old_hash()).set_calculated_hash(calc.new_hash()), { dcp::VerificationNote::Type::ERROR, dcp::VerificationNote::Code::INVALID_MAIN_PICTURE_ACTIVE_AREA, "height 5125 is not a multiple of 2", canonical(find_cpl(dir)) }, { dcp::VerificationNote::Type::ERROR, dcp::VerificationNote::Code::INVALID_MAIN_PICTURE_ACTIVE_AREA, "width 9900 is bigger than the asset width 1998", canonical(find_cpl(dir)) }, { dcp::VerificationNote::Type::ERROR, dcp::VerificationNote::Code::INVALID_MAIN_PICTURE_ACTIVE_AREA, "height 5125 is bigger than the asset height 1080", canonical(find_cpl(dir)) }, @@ -3296,6 +3581,7 @@ BOOST_AUTO_TEST_CASE(verify_duplicate_pkl_asset_ids) check_verify_result( { dir }, + {}, { { dcp::VerificationNote::Type::ERROR, dcp::VerificationNote::Code::DUPLICATE_ASSET_ID_IN_PKL, pkl.id(), canonical(find_pkl(dir)) }, }); @@ -3321,6 +3607,7 @@ BOOST_AUTO_TEST_CASE(verify_duplicate_assetmap_asset_ids) check_verify_result( { dir }, + {}, { { dcp::VerificationNote::Type::ERROR, dcp::VerificationNote::Code::DUPLICATE_ASSET_ID_IN_ASSETMAP, asset_map.id(), canonical(find_asset_map(dir)) }, { dcp::VerificationNote::Type::WARNING, dcp::VerificationNote::Code::EXTERNAL_ASSET, string("5407b210-4441-4e97-8b16-8bdc7c12da54") }, @@ -3394,6 +3681,7 @@ BOOST_AUTO_TEST_CASE(verify_mismatched_sound_channel_counts) check_verify_result( { path }, + {}, { { dcp::VerificationNote::Type::ERROR, dcp::VerificationNote::Code::MISMATCHED_SOUND_CHANNEL_COUNTS, canonical(find_file(path, "audio2")) }, }); @@ -3444,6 +3732,7 @@ BOOST_AUTO_TEST_CASE(verify_invalid_main_sound_configuration) check_verify_result( { path }, + {}, { { dcp::VerificationNote::Type::ERROR, dcp::VerificationNote::Code::INVALID_MAIN_SOUND_CONFIGURATION, std::string{"MainSoundConfiguration has 6 channels but sound assets have 2"}, canonical(find_cpl(path)) }, }); @@ -3500,14 +3789,41 @@ BOOST_AUTO_TEST_CASE(verify_invalid_tile_part_size) dcp->set_annotation_text("A Test DCP"); dcp->write_xml(); - check_verify_result( - { path }, - { - dcp::VerificationNote(dcp::VerificationNote::Type::ERROR, dcp::VerificationNote::Code::INVALID_JPEG2000_TILE_PART_SIZE).set_frame(0).set_component(0).set_size(1321721), - { dcp::VerificationNote::Type::ERROR, dcp::VerificationNote::Code::INVALID_PICTURE_FRAME_SIZE_IN_BYTES, canonical(path / "video.mxf") }, - { dcp::VerificationNote::Type::WARNING, dcp::VerificationNote::Code::MISSING_FFOC }, - { dcp::VerificationNote::Type::WARNING, dcp::VerificationNote::Code::MISSING_LFOC }, - }); + vector expected; + + for (auto frame = 0; frame < 24; frame++) { + expected.push_back( + dcp::VerificationNote( + dcp::VerificationNote::Type::ERROR, dcp::VerificationNote::Code::INVALID_PICTURE_FRAME_SIZE_IN_BYTES, canonical(path / "video.mxf") + ).set_frame(frame).set_frame_rate(24) + ); + } + + int component_sizes[] = { + 1321816, + 1294414, + 1289881, + }; + + for (auto frame = 0; frame < 24; frame++) { + for (auto component = 0; component < 3; component++) { + expected.push_back( + dcp::VerificationNote( + dcp::VerificationNote::Type::ERROR, dcp::VerificationNote::Code::INVALID_JPEG2000_TILE_PART_SIZE + ).set_frame(frame).set_component(component).set_size(component_sizes[component]) + ); + } + } + + expected.push_back( + { dcp::VerificationNote::Type::WARNING, dcp::VerificationNote::Code::MISSING_FFOC } + ); + + expected.push_back( + { dcp::VerificationNote::Type::WARNING, dcp::VerificationNote::Code::MISSING_LFOC } + ); + + check_verify_result({ path }, {}, expected); } @@ -3516,6 +3832,7 @@ BOOST_AUTO_TEST_CASE(verify_too_many_subtitle_namespaces) boost::filesystem::path const dir = "test/ref/DCP/subtitle_namespace_test"; check_verify_result( { dir }, + {}, { { dcp::VerificationNote::Type::BV21_ERROR, dcp::VerificationNote::Code::MISSING_FFEC_IN_FEATURE }, { dcp::VerificationNote::Type::BV21_ERROR, dcp::VerificationNote::Code::MISSING_FFMC_IN_FEATURE }, @@ -3541,7 +3858,9 @@ BOOST_AUTO_TEST_CASE(verify_missing_load_font_for_font) write_dcp_with_single_asset (dir, reel_asset, dcp::Standard::INTEROP); check_verify_result ( - {dir}, { + {dir}, + {}, + { { dcp::VerificationNote::Type::BV21_ERROR, dcp::VerificationNote::Code::INVALID_STANDARD }, dcp::VerificationNote(dcp::VerificationNote::Type::ERROR, dcp::VerificationNote::Code::MISSING_LOAD_FONT_FOR_FONT).set_id("theFontId") }); @@ -3551,7 +3870,7 @@ BOOST_AUTO_TEST_CASE(verify_missing_load_font_for_font) BOOST_AUTO_TEST_CASE(verify_missing_load_font) { - boost::filesystem::path const dir = dcp::String::compose("build/test/%1", boost::unit_test::framework::current_test_case().full_name()); + boost::filesystem::path const dir = "build/test/verify_missing_load_font"; prepare_directory(dir); auto dcp = make_simple (dir, 1, 202); @@ -3589,6 +3908,7 @@ BOOST_AUTO_TEST_CASE(verify_missing_load_font) check_verify_result ( { dir }, + {}, { dcp::VerificationNote(dcp::VerificationNote::Type::ERROR, dcp::VerificationNote::Code::MISSING_LOAD_FONT).set_id(reel_subs->id()) }); @@ -3614,7 +3934,55 @@ BOOST_AUTO_TEST_CASE(verify_spots_wrong_asset) check_verify_result( {dir / "1"}, + {}, { dcp::VerificationNote(dcp::VerificationNote::Type::ERROR, dcp::VerificationNote::Code::MISMATCHED_ASSET_MAP_ID).set_id(asset_1).set_other_id(asset_2) }); } + + +BOOST_AUTO_TEST_CASE(verify_cpl_content_version_label_text_empty) +{ + boost::filesystem::path const dir = "build/test/verify_cpl_content_version_label_text_empty"; + boost::filesystem::remove_all(dir); + + auto dcp = make_simple(dir); + BOOST_REQUIRE(dcp->cpls().size() == 1); + auto cpl = dcp->cpls()[0]; + cpl->set_content_version(dcp::ContentVersion("")); + dcp->write_xml(); + + check_verify_result( + {dir}, + {}, + { + dcp::VerificationNote(dcp::VerificationNote::Type::WARNING, dcp::VerificationNote::Code::EMPTY_CONTENT_VERSION_LABEL_TEXT, cpl->file().get()).set_id(cpl->id()) + }); +} + + +/** Check that we don't get any strange errors when verifying encrypted DCPs (DoM #2659) */ +BOOST_AUTO_TEST_CASE(verify_encrypted_smpte_dcp) +{ + auto const dir = path("build/test/verify_encrypted_smpte_dcp"); + dcp::Key key; + auto key_id = dcp::make_uuid(); + auto cpl = dcp_with_text(dir, {{ 4 * 24, 5 * 24 }}, key, key_id); + + dcp::DecryptedKDM kdm(dcp::LocalTime(), dcp::LocalTime(), "", "", ""); + kdm.add_key(dcp::DecryptedKDMKey(string{"MDIK"}, key_id, key, cpl->id(), dcp::Standard::SMPTE)); + + path const pkl_file = find_file(dir, "pkl_"); + path const cpl_file = find_file(dir, "cpl_"); + + check_verify_result( + { dir }, + { kdm }, + { + { dcp::VerificationNote::Type::BV21_ERROR, dcp::VerificationNote::Code::MISSING_CPL_METADATA, cpl->id(), canonical(cpl_file) }, + { dcp::VerificationNote::Type::BV21_ERROR, dcp::VerificationNote::Code::UNSIGNED_CPL_WITH_ENCRYPTED_CONTENT, cpl->id(), canonical(cpl_file) }, + { dcp::VerificationNote::Type::BV21_ERROR, dcp::VerificationNote::Code::UNSIGNED_PKL_WITH_ENCRYPTED_CONTENT, filename_to_id(pkl_file.filename()), canonical(pkl_file) } + }); +} + +