Fix crash with sub-sample push parts in AudioMerger.
[dcpomatic.git] / test / dcpomatic_time_test.cc
1 /*
2     Copyright (C) 2015-2017 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 /** @file  test/dcpomatic_time_test.cc
22  *  @brief Test Time and TimePeriod classes.
23  *  @ingroup selfcontained
24  */
25
26 #include "lib/dcpomatic_time.h"
27 #include "lib/dcpomatic_time_coalesce.h"
28 #include <boost/test/unit_test.hpp>
29 #include <list>
30 #include <iostream>
31
32 using std::list;
33 using std::cout;
34 using namespace dcpomatic;
35
36 BOOST_AUTO_TEST_CASE (dcpomatic_time_test)
37 {
38         FrameRateChange frc (24, 48);
39         int j = 0;
40         int k = 0;
41         for (int64_t i = 0; i < 62000; i += 2000) {
42                 DCPTime d (i);
43                 ContentTime c (d, frc);
44                 BOOST_CHECK_EQUAL (c.frames_floor (24.0), j);
45                 ++k;
46                 if (k == 2) {
47                         ++j;
48                         k = 0;
49                 }
50         }
51 }
52
53 BOOST_AUTO_TEST_CASE (dcpomatic_time_period_overlaps_test)
54 {
55         /* Taking times as the start of a sampling interval
56
57            |--|--|--|--|--|--|--|--|--|--|
58            0  1  2  3  4  5  6  7  8  9  |
59            |--|--|--|--|--|--|--|--|--|--|
60
61            <------a----><----b----->
62
63            and saying `from' is the start of the first sampling
64            interval and `to' is the start of the interval after
65            the period... a and b do not overlap.
66         */
67
68         TimePeriod<DCPTime> a (DCPTime (0), DCPTime (4));
69         TimePeriod<DCPTime> b (DCPTime (4), DCPTime (8));
70         BOOST_CHECK (!a.overlap (b));
71
72         /* Some more obvious non-overlaps */
73         a = TimePeriod<DCPTime> (DCPTime (0), DCPTime (4));
74         b = TimePeriod<DCPTime> (DCPTime (5), DCPTime (8));
75         BOOST_CHECK (!a.overlap (b));
76
77         /* Some overlaps */
78         a = TimePeriod<DCPTime> (DCPTime (0), DCPTime (4));
79         b = TimePeriod<DCPTime> (DCPTime (3), DCPTime (8));
80         BOOST_CHECK (a.overlap(b));
81         BOOST_CHECK (a.overlap(b).get() == DCPTimePeriod(DCPTime(3), DCPTime(4)));
82         a = TimePeriod<DCPTime> (DCPTime (1), DCPTime (9));
83         b = TimePeriod<DCPTime> (DCPTime (0), DCPTime (10));
84         BOOST_CHECK (a.overlap(b));
85         BOOST_CHECK (a.overlap(b).get() == DCPTimePeriod(DCPTime(1), DCPTime(9)));
86 }
87
88 BOOST_AUTO_TEST_CASE (dcpomatic_time_period_subtract_test1)
89 {
90         DCPTimePeriod A (DCPTime (0), DCPTime (106));
91         list<DCPTimePeriod> B;
92         B.push_back (DCPTimePeriod (DCPTime (0), DCPTime (42)));
93         B.push_back (DCPTimePeriod (DCPTime (52), DCPTime (91)));
94         B.push_back (DCPTimePeriod (DCPTime (94), DCPTime (106)));
95         list<DCPTimePeriod> r = subtract (A, B);
96         list<DCPTimePeriod>::const_iterator i = r.begin ();
97         BOOST_REQUIRE (i != r.end ());
98         BOOST_CHECK (i->from == DCPTime (42));
99         BOOST_CHECK (i->to == DCPTime (52));
100         ++i;
101         BOOST_REQUIRE (i != r.end ());
102         BOOST_CHECK (i->from == DCPTime (91));
103         BOOST_CHECK (i->to == DCPTime (94));
104         ++i;
105         BOOST_REQUIRE (i == r.end ());
106 }
107
108 BOOST_AUTO_TEST_CASE (dcpomatic_time_period_subtract_test2)
109 {
110         DCPTimePeriod A (DCPTime (0), DCPTime (106));
111         list<DCPTimePeriod> B;
112         B.push_back (DCPTimePeriod (DCPTime (14), DCPTime (42)));
113         B.push_back (DCPTimePeriod (DCPTime (52), DCPTime (91)));
114         B.push_back (DCPTimePeriod (DCPTime (94), DCPTime (106)));
115         list<DCPTimePeriod> r = subtract (A, B);
116         list<DCPTimePeriod>::const_iterator i = r.begin ();
117         BOOST_REQUIRE (i != r.end ());
118         BOOST_CHECK (i->from == DCPTime (0));
119         BOOST_CHECK (i->to == DCPTime (14));
120         ++i;
121         BOOST_REQUIRE (i != r.end ());
122         BOOST_CHECK (i->from == DCPTime (42));
123         BOOST_CHECK (i->to == DCPTime (52));
124         ++i;
125         BOOST_REQUIRE (i != r.end ());
126         BOOST_CHECK (i->from == DCPTime (91));
127         BOOST_CHECK (i->to == DCPTime (94));
128         ++i;
129         BOOST_REQUIRE (i == r.end ());
130 }
131
132 BOOST_AUTO_TEST_CASE (dcpomatic_time_period_subtract_test3)
133 {
134         DCPTimePeriod A (DCPTime (0), DCPTime (106));
135         list<DCPTimePeriod> B;
136         B.push_back (DCPTimePeriod (DCPTime (14), DCPTime (42)));
137         B.push_back (DCPTimePeriod (DCPTime (52), DCPTime (91)));
138         B.push_back (DCPTimePeriod (DCPTime (94), DCPTime (99)));
139         list<DCPTimePeriod> r = subtract (A, B);
140         list<DCPTimePeriod>::const_iterator i = r.begin ();
141         BOOST_REQUIRE (i != r.end ());
142         BOOST_CHECK (i->from == DCPTime (0));
143         BOOST_CHECK (i->to == DCPTime (14));
144         ++i;
145         BOOST_REQUIRE (i != r.end ());
146         BOOST_CHECK (i->from == DCPTime (42));
147         BOOST_CHECK (i->to == DCPTime (52));
148         ++i;
149         BOOST_REQUIRE (i != r.end ());
150         BOOST_CHECK (i->from == DCPTime (91));
151         BOOST_CHECK (i->to == DCPTime (94));
152         ++i;
153         BOOST_REQUIRE (i != r.end ());
154         BOOST_CHECK (i->from == DCPTime (99));
155         BOOST_CHECK (i->to == DCPTime (106));
156         ++i;
157         BOOST_REQUIRE (i == r.end ());
158 }
159
160 BOOST_AUTO_TEST_CASE (dcpomatic_time_period_subtract_test4)
161 {
162         DCPTimePeriod A (DCPTime (0), DCPTime (106));
163         list<DCPTimePeriod> B;
164         list<DCPTimePeriod> r = subtract (A, B);
165         list<DCPTimePeriod>::const_iterator i = r.begin ();
166         BOOST_REQUIRE (i != r.end ());
167         BOOST_CHECK (i->from == DCPTime (0));
168         BOOST_CHECK (i->to == DCPTime (106));
169         ++i;
170         BOOST_REQUIRE (i == r.end ());
171 }
172
173 BOOST_AUTO_TEST_CASE (dcpomatic_time_period_subtract_test5)
174 {
175         DCPTimePeriod A (DCPTime (0), DCPTime (106));
176         list<DCPTimePeriod> B;
177         B.push_back (DCPTimePeriod (DCPTime (14), DCPTime (42)));
178         B.push_back (DCPTimePeriod (DCPTime (42), DCPTime (91)));
179         B.push_back (DCPTimePeriod (DCPTime (94), DCPTime (99)));
180         list<DCPTimePeriod> r = subtract (A, B);
181         list<DCPTimePeriod>::const_iterator i = r.begin ();
182         BOOST_REQUIRE (i != r.end ());
183         BOOST_CHECK (i->from == DCPTime (0));
184         BOOST_CHECK (i->to == DCPTime (14));
185         ++i;
186         BOOST_REQUIRE (i != r.end ());
187         BOOST_CHECK (i->from ==DCPTime (91));
188         BOOST_CHECK (i->to == DCPTime (94));
189         ++i;
190         BOOST_REQUIRE (i != r.end ());
191         BOOST_CHECK (i->from == DCPTime (99));
192         BOOST_CHECK (i->to == DCPTime (106));
193         ++i;
194         BOOST_REQUIRE (i == r.end ());
195 }
196
197 BOOST_AUTO_TEST_CASE (dcpomatic_time_period_subtract_test6)
198 {
199         DCPTimePeriod A (DCPTime (0), DCPTime (106));
200         list<DCPTimePeriod> B;
201         B.push_back (DCPTimePeriod (DCPTime (0), DCPTime (42)));
202         B.push_back (DCPTimePeriod (DCPTime (42), DCPTime (91)));
203         B.push_back (DCPTimePeriod (DCPTime (91), DCPTime (106)));
204         list<DCPTimePeriod> r = subtract (A, B);
205         BOOST_CHECK (r.empty());
206 }
207
208 BOOST_AUTO_TEST_CASE (dcpomatic_time_period_subtract_test7)
209 {
210         DCPTimePeriod A (DCPTime (228), DCPTime (356));
211         list<DCPTimePeriod> B;
212         B.push_back (DCPTimePeriod (DCPTime (34), DCPTime (162)));
213         list<DCPTimePeriod> r = subtract (A, B);
214         list<DCPTimePeriod>::const_iterator i = r.begin ();
215         BOOST_REQUIRE (i != r.end ());
216         BOOST_CHECK (i->from == DCPTime (228));
217         BOOST_CHECK (i->to == DCPTime (356));
218         ++i;
219         BOOST_REQUIRE (i == r.end ());
220 }
221
222 BOOST_AUTO_TEST_CASE (dcpomatic_time_period_subtract_test8)
223 {
224         DCPTimePeriod A (DCPTime(0), DCPTime(32000));
225         list<DCPTimePeriod> B;
226         B.push_back (DCPTimePeriod (DCPTime(8000), DCPTime(20000)));
227         B.push_back (DCPTimePeriod (DCPTime(28000), DCPTime(32000)));
228         list<DCPTimePeriod> r = subtract (A, B);
229         list<DCPTimePeriod>::const_iterator i = r.begin ();
230         BOOST_REQUIRE (i != r.end ());
231         BOOST_CHECK (*i == DCPTimePeriod(DCPTime(0), DCPTime(8000)));
232         ++i;
233         BOOST_REQUIRE (i != r.end ());
234         BOOST_CHECK (*i == DCPTimePeriod(DCPTime(20000), DCPTime(28000)));
235         ++i;
236         BOOST_REQUIRE (i == r.end ());
237 }
238
239 BOOST_AUTO_TEST_CASE (dcpomatic_time_period_coalesce_test1)
240 {
241         DCPTimePeriod A (DCPTime(14), DCPTime(29));
242         DCPTimePeriod B (DCPTime(45), DCPTime(91));
243         list<DCPTimePeriod> p;
244         p.push_back (A);
245         p.push_back (B);
246         list<DCPTimePeriod> q = coalesce (p);
247         BOOST_REQUIRE_EQUAL (q.size(), 2);
248         BOOST_CHECK (q.front() == DCPTimePeriod(DCPTime(14), DCPTime(29)));
249         BOOST_CHECK (q.back () == DCPTimePeriod(DCPTime(45), DCPTime(91)));
250 }
251
252 BOOST_AUTO_TEST_CASE (dcpomatic_time_period_coalesce_test2)
253 {
254         DCPTimePeriod A (DCPTime(14), DCPTime(29));
255         DCPTimePeriod B (DCPTime(26), DCPTime(91));
256         list<DCPTimePeriod> p;
257         p.push_back (A);
258         p.push_back (B);
259         list<DCPTimePeriod> q = coalesce (p);
260         BOOST_REQUIRE_EQUAL (q.size(), 1);
261         BOOST_CHECK (q.front() == DCPTimePeriod(DCPTime(14), DCPTime(91)));
262 }
263
264 BOOST_AUTO_TEST_CASE (dcpomatic_time_period_coalesce_test3)
265 {
266         DCPTimePeriod A (DCPTime(14), DCPTime(29));
267         DCPTimePeriod B (DCPTime(29), DCPTime(91));
268         list<DCPTimePeriod> p;
269         p.push_back (A);
270         p.push_back (B);
271         list<DCPTimePeriod> q = coalesce (p);
272         BOOST_REQUIRE_EQUAL (q.size(), 1);
273         BOOST_CHECK (q.front() == DCPTimePeriod(DCPTime(14), DCPTime(91)));
274 }
275
276 BOOST_AUTO_TEST_CASE (dcpomatic_time_period_coalesce_test4)
277 {
278         DCPTimePeriod A (DCPTime(14), DCPTime(29));
279         DCPTimePeriod B (DCPTime(20), DCPTime(91));
280         DCPTimePeriod C (DCPTime(35), DCPTime(106));
281         list<DCPTimePeriod> p;
282         p.push_back (A);
283         p.push_back (B);
284         p.push_back (C);
285         list<DCPTimePeriod> q = coalesce (p);
286         BOOST_REQUIRE_EQUAL (q.size(), 1);
287         BOOST_CHECK (q.front() == DCPTimePeriod(DCPTime(14), DCPTime(106)));
288 }
289
290 BOOST_AUTO_TEST_CASE (dcpomatic_time_period_coalesce_test5)
291 {
292         DCPTimePeriod A (DCPTime(14), DCPTime(29));
293         DCPTimePeriod B (DCPTime(20), DCPTime(91));
294         DCPTimePeriod C (DCPTime(100), DCPTime(106));
295         list<DCPTimePeriod> p;
296         p.push_back (A);
297         p.push_back (B);
298         p.push_back (C);
299         list<DCPTimePeriod> q = coalesce (p);
300         BOOST_REQUIRE_EQUAL (q.size(), 2);
301         BOOST_CHECK (q.front() == DCPTimePeriod(DCPTime(14), DCPTime(91)));
302         BOOST_CHECK (q.back()  == DCPTimePeriod(DCPTime(100), DCPTime(106)));
303 }
304
305 /* Straightforward test of DCPTime::ceil */
306 BOOST_AUTO_TEST_CASE (dcpomatic_time_ceil_test)
307 {
308         BOOST_CHECK_EQUAL (DCPTime(0).ceil(DCPTime::HZ / 2).get(), 0);
309         BOOST_CHECK_EQUAL (DCPTime(1).ceil(DCPTime::HZ / 2).get(), 2);
310         BOOST_CHECK_EQUAL (DCPTime(2).ceil(DCPTime::HZ / 2).get(), 2);
311         BOOST_CHECK_EQUAL (DCPTime(3).ceil(DCPTime::HZ / 2).get(), 4);
312
313         BOOST_CHECK_EQUAL (DCPTime(0).ceil(DCPTime::HZ / 42).get(), 0);
314         BOOST_CHECK_EQUAL (DCPTime(1).ceil(DCPTime::HZ / 42).get(), 42);
315         BOOST_CHECK_EQUAL (DCPTime(42).ceil(DCPTime::HZ / 42).get(), 42);
316         BOOST_CHECK_EQUAL (DCPTime(43).ceil(DCPTime::HZ / 42).get(), 84);
317
318         /* Check that rounding up to non-integer frame rates works */
319         BOOST_CHECK_EQUAL (DCPTime(45312).ceil(29.976).get(), 48038);
320
321         /* Check another tricky case that used to fail */
322         BOOST_CHECK_EQUAL (DCPTime(212256039).ceil(23.976).get(), 212256256);
323 }
324
325 /* Straightforward test of DCPTime::floor */
326 BOOST_AUTO_TEST_CASE (dcpomatic_time_floor_test)
327 {
328         BOOST_CHECK_EQUAL (DCPTime(0).floor(DCPTime::HZ / 2).get(), 0);
329         BOOST_CHECK_EQUAL (DCPTime(1).floor(DCPTime::HZ / 2).get(), 0);
330         BOOST_CHECK_EQUAL (DCPTime(2).floor(DCPTime::HZ / 2).get(), 2);
331         BOOST_CHECK_EQUAL (DCPTime(3).floor(DCPTime::HZ / 2).get(), 2);
332
333         BOOST_CHECK_EQUAL (DCPTime(0).floor(DCPTime::HZ / 42).get(), 0);
334         BOOST_CHECK_EQUAL (DCPTime(1).floor(DCPTime::HZ / 42).get(), 0);
335         BOOST_CHECK_EQUAL (DCPTime(42).floor(DCPTime::HZ / 42.0).get(), 42);
336         BOOST_CHECK_EQUAL (DCPTime(43).floor(DCPTime::HZ / 42.0).get(), 42);
337
338         /* Check that rounding down to non-integer frame rates works */
339         BOOST_CHECK_EQUAL (DCPTime(45312).floor(29.976).get(), 44836);
340 }