Lumiera  0.pre.03
»edit your freedom«
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"
20 #include "lib/test/test-helper.hpp"
21 #include "lib/time/timevalue.hpp"
22 #include "lib/format-cout.hpp"
23 #include "lib/util.hpp"
24 
25 #include <boost/lexical_cast.hpp>
26 #include <string>
27 
28 using boost::lexical_cast;
29 using util::isnil;
30 using std::string;
31 
32 using LERR_(BOTTOM_VALUE);
33 
34 namespace lib {
35 namespace time{
36 namespace test{
37 
38 
39  /****************************************************/
45  class TimeValue_test : public Test
46  {
47  gavl_time_t
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<gavl_time_t> (arg[1]);
57  }
58 
59 
60  virtual void
61  run (Arg arg)
62  {
63  TimeValue ref (random_or_get(arg));
64 
66  checkMutableTime (ref);
67  checkTimeHash (ref);
69  verify_invalidFramerateProtection();
70  createOffsets (ref);
71  buildDuration (ref);
72  buildTimeSpan (ref);
73  compareTimeSpan (Time(ref));
74  relateTimeIntervals (ref);
75  verify_extremeValues();
76  verify_fractionalOffset();
77  }
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  gavl_time_t 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  gavl_time_t 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 || org == Time::ZERO);
213  CHECK (h2 - h1 == size_t(1)<<hh);
214  CHECK (h3 == size_t(_raw(org)));
215  }
216 
217 
218  void
219  verify_invalidFramerateProtection()
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
251  createOffsets (TimeValue org)
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
285  buildDuration (TimeValue org)
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
328  verify_extremeValues()
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);
346  CHECK (-Duration::MAX == Offset{Time::MIN - Time::MAX});
347  CHECK (Duration{3*Offset{Time::MAX}} == Duration::MAX);
348 
350  CHECK ( Time::MIN - Duration::MAX < -Duration::MAX);
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 
355  CHECK (TimeSpan(Time::MIN, Time::MAX) == TimeSpan(Time::MAX, Time::MIN));
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);
359  CHECK (TimeSpan(Time::MAX, Duration::MAX).conform() == TimeSpan(Time::MIN,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
369  verify_fractionalOffset()
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
391  buildTimeSpan (TimeValue org)
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
418  compareTimeSpan (Time const& org)
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
493  relateTimeIntervals (TimeValue org)
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
a mutable time value, behaving like a plain number, allowing copy and re-accessing ...
Definition: timevalue.hpp:232
static const Duration MAX
maximum possible temporal extension
Definition: timevalue.hpp:507
Automatically use custom string conversion in C++ stream output.
Definition: run.hpp:40
Framerate specified as frames per second.
Definition: timevalue.hpp:655
static const gavl_time_t SCALE
Number of micro ticks (µs) per second as basic time scale.
Definition: timevalue.hpp:167
int rani(uint bound=_iBOUND())
Definition: random.hpp:135
Primary class template for std::hash.
#define VERIFY_ERROR(ERROR_ID, ERRONEOUS_STATEMENT)
Macro to verify that a statement indeed raises an exception.
void checkTimeConvenience(TimeValue org)
static const Duration NIL
constant to indicate "no duration"
Definition: timevalue.hpp:506
Implementation namespace for support and library code.
Lumiera&#39;s internal time value datatype.
Definition: timevalue.hpp:299
Simplistic test class runner.
Duration abs() const
interpret the distance given by this offset as a time duration
Definition: timevalue.hpp:831
Tiny helper functions and shortcuts to be used everywhere Consider this header to be effectively incl...
boost::rational< int64_t > FSecs
rational representation of fractional seconds
Definition: timevalue.hpp:220
A collection of frequently used helper functions to support unit testing.
void checkBasicTimeValues(TimeValue org)
ExampleStrategy::Qualifier two(string additionalArg)
definition of another qualifier two(arg), accepting an additional argument
Offset measures a distance in time.
Definition: timevalue.hpp:358
Duration is the internal Lumiera time metric.
Definition: timevalue.hpp:468
A time interval anchored at a specific point in time.
Definition: timevalue.hpp:573
ExampleStrategy::Qualifier one()
definition of a qualifier one()
a family of time value like entities and their relationships.
basic constant internal time value.
Definition: timevalue.hpp:133
static const Time MAX
Definition: timevalue.hpp:309
void checkMutableTime(TimeValue org)
static const FrameRate PAL
predefined constant for PAL framerate
Definition: timevalue.hpp:671