Bv2.1 9.1: PKL annotation text must match CPL ContentTitleText if there is only one...
authorCarl Hetherington <cth@carlh.net>
Mon, 18 Jan 2021 21:53:57 +0000 (22:53 +0100)
committerCarl Hetherington <cth@carlh.net>
Mon, 18 Jan 2021 21:53:57 +0000 (22:53 +0100)
src/verify.cc
src/verify.h
test/combine_test.cc
test/dcp_test.cc
test/ref/DCP/dcp_test1/ASSETMAP.xml
test/ref/DCP/dcp_test1/pkl_2b9b857f-ab4a-440e-a313-1ace0f1cfc95.xml
test/verify_test.cc

index 3f15668fcf88b9a591778b011be73d3c7237c74c..901f44bc400fb0e44b1e0bbe704ee98e2f05d6fc 100644 (file)
@@ -1127,12 +1127,33 @@ dcp::verify (
                                }
                        }
 
-                       /* Check that the CPL's hash corresponds to the PKL */
                        for (auto i: dcp->pkls()) {
+                               /* Check that the CPL's hash corresponds to the PKL */
                                optional<string> h = i->hash(cpl->id());
                                if (h && make_digest(ArrayData(*cpl->file())) != *h) {
                                        notes.push_back (VerificationNote(VerificationNote::VERIFY_ERROR, VerificationNote::CPL_HASH_INCORRECT));
                                }
+
+                               /* Check that any PKL with a single CPL has its AnnotationText the same as the CPL's ContentTitleText */
+                               optional<string> required_annotation_text;
+                               for (auto j: i->asset_list()) {
+                                       /* See if this is a CPL */
+                                       for (auto k: dcp->cpls()) {
+                                               if (j->id() == k->id()) {
+                                                       if (!required_annotation_text) {
+                                                               /* First CPL we have found; this is the required AnnotationText unless we find another */
+                                                               required_annotation_text = cpl->content_title_text();
+                                                       } else {
+                                                               /* There's more than one CPL so we don't care what the PKL's AnnotationText is */
+                                                               required_annotation_text = boost::none;
+                                                       }
+                                               }
+                                       }
+                               }
+
+                               if (required_annotation_text && i->annotation_text() != required_annotation_text) {
+                                       notes.push_back ({VerificationNote::VERIFY_BV21_ERROR, VerificationNote::PKL_ANNOTATION_TEXT_DOES_NOT_MATCH_CPL_CONTENT_TITLE_TEXT, i->file().get()});
+                               }
                        }
 
                        /* set to true if any reel has a MainSubtitle */
@@ -1452,6 +1473,8 @@ dcp::note_to_string (dcp::VerificationNote note)
                return String::compose("The <ExtensionMetadata> is malformed in some way: %1", note.note().get());
        case dcp::VerificationNote::CPL_WITH_ENCRYPTED_CONTENT_NOT_SIGNED:
                return String::compose("The CPL %1, which has encrypted content, is not signed", note.file()->filename());
+       case dcp::VerificationNote::PKL_ANNOTATION_TEXT_DOES_NOT_MATCH_CPL_CONTENT_TITLE_TEXT:
+               return String::compose("The PKL %1 has only one CPL but its <AnnotationText> does not match the CPL's <ContentTitleText>", note.file()->filename());
        }
 
        return "";
index 833efa72e88d96a6f3f0493d5b4277fededf9b10..46c7b2e3d92f416a0273841b5e27e00ddfbe8885 100644 (file)
@@ -174,7 +174,9 @@ public:
                /** <ExtensionMetadata> must have a particular form Bv2.1_8.6.3 */
                INVALID_EXTENSION_METADATA,
                /** CPLs containing encrypted content must be signed Bv2.1_8.7 */
-               CPL_WITH_ENCRYPTED_CONTENT_NOT_SIGNED
+               CPL_WITH_ENCRYPTED_CONTENT_NOT_SIGNED,
+               /** If a PKL has one CPL its <ContentTitleText> must be the same as the PKL's <AnnotationText> */
+               PKL_ANNOTATION_TEXT_DOES_NOT_MATCH_CPL_CONTENT_TITLE_TEXT
        };
 
        VerificationNote (Type type, Code code)
index 050978c7eb903368efca2bd8d0ffd2f5a69ab062..62b7ffd50f39583b5321a3dfc302a85b1c0e80f0 100644 (file)
@@ -157,7 +157,14 @@ BOOST_AUTO_TEST_CASE (combine_single_dcp_test)
        remove_all (out);
        vector<path> inputs;
        inputs.push_back ("test/ref/DCP/dcp_test1");
-       dcp::combine (inputs, out);
+       dcp::combine (
+               inputs,
+               out,
+               dcp::String::compose("libdcp %1", dcp::version),
+               dcp::String::compose("libdcp %1", dcp::version),
+               dcp::LocalTime().as_string(),
+               "A Test DCP"
+               );
 
        check_no_errors (out);
        check_combined (inputs, out);
index dc24483eaa7ce0921a67b3862068a4ec649ad78e..cdcbe495b9cce0e8f63042d97ef0d78fa59949bd 100644 (file)
@@ -68,7 +68,7 @@ BOOST_AUTO_TEST_CASE (dcp_test1)
        RNGFixer fixer;
 
        make_simple("build/test/DCP/dcp_test1")->write_xml(
-               dcp::SMPTE, "OpenDCP 0.0.25", "OpenDCP 0.0.25", "2012-07-17T04:45:18+00:00", "Created by libdcp"
+               dcp::SMPTE, "OpenDCP 0.0.25", "OpenDCP 0.0.25", "2012-07-17T04:45:18+00:00", "A Test DCP"
                );
 
        /* build/test/DCP/dcp_test1 is checked against test/ref/DCP/dcp_test1 by run/tests */
index 72096d956ba04dd481c1abdc69c1e7e7d3228b77..e0426fb14b2f7aa9344fca54ac08d92452180052 100644 (file)
@@ -1,7 +1,7 @@
 <?xml version="1.0" encoding="UTF-8"?>
 <AssetMap xmlns="http://www.smpte-ra.org/schemas/429-9/2007/AM">
   <Id>urn:uuid:07e9f5a0-83ab-4791-8c6b-7df5d11f76f9</Id>
-  <AnnotationText>Created by libdcp</AnnotationText>
+  <AnnotationText>A Test DCP</AnnotationText>
   <Creator>OpenDCP 0.0.25</Creator>
   <VolumeCount>1</VolumeCount>
   <IssueDate>2012-07-17T04:45:18+00:00</IssueDate>
@@ -15,7 +15,7 @@
           <Path>pkl_2b9b857f-ab4a-440e-a313-1ace0f1cfc95.xml</Path>
           <VolumeIndex>1</VolumeIndex>
           <Offset>0</Offset>
-          <Length>1186</Length>
+          <Length>1179</Length>
         </Chunk>
       </ChunkList>
     </Asset>
index ea99d1148e575afa61e0d55c43277288c1098f38..5038b8ed8690a6b81f9cdacd208b341ebfc36287 100644 (file)
@@ -1,7 +1,7 @@
 <?xml version="1.0" encoding="UTF-8"?>
 <PackingList xmlns="http://www.smpte-ra.org/schemas/429-8/2007/PKL">
   <Id>urn:uuid:2b9b857f-ab4a-440e-a313-1ace0f1cfc95</Id>
-  <AnnotationText>Created by libdcp</AnnotationText>
+  <AnnotationText>A Test DCP</AnnotationText>
   <IssueDate>2012-07-17T04:45:18+00:00</IssueDate>
   <Issuer>OpenDCP 0.0.25</Issuer>
   <Creator>OpenDCP 0.0.25</Creator>
index 3d30797e8207f1b1fd1261dde41ee1e6974f4b6f..265529bb059c5ddb26e835cbe8cf1879146512f0 100644 (file)
@@ -117,7 +117,13 @@ write_dcp_with_single_asset (boost::filesystem::path dir, shared_ptr<dcp::ReelAs
        cpl->add (reel);
        auto dcp = make_shared<dcp::DCP>(dir);
        dcp->add (cpl);
-       dcp->write_xml (standard);
+       dcp->write_xml (
+               standard,
+               dcp::String::compose("libdcp %1", dcp::version),
+               dcp::String::compose("libdcp %1", dcp::version),
+               dcp::LocalTime().as_string(),
+               "hello"
+               );
 }
 
 
@@ -739,7 +745,13 @@ BOOST_AUTO_TEST_CASE (verify_test23)
 
        dcp::DCP dcp (dir);
        dcp.add (cpl);
-       dcp.write_xml (dcp::SMPTE);
+       dcp.write_xml (
+               dcp::SMPTE,
+               dcp::String::compose("libdcp %1", dcp::version),
+               dcp::String::compose("libdcp %1", dcp::version),
+               dcp::LocalTime().as_string(),
+               "hello"
+               );
 
        check_verify_result ({dir}, {{ dcp::VerificationNote::VERIFY_BV21_ERROR, dcp::VerificationNote::MISSING_CPL_METADATA }});
 }
@@ -778,7 +790,13 @@ BOOST_AUTO_TEST_CASE (verify_test24)
 
        dcp::DCP dcp (dir);
        dcp.add (cpl);
-       dcp.write_xml (dcp::SMPTE);
+       dcp.write_xml (
+               dcp::SMPTE,
+               dcp::String::compose("libdcp %1", dcp::version),
+               dcp::String::compose("libdcp %1", dcp::version),
+               dcp::LocalTime().as_string(),
+               "hello"
+               );
 
        {
                Editor e (find_cpl("build/test/verify_test24"));
@@ -813,7 +831,13 @@ BOOST_AUTO_TEST_CASE (verify_test25)
 
        dcp::DCP dcp (dir);
        dcp.add (cpl);
-       dcp.write_xml (dcp::SMPTE);
+       dcp.write_xml (
+               dcp::SMPTE,
+               dcp::String::compose("libdcp %1", dcp::version),
+               dcp::String::compose("libdcp %1", dcp::version),
+               dcp::LocalTime().as_string(),
+               "hello"
+               );
 
        {
                Editor e (find_cpl("build/test/verify_test25"));
@@ -912,7 +936,13 @@ BOOST_AUTO_TEST_CASE (verify_various_invalid_languages)
        cpl->_release_territory = "fred-jim";
        auto dcp = make_shared<dcp::DCP>(dir);
        dcp->add (cpl);
-       dcp->write_xml (dcp::SMPTE);
+       dcp->write_xml (
+               dcp::SMPTE,
+               dcp::String::compose("libdcp %1", dcp::version),
+               dcp::String::compose("libdcp %1", dcp::version),
+               dcp::LocalTime().as_string(),
+               "hello"
+               );
 
        auto notes = dcp::verify ({dir}, &stage, &progress, xsd_test);
        BOOST_REQUIRE_EQUAL (notes.size(), 4U);
@@ -984,7 +1014,13 @@ check_picture_size (int width, int height, int frame_rate, bool three_d)
        cpl->add (reel);
 
        d->add (cpl);
-       d->write_xml (dcp::SMPTE);
+       d->write_xml (
+               dcp::SMPTE,
+               dcp::String::compose("libdcp %1", dcp::version),
+               dcp::String::compose("libdcp %1", dcp::version),
+               dcp::LocalTime().as_string(),
+               "A Test DCP"
+               );
 
        return dcp::verify ({dcp_path}, &stage, &progress, xsd_test);
 }
@@ -1220,7 +1256,13 @@ BOOST_AUTO_TEST_CASE (verify_missing_language_tag_in_subtitle_xml)
 
        auto reel_subs = make_shared<dcp::ReelSubtitleAsset>(subs, dcp::Fraction(24, 1), 240, 0);
        dcp->cpls().front()->reels().front()->add(reel_subs);
-       dcp->write_xml (dcp::SMPTE);
+       dcp->write_xml (
+               dcp::SMPTE,
+               dcp::String::compose("libdcp %1", dcp::version),
+               dcp::String::compose("libdcp %1", dcp::version),
+               dcp::LocalTime().as_string(),
+               "A Test DCP"
+               );
 
        check_verify_result (
                { dir },
@@ -1255,7 +1297,13 @@ BOOST_AUTO_TEST_CASE (verify_inconsistent_subtitle_languages)
                cpl->reels()[1]->add(reel_subs);
        }
 
-       dcp->write_xml (dcp::SMPTE);
+       dcp->write_xml (
+               dcp::SMPTE,
+               dcp::String::compose("libdcp %1", dcp::version),
+               dcp::String::compose("libdcp %1", dcp::version),
+               dcp::LocalTime().as_string(),
+               "A Test DCP"
+               );
 
        check_verify_result (
                { path },
@@ -1303,7 +1351,13 @@ BOOST_AUTO_TEST_CASE (verify_missing_start_time_tag_in_subtitle_xml)
 
        auto reel_subs = make_shared<dcp::ReelSubtitleAsset>(subs, dcp::Fraction(24, 1), 240, 0);
        dcp->cpls().front()->reels().front()->add(reel_subs);
-       dcp->write_xml (dcp::SMPTE);
+       dcp->write_xml (
+               dcp::SMPTE,
+               dcp::String::compose("libdcp %1", dcp::version),
+               dcp::String::compose("libdcp %1", dcp::version),
+               dcp::LocalTime().as_string(),
+               "A Test DCP"
+               );
 
        check_verify_result (
                { dir },
@@ -1351,7 +1405,13 @@ BOOST_AUTO_TEST_CASE (verify_non_zero_start_time_tag_in_subtitle_xml)
 
        auto reel_subs = make_shared<dcp::ReelSubtitleAsset>(subs, dcp::Fraction(24, 1), 240, 0);
        dcp->cpls().front()->reels().front()->add(reel_subs);
-       dcp->write_xml (dcp::SMPTE);
+       dcp->write_xml (
+               dcp::SMPTE,
+               dcp::String::compose("libdcp %1", dcp::version),
+               dcp::String::compose("libdcp %1", dcp::version),
+               dcp::LocalTime().as_string(),
+               "A Test DCP"
+               );
 
        check_verify_result (
                { dir },
@@ -1457,7 +1517,14 @@ BOOST_AUTO_TEST_CASE (verify_text_early_on_second_reel)
        cpl->add (reel2);
        auto dcp = make_shared<dcp::DCP>(dir);
        dcp->add (cpl);
-       dcp->write_xml (dcp::SMPTE);
+       dcp->write_xml (
+               dcp::SMPTE,
+               dcp::String::compose("libdcp %1", dcp::version),
+               dcp::String::compose("libdcp %1", dcp::version),
+               dcp::LocalTime().as_string(),
+               "hello"
+               );
+
 
        check_verify_result ({dir}, {{ dcp::VerificationNote::VERIFY_BV21_ERROR, dcp::VerificationNote::MISSING_CPL_METADATA }});
 }
@@ -1721,7 +1788,13 @@ BOOST_AUTO_TEST_CASE (verify_sound_sampling_rate_must_be_48k)
        cpl->add (reel);
        auto dcp = make_shared<dcp::DCP>(dir);
        dcp->add (cpl);
-       dcp->write_xml (dcp::SMPTE);
+       dcp->write_xml (
+               dcp::SMPTE,
+               dcp::String::compose("libdcp %1", dcp::version),
+               dcp::String::compose("libdcp %1", dcp::version),
+               dcp::LocalTime().as_string(),
+               "hello"
+               );
 
        check_verify_result (
                {dir},
@@ -1736,7 +1809,14 @@ BOOST_AUTO_TEST_CASE (verify_cpl_must_have_annotation_text)
 {
        boost::filesystem::path const dir("build/test/verify_cpl_must_have_annotation_text");
        auto dcp = make_simple (dir);
-       dcp->write_xml (dcp::SMPTE);
+       dcp->write_xml (
+               dcp::SMPTE,
+               dcp::String::compose("libdcp %1", dcp::version),
+               dcp::String::compose("libdcp %1", dcp::version),
+               dcp::LocalTime().as_string(),
+               "A Test DCP"
+               );
+
        BOOST_REQUIRE_EQUAL (dcp->cpls().size(), 1U);
 
        {
@@ -1758,7 +1838,14 @@ BOOST_AUTO_TEST_CASE (verify_cpl_annotation_text_should_be_same_as_content_title
 {
        boost::filesystem::path const dir("build/test/verify_cpl_annotation_text_should_be_same_as_content_title_text");
        auto dcp = make_simple (dir);
-       dcp->write_xml (dcp::SMPTE);
+       dcp->write_xml (
+               dcp::SMPTE,
+               dcp::String::compose("libdcp %1", dcp::version),
+               dcp::String::compose("libdcp %1", dcp::version),
+               dcp::LocalTime().as_string(),
+               "A Test DCP"
+               );
+
        BOOST_REQUIRE_EQUAL (dcp->cpls().size(), 1U);
 
        {
@@ -1796,7 +1883,14 @@ BOOST_AUTO_TEST_CASE (verify_reel_assets_durations_must_match)
        cpl->add (reel);
 
        dcp->add (cpl);
-       dcp->write_xml (dcp::SMPTE);
+       dcp->write_xml (
+               dcp::SMPTE,
+               dcp::String::compose("libdcp %1", dcp::version),
+               dcp::String::compose("libdcp %1", dcp::version),
+               dcp::LocalTime().as_string(),
+               "A Test DCP"
+               );
+
 
        check_verify_result (
                {dir},
@@ -1855,7 +1949,13 @@ verify_subtitles_must_be_in_all_reels_check (boost::filesystem::path dir, bool a
        cpl->add (reel2);
 
        dcp->add (cpl);
-       dcp->write_xml (dcp::SMPTE);
+       dcp->write_xml (
+               dcp::SMPTE,
+               dcp::String::compose("libdcp %1", dcp::version),
+               dcp::String::compose("libdcp %1", dcp::version),
+               dcp::LocalTime().as_string(),
+               "A Test DCP"
+               );
 }
 
 
@@ -1933,8 +2033,13 @@ verify_closed_captions_must_be_in_all_reels_check (boost::filesystem::path dir,
        cpl->add (reel2);
 
        dcp->add (cpl);
-       dcp->write_xml (dcp::SMPTE);
-
+       dcp->write_xml (
+               dcp::SMPTE,
+               dcp::String::compose("libdcp %1", dcp::version),
+               dcp::String::compose("libdcp %1", dcp::version),
+               dcp::LocalTime().as_string(),
+               "A Test DCP"
+               );
 }
 
 
@@ -1994,7 +2099,13 @@ verify_text_entry_point_check (boost::filesystem::path dir, dcp::VerificationNot
        cpl->add (reel);
 
        dcp->add (cpl);
-       dcp->write_xml (dcp::SMPTE);
+       dcp->write_xml (
+               dcp::SMPTE,
+               dcp::String::compose("libdcp %1", dcp::version),
+               dcp::String::compose("libdcp %1", dcp::version),
+               dcp::LocalTime().as_string(),
+               "A Test DCP"
+               );
 
        check_verify_result (
                {dir},
@@ -2047,7 +2158,14 @@ BOOST_AUTO_TEST_CASE (verify_assets_must_have_hashes)
 
        boost::filesystem::path const dir("build/test/verify_assets_must_have_hashes");
        auto dcp = make_simple (dir);
-       dcp->write_xml (dcp::SMPTE);
+       dcp->write_xml (
+               dcp::SMPTE,
+               dcp::String::compose("libdcp %1", dcp::version),
+               dcp::String::compose("libdcp %1", dcp::version),
+               dcp::LocalTime().as_string(),
+               "A Test DCP"
+               );
+
        BOOST_REQUIRE_EQUAL (dcp->cpls().size(), 1U);
 
        {
@@ -2080,7 +2198,14 @@ verify_markers_test (
                markers_asset->set (i.first, i.second);
        }
        dcp->cpls()[0]->reels()[0]->add(markers_asset);
-       dcp->write_xml (dcp::SMPTE);
+       dcp->write_xml (
+               dcp::SMPTE,
+               dcp::String::compose("libdcp %1", dcp::version),
+               dcp::String::compose("libdcp %1", dcp::version),
+               dcp::LocalTime().as_string(),
+               "A Test DCP"
+               );
+
        check_verify_result ({dir}, test_notes);
 }
 
@@ -2174,7 +2299,14 @@ BOOST_AUTO_TEST_CASE (verify_cpl_metadata_version)
        prepare_directory (dir);
        auto dcp = make_simple (dir);
        dcp->cpls()[0]->unset_version_number();
-       dcp->write_xml (dcp::SMPTE);
+       dcp->write_xml (
+               dcp::SMPTE,
+               dcp::String::compose("libdcp %1", dcp::version),
+               dcp::String::compose("libdcp %1", dcp::version),
+               dcp::LocalTime().as_string(),
+               "A Test DCP"
+               );
+
        check_verify_result ({dir}, {{ dcp::VerificationNote::VERIFY_BV21_ERROR, dcp::VerificationNote::MISSING_CPL_METADATA_VERSION_NUMBER }});
 }
 
@@ -2183,7 +2315,14 @@ BOOST_AUTO_TEST_CASE (verify_cpl_extension_metadata1)
 {
        boost::filesystem::path dir = "build/test/verify_cpl_extension_metadata1";
        auto dcp = make_simple (dir);
-       dcp->write_xml (dcp::SMPTE);
+       dcp->write_xml (
+               dcp::SMPTE,
+               dcp::String::compose("libdcp %1", dcp::version),
+               dcp::String::compose("libdcp %1", dcp::version),
+               dcp::LocalTime().as_string(),
+               "A Test DCP"
+               );
+
        {
                Editor e (dcp->cpls()[0]->file().get());
                e.delete_lines ("<meta:ExtensionMetadataList>", "</meta:ExtensionMetadataList>");
@@ -2202,7 +2341,14 @@ BOOST_AUTO_TEST_CASE (verify_cpl_extension_metadata2)
 {
        boost::filesystem::path dir = "build/test/verify_cpl_extension_metadata2";
        auto dcp = make_simple (dir);
-       dcp->write_xml (dcp::SMPTE);
+       dcp->write_xml (
+               dcp::SMPTE,
+               dcp::String::compose("libdcp %1", dcp::version),
+               dcp::String::compose("libdcp %1", dcp::version),
+               dcp::LocalTime().as_string(),
+               "A Test DCP"
+               );
+
        {
                Editor e (dcp->cpls()[0]->file().get());
                e.delete_lines ("<meta:ExtensionMetadata scope=\"http://isdcf.com/ns/cplmd/app\">", "</meta:ExtensionMetadata>");
@@ -2221,7 +2367,14 @@ BOOST_AUTO_TEST_CASE (verify_cpl_extension_metadata3)
 {
        boost::filesystem::path dir = "build/test/verify_cpl_extension_metadata3";
        auto dcp = make_simple (dir);
-       dcp->write_xml (dcp::SMPTE);
+       dcp->write_xml (
+               dcp::SMPTE,
+               dcp::String::compose("libdcp %1", dcp::version),
+               dcp::String::compose("libdcp %1", dcp::version),
+               dcp::LocalTime().as_string(),
+               "A Test DCP"
+               );
+
        {
                Editor e (dcp->cpls()[0]->file().get());
                e.replace ("<meta:Name>A", "<meta:NameX>A");
@@ -2242,7 +2395,14 @@ BOOST_AUTO_TEST_CASE (verify_cpl_extension_metadata4)
 {
        boost::filesystem::path dir = "build/test/verify_cpl_extension_metadata4";
        auto dcp = make_simple (dir);
-       dcp->write_xml (dcp::SMPTE);
+       dcp->write_xml (
+               dcp::SMPTE,
+               dcp::String::compose("libdcp %1", dcp::version),
+               dcp::String::compose("libdcp %1", dcp::version),
+               dcp::LocalTime().as_string(),
+               "A Test DCP"
+               );
+
        {
                Editor e (dcp->cpls()[0]->file().get());
                e.replace ("Application", "Fred");
@@ -2261,7 +2421,13 @@ BOOST_AUTO_TEST_CASE (verify_cpl_extension_metadata5)
 {
        boost::filesystem::path dir = "build/test/verify_cpl_extension_metadata5";
        auto dcp = make_simple (dir);
-       dcp->write_xml (dcp::SMPTE);
+       dcp->write_xml (
+               dcp::SMPTE,
+               dcp::String::compose("libdcp %1", dcp::version),
+               dcp::String::compose("libdcp %1", dcp::version),
+               dcp::LocalTime().as_string(),
+               "A Test DCP"
+               );
        {
                Editor e (dcp->cpls()[0]->file().get());
                e.replace ("DCP Constraints Profile", "Fred");
@@ -2280,7 +2446,14 @@ BOOST_AUTO_TEST_CASE (verify_cpl_extension_metadata6)
 {
        boost::filesystem::path dir = "build/test/verify_cpl_extension_metadata6";
        auto dcp = make_simple (dir);
-       dcp->write_xml (dcp::SMPTE);
+       dcp->write_xml (
+               dcp::SMPTE,
+               dcp::String::compose("libdcp %1", dcp::version),
+               dcp::String::compose("libdcp %1", dcp::version),
+               dcp::LocalTime().as_string(),
+               "A Test DCP"
+               );
+
        {
                Editor e (dcp->cpls()[0]->file().get());
                e.replace ("<meta:Value>", "<meta:ValueX>");
@@ -2301,7 +2474,13 @@ BOOST_AUTO_TEST_CASE (verify_cpl_extension_metadata7)
 {
        boost::filesystem::path dir = "build/test/verify_cpl_extension_metadata7";
        auto dcp = make_simple (dir);
-       dcp->write_xml (dcp::SMPTE);
+       dcp->write_xml (
+               dcp::SMPTE,
+               dcp::String::compose("libdcp %1", dcp::version),
+               dcp::String::compose("libdcp %1", dcp::version),
+               dcp::LocalTime().as_string(),
+               "A Test DCP"
+               );
        {
                Editor e (dcp->cpls()[0]->file().get());
                e.replace ("SMPTE-RDD-52:2020-Bv2.1", "Fred");
@@ -2320,7 +2499,13 @@ BOOST_AUTO_TEST_CASE (verify_cpl_extension_metadata8)
 {
        boost::filesystem::path dir = "build/test/verify_cpl_extension_metadata8";
        auto dcp = make_simple (dir);
-       dcp->write_xml (dcp::SMPTE);
+       dcp->write_xml (
+               dcp::SMPTE,
+               dcp::String::compose("libdcp %1", dcp::version),
+               dcp::String::compose("libdcp %1", dcp::version),
+               dcp::LocalTime().as_string(),
+               "A Test DCP"
+               );
        {
                Editor e (dcp->cpls()[0]->file().get());
                e.replace ("<meta:Property>", "<meta:PropertyX>");
@@ -2341,7 +2526,13 @@ BOOST_AUTO_TEST_CASE (verify_cpl_extension_metadata9)
 {
        boost::filesystem::path dir = "build/test/verify_cpl_extension_metadata9";
        auto dcp = make_simple (dir);
-       dcp->write_xml (dcp::SMPTE);
+       dcp->write_xml (
+               dcp::SMPTE,
+               dcp::String::compose("libdcp %1", dcp::version),
+               dcp::String::compose("libdcp %1", dcp::version),
+               dcp::LocalTime().as_string(),
+               "A Test DCP"
+               );
        {
                Editor e (dcp->cpls()[0]->file().get());
                e.replace ("<meta:PropertyList>", "<meta:PropertyListX>");
@@ -2376,6 +2567,7 @@ BOOST_AUTO_TEST_CASE (verify_encrypted_cpl_is_signed)
                {dir},
                {
                        { dcp::VerificationNote::VERIFY_ERROR, dcp::VerificationNote::CPL_HASH_INCORRECT },
+                       { dcp::VerificationNote::VERIFY_BV21_ERROR, dcp::VerificationNote::PKL_ANNOTATION_TEXT_DOES_NOT_MATCH_CPL_CONTENT_TITLE_TEXT },
                        { dcp::VerificationNote::VERIFY_ERROR, dcp::VerificationNote::MISSING_FFEC_IN_FEATURE },
                        { dcp::VerificationNote::VERIFY_ERROR, dcp::VerificationNote::MISSING_FFMC_IN_FEATURE },
                        { dcp::VerificationNote::VERIFY_WARNING, dcp::VerificationNote::MISSING_FFOC },