Properly support ContentKind scope attribute. v1.8.26
authorCarl Hetherington <cth@carlh.net>
Fri, 2 Sep 2022 23:52:14 +0000 (01:52 +0200)
committerCarl Hetherington <cth@carlh.net>
Sat, 3 Sep 2022 12:46:38 +0000 (14:46 +0200)
14 files changed:
src/content_kind.cc
src/content_kind.h
src/cpl.cc
src/verify.cc
src/verify.h
test/cpl_test.cc [new file with mode: 0644]
test/data/cpl_content_kind_test1.xml [new file with mode: 0644]
test/data/cpl_content_kind_test2.xml [new file with mode: 0644]
test/data/cpl_content_kind_test3.xml [new file with mode: 0644]
test/ref/cpl_content_kind_test1.xml [new file with mode: 0644]
test/ref/cpl_content_kind_test2.xml [new file with mode: 0644]
test/ref/cpl_content_kind_test3.xml [new file with mode: 0644]
test/verify_test.cc
test/wscript

index 4b0da53c308cef9faaa259470032abb72f017015..104394521a910f62a325c96fee411e825473918e 100644 (file)
@@ -43,6 +43,10 @@ using std::vector;
 using namespace dcp;
 
 
+static std::string const smpte_429_16_scope = "http://www.smpte-ra.org/schemas/429-16/2014/CPL-Metadata#scope/content-kind";
+static std::string const smpte_2067_3_scope = "http://www.smpte-ra.org/schemas/2067-3/2013#content-kind";
+
+
 ContentKind const ContentKind::FEATURE                     = ContentKind{"feature"};
 ContentKind const ContentKind::SHORT                       = ContentKind{"short"};
 ContentKind const ContentKind::TRAILER                     = ContentKind{"trailer"};
@@ -53,8 +57,12 @@ ContentKind const ContentKind::TEASER                      = ContentKind{"teaser
 ContentKind const ContentKind::POLICY                      = ContentKind{"policy"};
 ContentKind const ContentKind::PUBLIC_SERVICE_ANNOUNCEMENT = ContentKind{"psa"};
 ContentKind const ContentKind::ADVERTISEMENT               = ContentKind{"advertisement"};
-ContentKind const ContentKind::EPISODE                     = ContentKind{"episode"};
-ContentKind const ContentKind::PROMO                       = ContentKind{"promo"};
+ContentKind const ContentKind::CLIP                        = ContentKind{"clip", smpte_429_16_scope};
+ContentKind const ContentKind::PROMO                       = ContentKind{"promo", smpte_429_16_scope};
+ContentKind const ContentKind::STEREOCARD                  = ContentKind{"stereocard", smpte_429_16_scope};
+ContentKind const ContentKind::EPISODE                     = ContentKind{"episode", smpte_2067_3_scope};
+ContentKind const ContentKind::HIGHLIGHTS                  = ContentKind{"highlights", smpte_2067_3_scope};
+ContentKind const ContentKind::EVENT                       = ContentKind{"event", smpte_2067_3_scope};
 
 
 vector<ContentKind>
@@ -93,7 +101,7 @@ ContentKind::from_name(string name)
 bool
 dcp::operator==(ContentKind const& a, ContentKind const& b)
 {
-       return a.name() == b.name();
+       return a.name() == b.name() && a.scope() == b.scope();
 }
 
 
index 08aa17b49936aedfcc556ef1bea6fb2a46381737..39872feab2a33c88b060c110e3589b575bdca747 100644 (file)
@@ -47,10 +47,19 @@ namespace dcp {
 class ContentKind
 {
 public:
+       ContentKind(std::string name, boost::optional<std::string> scope)
+               : _name(name)
+               , _scope(scope)
+       {}
+
        std::string name() const {
                return _name;
        }
 
+       boost::optional<std::string> scope() const {
+               return _scope;
+       }
+
        static const ContentKind FEATURE;
        static const ContentKind SHORT;
        static const ContentKind TRAILER;
@@ -61,8 +70,12 @@ public:
        static const ContentKind POLICY;
        static const ContentKind PUBLIC_SERVICE_ANNOUNCEMENT;
        static const ContentKind ADVERTISEMENT;
-       static const ContentKind EPISODE;
+       static const ContentKind CLIP;
        static const ContentKind PROMO;
+       static const ContentKind STEREOCARD;
+       static const ContentKind EPISODE;
+       static const ContentKind HIGHLIGHTS;
+       static const ContentKind EVENT;
 
        static ContentKind from_name(std::string name);
        static std::vector<ContentKind> all();
@@ -73,6 +86,7 @@ private:
        {}
 
        std::string _name;
+       boost::optional<std::string> _scope;
 };
 
 
index 5e0ca2ccd70c1a49476a70c6a4e41c3973e5c986..ee1817fc57571025f8692a5b25fc0bc2a8644bc7 100644 (file)
@@ -122,7 +122,8 @@ CPL::CPL (boost::filesystem::path file)
        _creator = f.optional_string_child("Creator").get_value_or("");
        _issue_date = f.string_child ("IssueDate");
        _content_title_text = f.string_child ("ContentTitleText");
-       _content_kind = ContentKind::from_name(f.string_child("ContentKind"));
+       auto content_kind = f.node_child("ContentKind");
+       _content_kind = ContentKind(content_kind->content(), content_kind->optional_string_attribute("scope"));
        shared_ptr<cxml::Node> content_version = f.optional_node_child ("ContentVersion");
        if (content_version) {
                /* XXX: SMPTE should insist that Id is present */
@@ -198,7 +199,11 @@ CPL::write_xml (boost::filesystem::path file, shared_ptr<const CertificateChain>
        root->add_child("Issuer")->add_child_text (_issuer);
        root->add_child("Creator")->add_child_text (_creator);
        root->add_child("ContentTitleText")->add_child_text (_content_title_text);
-       root->add_child("ContentKind")->add_child_text(_content_kind.name());
+       auto content_kind = root->add_child("ContentKind");
+       content_kind->add_child_text(_content_kind.name());
+       if (_content_kind.scope()) {
+               content_kind->set_attribute("scope", *_content_kind.scope());
+       }
        if (_content_versions.empty()) {
                ContentVersion cv;
                cv.as_xml (root);
index e14a81b1d7b3b0812c62bd0d174652dd829df410..a3f7d5a7107fd201eb4f0d1b0ef1977beefda593 100644 (file)
@@ -1315,6 +1315,19 @@ dcp::verify (
                                verify_language_tag (i, notes);
                        }
 
+                       if (!cpl->content_kind().scope() || *cpl->content_kind().scope() == "http://www.smpte-ra.org/schemas/429-7/2006/CPL#standard-content") {
+                               /* This is a content kind from http://www.smpte-ra.org/schemas/429-7/2006/CPL#standard-content; make sure it's one
+                                * of the approved ones.
+                                */
+                               auto all = ContentKind::all();
+                               auto name = cpl->content_kind().name();
+                               transform(name.begin(), name.end(), name.begin(), ::tolower);
+                               auto iter = std::find_if(all.begin(), all.end(), [name](ContentKind const& k) { return !k.scope() && k.name() == name; });
+                               if (iter == all.end()) {
+                                       notes.push_back({VerificationNote::Type::ERROR, VerificationNote::Code::INVALID_CONTENT_KIND, cpl->content_kind().name()});
+                               }
+                       }
+
                        if (cpl->release_territory()) {
                                if (!cpl->release_territory_scope() || cpl->release_territory_scope().get() != "http://www.smpte-ra.org/schemas/429-16/2014/CPL-Metadata#scope/release-territory/UNM49") {
                                        auto terr = cpl->release_territory().get();
@@ -1770,6 +1783,8 @@ dcp::note_to_string (VerificationNote note)
                return "There is an <EntryPoint> node inside a <MainMarkers>.";
        case VerificationNote::Code::UNEXPECTED_DURATION:
                return "There is an <Duration> node inside a <MainMarkers>.";
+       case VerificationNote::Code::INVALID_CONTENT_KIND:
+               return String::compose("<ContentKind> has an invalid value %1.", note.note().get());
        }
 
        return "";
index 3dd7d125d369048e14716db36fcf011fb5f8d672..baa36138e4b7e6f446936c77ae8a2dd245c151c2 100644 (file)
@@ -396,7 +396,9 @@ public:
                /** Some <MainMarkers> asset has an <EntryPoint> that should not be there */
                UNEXPECTED_ENTRY_POINT,
                /** Some <MainMarkers> asset has an <Duration> that should not be there */
-               UNEXPECTED_DURATION
+               UNEXPECTED_DURATION,
+               /** A <ContentKind> has been specified with either no scope or the SMPTE 429-7 scope, but which is not one of those allowed */
+               INVALID_CONTENT_KIND
        };
 
        VerificationNote (Type type, Code code)
diff --git a/test/cpl_test.cc b/test/cpl_test.cc
new file mode 100644 (file)
index 0000000..cc51c12
--- /dev/null
@@ -0,0 +1,71 @@
+/*
+    Copyright (C) 2022 Carl Hetherington <cth@carlh.net>
+
+    This file is part of libdcp.
+
+    libdcp is free software; you can redistribute it and/or modify
+    it under the terms of the GNU General Public License as published by
+    the Free Software Foundation; either version 2 of the License, or
+    (at your option) any later version.
+
+    libdcp is distributed in the hope that it will be useful,
+    but WITHOUT ANY WARRANTY; without even the implied warranty of
+    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+    GNU General Public License for more details.
+
+    You should have received a copy of the GNU General Public License
+    along with libdcp.  If not, see <http://www.gnu.org/licenses/>.
+
+    In addition, as a special exception, the copyright holders give
+    permission to link the code of portions of this program with the
+    OpenSSL library under certain conditions as described in each
+    individual source file, and distribute linked combinations
+    including the two.
+
+    You must obey the GNU General Public License in all respects
+    for all of the code used other than OpenSSL.  If you modify
+    file(s) with this exception, you may extend this exception to your
+    version of the file(s), but you are not obligated to do so.  If you
+    do not wish to do so, delete this exception statement from your
+    version.  If you delete this exception statement from all source
+    files in the program, then also delete it here.
+*/
+
+
+#include "cpl.h"
+#include "test.h"
+#include <boost/test/unit_test.hpp>
+
+
+BOOST_AUTO_TEST_CASE(cpl_content_kind_test1)
+{
+       dcp::CPL cpl("test/data/cpl_content_kind_test1.xml");
+       BOOST_CHECK_EQUAL(cpl.content_kind().name(), "feature");
+       BOOST_CHECK(!cpl.content_kind().scope());
+       cpl.write_xml("build/test/cpl_content_kind_test1.xml", {});
+       check_xml(dcp::file_to_string("test/ref/cpl_content_kind_test1.xml"), dcp::file_to_string("build/test/cpl_content_kind_test1.xml"), {});
+}
+
+
+BOOST_AUTO_TEST_CASE(cpl_content_kind_test2)
+{
+       dcp::CPL cpl("test/data/cpl_content_kind_test2.xml");
+       BOOST_CHECK_EQUAL(cpl.content_kind().name(), "clip");
+       BOOST_REQUIRE(static_cast<bool>(cpl.content_kind().scope()));
+       BOOST_CHECK_EQUAL(*cpl.content_kind().scope(), "http://www.smpte-ra.org/schemas/429-16/2014/CPL-Metadata#scope/content-kind");
+       cpl.write_xml("build/test/cpl_content_kind_test2.xml", {});
+       check_xml(dcp::file_to_string("test/ref/cpl_content_kind_test2.xml"), dcp::file_to_string("build/test/cpl_content_kind_test2.xml"), {});
+}
+
+
+BOOST_AUTO_TEST_CASE(cpl_content_kind_test3)
+{
+       dcp::CPL cpl("test/data/cpl_content_kind_test3.xml");
+       BOOST_CHECK_EQUAL(cpl.content_kind().name(), "tangoadvert");
+       BOOST_REQUIRE(static_cast<bool>(cpl.content_kind().scope()));
+       BOOST_CHECK_EQUAL(*cpl.content_kind().scope(), "youvebeentangoed");
+       cpl.write_xml("build/test/cpl_content_kind_test3.xml", {});
+       check_xml(dcp::file_to_string("test/ref/cpl_content_kind_test3.xml"), dcp::file_to_string("build/test/cpl_content_kind_test3.xml"), {});
+}
+
+
diff --git a/test/data/cpl_content_kind_test1.xml b/test/data/cpl_content_kind_test1.xml
new file mode 100644 (file)
index 0000000..7fcf2a1
--- /dev/null
@@ -0,0 +1,32 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<CompositionPlaylist xmlns="http://www.smpte-ra.org/schemas/429-7/2006/CPL">
+  <Id>urn:uuid:81fb54df-e1bf-4647-8788-ea7ba154375b</Id>
+  <AnnotationText></AnnotationText>
+  <IssueDate>2020-08-28T13:35:06+02:00</IssueDate>
+  <Issuer>libdcp1.6.4devel</Issuer>
+  <Creator>libdcp1.6.4devel</Creator>
+  <ContentTitleText></ContentTitleText>
+  <ContentKind>feature</ContentKind>
+  <ContentVersion>
+    <Id>some-id</Id>
+    <LabelText>version 1</LabelText>
+  </ContentVersion>
+  <RatingList/>
+  <ReelList>
+    <Reel>
+      <Id>urn:uuid:46c3eb45-15e5-47d6-8684-d8641e4dc516</Id>
+      <AssetList>
+        <MainPicture>
+          <Id>urn:uuid:e98d059d-645f-4343-a30f-edc61d58b8e0</Id>
+          <EditRate>24 1</EditRate>
+          <IntrinsicDuration>24</IntrinsicDuration>
+          <EntryPoint>0</EntryPoint>
+          <Duration>24</Duration>
+          <Hash>JtPL3uT3jyKMLysaqgdBWQb/n2E=</Hash>
+          <FrameRate>24 1</FrameRate>
+          <ScreenAspectRatio>1998 1080</ScreenAspectRatio>
+        </MainPicture>
+      </AssetList>
+    </Reel>
+  </ReelList>
+</CompositionPlaylist>
diff --git a/test/data/cpl_content_kind_test2.xml b/test/data/cpl_content_kind_test2.xml
new file mode 100644 (file)
index 0000000..7cdf114
--- /dev/null
@@ -0,0 +1,32 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<CompositionPlaylist xmlns="http://www.smpte-ra.org/schemas/429-7/2006/CPL">
+  <Id>urn:uuid:81fb54df-e1bf-4647-8788-ea7ba154375b</Id>
+  <AnnotationText></AnnotationText>
+  <IssueDate>2020-08-28T13:35:06+02:00</IssueDate>
+  <Issuer>libdcp1.6.4devel</Issuer>
+  <Creator>libdcp1.6.4devel</Creator>
+  <ContentTitleText></ContentTitleText>
+  <ContentKind scope="http://www.smpte-ra.org/schemas/429-16/2014/CPL-Metadata#scope/content-kind">clip</ContentKind>
+  <ContentVersion>
+    <Id>some-id</Id>
+    <LabelText>version 1</LabelText>
+  </ContentVersion>
+  <RatingList/>
+  <ReelList>
+    <Reel>
+      <Id>urn:uuid:46c3eb45-15e5-47d6-8684-d8641e4dc516</Id>
+      <AssetList>
+        <MainPicture>
+          <Id>urn:uuid:e98d059d-645f-4343-a30f-edc61d58b8e0</Id>
+          <EditRate>24 1</EditRate>
+          <IntrinsicDuration>24</IntrinsicDuration>
+          <EntryPoint>0</EntryPoint>
+          <Duration>24</Duration>
+          <Hash>JtPL3uT3jyKMLysaqgdBWQb/n2E=</Hash>
+          <FrameRate>24 1</FrameRate>
+          <ScreenAspectRatio>1998 1080</ScreenAspectRatio>
+        </MainPicture>
+      </AssetList>
+    </Reel>
+  </ReelList>
+</CompositionPlaylist>
diff --git a/test/data/cpl_content_kind_test3.xml b/test/data/cpl_content_kind_test3.xml
new file mode 100644 (file)
index 0000000..e67df3a
--- /dev/null
@@ -0,0 +1,32 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<CompositionPlaylist xmlns="http://www.smpte-ra.org/schemas/429-7/2006/CPL">
+  <Id>urn:uuid:81fb54df-e1bf-4647-8788-ea7ba154375b</Id>
+  <AnnotationText></AnnotationText>
+  <IssueDate>2020-08-28T13:35:06+02:00</IssueDate>
+  <Issuer>libdcp1.6.4devel</Issuer>
+  <Creator>libdcp1.6.4devel</Creator>
+  <ContentTitleText></ContentTitleText>
+  <ContentKind scope="youvebeentangoed">tangoadvert</ContentKind>
+  <ContentVersion>
+    <Id>some-id</Id>
+    <LabelText>version 1</LabelText>
+  </ContentVersion>
+  <RatingList/>
+  <ReelList>
+    <Reel>
+      <Id>urn:uuid:46c3eb45-15e5-47d6-8684-d8641e4dc516</Id>
+      <AssetList>
+        <MainPicture>
+          <Id>urn:uuid:e98d059d-645f-4343-a30f-edc61d58b8e0</Id>
+          <EditRate>24 1</EditRate>
+          <IntrinsicDuration>24</IntrinsicDuration>
+          <EntryPoint>0</EntryPoint>
+          <Duration>24</Duration>
+          <Hash>JtPL3uT3jyKMLysaqgdBWQb/n2E=</Hash>
+          <FrameRate>24 1</FrameRate>
+          <ScreenAspectRatio>1998 1080</ScreenAspectRatio>
+        </MainPicture>
+      </AssetList>
+    </Reel>
+  </ReelList>
+</CompositionPlaylist>
diff --git a/test/ref/cpl_content_kind_test1.xml b/test/ref/cpl_content_kind_test1.xml
new file mode 100644 (file)
index 0000000..7fcf2a1
--- /dev/null
@@ -0,0 +1,32 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<CompositionPlaylist xmlns="http://www.smpte-ra.org/schemas/429-7/2006/CPL">
+  <Id>urn:uuid:81fb54df-e1bf-4647-8788-ea7ba154375b</Id>
+  <AnnotationText></AnnotationText>
+  <IssueDate>2020-08-28T13:35:06+02:00</IssueDate>
+  <Issuer>libdcp1.6.4devel</Issuer>
+  <Creator>libdcp1.6.4devel</Creator>
+  <ContentTitleText></ContentTitleText>
+  <ContentKind>feature</ContentKind>
+  <ContentVersion>
+    <Id>some-id</Id>
+    <LabelText>version 1</LabelText>
+  </ContentVersion>
+  <RatingList/>
+  <ReelList>
+    <Reel>
+      <Id>urn:uuid:46c3eb45-15e5-47d6-8684-d8641e4dc516</Id>
+      <AssetList>
+        <MainPicture>
+          <Id>urn:uuid:e98d059d-645f-4343-a30f-edc61d58b8e0</Id>
+          <EditRate>24 1</EditRate>
+          <IntrinsicDuration>24</IntrinsicDuration>
+          <EntryPoint>0</EntryPoint>
+          <Duration>24</Duration>
+          <Hash>JtPL3uT3jyKMLysaqgdBWQb/n2E=</Hash>
+          <FrameRate>24 1</FrameRate>
+          <ScreenAspectRatio>1998 1080</ScreenAspectRatio>
+        </MainPicture>
+      </AssetList>
+    </Reel>
+  </ReelList>
+</CompositionPlaylist>
diff --git a/test/ref/cpl_content_kind_test2.xml b/test/ref/cpl_content_kind_test2.xml
new file mode 100644 (file)
index 0000000..7cdf114
--- /dev/null
@@ -0,0 +1,32 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<CompositionPlaylist xmlns="http://www.smpte-ra.org/schemas/429-7/2006/CPL">
+  <Id>urn:uuid:81fb54df-e1bf-4647-8788-ea7ba154375b</Id>
+  <AnnotationText></AnnotationText>
+  <IssueDate>2020-08-28T13:35:06+02:00</IssueDate>
+  <Issuer>libdcp1.6.4devel</Issuer>
+  <Creator>libdcp1.6.4devel</Creator>
+  <ContentTitleText></ContentTitleText>
+  <ContentKind scope="http://www.smpte-ra.org/schemas/429-16/2014/CPL-Metadata#scope/content-kind">clip</ContentKind>
+  <ContentVersion>
+    <Id>some-id</Id>
+    <LabelText>version 1</LabelText>
+  </ContentVersion>
+  <RatingList/>
+  <ReelList>
+    <Reel>
+      <Id>urn:uuid:46c3eb45-15e5-47d6-8684-d8641e4dc516</Id>
+      <AssetList>
+        <MainPicture>
+          <Id>urn:uuid:e98d059d-645f-4343-a30f-edc61d58b8e0</Id>
+          <EditRate>24 1</EditRate>
+          <IntrinsicDuration>24</IntrinsicDuration>
+          <EntryPoint>0</EntryPoint>
+          <Duration>24</Duration>
+          <Hash>JtPL3uT3jyKMLysaqgdBWQb/n2E=</Hash>
+          <FrameRate>24 1</FrameRate>
+          <ScreenAspectRatio>1998 1080</ScreenAspectRatio>
+        </MainPicture>
+      </AssetList>
+    </Reel>
+  </ReelList>
+</CompositionPlaylist>
diff --git a/test/ref/cpl_content_kind_test3.xml b/test/ref/cpl_content_kind_test3.xml
new file mode 100644 (file)
index 0000000..e67df3a
--- /dev/null
@@ -0,0 +1,32 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<CompositionPlaylist xmlns="http://www.smpte-ra.org/schemas/429-7/2006/CPL">
+  <Id>urn:uuid:81fb54df-e1bf-4647-8788-ea7ba154375b</Id>
+  <AnnotationText></AnnotationText>
+  <IssueDate>2020-08-28T13:35:06+02:00</IssueDate>
+  <Issuer>libdcp1.6.4devel</Issuer>
+  <Creator>libdcp1.6.4devel</Creator>
+  <ContentTitleText></ContentTitleText>
+  <ContentKind scope="youvebeentangoed">tangoadvert</ContentKind>
+  <ContentVersion>
+    <Id>some-id</Id>
+    <LabelText>version 1</LabelText>
+  </ContentVersion>
+  <RatingList/>
+  <ReelList>
+    <Reel>
+      <Id>urn:uuid:46c3eb45-15e5-47d6-8684-d8641e4dc516</Id>
+      <AssetList>
+        <MainPicture>
+          <Id>urn:uuid:e98d059d-645f-4343-a30f-edc61d58b8e0</Id>
+          <EditRate>24 1</EditRate>
+          <IntrinsicDuration>24</IntrinsicDuration>
+          <EntryPoint>0</EntryPoint>
+          <Duration>24</Duration>
+          <Hash>JtPL3uT3jyKMLysaqgdBWQb/n2E=</Hash>
+          <FrameRate>24 1</FrameRate>
+          <ScreenAspectRatio>1998 1080</ScreenAspectRatio>
+        </MainPicture>
+      </AssetList>
+    </Reel>
+  </ReelList>
+</CompositionPlaylist>
index 20bef0fa436fe00e3bc0aa2bf6e97436957a73a7..0b65c9d38d7fb5e62e5567e0d3f1098032b29d40 100644 (file)
@@ -419,8 +419,10 @@ BOOST_AUTO_TEST_CASE (verify_failed_read_content_kind)
 
        check_verify_result (
                { dir },
-               {{ dcp::VerificationNote::Type::ERROR, dcp::VerificationNote::Code::FAILED_READ, string("Bad content kind 'xtrailer'")}}
-               );
+               {
+                       { dcp::VerificationNote::Type::ERROR, dcp::VerificationNote::Code::MISMATCHED_CPL_HASHES, dcp_test1_cpl_id, canonical(dir / dcp_test1_cpl) },
+                       { dcp::VerificationNote::Type::ERROR, dcp::VerificationNote::Code::INVALID_CONTENT_KIND, string("xtrailer") }
+               });
 }
 
 
@@ -3159,3 +3161,51 @@ BOOST_AUTO_TEST_CASE (verify_unexpected_things_in_main_markers)
                });
 }
 
+
+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();
+
+       {
+               Editor e(find_cpl(dir));
+               e.replace("trailer", "trip");
+       }
+
+       dcp::CPL cpl (find_cpl(dir));
+
+       check_verify_result (
+               { dir },
+               {
+                       { dcp::VerificationNote::Type::ERROR, dcp::VerificationNote::Code::MISMATCHED_CPL_HASHES, cpl.id(), canonical(find_cpl(dir)) },
+                       { dcp::VerificationNote::Type::ERROR, dcp::VerificationNote::Code::INVALID_CONTENT_KIND, string("trip") }
+               });
+
+}
+
+
+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();
+
+       {
+               Editor e(find_cpl(dir));
+               e.replace("<ContentKind>trailer</ContentKind>", "<ContentKind scope=\"http://bobs.contents/\">trip</ContentKind>");
+       }
+
+       dcp::CPL cpl (find_cpl(dir));
+
+       check_verify_result (
+               { dir },
+               {
+                       { dcp::VerificationNote::Type::ERROR, dcp::VerificationNote::Code::MISMATCHED_CPL_HASHES, cpl.id(), canonical(find_cpl(dir)) },
+               });
+
+}
index 340c6e7db73c1ae76365bbe38c40b72b6a84e069..b6cec631d5b5def49646373dc0743860b365b2be 100644 (file)
@@ -71,6 +71,7 @@ def build(bld):
                  colour_test.cc
                  colour_conversion_test.cc
                  combine_test.cc
+                 cpl_test.cc
                  cpl_metadata_test.cc
                  cpl_sar_test.cc
                  cpl_ratings_test.cc