Add overlap() for lists of time periods.
[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
22 /** @file  test/dcpomatic_time_test.cc
23  *  @brief Test dcpomatic::Time and dcpomatic::TimePeriod classes.
24  *  @ingroup selfcontained
25  */
26
27
28 #include "lib/dcpomatic_time.h"
29 #include "lib/dcpomatic_time_coalesce.h"
30 #include "lib/dcpomatic_time_overlap.h"
31 #include <boost/test/unit_test.hpp>
32 #include <iostream>
33 #include <list>
34
35
36 using std::cout;
37 using std::list;
38 using namespace dcpomatic;
39
40
41 BOOST_AUTO_TEST_CASE (dcpomatic_time_test)
42 {
43         FrameRateChange frc (24, 48);
44         int j = 0;
45         int k = 0;
46         for (int64_t i = 0; i < 62000; i += 2000) {
47                 DCPTime d (i);
48                 ContentTime c (d, frc);
49                 BOOST_CHECK_EQUAL (c.frames_floor (24.0), j);
50                 ++k;
51                 if (k == 2) {
52                         ++j;
53                         k = 0;
54                 }
55         }
56 }
57
58
59 BOOST_AUTO_TEST_CASE (dcpomatic_time_period_overlaps_test)
60 {
61         /* Taking times as the start of a sampling interval
62
63            |--|--|--|--|--|--|--|--|--|--|
64            0  1  2  3  4  5  6  7  8  9  |
65            |--|--|--|--|--|--|--|--|--|--|
66
67            <------a----><----b----->
68
69            and saying `from' is the start of the first sampling
70            interval and `to' is the start of the interval after
71            the period... a and b do not overlap.
72         */
73
74         TimePeriod<DCPTime> a (DCPTime(0), DCPTime(4));
75         TimePeriod<DCPTime> b (DCPTime (4), DCPTime (8));
76         BOOST_CHECK (!a.overlap (b));
77
78         /* Some more obvious non-overlaps */
79         a = TimePeriod<DCPTime> (DCPTime (0), DCPTime (4));
80         b = TimePeriod<DCPTime> (DCPTime (5), DCPTime (8));
81         BOOST_CHECK (!a.overlap (b));
82
83         /* Some overlaps */
84         a = TimePeriod<DCPTime> (DCPTime (0), DCPTime (4));
85         b = TimePeriod<DCPTime> (DCPTime (3), DCPTime (8));
86         BOOST_CHECK (a.overlap(b));
87         BOOST_CHECK (a.overlap(b).get() == DCPTimePeriod(DCPTime(3), DCPTime(4)));
88         a = TimePeriod<DCPTime> (DCPTime (1), DCPTime (9));
89         b = TimePeriod<DCPTime> (DCPTime (0), DCPTime (10));
90         BOOST_CHECK (a.overlap(b));
91         BOOST_CHECK (a.overlap(b).get() == DCPTimePeriod(DCPTime(1), DCPTime(9)));
92 }
93
94
95 BOOST_AUTO_TEST_CASE (dcpomatic_time_period_subtract_test1)
96 {
97         DCPTimePeriod A (DCPTime (0), DCPTime (106));
98         list<DCPTimePeriod> B = {
99                 DCPTimePeriod(DCPTime(0), DCPTime(42)),
100                 DCPTimePeriod(DCPTime(52), DCPTime(91)),
101                 DCPTimePeriod(DCPTime(94), DCPTime(106))
102         };
103         auto r = subtract ({A}, B);
104         auto i = r.begin ();
105         BOOST_REQUIRE (i != r.end ());
106         BOOST_CHECK (i->from == DCPTime (42));
107         BOOST_CHECK (i->to == DCPTime (52));
108         ++i;
109         BOOST_REQUIRE (i != r.end ());
110         BOOST_CHECK (i->from == DCPTime (91));
111         BOOST_CHECK (i->to == DCPTime (94));
112         ++i;
113         BOOST_REQUIRE (i == r.end ());
114 }
115
116
117 BOOST_AUTO_TEST_CASE (dcpomatic_time_period_subtract_test2)
118 {
119         DCPTimePeriod A (DCPTime (0), DCPTime (106));
120         list<DCPTimePeriod> B = {
121                 DCPTimePeriod(DCPTime(14), DCPTime(42)),
122                 DCPTimePeriod(DCPTime(52), DCPTime(91)),
123                 DCPTimePeriod(DCPTime(94), DCPTime(106))
124         };
125         auto r = subtract ({A}, B);
126         auto i = r.begin ();
127         BOOST_REQUIRE (i != r.end ());
128         BOOST_CHECK (i->from == DCPTime (0));
129         BOOST_CHECK (i->to == DCPTime (14));
130         ++i;
131         BOOST_REQUIRE (i != r.end ());
132         BOOST_CHECK (i->from == DCPTime (42));
133         BOOST_CHECK (i->to == DCPTime (52));
134         ++i;
135         BOOST_REQUIRE (i != r.end ());
136         BOOST_CHECK (i->from == DCPTime (91));
137         BOOST_CHECK (i->to == DCPTime (94));
138         ++i;
139         BOOST_REQUIRE (i == r.end ());
140 }
141
142
143 BOOST_AUTO_TEST_CASE (dcpomatic_time_period_subtract_test3)
144 {
145         DCPTimePeriod A (DCPTime (0), DCPTime (106));
146         list<DCPTimePeriod> B = {
147                 DCPTimePeriod(DCPTime(14), DCPTime(42)),
148                 DCPTimePeriod(DCPTime(52), DCPTime(91)),
149                 DCPTimePeriod(DCPTime(94), DCPTime(99))
150         };
151         auto r = subtract ({A}, B);
152         auto i = r.begin ();
153         BOOST_REQUIRE (i != r.end ());
154         BOOST_CHECK (i->from == DCPTime (0));
155         BOOST_CHECK (i->to == DCPTime (14));
156         ++i;
157         BOOST_REQUIRE (i != r.end ());
158         BOOST_CHECK (i->from == DCPTime (42));
159         BOOST_CHECK (i->to == DCPTime (52));
160         ++i;
161         BOOST_REQUIRE (i != r.end ());
162         BOOST_CHECK (i->from == DCPTime (91));
163         BOOST_CHECK (i->to == DCPTime (94));
164         ++i;
165         BOOST_REQUIRE (i != r.end ());
166         BOOST_CHECK (i->from == DCPTime (99));
167         BOOST_CHECK (i->to == DCPTime (106));
168         ++i;
169         BOOST_REQUIRE (i == r.end ());
170 }
171
172
173 BOOST_AUTO_TEST_CASE (dcpomatic_time_period_subtract_test4)
174 {
175         DCPTimePeriod A (DCPTime (0), DCPTime (106));
176         list<DCPTimePeriod> B;
177         auto r = subtract ({A}, B);
178         auto i = r.begin ();
179         BOOST_REQUIRE (i != r.end ());
180         BOOST_CHECK (i->from == DCPTime (0));
181         BOOST_CHECK (i->to == DCPTime (106));
182         ++i;
183         BOOST_REQUIRE (i == r.end ());
184 }
185
186
187 BOOST_AUTO_TEST_CASE (dcpomatic_time_period_subtract_test5)
188 {
189         DCPTimePeriod A (DCPTime (0), DCPTime (106));
190         list<DCPTimePeriod> B = {
191                 DCPTimePeriod(DCPTime(14), DCPTime(42)),
192                 DCPTimePeriod(DCPTime(42), DCPTime(91)),
193                 DCPTimePeriod(DCPTime(94), DCPTime(99))
194         };
195         auto r = subtract ({A}, B);
196         auto i = r.begin ();
197         BOOST_REQUIRE (i != r.end ());
198         BOOST_CHECK (i->from == DCPTime (0));
199         BOOST_CHECK (i->to == DCPTime (14));
200         ++i;
201         BOOST_REQUIRE (i != r.end ());
202         BOOST_CHECK (i->from ==DCPTime (91));
203         BOOST_CHECK (i->to == DCPTime (94));
204         ++i;
205         BOOST_REQUIRE (i != r.end ());
206         BOOST_CHECK (i->from == DCPTime (99));
207         BOOST_CHECK (i->to == DCPTime (106));
208         ++i;
209         BOOST_REQUIRE (i == r.end ());
210 }
211
212
213 BOOST_AUTO_TEST_CASE (dcpomatic_time_period_subtract_test6)
214 {
215         DCPTimePeriod A (DCPTime (0), DCPTime (106));
216         list<DCPTimePeriod> B = {
217                 DCPTimePeriod(DCPTime(0), DCPTime(42)),
218                 DCPTimePeriod(DCPTime(42), DCPTime(91)),
219                 DCPTimePeriod(DCPTime(91), DCPTime(106))
220         };
221         auto r = subtract ({A}, B);
222         BOOST_CHECK (r.empty());
223 }
224
225
226 BOOST_AUTO_TEST_CASE (dcpomatic_time_period_subtract_test7)
227 {
228         DCPTimePeriod A (DCPTime (228), DCPTime (356));
229         list<DCPTimePeriod> B = {
230                 DCPTimePeriod(DCPTime(34), DCPTime(162))
231         };
232         auto r = subtract ({A}, B);
233         auto i = r.begin ();
234         BOOST_REQUIRE (i != r.end ());
235         BOOST_CHECK (i->from == DCPTime (228));
236         BOOST_CHECK (i->to == DCPTime (356));
237         ++i;
238         BOOST_REQUIRE (i == r.end ());
239 }
240
241
242 BOOST_AUTO_TEST_CASE (dcpomatic_time_period_subtract_test8)
243 {
244         DCPTimePeriod A (DCPTime(0), DCPTime(32000));
245         list<DCPTimePeriod> B = {
246                 DCPTimePeriod(DCPTime(8000), DCPTime(20000)),
247                 DCPTimePeriod(DCPTime(28000), DCPTime(32000))
248         };
249         auto r = subtract ({A}, B);
250         auto i = r.begin ();
251         BOOST_REQUIRE (i != r.end ());
252         BOOST_CHECK (*i == DCPTimePeriod(DCPTime(0), DCPTime(8000)));
253         ++i;
254         BOOST_REQUIRE (i != r.end ());
255         BOOST_CHECK (*i == DCPTimePeriod(DCPTime(20000), DCPTime(28000)));
256         ++i;
257         BOOST_REQUIRE (i == r.end ());
258 }
259
260
261 BOOST_AUTO_TEST_CASE (dcpomatic_time_period_subtract_list_from_list_test1)
262 {
263         list<DCPTimePeriod> A = {
264                 DCPTimePeriod(DCPTime(0),    DCPTime(2000)),
265                 DCPTimePeriod(DCPTime(4000), DCPTime(6000))
266         };
267
268         list<DCPTimePeriod> B = {
269                 DCPTimePeriod(DCPTime(1000), DCPTime(3000)),
270                 DCPTimePeriod(DCPTime(5000), DCPTime(7000))
271         };
272
273         auto result = subtract(A, B);
274         list<DCPTimePeriod> reference = {
275                 DCPTimePeriod(DCPTime(0),    DCPTime(1000)),
276                 DCPTimePeriod(DCPTime(4000), DCPTime(5000))
277         };
278
279         BOOST_CHECK (result == reference);
280 }
281
282
283 BOOST_AUTO_TEST_CASE (dcpomatic_time_period_subtract_list_from_list_test2)
284 {
285         list<DCPTimePeriod> A = {
286                 DCPTimePeriod(DCPTime(0),    DCPTime(2000)),
287                 DCPTimePeriod(DCPTime(4000), DCPTime(6000))
288         };
289
290         list<DCPTimePeriod> B = {
291                 DCPTimePeriod(DCPTime(500),  DCPTime(1500)),
292                 DCPTimePeriod(DCPTime(4500), DCPTime(5500))
293         };
294
295         auto result = subtract(A, B);
296         list<DCPTimePeriod> reference = {
297                 DCPTimePeriod(DCPTime(0),    DCPTime(500)),
298                 DCPTimePeriod(DCPTime(1500), DCPTime(2000)),
299                 DCPTimePeriod(DCPTime(4000), DCPTime(4500)),
300                 DCPTimePeriod(DCPTime(5500), DCPTime(6000)),
301         };
302
303         BOOST_CHECK (result == reference);
304 }
305
306
307 BOOST_AUTO_TEST_CASE (dcpomatic_time_period_subtract_list_from_list_test3)
308 {
309         list<DCPTimePeriod> A = {
310                 DCPTimePeriod(DCPTime(500),  DCPTime(1500)),
311                 DCPTimePeriod(DCPTime(4500), DCPTime(5500))
312         };
313
314         list<DCPTimePeriod> B = {
315                 DCPTimePeriod(DCPTime(0),    DCPTime(2000)),
316                 DCPTimePeriod(DCPTime(4000), DCPTime(6000))
317         };
318
319         auto result = subtract(A, B);
320         BOOST_CHECK (result.empty());
321 }
322
323
324 BOOST_AUTO_TEST_CASE (dcpomatic_time_period_coalesce_test1)
325 {
326         DCPTimePeriod A (DCPTime(14), DCPTime(29));
327         DCPTimePeriod B (DCPTime(45), DCPTime(91));
328         list<DCPTimePeriod> p = { A, B };
329         auto q = coalesce (p);
330         BOOST_REQUIRE_EQUAL (q.size(), 2U);
331         BOOST_CHECK (q.front() == DCPTimePeriod(DCPTime(14), DCPTime(29)));
332         BOOST_CHECK (q.back () == DCPTimePeriod(DCPTime(45), DCPTime(91)));
333 }
334
335
336 BOOST_AUTO_TEST_CASE (dcpomatic_time_period_coalesce_test2)
337 {
338         DCPTimePeriod A (DCPTime(14), DCPTime(29));
339         DCPTimePeriod B (DCPTime(26), DCPTime(91));
340         list<DCPTimePeriod> p = { A, B };
341         auto q = coalesce (p);
342         BOOST_REQUIRE_EQUAL (q.size(), 1U);
343         BOOST_CHECK (q.front() == DCPTimePeriod(DCPTime(14), DCPTime(91)));
344 }
345
346
347 BOOST_AUTO_TEST_CASE (dcpomatic_time_period_coalesce_test3)
348 {
349         DCPTimePeriod A (DCPTime(14), DCPTime(29));
350         DCPTimePeriod B (DCPTime(29), DCPTime(91));
351         list<DCPTimePeriod> p = { A, B };
352         auto q = coalesce (p);
353         BOOST_REQUIRE_EQUAL (q.size(), 1U);
354         BOOST_CHECK (q.front() == DCPTimePeriod(DCPTime(14), DCPTime(91)));
355 }
356
357
358 BOOST_AUTO_TEST_CASE (dcpomatic_time_period_coalesce_test4)
359 {
360         DCPTimePeriod A (DCPTime(14), DCPTime(29));
361         DCPTimePeriod B (DCPTime(20), DCPTime(91));
362         DCPTimePeriod C (DCPTime(35), DCPTime(106));
363         list<DCPTimePeriod> p = { A, B, C };
364         auto q = coalesce (p);
365         BOOST_REQUIRE_EQUAL (q.size(), 1U);
366         BOOST_CHECK (q.front() == DCPTimePeriod(DCPTime(14), DCPTime(106)));
367 }
368
369
370 BOOST_AUTO_TEST_CASE (dcpomatic_time_period_coalesce_test5)
371 {
372         DCPTimePeriod A (DCPTime(14), DCPTime(29));
373         DCPTimePeriod B (DCPTime(20), DCPTime(91));
374         DCPTimePeriod C (DCPTime(100), DCPTime(106));
375         list<DCPTimePeriod> p = { A, B, C };
376         auto q = coalesce (p);
377         BOOST_REQUIRE_EQUAL (q.size(), 2U);
378         BOOST_CHECK (q.front() == DCPTimePeriod(DCPTime(14), DCPTime(91)));
379         BOOST_CHECK (q.back()  == DCPTimePeriod(DCPTime(100), DCPTime(106)));
380 }
381
382
383 BOOST_AUTO_TEST_CASE (test_coalesce_with_overlapping_periods)
384 {
385         DCPTimePeriod A (DCPTime(0), DCPTime(10));
386         DCPTimePeriod B (DCPTime(2), DCPTime(8));
387         list<DCPTimePeriod> p = { A, B };
388         auto q = coalesce(p);
389         BOOST_REQUIRE_EQUAL (q.size(), 1U);
390         BOOST_CHECK (q.front() == DCPTimePeriod(DCPTime(0), DCPTime(10)));
391 }
392
393
394 /* Straightforward test of DCPTime::ceil */
395 BOOST_AUTO_TEST_CASE (dcpomatic_time_ceil_test)
396 {
397         BOOST_CHECK_EQUAL (DCPTime(0).ceil(DCPTime::HZ / 2).get(), 0);
398         BOOST_CHECK_EQUAL (DCPTime(1).ceil(DCPTime::HZ / 2).get(), 2);
399         BOOST_CHECK_EQUAL (DCPTime(2).ceil(DCPTime::HZ / 2).get(), 2);
400         BOOST_CHECK_EQUAL (DCPTime(3).ceil(DCPTime::HZ / 2).get(), 4);
401
402         BOOST_CHECK_EQUAL (DCPTime(0).ceil(DCPTime::HZ / 42).get(), 0);
403         BOOST_CHECK_EQUAL (DCPTime(1).ceil(DCPTime::HZ / 42).get(), 42);
404         BOOST_CHECK_EQUAL (DCPTime(42).ceil(DCPTime::HZ / 42).get(), 42);
405         BOOST_CHECK_EQUAL (DCPTime(43).ceil(DCPTime::HZ / 42).get(), 84);
406
407         /* Check that rounding up to non-integer frame rates works */
408         BOOST_CHECK_EQUAL (DCPTime(45312).ceil(29.976).get(), 48038);
409
410         /* Check another tricky case that used to fail */
411         BOOST_CHECK_EQUAL (DCPTime(212256039).ceil(23.976).get(), 212256256);
412 }
413
414
415 /* Straightforward test of DCPTime::floor */
416 BOOST_AUTO_TEST_CASE (dcpomatic_time_floor_test)
417 {
418         BOOST_CHECK_EQUAL (DCPTime(0).floor(DCPTime::HZ / 2).get(), 0);
419         BOOST_CHECK_EQUAL (DCPTime(1).floor(DCPTime::HZ / 2).get(), 0);
420         BOOST_CHECK_EQUAL (DCPTime(2).floor(DCPTime::HZ / 2).get(), 2);
421         BOOST_CHECK_EQUAL (DCPTime(3).floor(DCPTime::HZ / 2).get(), 2);
422
423         BOOST_CHECK_EQUAL (DCPTime(0).floor(DCPTime::HZ / 42).get(), 0);
424         BOOST_CHECK_EQUAL (DCPTime(1).floor(DCPTime::HZ / 42).get(), 0);
425         BOOST_CHECK_EQUAL (DCPTime(42).floor(DCPTime::HZ / 42.0).get(), 42);
426         BOOST_CHECK_EQUAL (DCPTime(43).floor(DCPTime::HZ / 42.0).get(), 42);
427
428         /* Check that rounding down to non-integer frame rates works */
429         BOOST_CHECK_EQUAL (DCPTime(45312).floor(29.976).get(), 44836);
430 }
431
432
433 BOOST_AUTO_TEST_CASE (dcpomatic_time_overlap_test1)
434 {
435         list<DCPTimePeriod> A = {
436                 { DCPTime(0), DCPTime(5) }
437         };
438
439         BOOST_CHECK (overlap(A, std::list<DCPTimePeriod>()).empty());
440         BOOST_CHECK (overlap(std::list<DCPTimePeriod>(), A).empty());
441 }
442
443
444 BOOST_AUTO_TEST_CASE (dcpomatic_time_overlap_test2)
445 {
446         list<DCPTimePeriod> A = {
447                 { DCPTime(0), DCPTime(5) }
448         };
449
450         list<DCPTimePeriod> B = {
451                 { DCPTime(6), DCPTime(10) }
452         };
453
454         BOOST_CHECK (overlap(A, B).empty());
455         BOOST_CHECK (overlap(B, A).empty());
456 }
457
458
459 BOOST_AUTO_TEST_CASE (dcpomatic_time_overlap_test3)
460 {
461         list<DCPTimePeriod> A = {
462                 { DCPTime(0), DCPTime(5) }
463         };
464
465         list<DCPTimePeriod> B = {
466                 { DCPTime(2), DCPTime(3) }
467         };
468
469         std::list<DCPTimePeriod> correct = {
470                 { DCPTime(2), DCPTime(3) }
471         };
472
473         BOOST_CHECK (overlap(A, B) == correct);
474         BOOST_CHECK (overlap(B, A) == correct);
475 }
476
477
478 BOOST_AUTO_TEST_CASE (dcpomatic_time_overlap_test4)
479 {
480         list<DCPTimePeriod> A = {
481                 { DCPTime(0), DCPTime(5) }
482         };
483
484         list<DCPTimePeriod> B = {
485                 { DCPTime(0), DCPTime(5) }
486         };
487
488         std::list<DCPTimePeriod> correct = {
489                 { DCPTime(0), DCPTime(5) }
490         };
491
492         BOOST_CHECK (overlap(A, B) == correct);
493         BOOST_CHECK (overlap(B, A) == correct);
494 }
495
496
497 BOOST_AUTO_TEST_CASE (dcpomatic_time_overlap_test5)
498 {
499         list<DCPTimePeriod> A = {
500                 { DCPTime(0), DCPTime(5) },
501                 { DCPTime(7), DCPTime(12) }
502         };
503
504         list<DCPTimePeriod> B = {
505                 { DCPTime(0), DCPTime(15) }
506         };
507
508         std::list<DCPTimePeriod> correct = {
509                 { DCPTime(0), DCPTime(5) },
510                 { DCPTime(7), DCPTime(12) }
511         };
512
513         BOOST_CHECK (overlap(A, B) == correct);
514         BOOST_CHECK (overlap(B, A) == correct);
515 }
516
517
518 BOOST_AUTO_TEST_CASE (dcpomatic_time_overlap_test6)
519 {
520         list<DCPTimePeriod> A = {
521                 { DCPTime(0), DCPTime(5) },
522                 { DCPTime(7), DCPTime(12) }
523         };
524
525         list<DCPTimePeriod> B = {
526                 { DCPTime(3), DCPTime(10) }
527         };
528
529         std::list<DCPTimePeriod> correct = {
530                 { DCPTime(3), DCPTime(5) },
531                 { DCPTime(7), DCPTime(10) }
532         };
533
534         BOOST_CHECK (overlap(A, B) == correct);
535         BOOST_CHECK (overlap(B, A) == correct);
536 }