ChimeraTK-DeviceAccess 03.25.00
Loading...
Searching...
No Matches
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>
22using namespace boost::unit_test_framework;
23
24#include "DeviceBackendImpl.h"
25#include "NDRegisterAccessor.h"
28
29#include <boost/make_shared.hpp>
30
31using 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
58BOOST_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
81BOOST_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
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
302BOOST_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
337BOOST_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
370BOOST_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
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
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
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
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
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 }
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 }
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 }
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 }
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
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
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
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
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
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
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
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
1301 BOOST_CHECK(accessor.getVersionNumber() == VersionNumber{nullptr});
1302}
1303
1304/**********************************************************************************************************************/
1305
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
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
1357BOOST_AUTO_TEST_CASE(test_B_15_3_1) {
1358 BOOST_CHECK(std::is_default_constructible<TransferElement>::value == false);
1359}
1360
1361/**********************************************************************************************************************/
1362
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
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
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/**********************************************************************************************************************/
Set of AccessMode flags with additional functionality for an easier handling.
Definition AccessMode.h:48
bool writeTransferDestructively(ChimeraTK::VersionNumber versionNumber)
Write the data to the device.
bool readNonBlocking()
Read the next value, if available in the input buffer.
void preRead(TransferType type)
Perform any pre-read tasks if necessary.
bool readLatest()
Read the latest value, discarding any other update since the last read if present.
bool writeTransfer(ChimeraTK::VersionNumber versionNumber)
Write the data to the device.
bool readTransferNonBlocking()
Read the data from the device but do not fill it into the user buffer of this TransferElement.
void readTransfer()
Read the data from the device but do not fill it into the user buffer of this TransferElement.
Special accessor used to test the behaviour of the TransferElement base class and the TransferGroup.
AccessModeFlags _accessModeFlags
The access mode flags for this transfer element.
Class for generating and holding version numbers without exposing a numeric representation.
Exception thrown when a logic error has occured.
Definition Exception.h:51
Exception thrown when a runtime error has occured.
Definition Exception.h:18
#define TEST_TRANSFER_SEQUENCE(transferElement, expectedType, expectTransferExecution)
Helper macro for test_B_4 to avoid code duplication.
BOOST_AUTO_TEST_CASE(B_3_1_2_4)
Test the return values of readNonBlocking()/readLatest() for synchronous reads.