Switch to testing on Ubuntu 16.04 and 22.04.
[libdcp.git] / test / combine_test.cc
index 81fb08ba1b99783ae7f69ebec3e17dbcd916cfb4..231b859da96da12e2cfc45a310b38f40120f3ed0 100644 (file)
@@ -1,5 +1,5 @@
 /*
-    Copyright (C) 2020 Carl Hetherington <cth@carlh.net>
+    Copyright (C) 2020-2021 Carl Hetherington <cth@carlh.net>
 
     This file is part of libdcp.
 
@@ -35,6 +35,7 @@
 #include "combine.h"
 #include "cpl.h"
 #include "dcp.h"
+#include "equality_options.h"
 #include "interop_subtitle_asset.h"
 #include "reel_subtitle_asset.h"
 #include "reel_mono_picture_asset.h"
@@ -42,9 +43,9 @@
 #include "test.h"
 #include "types.h"
 #include "verify.h"
+#include "reel_interop_subtitle_asset.h"
 #include "reel_markers_asset.h"
 #include <boost/algorithm/string.hpp>
-#include <boost/foreach.hpp>
 #include <boost/optional.hpp>
 #include <boost/test/unit_test.hpp>
 #include <iostream>
@@ -74,7 +75,7 @@ static
 void
 dump_notes (vector<dcp::VerificationNote> const & notes)
 {
-       BOOST_FOREACH (dcp::VerificationNote i, notes) {
+       for (auto i: notes) {
                std::cout << dcp::note_to_string(i) << "\n";
        }
 }
@@ -86,10 +87,10 @@ check_no_errors (boost::filesystem::path path)
 {
        vector<boost::filesystem::path> directories;
        directories.push_back (path);
-       auto notes = dcp::verify (directories, &stage, &progress, xsd_test);
+       auto notes = dcp::verify(directories, &stage, &progress, {}, xsd_test);
        vector<dcp::VerificationNote> filtered_notes;
        std::copy_if (notes.begin(), notes.end(), std::back_inserter(filtered_notes), [](dcp::VerificationNote const& i) {
-               return i.code() != dcp::VerificationNote::INVALID_STANDARD && i.code() != dcp::VerificationNote::INVALID_SUBTITLE_DURATION;
+               return i.code() != dcp::VerificationNote::Code::INVALID_STANDARD && i.code() != dcp::VerificationNote::Code::INVALID_SUBTITLE_DURATION;
        });
        dump_notes (filtered_notes);
        BOOST_CHECK (filtered_notes.empty());
@@ -98,9 +99,9 @@ check_no_errors (boost::filesystem::path path)
 
 template <class T>
 shared_ptr<T>
-pointer_to_id_in_vector (shared_ptr<T> needle, vector<shared_ptr<T> > haystack)
+pointer_to_id_in_vector (shared_ptr<T> needle, vector<shared_ptr<T>> haystack)
 {
-       BOOST_FOREACH (shared_ptr<T> i, haystack) {
+       for (auto i: haystack) {
                if (i->id() == needle->id()) {
                        return i;
                }
@@ -128,19 +129,18 @@ check_combined (vector<boost::filesystem::path> inputs, boost::filesystem::path
        dcp::EqualityOptions options;
        options.load_font_nodes_can_differ = true;
 
-       BOOST_FOREACH (boost::filesystem::path i, inputs)
-       {
+       for (auto i: inputs) {
                dcp::DCP input_dcp (i);
                input_dcp.read ();
 
                BOOST_REQUIRE (input_dcp.cpls().size() == 1);
-               shared_ptr<dcp::CPL> input_cpl = input_dcp.cpls().front();
+               auto input_cpl = input_dcp.cpls().front();
 
-               shared_ptr<dcp::CPL> output_cpl = pointer_to_id_in_vector (input_cpl, output_dcp.cpls());
+               auto output_cpl = pointer_to_id_in_vector (input_cpl, output_dcp.cpls());
                BOOST_REQUIRE (output_cpl);
 
-               BOOST_FOREACH (shared_ptr<dcp::Asset> i, input_dcp.assets(true)) {
-                       shared_ptr<dcp::Asset> o = pointer_to_id_in_vector(i, output_dcp.assets());
+               for (auto i: input_dcp.assets(true)) {
+                       auto o = pointer_to_id_in_vector(i, output_dcp.assets());
                        BOOST_REQUIRE_MESSAGE (o, "Could not find " << i->id() << " in combined DCP.");
                        BOOST_CHECK (i->equals(o, options, note_handler));
                }
@@ -177,8 +177,8 @@ BOOST_AUTO_TEST_CASE (combine_two_dcps_with_same_asset_filenames_test)
        using namespace boost::filesystem;
        boost::filesystem::path const out = "build/test/combine_two_dcps_with_same_asset_filenames_test";
 
-       shared_ptr<dcp::DCP> second = make_simple ("build/test/combine_input2");
-       second->write_xml (dcp::SMPTE);
+       auto second = make_simple ("build/test/combine_input2");
+       second->write_xml ();
 
        remove_all (out);
        vector<path> inputs;
@@ -191,22 +191,41 @@ BOOST_AUTO_TEST_CASE (combine_two_dcps_with_same_asset_filenames_test)
 }
 
 
+BOOST_AUTO_TEST_CASE(combine_two_dcps_one_with_interop_subs_test)
+{
+       using namespace boost::algorithm;
+       using namespace boost::filesystem;
+       boost::filesystem::path const out = "build/test/combine_two_dcps_one_with_interop_subs_test";
+
+       auto first = make_simple("build/test/combine_input1", 1, 24, dcp::Standard::INTEROP);
+       first->write_xml ();
+
+       auto second = make_simple_with_interop_subs("build/test/combine_input2");
+       second->write_xml ();
+
+       remove_all (out);
+       vector<path> inputs = {"build/test/combine_input1", "build/test/combine_input2"};
+       dcp::combine (inputs, out);
+
+       check_no_errors (out);
+       check_combined (inputs, out);
+}
+
+
 BOOST_AUTO_TEST_CASE (combine_two_dcps_with_interop_subs_test)
 {
        using namespace boost::algorithm;
        using namespace boost::filesystem;
        boost::filesystem::path const out = "build/test/combine_two_dcps_with_interop_subs_test";
 
-       shared_ptr<dcp::DCP> first = make_simple_with_interop_subs ("build/test/combine_input1");
-       first->write_xml (dcp::INTEROP);
+       auto first = make_simple_with_interop_subs ("build/test/combine_input1");
+       first->write_xml ();
 
-       shared_ptr<dcp::DCP> second = make_simple_with_interop_subs ("build/test/combine_input2");
-       second->write_xml (dcp::INTEROP);
+       auto second = make_simple_with_interop_subs ("build/test/combine_input2");
+       second->write_xml ();
 
        remove_all (out);
-       vector<path> inputs;
-       inputs.push_back ("build/test/combine_input1");
-       inputs.push_back ("build/test/combine_input2");
+       vector<path> inputs = {"build/test/combine_input1", "build/test/combine_input2"};
        dcp::combine (inputs, out);
 
        check_no_errors (out);
@@ -220,11 +239,11 @@ BOOST_AUTO_TEST_CASE (combine_two_dcps_with_smpte_subs_test)
        using namespace boost::filesystem;
        boost::filesystem::path const out = "build/test/combine_two_dcps_with_smpte_subs_test";
 
-       shared_ptr<dcp::DCP> first = make_simple_with_smpte_subs ("build/test/combine_input1");
-       first->write_xml (dcp::SMPTE);
+       auto first = make_simple_with_smpte_subs ("build/test/combine_input1");
+       first->write_xml ();
 
-       shared_ptr<dcp::DCP> second = make_simple_with_smpte_subs ("build/test/combine_input2");
-       second->write_xml (dcp::SMPTE);
+       auto second = make_simple_with_smpte_subs ("build/test/combine_input2");
+       second->write_xml ();
 
        remove_all (out);
        vector<path> inputs;
@@ -243,11 +262,11 @@ BOOST_AUTO_TEST_CASE (combine_two_dcps_with_interop_ccaps_test)
        using namespace boost::filesystem;
        boost::filesystem::path const out = "build/test/combine_two_dcps_with_interop_ccaps_test";
 
-       shared_ptr<dcp::DCP> first = make_simple_with_interop_ccaps ("build/test/combine_input1");
-       first->write_xml (dcp::INTEROP);
+       auto first = make_simple_with_interop_ccaps ("build/test/combine_input1");
+       first->write_xml ();
 
-       shared_ptr<dcp::DCP> second = make_simple_with_interop_ccaps ("build/test/combine_input2");
-       second->write_xml (dcp::INTEROP);
+       auto second = make_simple_with_interop_ccaps ("build/test/combine_input2");
+       second->write_xml ();
 
        remove_all (out);
        vector<path> inputs;
@@ -266,11 +285,11 @@ BOOST_AUTO_TEST_CASE (combine_two_dcps_with_smpte_ccaps_test)
        using namespace boost::filesystem;
        boost::filesystem::path const out = "build/test/combine_two_dcps_with_interop_ccaps_test";
 
-       shared_ptr<dcp::DCP> first = make_simple_with_smpte_ccaps ("build/test/combine_input1");
-       first->write_xml (dcp::SMPTE);
+       auto first = make_simple_with_smpte_ccaps ("build/test/combine_input1");
+       first->write_xml ();
 
-       shared_ptr<dcp::DCP> second = make_simple_with_smpte_ccaps ("build/test/combine_input2");
-       second->write_xml (dcp::SMPTE);
+       auto second = make_simple_with_smpte_ccaps ("build/test/combine_input2");
+       second->write_xml ();
 
        remove_all (out);
        vector<path> inputs;
@@ -289,11 +308,11 @@ BOOST_AUTO_TEST_CASE (combine_two_multi_reel_dcps)
        using namespace boost::filesystem;
        boost::filesystem::path const out = "build/test/combine_two_multi_reel_dcps";
 
-       shared_ptr<dcp::DCP> first = make_simple ("build/test/combine_input1", 4);
-       first->write_xml (dcp::SMPTE);
+       auto first = make_simple ("build/test/combine_input1", 4);
+       first->write_xml ();
 
-       shared_ptr<dcp::DCP> second = make_simple ("build/test/combine_input2", 4);
-       second->write_xml (dcp::SMPTE);
+       auto second = make_simple ("build/test/combine_input2", 4);
+       second->write_xml ();
 
        remove_all (out);
        vector<path> inputs;
@@ -311,33 +330,33 @@ BOOST_AUTO_TEST_CASE (combine_two_dcps_with_shared_asset)
        using namespace boost::filesystem;
        boost::filesystem::path const out = "build/test/combine_two_dcps_with_shared_asset";
 
-       shared_ptr<dcp::DCP> first = make_simple ("build/test/combine_input1", 1);
-       first->write_xml (dcp::SMPTE);
+       auto first = make_simple ("build/test/combine_input1", 1);
+       first->write_xml ();
 
        remove_all ("build/test/combine_input2");
-       shared_ptr<dcp::DCP> second(new dcp::DCP("build/test/combine_input2"));
+       auto second = make_shared<dcp::DCP>("build/test/combine_input2");
 
        dcp::MXFMetadata mxf_meta;
        mxf_meta.company_name = "OpenDCP";
        mxf_meta.product_version = "0.0.25";
 
-       shared_ptr<dcp::CPL> cpl (new dcp::CPL("A Test DCP", dcp::TRAILER));
+       auto cpl = make_shared<dcp::CPL>("A Test DCP", dcp::ContentKind::TRAILER, dcp::Standard::SMPTE);
        cpl->set_content_version (
                dcp::ContentVersion("urn:uuid:75ac29aa-42ac-1234-ecae-49251abefd11","content-version-label-text")
                );
-       cpl->set_main_sound_configuration ("L,C,R,Lfe,-,-");
+       cpl->set_main_sound_configuration(dcp::MainSoundConfiguration("51/L,C,R,LFE,-,-"));
        cpl->set_main_sound_sample_rate (48000);
        cpl->set_main_picture_stored_area (dcp::Size(1998, 1080));
        cpl->set_main_picture_active_area (dcp::Size(1440, 1080));
        cpl->set_version_number(1);
 
-       shared_ptr<dcp::ReelMonoPictureAsset> pic(new dcp::ReelMonoPictureAsset(simple_picture("build/test/combine_input2", ""), 0));
-       shared_ptr<dcp::ReelSoundAsset> sound(new dcp::ReelSoundAsset(first->cpls().front()->reels().front()->main_sound()->asset(), 0));
+       auto pic = make_shared<dcp::ReelMonoPictureAsset>(simple_picture("build/test/combine_input2", ""), 0);
+       auto sound = make_shared<dcp::ReelSoundAsset>(first->cpls().front()->reels().front()->main_sound()->asset(), 0);
        auto reel = make_shared<dcp::Reel>(pic, sound);
        reel->add (simple_markers());
        cpl->add (reel);
        second->add (cpl);
-       second->write_xml (dcp::SMPTE);
+       second->write_xml ();
 
        remove_all (out);
        vector<path> inputs;
@@ -350,5 +369,121 @@ BOOST_AUTO_TEST_CASE (combine_two_dcps_with_shared_asset)
 }
 
 
+/** Two DCPs each with a copy of the exact same asset */
+BOOST_AUTO_TEST_CASE (combine_two_dcps_with_duplicated_asset)
+{
+       using namespace boost::filesystem;
+       boost::filesystem::path const out = "build/test/combine_two_dcps_with_duplicated_asset";
+
+       auto first = make_simple ("build/test/combine_input1", 1);
+       first->write_xml ();
+
+       remove_all ("build/test/combine_input2");
+       auto second = make_shared<dcp::DCP>("build/test/combine_input2");
+
+       dcp::MXFMetadata mxf_meta;
+       mxf_meta.company_name = "OpenDCP";
+       mxf_meta.product_version = "0.0.25";
+
+       auto cpl = make_shared<dcp::CPL>("A Test DCP", dcp::ContentKind::TRAILER, dcp::Standard::SMPTE);
+       cpl->set_content_version (
+               dcp::ContentVersion("urn:uuid:75ac29aa-42ac-1234-ecae-49251abefd11","content-version-label-text")
+               );
+       cpl->set_main_sound_configuration(dcp::MainSoundConfiguration("51/L,C,R,LFE,-,-"));
+       cpl->set_main_sound_sample_rate (48000);
+       cpl->set_main_picture_stored_area (dcp::Size(1998, 1080));
+       cpl->set_main_picture_active_area (dcp::Size(1440, 1080));
+       cpl->set_version_number(1);
+
+       auto pic = make_shared<dcp::ReelMonoPictureAsset>(simple_picture("build/test/combine_input2", ""), 0);
+       auto first_sound_asset = first->cpls()[0]->reels()[0]->main_sound()->asset()->file();
+       BOOST_REQUIRE (first_sound_asset);
+       boost::filesystem::path second_sound_asset = "build/test/combine_input2/my_great_audio.mxf";
+       boost::filesystem::copy_file (*first_sound_asset, second_sound_asset);
+       auto sound = make_shared<dcp::ReelSoundAsset>(make_shared<dcp::SoundAsset>(second_sound_asset), 0);
+       auto reel = make_shared<dcp::Reel>(pic, sound);
+       reel->add (simple_markers());
+       cpl->add (reel);
+       second->add (cpl);
+       second->write_xml ();
+
+       remove_all (out);
+       vector<path> inputs;
+       inputs.push_back ("build/test/combine_input1");
+       inputs.push_back ("build/test/combine_input2");
+       dcp::combine (inputs, out);
+
+       check_no_errors (out);
+       check_combined (inputs, out);
+
+       BOOST_REQUIRE (!boost::filesystem::exists(out / "my_great_audio.mxf"));
+}
+
+
+BOOST_AUTO_TEST_CASE (check_cpls_unchanged_after_combine)
+{
+       boost::filesystem::path in = "build/test/combine_one_dcp_with_composition_metadata_in";
+       boost::filesystem::path out = "build/test/combine_one_dcp_with_composition_metadata_out";
+       auto dcp = make_simple (in);
+       dcp->write_xml ();
+
+       dcp::combine ({in}, out);
+
+       BOOST_REQUIRE_EQUAL (dcp->cpls().size(), 1U);
+       auto cpl = dcp->cpls()[0]->file();
+       BOOST_REQUIRE (cpl);
+       check_file (*cpl, out / cpl->filename());
+}
+
+
+/** The combine process would write multiple fonts with the same ID (#2402) */
+BOOST_AUTO_TEST_CASE(combine_multi_reel_subtitles)
+{
+       boost::filesystem::path in = "build/test/combine_multi_reel_subtitles_in";
+       boost::filesystem::path out = "build/test/combine_multi_reel_subtitles_out";
+       remove_all(out);
+
+       auto dcp = make_simple(in, 2, 24, dcp::Standard::INTEROP);
+
+       dcp::ArrayData data1(4096);
+       memset(data1.data(), 0, data1.size());
+
+       auto subs1 = make_shared<dcp::InteropSubtitleAsset>();
+       subs1->add(simple_subtitle());
+       boost::filesystem::create_directory(in / "subs1");
+       subs1->add_font("afont1", data1);
+       subs1->write(in / "subs1" / "subs1.xml");
+
+       dcp::ArrayData data2(4096);
+       memset(data2.data(), 1, data1.size());
+
+       auto subs2 = make_shared<dcp::InteropSubtitleAsset>();
+       subs2->add(simple_subtitle());
+       boost::filesystem::create_directory(in / "subs2");
+       subs2->add_font("afont2", data2);
+       subs2->write(in / "subs2" / "subs2.xml");
+
+       auto reel_subs1 = make_shared<dcp::ReelInteropSubtitleAsset>(subs1, dcp::Fraction(24, 1), 240, 0);
+       dcp->cpls()[0]->reels()[0]->add(reel_subs1);
+
+       auto reel_subs2 = make_shared<dcp::ReelInteropSubtitleAsset>(subs2, dcp::Fraction(24, 1), 240, 0);
+       dcp->cpls()[0]->reels()[1]->add(reel_subs2);
+
+       dcp->write_xml();
+
+       dcp::combine({in}, out);
+
+       check_combined({in}, out);
+
+       auto notes = dcp::verify({out}, &stage, &progress, {}, xsd_test);
+       vector<dcp::VerificationNote> filtered_notes;
+       std::copy_if(notes.begin(), notes.end(), std::back_inserter(filtered_notes), [](dcp::VerificationNote const& i) {
+               return i.code() != dcp::VerificationNote::Code::INVALID_STANDARD && i.code() != dcp::VerificationNote::Code::MISMATCHED_PKL_ANNOTATION_TEXT_WITH_CPL;
+       });
+       dump_notes(filtered_notes);
+       BOOST_CHECK(filtered_notes.empty());
+}
+
+
 /* XXX: same CPL names */
 /* XXX: Interop PNG subs */