Use 2.18.x subdirectory for configuration.
[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.18");
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::filesystem::path const prefix = "build/test/bad_config/2.18";
77
78         BOOST_CHECK(boost::filesystem::exists(prefix / "config.xml.1"));
79         BOOST_CHECK(dcp::file_to_string(prefix / "config.xml.1") == first_write_xml);
80         BOOST_CHECK(!boost::filesystem::exists(prefix / "config.xml.2"));
81         BOOST_CHECK(!boost::filesystem::exists(prefix / "config.xml.3"));
82         BOOST_CHECK(!boost::filesystem::exists(prefix / "config.xml.4"));
83
84         Config::drop();
85         auto const second_write_xml = rewrite_bad_config("config.xml", "second write");
86         Config::instance();
87
88         BOOST_CHECK(boost::filesystem::exists(prefix / "config.xml.1"));
89         BOOST_CHECK(dcp::file_to_string(prefix / "config.xml.1") == first_write_xml);
90         BOOST_CHECK(boost::filesystem::exists(prefix / "config.xml.2"));
91         BOOST_CHECK(dcp::file_to_string(prefix / "config.xml.2") == second_write_xml);
92         BOOST_CHECK(!boost::filesystem::exists(prefix / "config.xml.3"));
93         BOOST_CHECK(!boost::filesystem::exists(prefix / "config.xml.4"));
94
95         Config::drop();
96         auto const third_write_xml = rewrite_bad_config("config.xml", "third write");
97         Config::instance();
98
99         BOOST_CHECK(boost::filesystem::exists(prefix / "config.xml.1"));
100         BOOST_CHECK(dcp::file_to_string(prefix / "config.xml.1") == first_write_xml);
101         BOOST_CHECK(boost::filesystem::exists(prefix / "config.xml.2"));
102         BOOST_CHECK(dcp::file_to_string(prefix / "config.xml.2") == second_write_xml);
103         BOOST_CHECK(boost::filesystem::exists(prefix / "config.xml.3"));
104         BOOST_CHECK(dcp::file_to_string(prefix / "config.xml.3") == third_write_xml);
105         BOOST_CHECK(!boost::filesystem::exists(prefix / "config.xml.4"));
106
107         Config::drop();
108         auto const fourth_write_xml = rewrite_bad_config("config.xml", "fourth write");
109         Config::instance();
110
111         BOOST_CHECK(boost::filesystem::exists(prefix / "config.xml.1"));
112         BOOST_CHECK(dcp::file_to_string(prefix / "config.xml.1") == first_write_xml);
113         BOOST_CHECK(boost::filesystem::exists(prefix / "config.xml.2"));
114         BOOST_CHECK(dcp::file_to_string(prefix / "config.xml.2") == second_write_xml);
115         BOOST_CHECK(boost::filesystem::exists(prefix / "config.xml.3"));
116         BOOST_CHECK(dcp::file_to_string(prefix / "config.xml.3") == third_write_xml);
117         BOOST_CHECK(boost::filesystem::exists(prefix / "config.xml.4"));
118         BOOST_CHECK(dcp::file_to_string(prefix / "config.xml.4") == fourth_write_xml);
119 }
120
121
122 BOOST_AUTO_TEST_CASE (config_backup_with_link_test)
123 {
124         using namespace boost::filesystem;
125
126         ConfigRestorer cr;
127
128         auto base = path("build/test/bad_config");
129         auto version = base / "2.18";
130
131         Config::override_path = base;
132         Config::drop();
133
134         boost::filesystem::remove_all (base);
135
136         boost::filesystem::create_directories (version);
137         std::ofstream f (path(version / "config.xml").string().c_str());
138         f << "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n"
139           << "<Config>\n"
140           << "<Link>" << path(version / "actual.xml").string() << "</Link>\n"
141           << "</Config>\n";
142         f.close ();
143
144         Config::drop ();
145         /* Cause actual.xml to be backed up */
146         rewrite_bad_config ("actual.xml", "first write");
147         Config::instance ();
148
149         /* Make sure actual.xml was backed up to the right place */
150         BOOST_CHECK (boost::filesystem::exists(version / "actual.xml.1"));
151 }
152
153
154 BOOST_AUTO_TEST_CASE (config_write_utf8_test)
155 {
156         ConfigRestorer cr;
157
158         boost::filesystem::remove_all ("build/test/config.xml");
159         boost::filesystem::copy_file ("test/data/utf8_config.xml", "build/test/config.xml");
160         Config::override_path = "build/test";
161         Config::drop ();
162         Config::instance()->write();
163
164         check_text_file ("test/data/utf8_config.xml", "build/test/config.xml");
165 }
166
167
168 /* 2.14 -> 2.18 */
169 BOOST_AUTO_TEST_CASE (config_upgrade_test1)
170 {
171         ConfigRestorer cr;
172
173         boost::filesystem::path dir = "build/test/config_upgrade_test";
174         Config::override_path = dir;
175         Config::drop ();
176         boost::filesystem::remove_all (dir);
177         boost::filesystem::create_directories (dir);
178
179         boost::filesystem::copy_file ("test/data/2.14.config.xml", dir / "config.xml");
180         boost::filesystem::copy_file ("test/data/2.14.cinemas.xml", dir / "cinemas.xml");
181         Config::instance();
182         try {
183                 /* This will fail to write cinemas.xml since the link is to a non-existent directory */
184                 Config::instance()->write();
185         } catch (...) {}
186
187         check_xml (dir / "config.xml", "test/data/2.14.config.xml", {});
188         check_xml (dir / "cinemas.xml", "test/data/2.14.cinemas.xml", {});
189 #ifdef DCPOMATIC_WINDOWS
190         /* This file has the windows path for dkdm_recipients.xml (with backslashes) */
191         check_xml(dir / "2.18" / "config.xml", "test/data/2.18.config.windows.xml", {});
192 #else
193         check_xml(dir / "2.18" / "config.xml", "test/data/2.18.config.xml", {});
194 #endif
195         /* cinemas.xml is not copied into 2.18 as its format has not changed */
196         BOOST_REQUIRE (!boost::filesystem::exists(dir / "2.18" / "cinemas.xml"));
197 }
198
199
200 /* 2.16 -> 2.18 */
201 BOOST_AUTO_TEST_CASE (config_upgrade_test2)
202 {
203         ConfigRestorer cr;
204
205         boost::filesystem::path dir = "build/test/config_upgrade_test";
206         Config::override_path = dir;
207         Config::drop ();
208         boost::filesystem::remove_all (dir);
209         boost::filesystem::create_directories (dir);
210
211         boost::filesystem::copy_file("test/data/2.16.config.xml", dir / "config.xml");
212         boost::filesystem::copy_file("test/data/2.14.cinemas.xml", dir / "cinemas.xml");
213         Config::instance();
214         try {
215                 /* This will fail to write cinemas.xml since the link is to a non-existent directory */
216                 Config::instance()->write();
217         } catch (...) {}
218
219         check_xml(dir / "config.xml", "test/data/2.16.config.xml", {});
220         check_xml(dir / "cinemas.xml", "test/data/2.14.cinemas.xml", {});
221 #ifdef DCPOMATIC_WINDOWS
222         /* This file has the windows path for dkdm_recipients.xml (with backslashes) */
223         check_xml(dir / "2.18" / "config.xml", "test/data/2.18.config.windows.xml", {});
224 #else
225         check_xml(dir / "2.18" / "config.xml", "test/data/2.18.config.xml", {});
226 #endif
227         /* cinemas.xml is not copied into 2.18 as its format has not changed */
228         BOOST_REQUIRE (!boost::filesystem::exists(dir / "2.18" / "cinemas.xml"));
229 }
230
231
232 BOOST_AUTO_TEST_CASE (config_keep_cinemas_if_making_new_config)
233 {
234         ConfigRestorer cr;
235
236         boost::filesystem::path dir = "build/test/config_keep_cinemas_if_making_new_config";
237         Config::override_path = dir;
238         Config::drop ();
239         boost::filesystem::remove_all (dir);
240         boost::filesystem::create_directories (dir);
241
242         Config::instance()->write();
243
244         Config::instance()->add_cinema(make_shared<Cinema>("My Great Cinema", list<string>(), "", 0, 0));
245         Config::instance()->write();
246
247         boost::filesystem::copy_file (dir / "cinemas.xml", dir / "backup_for_test.xml");
248
249         Config::drop ();
250         boost::filesystem::remove (dir / "2.18" / "config.xml");
251         Config::instance();
252
253         check_text_file(dir / "backup_for_test.xml", dir / "cinemas.xml");
254 }
255
256
257 BOOST_AUTO_TEST_CASE(keep_config_if_cinemas_fail_to_load)
258 {
259         ConfigRestorer cr;
260
261         /* Make a new config */
262         boost::filesystem::path dir = "build/test/keep_config_if_cinemas_fail_to_load";
263         Config::override_path = dir;
264         Config::drop();
265         boost::filesystem::remove_all(dir);
266         boost::filesystem::create_directories(dir);
267         Config::instance()->write();
268
269         auto const cinemas = dir / "cinemas.xml";
270
271         /* Back things up */
272         boost::filesystem::copy_file(dir / "2.18" / "config.xml", dir / "config_backup_for_test.xml");
273         boost::filesystem::copy_file(cinemas, dir / "cinemas_backup_for_test.xml");
274
275         /* Corrupt the cinemas */
276         Config::drop();
277         std::ofstream corrupt(cinemas.string().c_str());
278         corrupt << "foo\n";
279         corrupt.close();
280         Config::instance();
281
282         /* We should have a new cinemas.xml and the old config.xml */
283         check_text_file(dir / "2.18" / "config.xml", dir / "config_backup_for_test.xml");
284         check_text_file(cinemas, dir / "cinemas_backup_for_test.xml");
285 }
286