e905500852428e9e8a56afb202342101457b3a22
[dcpomatic.git] / test / config_test.cc
1 /*
2     Copyright (C) 2018-2021 Carl Hetherington <cth@carlh.net>
3
4     This file is part of DCP-o-matic.
5
6     DCP-o-matic 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     DCP-o-matic 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 DCP-o-matic.  If not, see <http://www.gnu.org/licenses/>.
18
19 */
20
21
22 #include "lib/cinema.h"
23 #include "lib/config.h"
24 #include "test.h"
25 #include <boost/test/unit_test.hpp>
26 #include <fstream>
27
28
29 using std::list;
30 using std::ofstream;
31 using std::make_shared;
32 using std::string;
33 using boost::optional;
34
35
36 static string
37 rewrite_bad_config (string filename, string extra_line)
38 {
39         using namespace boost::filesystem;
40
41         auto base = path("build/test/bad_config/2.16");
42         auto file = base / filename;
43
44         boost::system::error_code ec;
45         remove (file, ec);
46
47         boost::filesystem::create_directories (base);
48         std::ofstream f (file.string().c_str());
49         f << "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n"
50           << "<Config>\n"
51           << "<Foo></Foo>\n"
52           << extra_line << "\n"
53           << "</Config>\n";
54         f.close ();
55
56         return dcp::file_to_string (file);
57 }
58
59
60 BOOST_AUTO_TEST_CASE (config_backup_test)
61 {
62         ConfigRestorer cr;
63
64         Config::override_path = "build/test/bad_config";
65         Config::drop();
66         boost::filesystem::remove_all ("build/test/bad_config");
67
68         /* Write an invalid config file to config.xml */
69         auto const first_write_xml = rewrite_bad_config("config.xml", "first write");
70
71         /* Load the config; this should fail, causing the bad config to be copied to config.xml.1
72          * and a new config.xml created in its place.
73          */
74         Config::instance();
75
76         BOOST_CHECK ( boost::filesystem::exists("build/test/bad_config/2.16/config.xml.1"));
77         BOOST_CHECK (dcp::file_to_string("build/test/bad_config/2.16/config.xml.1") == first_write_xml);
78         BOOST_CHECK (!boost::filesystem::exists("build/test/bad_config/2.16/config.xml.2"));
79         BOOST_CHECK (!boost::filesystem::exists("build/test/bad_config/2.16/config.xml.3"));
80         BOOST_CHECK (!boost::filesystem::exists("build/test/bad_config/2.16/config.xml.4"));
81
82         Config::drop();
83         auto const second_write_xml = rewrite_bad_config("config.xml", "second write");
84         Config::instance();
85
86         BOOST_CHECK ( boost::filesystem::exists("build/test/bad_config/2.16/config.xml.1"));
87         BOOST_CHECK (dcp::file_to_string("build/test/bad_config/2.16/config.xml.1") == first_write_xml);
88         BOOST_CHECK ( boost::filesystem::exists("build/test/bad_config/2.16/config.xml.2"));
89         BOOST_CHECK (dcp::file_to_string("build/test/bad_config/2.16/config.xml.2") == second_write_xml);
90         BOOST_CHECK (!boost::filesystem::exists("build/test/bad_config/2.16/config.xml.3"));
91         BOOST_CHECK (!boost::filesystem::exists("build/test/bad_config/2.16/config.xml.4"));
92
93         Config::drop();
94         auto const third_write_xml = rewrite_bad_config("config.xml", "third write");
95         Config::instance();
96
97         BOOST_CHECK ( boost::filesystem::exists("build/test/bad_config/2.16/config.xml.1"));
98         BOOST_CHECK (dcp::file_to_string("build/test/bad_config/2.16/config.xml.1") == first_write_xml);
99         BOOST_CHECK ( boost::filesystem::exists("build/test/bad_config/2.16/config.xml.2"));
100         BOOST_CHECK (dcp::file_to_string("build/test/bad_config/2.16/config.xml.2") == second_write_xml);
101         BOOST_CHECK ( boost::filesystem::exists("build/test/bad_config/2.16/config.xml.3"));
102         BOOST_CHECK (dcp::file_to_string("build/test/bad_config/2.16/config.xml.3") == third_write_xml);
103         BOOST_CHECK (!boost::filesystem::exists("build/test/bad_config/2.16/config.xml.4"));
104
105         Config::drop();
106         auto const fourth_write_xml = rewrite_bad_config("config.xml", "fourth write");
107         Config::instance();
108
109         BOOST_CHECK (boost::filesystem::exists("build/test/bad_config/2.16/config.xml.1"));
110         BOOST_CHECK (dcp::file_to_string("build/test/bad_config/2.16/config.xml.1") == first_write_xml);
111         BOOST_CHECK (boost::filesystem::exists("build/test/bad_config/2.16/config.xml.2"));
112         BOOST_CHECK (dcp::file_to_string("build/test/bad_config/2.16/config.xml.2") == second_write_xml);
113         BOOST_CHECK (boost::filesystem::exists("build/test/bad_config/2.16/config.xml.3"));
114         BOOST_CHECK (dcp::file_to_string("build/test/bad_config/2.16/config.xml.3") == third_write_xml);
115         BOOST_CHECK (boost::filesystem::exists("build/test/bad_config/2.16/config.xml.4"));
116         BOOST_CHECK (dcp::file_to_string("build/test/bad_config/2.16/config.xml.4") == fourth_write_xml);
117 }
118
119
120 BOOST_AUTO_TEST_CASE (config_backup_with_link_test)
121 {
122         using namespace boost::filesystem;
123
124         ConfigRestorer cr;
125
126         auto base = path("build/test/bad_config");
127         auto version = base / "2.16";
128
129         Config::override_path = base;
130         Config::drop();
131
132         boost::filesystem::remove_all (base);
133
134         boost::filesystem::create_directories (version);
135         std::ofstream f (path(version / "config.xml").string().c_str());
136         f << "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n"
137           << "<Config>\n"
138           << "<Link>" << path(version / "actual.xml").string() << "</Link>\n"
139           << "</Config>\n";
140         f.close ();
141
142         Config::drop ();
143         /* Cause actual.xml to be backed up */
144         rewrite_bad_config ("actual.xml", "first write");
145         Config::instance ();
146
147         /* Make sure actual.xml was backed up to the right place */
148         BOOST_CHECK (boost::filesystem::exists(version / "actual.xml.1"));
149 }
150
151
152 BOOST_AUTO_TEST_CASE (config_write_utf8_test)
153 {
154         ConfigRestorer cr;
155
156         boost::filesystem::remove_all ("build/test/config.xml");
157         boost::filesystem::copy_file ("test/data/utf8_config.xml", "build/test/config.xml");
158         Config::override_path = "build/test";
159         Config::drop ();
160         Config::instance()->write();
161
162         check_text_file ("test/data/utf8_config.xml", "build/test/config.xml");
163 }
164
165
166 BOOST_AUTO_TEST_CASE (config_upgrade_test)
167 {
168         ConfigRestorer cr;
169
170         boost::filesystem::path dir = "build/test/config_upgrade_test";
171         Config::override_path = dir;
172         Config::drop ();
173         boost::filesystem::remove_all (dir);
174         boost::filesystem::create_directories (dir);
175
176         boost::filesystem::copy_file ("test/data/2.14.config.xml", dir / "config.xml");
177         boost::filesystem::copy_file ("test/data/2.14.cinemas.xml", dir / "cinemas.xml");
178         Config::instance();
179         try {
180                 /* This will fail to write cinemas.xml since the link is to a non-existent directory */
181                 Config::instance()->write();
182         } catch (...) {}
183
184         check_xml (dir / "config.xml", "test/data/2.14.config.xml", {});
185         check_xml (dir / "cinemas.xml", "test/data/2.14.cinemas.xml", {});
186 #ifdef DCPOMATIC_WINDOWS
187         /* This file has the windows path for dkdm_recipients.xml (with backslashes) */
188         check_xml (dir / "2.16" / "config.xml", "test/data/2.16.config.windows.xml", {});
189 #else
190         check_xml (dir / "2.16" / "config.xml", "test/data/2.16.config.xml", {});
191 #endif
192         /* cinemas.xml is not copied into 2.16 as its format has not changed */
193         BOOST_REQUIRE (!boost::filesystem::exists(dir / "2.16" / "cinemas.xml"));
194 }
195
196
197 BOOST_AUTO_TEST_CASE (config_keep_cinemas_if_making_new_config)
198 {
199         ConfigRestorer cr;
200
201         boost::filesystem::path dir = "build/test/config_keep_cinemas_if_making_new_config";
202         Config::override_path = dir;
203         Config::drop ();
204         boost::filesystem::remove_all (dir);
205         boost::filesystem::create_directories (dir);
206
207         Config::instance()->write();
208
209         Config::instance()->add_cinema(make_shared<Cinema>("My Great Cinema", list<string>(), "", 0, 0));
210         Config::instance()->write();
211
212         boost::filesystem::copy_file (dir / "cinemas.xml", dir / "backup_for_test.xml");
213
214         Config::drop ();
215         boost::filesystem::remove (dir / "2.16" / "config.xml");
216         Config::instance();
217
218         check_text_file(dir / "backup_for_test.xml", dir / "cinemas.xml");
219 }
220
221
222 BOOST_AUTO_TEST_CASE(keep_config_if_cinemas_fail_to_load)
223 {
224         ConfigRestorer cr;
225
226         /* Make a new config */
227         boost::filesystem::path dir = "build/test/keep_config_if_cinemas_fail_to_load";
228         Config::override_path = dir;
229         Config::drop();
230         boost::filesystem::remove_all(dir);
231         boost::filesystem::create_directories(dir);
232         Config::instance()->write();
233
234         auto const cinemas = dir / "cinemas.xml";
235
236         /* Back things up */
237         boost::filesystem::copy_file(dir / "2.16" / "config.xml", dir / "config_backup_for_test.xml");
238         boost::filesystem::copy_file(cinemas, dir / "cinemas_backup_for_test.xml");
239
240         /* Corrupt the cinemas */
241         Config::drop();
242         std::ofstream corrupt(cinemas.string().c_str());
243         corrupt << "foo\n";
244         corrupt.close();
245         Config::instance();
246
247         /* We should have a new cinemas.xml and the old config.xml */
248         check_text_file(dir / "2.16" / "config.xml", dir / "config_backup_for_test.xml");
249         check_text_file(cinemas, dir / "cinemas_backup_for_test.xml");
250 }
251