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) Lumiera.org
5  2011, Hermann Vosseler <Ichthyostega@web.de>
6 
7  This program is free software; you can redistribute it and/or
8  modify it under the terms of the GNU General Public License as
9  published by the Free Software Foundation; either version 2 of
10  the License, or (at your option) any later version.
11 
12  This program is distributed in the hope that it will be useful,
13  but WITHOUT ANY WARRANTY; without even the implied warranty of
14  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15  GNU General Public License for more details.
16 
17  You should have received a copy of the GNU General Public License
18  along with this program; if not, write to the Free Software
19  Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
20 
21 * *****************************************************/
22 
28 #include "lib/test/run.hpp"
29 #include "lib/test/test-helper.hpp"
30 #include "lib/time/timevalue.hpp"
31 #include "lib/time/timequant.hpp"
32 #include "lib/time/control.hpp"
33 
36 #include "lib/scoped-holder.hpp"
37 #include "lib/format-cout.hpp"
38 #include "lib/util.hpp"
39 
40 #include <boost/lexical_cast.hpp>
41 #include <string>
42 #include <limits>
43 
44 using boost::lexical_cast;
45 using util::typeStr;
46 using util::isnil;
47 using std::string;
48 
49 
50 namespace lib {
51 namespace time{
52 namespace test{
53 
54  namespace error = lumiera::error;
55 
56  using lib::ScopedHolder;
58  using lib::meta::Types;
60  using LERR_(UNCONNECTED);
61 
62 
63 
64  namespace { // Test setup and helpers....
65 
66  inline string
67  pop (Arg arg)
68  {
69  if (isnil (arg)) return "";
70  string entry = arg[0];
71  arg.erase (arg.begin());
72  return entry;
73  }
74 
75 
82  template<class TI>
85  {
86  mutable
87  ScopedHolder<TI> received_;
88 
89  public:
90  TestListener()
91  {
92  received_.create (Time::ZERO);
93  }
94 
95  TestListener(TI const& initialValue)
96  {
97  received_.create (initialValue);
98  }
99 
100  void
101  operator() (TI const& changeValue) const
102  {
103  received_.clear();
104  received_.create (changeValue);
105  }
106 
107  TI const&
108  receivedValue() const
109  {
110  return *received_;
111  }
112  };
113 
114  }//(End)Test helpers
115 
116 
117 
118 
119  /*******************************************************************/
133  class TimeControl_test : public Test
134  {
135  gavl_time_t
136  random_or_get (string arg)
137  {
138  if (isnil(arg))
139  return gavl_time_t (1 + (rand() % 100000)) * TimeValue::SCALE;
140  else
141  return lexical_cast<gavl_time_t> (arg);
142  }
143 
144 
145  virtual void
146  run (Arg arg)
147  {
148  TimeValue o (random_or_get (pop(arg)));
149  TimeValue c (random_or_get (pop(arg)));
150  CHECK (c!=Time::ZERO && o != c, "unsuitable testdata");
151 
152  // 25fps-grid, but with an time origin offset by 1/50sec
153  TimeGrid::build("test_grid_PAL", FrameRate::PAL, Time(FSecs(1,50)));
154 
155  // disjoint NTSC-framerate grid for grid aligned changes
156  TimeGrid::build("test_grid_NTSC", FrameRate::NTSC);
157 
158  verifyBasics();
159  verifyMatrix_of_MutationCases(o,c);
160  }
161 
162 
163  void
164  verifyBasics()
165  {
166  TimeSpan target(Time(0,10), FSecs(5));
167 
168  Control<Time> controller;
169  TestListener<Time> follower;
170 
171  VERIFY_ERROR (UNCONNECTED, controller(Time::ZERO) );
172 
173  target.accept (controller);
174  CHECK (Time(0,10) == target);
175  controller (Time(FSecs(21,2)));
176  CHECK (Time(500,10) == target);
177 
178  CHECK (follower.receivedValue() == Time::ZERO);
179  controller.connectChangeNotification (follower);
180  CHECK (follower.receivedValue() == Time(500,10));
181 
182  controller (Offset(-Time(500,1)));
183  CHECK (Time(0,9) == target);
184  CHECK (Time(0,9) == follower.receivedValue());
185  }
186 
187 
193  void verifyMatrix_of_MutationCases (TimeValue const& o, TimeValue const& c);
194  };
195 
196 
197  namespace { // Implementation: Matrix of individual test combinations
198 
199 
200  template<class T>
201  inline bool
202  isDuration()
203  {
204  return std::is_same<T,Duration>::value;
205  }
206 
207  template<class T>
208  inline bool
209  isQuTime()
210  {
211  return std::is_same<T,QuTime>::value;
212  }
213 
214  template<class T>
215  inline TimeValue
216  materialise (T const& someTime)
217  {
218  return someTime;
219  }
220  inline TimeValue
221  materialise (QuTime const& alignedTime)
222  {
223  PQuant grid(alignedTime);
224  return grid->materialise (alignedTime);
225  }
226 
227 
228  template<class TAR>
229  struct TestTarget
230  {
231  static TAR
232  build (TimeValue const& org)
233  {
234  return TAR(org);
235  }
236  };
237 
238  template<>
240  {
241  static TimeSpan
242  build (TimeValue const& org)
243  {
244  return TimeSpan (org, FSecs(3,2));
245  }
246  };
247 
248  template<>
250  {
251  static QuTime
252  build (TimeValue const& org)
253  {
254  return QuTime (org, "test_grid_PAL");
255  }
256  };
257 
258 
259  template<class SRC>
260  struct TestChange
261  {
262  static SRC
263  prepareChangeValue (TimeValue const& c)
264  {
265  return SRC(c);
266  }
267  };
268 
269  template<>
271  {
272  static TimeSpan
273  prepareChangeValue (TimeValue const& c)
274  {
275  return TimeSpan (c, Duration(c));
276  }
277  };
278 
279  template<>
281  {
282  static QuTime
283  prepareChangeValue (TimeValue const& c)
284  {
285  return QuTime (c, "test_grid_NTSC");
286  }
287  };
288 
289 
290 
291  template<class TAR, class SRC>
292  void
293  ____verify_wasChanged (TAR const& target, TimeValue const& org, SRC const& change)
294  {
295  if (isDuration<TAR>())
296  {
297  CHECK (target == org, "Logic error: Duration was changed by time value");
298  }
299  else
300  if (isDuration<SRC>())
301  {
302  CHECK (target == org, "Logic error: Duration used to change time value");
303  }
304  else
305  if (isQuTime<SRC>())
306  {
307  CHECK (target != org);
308  CHECK (target == materialise(change));
309  }
310  else
311  {
312  CHECK (target != org);
313  CHECK (target == change);
314  }
315  }
316 
317  void
318  ____verify_wasChanged (Duration const& target, TimeValue const& org, Duration const& otherDuration)
319  {
320  CHECK (target != org);
321  CHECK (target == otherDuration);
322  }
323  void
324  ____verify_wasChanged (Duration const& target, TimeValue const& org, TimeSpan const& span_as_change)
325  {
326  CHECK (target != org);
327  CHECK (target == span_as_change.duration());
328  }
329  void
330  ____verify_wasChanged (TimeSpan const& target, TimeValue const& org, Duration const& changedDur)
331  {
332  CHECK (target == org, "Logic error: Duration was used as start point of the target TimeSpan");
333  CHECK (target.duration() != Time(FSecs(3,2)), "length of the timespan should have been changed");
334  CHECK (target.duration() == changedDur);
335  }
336 
337 
338 
339  template<class TAR>
340  void
341  ____verify_wasOffset (TAR const& target, TAR const& refState, Offset const& offset)
342  {
343  CHECK (target != refState);
344  CHECK (target == Time(refState)+offset);
345  }
346 
347  template<class TAR>
348  void
349  ____verify_wasOffsetBack (TAR const& target, TAR const& refState)
350  {
351  CHECK (target == refState);
352  }
353 
354 
355  template<class TAR>
356  void
357  ____verify_nudged (TAR const& target, TAR const& refState, FrameCnt offsetSteps)
358  {
359  CHECK (target != refState || !offsetSteps);
360  CHECK (target == Time(refState)+Time(FSecs(offsetSteps)));
361  }
362  template<>
363  void
364  ____verify_nudged (QuTime const& target, QuTime const& refState, FrameCnt offsetSteps)
365  {
366  CHECK (target != refState || !offsetSteps);
367  CHECK (target == Time (materialise(refState))
368  + Offset(offsetSteps, FrameRate::PAL));
369  }
370 
371 
372  template<class TAR, class SRC>
373  void
374  ____verify_notification (TAR const& target, TestListener<SRC> const& follower)
375  {
376  if (isDuration<SRC>())
377  {
378  CHECK (materialise(target) == follower.receivedValue()
379  || Duration::NIL == follower.receivedValue() );
380  }
381  else
382  if (isQuTime<TAR>())
383  {
384  CHECK (materialise (target) == follower.receivedValue());
385  }
386  else
387  {
388  CHECK (target == follower.receivedValue());
389  }
390  }
391  void
392  ____verify_notification (TimeSpan const& targetTimeSpan, TestListener<Duration> const& follower)
393  {
394  CHECK (follower.receivedValue() == targetTimeSpan.duration());
395  }
396  void
397  ____verify_notification (Duration const& target, TestListener<Duration> const& follower)
398  {
399  CHECK (target == follower.receivedValue());
400  }
401  void
402  ____verify_notification (Duration const& targetDuration, TestListener<TimeSpan> const& follower)
403  {
404  CHECK (Time::ZERO == follower.receivedValue());
405  CHECK (targetDuration == follower.receivedValue().duration());
406  }
407 
408 
409 
410 
411  template< class TAR
412  , class SRC
413  , class BASE
414  >
415  struct TestCase
416  : BASE
417  {
418  void
419  performTestSequence(TimeValue const& org, TimeValue const& c)
420  {
421  cout << "Test-Case. Target=" << typeStr<TAR>()
422  << "\t <--feed--- " << typeStr<SRC>()
423  << endl;
424 
425  // test subject
426  Control<SRC> controller;
427 
428  TAR target = TestTarget<TAR>::build(org);
429  SRC change = TestChange<SRC>::prepareChangeValue(c);
430  TestListener<SRC> follower(change);
431 
432  controller.connectChangeNotification(follower);
433  target.accept (controller);
434 
435  controller (change);
436  ____verify_wasChanged (target, org, change);
437  ____verify_notification(target,follower);
438 
439  TAR refState(target);
440 
441  Offset offset(c);
442  controller (offset);
443  ____verify_wasOffset (target, refState, offset);
444  controller (-offset);
445  ____verify_wasOffsetBack (target, refState);
446  ____verify_notification(target,follower);
447 
448  controller (0);
449  ____verify_nudged (target, refState, 0);
450  ____verify_notification(target,follower);
451 
452  controller (+1);
453  ____verify_nudged (target, refState, +1);
454  ____verify_notification(target,follower);
455 
456  controller (-2);
457  ____verify_nudged (target, refState, -1);
458  ____verify_notification(target,follower);
459 
460  int maxInt = std::numeric_limits<int>::max();
461  int minInt = std::numeric_limits<int>::min();
462 
463  controller (maxInt);
464  ____verify_nudged (target, refState, -1LL + maxInt);
465  ____verify_notification(target,follower);
466 
467  controller (minInt);
468  ____verify_nudged (target, refState, -1LL + maxInt+minInt);
469  ____verify_notification(target,follower);
470 
471 
472  // tail recursion: further test combinations....
473  BASE::performTestSequence(org,c);
474  }
475  };
476 
478  {
479  void performTestSequence(TimeValue const&, TimeValue const&) { }
480  };
481 
482  }//(End)Implementation Test-case matrix
483 
484 
485  void
487  {
488  typedef Types<Duration,TimeSpan,QuTime> KindsOfTarget; // time entities to receive value changes
489  typedef Types<TimeValue,Time,Duration,TimeSpan,QuTime> KindsOfSource; // time entities to be used as change values
490  typedef InstantiateChainedCombinations< KindsOfTarget
491  , KindsOfSource
492  , TestCase // template to be instantiated for each type
493  , IterationEnd > TestMatrix;
494 
495  TestMatrix().performTestSequence(origVal, change);
496  }
497 
498 
499 
500 
501 
503  LAUNCHER (TimeControl_test, "unit common");
504 
505 
506 
507 }}} // namespace lib::time::test
Interface: a grid and scale definition for time quantisation.
Definition: time-grid.hpp:86
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:224
Automatically use custom string conversion in C++ stream output.
Frontend/Interface: controller-element to retrieve and change running time values.
Definition: control.hpp:134
void verifyMatrix_of_MutationCases(TimeValue const &o, TimeValue const &c)
void accept(Mutation const &)
may change start / duration
Definition: mutation.hpp:132
AnyPair entry(Query< TY > const &query, typename WrapReturn< TY >::Wrapper &obj)
helper to simplify creating mock table entries, wrapped correctly
Definition: run.hpp:49
Any copy and copy construction prohibited.
Definition: nocopy.hpp:46
static const gavl_time_t SCALE
Number of micro ticks (µs) per second as basic time scale.
Definition: timevalue.hpp:176
#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:167
static const Duration NIL
constant to indicate "no duration"
Definition: timevalue.hpp:515
Implementation namespace for support and library code.
Lumiera&#39;s internal time value datatype.
Definition: timevalue.hpp:308
Metaprogramming facilities to generate combination cases.
Simple 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:229
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:367
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:477
A time interval anchored at a specific point in time.
Definition: timevalue.hpp:582
int64_t FrameCnt
relative framecount or frame number.
Definition: digxel.hpp:321
a family of time value like entities and their relationships.
basic constant internal time value.
Definition: timevalue.hpp:142
static const FrameRate PAL
predefined constant for PAL framerate
Definition: timevalue.hpp:680
grid aligned time specification, referring to a specific scale.
Definition: timequant.hpp:99