Lumiera  0.pre.03
»edit your freedom«
time-mutation-test.cpp
Go to the documentation of this file.
1 /*
2  TimeMutation(Test) - explicitly changing time specifications
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/mutation.hpp"
25 #include "lib/util.hpp"
26 
27 #include <boost/lexical_cast.hpp>
28 #include <string>
29 
30 using boost::lexical_cast;
31 using util::isnil;
32 using std::string;
33 
34 
35 namespace lib {
36 namespace time{
37 namespace test{
38 
40 
41  namespace {
42  inline string
43  pop (Arg arg)
44  {
45  if (isnil (arg)) return "";
46  string entry = arg[0];
47  arg.erase (arg.begin());
48  return entry;
49  }
50  }
51 
52 
53 
54 
55  /************************************************************/
62  class TimeMutation_test : public Test
63  {
64  gavl_time_t
65  random_or_get (string arg)
66  {
67  if (isnil(arg))
68  return gavl_time_t(1 + rani (100000)) * TimeValue::SCALE;
69  else
70  return lexical_cast<gavl_time_t> (arg);
71  }
72 
73  struct TestValues
74  {
75  TimeVar var;
76  Duration dur;
77  TimeSpan span;
78  QuTime quant;
79 
81  : var(o)
82  , dur(o)
83  , span(o, Offset(o))
84  , quant(o, "test_grid")
85  { }
86  };
87 
88 
89  virtual void
90  run (Arg arg)
91  {
92  if (isnil(arg))
93  seedRand();
94  TimeValue o (random_or_get (pop(arg)));
95  TimeValue c (random_or_get (pop(arg)));
96  CHECK (o != c, "unsuitable testdata");
97 
98  // using a 25fps-grid, but with an time origin offset by 1/50sec
99  TimeGrid::build("test_grid", FrameRate::PAL, Time(FSecs(1,50)));
100 
101  QuTime qChange (c, "test_grid");
102  FrameNr count(qChange);
103 
104  mutate_by_Value (o, Time(c));
105  mutate_by_Offset (o, Offset(c));
106  mutate_quantised (o, qChange);
107  mutate_by_Increment(o, count);
108  }
109 
110 
111  void
112  mutate_by_Value(TimeValue original, Time newStart)
113  {
114  TestValues t(original);
115 
116  CHECK (t.span.start() == original);
117  t.span.accept (Mutation::changeTime (newStart));
118  CHECK (t.span.start() != original);
119  CHECK (t.span.start() == newStart);
120 
121  // instead of invoking directly, we can store and copy mutation messages
122  EncapsulatedMutation change_back(Mutation::changeTime (Time(original)));
123  t.span.accept (change_back);
124  CHECK (t.span.start() == original);
125 
126  CHECK (t.quant == original);
127  t.quant.accept (Mutation::changeTime (newStart));
128  CHECK (t.quant != original);
129  CHECK (t.quant == newStart);
130 
131  // Durations have no start time...
132  VERIFY_ERROR (INVALID_MUTATION, t.dur.accept(change_back));
133  VERIFY_ERROR (INVALID_MUTATION, t.span.duration().accept(change_back));
134 
135  CHECK (t.dur == original);
136  t.dur.accept (Mutation::changeDuration (Duration(2*t.var)));
137  CHECK (t.dur != original);
138  CHECK (t.dur == t.var*2);
139 
140  CHECK (t.span.start() == original);
141  CHECK (t.span.duration() == original);
142  t.span.accept (Mutation::changeDuration(Duration(3*t.var)));
143  CHECK (t.span.duration() != original);
144  CHECK (t.span.duration() == t.var*3); // affects the duration,
145  CHECK (t.span.start() == original); // while the start time remains unaltered
146 
147  // can't change the 'duration' of a quantised time point...
148  VERIFY_ERROR (INVALID_MUTATION, t.quant.accept(Mutation::changeDuration (Duration(t.var))));
149  }
150 
151 
152  void
153  mutate_by_Offset (TimeValue original, Offset change)
154  {
155  TestValues t(original);
156  TimeValue& should_be(t.var+=change); // use as ref for verification
157 
158  CHECK (t.span == original);
159  CHECK (t.span != should_be);
160  t.span.accept (Mutation::adjust (change));
161  CHECK (t.span == should_be);
162 
163  t.dur.accept (Mutation::adjust (change));
164  CHECK (t.dur == should_be);
165 
166  t.quant.accept (Mutation::adjust (change));
167  CHECK (t.quant == should_be);
168 
169  // adjustment is cumulative
170  EncapsulatedMutation back_off = Mutation::adjust (-change);
171  t.span.accept (back_off);
172  CHECK (t.span == original);
173  t.span.accept (back_off);
174  t.span.accept (back_off);
175  t.span.accept (back_off);
176  CHECK (t.span == Time(original) - 3*change);
177  }
178 
179 
180  void
181  mutate_quantised (TimeValue original, QuTime change)
182  {
183  TestValues t(original);
184  t.var = change;
185  CHECK (Time(change) == t.var); // the underlying raw time value
186 
187  CHECK (t.span == original);
188  t.span.accept (Mutation::materialise (change));
189  CHECK (t.span != original);
190  CHECK (t.span != t.var); // really materialised (grid-aligned)
191 
192  // simulate what happened by explicit operations...
193  Secs seconds = change.formatAs<format::Seconds>();
194  PQuant quantiser(change);
195  Time materialised (quantiser->materialise(change));
196  CHECK (t.span == materialised);
197 
198  CHECK (t.span.duration() == original); // not affected by mutation as usual
199  VERIFY_ERROR (INVALID_MUTATION, t.dur.accept (Mutation::materialise (change)));
200  // not surprising, a time point has no duration!!
201 
202  CHECK (t.quant == original);
203  t.quant.accept (Mutation::materialise (change));
204  CHECK (t.quant != original);
205  CHECK (t.quant == materialised);
206  // but note, here we checked the underlying raw value.
207  // because t.quant is itself quantised, this might
208  // result in a second, chained quantisation finally
209 
210  // Here accidentally both the change and t.quant use the same grid.
211  // For a more contrived example, we try to use a different grid...
212  TimeGrid::build("special_funny_grid", 1, Time(0,-10)); // (1 frame per second, zero point at -10s)
213  QuTime funny (original, "special_funny_grid");
214  funny.accept (Mutation::materialise (change));
215  CHECK (funny == t.quant); // leading to the same raw value this far
216 
217  Time doublyQuantised (PQuant(funny)->materialise(funny));
218  CHECK (doublyQuantised != materialised);
219  }
220 
221 
222  void
223  mutate_by_Increment (TimeValue original, int change)
224  {
225  TestValues t(original);
226 
227  // without any additional specification,
228  // the nudge-Mutation uses a 'natural grid'
229  t.span.accept (Mutation::nudge (change));
230  t.dur.accept (Mutation::nudge (change));
231 
232  t.var += Time(FSecs(change)); // natural grid is in seconds
233  CHECK (t.span.start() == t.var);
234  CHECK (t.dur == t.var);
235 
236  // any other grid can be specified explicitly
237  t.dur.accept (Mutation::nudge (change, "test_grid"));
238  CHECK (t.dur != t.var);
239  CHECK (t.dur == t.var + change * FrameRate::PAL.duration());
240  // ....this time the change was measured in grid units,
241  // taken relative to the origin of the specified grid
242  PQuant testGrid = Quantiser::retrieve("test_grid");
243  Offset distance (testGrid->timeOf(0), testGrid->timeOf(change));
244  CHECK (distance == change * FrameRate::PAL.duration());
245  CHECK (t.dur - t.var == distance);
246 
247 
248 
249  // To the contrary, *quantised* values behave quite differently...
250  long frameNr = t.quant.formatAs<format::Frames>();
251 
252  t.quant.accept (Mutation::nudge (change));
253  CHECK (t.quant != original);
254  long frameNr_after = t.quant.formatAs<format::Frames>();
255  CHECK (frameNr_after == frameNr + change);
256  //i.e. the quantised time's own grid is used
257  }
258  };
259 
260 
262  LAUNCHER (TimeMutation_test, "unit common");
263 
264 
265 
266 }}} // namespace lib::time::test
a mutable time value, behaving like a plain number, allowing copy and re-accessing ...
Definition: timevalue.hpp:232
Interface: a grid and scale definition for time quantisation.
Definition: time-grid.hpp:77
Frame count as timecode format.
Definition: formats.hpp:75
Modifying time and timecode values.
static PQuant retrieve(Symbol gridID)
Access an existing grid definition or quantiser, known by the given symbolic ID.
static EncapsulatedMutation changeTime(Time)
Convenience factory to yield a simple Mutation changing the absolute start time.
Definition: mutation.cpp:285
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
static const gavl_time_t SCALE
Number of micro ticks (µs) per second as basic time scale.
Definition: timevalue.hpp:167
static EncapsulatedMutation adjust(Offset)
Convenience factory: simple Mutation to adjust the duration or length of a timespan.
Definition: mutation.cpp:307
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
void accept(Mutation const &)
receive change message, which might cause re-quantisation
Implementation namespace for support and library code.
Lumiera&#39;s internal time value datatype.
Definition: timevalue.hpp:299
format::Traits< FMT >::TimeCode formatAs() const
create new time code instance, then castInto
Definition: timequant.hpp:138
static EncapsulatedMutation materialise(QuTime const &)
Convenience factory: materialise the given quantised time into an explicit fixed internal time value...
Definition: mutation.cpp:319
Simplistic test class runner.
Template to build polymorphic value objects.
Tiny helper functions and shortcuts to be used everywhere Consider this header to be effectively incl...
Simple timecode specification as fractional seconds.
Definition: formats.hpp:126
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.
Duration duration() const
duration of one frame
Definition: time.cpp:254
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
To establish a reference scale for quantised time values.
static EncapsulatedMutation nudge(int adjustment)
build a time mutation to nudge the target time value by an offset, defined as number of steps on an i...
Definition: mutation.cpp:336
Duration is the internal Lumiera time metric.
Definition: timevalue.hpp:468
static EncapsulatedMutation changeDuration(Duration)
Convenience factory: simple Mutation to adjust the duration or length of a timespan.
Definition: mutation.cpp:296
A time interval anchored at a specific point in time.
Definition: timevalue.hpp:573
A frame counting timecode value.
Definition: timecode.hpp:96
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