Validate XML with xerces.
[libdcp.git] / test / verify_test.cc
index 98f37635d3205146efe11bdf1017f0e7ce8517b7..737c2fb96164fdf598db2bca35231472ab7ab6bb 100644 (file)
@@ -1,5 +1,5 @@
 /*
-    Copyright (C) 2018 Carl Hetherington <cth@carlh.net>
+    Copyright (C) 2018-2019 Carl Hetherington <cth@carlh.net>
 
     This file is part of libdcp.
 
@@ -35,6 +35,7 @@
 #include "util.h"
 #include "compose.hpp"
 #include <boost/test/unit_test.hpp>
+#include <boost/foreach.hpp>
 #include <boost/algorithm/string.hpp>
 #include <cstdio>
 #include <iostream>
@@ -102,11 +103,20 @@ private:
        std::string _content;
 };
 
+static
+void
+dump_notes (list<dcp::VerificationNote> const & notes)
+{
+       BOOST_FOREACH (dcp::VerificationNote i, notes) {
+               std::cout << dcp::note_to_string(i) << "\n";
+       }
+}
+
 /* Check DCP as-is (should be OK) */
 BOOST_AUTO_TEST_CASE (verify_test1)
 {
        vector<boost::filesystem::path> directories = setup (1);
-       list<dcp::VerificationNote> notes = dcp::verify (directories, &stage, &progress);
+       list<dcp::VerificationNote> notes = dcp::verify (directories, &stage, &progress, "xsd");
 
        boost::filesystem::path const cpl_file = "build/test/verify_test1/cpl_81fb54df-e1bf-4647-8788-ea7ba154375b.xml";
 
@@ -132,6 +142,8 @@ BOOST_AUTO_TEST_CASE (verify_test1)
        ++st;
        BOOST_REQUIRE (st == stages.end());
 
+       dump_notes (notes);
+
        BOOST_CHECK_EQUAL (notes.size(), 0);
 }
 
@@ -153,7 +165,7 @@ BOOST_AUTO_TEST_CASE (verify_test2)
        BOOST_REQUIRE (fwrite (&x, sizeof(x), 1, mod) == 1);
        fclose (mod);
 
-       list<dcp::VerificationNote> notes = dcp::verify (directories, &stage, &progress);
+       list<dcp::VerificationNote> notes = dcp::verify (directories, &stage, &progress, "xsd");
 
        BOOST_REQUIRE_EQUAL (notes.size(), 2);
        BOOST_CHECK_EQUAL (notes.front().type(), dcp::VerificationNote::VERIFY_ERROR);
@@ -172,7 +184,7 @@ BOOST_AUTO_TEST_CASE (verify_test3)
                e.replace ("<Hash>", "<Hash>x");
        }
 
-       list<dcp::VerificationNote> notes = dcp::verify (directories, &stage, &progress);
+       list<dcp::VerificationNote> notes = dcp::verify (directories, &stage, &progress, "xsd");
 
        BOOST_REQUIRE_EQUAL (notes.size(), 3);
        list<dcp::VerificationNote>::const_iterator i = notes.begin();
@@ -197,30 +209,96 @@ BOOST_AUTO_TEST_CASE (verify_test4)
                e.replace ("<ContentKind>", "<ContentKind>x");
        }
 
-       list<dcp::VerificationNote> notes = dcp::verify (directories, &stage, &progress);
+       list<dcp::VerificationNote> notes = dcp::verify (directories, &stage, &progress, "xsd");
 
        BOOST_REQUIRE_EQUAL (notes.size(), 1);
        BOOST_CHECK_EQUAL (notes.front().code(), dcp::VerificationNote::GENERAL_READ);
        BOOST_CHECK_EQUAL (*notes.front().note(), "Bad content kind 'xfeature'");
 }
 
-/* FrameRate */
-BOOST_AUTO_TEST_CASE (verify_test5)
+static
+boost::filesystem::path
+cpl (int n)
 {
-       vector<boost::filesystem::path> directories = setup (5);
+       return dcp::String::compose("build/test/verify_test%1/cpl_81fb54df-e1bf-4647-8788-ea7ba154375b.xml", n);
+}
 
-       boost::filesystem::path const cpl_file = "build/test/verify_test5/cpl_81fb54df-e1bf-4647-8788-ea7ba154375b.xml";
+static
+void check_after_replace (int n, boost::function<boost::filesystem::path (int)> file, string from, string to, dcp::VerificationNote::Code code1)
+{
+       vector<boost::filesystem::path> directories = setup (n);
 
        {
-               Editor e ("build/test/verify_test5/cpl_81fb54df-e1bf-4647-8788-ea7ba154375b.xml");
-               e.replace ("<FrameRate>24 1", "<FrameRate>99 1");
+               Editor e (file(n));
+               e.replace (from, to);
        }
 
-       list<dcp::VerificationNote> notes = dcp::verify (directories, &stage, &progress);
+       list<dcp::VerificationNote> notes = dcp::verify (directories, &stage, &progress, "xsd");
+
+       dump_notes (notes);
+
+       BOOST_REQUIRE_EQUAL (notes.size(), 1);
+       BOOST_CHECK_EQUAL (notes.front().code(), code1);
+}
+
+static
+void check_after_replace (int n, boost::function<boost::filesystem::path (int)> file, string from, string to, dcp::VerificationNote::Code code1, dcp::VerificationNote::Code code2)
+{
+       vector<boost::filesystem::path> directories = setup (n);
+
+       {
+               Editor e (file(n));
+               e.replace (from, to);
+       }
+
+       list<dcp::VerificationNote> notes = dcp::verify (directories, &stage, &progress, "xsd");
+
+       dump_notes (notes);
 
        BOOST_REQUIRE_EQUAL (notes.size(), 2);
-       BOOST_CHECK_EQUAL (notes.front().code(), dcp::VerificationNote::CPL_HASH_INCORRECT);
-       BOOST_CHECK_EQUAL (notes.back().code(), dcp::VerificationNote::INVALID_PICTURE_FRAME_RATE);
+       BOOST_CHECK_EQUAL (notes.front().code(), code1);
+       BOOST_CHECK_EQUAL (notes.back().code(), code2);
+}
+
+static
+void check_after_replace (
+       int n, boost::function<boost::filesystem::path (int)> file,
+       string from,
+       string to,
+       dcp::VerificationNote::Code code1,
+       dcp::VerificationNote::Code code2,
+       dcp::VerificationNote::Code code3
+       )
+{
+       vector<boost::filesystem::path> directories = setup (n);
+
+       {
+               Editor e (file(n));
+               e.replace (from, to);
+       }
+
+       list<dcp::VerificationNote> notes = dcp::verify (directories, &stage, &progress, "xsd");
+
+       dump_notes (notes);
+
+       BOOST_REQUIRE_EQUAL (notes.size(), 3);
+       list<dcp::VerificationNote>::const_iterator i = notes.begin ();
+       BOOST_CHECK_EQUAL (i->code(), code1);
+       ++i;
+       BOOST_CHECK_EQUAL (i->code(), code2);
+       ++i;
+       BOOST_CHECK_EQUAL (i->code(), code3);
+}
+
+/* FrameRate */
+BOOST_AUTO_TEST_CASE (verify_test5)
+{
+       check_after_replace (
+                       5, &cpl,
+                       "<FrameRate>24 1", "<FrameRate>99 1",
+                       dcp::VerificationNote::CPL_HASH_INCORRECT,
+                       dcp::VerificationNote::INVALID_PICTURE_FRAME_RATE
+                       );
 }
 
 /* Missing asset */
@@ -229,33 +307,60 @@ BOOST_AUTO_TEST_CASE (verify_test6)
        vector<boost::filesystem::path> directories = setup (6);
 
        boost::filesystem::remove ("build/test/verify_test6/video.mxf");
-       list<dcp::VerificationNote> notes = dcp::verify (directories, &stage, &progress);
+       list<dcp::VerificationNote> notes = dcp::verify (directories, &stage, &progress, "xsd");
 
        BOOST_REQUIRE_EQUAL (notes.size(), 1);
        BOOST_CHECK_EQUAL (notes.front().type(), dcp::VerificationNote::VERIFY_ERROR);
-       BOOST_CHECK_EQUAL (notes.front().code(), dcp::VerificationNote::GENERAL_READ);
-       BOOST_REQUIRE (static_cast<bool>(notes.front().note()));
-       BOOST_REQUIRE_EQUAL (notes.front().note().get(), "Missing asset video.mxf");
+       BOOST_CHECK_EQUAL (notes.front().code(), dcp::VerificationNote::Code::MISSING_ASSET);
+}
+
+static
+boost::filesystem::path
+assetmap (int n)
+{
+       return dcp::String::compose("build/test/verify_test%1/ASSETMAP.xml", n);
 }
 
 /* Empty asset filename in ASSETMAP */
 BOOST_AUTO_TEST_CASE (verify_test7)
 {
-       vector<boost::filesystem::path> directories = setup (7);
-
-       boost::filesystem::path const assetmap_file = "build/test/verify_test7/ASSETMAP.xml";
-
-       {
-               Editor e ("build/test/verify_test7/ASSETMAP.xml");
-               e.replace ("<Path>video.mxf</Path>", "<Path></Path>");
-       }
+       check_after_replace (
+                       7, &assetmap,
+                       "<Path>video.mxf</Path>", "<Path></Path>",
+                       dcp::VerificationNote::Code::EMPTY_ASSET_PATH
+                       );
+}
 
-       list<dcp::VerificationNote> notes = dcp::verify (directories, &stage, &progress);
+/* Mismatched standard */
+BOOST_AUTO_TEST_CASE (verify_test8)
+{
+       check_after_replace (
+                       8, &cpl,
+                       "http://www.smpte-ra.org/schemas/429-7/2006/CPL", "http://www.digicine.com/PROTO-ASDCP-CPL-20040511#",
+                       dcp::VerificationNote::Code::MISMATCHED_STANDARD,
+                       dcp::VerificationNote::Code::XML_VALIDATION_ERROR,
+                       dcp::VerificationNote::Code::CPL_HASH_INCORRECT
+                       );
+}
 
-       BOOST_REQUIRE_EQUAL (notes.size(), 1);
-       BOOST_CHECK_EQUAL (notes.front().type(), dcp::VerificationNote::VERIFY_ERROR);
-       BOOST_CHECK_EQUAL (notes.front().code(), dcp::VerificationNote::GENERAL_READ);
-       BOOST_REQUIRE (static_cast<bool>(notes.front().note()));
-       BOOST_REQUIRE_EQUAL (notes.front().note().get(), "Asset map path is empty for asset 1fab8bb0-cfaf-4225-ad6d-01768bc10470");
+/* Badly formatted <Id> in CPL */
+BOOST_AUTO_TEST_CASE (verify_test9)
+{
+       /* There's no CPL_HASH_INCORRECT error here because it can't find the correct hash by ID (since the ID is wrong) */
+       check_after_replace (
+                       9, &cpl,
+                       "<Id>urn:uuid:81fb54df-e1bf-4647-8788-ea7ba154375b", "<Id>urn:uuid:81fb54df-e1bf-4647-8788-ea7ba154375",
+                       dcp::VerificationNote::Code::XML_VALIDATION_ERROR
+                       );
 }
 
+/* Badly formatted <IssueDate> in CPL */
+BOOST_AUTO_TEST_CASE (verify_test10)
+{
+       check_after_replace (
+                       10, &cpl,
+                       "<IssueDate>", "<IssueDate>x",
+                       dcp::VerificationNote::Code::XML_VALIDATION_ERROR,
+                       dcp::VerificationNote::Code::CPL_HASH_INCORRECT
+                       );
+}