Merge branch 'master' of /home/carl/git/dvdomatic
[dcpomatic.git] / test / test.cc
1 /*
2     Copyright (C) 2012 Carl Hetherington <cth@carlh.net>
3
4     This program is free software; you can redistribute it and/or modify
5     it under the terms of the GNU General Public License as published by
6     the Free Software Foundation; either version 2 of the License, or
7     (at your option) any later version.
8
9     This program is distributed in the hope that it will be useful,
10     but WITHOUT ANY WARRANTY; without even the implied warranty of
11     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12     GNU General Public License for more details.
13
14     You should have received a copy of the GNU General Public License
15     along with this program; if not, write to the Free Software
16     Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
17
18 */
19
20 #include <fstream>
21 #include <iostream>
22 #include <boost/filesystem.hpp>
23 #include <boost/algorithm/string/predicate.hpp>
24 #include "format.h"
25 #include "film.h"
26 #include "filter.h"
27 #include "job_manager.h"
28 #include "util.h"
29 #include "exceptions.h"
30 #include "dvd.h"
31 #include "delay_line.h"
32 #include "image.h"
33 #include "log.h"
34 #include "dcp_video_frame.h"
35 #include "config.h"
36 #include "server.h"
37 #define BOOST_TEST_DYN_LINK
38 #define BOOST_TEST_MODULE dvdomatic_test
39 #include <boost/test/unit_test.hpp>
40
41 using namespace std;
42 using namespace boost;
43
44 BOOST_AUTO_TEST_CASE (film_metadata_test)
45 {
46         dvdomatic_setup ();
47         
48         string const test_film = "build/test/film";
49         
50         if (boost::filesystem::exists (test_film)) {
51                 boost::filesystem::remove_all (test_film);
52         }
53
54         BOOST_CHECK_THROW (new Film ("build/test/film", true), OpenFileError);
55         
56         Film f (test_film, false);
57         BOOST_CHECK (f.format() == 0);
58         BOOST_CHECK (f.dcp_content_type() == 0);
59         BOOST_CHECK (f.filters ().empty());
60
61         f.set_name ("fred");
62         BOOST_CHECK_THROW (f.set_content ("jim"), OpenFileError);
63         f.set_dcp_content_type (DCPContentType::from_pretty_name ("Short"));
64         f.set_format (Format::from_nickname ("Flat"));
65         f.set_left_crop (1);
66         f.set_right_crop (2);
67         f.set_top_crop (3);
68         f.set_bottom_crop (4);
69         vector<Filter const *> f_filters;
70         f_filters.push_back (Filter::from_id ("pphb"));
71         f_filters.push_back (Filter::from_id ("unsharp"));
72         f.set_filters (f_filters);
73         f.set_dcp_frames (42);
74         f.set_dcp_ab (true);
75         f.write_metadata ();
76
77         stringstream s;
78         s << "diff -u test/metadata.ref " << test_film << "/metadata";
79         BOOST_CHECK_EQUAL (::system (s.str().c_str ()), 0);
80
81         Film g (test_film, true);
82
83         BOOST_CHECK_EQUAL (g.name(), "fred");
84         BOOST_CHECK_EQUAL (g.dcp_content_type(), DCPContentType::from_pretty_name ("Short"));
85         BOOST_CHECK_EQUAL (g.format(), Format::from_nickname ("Flat"));
86         BOOST_CHECK_EQUAL (g.crop().left, 1);
87         BOOST_CHECK_EQUAL (g.crop().right, 2);
88         BOOST_CHECK_EQUAL (g.crop().top, 3);
89         BOOST_CHECK_EQUAL (g.crop().bottom, 4);
90         vector<Filter const *> g_filters = g.filters ();
91         BOOST_CHECK_EQUAL (g_filters.size(), 2);
92         BOOST_CHECK_EQUAL (g_filters.front(), Filter::from_id ("pphb"));
93         BOOST_CHECK_EQUAL (g_filters.back(), Filter::from_id ("unsharp"));
94         BOOST_CHECK_EQUAL (g.dcp_frames(), 42);
95         BOOST_CHECK_EQUAL (g.dcp_ab(), true);
96         
97         g.write_metadata ();
98         BOOST_CHECK_EQUAL (::system (s.str().c_str ()), 0);
99 }
100
101 BOOST_AUTO_TEST_CASE (format_test)
102 {
103         Format::setup_formats ();
104         
105         Format const * f = Format::from_nickname ("Flat");
106         BOOST_CHECK (f);
107         BOOST_CHECK_EQUAL (f->ratio_as_integer(), 185);
108         
109         f = Format::from_nickname ("Scope");
110         BOOST_CHECK (f);
111         BOOST_CHECK_EQUAL (f->ratio_as_integer(), 239);
112 }
113
114 BOOST_AUTO_TEST_CASE (util_test)
115 {
116         string t = "Hello this is a string \"with quotes\" and indeed without them";
117         vector<string> b = split_at_spaces_considering_quotes (t);
118         vector<string>::iterator i = b.begin ();
119         BOOST_CHECK_EQUAL (*i++, "Hello");
120         BOOST_CHECK_EQUAL (*i++, "this");
121         BOOST_CHECK_EQUAL (*i++, "is");
122         BOOST_CHECK_EQUAL (*i++, "a");
123         BOOST_CHECK_EQUAL (*i++, "string");
124         BOOST_CHECK_EQUAL (*i++, "with quotes");
125         BOOST_CHECK_EQUAL (*i++, "and");
126         BOOST_CHECK_EQUAL (*i++, "indeed");
127         BOOST_CHECK_EQUAL (*i++, "without");
128         BOOST_CHECK_EQUAL (*i++, "them");
129 }
130
131 BOOST_AUTO_TEST_CASE (dvd_test)
132 {
133         list<DVDTitle> const t = dvd_titles ("test/dvd");
134         BOOST_CHECK_EQUAL (t.size(), 3);
135         list<DVDTitle>::const_iterator i = t.begin ();
136         
137         BOOST_CHECK_EQUAL (i->number, 1);
138         BOOST_CHECK_EQUAL (i->size, 0);
139         ++i;
140         
141         BOOST_CHECK_EQUAL (i->number, 2);
142         BOOST_CHECK_EQUAL (i->size, 14);
143         ++i;
144         
145         BOOST_CHECK_EQUAL (i->number, 3);
146         BOOST_CHECK_EQUAL (i->size, 7);
147 }
148
149 void
150 do_positive_delay_line_test (int delay_length, int block_length)
151 {
152         DelayLine d (delay_length);
153         uint8_t data[block_length];
154
155         int in = 0;
156         int out = 0;
157         int returned = 0;
158         int zeros = 0;
159         
160         for (int i = 0; i < 64; ++i) {
161                 for (int j = 0; j < block_length; ++j) {
162                         data[j] = in;
163                         ++in;
164                 }
165
166                 int const a = d.feed (data, block_length);
167                 returned += a;
168
169                 for (int j = 0; j < a; ++j) {
170                         if (zeros < delay_length) {
171                                 BOOST_CHECK_EQUAL (data[j], 0);
172                                 ++zeros;
173                         } else {
174                                 BOOST_CHECK_EQUAL (data[j], out & 0xff);
175                                 ++out;
176                         }
177                 }
178         }
179
180         BOOST_CHECK_EQUAL (returned, 64 * block_length);
181 }
182
183 void
184 do_negative_delay_line_test (int delay_length, int block_length)
185 {
186         DelayLine d (delay_length);
187         uint8_t data[block_length];
188
189         int in = 0;
190         int out = -delay_length;
191         int returned = 0;
192         
193         for (int i = 0; i < 256; ++i) {
194                 for (int j = 0; j < block_length; ++j) {
195                         data[j] = in;
196                         ++in;
197                 }
198
199                 int const a = d.feed (data, block_length);
200                 returned += a;
201
202                 for (int j = 0; j < a; ++j) {
203                         BOOST_CHECK_EQUAL (data[j], out & 0xff);
204                         ++out;
205                 }
206         }
207
208         uint8_t remainder[-delay_length];
209         d.get_remaining (remainder);
210         returned += -delay_length;
211
212         for (int i = 0; i < -delay_length; ++i) {
213                 BOOST_CHECK_EQUAL (remainder[i], 0);
214                 ++out;
215         }
216
217         BOOST_CHECK_EQUAL (returned, 256 * block_length);
218         
219 }
220
221 BOOST_AUTO_TEST_CASE (delay_line_test)
222 {
223         do_positive_delay_line_test (64, 128);
224         do_positive_delay_line_test (128, 64);
225         do_positive_delay_line_test (3, 512);
226         do_positive_delay_line_test (512, 3);
227
228         do_positive_delay_line_test (0, 64);
229
230         do_negative_delay_line_test (-64, 128);
231         do_negative_delay_line_test (-128, 64);
232         do_negative_delay_line_test (-3, 512);
233         do_negative_delay_line_test (-512, 3);
234 }
235
236 BOOST_AUTO_TEST_CASE (md5_digest_test)
237 {
238         string const t = md5_digest ("test/md5.test");
239         BOOST_CHECK_EQUAL (t, "15058685ba99decdc4398c7634796eb0");
240
241         BOOST_CHECK_THROW (md5_digest ("foobar"), OpenFileError);
242 }
243
244 BOOST_AUTO_TEST_CASE (paths_test)
245 {
246         FilmState s;
247         s.directory = "build/test/a/b/c/d/e";
248         s.thumbs.push_back (42);
249         BOOST_CHECK_EQUAL (s.thumb_file (0), "build/test/a/b/c/d/e/thumbs/00000042.tiff");
250
251         s.content = "/foo/bar/baz";
252         BOOST_CHECK_EQUAL (s.content_path(), "/foo/bar/baz");
253         s.content = "foo/bar/baz";
254         BOOST_CHECK_EQUAL (s.content_path(), "build/test/a/b/c/d/e/foo/bar/baz");
255 }
256
257 void
258 do_remote_encode (shared_ptr<DCPVideoFrame> frame, ServerDescription* description, shared_ptr<EncodedData> locally_encoded)
259 {
260         shared_ptr<EncodedData> remotely_encoded;
261         BOOST_CHECK_NO_THROW (remotely_encoded = frame->encode_remotely (description));
262         BOOST_CHECK (remotely_encoded);
263         
264         BOOST_CHECK_EQUAL (locally_encoded->size(), remotely_encoded->size());
265         BOOST_CHECK (memcmp (locally_encoded->data(), remotely_encoded->data(), locally_encoded->size()) == 0);
266 }
267
268 BOOST_AUTO_TEST_CASE (client_server_test)
269 {
270         shared_ptr<SimpleImage> image (new SimpleImage (PIX_FMT_RGB24, Size (1998, 1080)));
271         image->set_line_size (0, 1998 * 3);
272
273         uint8_t* p = image->data()[0];
274         
275         for (int y = 0; y < 1080; ++y) {
276                 for (int x = 0; x < 1998; ++x) {
277                         *p++ = x % 256;
278                         *p++ = y % 256;
279                         *p++ = (x + y) % 256;
280                 }
281         }
282
283         FileLog log ("build/test/client_server_test.log");
284
285         shared_ptr<DCPVideoFrame> frame (
286                 new DCPVideoFrame (
287                         image,
288                         Size (1998, 1080),
289                         0,
290                         Scaler::from_id ("bicubic"),
291                         0,
292                         24,
293                         "",
294                         0,
295                         200000000,
296                         &log
297                         )
298                 );
299
300         shared_ptr<EncodedData> locally_encoded = frame->encode_locally ();
301         
302         Config::instance()->set_server_port (61920);
303         Server* server = new Server (&log);
304
305         new thread (boost::bind (&Server::run, server, 2));
306
307         ServerDescription description ("localhost", 2);
308
309         list<thread*> threads;
310         for (int i = 0; i < 8; ++i) {
311                 threads.push_back (new thread (boost::bind (do_remote_encode, frame, &description, locally_encoded)));
312         }
313
314         for (list<thread*>::iterator i = threads.begin(); i != threads.end(); ++i) {
315                 (*i)->join ();
316         }
317 }