Lumiera  0.pre.03
»edit your freedom«
time-control-test.cpp
Go to the documentation of this file.
1 /*
2  TimeControl(Test) - mutating time entities with life connection and feedback
3 
4  Copyright (C)
5  2011, 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/time/timequant.hpp"
23 #include "lib/time/control.hpp"
24 
27 #include "lib/scoped-holder.hpp"
28 #include "lib/format-cout.hpp"
29 #include "lib/util.hpp"
30 
31 #include <boost/lexical_cast.hpp>
32 #include <string>
33 #include <limits>
34 
35 using boost::lexical_cast;
36 using util::typeStr;
37 using util::isnil;
38 using std::string;
39 
40 
41 namespace lib {
42 namespace time{
43 namespace test{
44 
45  namespace error = lumiera::error;
46 
47  using lib::ScopedHolder;
49  using lib::meta::Types;
51  using LERR_(UNCONNECTED);
52 
53 
54 
55  namespace { // Test setup and helpers....
56 
57  inline string
58  pop (Arg arg)
59  {
60  if (isnil (arg)) return "";
61  string entry = arg[0];
62  arg.erase (arg.begin());
63  return entry;
64  }
65 
66 
73  template<class TI>
76  {
77  mutable
78  ScopedHolder<TI> received_;
79 
80  public:
81  TestListener()
82  {
83  received_.create (Time::ZERO);
84  }
85 
86  TestListener(TI const& initialValue)
87  {
88  received_.create (initialValue);
89  }
90 
91  void
92  operator() (TI const& changeValue) const
93  {
94  received_.clear();
95  received_.create (changeValue);
96  }
97 
98  TI const&
99  receivedValue() const
100  {
101  return *received_;
102  }
103  };
104 
105  }//(End)Test helpers
106 
107 
108 
109 
110  /*******************************************************************/
124  class TimeControl_test : public Test
125  {
126  gavl_time_t
127  random_or_get (string arg)
128  {
129  if (isnil(arg))
130  return gavl_time_t(1 + rani (100000)) * TimeValue::SCALE;
131  else
132  return lexical_cast<gavl_time_t> (arg);
133  }
134 
135 
136  virtual void
137  run (Arg arg)
138  {
139  if (isnil(arg))
140  seedRand();
141  TimeValue o (random_or_get (pop(arg)));
142  TimeValue c (random_or_get (pop(arg)));
143  CHECK (c!=Time::ZERO && o != c, "unsuitable testdata");
144 
145  // 25fps-grid, but with an time origin offset by 1/50sec
146  TimeGrid::build("test_grid_PAL", FrameRate::PAL, Time(FSecs(1,50)));
147 
148  // disjoint NTSC-framerate grid for grid aligned changes
149  TimeGrid::build("test_grid_NTSC", FrameRate::NTSC);
150 
151  verifyBasics();
152  verifyMatrix_of_MutationCases(o,c);
153  }
154 
155 
156  void
157  verifyBasics()
158  {
159  TimeSpan target(Time(0,10), FSecs(5));
160 
161  Control<Time> controller;
162  TestListener<Time> follower;
163 
164  VERIFY_ERROR (UNCONNECTED, controller(Time::ZERO) );
165 
166  target.accept (controller);
167  CHECK (Time(0,10) == target);
168  controller (Time(FSecs(21,2)));
169  CHECK (Time(500,10) == target);
170 
171  CHECK (follower.receivedValue() == Time::ZERO);
172  controller.connectChangeNotification (follower);
173  CHECK (follower.receivedValue() == Time(500,10));
174 
175  controller (Offset(-Time(500,1)));
176  CHECK (Time(0,9) == target);
177  CHECK (Time(0,9) == follower.receivedValue());
178  }
179 
180 
186  void verifyMatrix_of_MutationCases (TimeValue const& o, TimeValue const& c);
187  };
188 
189 
190  namespace { // Implementation: Matrix of individual test combinations
191 
192 
193  template<class T>
194  inline bool
195  isDuration()
196  {
197  return std::is_same<T,Duration>::value;
198  }
199 
200  template<class T>
201  inline bool
202  isQuTime()
203  {
204  return std::is_same<T,QuTime>::value;
205  }
206 
207  template<class T>
208  inline TimeValue
209  materialise (T const& someTime)
210  {
211  return someTime;
212  }
213  inline TimeValue
214  materialise (QuTime const& alignedTime)
215  {
216  PQuant grid(alignedTime);
217  return grid->materialise (alignedTime);
218  }
219 
220 
221  template<class TAR>
222  struct TestTarget
223  {
224  static TAR
225  build (TimeValue const& org)
226  {
227  return TAR(org);
228  }
229  };
230 
231  template<>
233  {
234  static TimeSpan
235  build (TimeValue const& org)
236  {
237  return TimeSpan (org, FSecs(3,2));
238  }
239  };
240 
241  template<>
243  {
244  static QuTime
245  build (TimeValue const& org)
246  {
247  return QuTime (org, "test_grid_PAL");
248  }
249  };
250 
251 
252  template<class SRC>
253  struct TestChange
254  {
255  static SRC
256  prepareChangeValue (TimeValue const& c)
257  {
258  return SRC(c);
259  }
260  };
261 
262  template<>
264  {
265  static TimeSpan
266  prepareChangeValue (TimeValue const& c)
267  {
268  return TimeSpan (c, Duration(c));
269  }
270  };
271 
272  template<>
274  {
275  static QuTime
276  prepareChangeValue (TimeValue const& c)
277  {
278  return QuTime (c, "test_grid_NTSC");
279  }
280  };
281 
282 
283 
284  template<class TAR, class SRC>
285  void
286  ____verify_wasChanged (TAR const& target, TimeValue const& org, SRC const& change)
287  {
288  if (isDuration<TAR>())
289  {
290  CHECK (target == org, "Logic error: Duration was changed by time value");
291  }
292  else
293  if (isDuration<SRC>())
294  {
295  CHECK (target == org, "Logic error: Duration used to change time value");
296  }
297  else
298  if (isQuTime<SRC>())
299  {
300  CHECK (target != org);
301  CHECK (target == materialise(change));
302  }
303  else
304  {
305  CHECK (target != org);
306  CHECK (target == change);
307  }
308  }
309 
310  void
311  ____verify_wasChanged (Duration const& target, TimeValue const& org, Duration const& otherDuration)
312  {
313  CHECK (target != org);
314  CHECK (target == otherDuration);
315  }
316  void
317  ____verify_wasChanged (Duration const& target, TimeValue const& org, TimeSpan const& span_as_change)
318  {
319  CHECK (target != org);
320  CHECK (target == span_as_change.duration());
321  }
322  void
323  ____verify_wasChanged (TimeSpan const& target, TimeValue const& org, Duration const& changedDur)
324  {
325  CHECK (target == org, "Logic error: Duration was used as start point of the target TimeSpan");
326  CHECK (target.duration() != Time(FSecs(3,2)), "length of the timespan should have been changed");
327  CHECK (target.duration() == changedDur);
328  }
329 
330 
331 
332  template<class TAR>
333  void
334  ____verify_wasOffset (TAR const& target, TAR const& refState, Offset const& offset)
335  {
336  CHECK (target != refState);
337  CHECK (target == Time(refState)+offset);
338  }
339 
340  template<class TAR>
341  void
342  ____verify_wasOffsetBack (TAR const& target, TAR const& refState)
343  {
344  CHECK (target == refState);
345  }
346 
347 
348  template<class TAR>
349  void
350  ____verify_nudged (TAR const& target, TAR const& refState, FrameCnt offsetSteps)
351  {
352  CHECK (target != refState || !offsetSteps);
353  CHECK (target == Time(refState)+Time(FSecs(offsetSteps)));
354  }
355  template<>
356  void
357  ____verify_nudged (QuTime const& target, QuTime const& refState, FrameCnt offsetSteps)
358  {
359  CHECK (target != refState || !offsetSteps);
360  CHECK (target == Time (materialise(refState))
361  + Offset(offsetSteps, FrameRate::PAL));
362  }
363 
364 
365  template<class TAR, class SRC>
366  void
367  ____verify_notification (TAR const& target, TestListener<SRC> const& follower)
368  {
369  if (isDuration<SRC>())
370  {
371  CHECK (materialise(target) == follower.receivedValue()
372  || Duration::NIL == follower.receivedValue() );
373  }
374  else
375  if (isQuTime<TAR>())
376  {
377  CHECK (materialise (target) == follower.receivedValue());
378  }
379  else
380  {
381  CHECK (target == follower.receivedValue());
382  }
383  }
384  void
385  ____verify_notification (TimeSpan const& targetTimeSpan, TestListener<Duration> const& follower)
386  {
387  CHECK (follower.receivedValue() == targetTimeSpan.duration());
388  }
389  void
390  ____verify_notification (Duration const& target, TestListener<Duration> const& follower)
391  {
392  CHECK (target == follower.receivedValue());
393  }
394  void
395  ____verify_notification (Duration const& targetDuration, TestListener<TimeSpan> const& follower)
396  {
397  CHECK (Time::ZERO == follower.receivedValue());
398  CHECK (targetDuration == follower.receivedValue().duration());
399  }
400 
401 
402 
403 
404  template< class TAR
405  , class SRC
406  , class BASE
407  >
408  struct TestCase
409  : BASE
410  {
411  void
412  performTestSequence(TimeValue const& org, TimeValue const& c)
413  {
414  cout << "Test-Case. Target=" << typeStr<TAR>()
415  << "\t <--feed--- " << typeStr<SRC>()
416  << endl;
417 
418  // test subject
419  Control<SRC> controller;
420 
421  TAR target = TestTarget<TAR>::build(org);
422  SRC change = TestChange<SRC>::prepareChangeValue(c);
423  TestListener<SRC> follower(change);
424 
425  controller.connectChangeNotification(follower);
426  target.accept (controller);
427 
428  controller (change);
429  ____verify_wasChanged (target, org, change);
430  ____verify_notification(target,follower);
431 
432  TAR refState(target);
433 
434  Offset offset(c);
435  controller (offset);
436  ____verify_wasOffset (target, refState, offset);
437  controller (-offset);
438  ____verify_wasOffsetBack (target, refState);
439  ____verify_notification(target,follower);
440 
441  controller (0);
442  ____verify_nudged (target, refState, 0);
443  ____verify_notification(target,follower);
444 
445  controller (+1);
446  ____verify_nudged (target, refState, +1);
447  ____verify_notification(target,follower);
448 
449  controller (-2);
450  ____verify_nudged (target, refState, -1);
451  ____verify_notification(target,follower);
452 
453  int maxInt = std::numeric_limits<int>::max();
454  int minInt = std::numeric_limits<int>::min();
455 
456  controller (maxInt);
457  ____verify_nudged (target, refState, -1LL + maxInt);
458  ____verify_notification(target,follower);
459 
460  controller (minInt);
461  ____verify_nudged (target, refState, -1LL + maxInt+minInt);
462  ____verify_notification(target,follower);
463 
464 
465  // tail recursion: further test combinations....
466  BASE::performTestSequence(org,c);
467  }
468  };
469 
471  {
472  void performTestSequence(TimeValue const&, TimeValue const&) { }
473  };
474 
475  }//(End)Implementation Test-case matrix
476 
477 
478  void
480  {
481  typedef Types<Duration,TimeSpan,QuTime> KindsOfTarget; // time entities to receive value changes
482  typedef Types<TimeValue,Time,Duration,TimeSpan,QuTime> KindsOfSource; // time entities to be used as change values
483  typedef InstantiateChainedCombinations< KindsOfTarget
484  , KindsOfSource
485  , TestCase // template to be instantiated for each type
486  , IterationEnd > TestMatrix;
487 
488  TestMatrix().performTestSequence(origVal, change);
489  }
490 
491 
492 
493 
494 
496  LAUNCHER (TimeControl_test, "unit common");
497 
498 
499 
500 }}} // namespace lib::time::test
Interface: a grid and scale definition for time quantisation.
Definition: time-grid.hpp:77
Some wrappers for coping with ownership problems.
void connectChangeNotification(SIG const &toNotify)
install a callback functor to be invoked as notification for any changes imposed onto the observed ti...
Definition: control.hpp:215
Automatically use custom string conversion in C++ stream output.
Frontend/Interface: controller-element to retrieve and change running time values.
Definition: control.hpp:125
void verifyMatrix_of_MutationCases(TimeValue const &o, TimeValue const &c)
void accept(Mutation const &)
may change start / duration
Definition: mutation.hpp:123
AnyPair entry(Query< TY > const &query, typename WrapReturn< TY >::Wrapper &obj)
helper to simplify creating mock table entries, wrapped correctly
Definition: run.hpp:40
Any copy and copy construction prohibited.
Definition: nocopy.hpp:37
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
#define VERIFY_ERROR(ERROR_ID, ERRONEOUS_STATEMENT)
Macro to verify that a statement indeed raises an exception.
static PGrid build(FrameRate frames_per_second)
Definition: time-grid.cpp:158
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
Metaprogramming facilities to generate combination cases.
Simplistic test class runner.
Tiny helper functions and shortcuts to be used everywhere Consider this header to be effectively incl...
Inline buffer holding and owning an object similar to unique_ptr.
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.
Support library to represent grid-aligned time specifications This is part of Lumiera&#39;s time and time...
Offset measures a distance in time.
Definition: timevalue.hpp:358
Manipulating and monitoring time entities with life changes.
To establish a reference scale for quantised time values.
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
int64_t FrameCnt
relative framecount or frame number.
Definition: digxel.hpp:312
a family of time value like entities and their relationships.
basic constant internal time value.
Definition: timevalue.hpp:133
static const FrameRate PAL
predefined constant for PAL framerate
Definition: timevalue.hpp:671
grid aligned time specification, referring to a specific scale.
Definition: timequant.hpp:90