ChimeraTK-DeviceAccess  03.18.00
testTransferElement.cpp
Go to the documentation of this file.
1 // SPDX-FileCopyrightText: Deutsches Elektronen-Synchrotron DESY, MSK, ChimeraTK Project <chimeratk-support@desy.de>
2 // SPDX-License-Identifier: LGPL-3.0-or-later
3 
4 /**********************************************************************************************************************/
5 /*
6  * Tests for the TransferElement base class.
7  *
8  * IMPORTANT: READ BEFORE MODIFYING!
9  *
10  * These tests test whether the implementation of the TransferElement base class (and maybe potentially at some point
11  * the NDRegisterAccessor base class) behave according to the specification. The purpose of these tests is NOT to
12  * verify that the specifications are correct or complete. These tests are intentionally low-level and test exactly
13  * point-by-point the (low-level) behaviour described in the specification. It intentionally does NOT test whether the
14  * high-level ideas behind the specification works. This is outside the scope of this test, adding it here would
15  * prevent an exact identification of the tested parts of the specification.
16  */
17 /**********************************************************************************************************************/
18 
19 #define BOOST_TEST_DYN_LINK
20 #define BOOST_TEST_MODULE TransferElementTest
21 #include <boost/test/unit_test.hpp>
22 using namespace boost::unit_test_framework;
23 
24 #include "DeviceBackendImpl.h"
25 #include "NDRegisterAccessor.h"
28 
29 #include <boost/make_shared.hpp>
30 
31 using namespace ChimeraTK;
32 
33 /**********************************************************************************************************************/
34 
41  bool ret;
42 
43  accessor.resetCounters();
44  ret = accessor.readNonBlocking();
45  BOOST_CHECK(ret == true);
46 
47  accessor.resetCounters();
48  ret = accessor.readLatest();
49  BOOST_CHECK(ret == true);
50 }
51 
52 /**********************************************************************************************************************/
53 
58 BOOST_AUTO_TEST_CASE(test_B_3_1_3_1) {
59  {
60  TransferElementTestAccessor<int32_t> accessor({AccessMode::wait_for_new_data});
61 
62  accessor.resetCounters();
63  std::atomic<bool> readCompleted{false};
64  std::thread t([&] {
65  accessor.read();
66  readCompleted = true;
67  });
68  usleep(10000);
69  BOOST_CHECK(!readCompleted);
70  accessor.push();
71  t.join();
72  }
73 }
74 
75 /**********************************************************************************************************************/
76 
81 BOOST_AUTO_TEST_CASE(test_B_3_1_3_2) {
82  {
83  TransferElementTestAccessor<int32_t> accessor({AccessMode::wait_for_new_data});
84 
85  accessor.resetCounters();
86  BOOST_CHECK(accessor.readNonBlocking() == false);
87  accessor.push();
88  BOOST_CHECK(accessor.readNonBlocking() == true);
89  BOOST_CHECK(accessor.readNonBlocking() == false);
90  accessor.push();
91  accessor.push();
92  BOOST_CHECK(accessor.readNonBlocking() == true);
93  BOOST_CHECK(accessor.readNonBlocking() == true);
94  BOOST_CHECK(accessor.readNonBlocking() == false);
95  }
96 }
97 
98 /**********************************************************************************************************************/
99 
108  TransferElementTestAccessor<int32_t> asyncAccessor({AccessMode::wait_for_new_data});
109  bool ret;
110 
111  // Without AccessMode::wait_for_new_data
112  accessor.resetCounters();
113  ret = accessor.readLatest();
114  BOOST_CHECK(ret == true);
115  BOOST_CHECK_EQUAL(accessor._readTransfer_counter, 1);
116  BOOST_CHECK_EQUAL(accessor._postRead_counter, 1);
117 
118  // With AccessMode::wait_for_new_data
119  asyncAccessor.resetCounters();
120  ret = asyncAccessor.readLatest();
121  BOOST_CHECK(ret == false);
122  BOOST_CHECK_EQUAL(asyncAccessor._postRead_counter, 1); // no update -> one call to readNonBlocking()
123 
124  asyncAccessor.resetCounters();
125  asyncAccessor.push();
126  ret = asyncAccessor.readLatest();
127  BOOST_CHECK(ret == true);
128  BOOST_CHECK_EQUAL(asyncAccessor._postRead_counter, 2); // one update -> two calls to readNonBlocking()
129 
130  asyncAccessor.resetCounters();
131  ret = asyncAccessor.readLatest();
132  BOOST_CHECK(ret == false);
133  BOOST_CHECK_EQUAL(asyncAccessor._postRead_counter, 1);
134 
135  asyncAccessor.resetCounters();
136  while(asyncAccessor.push()) continue; // fill the queue
137  ret = asyncAccessor.readLatest();
138  BOOST_CHECK(ret == true);
139  BOOST_CHECK_EQUAL(asyncAccessor._postRead_counter, 4); // _readQueue.size() updates -> one more readNonBlocking() call
140 
141  asyncAccessor.resetCounters();
142  ret = asyncAccessor.readLatest();
143  BOOST_CHECK(ret == false);
144  BOOST_CHECK_EQUAL(asyncAccessor._postRead_counter, 1);
145 }
146 
147 /**********************************************************************************************************************/
148 
152 #define TEST_TRANSFER_SEQUENCE(transferElement, expectedType, expectTransferExecution) \
153  assert(expectedType != TransferType::readLatest); /* doesn't exist any more -> remove from definition! */ \
154  \
155  /* correct stages in read */ \
156  if((expectedType == TransferType::read || expectedType == TransferType::readNonBlocking)) { \
157  BOOST_CHECK_EQUAL(transferElement._preRead_counter, 1); \
158  if(expectTransferExecution) { \
159  BOOST_CHECK_EQUAL(transferElement._readTransfer_counter, 1); \
160  } \
161  else { \
162  BOOST_CHECK_EQUAL(transferElement._readTransfer_counter, 0); \
163  } \
164  BOOST_CHECK_EQUAL(transferElement._postRead_counter, 1); \
165  } \
166  \
167  /* correct stages in non-destructive write */ \
168  if(expectedType == TransferType::write) { \
169  BOOST_CHECK_EQUAL(transferElement._preWrite_counter, 1); \
170  if(expectTransferExecution) { \
171  BOOST_CHECK_EQUAL(transferElement._writeTransfer_counter, 1); \
172  } \
173  else { \
174  BOOST_CHECK_EQUAL(transferElement._writeTransfer_counter, 0); \
175  } \
176  BOOST_CHECK_EQUAL(transferElement._postWrite_counter, 1); \
177  } \
178  \
179  /* correct stages in destructive write */ \
180  if(expectedType == TransferType::writeDestructively) { \
181  BOOST_CHECK_EQUAL(transferElement._preWrite_counter, 1); \
182  if(expectTransferExecution) { \
183  BOOST_CHECK_EQUAL(transferElement._writeTransferDestructively_counter, 1); \
184  } \
185  else { \
186  BOOST_CHECK_EQUAL(transferElement._writeTransferDestructively_counter, 0); \
187  } \
188  BOOST_CHECK_EQUAL(transferElement._postWrite_counter, 1); \
189  } \
190  \
191  /* order of stages */ \
192  BOOST_CHECK_EQUAL(transferElement._preIndex, 0); \
193  if(expectTransferExecution) { \
194  BOOST_CHECK_EQUAL(transferElement._transferIndex, 1); \
195  BOOST_CHECK_EQUAL(transferElement._postIndex, 2); \
196  } \
197  else { \
198  BOOST_CHECK_EQUAL(transferElement._postIndex, 1); \
199  } \
200  \
201  /* check transfer type passed to preXxx() and postXxx() */ \
202  BOOST_CHECK(transferElement._transferType_pre == expectedType); \
203  BOOST_CHECK(transferElement._transferType_post == expectedType)
204 
205 /**********************************************************************************************************************/
206 
212  {
214 
215  accessor.resetCounters();
216  accessor.read();
217  TEST_TRANSFER_SEQUENCE(accessor, TransferType::read, true);
218 
219  accessor.resetCounters();
220  accessor.readNonBlocking();
221  TEST_TRANSFER_SEQUENCE(accessor, TransferType::readNonBlocking, true);
222  accessor.resetCounters();
223 
224  accessor.write();
225  TEST_TRANSFER_SEQUENCE(accessor, TransferType::write, true);
226 
227  accessor.resetCounters();
228  accessor.write();
229  TEST_TRANSFER_SEQUENCE(accessor, TransferType::write, true);
230 
231  accessor.resetCounters();
232  accessor.writeDestructively();
233  TEST_TRANSFER_SEQUENCE(accessor, TransferType::writeDestructively, true);
234 
235  accessor.resetCounters();
236  accessor.writeDestructively();
237  TEST_TRANSFER_SEQUENCE(accessor, TransferType::writeDestructively, true);
238  }
239 
240  {
241  TransferElementTestAccessor<int32_t> accessor({AccessMode::wait_for_new_data});
242 
243  accessor.resetCounters();
244  accessor.push();
245  accessor.read();
246  TEST_TRANSFER_SEQUENCE(accessor, TransferType::read, false);
247 
248  accessor.resetCounters();
249  accessor.readNonBlocking();
250  TEST_TRANSFER_SEQUENCE(accessor, TransferType::readNonBlocking, false);
251  }
252 }
253 
254 /**********************************************************************************************************************/
255 
260 BOOST_AUTO_TEST_CASE(test_B_4_1) {
262 
263  accessor.resetCounters();
264  accessor.preRead(TransferType::read);
265  BOOST_CHECK_EQUAL(accessor._preRead_counter, 1);
266  BOOST_CHECK(accessor._transferType_pre == TransferType::read);
267  accessor.readTransfer();
268  accessor.postRead(TransferType::read, true);
269 
270  accessor.resetCounters();
271  accessor.preRead(TransferType::readNonBlocking);
272  BOOST_CHECK_EQUAL(accessor._preRead_counter, 1);
273  BOOST_CHECK(accessor._transferType_pre == TransferType::readNonBlocking);
274  accessor.readTransfer();
275  accessor.postRead(TransferType::readNonBlocking, true);
276 
277  VersionNumber v{};
278  accessor.resetCounters();
279  accessor.preWrite(TransferType::write, v);
280  BOOST_CHECK_EQUAL(accessor._preWrite_counter, 1);
281  BOOST_CHECK(accessor._transferType_pre == TransferType::write);
282  BOOST_CHECK(accessor._preWrite_version == v);
283  accessor.writeTransfer(v);
284  accessor.postWrite(TransferType::write, v);
285 
286  v = {};
287  accessor.resetCounters();
288  accessor.preWrite(TransferType::writeDestructively, v);
289  BOOST_CHECK_EQUAL(accessor._preWrite_counter, 1);
290  BOOST_CHECK(accessor._transferType_pre == TransferType::writeDestructively);
291  BOOST_CHECK(accessor._preWrite_version == v);
292  accessor.writeTransfer(v);
293  accessor.postWrite(TransferType::writeDestructively, v);
294 }
295 
296 /**********************************************************************************************************************/
297 
302 BOOST_AUTO_TEST_CASE(test_B_4_2_1) {
303  {
304  TransferElementTestAccessor<int32_t> accessor({AccessMode::wait_for_new_data});
305 
306  accessor.resetCounters();
307  accessor.preRead(TransferType::read);
308  std::atomic<bool> readCompleted{false};
309  std::thread t([&] {
310  accessor.readTransfer();
311  readCompleted = true;
312  });
313  usleep(10000);
314  BOOST_CHECK(!readCompleted);
315  accessor.push();
316  t.join();
317  accessor.postRead(TransferType::read, true);
318  }
319  {
321 
322  accessor.resetCounters();
323  accessor.preRead(TransferType::read);
324  BOOST_CHECK_EQUAL(accessor._readTransfer_counter, 0);
325  accessor.readTransfer();
326  BOOST_CHECK_EQUAL(accessor._readTransfer_counter, 1);
327  accessor.postRead(TransferType::read, true);
328  }
329 }
330 
331 /**********************************************************************************************************************/
332 
337 BOOST_AUTO_TEST_CASE(test_B_4_2_2) {
338  {
339  TransferElementTestAccessor<int32_t> accessor({AccessMode::wait_for_new_data});
340 
341  accessor.resetCounters();
342  accessor.preRead(TransferType::readNonBlocking);
343  BOOST_CHECK(accessor.readTransferNonBlocking() == false);
344  accessor.postRead(TransferType::readNonBlocking, true);
345 
346  accessor.resetCounters();
347  accessor.push();
348  accessor.preRead(TransferType::readNonBlocking);
349  BOOST_CHECK(accessor.readTransferNonBlocking() == true);
350  accessor.postRead(TransferType::readNonBlocking, true);
351  }
352  {
354 
355  accessor.resetCounters();
356  accessor.preRead(TransferType::readNonBlocking);
357  BOOST_CHECK_EQUAL(accessor._readTransfer_counter, 0);
358  BOOST_CHECK(accessor.readTransferNonBlocking() == true);
359  BOOST_CHECK_EQUAL(accessor._readTransfer_counter, 1);
360  accessor.postRead(TransferType::readNonBlocking, true);
361  }
362 }
363 
364 /**********************************************************************************************************************/
365 
370 BOOST_AUTO_TEST_CASE(test_B_4_2_3) {
372  VersionNumber v{nullptr};
373 
374  accessor.resetCounters();
375  v = {};
376  accessor.preWrite(TransferType::write, v);
377  BOOST_CHECK_EQUAL(accessor._writeTransfer_counter, 0);
378  accessor.writeTransfer(v);
379  BOOST_CHECK_EQUAL(accessor._writeTransfer_counter, 1);
380  BOOST_CHECK(accessor._writeTransfer_version == v);
381  accessor.postWrite(TransferType::write, v);
382 
383  accessor.resetCounters();
384  v = {};
385  accessor.preWrite(TransferType::writeDestructively, v);
386  BOOST_CHECK_EQUAL(accessor._writeTransferDestructively_counter, 0);
387  accessor.writeTransferDestructively(v);
388  BOOST_CHECK_EQUAL(accessor._writeTransferDestructively_counter, 1);
389  BOOST_CHECK(accessor._writeTransfer_version == v);
390  accessor.postWrite(TransferType::writeDestructively, v);
391 }
392 
393 /**********************************************************************************************************************/
394 
399 BOOST_AUTO_TEST_CASE(test_B_4_3) {
401 
402  accessor.resetCounters();
403  accessor.preRead(TransferType::read);
404  accessor.readTransfer();
405  BOOST_CHECK_EQUAL(accessor._postRead_counter, 0);
406  accessor.postRead(TransferType::read, true);
407  BOOST_CHECK_EQUAL(accessor._postRead_counter, 1);
408  BOOST_CHECK(accessor._transferType_post == TransferType::read);
409  BOOST_CHECK(accessor._updateDataBuffer == true);
410 
411  accessor.resetCounters();
412  accessor.preRead(TransferType::read);
413  accessor.readTransfer();
414  BOOST_CHECK_EQUAL(accessor._postRead_counter, 0);
415  accessor.postRead(TransferType::read, false);
416  BOOST_CHECK_EQUAL(accessor._postRead_counter, 1);
417  BOOST_CHECK(accessor._transferType_post == TransferType::read);
418  BOOST_CHECK(accessor._updateDataBuffer == false);
419 
420  accessor.resetCounters();
421  accessor.preRead(TransferType::readNonBlocking);
422  accessor.readTransferNonBlocking();
423  BOOST_CHECK_EQUAL(accessor._postRead_counter, 0);
424  accessor.postRead(TransferType::readNonBlocking, true);
425  BOOST_CHECK_EQUAL(accessor._postRead_counter, 1);
426  BOOST_CHECK(accessor._transferType_post == TransferType::readNonBlocking);
427  BOOST_CHECK(accessor._updateDataBuffer == true);
428 
429  accessor.resetCounters();
430  accessor.preRead(TransferType::readNonBlocking);
431  accessor.readTransferNonBlocking();
432  BOOST_CHECK_EQUAL(accessor._postRead_counter, 0);
433  accessor.postRead(TransferType::readNonBlocking, false);
434  BOOST_CHECK_EQUAL(accessor._postRead_counter, 1);
435  BOOST_CHECK(accessor._transferType_post == TransferType::readNonBlocking);
436  BOOST_CHECK(accessor._updateDataBuffer == false);
437 }
438 
439 /**********************************************************************************************************************/
440 
447 
448  accessor.resetCounters();
449  VersionNumber v1{};
450  accessor.preWrite(TransferType::write, v1);
451  accessor.writeTransfer(v1);
452  BOOST_CHECK(accessor.getVersionNumber() == VersionNumber(nullptr));
453  accessor.postWrite(TransferType::write, v1);
454  BOOST_CHECK(accessor.getVersionNumber() == v1);
455 }
456 
457 /**********************************************************************************************************************/
458 
463 BOOST_AUTO_TEST_CASE(test_B_5_1) {
464  {
466 
467  // read()
468  accessor.resetCounters();
469  accessor._throwLogicErr = true;
470  BOOST_CHECK_THROW(accessor.read(), ChimeraTK::logic_error); // (no test intended, just catch)
471  BOOST_CHECK_EQUAL(accessor._preRead_counter, 1);
472  BOOST_CHECK_EQUAL(accessor._postRead_counter, 1);
473 
474  accessor.resetCounters();
475  accessor._throwRuntimeErrInPre = true;
476  BOOST_CHECK_THROW(accessor.read(), ChimeraTK::runtime_error); // (no test intended, just catch)
477  BOOST_CHECK_EQUAL(accessor._preRead_counter, 1);
478  BOOST_CHECK_EQUAL(accessor._postRead_counter, 1);
479 
480  accessor.resetCounters();
481  accessor._throwRuntimeErrInTransfer = true;
482  BOOST_CHECK_THROW(accessor.read(), ChimeraTK::runtime_error); // (no test intended, just catch)
483  BOOST_CHECK_EQUAL(accessor._preRead_counter, 1);
484  BOOST_CHECK_EQUAL(accessor._postRead_counter, 1);
485 
486  // readNonBlocking() (there is a slightly different code path in the implementation despite identical behaviour)
487  accessor.resetCounters();
488  accessor._throwLogicErr = true;
489  BOOST_CHECK_THROW(accessor.readNonBlocking(), ChimeraTK::logic_error); // (no test intended, just catch)
490  BOOST_CHECK_EQUAL(accessor._preRead_counter, 1);
491  BOOST_CHECK_EQUAL(accessor._postRead_counter, 1);
492 
493  accessor.resetCounters();
494  accessor._throwRuntimeErrInPre = true;
495  BOOST_CHECK_THROW(accessor.readNonBlocking(), ChimeraTK::runtime_error); // (no test intended, just catch)
496  BOOST_CHECK_EQUAL(accessor._preRead_counter, 1);
497  BOOST_CHECK_EQUAL(accessor._postRead_counter, 1);
498 
499  accessor.resetCounters();
500  accessor._throwRuntimeErrInTransfer = true;
501  BOOST_CHECK_THROW(accessor.readNonBlocking(), ChimeraTK::runtime_error); // (no test intended, just catch)
502  BOOST_CHECK_EQUAL(accessor._preRead_counter, 1);
503  BOOST_CHECK_EQUAL(accessor._postRead_counter, 1);
504 
505  // write()
506  accessor.resetCounters();
507  accessor._throwLogicErr = true;
508  BOOST_CHECK_THROW(accessor.write(), ChimeraTK::logic_error); // (no test intended, just catch)
509  BOOST_CHECK_EQUAL(accessor._preWrite_counter, 1);
510  BOOST_CHECK_EQUAL(accessor._postWrite_counter, 1);
511 
512  accessor.resetCounters();
513  accessor._throwRuntimeErrInPre = true;
514  BOOST_CHECK_THROW(accessor.write(), ChimeraTK::runtime_error); // (no test intended, just catch)
515  BOOST_CHECK_EQUAL(accessor._preWrite_counter, 1);
516  BOOST_CHECK_EQUAL(accessor._postWrite_counter, 1);
517 
518  accessor.resetCounters();
519  accessor._throwRuntimeErrInTransfer = true;
520  BOOST_CHECK_THROW(accessor.write(), ChimeraTK::runtime_error); // (no test intended, just catch)
521  BOOST_CHECK_EQUAL(accessor._preWrite_counter, 1);
522  BOOST_CHECK_EQUAL(accessor._postWrite_counter, 1);
523 
524  // writeDestructively()
525  accessor.resetCounters();
526  accessor._throwLogicErr = true;
527  BOOST_CHECK_THROW(accessor.writeDestructively(), ChimeraTK::logic_error); // (no test intended, just catch)
528  BOOST_CHECK_EQUAL(accessor._preWrite_counter, 1);
529  BOOST_CHECK_EQUAL(accessor._postWrite_counter, 1);
530 
531  accessor.resetCounters();
532  accessor._throwRuntimeErrInPre = true;
533  BOOST_CHECK_THROW(accessor.writeDestructively(), ChimeraTK::runtime_error); // (no test intended, just catch)
534  BOOST_CHECK_EQUAL(accessor._preWrite_counter, 1);
535  BOOST_CHECK_EQUAL(accessor._postWrite_counter, 1);
536 
537  accessor.resetCounters();
538  accessor._throwRuntimeErrInTransfer = true;
539  BOOST_CHECK_THROW(accessor.writeDestructively(), ChimeraTK::runtime_error); // (no test intended, just catch)
540  BOOST_CHECK_EQUAL(accessor._preWrite_counter, 1);
541  BOOST_CHECK_EQUAL(accessor._postWrite_counter, 1);
542  }
543 
544  {
545  TransferElementTestAccessor<int32_t> accessor({AccessMode::wait_for_new_data});
546 
547  // read()
548  accessor.resetCounters();
549  accessor._throwLogicErr = true;
550  BOOST_CHECK_THROW(accessor.read(), ChimeraTK::logic_error); // (no test intended, just catch)
551  BOOST_CHECK_EQUAL(accessor._preRead_counter, 1);
552  BOOST_CHECK_EQUAL(accessor._postRead_counter, 1);
553 
554  accessor.resetCounters();
555  accessor._throwRuntimeErrInPre = true;
556  BOOST_CHECK_THROW(accessor.read(), ChimeraTK::runtime_error); // (no test intended, just catch)
557  BOOST_CHECK_EQUAL(accessor._preRead_counter, 1);
558  BOOST_CHECK_EQUAL(accessor._postRead_counter, 1);
559 
560  accessor.resetCounters();
561  accessor.putRuntimeErrorOnQueue();
562  BOOST_CHECK_THROW(accessor.read(), ChimeraTK::runtime_error); // (no test intended, just catch)
563  BOOST_CHECK_EQUAL(accessor._preRead_counter, 1);
564  BOOST_CHECK_EQUAL(accessor._postRead_counter, 1);
565 
566  // readNonBlocking() (there is a slightly different code path in the implementation despite identical behaviour)
567  accessor.resetCounters();
568  accessor._throwLogicErr = true;
569  BOOST_CHECK_THROW(accessor.readNonBlocking(), ChimeraTK::logic_error); // (no test intended, just catch)
570  BOOST_CHECK_EQUAL(accessor._preRead_counter, 1);
571  BOOST_CHECK_EQUAL(accessor._postRead_counter, 1);
572 
573  accessor.resetCounters();
574  accessor._throwRuntimeErrInPre = true;
575  BOOST_CHECK_THROW(accessor.readNonBlocking(), ChimeraTK::runtime_error); // (no test intended, just catch)
576  BOOST_CHECK_EQUAL(accessor._preRead_counter, 1);
577  BOOST_CHECK_EQUAL(accessor._postRead_counter, 1);
578 
579  accessor.resetCounters();
580  accessor.putRuntimeErrorOnQueue();
581  BOOST_CHECK_THROW(accessor.readNonBlocking(), ChimeraTK::runtime_error); // (no test intended, just catch)
582  BOOST_CHECK_EQUAL(accessor._preRead_counter, 1);
583  BOOST_CHECK_EQUAL(accessor._postRead_counter, 1);
584  }
585 }
586 
587 /**********************************************************************************************************************/
588 
593 BOOST_AUTO_TEST_CASE(test_B_5_2) {
595 
596  // read()
597  accessor.resetCounters();
598  accessor.preRead(TransferType::read);
599  accessor.preRead(TransferType::read);
600  accessor.preRead(TransferType::read);
601  accessor.readTransfer();
602  accessor.postRead(TransferType::read, true);
603  accessor.postRead(TransferType::read, true);
604  accessor.postRead(TransferType::read, true);
605  BOOST_CHECK_EQUAL(accessor._preRead_counter, 1);
606  BOOST_CHECK_EQUAL(accessor._postRead_counter, 1);
607 
608  // write()
609  accessor.resetCounters();
610  VersionNumber v{};
611  accessor.preWrite(TransferType::write, v);
612  accessor.preWrite(TransferType::write, v);
613  accessor.preWrite(TransferType::write, v);
614  accessor.writeTransfer(v);
615  accessor.postWrite(TransferType::write, v);
616  accessor.postWrite(TransferType::write, v);
617  accessor.postWrite(TransferType::write, v);
618  BOOST_CHECK_EQUAL(accessor._preWrite_counter, 1);
619  BOOST_CHECK_EQUAL(accessor._postWrite_counter, 1);
620 
621  // no need to test all read and write types, since the mechanism does not depend on the type.
622 }
623 
624 /**********************************************************************************************************************/
625 
630 BOOST_AUTO_TEST_CASE(test_B_6_1) {
631  {
633 
634  // read()
635  accessor.resetCounters();
636  accessor._throwLogicErr = true;
637  BOOST_CHECK_THROW(accessor.read(), ChimeraTK::logic_error); // (no test intended, just catch)
638  BOOST_CHECK_EQUAL(accessor._readTransfer_counter, 0);
639 
640  accessor.resetCounters();
641  accessor._throwRuntimeErrInPre = true;
642  BOOST_CHECK_THROW(accessor.read(), ChimeraTK::runtime_error); // (no test intended, just catch)
643  BOOST_CHECK_EQUAL(accessor._readTransfer_counter, 0);
644 
645  // readNonBlocking()
646  accessor.resetCounters();
647  accessor._throwLogicErr = true;
648  BOOST_CHECK_THROW(accessor.readNonBlocking(), ChimeraTK::logic_error); // (no test intended, just catch)
649  BOOST_CHECK_EQUAL(accessor._readTransfer_counter, 0);
650 
651  accessor.resetCounters();
652  accessor._throwRuntimeErrInPre = true;
653  BOOST_CHECK_THROW(accessor.readNonBlocking(), ChimeraTK::runtime_error); // (no test intended, just catch)
654  BOOST_CHECK_EQUAL(accessor._readTransfer_counter, 0);
655 
656  // write()
657  accessor.resetCounters();
658  accessor._throwLogicErr = true;
659  BOOST_CHECK_THROW(accessor.write(), ChimeraTK::logic_error); // (no test intended, just catch)
660  BOOST_CHECK_EQUAL(accessor._writeTransfer_counter, 0);
661 
662  accessor.resetCounters();
663  accessor._throwRuntimeErrInPre = true;
664  BOOST_CHECK_THROW(accessor.write(), ChimeraTK::runtime_error); // (no test intended, just catch)
665  BOOST_CHECK_EQUAL(accessor._writeTransfer_counter, 0);
666 
667  // writeDestructively()
668  accessor.resetCounters();
669  accessor._throwLogicErr = true;
670  BOOST_CHECK_THROW(accessor.writeDestructively(), ChimeraTK::logic_error); // (no test intended, just catch)
671  BOOST_CHECK_EQUAL(accessor._writeTransferDestructively_counter, 0);
672 
673  accessor.resetCounters();
674  accessor._throwRuntimeErrInPre = true;
675  BOOST_CHECK_THROW(accessor.writeDestructively(), ChimeraTK::runtime_error); // (no test intended, just catch)
676  BOOST_CHECK_EQUAL(accessor._writeTransferDestructively_counter, 0);
677  }
678  {
679  TransferElementTestAccessor<int32_t> accessor({AccessMode::wait_for_new_data});
680 
681  // Place one element into _readQueue, which needs to stay there. If it is removed from the queue, a transfer
682  // function has been executed.
683  accessor.push();
684  assert(accessor._readQueue.read_available() == 1);
685 
686  // read()
687  accessor.resetCounters();
688  accessor._throwLogicErr = true;
689  BOOST_CHECK_THROW(accessor.read(), ChimeraTK::logic_error); // (no test intended, just catch)
690  BOOST_CHECK_EQUAL(accessor._readQueue.read_available(), 1);
691 
692  accessor.resetCounters();
693  accessor._throwRuntimeErrInPre = true;
694  BOOST_CHECK_THROW(accessor.read(), ChimeraTK::runtime_error); // (no test intended, just catch)
695  BOOST_CHECK_EQUAL(accessor._readQueue.read_available(), 1);
696 
697  // readNonBlocking()
698  accessor.resetCounters();
699  accessor._throwLogicErr = true;
700  BOOST_CHECK_THROW(accessor.readNonBlocking(), ChimeraTK::logic_error); // (no test intended, just catch)
701  BOOST_CHECK_EQUAL(accessor._readQueue.read_available(), 1);
702 
703  accessor.resetCounters();
704  accessor._throwRuntimeErrInPre = true;
705  BOOST_CHECK_THROW(accessor.readNonBlocking(), ChimeraTK::runtime_error); // (no test intended, just catch)
706  BOOST_CHECK_EQUAL(accessor._readQueue.read_available(), 1);
707  }
708 }
709 
710 /**********************************************************************************************************************/
711 
716 BOOST_AUTO_TEST_CASE(test_B_6_2) {
718  std::exception_ptr myException;
719  VersionNumber v{nullptr};
720 
721  // Simply check that preXxx()/xxxTransferYyy() are throwing. Since previous tests have shown that the stages are
722  // correctly called even with exceptions, we can then conclude that the code calling preXxx()/xxxTransferYyy() is
723  // catching the exception to delay it.
724 
725  // Note, this test uses synchronous read operations only, since asynchronous read operations are anyway executed in
726  // the outermost decorator. This is ensured already by the API, so nothing can be tested there.
727 
728  // The test acts like a decorator, the "accessor" is its target.
729 
730  // test preRead
731  // ------------
732  accessor.resetCounters();
733  accessor._throwRuntimeErrInPre = true;
734  BOOST_CHECK_THROW(accessor.preRead(TransferType::read), ChimeraTK::runtime_error);
735  accessor.postRead(TransferType::read, false); // just complete the sequence as required by the spec
736 
737  // test preWrite
738  // ------------
739  accessor.resetCounters();
740  accessor._throwRuntimeErrInPre = true;
741  BOOST_CHECK_THROW(accessor.preWrite(TransferType::write, {}), ChimeraTK::runtime_error);
742  accessor.postWrite(TransferType::write, {}); // just complete the sequence as required by the spec
743 
744  // test readTransfer (sync)
745  // ------------------------
746  accessor.resetCounters();
747  accessor._throwRuntimeErrInTransfer = true; // target shall throw in the transfer
748 
749  // this is like doPreRead of the decorator
750  accessor.preRead(TransferType::read);
751 
752  // this is like doReadTransferSynchronously of the decorator, including the exception handling normally implemented
753  // in the TransferElement base class
754  myException = std::exception_ptr{nullptr};
755  try {
756  accessor.readTransfer();
757  BOOST_ERROR("readTransfer() must throw a ChimeraTK::runtime_error");
758  }
759  catch(ChimeraTK::runtime_error&) {
760  myException = std::current_exception();
761  }
762 
763  // this is like doPostRead of the decorator (we are cheating here a bit and discard the exception...)
764  accessor.postRead(TransferType::read, false);
765 
766  // test readTransferNonBlocking (sync) -> not sure if this is needed, decorators won't delegate to this?
767  // -----------------------------------
768  accessor.resetCounters();
769  accessor._throwRuntimeErrInTransfer = true; // target shall throw in the transfer
770 
771  // this is like doPreRead of the decorator
772  accessor.preRead(TransferType::readNonBlocking);
773 
774  // this is like doReadTransferSynchronously of the decorator, including the exception handling normally implemented
775  // in the TransferElement base class
776  myException = std::exception_ptr{nullptr};
777  try {
778  accessor.readTransferNonBlocking();
779  BOOST_ERROR("readTransferNonBlocking() must throw a ChimeraTK::runtime_error");
780  }
781  catch(ChimeraTK::runtime_error&) {
782  myException = std::current_exception();
783  }
784 
785  // this is like doPostRead of the decorator (cheating again...)
786  accessor.postRead(TransferType::readNonBlocking, false);
787 
788  // test writeTransfer
789  // ------------------
790  accessor.resetCounters();
791  accessor._throwRuntimeErrInTransfer = true;
792  v = {};
793 
794  // this is like doPreWrite of the decorator
795  accessor.preWrite(TransferType::write, v);
796 
797  // this is like doWriteTransfer of the decorator
798  try {
799  accessor.writeTransfer(v);
800  BOOST_ERROR("writeTransfer() must throw a ChimeraTK::runtime_error");
801  }
802  catch(ChimeraTK::runtime_error&) {
803  myException = std::current_exception();
804  }
805 
806  // this is like doPostWrite of the decorator (cheating again...)
807  accessor.postWrite(TransferType::write, v);
808 
809  // test writeTransferDestructively
810  // -------------------------------
811  accessor.resetCounters();
812  accessor._throwRuntimeErrInTransfer = true;
813  v = {};
814 
815  // this is like doPreWrite of the decorator
816  accessor.preWrite(TransferType::writeDestructively, v);
817 
818  // this is like doWriteTransferDestructively of the decorator
819  try {
820  accessor.writeTransferDestructively(v);
821  BOOST_ERROR("writeTransferDestructively() must throw a ChimeraTK::runtime_error");
822  }
823  catch(ChimeraTK::runtime_error&) {
824  myException = std::current_exception();
825  }
826 
827  // this is like doPostWrite of the decorator (cheating again...)
828  accessor.postWrite(TransferType::writeDestructively, v);
829 }
830 
831 /**********************************************************************************************************************/
832 
837 BOOST_AUTO_TEST_CASE(test_B_7_2) {
838  {
840  bool ret;
841  VersionNumber v{nullptr};
842 
843  accessor.resetCounters();
844  v = {};
845  accessor._previousDataLost = false;
846  accessor.preWrite(TransferType::write, v);
847  ret = accessor.writeTransfer(v);
848  BOOST_CHECK(ret == false);
849  accessor.postWrite(TransferType::write, v);
850 
851  accessor.resetCounters();
852  v = {};
853  accessor._previousDataLost = true;
854  accessor.preWrite(TransferType::write, v);
855  ret = accessor.writeTransfer(v);
856  BOOST_CHECK(ret == true);
857  accessor.postWrite(TransferType::write, v);
858 
859  accessor.resetCounters();
860  v = {};
861  accessor._previousDataLost = false;
862  accessor.preWrite(TransferType::writeDestructively, v);
863  ret = accessor.writeTransferDestructively(v);
864  BOOST_CHECK(ret == false);
865  accessor.postWrite(TransferType::writeDestructively, v);
866 
867  accessor.resetCounters();
868  v = {};
869  accessor._previousDataLost = true;
870  accessor.preWrite(TransferType::writeDestructively, v);
871  ret = accessor.writeTransferDestructively(v);
872  BOOST_CHECK(ret == true);
873  accessor.postWrite(TransferType::writeDestructively, v);
874  }
875 }
876 
877 /**********************************************************************************************************************/
878 
883 BOOST_AUTO_TEST_CASE(test_B_7_3) {
884  {
886 
887  accessor.resetCounters();
888  accessor.read();
889  BOOST_CHECK(accessor._updateDataBuffer == true);
890 
891  accessor.resetCounters();
892  accessor.readNonBlocking();
893  BOOST_CHECK(accessor._updateDataBuffer == true); // (cf. B.4.2.2 second sub-point)
894  }
895  {
896  TransferElementTestAccessor<int32_t> accessor({AccessMode::wait_for_new_data});
897 
898  accessor.resetCounters();
899  accessor.push();
900  accessor.read();
901  BOOST_CHECK(accessor._updateDataBuffer == true);
902 
903  accessor.resetCounters();
904  accessor.push();
905  accessor.readNonBlocking();
906  BOOST_CHECK(accessor._updateDataBuffer == true);
907 
908  accessor.resetCounters();
909  accessor.readNonBlocking();
910  BOOST_CHECK(accessor._updateDataBuffer == false);
911  }
912 }
913 
914 /**********************************************************************************************************************/
915 
920 BOOST_AUTO_TEST_CASE(test_B_7_4) {
921  {
923 
924  // logic_error in preRead
925  accessor.resetCounters();
926  accessor._throwLogicErr = true;
927  BOOST_CHECK_THROW(accessor.read(), ChimeraTK::logic_error); // (no test intended, just catch)
928  BOOST_CHECK(accessor._updateDataBuffer == false);
929 
930  // runtime_error in preRead
931  accessor.resetCounters();
932  accessor._throwRuntimeErrInPre = true;
933  BOOST_CHECK_THROW(accessor.read(), ChimeraTK::runtime_error); // (no test intended, just catch)
934  BOOST_CHECK(accessor._updateDataBuffer == false);
935 
936  // runtime_error in readTransfer (sync)
937  accessor.resetCounters();
938  accessor._throwRuntimeErrInTransfer = true;
939  BOOST_CHECK_THROW(accessor.read(), ChimeraTK::runtime_error); // (no test intended, just catch)
940  BOOST_CHECK(accessor._updateDataBuffer == false);
941 
942  // runtime_error in readTransferNonBlocking (sync)
943  accessor.resetCounters();
944  accessor._throwRuntimeErrInTransfer = true;
945  BOOST_CHECK_THROW(accessor.readNonBlocking(), ChimeraTK::runtime_error); // (no test intended, just catch)
946  BOOST_CHECK(accessor._updateDataBuffer == false);
947  }
948  {
949  TransferElementTestAccessor<int32_t> accessor({AccessMode::wait_for_new_data});
950 
951  // runtime_error in readTransfer (async)
952  accessor.resetCounters();
953  accessor.putRuntimeErrorOnQueue();
954  BOOST_CHECK_THROW(accessor.read(), ChimeraTK::runtime_error); // (no test intended, just catch)
955  BOOST_CHECK(accessor._updateDataBuffer == false);
956 
957  // runtime_error in readTransferNonBlocking (async)
958  accessor.resetCounters();
959  accessor.putRuntimeErrorOnQueue();
960  BOOST_CHECK_THROW(accessor.readNonBlocking(), ChimeraTK::runtime_error); // (no test intended, just catch)
961  BOOST_CHECK(accessor._updateDataBuffer == false);
962  }
963 }
964 
965 /**********************************************************************************************************************/
966 
975  TransferElementTestAccessor<int32_t> accessor({AccessMode::wait_for_new_data});
976 
977  // check with readTransferNonBlocking()
978  accessor.resetCounters();
979  accessor.push();
980  accessor.preRead(TransferType::readNonBlocking);
981  BOOST_CHECK_EQUAL(accessor._readQueue.read_available(), 1);
982  accessor.readTransferNonBlocking();
983  BOOST_CHECK_EQUAL(accessor._readQueue.read_available(), 0);
984  accessor.postRead(TransferType::readNonBlocking, true);
985 
986  // check with readTransfer()
987  accessor.resetCounters();
988  accessor.push();
989  accessor.preRead(TransferType::read);
990  BOOST_CHECK_EQUAL(accessor._readQueue.read_available(), 1);
991  accessor.readTransfer();
992  BOOST_CHECK_EQUAL(accessor._readQueue.read_available(), 0);
993  accessor.postRead(TransferType::read, true);
994 }
995 
996 /**********************************************************************************************************************/
997 
1003  TransferElementTestAccessor<int32_t> accessor({AccessMode::wait_for_new_data});
1004  bool ret;
1005 
1006  // check with readNonBlocking()
1007  accessor.resetCounters();
1008  accessor.putDiscardValueOnQueue();
1009  ret = accessor.readNonBlocking();
1010  BOOST_CHECK(ret == false); // B.8.2.2
1011  BOOST_CHECK(accessor._postRead_counter == 1); // B.8.2.2
1012 
1013  // check with blocking read()
1014  accessor.resetCounters();
1015  accessor.putDiscardValueOnQueue();
1016  std::atomic<bool> readFinished{false};
1017  std::thread t([&] { // laungh read() in another thread, since it will block
1018  accessor.read();
1019  readFinished = true;
1020  });
1021  usleep(1000000); // 1 second
1022  BOOST_CHECK(readFinished == false); // B.8.2.2
1023  accessor.push();
1024  t.join();
1025 }
1026 
1027 /**********************************************************************************************************************/
1028 
1034  TransferElementTestAccessor<int32_t> accessor({AccessMode::wait_for_new_data});
1035 
1036  // use a special exception to make sure it works independent of the type of exception
1037  class MyException {};
1038 
1039  // check with readTransferNonBlocking()
1040  accessor.resetCounters();
1041  try {
1042  throw MyException();
1043  }
1044  catch(...) {
1045  accessor._readQueue.push_overwrite_exception(std::current_exception());
1046  }
1047  accessor.preRead(TransferType::readNonBlocking);
1048  BOOST_CHECK_EQUAL(accessor._readQueue.read_available(), 1);
1049  BOOST_CHECK_THROW(accessor.readTransferNonBlocking(), MyException);
1050  BOOST_CHECK_EQUAL(accessor._readQueue.read_available(), 0);
1051  accessor.postRead(TransferType::readNonBlocking, true); // small cheat: discard the exception
1052 
1053  // check with readTransfer()
1054  accessor.resetCounters();
1055  try {
1056  throw MyException();
1057  }
1058  catch(...) {
1059  accessor._readQueue.push_overwrite_exception(std::current_exception());
1060  }
1061  accessor.preRead(TransferType::read);
1062  BOOST_CHECK_EQUAL(accessor._readQueue.read_available(), 1);
1063  BOOST_CHECK_THROW(accessor.readTransferNonBlocking(), MyException);
1064  BOOST_CHECK_EQUAL(accessor._readQueue.read_available(), 0);
1065  accessor.postRead(TransferType::read, true); // small cheat: discard the exception
1066 }
1067 
1068 /**********************************************************************************************************************/
1069 
1075  TransferElementTestAccessor<int32_t> accessor({AccessMode::wait_for_new_data});
1076  accessor.resetCounters();
1077  accessor.interrupt();
1078  BOOST_CHECK_THROW(accessor._readQueue.pop(), boost::thread_interrupted);
1079 }
1080 
1081 /**********************************************************************************************************************/
1082 
1088  TransferElementTestAccessor<int32_t> accessor({AccessMode::wait_for_new_data});
1089 
1090  accessor.resetCounters();
1091  accessor.interrupt();
1092  BOOST_CHECK_THROW(accessor.read(), boost::thread_interrupted);
1093 
1094  accessor.resetCounters();
1095  accessor.interrupt();
1096  BOOST_CHECK_THROW(accessor.readNonBlocking(), boost::thread_interrupted);
1097 
1098  accessor.resetCounters();
1099  accessor.push();
1100  accessor.push();
1101  accessor.interrupt();
1102  BOOST_CHECK_NO_THROW(accessor.read());
1103  BOOST_CHECK_NO_THROW(accessor.read());
1104  BOOST_CHECK_THROW(accessor.read(), boost::thread_interrupted);
1105 
1106  accessor.resetCounters();
1107  accessor.push();
1108  accessor.push();
1109  accessor.interrupt();
1110  BOOST_CHECK_NO_THROW(accessor.readNonBlocking());
1111  BOOST_CHECK_NO_THROW(accessor.readNonBlocking());
1112  BOOST_CHECK_THROW(accessor.readNonBlocking(), boost::thread_interrupted);
1113 
1114  accessor.resetCounters();
1115  accessor.push();
1116  accessor.push();
1117  accessor.interrupt();
1118  BOOST_CHECK_THROW(accessor.readLatest(), boost::thread_interrupted);
1119  BOOST_CHECK_EQUAL(accessor._readQueue.read_available(), 0);
1120 }
1121 
1122 /**********************************************************************************************************************/
1123 
1128 BOOST_AUTO_TEST_CASE(test_B_8_6_3) {
1129  TransferElementTestAccessor<int32_t> accessor({AccessMode::wait_for_new_data});
1130 
1131  accessor.resetCounters();
1132  accessor.interrupt();
1133  BOOST_CHECK_THROW(accessor.read(), boost::thread_interrupted); // (no test intended, just catch)
1134  BOOST_CHECK_EQUAL(accessor._preRead_counter, 1);
1135  BOOST_CHECK_EQUAL(accessor._postRead_counter, 1);
1136 
1137  accessor.resetCounters();
1138  accessor.interrupt();
1139  BOOST_CHECK_THROW(accessor.readNonBlocking(), boost::thread_interrupted); // (no test intended, just catch)
1140  BOOST_CHECK_EQUAL(accessor._preRead_counter, 1);
1141  BOOST_CHECK_EQUAL(accessor._postRead_counter, 1);
1142 }
1143 
1144 /**********************************************************************************************************************/
1145 
1150 BOOST_AUTO_TEST_CASE(test_B_8_6_4) {
1151  TransferElementTestAccessor<int32_t> accessor({AccessMode::wait_for_new_data});
1152 
1153  accessor.resetCounters();
1154  accessor.interrupt();
1155  BOOST_CHECK_THROW(accessor.read(), boost::thread_interrupted); // (no test intended, just catch)
1156 
1157  accessor.resetCounters();
1158  accessor.push();
1159  BOOST_CHECK_NO_THROW(accessor.read());
1160 
1161  accessor.resetCounters();
1162  accessor.interrupt();
1163  BOOST_CHECK_THROW(accessor.readNonBlocking(), boost::thread_interrupted); // (no test intended, just catch)
1164 
1165  accessor.resetCounters();
1166  accessor.push();
1167  BOOST_CHECK_NO_THROW(accessor.readNonBlocking());
1168 }
1169 
1170 /**********************************************************************************************************************/
1171 
1176 BOOST_AUTO_TEST_CASE(test_B_11_3) {
1178  TransferElementTestAccessor<int32_t> asyncAccessor({AccessMode::wait_for_new_data});
1179  VersionNumber v{nullptr};
1180 
1181  accessor.resetCounters();
1182  v = {};
1183  BOOST_CHECK(accessor.getVersionNumber() != v);
1184  accessor.write(v);
1185  BOOST_CHECK(accessor.getVersionNumber() == v);
1186 
1187  accessor.resetCounters();
1188  v = {};
1189  accessor._setPostReadVersion = v;
1190  accessor.read();
1191  BOOST_CHECK(accessor.getVersionNumber() == v);
1192 
1193  // Test also with async accessor. As of now this is not a different code path, but this test might help to remember
1194  // to modify this test if in future the implementation-specific data transport queue is changed into a fixed
1195  // typed _readQueue in the base classes (which then will also transport the VersionNumber).
1196  asyncAccessor.resetCounters();
1197  v = {};
1198  asyncAccessor.push();
1199  asyncAccessor._setPostReadVersion = v;
1200  asyncAccessor.read();
1201  BOOST_CHECK(asyncAccessor.getVersionNumber() == v);
1202 }
1203 
1204 /**********************************************************************************************************************/
1205 
1212 
1213  VersionNumber v1;
1214  VersionNumber v2;
1215  accessor.resetCounters();
1216  accessor.write(v2);
1217  accessor.resetCounters();
1218  BOOST_CHECK_THROW(accessor.write(v1), ChimeraTK::logic_error);
1219 }
1220 
1221 /**********************************************************************************************************************/
1222 
1229  VersionNumber v{nullptr};
1230 
1231  v = {};
1232  accessor.resetCounters();
1233  accessor.write(v);
1234  BOOST_CHECK(accessor._preWrite_version == v);
1235  BOOST_CHECK(accessor._writeTransfer_version == v);
1236  BOOST_CHECK(accessor._postWrite_version == v);
1237 
1238  v = {};
1239  accessor.resetCounters();
1240  accessor.writeDestructively(v);
1241  BOOST_CHECK(accessor._preWrite_version == v);
1242  BOOST_CHECK(accessor._writeTransfer_version == v);
1243  BOOST_CHECK(accessor._postWrite_version == v);
1244 }
1245 
1246 /**********************************************************************************************************************/
1247 
1253 BOOST_AUTO_TEST_CASE(test_B_11_5) {
1255  VersionNumber v{nullptr};
1256 
1257  VersionNumber v1;
1258  accessor.resetCounters();
1259  accessor.write(v1);
1260 
1261  // test with logic error
1262  accessor.resetCounters();
1263  v = {};
1264  accessor._throwLogicErr = true;
1265  BOOST_CHECK_THROW(accessor.write(v), ChimeraTK::logic_error); // (no test intended, just catch)
1266  BOOST_CHECK(accessor.getVersionNumber() == v1);
1267 
1268  // test with runtime error in preWrite
1269  accessor.resetCounters();
1270  v = {};
1271  accessor._throwRuntimeErrInPre = true;
1272  BOOST_CHECK_THROW(accessor.write(v), ChimeraTK::runtime_error); // (no test intended, just catch)
1273  BOOST_CHECK(accessor.getVersionNumber() == v1);
1274 
1275  // test with runtime error in doWriteTransfer
1276  accessor.resetCounters();
1277  v = {};
1278  accessor._throwRuntimeErrInTransfer = true;
1279  BOOST_CHECK_THROW(accessor.write(v), ChimeraTK::runtime_error); // (no test intended, just catch)
1280  BOOST_CHECK(accessor.getVersionNumber() == v1);
1281 
1282  // test with runtime error in doWriteTransferDestructively
1283  accessor.resetCounters();
1284  v = {};
1285  accessor._throwRuntimeErrInTransfer = true;
1286  BOOST_CHECK_THROW(accessor.writeDestructively(v), ChimeraTK::runtime_error); // (no test intended, just catch)
1287  BOOST_CHECK(accessor.getVersionNumber() == v1);
1288 }
1289 
1290 /**********************************************************************************************************************/
1291 
1299 BOOST_AUTO_TEST_CASE(test_B_11_6) {
1301  BOOST_CHECK(accessor.getVersionNumber() == VersionNumber{nullptr});
1302 }
1303 
1304 /**********************************************************************************************************************/
1305 
1310 BOOST_AUTO_TEST_CASE(test_B_15_2) {
1312 
1313  accessor._accessModeFlags = AccessModeFlags({});
1314  BOOST_CHECK(accessor.getAccessModeFlags() == AccessModeFlags({}));
1315 
1316  accessor._accessModeFlags = AccessModeFlags({AccessMode::wait_for_new_data});
1317  BOOST_CHECK(accessor.getAccessModeFlags() == AccessModeFlags({AccessMode::wait_for_new_data}));
1318 
1319  accessor._accessModeFlags = AccessModeFlags({AccessMode::raw});
1320  BOOST_CHECK(accessor.getAccessModeFlags() == AccessModeFlags({AccessMode::raw}));
1321 
1322  accessor._accessModeFlags = AccessModeFlags({AccessMode::wait_for_new_data, AccessMode::raw});
1323  BOOST_CHECK(accessor.getAccessModeFlags() == AccessModeFlags({AccessMode::wait_for_new_data, AccessMode::raw}));
1324 }
1325 
1326 /**********************************************************************************************************************/
1327 
1332 BOOST_AUTO_TEST_CASE(test_B_15_3) {
1333  {
1335  BOOST_CHECK(accessor._accessModeFlags == AccessModeFlags({}));
1336  }
1337  {
1338  TransferElementTestAccessor<int32_t> accessor({AccessMode::wait_for_new_data});
1339  BOOST_CHECK(accessor._accessModeFlags == AccessModeFlags({AccessMode::wait_for_new_data}));
1340  }
1341  {
1342  TransferElementTestAccessor<int32_t> accessor({AccessMode::raw});
1343  BOOST_CHECK(accessor._accessModeFlags == AccessModeFlags({AccessMode::raw}));
1344  }
1345  {
1346  TransferElementTestAccessor<int32_t> accessor({AccessMode::wait_for_new_data, AccessMode::raw});
1347  BOOST_CHECK(accessor._accessModeFlags == AccessModeFlags({AccessMode::wait_for_new_data, AccessMode::raw}));
1348  }
1349 }
1350 
1351 /**********************************************************************************************************************/
1352 
1357 BOOST_AUTO_TEST_CASE(test_B_15_3_1) {
1358  BOOST_CHECK(std::is_default_constructible<TransferElement>::value == false);
1359 }
1360 
1361 /**********************************************************************************************************************/
1362 
1367 BOOST_AUTO_TEST_CASE(test_B_16_1) {
1369  TransferElementTestAccessor<int32_t> asyncAccessor({AccessMode::wait_for_new_data});
1370 
1371  // test logic_error in preRead
1372  accessor.resetCounters();
1373  accessor._throwLogicErr = true;
1374  BOOST_CHECK_THROW(accessor.read(), ChimeraTK::logic_error); // (no test intended, just catch)
1375  BOOST_CHECK(accessor._seenActiveException == accessor._thrownException);
1376 
1377  // test runtime_error in preRead
1378  accessor.resetCounters();
1379  accessor._throwRuntimeErrInPre = true;
1380  BOOST_CHECK_THROW(accessor.read(), ChimeraTK::runtime_error); // (no test intended, just catch)
1381  BOOST_CHECK(accessor._seenActiveException == accessor._thrownException);
1382 
1383  // test runtime_error in readTransfer (sync)
1384  accessor.resetCounters();
1385  accessor._throwRuntimeErrInTransfer = true;
1386  BOOST_CHECK_THROW(accessor.read(), ChimeraTK::runtime_error); // (no test intended, just catch)
1387  BOOST_CHECK(accessor._seenActiveException == accessor._thrownException);
1388 
1389  // test runtime_error in readTransferNonBlocking (sync)
1390  accessor.resetCounters();
1391  accessor._throwRuntimeErrInTransfer = true;
1392  BOOST_CHECK_THROW(accessor.readNonBlocking(), ChimeraTK::runtime_error); // (no test intended, just catch)
1393  BOOST_CHECK(accessor._seenActiveException == accessor._thrownException);
1394 
1395  // test runtime_error in readTransfer (async)
1396  asyncAccessor.resetCounters();
1397  asyncAccessor.putRuntimeErrorOnQueue();
1398  BOOST_CHECK_THROW(asyncAccessor.read(), ChimeraTK::runtime_error); // (no test intended, just catch)
1399  BOOST_CHECK(asyncAccessor._seenActiveException == asyncAccessor._thrownException);
1400 
1401  // test runtime_error in readTransferNonBlocking (async)
1402  asyncAccessor.resetCounters();
1403  asyncAccessor.putRuntimeErrorOnQueue();
1404  BOOST_CHECK_THROW(asyncAccessor.readNonBlocking(), ChimeraTK::runtime_error); // (no test intended, just catch)
1405  BOOST_CHECK(asyncAccessor._seenActiveException == asyncAccessor._thrownException);
1406 
1407  // no test for bad_numeric_cast in postRead: not applicable, exception is not caught and rethrown, but directly thrown
1408 
1409  // test logic_error in preWrite
1410  accessor.resetCounters();
1411  accessor._throwLogicErr = true;
1412  BOOST_CHECK_THROW(accessor.write(), ChimeraTK::logic_error); // (no test intended, just catch)
1413  BOOST_CHECK(accessor._seenActiveException == accessor._thrownException);
1414 
1415  // test runtime_error in preWrite
1416  accessor.resetCounters();
1417  accessor._throwRuntimeErrInPre = true;
1418  BOOST_CHECK_THROW(accessor.write(), ChimeraTK::runtime_error); // (no test intended, just catch)
1419  BOOST_CHECK(accessor._seenActiveException == accessor._thrownException);
1420 
1421  // test runtime_error in writeTransfer
1422  accessor.resetCounters();
1423  accessor._throwRuntimeErrInTransfer = true;
1424  BOOST_CHECK_THROW(accessor.write(), ChimeraTK::runtime_error); // (no test intended, just catch)
1425  BOOST_CHECK(accessor._seenActiveException == accessor._thrownException);
1426 
1427  // test runtime_error in writeTransferDestructively
1428  accessor.resetCounters();
1429  accessor._throwRuntimeErrInTransfer = true;
1430  BOOST_CHECK_THROW(accessor.writeDestructively(), ChimeraTK::runtime_error); // (no test intended, just catch)
1431  BOOST_CHECK(accessor._seenActiveException == accessor._thrownException);
1432 }
1433 
1434 /**********************************************************************************************************************/
1435 
1440 BOOST_AUTO_TEST_CASE(test_B_16_2) {
1442 
1443  // Using a special exception class excludes any restriction to a specific exception type.
1444  class MySpecialException {};
1445 
1446  // test postRead
1447  accessor.preRead(TransferType::read);
1448  accessor.readTransfer();
1449 
1450  try {
1451  throw MySpecialException();
1452  }
1453  catch(...) {
1454  auto myException = std::current_exception();
1455  auto myException_copy = myException;
1456  accessor.setActiveException(myException);
1457  }
1458 
1459  BOOST_CHECK_EQUAL(accessor._postRead_counter, 0);
1460  BOOST_CHECK_THROW(accessor.postRead(TransferType::read, false), MySpecialException);
1461  BOOST_CHECK_EQUAL(accessor._postRead_counter, 1);
1462 
1463  // test postWrite
1464  VersionNumber v;
1465  accessor.preWrite(TransferType::write, v);
1466  accessor.writeTransfer(v);
1467 
1468  try {
1469  throw MySpecialException();
1470  }
1471  catch(...) {
1472  auto myException = std::current_exception();
1473  auto myException_copy = myException;
1474  accessor.setActiveException(myException);
1475  }
1476 
1477  BOOST_CHECK_EQUAL(accessor._postWrite_counter, 0);
1478  BOOST_CHECK_THROW(accessor.postWrite(TransferType::write, v), MySpecialException);
1479  BOOST_CHECK_EQUAL(accessor._postWrite_counter, 1);
1480 }
1481 
1482 /**********************************************************************************************************************/
1483 
1488 BOOST_AUTO_TEST_CASE(test_B_16_3) {
1490 
1491  // Using a special exception class excludes any restriction to a specific exception type.
1492  class MySpecialException {};
1493 
1494  try {
1495  throw MySpecialException();
1496  }
1497  catch(...) {
1498  auto myException = std::current_exception();
1499  auto myException_copy = myException;
1500  accessor.setActiveException(myException);
1501  BOOST_CHECK(myException == nullptr);
1502  BOOST_CHECK(accessor._activeException == myException_copy);
1503  }
1504 }
1505 
1506 /**********************************************************************************************************************/
ChimeraTK::TransferElementTestAccessor::push
bool push()
Definition: TransferElementTestAccessor.h:262
DeviceBackendImpl.h
BOOST_AUTO_TEST_CASE
BOOST_AUTO_TEST_CASE(B_3_1_2_4)
Test the return values of readNonBlocking()/readLatest() for synchronous reads.
Definition: testTransferElement.cpp:39
ChimeraTK::runtime_error
Exception thrown when a runtime error has occured.
Definition: Exception.h:18
NDRegisterAccessorDecorator.h
ChimeraTK::TransferElementTestAccessor::_accessModeFlags
AccessModeFlags _accessModeFlags
The access mode flags for this transfer element.
Definition: TransferElement.h:826
NDRegisterAccessor.h
ChimeraTK::TransferElementTestAccessor
Special accessor used to test the behaviour of the TransferElement base class and the TransferGroup.
Definition: TransferElementTestAccessor.h:11
ChimeraTK::VersionNumber
Class for generating and holding version numbers without exposing a numeric representation.
Definition: VersionNumber.h:23
TEST_TRANSFER_SEQUENCE
#define TEST_TRANSFER_SEQUENCE(transferElement, expectedType, expectTransferExecution)
Helper macro for test_B_4 to avoid code duplication.
Definition: testTransferElement.cpp:152
ChimeraTK::AccessModeFlags
Set of AccessMode flags with additional functionality for an easier handling.
Definition: AccessMode.h:48
ChimeraTK
Definition: DummyBackend.h:16
ChimeraTK::TransferElementTestAccessor::resetCounters
void resetCounters()
Definition: TransferElementTestAccessor.h:212
TransferElementTestAccessor.h
ChimeraTK::logic_error
Exception thrown when a logic error has occured.
Definition: Exception.h:51