2 Copyright (C) 2018-2019 Carl Hetherington <cth@carlh.net>
4 This file is part of libdcp.
6 libdcp is free software; you can redistribute it and/or modify
7 it under the terms of the GNU General Public License as published by
8 the Free Software Foundation; either version 2 of the License, or
9 (at your option) any later version.
11 libdcp is distributed in the hope that it will be useful,
12 but WITHOUT ANY WARRANTY; without even the implied warranty of
13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 GNU General Public License for more details.
16 You should have received a copy of the GNU General Public License
17 along with libdcp. If not, see <http://www.gnu.org/licenses/>.
19 In addition, as a special exception, the copyright holders give
20 permission to link the code of portions of this program with the
21 OpenSSL library under certain conditions as described in each
22 individual source file, and distribute linked combinations
25 You must obey the GNU General Public License in all respects
26 for all of the code used other than OpenSSL. If you modify
27 file(s) with this exception, you may extend this exception to your
28 version of the file(s), but you are not obligated to do so. If you
29 do not wish to do so, delete this exception statement from your
30 version. If you delete this exception statement from all source
31 files in the program, then also delete it here.
36 #include "compose.hpp"
37 #include <boost/test/unit_test.hpp>
38 #include <boost/foreach.hpp>
39 #include <boost/algorithm/string.hpp>
48 using boost::optional;
50 static list<pair<string, optional<boost::filesystem::path> > > stages;
53 stage (string s, optional<boost::filesystem::path> p)
55 stages.push_back (make_pair (s, p));
64 static vector<boost::filesystem::path>
67 boost::filesystem::remove_all (dcp::String::compose("build/test/verify_test%1", n));
68 boost::filesystem::create_directory (dcp::String::compose("build/test/verify_test%1", n));
69 for (boost::filesystem::directory_iterator i("test/ref/DCP/dcp_test1"); i != boost::filesystem::directory_iterator(); ++i) {
70 boost::filesystem::copy_file (i->path(), dcp::String::compose("build/test/verify_test%1", n) / i->path().filename());
73 vector<boost::filesystem::path> directories;
74 directories.push_back (dcp::String::compose("build/test/verify_test%1", n));
82 Editor (boost::filesystem::path path)
85 _content = dcp::file_to_string (_path);
90 FILE* f = fopen(_path.string().c_str(), "w");
92 fwrite (_content.c_str(), _content.length(), 1, f);
96 void replace (string a, string b)
98 boost::algorithm::replace_all (_content, a, b);
102 boost::filesystem::path _path;
103 std::string _content;
108 dump_notes (list<dcp::VerificationNote> const & notes)
110 BOOST_FOREACH (dcp::VerificationNote i, notes) {
111 std::cout << dcp::note_to_string(i) << "\n";
115 /* Check DCP as-is (should be OK) */
116 BOOST_AUTO_TEST_CASE (verify_test1)
118 vector<boost::filesystem::path> directories = setup (1);
119 list<dcp::VerificationNote> notes = dcp::verify (directories, &stage, &progress, "xsd");
121 boost::filesystem::path const cpl_file = "build/test/verify_test1/cpl_81fb54df-e1bf-4647-8788-ea7ba154375b.xml";
123 list<pair<string, optional<boost::filesystem::path> > >::const_iterator st = stages.begin();
124 BOOST_CHECK_EQUAL (st->first, "Checking DCP");
125 BOOST_REQUIRE (st->second);
126 BOOST_CHECK_EQUAL (st->second.get(), boost::filesystem::canonical("build/test/verify_test1"));
128 BOOST_CHECK_EQUAL (st->first, "Checking CPL");
129 BOOST_REQUIRE (st->second);
130 BOOST_CHECK_EQUAL (st->second.get(), boost::filesystem::canonical(cpl_file));
132 BOOST_CHECK_EQUAL (st->first, "Checking reel");
133 BOOST_REQUIRE (!st->second);
135 BOOST_CHECK_EQUAL (st->first, "Checking picture asset hash");
136 BOOST_REQUIRE (st->second);
137 BOOST_CHECK_EQUAL (st->second.get(), boost::filesystem::canonical("build/test/verify_test1/video.mxf"));
139 BOOST_CHECK_EQUAL (st->first, "Checking sound asset hash");
140 BOOST_REQUIRE (st->second);
141 BOOST_CHECK_EQUAL (st->second.get(), boost::filesystem::canonical("build/test/verify_test1/audio.mxf"));
143 BOOST_REQUIRE (st == stages.end());
147 BOOST_CHECK_EQUAL (notes.size(), 0);
150 /* Corrupt the MXFs and check that this is spotted */
151 BOOST_AUTO_TEST_CASE (verify_test2)
153 vector<boost::filesystem::path> directories = setup (2);
155 FILE* mod = fopen("build/test/verify_test2/video.mxf", "r+b");
157 fseek (mod, 4096, SEEK_SET);
159 fwrite (&x, sizeof(x), 1, mod);
162 mod = fopen("build/test/verify_test2/audio.mxf", "r+b");
164 fseek (mod, 4096, SEEK_SET);
165 BOOST_REQUIRE (fwrite (&x, sizeof(x), 1, mod) == 1);
168 list<dcp::VerificationNote> notes = dcp::verify (directories, &stage, &progress, "xsd");
170 BOOST_REQUIRE_EQUAL (notes.size(), 2);
171 BOOST_CHECK_EQUAL (notes.front().type(), dcp::VerificationNote::VERIFY_ERROR);
172 BOOST_CHECK_EQUAL (notes.front().code(), dcp::VerificationNote::PICTURE_HASH_INCORRECT);
173 BOOST_CHECK_EQUAL (notes.back().type(), dcp::VerificationNote::VERIFY_ERROR);
174 BOOST_CHECK_EQUAL (notes.back().code(), dcp::VerificationNote::SOUND_HASH_INCORRECT);
177 /* Corrupt the hashes in the PKL and check that the disagreement between CPL and PKL is spotted */
178 BOOST_AUTO_TEST_CASE (verify_test3)
180 vector<boost::filesystem::path> directories = setup (3);
183 Editor e ("build/test/verify_test3/pkl_ae8a9818-872a-4f86-8493-11dfdea03e09.xml");
184 e.replace ("<Hash>", "<Hash>x");
187 list<dcp::VerificationNote> notes = dcp::verify (directories, &stage, &progress, "xsd");
189 BOOST_REQUIRE_EQUAL (notes.size(), 3);
190 list<dcp::VerificationNote>::const_iterator i = notes.begin();
191 BOOST_CHECK_EQUAL (i->type(), dcp::VerificationNote::VERIFY_ERROR);
192 BOOST_CHECK_EQUAL (i->code(), dcp::VerificationNote::CPL_HASH_INCORRECT);
194 BOOST_CHECK_EQUAL (i->type(), dcp::VerificationNote::VERIFY_ERROR);
195 BOOST_CHECK_EQUAL (i->code(), dcp::VerificationNote::PKL_CPL_PICTURE_HASHES_DISAGREE);
197 BOOST_CHECK_EQUAL (i->type(), dcp::VerificationNote::VERIFY_ERROR);
198 BOOST_CHECK_EQUAL (i->code(), dcp::VerificationNote::PKL_CPL_SOUND_HASHES_DISAGREE);
202 /* Corrupt the ContentKind in the CPL */
203 BOOST_AUTO_TEST_CASE (verify_test4)
205 vector<boost::filesystem::path> directories = setup (4);
208 Editor e ("build/test/verify_test4/cpl_81fb54df-e1bf-4647-8788-ea7ba154375b.xml");
209 e.replace ("<ContentKind>", "<ContentKind>x");
212 list<dcp::VerificationNote> notes = dcp::verify (directories, &stage, &progress, "xsd");
214 BOOST_REQUIRE_EQUAL (notes.size(), 1);
215 BOOST_CHECK_EQUAL (notes.front().code(), dcp::VerificationNote::GENERAL_READ);
216 BOOST_CHECK_EQUAL (*notes.front().note(), "Bad content kind 'xfeature'");
220 boost::filesystem::path
223 return dcp::String::compose("build/test/verify_test%1/cpl_81fb54df-e1bf-4647-8788-ea7ba154375b.xml", n);
227 void check_after_replace (int n, boost::function<boost::filesystem::path (int)> file, string from, string to, dcp::VerificationNote::Code code1)
229 vector<boost::filesystem::path> directories = setup (n);
233 e.replace (from, to);
236 list<dcp::VerificationNote> notes = dcp::verify (directories, &stage, &progress, "xsd");
240 BOOST_REQUIRE_EQUAL (notes.size(), 1);
241 BOOST_CHECK_EQUAL (notes.front().code(), code1);
245 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)
247 vector<boost::filesystem::path> directories = setup (n);
251 e.replace (from, to);
254 list<dcp::VerificationNote> notes = dcp::verify (directories, &stage, &progress, "xsd");
258 BOOST_REQUIRE_EQUAL (notes.size(), 2);
259 BOOST_CHECK_EQUAL (notes.front().code(), code1);
260 BOOST_CHECK_EQUAL (notes.back().code(), code2);
264 void check_after_replace (
265 int n, boost::function<boost::filesystem::path (int)> file,
268 dcp::VerificationNote::Code code1,
269 dcp::VerificationNote::Code code2,
270 dcp::VerificationNote::Code code3
273 vector<boost::filesystem::path> directories = setup (n);
277 e.replace (from, to);
280 list<dcp::VerificationNote> notes = dcp::verify (directories, &stage, &progress, "xsd");
284 BOOST_REQUIRE_EQUAL (notes.size(), 3);
285 list<dcp::VerificationNote>::const_iterator i = notes.begin ();
286 BOOST_CHECK_EQUAL (i->code(), code1);
288 BOOST_CHECK_EQUAL (i->code(), code2);
290 BOOST_CHECK_EQUAL (i->code(), code3);
294 BOOST_AUTO_TEST_CASE (verify_test5)
296 check_after_replace (
298 "<FrameRate>24 1", "<FrameRate>99 1",
299 dcp::VerificationNote::CPL_HASH_INCORRECT,
300 dcp::VerificationNote::INVALID_PICTURE_FRAME_RATE
305 BOOST_AUTO_TEST_CASE (verify_test6)
307 vector<boost::filesystem::path> directories = setup (6);
309 boost::filesystem::remove ("build/test/verify_test6/video.mxf");
310 list<dcp::VerificationNote> notes = dcp::verify (directories, &stage, &progress, "xsd");
312 BOOST_REQUIRE_EQUAL (notes.size(), 1);
313 BOOST_CHECK_EQUAL (notes.front().type(), dcp::VerificationNote::VERIFY_ERROR);
314 BOOST_CHECK_EQUAL (notes.front().code(), dcp::VerificationNote::Code::MISSING_ASSET);
318 boost::filesystem::path
321 return dcp::String::compose("build/test/verify_test%1/ASSETMAP.xml", n);
324 /* Empty asset filename in ASSETMAP */
325 BOOST_AUTO_TEST_CASE (verify_test7)
327 check_after_replace (
329 "<Path>video.mxf</Path>", "<Path></Path>",
330 dcp::VerificationNote::Code::EMPTY_ASSET_PATH
334 /* Mismatched standard */
335 BOOST_AUTO_TEST_CASE (verify_test8)
337 check_after_replace (
339 "http://www.smpte-ra.org/schemas/429-7/2006/CPL", "http://www.digicine.com/PROTO-ASDCP-CPL-20040511#",
340 dcp::VerificationNote::Code::MISMATCHED_STANDARD,
341 dcp::VerificationNote::Code::XML_VALIDATION_ERROR,
342 dcp::VerificationNote::Code::CPL_HASH_INCORRECT
346 /* Badly formatted <Id> in CPL */
347 BOOST_AUTO_TEST_CASE (verify_test9)
349 /* There's no CPL_HASH_INCORRECT error here because it can't find the correct hash by ID (since the ID is wrong) */
350 check_after_replace (
352 "<Id>urn:uuid:81fb54df-e1bf-4647-8788-ea7ba154375b", "<Id>urn:uuid:81fb54df-e1bf-4647-8788-ea7ba154375",
353 dcp::VerificationNote::Code::XML_VALIDATION_ERROR
357 /* Badly formatted <IssueDate> in CPL */
358 BOOST_AUTO_TEST_CASE (verify_test10)
360 check_after_replace (
362 "<IssueDate>", "<IssueDate>x",
363 dcp::VerificationNote::Code::XML_VALIDATION_ERROR,
364 dcp::VerificationNote::Code::CPL_HASH_INCORRECT