Use feature not trailer for some tests to avoid verification errors about FFEC/FFMC.
[libdcp.git] / test / combine_test.cc
1 /*
2     Copyright (C) 2020 Carl Hetherington <cth@carlh.net>
3
4     This file is part of libdcp.
5
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.
10
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.
15
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/>.
18
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
23     including the two.
24
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.
32 */
33
34
35 #include "combine.h"
36 #include "cpl.h"
37 #include "dcp.h"
38 #include "interop_subtitle_asset.h"
39 #include "reel_subtitle_asset.h"
40 #include "reel_mono_picture_asset.h"
41 #include "reel_sound_asset.h"
42 #include "test.h"
43 #include "types.h"
44 #include "verify.h"
45 #include <boost/algorithm/string.hpp>
46 #include <boost/foreach.hpp>
47 #include <boost/optional.hpp>
48 #include <boost/test/unit_test.hpp>
49 #include <iostream>
50
51
52 using std::list;
53 using std::string;
54 using std::vector;
55 using boost::optional;
56 using std::shared_ptr;
57
58
59 static void
60 stage (string, optional<boost::filesystem::path>)
61 {
62 }
63
64
65 static void
66 progress (float)
67 {
68 }
69
70
71 static
72 void
73 dump_notes (vector<dcp::VerificationNote> const & notes)
74 {
75         BOOST_FOREACH (dcp::VerificationNote i, notes) {
76                 std::cout << dcp::note_to_string(i) << "\n";
77         }
78 }
79
80
81 static
82 void
83 check_no_errors (boost::filesystem::path path)
84 {
85         vector<boost::filesystem::path> directories;
86         directories.push_back (path);
87         auto notes = dcp::verify (directories, &stage, &progress, xsd_test);
88         vector<dcp::VerificationNote> filtered_notes;
89         std::copy_if (notes.begin(), notes.end(), std::back_inserter(filtered_notes), [](dcp::VerificationNote const& i) {
90                 return i.code() != dcp::VerificationNote::NOT_SMPTE && i.code() != dcp::VerificationNote::SUBTITLE_TOO_SHORT;
91         });
92         dump_notes (filtered_notes);
93         BOOST_CHECK (filtered_notes.empty());
94 }
95
96
97 template <class T>
98 shared_ptr<T>
99 pointer_to_id_in_vector (shared_ptr<T> needle, vector<shared_ptr<T> > haystack)
100 {
101         BOOST_FOREACH (shared_ptr<T> i, haystack) {
102                 if (i->id() == needle->id()) {
103                         return i;
104                 }
105         }
106
107         return shared_ptr<T>();
108 }
109
110
111 static
112 void
113 note_handler (dcp::NoteType, std::string)
114 {
115         // std::cout << "> " << n << "\n";
116 }
117
118
119 static
120 void
121 check_combined (vector<boost::filesystem::path> inputs, boost::filesystem::path output)
122 {
123         dcp::DCP output_dcp (output);
124         output_dcp.read ();
125
126         dcp::EqualityOptions options;
127         options.load_font_nodes_can_differ = true;
128
129         BOOST_FOREACH (boost::filesystem::path i, inputs)
130         {
131                 dcp::DCP input_dcp (i);
132                 input_dcp.read ();
133
134                 BOOST_REQUIRE (input_dcp.cpls().size() == 1);
135                 shared_ptr<dcp::CPL> input_cpl = input_dcp.cpls().front();
136
137                 shared_ptr<dcp::CPL> output_cpl = pointer_to_id_in_vector (input_cpl, output_dcp.cpls());
138                 BOOST_REQUIRE (output_cpl);
139
140                 BOOST_FOREACH (shared_ptr<dcp::Asset> i, input_dcp.assets(true)) {
141                         shared_ptr<dcp::Asset> o = pointer_to_id_in_vector(i, output_dcp.assets());
142                         BOOST_REQUIRE_MESSAGE (o, "Could not find " << i->id() << " in combined DCP.");
143                         BOOST_CHECK (i->equals(o, options, note_handler));
144                 }
145         }
146 }
147
148
149 BOOST_AUTO_TEST_CASE (combine_single_dcp_test)
150 {
151         using namespace boost::algorithm;
152         using namespace boost::filesystem;
153         boost::filesystem::path const out = "build/test/combine_single_dcp_test";
154
155         remove_all (out);
156         vector<path> inputs;
157         inputs.push_back ("test/ref/DCP/dcp_test1");
158         dcp::combine (inputs, out);
159
160         check_no_errors (out);
161         check_combined (inputs, out);
162 }
163
164
165 BOOST_AUTO_TEST_CASE (combine_two_dcps_with_same_asset_filenames_test)
166 {
167         using namespace boost::algorithm;
168         using namespace boost::filesystem;
169         boost::filesystem::path const out = "build/test/combine_two_dcps_with_same_asset_filenames_test";
170
171         shared_ptr<dcp::DCP> second = make_simple ("build/test/combine_input2");
172         second->write_xml (dcp::SMPTE);
173
174         remove_all (out);
175         vector<path> inputs;
176         inputs.push_back ("test/ref/DCP/dcp_test1");
177         inputs.push_back ("build/test/combine_input2");
178         dcp::combine (inputs, out);
179
180         check_no_errors (out);
181         check_combined (inputs, out);
182 }
183
184
185 BOOST_AUTO_TEST_CASE (combine_two_dcps_with_interop_subs_test)
186 {
187         using namespace boost::algorithm;
188         using namespace boost::filesystem;
189         boost::filesystem::path const out = "build/test/combine_two_dcps_with_interop_subs_test";
190
191         shared_ptr<dcp::DCP> first = make_simple_with_interop_subs ("build/test/combine_input1");
192         first->write_xml (dcp::INTEROP);
193
194         shared_ptr<dcp::DCP> second = make_simple_with_interop_subs ("build/test/combine_input2");
195         second->write_xml (dcp::INTEROP);
196
197         remove_all (out);
198         vector<path> inputs;
199         inputs.push_back ("build/test/combine_input1");
200         inputs.push_back ("build/test/combine_input2");
201         dcp::combine (inputs, out);
202
203         check_no_errors (out);
204         check_combined (inputs, out);
205 }
206
207
208 BOOST_AUTO_TEST_CASE (combine_two_dcps_with_smpte_subs_test)
209 {
210         using namespace boost::algorithm;
211         using namespace boost::filesystem;
212         boost::filesystem::path const out = "build/test/combine_two_dcps_with_smpte_subs_test";
213
214         shared_ptr<dcp::DCP> first = make_simple_with_smpte_subs ("build/test/combine_input1");
215         first->write_xml (dcp::SMPTE);
216
217         shared_ptr<dcp::DCP> second = make_simple_with_smpte_subs ("build/test/combine_input2");
218         second->write_xml (dcp::SMPTE);
219
220         remove_all (out);
221         vector<path> inputs;
222         inputs.push_back ("build/test/combine_input1");
223         inputs.push_back ("build/test/combine_input2");
224         dcp::combine (inputs, out);
225
226         check_no_errors (out);
227         check_combined (inputs, out);
228 }
229
230
231 BOOST_AUTO_TEST_CASE (combine_two_dcps_with_interop_ccaps_test)
232 {
233         using namespace boost::algorithm;
234         using namespace boost::filesystem;
235         boost::filesystem::path const out = "build/test/combine_two_dcps_with_interop_ccaps_test";
236
237         shared_ptr<dcp::DCP> first = make_simple_with_interop_ccaps ("build/test/combine_input1");
238         first->write_xml (dcp::INTEROP);
239
240         shared_ptr<dcp::DCP> second = make_simple_with_interop_ccaps ("build/test/combine_input2");
241         second->write_xml (dcp::INTEROP);
242
243         remove_all (out);
244         vector<path> inputs;
245         inputs.push_back ("build/test/combine_input1");
246         inputs.push_back ("build/test/combine_input2");
247         dcp::combine (inputs, out);
248
249         check_no_errors (out);
250         check_combined (inputs, out);
251 }
252
253
254 BOOST_AUTO_TEST_CASE (combine_two_dcps_with_smpte_ccaps_test)
255 {
256         using namespace boost::algorithm;
257         using namespace boost::filesystem;
258         boost::filesystem::path const out = "build/test/combine_two_dcps_with_interop_ccaps_test";
259
260         shared_ptr<dcp::DCP> first = make_simple_with_smpte_ccaps ("build/test/combine_input1");
261         first->write_xml (dcp::SMPTE);
262
263         shared_ptr<dcp::DCP> second = make_simple_with_smpte_ccaps ("build/test/combine_input2");
264         second->write_xml (dcp::SMPTE);
265
266         remove_all (out);
267         vector<path> inputs;
268         inputs.push_back ("build/test/combine_input1");
269         inputs.push_back ("build/test/combine_input2");
270         dcp::combine (inputs, out);
271
272         check_no_errors (out);
273         check_combined (inputs, out);
274 }
275
276
277 BOOST_AUTO_TEST_CASE (combine_two_multi_reel_dcps)
278 {
279         using namespace boost::algorithm;
280         using namespace boost::filesystem;
281         boost::filesystem::path const out = "build/test/combine_two_multi_reel_dcps";
282
283         shared_ptr<dcp::DCP> first = make_simple ("build/test/combine_input1", 4);
284         first->write_xml (dcp::SMPTE);
285
286         shared_ptr<dcp::DCP> second = make_simple ("build/test/combine_input2", 4);
287         second->write_xml (dcp::SMPTE);
288
289         remove_all (out);
290         vector<path> inputs;
291         inputs.push_back ("build/test/combine_input1");
292         inputs.push_back ("build/test/combine_input2");
293         dcp::combine (inputs, out);
294
295         check_no_errors (out);
296         check_combined (inputs, out);
297 }
298
299
300 BOOST_AUTO_TEST_CASE (combine_two_dcps_with_shared_asset)
301 {
302         using namespace boost::filesystem;
303         boost::filesystem::path const out = "build/test/combine_two_dcps_with_shared_asset";
304
305         shared_ptr<dcp::DCP> first = make_simple ("build/test/combine_input1", 1);
306         first->write_xml (dcp::SMPTE);
307
308         remove_all ("build/test/combine_input2");
309         shared_ptr<dcp::DCP> second(new dcp::DCP("build/test/combine_input2"));
310
311         dcp::MXFMetadata mxf_meta;
312         mxf_meta.company_name = "OpenDCP";
313         mxf_meta.product_version = "0.0.25";
314
315         shared_ptr<dcp::CPL> cpl (new dcp::CPL("A Test DCP", dcp::TRAILER));
316         cpl->set_content_version (
317                 dcp::ContentVersion("urn:uuid:75ac29aa-42ac-1234-ecae-49251abefd11","content-version-label-text")
318                 );
319
320         shared_ptr<dcp::ReelMonoPictureAsset> pic(new dcp::ReelMonoPictureAsset(simple_picture("build/test/combine_input2", ""), 0));
321         shared_ptr<dcp::ReelSoundAsset> sound(new dcp::ReelSoundAsset(first->cpls().front()->reels().front()->main_sound()->asset(), 0));
322         cpl->add (shared_ptr<dcp::Reel>(new dcp::Reel(pic, sound)));
323         second->add (cpl);
324         second->write_xml (dcp::SMPTE);
325
326         remove_all (out);
327         vector<path> inputs;
328         inputs.push_back ("build/test/combine_input1");
329         inputs.push_back ("build/test/combine_input2");
330         dcp::combine (inputs, out);
331
332         check_no_errors (out);
333         check_combined (inputs, out);
334 }
335
336
337 /* XXX: same CPL names */
338 /* XXX: Interop PNG subs */