Lumiera  0.pre.03
»edit your freedom«
node-devel-test.cpp
Go to the documentation of this file.
1 /*
2  NodeDevel(Test) - Render Node development and test support
3 
4  Copyright (C)
5  2024, 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/hash-combine.hpp"
21 #include "lib/test/test-helper.hpp"
24 #include "lib/iter-zip.hpp"
25 #include "lib/random.hpp"
26 //#include "lib/util.hpp"
27 
28 #include <vector>
29 
30 using lib::zip;
31 using lib::izip;
32 using std::vector;
33 
34 
35 namespace steam {
36 namespace engine{
37 namespace test {
38 
39 
40  namespace {
43  struct Buffer
45  {
46  alignas(TestFrame)
47  std::byte storage[sizeof(TestFrame)];
48 
49  operator TestFrame* () { return std::launder (reinterpret_cast<TestFrame* > (&storage)); }
50  TestFrame* operator->() { return std::launder (reinterpret_cast<TestFrame* > (&storage)); }
51  TestFrame& operator* () { return * std::launder (reinterpret_cast<TestFrame* > (&storage)); }
52 
53  TestFrame&
54  buildData (uint seq=0, uint family=0)
55  {
56  return * new(&storage) TestFrame{seq,family};
57  }
58  };
59  }
60 
61 
62 
63  /***************************************************************/
66  class NodeDevel_test : public Test
67  {
68  virtual void
69  run (Arg)
70  {
71  seedRand();
73 
74  processing_generateFrame();
75  processing_generateMultichan();
76  processing_duplicateMultichan();
77  processing_manipulateMultichan();
78  processing_manipulateFrame();
79  processing_combineFrames();
80 
81  testRand_simpleUsage();
82  }
83 
84 
87  void
89  {
90  size_t frameNr = defaultGen.u64();
91  uint flavour = defaultGen.u64();
92 
93  Buffer buff;
94  CHECK (not buff->isSane());
95 
96  generateFrame (buff, frameNr, flavour);
97  CHECK ( buff->isSane());
98  CHECK ( buff->isPristine());
99  CHECK (*buff == TestFrame(frameNr,flavour));
100  }
101 
105  void
107  {
108  size_t frameNr = defaultGen.u64();
109  uint flavour = defaultGen.u64();
110 
111  uint channels = 1 + rani(50);
112  CHECK (1 <= channels and channels <= 50);
113 
114  Buffer buff[50];
115  for (uint i=0; i<channels; ++i)
116  CHECK (not buff[i]->isSane());
117 
118  generateMultichan (buff[0], channels, frameNr, flavour);
119  for (uint i=0; i<channels; ++i)
120  {
121  CHECK (buff[i]->isPristine());
122  CHECK (*(buff[i]) == TestFrame(frameNr,flavour+i));
123  }
124  }
125 
126 
128  void
130  {
131  size_t frameNr = defaultGen.u64();
132  uint flavour = defaultGen.u64();
133  uint channels = 1 + rani(50);
134  Buffer srcBuff[50];
135  generateMultichan (srcBuff[0], channels, frameNr, flavour);
136 
137  Buffer clone[50];
138  for (uint i=0; i<channels; ++i)
139  CHECK (not clone[i]->isSane());
140 
141  duplicateMultichan (clone[0],srcBuff[0], channels);
142  for (uint i=0; i<channels; ++i)
143  {
144  CHECK (clone[i]->isPristine());
145  CHECK (*(clone[i]) == *(srcBuff[i]));
146  }
147  }
148 
149 
160  void
162  {
163  size_t frameNr = defaultGen.u64();
164  uint flavour = defaultGen.u64();
165  uint channels = 1 + rani(50);
166  Buffer buff[50], refData[50];
167  generateMultichan (buff[0], channels, frameNr, flavour);
168  // stash away a copy of the test data for verification
169  duplicateMultichan(refData[0],buff[0], channels);
170 
171  for (uint c=0; c<channels; ++c)
172  CHECK (buff[c]->isPristine());
173 
174  uint64_t param = defaultGen.u64();
175  manipulateMultichan(buff[0], channels, param);
176 
177  const uint SIZ = buff[0]->data64().size();
178  vector<uint64_t> xlink(SIZ, param); // temporary storage for verifying the hash-chain
179  for (uint c=0; c<channels; ++c)
180  {
181  CHECK (buff[c]->isSane()); // checksum matches
182  CHECK (not buff[c]->isPristine()); // data was indeed changed
183 
184  CHECK (*(buff[c]) != *(refData[c]));
185 
186  for (auto& [i, link] : izip(xlink))
187  {
188  auto const& refPoint = refData[c]->data64()[i];
189  lib::hash::combine (link, refPoint);
190  CHECK (link != refPoint);
191  CHECK (link == buff[c]->data64()[i]);
192  }
193  }
194  }
195 
200  void
202  {
203  size_t frameNr = defaultGen.u64();
204  uint flavour = defaultGen.u64();
205 
206  Buffer iBuff, oBuff;
207  iBuff.buildData(frameNr,flavour);
208  oBuff.buildData(frameNr,flavour);
209  CHECK (iBuff->isPristine());
210  CHECK (oBuff->isPristine());
211 
212  uint64_t param = defaultGen.u64();
213  manipulateFrame (oBuff, iBuff, param);
214  CHECK ( oBuff->isValid());
215  CHECK (not oBuff->isPristine());
216  CHECK ( iBuff->isPristine());
217 
218  for (auto [iDat,oDat] : zip (iBuff->data64()
219  ,oBuff->data64()))
220  {
221  CHECK (oDat != iDat);
222  uint64_t feed = param;
223  lib::hash::combine (feed, iDat);
224  CHECK (feed != param);
225  CHECK (feed != iDat);
226  CHECK (feed == oDat);
227  }
228  // can also process in-place
229  manipulateFrame (iBuff, iBuff, param);
230  CHECK (not iBuff->isPristine());
231  CHECK ( iBuff->isValid());
232  CHECK (*iBuff == *oBuff); // second invocation exactly reproduced data from first invocation
233  }
234 
237  void
239  {
240  size_t frameNr = defaultGen.u64();
241  uint flavour = defaultGen.u64();
242 
243  Buffer i1Buff, i2Buff, oBuff;
244  i1Buff.buildData(frameNr,flavour+0);
245  i2Buff.buildData(frameNr,flavour+1);
246  oBuff.buildData();
247  CHECK (i1Buff->isPristine());
248  CHECK (i2Buff->isPristine());
249  CHECK (oBuff->isPristine());
250 
251  double mix = defaultGen.uni();
252  combineFrames (oBuff, i1Buff, i2Buff, mix);
253  CHECK ( oBuff->isValid());
254  CHECK (not oBuff->isPristine());
255  CHECK ( i1Buff->isPristine());
256  CHECK ( i2Buff->isPristine());
257 
258  for (auto [oDat,i1Dat,i2Dat] : zip (oBuff->data()
259  ,i1Buff->data()
260  ,i2Buff->data()))
261  CHECK (oDat == std::lround((1-mix)*i1Dat + mix*i2Dat));
262 
263  // can also process in-place
264  combineFrames (i1Buff, i1Buff, i2Buff, mix);
265  CHECK (not i1Buff->isPristine());
266  CHECK ( i1Buff->isValid());
267  CHECK (*i1Buff == *oBuff); // second invocation exactly reproduced data from first invocation
268  }
269 
270 
271 
278  void
280  {
281  auto spec = testRand().setupGenerator();
282 SHOW_EXPR(spec.PROTO);
283  CHECK (spec.PROTO == "generate-TestFrame"_expect);
284  }
285  };
286 
287 
289  LAUNCHER (NodeDevel_test, "unit node");
290 
291 
292 
293 }}} // namespace steam::engine::test
void manipulateMultichan(TestFrame *buffArry, uint chanCnt, uint64_t param)
»process« a planar multi channel array of data frames in-place.
Mock data frame for simulated rendering.
Definition: testframe.hpp:68
void generateMultichan(TestFrame *buffArry, uint chanCnt, size_t frameNr, uint flavour)
produce planar multi channel output of random data frames
auto izip(ITS &&...iters)
tuple-combining iterator prefixed by index sequence
Definition: iter-zip.hpp:152
Definition: run.hpp:40
Any copy and copy construction prohibited.
Definition: nocopy.hpp:37
void combine(size_t &combinedHash, size_t additionalHash)
meld the additional hash value into the given base hash value.
int rani(uint bound=_iBOUND())
Definition: random.hpp:135
A faked »media calculation« environment to validate the render node network.
Helpers typically used while writing tests.
void generateFrame(TestFrame *buff, size_t frameNr, uint flavour)
produce sequences of frames with (reproducible) random data
Steam-Layer implementation namespace root.
void duplicateMultichan(TestFrame *outArry, TestFrame *inArry, uint chanCnt)
create an identical clone copy of the planar multi channel frame array
Iterator builder to combine several iterables into a tuple sequence.
void manipulateFrame(TestFrame *out, TestFrame const *in, uint64_t param)
»process« random frame date by hash-chaining with a parameter.
Simplistic test class runner.
uint64_t u64()
random 64bit number from full range.
Definition: random.hpp:224
A collection of frequently used helper functions to support unit testing.
Generating (pseudo) random numbers with controlled seed.
static void reseed()
discard all cached #testData and recalibrate data generation
Definition: testframe.cpp:204
double uni()
random double drawn from interval [0.0 ... 1.0[
Definition: random.hpp:232
void combineFrames(TestFrame *out, TestFrame const *srcA, TestFrame const *srcB, double mix)
mix two random data frames by a parameter-controlled proportion
Random defaultGen
a global default RandomSequencer for mundane purposes
Definition: random.cpp:70
lib::Depend< TestRandOntology > testRand
Storage for the Singleton-Accessor/Factory.
uninitialised local storage that can be passed as working buffer and accessed as TestFrame ...
auto zip(ITS &&...iters)
Build a tuple-combining iterator builder.
Definition: iter-zip.hpp:138