2 Copyright (C) 2018 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/algorithm/string.hpp>
47 using boost::optional;
49 static list<pair<string, optional<boost::filesystem::path> > > stages;
52 stage (string s, optional<boost::filesystem::path> p)
54 stages.push_back (make_pair (s, p));
63 static vector<boost::filesystem::path>
66 boost::filesystem::remove_all (dcp::String::compose("build/test/verify_test%1", n));
67 boost::filesystem::create_directory (dcp::String::compose("build/test/verify_test%1", n));
68 for (boost::filesystem::directory_iterator i("test/ref/DCP/dcp_test1"); i != boost::filesystem::directory_iterator(); ++i) {
69 boost::filesystem::copy_file (i->path(), dcp::String::compose("build/test/verify_test%1", n) / i->path().filename());
72 vector<boost::filesystem::path> directories;
73 directories.push_back (dcp::String::compose("build/test/verify_test%1", n));
81 Editor (boost::filesystem::path path)
84 _content = dcp::file_to_string (_path);
89 FILE* f = fopen(_path.string().c_str(), "w");
91 fwrite (_content.c_str(), _content.length(), 1, f);
95 void replace (string a, string b)
97 boost::algorithm::replace_all (_content, a, b);
101 boost::filesystem::path _path;
102 std::string _content;
105 /* Check DCP as-is (should be OK) */
106 BOOST_AUTO_TEST_CASE (verify_test1)
108 vector<boost::filesystem::path> directories = setup (1);
109 list<dcp::VerificationNote> notes = dcp::verify (directories, &stage, &progress);
111 boost::filesystem::path const cpl_file = "build/test/verify_test1/cpl_81fb54df-e1bf-4647-8788-ea7ba154375b.xml";
113 list<pair<string, optional<boost::filesystem::path> > >::const_iterator st = stages.begin();
114 BOOST_CHECK_EQUAL (st->first, "Checking DCP");
115 BOOST_REQUIRE (st->second);
116 BOOST_CHECK_EQUAL (st->second.get(), boost::filesystem::canonical("build/test/verify_test1"));
118 BOOST_CHECK_EQUAL (st->first, "Checking CPL");
119 BOOST_REQUIRE (st->second);
120 BOOST_CHECK_EQUAL (st->second.get(), boost::filesystem::canonical(cpl_file));
122 BOOST_CHECK_EQUAL (st->first, "Checking reel");
123 BOOST_REQUIRE (!st->second);
125 BOOST_CHECK_EQUAL (st->first, "Checking picture asset hash");
126 BOOST_REQUIRE (st->second);
127 BOOST_CHECK_EQUAL (st->second.get(), boost::filesystem::canonical("build/test/verify_test1/video.mxf"));
129 BOOST_CHECK_EQUAL (st->first, "Checking sound asset hash");
130 BOOST_REQUIRE (st->second);
131 BOOST_CHECK_EQUAL (st->second.get(), boost::filesystem::canonical("build/test/verify_test1/audio.mxf"));
133 BOOST_REQUIRE (st == stages.end());
135 BOOST_CHECK_EQUAL (notes.size(), 0);
138 /* Corrupt the MXFs and check that this is spotted */
139 BOOST_AUTO_TEST_CASE (verify_test2)
141 vector<boost::filesystem::path> directories = setup (2);
143 FILE* mod = fopen("build/test/verify_test2/video.mxf", "r+b");
145 fseek (mod, 4096, SEEK_SET);
147 fwrite (&x, sizeof(x), 1, mod);
150 mod = fopen("build/test/verify_test2/audio.mxf", "r+b");
152 fseek (mod, 4096, SEEK_SET);
153 BOOST_REQUIRE (fwrite (&x, sizeof(x), 1, mod) == 1);
156 list<dcp::VerificationNote> notes = dcp::verify (directories, &stage, &progress);
158 BOOST_REQUIRE_EQUAL (notes.size(), 2);
159 BOOST_CHECK_EQUAL (notes.front().type(), dcp::VerificationNote::VERIFY_ERROR);
160 BOOST_CHECK_EQUAL (notes.front().code(), dcp::VerificationNote::PICTURE_HASH_INCORRECT);
161 BOOST_CHECK_EQUAL (notes.back().type(), dcp::VerificationNote::VERIFY_ERROR);
162 BOOST_CHECK_EQUAL (notes.back().code(), dcp::VerificationNote::SOUND_HASH_INCORRECT);
165 /* Corrupt the hashes in the PKL and check that the disagreement between CPL and PKL is spotted */
166 BOOST_AUTO_TEST_CASE (verify_test3)
168 vector<boost::filesystem::path> directories = setup (3);
171 Editor e ("build/test/verify_test3/pkl_ae8a9818-872a-4f86-8493-11dfdea03e09.xml");
172 e.replace ("<Hash>", "<Hash>x");
175 list<dcp::VerificationNote> notes = dcp::verify (directories, &stage, &progress);
177 BOOST_REQUIRE_EQUAL (notes.size(), 3);
178 list<dcp::VerificationNote>::const_iterator i = notes.begin();
179 BOOST_CHECK_EQUAL (i->type(), dcp::VerificationNote::VERIFY_ERROR);
180 BOOST_CHECK_EQUAL (i->code(), dcp::VerificationNote::CPL_HASH_INCORRECT);
182 BOOST_CHECK_EQUAL (i->type(), dcp::VerificationNote::VERIFY_ERROR);
183 BOOST_CHECK_EQUAL (i->code(), dcp::VerificationNote::PKL_CPL_PICTURE_HASHES_DISAGREE);
185 BOOST_CHECK_EQUAL (i->type(), dcp::VerificationNote::VERIFY_ERROR);
186 BOOST_CHECK_EQUAL (i->code(), dcp::VerificationNote::PKL_CPL_SOUND_HASHES_DISAGREE);
190 /* Corrupt the ContentKind in the CPL */
191 BOOST_AUTO_TEST_CASE (verify_test4)
193 vector<boost::filesystem::path> directories = setup (4);
196 Editor e ("build/test/verify_test4/cpl_81fb54df-e1bf-4647-8788-ea7ba154375b.xml");
197 e.replace ("<ContentKind>", "<ContentKind>x");
200 list<dcp::VerificationNote> notes = dcp::verify (directories, &stage, &progress);
202 BOOST_REQUIRE_EQUAL (notes.size(), 1);
203 BOOST_CHECK_EQUAL (notes.front().code(), dcp::VerificationNote::GENERAL_READ);
204 BOOST_CHECK_EQUAL (*notes.front().note(), "Bad content kind 'xfeature'");
208 BOOST_AUTO_TEST_CASE (verify_test5)
210 vector<boost::filesystem::path> directories = setup (5);
212 boost::filesystem::path const cpl_file = "build/test/verify_test5/cpl_81fb54df-e1bf-4647-8788-ea7ba154375b.xml";
215 Editor e ("build/test/verify_test5/cpl_81fb54df-e1bf-4647-8788-ea7ba154375b.xml");
216 e.replace ("<FrameRate>24 1", "<FrameRate>99 1");
219 list<dcp::VerificationNote> notes = dcp::verify (directories, &stage, &progress);
221 BOOST_REQUIRE_EQUAL (notes.size(), 2);
222 BOOST_CHECK_EQUAL (notes.front().code(), dcp::VerificationNote::CPL_HASH_INCORRECT);
223 BOOST_CHECK_EQUAL (notes.back().code(), dcp::VerificationNote::INVALID_PICTURE_FRAME_RATE);
227 BOOST_AUTO_TEST_CASE (verify_test6)
229 vector<boost::filesystem::path> directories = setup (6);
231 boost::filesystem::remove ("build/test/verify_test6/video.mxf");
232 list<dcp::VerificationNote> notes = dcp::verify (directories, &stage, &progress);
234 BOOST_REQUIRE_EQUAL (notes.size(), 1);
235 BOOST_CHECK_EQUAL (notes.front().type(), dcp::VerificationNote::VERIFY_ERROR);
236 BOOST_CHECK_EQUAL (notes.front().code(), dcp::VerificationNote::GENERAL_READ);
237 BOOST_REQUIRE (static_cast<bool>(notes.front().note()));
238 BOOST_REQUIRE_EQUAL (notes.front().note().get(), "Missing asset video.mxf");
241 /* Empty asset filename in ASSETMAP */
242 BOOST_AUTO_TEST_CASE (verify_test7)
244 vector<boost::filesystem::path> directories = setup (7);
246 boost::filesystem::path const assetmap_file = "build/test/verify_test7/ASSETMAP.xml";
249 Editor e ("build/test/verify_test7/ASSETMAP.xml");
250 e.replace ("<Path>video.mxf</Path>", "<Path></Path>");
253 list<dcp::VerificationNote> notes = dcp::verify (directories, &stage, &progress);
255 BOOST_REQUIRE_EQUAL (notes.size(), 1);
256 BOOST_CHECK_EQUAL (notes.front().type(), dcp::VerificationNote::VERIFY_ERROR);
257 BOOST_CHECK_EQUAL (notes.front().code(), dcp::VerificationNote::GENERAL_READ);
258 BOOST_REQUIRE (static_cast<bool>(notes.front().note()));
259 BOOST_REQUIRE_EQUAL (notes.front().note().get(), "Asset map path is empty for asset 1fab8bb0-cfaf-4225-ad6d-01768bc10470");