Lumiera 0.pre.04
»edit your freedom«
Loading...
Searching...
No Matches
time-value-test.cpp
Go to the documentation of this file.
1/*
2 TimeValue(Test) - working with time values and time intervals in C++...
3
4 Copyright (C)
5 2010, Hermann Vosseler <Ichthyostega@web.de>
6
7  **Lumiera** is free software; you can redistribute it and/or modify it
8  under the terms of the GNU General Public License as published by the
9  Free Software Foundation; either version 2 of the License, or (at your
10  option) any later version. See the file COPYING for further details.
11
12* *****************************************************************/
13
19#include "lib/test/run.hpp"
22#include "lib/format-cout.hpp"
23#include "lib/util.hpp"
24
25#include <boost/lexical_cast.hpp>
26#include <string>
27
28using boost::lexical_cast;
29using util::isnil;
30using std::string;
31
32using LERR_(BOTTOM_VALUE);
33
34namespace lib {
35namespace time{
36namespace test{
37
38
39 /****************************************************/
45 class TimeValue_test : public Test
46 {
48 random_or_get (Arg arg)
49 {
50 if (isnil(arg))
51 {// use random time value for all tests
52 seedRand();
53 return 1 + rani(10000);
54 }
55 else
56 return lexical_cast<raw_time_64> (arg[1]);
57 }
58
59
60 virtual void
78
79
84 void
86 {
87 TimeValue zero(0);
88 TimeValue one (1);
89 TimeValue max (Time::MAX);
90 TimeValue min (Time::MIN);
91
92 TimeValue val (org);
93
94 CHECK (zero == zero);
95 CHECK (zero <= zero);
96 CHECK (zero >= zero);
97
98 CHECK (zero < one);
99 CHECK (min < max);
100 CHECK (min < val);
101 CHECK (val < max);
102
103 // mixed comparisons with raw numeric time
104 raw_time_64 g2 (-2);
105 CHECK (zero > g2);
106 CHECK (one > g2);
107 CHECK (one >= g2);
108 CHECK (g2 < max);
109
110 CHECK (!(g2 > max));
111 CHECK (!(g2 < min));
112 }
113
114
120 void
122 {
123 TimeVar zero;
124 TimeVar one = TimeValue(1);
125 TimeVar two = TimeValue(2);
126
127 TimeVar var (org);
128
129 var += two;
130 var *= 2;
131 CHECK (zero == (var - 2*(org + two)) );
132
133 // the transient vars caused no side-effects
134 CHECK (var == 2*two + org + org);
135 CHECK (two == TimeValue(2));
136
137 var = org; // assign new value
138 CHECK (zero == (var - org));
139
140 CHECK (zero < one);
141 CHECK (one < two);
142 CHECK (var < Time::MAX);
143 CHECK (var > Time::MIN);
144
145 raw_time_64 raw = _raw(var);
146 CHECK (raw == org);
147 CHECK (raw > org - two);
148
149 // unary minus will flip around origin
150 CHECK (zero == -var + var);
151 CHECK (zero != -var);
152 CHECK (var == org); // unaltered
153 }
154
155
159 void
161 {
162 Time o1(org);
163 TimeVar v(org);
164 Time o2(v);
165 CHECK (o1 == o2);
166 CHECK (o1 == org);
167
168 // time in seconds
169 Time t1(FSecs(1));
170 CHECK (t1 == TimeValue(TimeValue::SCALE));
171
172 // create from fractional seconds
173 FSecs halve(1,2);
174 CHECK (0.5 == boost::rational_cast<double> (halve));
175 Time th(halve);
176 CHECK (th == TimeValue(TimeValue::SCALE/2));
177
178 Time tx1(500,0);
179 CHECK (tx1 == th);
180 Time tx2(1,2);
181 CHECK (tx2 == TimeValue(2.001*TimeValue::SCALE));
182 Time tx3(1,1,1,1);
183 CHECK (tx3 == TimeValue(TimeValue::SCALE*(0.001 + 1 + 60 + 60*60)));
184
185 CHECK ("1:01:01.001" == string(tx3));
186
187 // create time variable on the fly....
188 CHECK (th+th == t1);
189 CHECK (t1-th == th);
190 CHECK (((t1-th)*=2) == t1);
191 CHECK (th-th == TimeValue(0));
192
193 // that was indeed a temporary and didn't affect the originals
194 CHECK (t1 == TimeValue(TimeValue::SCALE));
195 CHECK (th == TimeValue(TimeValue::SCALE/2));
196 }
197
198
200 void
202 {
203 std::hash<TimeValue> hashFunc;
204 CHECK (0 == hashFunc (Time::ZERO));
205 size_t hh = sizeof(size_t)*CHAR_BIT/2;
206 CHECK (size_t(1)<<hh == hashFunc (TimeValue{1}));
207 CHECK (size_t(1) == hashFunc (TimeValue(size_t(1)<<hh)));
208
209 size_t h1 = hashFunc (org);
210 size_t h2 = hashFunc (Time{org} + TimeValue{1});
211 size_t h3 = hashFunc (TimeValue(h1));
212 CHECK (h1 > 0 or org == Time::ZERO);
213 CHECK (h2 - h1 == size_t(1)<<hh);
214 CHECK (h3 == size_t(_raw(org)));
215 }
216
217
218 void
220 {
221 VERIFY_ERROR (BOTTOM_VALUE, FrameRate infinite(0) );
222 VERIFY_ERROR (BOTTOM_VALUE, FrameRate infinite(0,123) );
223
224 CHECK (isnil (Duration (0, FrameRate::PAL)));
225 CHECK (isnil (Duration (0, FrameRate(123))));
226
227 CHECK (FrameRate::approx(2000) == "2000FPS"_expect);
228 CHECK (FrameRate::approx(1e05) == "100000FPS"_expect);
229 CHECK (FrameRate::approx(1e06) == "1000000FPS"_expect); // exact
230 CHECK (FrameRate::approx(1e12) == "4194303FPS"_expect); // limited (≈4.2e+6)
231 CHECK (FrameRate::approx(1e14) == "4194303FPS"_expect); // limited + numeric overflow prevented
232 CHECK (FrameRate::approx(1e-5) == "14/1398101FPS"_expect); // quantised ≈ 1.00135827e-5
233 CHECK (FrameRate::approx(1e-6) == "4/4194303FPS"_expect); // quantised ≈ 0.95367454e-6
234 CHECK (FrameRate::approx(1e-7) == "1/4194303FPS"_expect); // limited ≈ 2.38418636e-7
235 CHECK (FrameRate::approx(1e-9) == "1/4194303FPS"_expect); // limited ≈ 2.38418636e-7
236
237 CHECK (FrameRate( 20'000, Duration{Time{0,10}}) == "2000FPS"_expect); // exact
238 CHECK (FrameRate( 20'000, Duration{Time::MAX }) == "1/4194303FPS"_expect); // limited
239
240 CHECK (FrameRate(size_t(2e10), Duration{Time::MAX }) == "272848/4194303FPS"_expect); // quantised ≈ 6.5052048e-2
241 CHECK (FrameRate(size_t(2e14), Duration{Time::MAX }) == "3552496/5461FPS"_expect); // quantised ≈ 650.52115 exact:650.521
242 CHECK (FrameRate(size_t(2e15), Duration{Time::MAX }) == "3324163/511FPS"_expect); // quantised ≈ 6505.2114 exact:6505.21
243 CHECK (FrameRate(size_t(2e16), Duration{Time::MAX }) == "4098284/63FPS"_expect); // quantised ≈ 65052,127 exact:65052.1
244 CHECK (FrameRate(size_t(2e17), Duration{Time::MAX }) == "650521FPS"_expect); // exact:650521
245 CHECK (FrameRate(size_t(2e18), Duration{Time::MAX }) == "4194303FPS"_expect); // limited (≈4.2e+6) exact:6.50521e+06
246 CHECK (FrameRate(size_t(2e20), Duration{Time::MAX }) == "4194303FPS"_expect); // limited exact:6.50521e+08
247 }
248
249
250 void
252 {
253 TimeValue four(4);
254 TimeValue five(5);
255
256 Offset off5 (five);
257 CHECK (0 < off5);
258
259 TimeVar point(org);
260 point += off5;
261 CHECK (org < point);
262
263 Offset reverse(point,org);
264 CHECK (reverse < off5);
265 CHECK (reverse.abs() == off5);
266
267 CHECK (0 == off5 + reverse);
268
269 // chaining and copy construction
270 Offset off9 (off5 + Offset(four));
271 CHECK (9 == off9);
272 // simple linear combinations
273 CHECK (7 == -2*off9 + off5*5);
274
275 // build offset by number of frames
276 Offset byFrames(-125, FrameRate::PAL);
277 CHECK (Time(FSecs(-5)) == byFrames);
278
279 CHECK (Offset(-5, FrameRate(5,4)) == -Offset(5, FrameRate(5,4)));
280 CHECK (Offset(3, FrameRate(3)) == Offset(12345, FrameRate(24690,2)));
281 } // precise rational number calculations
282
283
284 void
286 {
287 TimeValue zero(0);
288 TimeVar point(org);
289 point += TimeValue(5);
290 CHECK (org < point);
291
292 Offset backwards(point,org);
293 CHECK (backwards < zero);
294
295 Duration distance(backwards);
296 CHECK (distance > zero);
297 CHECK (distance == backwards.abs());
298
299 Duration len1(Time(23,4,5,6));
300 CHECK (len1 == Time(FSecs(23,1000)) + Time(0, 4 + 5*60 + 6*3600));
301
302 Duration len2(Time(FSecs(-10))); // negative specs...
303 CHECK (len2 == Time(FSecs(10)));//
304 CHECK (len2 > zero); // will be taken absolute
305
306 Duration unit(50, FrameRate::PAL);
307 CHECK (Time(0,2,0,0) == unit); // duration of 50 frames at 25fps is... (guess what)
308
309 CHECK (FrameRate::PAL.duration() == Time(FSecs(1,25)));
310 CHECK (FrameRate::NTSC.duration() == Time(FSecs(1001,30000)));
311 cout << "NTSC-Framerate = " << FrameRate::NTSC.asDouble() << endl;
312
313 CHECK (zero == Duration::NIL);
314 CHECK (isnil (Duration::NIL));
315
316 // assign to variable for calculations
317 point = backwards;
318 point *= 2;
319 CHECK (point < zero);
320 CHECK (point < backwards);
321
322 CHECK (distance + point < zero); // using the duration as offset
323 CHECK (distance == backwards.abs()); // while this didn't alter the duration as such
324 }
325
326
327 void
329 {
330 CHECK (Time::MIN < Time::MAX);
331 CHECK (_raw(Time::MAX) < std::numeric_limits<int64_t>::max());
332 CHECK (_raw(Time::MIN) > std::numeric_limits<int64_t>::min());
333
334 // Values are limited at construction, but not in calculations
335 CHECK (Time::MAX - Time(0,1) < Time::MAX);
336 CHECK (Time::MAX - Time(0,1) + Time(0,3) > Time::MAX);
337 CHECK (TimeValue{_raw(Time::MAX-Time(0,1)+Time(0,3))} == Time::MAX); // clipped at max
338 CHECK (TimeValue{_raw(Time::MIN+Time(0,5)-Time(0,9))} == Time::MIN); // clipped at min
339
340 TimeValue outlier{Time::MIN - TimeValue(1)};
341 CHECK (outlier < Time::MIN);
342
343 CHECK (Duration::MAX > Time::MAX);
344 CHECK (_raw(Duration::MAX) < std::numeric_limits<int64_t>::max());
345 CHECK (Duration::MAX == Time::MAX - Time::MIN);
347 CHECK (Duration{3*Offset{Time::MAX}} == Duration::MAX);
348
351 CHECK ( Offset{Time::MAX + Duration::MAX} == Duration::MAX); // clipped at max
352 CHECK ( Offset{Time::MIN - Duration::MAX} == -Duration::MAX); // clipped at min
353 CHECK (Duration{Offset{Time::MIN - Duration::MAX}} == Duration::MAX); // duration is absolute
354
356 CHECK (TimeSpan(Time::MAX, Duration::MAX).start() == Time::MAX);
357 CHECK (TimeSpan(Time::MAX, Duration::MAX).end() == Time::MAX + Duration::MAX); // note: end() can yield value beyond [Time::MIN...Time::MAX]
358 CHECK (TimeSpan(Time::MAX, Duration::MAX).duration() == Duration::MAX);
360 CHECK (TimeSpan(outlier, Duration::MAX).conform() == TimeSpan(Time::MIN,Duration::MAX));
361 CHECK (TimeSpan(Time::MAX, Offset(FSecs(-1))) == TimeSpan(Time::MAX-Offset(FSecs(1)), FSecs(1)));
362 CHECK (TimeSpan(Time::MAX, FSecs(5)).start() == Time::MAX);
363 CHECK (TimeSpan(Time::MAX, FSecs(5)).duration() == Duration(FSecs(5)));
364 CHECK (TimeSpan(Time::MAX, FSecs(5)).conform() == TimeSpan(Time::MAX-Offset(FSecs(5)), FSecs(5)));
365 }
366
367
368 void
370 {
371 typedef boost::rational<FrameCnt> Frac;
372
373 Duration three (TimeValue(3)); // three micro seconds
374
375 Offset o1 = Frac(1,2) * three;
376 CHECK (o1 > Time::ZERO);
377 CHECK (o1 == TimeValue(1)); // bias towards the next lower micro grid position
378
379 Offset o2 = -Frac(1,2) * three;
380 CHECK (o2 < Time::ZERO);
381 CHECK (o2 == TimeValue(-2));
382
383 CHECK (three * Frac(1,2) * 2 != three);
384 CHECK (three *(Frac(1,2) * 2) == three);
385 // integral arithmetics is precise,
386 // but not necessarily exact!
387 }
388
389
390 void
392 {
393 TimeValue five(5);
394
395 TimeSpan interval (Time(org), Duration(Offset (org,five)));
396
397 // the time span behaves like a time
398 CHECK (org == interval);
399
400 // can get the length by direct conversion
401 Duration theLength(interval);
402 CHECK (theLength == Offset(org,five).abs());
403
404 Time endpoint = interval.end();
405 TimeSpan successor (endpoint, FSecs(2));
406
407 CHECK (Offset(interval,endpoint) == Offset(org,five).abs());
408 CHECK (Offset(endpoint,successor.end()) == Duration(successor));
409
410 cout << "Interval-1: " << interval
411 << " Interval-2: " << successor
412 << " End point: " << successor.end()
413 << endl;
414 }
415
416
417 void
419 {
420 TimeSpan span1 (org, org+org); // using the distance between start and end point
421 TimeSpan span2 (org+org, org); // note: TimeSpan is oriented automatically
422 TimeSpan span3 (org, FSecs(5,2)); // Duration given explicitly, in seconds
423 TimeSpan span4 (org, FSecs(5,-2)); // note: fractional seconds taken absolute, as Duration
424
425 CHECK (span1 == span2);
426 CHECK (span2 == span1);
427 CHECK (span3 == span4);
428 CHECK (span4 == span3);
429
430 CHECK (span1 != span3);
431 CHECK (span3 != span1);
432 CHECK (span1 != span4);
433 CHECK (span4 != span1);
434 CHECK (span2 != span3);
435 CHECK (span3 != span2);
436 CHECK (span2 != span4);
437 CHECK (span4 != span2);
438
439 // note that TimeSpan is oriented at creation
440 CHECK (span1.end() == span2.end());
441 CHECK (span3.end() == span4.end());
442
443 // Verify the extended order on time intervals
444 TimeSpan span1x (org+org, Duration(org)); // starting later than span1
445 TimeSpan span3y (org, FSecs(2)); // shorter than span3
446 TimeSpan span3z (org+org, FSecs(2)); // starting later and shorter than span3
447
448 CHECK (span1 != span1x);
449 CHECK (span3 != span3y);
450 CHECK (span3 != span3z);
451
452 CHECK ( span1 < span1x);
453 CHECK ( span1 <= span1x);
454 CHECK (!(span1 > span1x));
455 CHECK (!(span1 >= span1x));
456
457 CHECK ( span3 > span3y);
458 CHECK ( span3 >= span3y);
459 CHECK (!(span3 < span3y));
460 CHECK (!(span3 <= span3y));
461
462 CHECK ( span3 < span3z); // Note: the start point takes precedence on comparison
463 CHECK ( span3y < span3z);
464
465 // Verify this order is really different
466 // than the basic ordering of time values
467 CHECK (span1 < span1x);
468 CHECK (span1.duration() == span1x.duration());
469 CHECK (span1.start() < span1x.start());
470 CHECK (span1.end() < span1x.end());
471
472 CHECK (span3 > span3y);
473 CHECK (span3.duration() > span3y.duration());
474 CHECK (span3.start() == span3y.start());
475 CHECK (span3.end() > span3y.end());
476 CHECK (Time(span3) == Time(span3y));
477
478 CHECK (span3 < span3z);
479 CHECK (span3.duration() > span3z.duration());
480 CHECK (span3.start() < span3z.start());
481 CHECK (span3.end() != span3z.end()); // it's shorter, and org can be random, so that's all we know
482 CHECK (Time(span3) < Time(span3z));
483
484 CHECK (span3y < span3z);
485 CHECK (span3y.duration() == span3z.duration());
486 CHECK (span3y.start() < span3z.start());
487 CHECK (span3y.end() < span3z.end());
488 CHECK (Time(span3) < Time(span3z));
489 }
490
491
492 void
494 {
495 Time oneSec(FSecs(1));
496
497 TimeSpan span1 (org, FSecs(2));
498 TimeSpan span2 (oneSec + org, FSecs(2));
499
500 TimeVar probe(org);
501 CHECK ( span1.contains(probe));
502 CHECK (!span2.contains(probe));
503
504 probe = span2;
505 CHECK ( span1.contains(probe));
506 CHECK ( span2.contains(probe));
507
508 probe = span1.end();
509 CHECK (!span1.contains(probe)); // Note: end is always exclusive
510 CHECK ( span2.contains(probe));
511
512 probe = span2.end();
513 CHECK (!span1.contains(probe));
514 CHECK (!span2.contains(probe));
515 }
516 };
517
518
520 LAUNCHER (TimeValue_test, "unit common");
521
522
523
524}}} // namespace lib::time::test
Duration is the internal Lumiera time metric.
static const Duration MAX
maximum possible temporal extension
static const Duration NIL
constant to indicate "no duration"
Framerate specified as frames per second.
static const FrameRate PAL
predefined constant for PAL framerate
static FrameRate approx(double fps)
static const FrameRate NTSC
double asDouble() const
Offset measures a distance in time.
Duration abs() const
interpret the distance given by this offset as a time duration
A time interval anchored at a specific point in time.
bool contains(TimeValue const &tp) const
Time start() const
Duration & duration()
basic constant internal time value.
static const raw_time_64 SCALE
Number of micro ticks (µs) per second as basic time scale.
a mutable time value, behaving like a plain number, allowing copy and re-accessing
Lumiera's internal time value datatype.
static const Time MIN
static const Time ZERO
static const Time MAX
void checkTimeConvenience(TimeValue org)
void checkBasicTimeValues(TimeValue org)
void compareTimeSpan(Time const &org)
void relateTimeIntervals(TimeValue org)
#define LERR_(_NAME_)
Definition error.hpp:45
Automatically use custom string conversion in C++ stream output.
int64_t raw_time_64
Raw µ-tick time representation used in Lumiera.
boost::rational< int64_t > FSecs
rational representation of fractional seconds
Implementation namespace for support and library code.
int rani(uint bound=_iBOUND())
Definition random.hpp:135
Test runner and basic definitions for tests.
bool isnil(lib::time::Duration const &dur)
Simplistic test class runner.
#define LAUNCHER(_TEST_CLASS_, _GROUPS_)
Definition run.hpp:116
Primary class template for std::hash.
A collection of frequently used helper functions to support unit testing.
#define VERIFY_ERROR(ERROR_ID, ERRONEOUS_STATEMENT)
Macro to verify that a statement indeed raises an exception.
a family of time value like entities and their relationships.
Tiny helper functions and shortcuts to be used everywhere Consider this header to be effectively incl...