Avoid full_name() so we can build on Ubuntu 16.04.
[libdcp.git] / test / verify_test.cc
index a43e989b979cb1de6aa0f1c545a1aa6ef063f84f..a18058ef10968d0db40019e246fd620629b315fb 100644 (file)
@@ -153,135 +153,6 @@ write_dcp_with_single_asset (path dir, shared_ptr<dcp::ReelAsset> reel_asset, dc
 }
 
 
-/** Class that can alter a file by searching and replacing strings within it.
- *  On destruction modifies the file whose name was given to the constructor.
- */
-class Editor
-{
-public:
-       Editor (path path)
-               : _path(path)
-       {
-               _content = dcp::file_to_string (_path);
-       }
-
-       ~Editor ()
-       {
-               auto f = fopen(_path.string().c_str(), "w");
-               BOOST_REQUIRE (f);
-               fwrite (_content.c_str(), _content.length(), 1, f);
-               fclose (f);
-       }
-
-       class ChangeChecker
-       {
-       public:
-               ChangeChecker(Editor* editor)
-                       : _editor(editor)
-               {
-                       _old_content = _editor->_content;
-               }
-
-               ~ChangeChecker()
-               {
-                       BOOST_REQUIRE(_old_content != _editor->_content);
-               }
-       private:
-               Editor* _editor;
-               std::string _old_content;
-       };
-
-       void replace (string a, string b)
-       {
-               ChangeChecker cc(this);
-               boost::algorithm::replace_all (_content, a, b);
-       }
-
-       void delete_first_line_containing (string s)
-       {
-               ChangeChecker cc(this);
-               auto lines = as_lines();
-               _content = "";
-               bool done = false;
-               for (auto i: lines) {
-                       if (i.find(s) == string::npos || done) {
-                               _content += i + "\n";
-                       } else {
-                               done = true;
-                       }
-               }
-       }
-
-       void delete_lines (string from, string to)
-       {
-               ChangeChecker cc(this);
-               auto lines = as_lines();
-               bool deleting = false;
-               _content = "";
-               for (auto i: lines) {
-                       if (i.find(from) != string::npos) {
-                               deleting = true;
-                       }
-                       if (!deleting) {
-                               _content += i + "\n";
-                       }
-                       if (deleting && i.find(to) != string::npos) {
-                               deleting = false;
-                       }
-               }
-       }
-
-       void insert (string after, string line)
-       {
-               ChangeChecker cc(this);
-               auto lines = as_lines();
-               _content = "";
-               bool replaced = false;
-               for (auto i: lines) {
-                       _content += i + "\n";
-                       if (!replaced && i.find(after) != string::npos) {
-                               _content += line + "\n";
-                               replaced = true;
-                       }
-               }
-       }
-
-       void delete_lines_after(string after, int lines_to_delete)
-       {
-               ChangeChecker cc(this);
-               auto lines = as_lines();
-               _content = "";
-               auto iter = std::find_if(lines.begin(), lines.end(), [after](string const& line) {
-                       return line.find(after) != string::npos;
-               });
-               int to_delete = 0;
-               for (auto i = lines.begin(); i != lines.end(); ++i) {
-                       if (i == iter) {
-                               to_delete = lines_to_delete;
-                               _content += *i + "\n";
-                       } else if (to_delete == 0) {
-                               _content += *i + "\n";
-                       } else {
-                               --to_delete;
-                       }
-               }
-       }
-
-private:
-       friend class ChangeChecker;
-
-       vector<string> as_lines() const
-       {
-               vector<string> lines;
-               boost::algorithm::split(lines, _content, boost::is_any_of("\r\n"), boost::token_compress_on);
-               return lines;
-       }
-
-       path _path;
-       std::string _content;
-};
-
-
 LIBDCP_DISABLE_WARNINGS
 static
 void
@@ -359,6 +230,15 @@ check_verify_result_after_replace (string suffix, boost::function<path (string)>
 }
 
 
+static
+void
+add_font(shared_ptr<dcp::SubtitleAsset> asset)
+{
+       dcp::ArrayData fake_font(1024);
+       asset->add_font("font", fake_font);
+}
+
+
 BOOST_AUTO_TEST_CASE (verify_no_error)
 {
        stages.clear ();
@@ -661,6 +541,12 @@ 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 },
                {
@@ -669,7 +555,12 @@ BOOST_AUTO_TEST_CASE (verify_invalid_duration)
                        { 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")
                });
 }
 
@@ -779,6 +670,23 @@ BOOST_AUTO_TEST_CASE (verify_valid_interop_subtitles)
 }
 
 
+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<dcp::InteropSubtitleAsset>(dir / "ccap.xml");
+       auto reel_asset = make_shared<dcp::ReelInteropClosedCaptionAsset>(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"} }
+               });
+}
+
+
 BOOST_AUTO_TEST_CASE (verify_invalid_interop_subtitles)
 {
        using namespace boost::filesystem;
@@ -1412,6 +1320,7 @@ BOOST_AUTO_TEST_CASE (verify_invalid_closed_caption_xml_size_in_bytes)
        for (int i = 0; i < 2048; ++i) {
                add_test_subtitle (asset, i * 24, i * 24 + 20);
        }
+       add_font(asset);
        asset->set_language (dcp::LanguageTag("de-DE"));
        asset->write (dir / "subs.mxf");
        auto reel_asset = make_shared<dcp::ReelSMPTEClosedCaptionAsset>(asset, dcp::Fraction(24, 1), 49148, 0);
@@ -1424,7 +1333,7 @@ BOOST_AUTO_TEST_CASE (verify_invalid_closed_caption_xml_size_in_bytes)
                        {
                                dcp::VerificationNote::Type::BV21_ERROR,
                                dcp::VerificationNote::Code::INVALID_CLOSED_CAPTION_XML_SIZE_IN_BYTES,
-                               string("419292"),
+                               string("419371"),
                                canonical(dir / "subs.mxf")
                        },
                        { dcp::VerificationNote::Type::WARNING, dcp::VerificationNote::Code::INVALID_SUBTITLE_FIRST_TEXT_TIME },
@@ -1516,7 +1425,6 @@ BOOST_AUTO_TEST_CASE (verify_missing_subtitle_language)
 
        auto reel_subs = make_shared<dcp::ReelSMPTESubtitleAsset>(subs, dcp::Fraction(24, 1), 106, 0);
        dcp->cpls()[0]->reels()[0]->add(reel_subs);
-       dcp->set_annotation_text("A Test DCP");
        dcp->write_xml();
 
        check_verify_result (
@@ -1539,6 +1447,7 @@ BOOST_AUTO_TEST_CASE (verify_mismatched_subtitle_languages)
                auto subs = make_shared<dcp::SMPTESubtitleAsset>();
                subs->set_language (dcp::LanguageTag("de-DE"));
                subs->add (simple_subtitle());
+               add_font(subs);
                subs->write (path / "subs1.mxf");
                auto reel_subs = make_shared<dcp::ReelSMPTESubtitleAsset>(subs, dcp::Fraction(24, 1), reel_length, 0);
                cpl->reels()[0]->add(reel_subs);
@@ -1548,12 +1457,12 @@ BOOST_AUTO_TEST_CASE (verify_mismatched_subtitle_languages)
                auto subs = make_shared<dcp::SMPTESubtitleAsset>();
                subs->set_language (dcp::LanguageTag("en-US"));
                subs->add (simple_subtitle());
+               add_font(subs);
                subs->write (path / "subs2.mxf");
                auto reel_subs = make_shared<dcp::ReelSMPTESubtitleAsset>(subs, dcp::Fraction(24, 1), reel_length, 0);
                cpl->reels()[1]->add(reel_subs);
        }
 
-       dcp->set_annotation_text("A Test DCP");
        dcp->write_xml();
 
        check_verify_result (
@@ -1577,6 +1486,7 @@ BOOST_AUTO_TEST_CASE (verify_multiple_closed_caption_languages_allowed)
                auto ccaps = make_shared<dcp::SMPTESubtitleAsset>();
                ccaps->set_language (dcp::LanguageTag("de-DE"));
                ccaps->add (simple_subtitle());
+               add_font(ccaps);
                ccaps->write (path / "subs1.mxf");
                auto reel_ccaps = make_shared<dcp::ReelSMPTEClosedCaptionAsset>(ccaps, dcp::Fraction(24, 1), reel_length, 0);
                cpl->reels()[0]->add(reel_ccaps);
@@ -1586,12 +1496,12 @@ BOOST_AUTO_TEST_CASE (verify_multiple_closed_caption_languages_allowed)
                auto ccaps = make_shared<dcp::SMPTESubtitleAsset>();
                ccaps->set_language (dcp::LanguageTag("en-US"));
                ccaps->add (simple_subtitle());
+               add_font(ccaps);
                ccaps->write (path / "subs2.mxf");
                auto reel_ccaps = make_shared<dcp::ReelSMPTEClosedCaptionAsset>(ccaps, dcp::Fraction(24, 1), reel_length, 0);
                cpl->reels()[1]->add(reel_ccaps);
        }
 
-       dcp->set_annotation_text("A Test DCP");
        dcp->write_xml();
 
        check_verify_result (
@@ -1639,7 +1549,6 @@ BOOST_AUTO_TEST_CASE (verify_missing_subtitle_start_time)
 
        auto reel_subs = make_shared<dcp::ReelSMPTESubtitleAsset>(subs, dcp::Fraction(24, 1), 106, 0);
        dcp->cpls()[0]->reels()[0]->add(reel_subs);
-       dcp->set_annotation_text("A Test DCP");
        dcp->write_xml();
 
        check_verify_result (
@@ -1688,7 +1597,6 @@ BOOST_AUTO_TEST_CASE (verify_invalid_subtitle_start_time)
 
        auto reel_subs = make_shared<dcp::ReelSMPTESubtitleAsset>(subs, dcp::Fraction(24, 1), 106, 0);
        dcp->cpls().front()->reels().front()->add(reel_subs);
-       dcp->set_annotation_text("A Test DCP");
        dcp->write_xml();
 
        check_verify_result (
@@ -1730,6 +1638,7 @@ dcp_with_text (path dir, vector<TestText> subs)
                add_test_subtitle (asset, i.in, i.out, i.v_position, i.v_align, i.text);
        }
        asset->set_language (dcp::LanguageTag("de-DE"));
+       add_font(asset);
        asset->write (dir / "subs.mxf");
 
        auto reel_asset = make_shared<T>(asset, dcp::Fraction(24, 1), asset->intrinsic_duration(), 0);
@@ -1808,6 +1717,7 @@ BOOST_AUTO_TEST_CASE (verify_valid_subtitle_first_text_time_on_second_reel)
        /* Just late enough */
        add_test_subtitle (asset1, 4 * 24, 5 * 24);
        asset1->set_language (dcp::LanguageTag("de-DE"));
+       add_font(asset1);
        asset1->write (dir / "subs1.mxf");
        auto reel_asset1 = make_shared<dcp::ReelSMPTESubtitleAsset>(asset1, dcp::Fraction(24, 1), 5 * 24, 0);
        auto reel1 = make_shared<dcp::Reel>();
@@ -1818,6 +1728,7 @@ BOOST_AUTO_TEST_CASE (verify_valid_subtitle_first_text_time_on_second_reel)
 
        auto asset2 = make_shared<dcp::SMPTESubtitleAsset>();
        asset2->set_start_time (dcp::Time());
+       add_font(asset2);
        /* This would be too early on first reel but should be OK on the second */
        add_test_subtitle (asset2, 3, 4 * 24);
        asset2->set_language (dcp::LanguageTag("de-DE"));
@@ -1900,6 +1811,7 @@ BOOST_AUTO_TEST_CASE (verify_subtitle_overlapping_reel_boundary)
        auto asset = make_shared<dcp::SMPTESubtitleAsset>();
        asset->set_start_time (dcp::Time());
        add_test_subtitle (asset, 0, 4 * 24);
+       add_font(asset);
        asset->set_language (dcp::LanguageTag("de-DE"));
        asset->write (dir / "subs.mxf");
 
@@ -2254,7 +2166,6 @@ BOOST_AUTO_TEST_CASE (verify_missing_cpl_annotation_text)
 {
        path const dir("build/test/verify_missing_cpl_annotation_text");
        auto dcp = make_simple (dir);
-       dcp->set_annotation_text("A Test DCP");
        dcp->write_xml();
 
        BOOST_REQUIRE_EQUAL (dcp->cpls().size(), 1U);
@@ -2280,7 +2191,6 @@ BOOST_AUTO_TEST_CASE (verify_mismatched_cpl_annotation_text)
 {
        path const dir("build/test/verify_mismatched_cpl_annotation_text");
        auto dcp = make_simple (dir);
-       dcp->set_annotation_text("A Test DCP");
        dcp->write_xml();
 
        BOOST_REQUIRE_EQUAL (dcp->cpls().size(), 1U);
@@ -2347,12 +2257,13 @@ verify_subtitles_must_be_in_all_reels_check (path dir, bool add_to_reel1, bool a
        subs->set_language (dcp::LanguageTag("de-DE"));
        subs->set_start_time (dcp::Time());
        subs->add (simple_subtitle());
+       add_font(subs);
        subs->write (dir / "subs.mxf");
        auto reel_subs = make_shared<dcp::ReelSMPTESubtitleAsset>(subs, dcp::Fraction(24, 1), reel_length, 0);
 
        auto reel1 = make_shared<dcp::Reel>(
-               make_shared<dcp::ReelMonoPictureAsset>(simple_picture(dir, "", reel_length), 0),
-               make_shared<dcp::ReelSoundAsset>(simple_sound(dir, "", dcp::MXFMetadata(), "en-US", reel_length), 0)
+               make_shared<dcp::ReelMonoPictureAsset>(simple_picture(dir, "1", reel_length), 0),
+               make_shared<dcp::ReelSoundAsset>(simple_sound(dir, "1", dcp::MXFMetadata(), "en-US", reel_length), 0)
                );
 
        if (add_to_reel1) {
@@ -2366,8 +2277,8 @@ verify_subtitles_must_be_in_all_reels_check (path dir, bool add_to_reel1, bool a
        cpl->add (reel1);
 
        auto reel2 = make_shared<dcp::Reel>(
-               make_shared<dcp::ReelMonoPictureAsset>(simple_picture(dir, "", reel_length), 0),
-               make_shared<dcp::ReelSoundAsset>(simple_sound(dir, "", dcp::MXFMetadata(), "en-US", reel_length), 0)
+               make_shared<dcp::ReelMonoPictureAsset>(simple_picture(dir, "2", reel_length), 0),
+               make_shared<dcp::ReelSoundAsset>(simple_sound(dir, "2", dcp::MXFMetadata(), "en-US", reel_length), 0)
                );
 
        if (add_to_reel2) {
@@ -2430,11 +2341,12 @@ verify_closed_captions_must_be_in_all_reels_check (path dir, int caps_in_reel1,
        subs->set_language (dcp::LanguageTag("de-DE"));
        subs->set_start_time (dcp::Time());
        subs->add (simple_subtitle());
+       add_font(subs);
        subs->write (dir / "subs.mxf");
 
        auto reel1 = make_shared<dcp::Reel>(
-               make_shared<dcp::ReelMonoPictureAsset>(simple_picture(dir, "", reel_length), 0),
-               make_shared<dcp::ReelSoundAsset>(simple_sound(dir, "", dcp::MXFMetadata(), "en-US", reel_length), 0)
+               make_shared<dcp::ReelMonoPictureAsset>(simple_picture(dir, "1", reel_length), 0),
+               make_shared<dcp::ReelSoundAsset>(simple_sound(dir, "1", dcp::MXFMetadata(), "en-US", reel_length), 0)
                );
 
        for (int i = 0; i < caps_in_reel1; ++i) {
@@ -2448,8 +2360,8 @@ verify_closed_captions_must_be_in_all_reels_check (path dir, int caps_in_reel1,
        cpl->add (reel1);
 
        auto reel2 = make_shared<dcp::Reel>(
-               make_shared<dcp::ReelMonoPictureAsset>(simple_picture(dir, "", reel_length), 0),
-               make_shared<dcp::ReelSoundAsset>(simple_sound(dir, "", dcp::MXFMetadata(), "en-US", reel_length), 0)
+               make_shared<dcp::ReelMonoPictureAsset>(simple_picture(dir, "2", reel_length), 0),
+               make_shared<dcp::ReelSoundAsset>(simple_sound(dir, "2", dcp::MXFMetadata(), "en-US", reel_length), 0)
                );
 
        for (int i = 0; i < caps_in_reel2; ++i) {
@@ -2511,6 +2423,7 @@ verify_text_entry_point_check (path dir, dcp::VerificationNote::Code code, boost
        subs->set_language (dcp::LanguageTag("de-DE"));
        subs->set_start_time (dcp::Time());
        subs->add (simple_subtitle());
+       add_font(subs);
        subs->write (dir / "subs.mxf");
        auto reel_text = make_shared<T>(subs, dcp::Fraction(24, 1), reel_length, 0);
        adjust (reel_text);
@@ -2581,7 +2494,6 @@ BOOST_AUTO_TEST_CASE (verify_missing_hash)
 
        path const dir("build/test/verify_missing_hash");
        auto dcp = make_simple (dir);
-       dcp->set_annotation_text("A Test DCP");
        dcp->write_xml();
 
        BOOST_REQUIRE_EQUAL (dcp->cpls().size(), 1U);
@@ -2620,7 +2532,6 @@ verify_markers_test (
                markers_asset->set (i.first, i.second);
        }
        dcp->cpls()[0]->reels()[0]->add(markers_asset);
-       dcp->set_annotation_text("A Test DCP");
        dcp->write_xml();
 
        check_verify_result ({dir}, test_notes);
@@ -2717,7 +2628,6 @@ BOOST_AUTO_TEST_CASE (verify_missing_cpl_metadata_version_number)
        auto dcp = make_simple (dir);
        auto cpl = dcp->cpls()[0];
        cpl->unset_version_number();
-       dcp->set_annotation_text("A Test DCP");
        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() }});
@@ -2728,7 +2638,6 @@ BOOST_AUTO_TEST_CASE (verify_missing_extension_metadata1)
 {
        path dir = "build/test/verify_missing_extension_metadata1";
        auto dcp = make_simple (dir);
-       dcp->set_annotation_text("A Test DCP");
        dcp->write_xml();
 
        BOOST_REQUIRE_EQUAL (dcp->cpls().size(), 1U);
@@ -2752,7 +2661,6 @@ BOOST_AUTO_TEST_CASE (verify_missing_extension_metadata2)
 {
        path dir = "build/test/verify_missing_extension_metadata2";
        auto dcp = make_simple (dir);
-       dcp->set_annotation_text("A Test DCP");
        dcp->write_xml();
 
        auto cpl = dcp->cpls()[0];
@@ -2775,7 +2683,6 @@ BOOST_AUTO_TEST_CASE (verify_invalid_xml_cpl_extension_metadata3)
 {
        path dir = "build/test/verify_invalid_xml_cpl_extension_metadata3";
        auto dcp = make_simple (dir);
-       dcp->set_annotation_text("A Test DCP");
        dcp->write_xml();
 
        auto const cpl = dcp->cpls()[0];
@@ -2800,7 +2707,6 @@ BOOST_AUTO_TEST_CASE (verify_invalid_extension_metadata1)
 {
        path dir = "build/test/verify_invalid_extension_metadata1";
        auto dcp = make_simple (dir);
-       dcp->set_annotation_text("A Test DCP");
        dcp->write_xml();
 
        auto cpl = dcp->cpls()[0];
@@ -2823,7 +2729,6 @@ BOOST_AUTO_TEST_CASE (verify_invalid_extension_metadata2)
 {
        path dir = "build/test/verify_invalid_extension_metadata2";
        auto dcp = make_simple (dir);
-       dcp->set_annotation_text("A Test DCP");
        dcp->write_xml();
 
        auto cpl = dcp->cpls()[0];
@@ -2846,7 +2751,6 @@ BOOST_AUTO_TEST_CASE (verify_invalid_xml_cpl_extension_metadata6)
 {
        path dir = "build/test/verify_invalid_xml_cpl_extension_metadata6";
        auto dcp = make_simple (dir);
-       dcp->set_annotation_text("A Test DCP");
        dcp->write_xml();
 
        auto const cpl = dcp->cpls()[0];
@@ -2871,7 +2775,6 @@ BOOST_AUTO_TEST_CASE (verify_invalid_xml_cpl_extension_metadata7)
 {
        path dir = "build/test/verify_invalid_xml_cpl_extension_metadata7";
        auto dcp = make_simple (dir);
-       dcp->set_annotation_text("A Test DCP");
        dcp->write_xml();
 
        auto const cpl = dcp->cpls()[0];
@@ -2894,7 +2797,6 @@ BOOST_AUTO_TEST_CASE (verify_invalid_xml_cpl_extension_metadata8)
 {
        path dir = "build/test/verify_invalid_xml_cpl_extension_metadata8";
        auto dcp = make_simple (dir);
-       dcp->set_annotation_text("A Test DCP");
        dcp->write_xml();
 
        auto const cpl = dcp->cpls()[0];
@@ -2919,7 +2821,6 @@ BOOST_AUTO_TEST_CASE (verify_invalid_xml_cpl_extension_metadata9)
 {
        path dir = "build/test/verify_invalid_xml_cpl_extension_metadata9";
        auto dcp = make_simple (dir);
-       dcp->set_annotation_text("A Test DCP");
        dcp->write_xml();
 
        auto const cpl = dcp->cpls()[0];
@@ -3158,6 +3059,7 @@ BOOST_AUTO_TEST_CASE (verify_mismatched_subtitle_resource_id)
                "<EditRate>25 1</EditRate>"
                "<TimeCodeRate>25</TimeCodeRate>"
                "<StartTime>00:00:00:00</StartTime>"
+               "<LoadFont ID=\"arial\">urn:uuid:e4f0ff0a-9eba-49e0-92ee-d89a88a575f6</LoadFont>"
                "<SubtitleList>"
                "<Font ID=\"arial\" Color=\"FFFEFEFE\" Weight=\"normal\" Size=\"42\" Effect=\"border\" EffectColor=\"FF181818\" AspectAdjust=\"1.00\">"
                "<Subtitle SpotNumber=\"1\" TimeIn=\"00:00:03:00\" TimeOut=\"00:00:04:10\" FadeUpTime=\"00:00:00:00\" FadeDownTime=\"00:00:00:00\">"
@@ -3222,6 +3124,7 @@ BOOST_AUTO_TEST_CASE (verify_incorrect_timed_text_id)
                "<EditRate>25 1</EditRate>"
                "<TimeCodeRate>25</TimeCodeRate>"
                "<StartTime>00:00:00:00</StartTime>"
+               "<LoadFont ID=\"font\">urn:uuid:0ce6e0ba-58b9-4344-8929-4d9c959c2d55</LoadFont>"
                "<SubtitleList>"
                "<Font ID=\"arial\" Color=\"FFFEFEFE\" Weight=\"normal\" Size=\"42\" Effect=\"border\" EffectColor=\"FF181818\" AspectAdjust=\"1.00\">"
                "<Subtitle SpotNumber=\"1\" TimeIn=\"00:00:03:00\" TimeOut=\"00:00:04:10\" FadeUpTime=\"00:00:00:00\" FadeDownTime=\"00:00:00:00\">"
@@ -3275,7 +3178,6 @@ BOOST_AUTO_TEST_CASE (verify_unexpected_things_in_main_markers)
        path dir = "build/test/verify_unexpected_things_in_main_markers";
        prepare_directory (dir);
        auto dcp = make_simple (dir, 1, 24);
-       dcp->set_annotation_text("A Test DCP");
        dcp->write_xml();
 
        {
@@ -3303,7 +3205,6 @@ BOOST_AUTO_TEST_CASE(verify_invalid_content_kind)
        path dir = "build/test/verify_invalid_content_kind";
        prepare_directory (dir);
        auto dcp = make_simple (dir, 1, 24);
-       dcp->set_annotation_text("A Test DCP");
        dcp->write_xml();
 
        {
@@ -3328,7 +3229,6 @@ BOOST_AUTO_TEST_CASE(verify_valid_content_kind)
        path dir = "build/test/verify_valid_content_kind";
        prepare_directory (dir);
        auto dcp = make_simple (dir, 1, 24);
-       dcp->set_annotation_text("A Test DCP");
        dcp->write_xml();
 
        {
@@ -3370,7 +3270,6 @@ BOOST_AUTO_TEST_CASE(verify_invalid_main_picture_active_area_1)
                { dir },
                {
                        { dcp::VerificationNote::Type::ERROR, dcp::VerificationNote::Code::MISMATCHED_CPL_HASHES, cpl.id(), canonical(find_cpl(dir)) },
-                       { dcp::VerificationNote::Type::BV21_ERROR, dcp::VerificationNote::Code::MISMATCHED_PKL_ANNOTATION_TEXT_WITH_CPL, pkl.id(), canonical(find_pkl(dir)), },
                        { 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)) },
                });
@@ -3400,7 +3299,6 @@ BOOST_AUTO_TEST_CASE(verify_invalid_main_picture_active_area_2)
                { dir },
                {
                        { dcp::VerificationNote::Type::ERROR, dcp::VerificationNote::Code::MISMATCHED_CPL_HASHES, cpl.id(), canonical(find_cpl(dir)) },
-                       { dcp::VerificationNote::Type::BV21_ERROR, dcp::VerificationNote::Code::MISMATCHED_PKL_ANNOTATION_TEXT_WITH_CPL, pkl.id(), canonical(find_pkl(dir)), },
                        { 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)) },
@@ -3452,7 +3350,6 @@ BOOST_AUTO_TEST_CASE(verify_duplicate_assetmap_asset_ids)
        check_verify_result(
                { dir },
                {
-                       { dcp::VerificationNote::Type::BV21_ERROR, dcp::VerificationNote::Code::MISMATCHED_PKL_ANNOTATION_TEXT_WITH_CPL, pkl.id(), canonical(find_pkl(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") },
                });
@@ -3658,7 +3555,7 @@ BOOST_AUTO_TEST_CASE(verify_too_many_subtitle_namespaces)
 }
 
 
-BOOST_AUTO_TEST_CASE(verify_missing_load_font)
+BOOST_AUTO_TEST_CASE(verify_missing_load_font_for_font)
 {
        path const dir("build/test/verify_missing_load_font");
        prepare_directory (dir);
@@ -3674,8 +3571,97 @@ BOOST_AUTO_TEST_CASE(verify_missing_load_font)
        check_verify_result (
                {dir}, {
                        { dcp::VerificationNote::Type::BV21_ERROR, dcp::VerificationNote::Code::INVALID_STANDARD },
-                       dcp::VerificationNote(dcp::VerificationNote::Type::ERROR, dcp::VerificationNote::Code::MISSING_LOAD_FONT).set_id("theFontId")
+                       dcp::VerificationNote(dcp::VerificationNote::Type::ERROR, dcp::VerificationNote::Code::MISSING_LOAD_FONT_FOR_FONT).set_id("theFontId")
                });
 
 }
 
+
+BOOST_AUTO_TEST_CASE(verify_missing_load_font)
+{
+       boost::filesystem::path const dir = "build/test/verify_missing_load_font";
+       prepare_directory(dir);
+       auto dcp = make_simple (dir, 1, 202);
+
+       string const xml =
+               "<?xml version=\"1.0\" encoding=\"UTF-8\"?>"
+               "<SubtitleReel xmlns=\"http://www.smpte-ra.org/schemas/428-7/2010/DCST\">"
+               "<Id>urn:uuid:e6a8ae03-ebbf-41ed-9def-913a87d1493a</Id>"
+               "<ContentTitleText>Content</ContentTitleText>"
+               "<AnnotationText>Annotation</AnnotationText>"
+               "<IssueDate>2018-10-02T12:25:14+02:00</IssueDate>"
+               "<ReelNumber>1</ReelNumber>"
+               "<EditRate>24 1</EditRate>"
+               "<TimeCodeRate>24</TimeCodeRate>"
+               "<StartTime>00:00:00:00</StartTime>"
+               "<Language>de-DE</Language>"
+               "<SubtitleList>"
+               "<Font ID=\"arial\" Color=\"FFFEFEFE\" Weight=\"normal\" Size=\"42\" Effect=\"border\" EffectColor=\"FF181818\" AspectAdjust=\"1.00\">"
+               "<Subtitle SpotNumber=\"1\" TimeIn=\"00:00:06:00\" TimeOut=\"00:00:08:10\" FadeUpTime=\"00:00:00:00\" FadeDownTime=\"00:00:00:00\">"
+               "<Text Hposition=\"0.0\" Halign=\"center\" Valign=\"bottom\" Vposition=\"13.5\" Direction=\"ltr\">Hello world</Text>"
+               "</Subtitle>"
+               "</Font>"
+               "</SubtitleList>"
+               "</SubtitleReel>";
+
+       dcp::File xml_file(dir / "subs.xml", "w");
+       BOOST_REQUIRE(xml_file);
+       xml_file.write(xml.c_str(), xml.size(), 1);
+       xml_file.close();
+       auto subs = make_shared<dcp::SMPTESubtitleAsset>(dir / "subs.xml");
+       subs->write(dir / "subs.mxf");
+
+       auto reel_subs = make_shared<dcp::ReelSMPTESubtitleAsset>(subs, dcp::Fraction(24, 1), 202, 0);
+       dcp->cpls()[0]->reels()[0]->add(reel_subs);
+       dcp->write_xml();
+
+       check_verify_result (
+               { dir },
+               {
+                       dcp::VerificationNote(dcp::VerificationNote::Type::ERROR, dcp::VerificationNote::Code::MISSING_LOAD_FONT).set_id(reel_subs->id())
+               });
+}
+
+
+BOOST_AUTO_TEST_CASE(verify_spots_wrong_asset)
+{
+       boost::filesystem::path const dir = "build/test/verify_spots_wrong_asset";
+       boost::filesystem::remove_all(dir);
+
+       auto dcp1 = make_simple(dir / "1");
+       dcp1->write_xml();
+
+       auto const asset_1 = dcp::MonoPictureAsset(dir / "1" / "video.mxf").id();
+
+       auto dcp2 = make_simple(dir / "2");
+       dcp2->write_xml();
+       auto const asset_2 = dcp::MonoPictureAsset(dir / "2" / "video.mxf").id();
+
+       boost::filesystem::remove(dir / "1" / "video.mxf");
+       boost::filesystem::copy_file(dir / "2" / "video.mxf", dir / "1" / "video.mxf");
+
+       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())
+               });
+}