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