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