Fix strange Windows build error introduced in 6c37cc1979b2a01205a888c4c98f3334685ee8dd
[libdcp.git] / test / cpl_metadata_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 "certificate_chain.h"
36 #include "cpl.h"
37 #include "exceptions.h"
38 #include "language_tag.h"
39 #include "reel.h"
40 #include "reel_subtitle_asset.h"
41 #include "stream_operators.h"
42 #include "test.h"
43 #include <memory>
44 #include <boost/test/unit_test.hpp>
45
46
47 using std::list;
48 using std::string;
49 using std::vector;
50 using std::shared_ptr;
51
52
53 BOOST_AUTO_TEST_CASE (cpl_metadata_bad_values_test)
54 {
55         dcp::CPL cpl("", dcp::ContentKind::FEATURE);
56         BOOST_CHECK_THROW (cpl.set_version_number(-1), dcp::BadSettingError);
57
58         vector<dcp::ContentVersion> cv;
59         cv.push_back (dcp::ContentVersion("same-id", "version 1"));
60         cv.push_back (dcp::ContentVersion("same-id", "version 2"));
61         BOOST_CHECK_THROW (cpl.set_content_versions(cv), dcp::DuplicateIdError);
62 }
63
64
65 BOOST_AUTO_TEST_CASE (main_sound_configuration_test1)
66 {
67         dcp::MainSoundConfiguration msc("51/L,R,C,LFE,-,-");
68         BOOST_CHECK_EQUAL (msc.to_string(), "51/L,R,C,LFE,-,-");
69         BOOST_CHECK_EQUAL (msc.channels(), 6);
70         BOOST_CHECK_EQUAL (msc.field(), dcp::MCASoundField::FIVE_POINT_ONE);
71         BOOST_CHECK_EQUAL (msc.mapping(0).get(), dcp::Channel::LEFT);
72         BOOST_CHECK_EQUAL (msc.mapping(1).get(), dcp::Channel::RIGHT);
73         BOOST_CHECK_EQUAL (msc.mapping(2).get(), dcp::Channel::CENTRE);
74         BOOST_CHECK_EQUAL (msc.mapping(3).get(), dcp::Channel::LFE);
75         BOOST_CHECK (!msc.mapping(4));
76         BOOST_CHECK (!msc.mapping(5));
77 }
78
79
80 BOOST_AUTO_TEST_CASE (main_sound_configuration_test2)
81 {
82         dcp::MainSoundConfiguration msc("71/L,R,C,LFE,-,-");
83         BOOST_CHECK_EQUAL (msc.to_string(), "71/L,R,C,LFE,-,-");
84         BOOST_CHECK_EQUAL (msc.channels(), 6);
85         BOOST_CHECK_EQUAL (msc.field(), dcp::MCASoundField::SEVEN_POINT_ONE);
86         BOOST_CHECK_EQUAL (msc.mapping(0).get(), dcp::Channel::LEFT);
87         BOOST_CHECK_EQUAL (msc.mapping(1).get(), dcp::Channel::RIGHT);
88         BOOST_CHECK_EQUAL (msc.mapping(2).get(), dcp::Channel::CENTRE);
89         BOOST_CHECK_EQUAL (msc.mapping(3).get(), dcp::Channel::LFE);
90         BOOST_CHECK (!msc.mapping(4));
91         BOOST_CHECK (!msc.mapping(5));
92 }
93
94
95 BOOST_AUTO_TEST_CASE (main_sound_configuration_test3)
96 {
97         dcp::MainSoundConfiguration msc("71/L,-,C,LFE,Lss,Rss");
98         BOOST_CHECK_EQUAL (msc.to_string(), "71/L,-,C,LFE,Lss,Rss");
99         BOOST_CHECK_EQUAL (msc.channels(), 6);
100         BOOST_CHECK_EQUAL (msc.field(), dcp::MCASoundField::SEVEN_POINT_ONE);
101         BOOST_CHECK_EQUAL (msc.mapping(0).get(), dcp::Channel::LEFT);
102         BOOST_CHECK (!msc.mapping(1));
103         BOOST_CHECK_EQUAL (msc.mapping(2).get(), dcp::Channel::CENTRE);
104         BOOST_CHECK_EQUAL (msc.mapping(3).get(), dcp::Channel::LFE);
105         BOOST_CHECK_EQUAL (msc.mapping(4).get(), dcp::Channel::LS);
106         BOOST_CHECK_EQUAL (msc.mapping(5).get(), dcp::Channel::RS);
107 }
108
109
110 BOOST_AUTO_TEST_CASE (main_sound_configuration_test4)
111 {
112         dcp::MainSoundConfiguration msc("71/L,-,C,LFE,Lss,Rss,-,-,-,-,-,-,-,-,-");
113         BOOST_CHECK_EQUAL (msc.to_string(), "71/L,-,C,LFE,Lss,Rss,-,-,-,-,-,-,-,-,-");
114         BOOST_CHECK_EQUAL (msc.channels(), 15);
115         BOOST_CHECK_EQUAL (msc.field(), dcp::MCASoundField::SEVEN_POINT_ONE);
116         BOOST_CHECK_EQUAL (msc.mapping(0).get(), dcp::Channel::LEFT);
117         BOOST_CHECK (!msc.mapping(1));
118         BOOST_CHECK_EQUAL (msc.mapping(2).get(), dcp::Channel::CENTRE);
119         BOOST_CHECK_EQUAL (msc.mapping(3).get(), dcp::Channel::LFE);
120         BOOST_CHECK_EQUAL (msc.mapping(4).get(), dcp::Channel::LS);
121         BOOST_CHECK_EQUAL (msc.mapping(5).get(), dcp::Channel::RS);
122         for (int i = 6; i < 15; ++i) {
123                 BOOST_CHECK (!msc.mapping(i));
124         }
125 }
126
127
128 BOOST_AUTO_TEST_CASE (main_sound_configuration_test5)
129 {
130         dcp::MainSoundConfiguration msc("71/L,-,C,LFE,Lss,Rss,HI,VIN,-,-,Lrs,Rrs,DBOX,FSKSync,SLVS");
131         BOOST_CHECK_EQUAL (msc.to_string(), "71/L,-,C,LFE,Lss,Rss,HI,VIN,-,-,Lrs,Rrs,DBOX,FSKSync,SLVS");
132         BOOST_CHECK_EQUAL (msc.channels(), 15);
133         BOOST_CHECK_EQUAL (msc.field(), dcp::MCASoundField::SEVEN_POINT_ONE);
134         BOOST_CHECK_EQUAL (msc.mapping(0).get(), dcp::Channel::LEFT);
135         BOOST_CHECK (!msc.mapping(1));
136         BOOST_CHECK_EQUAL (msc.mapping(2).get(), dcp::Channel::CENTRE);
137         BOOST_CHECK_EQUAL (msc.mapping(3).get(), dcp::Channel::LFE);
138         BOOST_CHECK_EQUAL (msc.mapping(4).get(), dcp::Channel::LS);
139         BOOST_CHECK_EQUAL (msc.mapping(5).get(), dcp::Channel::RS);
140         BOOST_CHECK_EQUAL (msc.mapping(6).get(), dcp::Channel::HI);
141         BOOST_CHECK_EQUAL (msc.mapping(7).get(), dcp::Channel::VI);
142         BOOST_CHECK (!msc.mapping(8));
143         BOOST_CHECK (!msc.mapping(9));
144         BOOST_CHECK_EQUAL (msc.mapping(10).get(), dcp::Channel::BSL);
145         BOOST_CHECK_EQUAL (msc.mapping(11).get(), dcp::Channel::BSR);
146         BOOST_CHECK_EQUAL (msc.mapping(12).get(), dcp::Channel::MOTION_DATA);
147         BOOST_CHECK_EQUAL (msc.mapping(13).get(), dcp::Channel::SYNC_SIGNAL);
148         BOOST_CHECK_EQUAL (msc.mapping(14).get(), dcp::Channel::SIGN_LANGUAGE);
149 }
150
151
152 BOOST_AUTO_TEST_CASE (luminance_test1)
153 {
154         BOOST_CHECK_NO_THROW (dcp::Luminance(4, dcp::Luminance::Unit::CANDELA_PER_SQUARE_METRE));
155         BOOST_CHECK_THROW (dcp::Luminance(-4, dcp::Luminance::Unit::CANDELA_PER_SQUARE_METRE), dcp::MiscError);
156 }
157
158
159 BOOST_AUTO_TEST_CASE (luminance_test2)
160 {
161         shared_ptr<cxml::Document> doc (new cxml::Document("Luminance"));
162
163         doc->read_string (
164                 "<Luminance units=\"candela-per-square-metre\">4.5</Luminance>"
165                 );
166
167         dcp::Luminance lum (doc);
168         BOOST_CHECK (lum.unit() == dcp::Luminance::Unit::CANDELA_PER_SQUARE_METRE);
169         BOOST_CHECK_CLOSE (lum.value(), 4.5, 0.1);
170 }
171
172
173 BOOST_AUTO_TEST_CASE (luminance_test3)
174 {
175         shared_ptr<cxml::Document> doc (new cxml::Document("Luminance"));
176
177         doc->read_string (
178                 "<Luminance units=\"candela-per-square-motre\">4.5</Luminance>"
179                 );
180
181         BOOST_CHECK_THROW (new dcp::Luminance(doc), dcp::XMLError);
182 }
183
184
185 BOOST_AUTO_TEST_CASE (luminance_test4)
186 {
187         shared_ptr<cxml::Document> doc (new cxml::Document("Luminance"));
188
189         doc->read_string (
190                 "<Luminance units=\"candela-per-square-metre\">-4.5</Luminance>"
191                 );
192
193         /* We tolerate out-of-range values when reading from XML */
194         dcp::Luminance lum (doc);
195         BOOST_CHECK (lum.unit() == dcp::Luminance::Unit::CANDELA_PER_SQUARE_METRE);
196         BOOST_CHECK_CLOSE (lum.value(), -4.5, 0.1);
197 }
198
199
200 /** A test where most CPL metadata is present */
201 BOOST_AUTO_TEST_CASE (cpl_metadata_read_test1)
202 {
203         dcp::CPL cpl("test/ref/cpl_metadata_test1.xml");
204
205         BOOST_CHECK_EQUAL (cpl.full_content_title_text().get(), "full-content-title");
206         BOOST_CHECK (cpl.full_content_title_text_language().get() == "de");
207         BOOST_CHECK (cpl.release_territory().get() == "ES");
208         BOOST_CHECK_EQUAL (cpl.version_number().get(), 2);
209         BOOST_CHECK_EQUAL (cpl.status().get(), dcp::Status::FINAL);
210         BOOST_CHECK_EQUAL (cpl.chain().get(), "the-chain");
211         BOOST_CHECK_EQUAL (cpl.distributor().get(), "the-distributor");
212         BOOST_CHECK_EQUAL (cpl.facility().get(), "the-facility");
213         BOOST_CHECK (cpl.luminance() == dcp::Luminance(4.5, dcp::Luminance::Unit::FOOT_LAMBERT));
214
215         dcp::MainSoundConfiguration msc(cpl.main_sound_configuration().get());
216         BOOST_CHECK_EQUAL (msc.mapping(0).get(), dcp::Channel::LEFT);
217         BOOST_CHECK_EQUAL (msc.mapping(1).get(), dcp::Channel::RIGHT);
218         BOOST_CHECK_EQUAL (msc.mapping(2).get(), dcp::Channel::CENTRE);
219         BOOST_CHECK_EQUAL (msc.mapping(3).get(), dcp::Channel::LFE);
220         BOOST_CHECK (!msc.mapping(4));
221         BOOST_CHECK (!msc.mapping(5));
222         BOOST_CHECK (!msc.mapping(6));
223         BOOST_CHECK (!msc.mapping(7));
224         BOOST_CHECK (!msc.mapping(8));
225         BOOST_CHECK (!msc.mapping(9));
226         BOOST_CHECK (!msc.mapping(10));
227         BOOST_CHECK (!msc.mapping(11));
228         BOOST_CHECK (!msc.mapping(12));
229         BOOST_CHECK_EQUAL (msc.mapping(13).get(), dcp::Channel::SYNC_SIGNAL);
230
231         BOOST_CHECK_EQUAL (cpl.main_sound_sample_rate().get(), 48000);
232         BOOST_CHECK (cpl.main_picture_stored_area().get() == dcp::Size(1998, 1080));
233         BOOST_CHECK (cpl.main_picture_active_area().get() == dcp::Size(1440, 1080));
234
235         auto reels = cpl.reels ();
236         BOOST_REQUIRE_EQUAL (reels.size(), 1);
237         BOOST_REQUIRE (reels.front()->main_subtitle()->language());
238         BOOST_CHECK_EQUAL (reels.front()->main_subtitle()->language().get(), "de-DE");
239
240         vector<string> asl = cpl.additional_subtitle_languages();
241         BOOST_REQUIRE_EQUAL (asl.size(), 2);
242         BOOST_CHECK_EQUAL (asl[0], "en-US");
243         BOOST_CHECK_EQUAL (asl[1], "fr-ZA");
244
245         BOOST_CHECK (cpl.additional_subtitle_languages() == asl);
246 }
247
248
249 /** A test where most CPL metadata is present */
250 BOOST_AUTO_TEST_CASE (cpl_metadata_write_test1)
251 {
252         RNGFixer fix;
253
254         dcp::CPL cpl("", dcp::ContentKind::FEATURE);
255         cpl.set_issue_date ("2020-08-28T13:35:06+02:00");
256
257         vector<dcp::ContentVersion> cv;
258         cv.push_back (dcp::ContentVersion("some-id", "version 1"));
259         cv.push_back (dcp::ContentVersion("another-id", "version 2"));
260         cpl.set_content_versions (cv);
261
262         cpl.set_full_content_title_text ("full-content-title");
263         cpl.set_full_content_title_text_language (dcp::LanguageTag("de"));
264         cpl.set_release_territory (dcp::LanguageTag::RegionSubtag("ES"));
265         cpl.set_version_number (2);
266         cpl.set_status (dcp::Status::FINAL);
267         cpl.set_chain ("the-chain");
268         cpl.set_distributor ("the-distributor");
269         cpl.set_facility ("the-facility");
270         cpl.set_luminance (dcp::Luminance(4.5, dcp::Luminance::Unit::FOOT_LAMBERT));
271         cpl.set_issuer ("libdcp1.6.4devel");
272         cpl.set_creator ("libdcp1.6.4devel");
273
274         dcp::MainSoundConfiguration msc(dcp::MCASoundField::SEVEN_POINT_ONE, 16);
275         msc.set_mapping (0, dcp::Channel::LEFT);
276         msc.set_mapping (1, dcp::Channel::RIGHT);
277         msc.set_mapping (2, dcp::Channel::CENTRE);
278         msc.set_mapping (3, dcp::Channel::LFE);
279         msc.set_mapping (13, dcp::Channel::SYNC_SIGNAL);
280         cpl.set_main_sound_configuration (msc.to_string());
281
282         cpl.set_main_sound_sample_rate (48000);
283         cpl.set_main_picture_stored_area (dcp::Size(1998, 1080));
284         cpl.set_main_picture_active_area (dcp::Size(1440, 1080));
285
286         shared_ptr<cxml::Document> doc (new cxml::Document("MainSubtitle"));
287
288         doc->read_string (
289                 "<MainSubtitle>"
290                 "<Id>urn:uuid:8bca1489-aab1-9259-a4fd-8150abc1de12</Id>"
291                 "<AnnotationText>Goodbye world!</AnnotationText>"
292                 "<EditRate>25 1</EditRate>"
293                 "<IntrinsicDuration>1870</IntrinsicDuration>"
294                 "<EntryPoint>0</EntryPoint>"
295                 "<Duration>525</Duration>"
296                 "<KeyId>urn:uuid:540cbf10-ab14-0233-ab1f-fb31501cabfa</KeyId>"
297                 "<Hash>3EABjX9BB1CAWhLUtHhrGSyLgOY=</Hash>"
298                 "<Language>de-DE</Language>"
299                 "</MainSubtitle>"
300                 );
301
302         shared_ptr<dcp::Reel> reel(new dcp::Reel());
303         reel->add (black_picture_asset("build/test/cpl_metadata_write_test1"));
304         reel->add (shared_ptr<dcp::ReelSubtitleAsset>(new dcp::ReelSubtitleAsset(doc)));
305         cpl.add (reel);
306
307         vector<dcp::LanguageTag> lt;
308         lt.push_back(dcp::LanguageTag("en-US"));
309         lt.push_back(dcp::LanguageTag("fr-ZA"));
310         cpl.set_additional_subtitle_languages (lt);
311
312         cpl.write_xml ("build/test/cpl_metadata_write_test1.xml", dcp::Standard::SMPTE, shared_ptr<dcp::CertificateChain>());
313         check_xml (
314                 dcp::file_to_string("test/ref/cpl_metadata_test1.xml"),
315                 dcp::file_to_string("build/test/cpl_metadata_write_test1.xml"),
316                 vector<string>()
317                 );
318 }
319
320
321 /** A test where most CPL metadata is present */
322 BOOST_AUTO_TEST_CASE (cpl_metadata_roundtrip_test_1)
323 {
324         dcp::CPL cpl ("test/ref/cpl_metadata_test1.xml");
325         cpl.write_xml ("build/test/cpl_metadata_roundtrip_test1.xml", dcp::Standard::SMPTE, shared_ptr<dcp::CertificateChain>());
326         vector<string> ignore;
327         ignore.push_back ("Id");
328         check_xml (
329                 dcp::file_to_string("test/ref/cpl_metadata_test1.xml"),
330                 dcp::file_to_string("build/test/cpl_metadata_roundtrip_test1.xml"),
331                 ignore
332                 );
333 }
334
335
336 /** A test where only a bare minimum of CPL metadata is present */
337 BOOST_AUTO_TEST_CASE (cpl_metadata_write_test2)
338 {
339         RNGFixer fix;
340
341         dcp::CPL cpl("", dcp::ContentKind::FEATURE);
342         cpl.set_issue_date ("2020-08-28T13:35:06+02:00");
343         cpl.set_content_version (dcp::ContentVersion("id", "version"));
344         cpl.set_issuer ("libdcp1.6.4devel");
345         cpl.set_creator ("libdcp1.6.4devel");
346
347         dcp::MainSoundConfiguration msc(dcp::MCASoundField::SEVEN_POINT_ONE, 16);
348         msc.set_mapping (0, dcp::Channel::LEFT);
349         msc.set_mapping (1, dcp::Channel::RIGHT);
350         msc.set_mapping (2, dcp::Channel::CENTRE);
351         msc.set_mapping (3, dcp::Channel::LFE);
352         msc.set_mapping (13, dcp::Channel::SYNC_SIGNAL);
353         cpl.set_main_sound_configuration (msc.to_string());
354
355         cpl.set_main_sound_sample_rate (48000);
356         cpl.set_main_picture_stored_area (dcp::Size(1998, 1080));
357         cpl.set_main_picture_active_area (dcp::Size(1440, 1080));
358
359         shared_ptr<dcp::Reel> reel(new dcp::Reel());
360         reel->add (black_picture_asset("build/test/cpl_metadata_write_test1"));
361         cpl.add (reel);
362
363         cpl.write_xml ("build/test/cpl_metadata_write_test2.xml", dcp::Standard::SMPTE, shared_ptr<dcp::CertificateChain>());
364         check_xml (
365                 dcp::file_to_string("test/ref/cpl_metadata_test2.xml"),
366                 dcp::file_to_string("build/test/cpl_metadata_write_test2.xml"),
367                 vector<string>()
368                 );
369 }
370
371
372 /** A test where only a bare minimum of CPL metadata is present */
373 BOOST_AUTO_TEST_CASE (cpl_metadata_read_test2)
374 {
375         dcp::CPL cpl("test/ref/cpl_metadata_test2.xml");
376
377         BOOST_CHECK_EQUAL (cpl.full_content_title_text().get(), "");
378         BOOST_CHECK (!cpl.full_content_title_text_language());
379         BOOST_CHECK (!cpl.release_territory());
380         BOOST_CHECK (!cpl.version_number());
381         BOOST_CHECK (!cpl.status());
382         BOOST_CHECK (!cpl.chain());
383         BOOST_CHECK (!cpl.distributor());
384         BOOST_CHECK (!cpl.facility());
385         BOOST_CHECK (!cpl.luminance());
386
387         dcp::MainSoundConfiguration msc(cpl.main_sound_configuration().get());
388         BOOST_CHECK_EQUAL (msc.mapping(0).get(), dcp::Channel::LEFT);
389         BOOST_CHECK_EQUAL (msc.mapping(1).get(), dcp::Channel::RIGHT);
390         BOOST_CHECK_EQUAL (msc.mapping(2).get(), dcp::Channel::CENTRE);
391         BOOST_CHECK_EQUAL (msc.mapping(3).get(), dcp::Channel::LFE);
392         BOOST_CHECK (!msc.mapping(4));
393         BOOST_CHECK (!msc.mapping(5));
394         BOOST_CHECK (!msc.mapping(6));
395         BOOST_CHECK (!msc.mapping(7));
396         BOOST_CHECK (!msc.mapping(8));
397         BOOST_CHECK (!msc.mapping(9));
398         BOOST_CHECK (!msc.mapping(10));
399         BOOST_CHECK (!msc.mapping(11));
400         BOOST_CHECK (!msc.mapping(12));
401         BOOST_CHECK_EQUAL (msc.mapping(13).get(), dcp::Channel::SYNC_SIGNAL);
402
403         BOOST_CHECK_EQUAL (cpl.main_sound_sample_rate().get(), 48000);
404         BOOST_CHECK (cpl.main_picture_stored_area().get() == dcp::Size(1998, 1080));
405         BOOST_CHECK (cpl.main_picture_active_area().get() == dcp::Size(1440, 1080));
406
407         auto reels = cpl.reels ();
408         BOOST_REQUIRE_EQUAL (reels.size(), 1);
409 }
410
411
412 /** A test where only a bare minimum of CPL metadata is present */
413 BOOST_AUTO_TEST_CASE (cpl_metadata_roundtrip_test_2)
414 {
415         dcp::CPL cpl ("test/ref/cpl_metadata_test2.xml");
416         cpl.write_xml ("build/test/cpl_metadata_roundtrip_test2.xml", dcp::Standard::SMPTE, shared_ptr<dcp::CertificateChain>());
417         vector<string> ignore;
418         ignore.push_back ("Id");
419         check_xml (
420                 dcp::file_to_string("test/ref/cpl_metadata_test2.xml"),
421                 dcp::file_to_string("build/test/cpl_metadata_roundtrip_test2.xml"),
422                 ignore
423                 );
424 }
425