RTC Toolkit 6.0.0-pre2
Loading...
Searching...
No Matches
repositoryIfTestSuite.hpp
Go to the documentation of this file.
1
12
13#ifndef RTCTK_COMPONENTFRAMEWORK_TEST_REPOSITORYIFTESTSUITE_HPP
14#define RTCTK_COMPONENTFRAMEWORK_TEST_REPOSITORYIFTESTSUITE_HPP
15
18
19#include <gmock/gmock.h>
20#include <gtest/gtest.h>
21
22#include <fmt/format.h>
23
24#include <exception>
25#include <future>
26#include <stdexcept>
27#include <type_traits>
28
29// ---------------- User defined types for testing type handling -----------------
30// The following forward declarations are used with specialisations of UserTypeHandler to allow
31// testing RepositoryIf methods such as CreateDataPoint, ReadDataPoint, WriteDataPoint, etc. that
32// will actually trigger exceptions when invoking certain UserTypeHandler methods.
33// To minimise boiler-plate code, some helper functions are implemented in these "type" classes that
34// are called within the UserTypeHandler specialisation. These methods serve no further purpose than
35// this and do not form part of a user defined type API.
37
39public:
41 explicit TestingUserTypeBase(std::string value) : m_value(std::move(value)) {
42 }
43 virtual RtcVectorUInt64 GetShape() const {
44 return {m_value.size()};
45 }
46
47 virtual gsl::span<char> MakeSpan() {
48 return gsl::span<char>{m_value.data(), m_value.size()};
49 };
50 virtual gsl::span<const char> MakeSpan() const {
51 return gsl::span<const char>{m_value.data(), m_value.size()};
52 };
53
54 virtual bool ResizeBuffer(const RtcVectorUInt64& shape) {
55 if (shape.size() == 1) {
56 m_value.resize(shape[0]);
57 } else {
58 m_value.resize(detail::GetNumOfElements(shape));
59 }
60 return true;
61 };
62
63 std::string m_value;
64};
65
67public:
69 RtcVectorUInt64 GetShape() const override {
70 throw std::runtime_error("GetShape");
71 }
72};
73
75public:
77 gsl::span<char> MakeSpan() override {
78 throw std::runtime_error("MakeSpan");
79 };
80 gsl::span<const char> MakeSpan() const override {
81 throw std::runtime_error("MakeSpan");
82 };
83};
84
86public:
88 bool ResizeBuffer(const RtcVectorUInt64& shape) override {
89 throw std::runtime_error("ResizeBuffer");
90 };
91};
92
93} // namespace rtctk::componentFramework::test
94
96// Register handlers for custom types that trigger exceptions for unit testing.
97template <>
100 using ElementType = char;
102 static const bool USES_TEMP_BUFFER = false;
103 using TempBufferType = void;
104
105 static RtcVectorUInt64 GetShape(const BufferType& buffer) {
106 return buffer.GetShape();
107 }
108
109 static gsl::span<ElementType> MakeSpan(BufferType& buffer) {
110 return buffer.MakeSpan();
111 }
112
113 static gsl::span<const ElementType> MakeSpan(const BufferType& buffer) {
114 return buffer.MakeSpan();
115 }
116
117 static bool ResizeBuffer(BufferType& buffer, const RtcVectorUInt64& shape) {
118 return buffer.ResizeBuffer(shape);
119 }
120};
121
122template <>
125 using ElementType = std::remove_cv_t<typename std::string::value_type>;
127 static const bool USES_TEMP_BUFFER = false;
128 using TempBufferType = void;
129
130 static RtcVectorUInt64 GetShape(const BufferType& buffer) {
131 return buffer.GetShape();
132 }
133
134 static gsl::span<ElementType> MakeSpan(BufferType& buffer) {
135 return buffer.MakeSpan();
136 }
137
138 static gsl::span<const ElementType> MakeSpan(const BufferType& buffer) {
139 return buffer.MakeSpan();
140 }
141
142 static bool ResizeBuffer(BufferType& buffer, const RtcVectorUInt64& shape) {
143 return buffer.ResizeBuffer(shape);
144 }
145};
146
147template <>
150 using ElementType = std::remove_cv_t<typename std::string::value_type>;
152 static const bool USES_TEMP_BUFFER = false;
153 using TempBufferType = void;
154
155 static RtcVectorUInt64 GetShape(const BufferType& buffer) {
156 return buffer.GetShape();
157 }
158
159 static gsl::span<ElementType> MakeSpan(BufferType& buffer) {
160 return buffer.MakeSpan();
161 }
162
163 static gsl::span<const ElementType> MakeSpan(const BufferType& buffer) {
164 return buffer.MakeSpan();
165 }
166
167 static bool ResizeBuffer(BufferType& buffer, const RtcVectorUInt64& shape) {
168 return buffer.ResizeBuffer(shape);
169 }
170};
171
172} // namespace rtctk::componentFramework::detail
173
175
176using testing::ContainerEq;
177using testing::IsEmpty;
178using testing::UnorderedElementsAreArray;
179
180static std::shared_ptr<RepositoryIf> MakeRepository();
181
182template <typename T>
183class RepositoryIfTestSuite : public testing::Test {
184public:
185 void SetUp() override {
186 repo = MakeRepository();
187 dp_paths.clear();
188 for (unsigned i = 0; i < 10; i++) {
189 std::string name = fmt::format("/test/datapoint_{:0>2}", i);
190 dp_paths.emplace_back(name);
191 }
192 }
193
194 void TearDown() override {
195 for (const auto& path : dp_paths) {
196 if (repo->DataPointExists(path)) {
197 repo->DeleteDataPoint(path);
198 }
199 }
200 dp_paths.clear();
201 }
202
204 if constexpr (std::is_same_v<T, std::byte>) {
205 return std::byte{43};
206 } else if constexpr (std::is_same_v<T, RtcBinary>) {
207 return {std::byte{42}, std::byte{43}};
208 } else if constexpr (std::is_same_v<T, RtcBool>) {
209 return false;
210 } else if constexpr (std::is_same_v<T, RtcString>) {
211 return "foo";
212 } else if constexpr (std::is_same_v<T, RtcMatrixBool>) {
213 return {1, 3, {false, true, false}};
214 } else if constexpr (std::is_same_v<T, RtcVectorBool>) {
215 return {false, false, false};
216 } else if constexpr (std::is_same_v<T, RtcMatrixString>) {
217 return {1, 2, {"foo", "bar"}};
218 } else if constexpr (std::is_same_v<T, RtcVectorString>) {
219 return {"goo", "gar"};
220 } else if constexpr (std::is_arithmetic_v<T>) {
221 return 42;
222 } else if constexpr (IS_MATRIX_BUFFER_TYPE<T>) {
223 return {1, 2, {42, 44}};
224 } else {
225 return {42, 43};
226 }
227 }
228
230 // Make sure the values and shapes are different for the test value returned by this method
231 // compared to those that are in MakeSomeTestValue.
232 if constexpr (std::is_same_v<T, std::byte>) {
233 return std::byte{43};
234 } else if constexpr (std::is_same_v<T, RtcBinary>) {
235 return {std::byte{43}, std::byte{44}, std::byte{45}};
236 } else if constexpr (std::is_same_v<T, RtcBool>) {
237 return true;
238 } else if constexpr (std::is_same_v<T, RtcString>) {
239 return "barfoo";
240 } else if constexpr (std::is_same_v<T, RtcMatrixBool>) {
241 return {2, 2, {true, false, true, false}};
242 } else if constexpr (std::is_same_v<T, RtcVectorBool>) {
243 return {true, true, true, true};
244 } else if constexpr (std::is_same_v<T, RtcMatrixString>) {
245 return {1, 3, {"foo", "bar", "baz"}};
246 } else if constexpr (std::is_same_v<T, RtcVectorString>) {
247 return {"goo", "gar", "gaz"};
248 } else if constexpr (std::is_arithmetic_v<T>) {
249 return 43;
250 } else if constexpr (IS_MATRIX_BUFFER_TYPE<T>) {
251 return {1, 3, {43, 44, 45}};
252 } else {
253 return {43, 44, 45};
254 }
255 }
256
257 template <typename U>
258 size_t GetExpectedSize(const U& value) {
259 if constexpr (std::is_same_v<U, std::byte>) {
260 return sizeof(value);
261 } else if constexpr (std::is_arithmetic_v<U>) {
262 return sizeof(value);
263 } else {
264 auto val = MakeSomeTestValue();
265 return val.size();
266 }
267 }
268
269protected:
270 std::vector<DataPointPath> dp_paths;
271 std::shared_ptr<RepositoryIf> repo;
272};
273
275
276template <typename T>
278
279// Define the fundamental type-set of datapoint types that must be supported for basic operations.
280using TypeSetForBasicOperation = ::testing::Types<RtcBool,
281 RtcInt8,
282 RtcInt16,
283 RtcInt32,
284 RtcInt64,
285 RtcUInt8,
286 RtcUInt16,
287 RtcUInt32,
288 RtcUInt64,
289 RtcFloat,
290 RtcDouble,
291 RtcString,
292 RtcBinary,
317
318// define different test sets
320
321TYPED_TEST(BasicOperation, DataPointExistanceConsistency) {
322 // Checks the following:
323 // - That a datapoint can be created with the datapoint type given as a template argument.
324 // - Can test for datapoint existance without exceptions and that the answer is consistent.
325 auto path1 = this->dp_paths[0];
326 auto path2 = this->dp_paths[1];
327 auto& repo = *this->repo;
328 bool exists = false;
329
330 // Check that no datapoints exist initially, including two dummy ones at different path levels.
331 // Checking the dummy datapoints with different path levels is an additional sanity check in
332 // case there is a bug related to handling path hierarchies in the adapter.
333 EXPECT_NO_THROW({ exists = repo.DataPointExists(path1); });
334 EXPECT_EQ(exists, false);
335 EXPECT_NO_THROW({ exists = repo.DataPointExists(path2); });
336 EXPECT_EQ(exists, false);
337 EXPECT_NO_THROW({ exists = repo.DataPointExists("/test/subdir/dummy"_dppath); });
338 EXPECT_EQ(exists, false);
339 EXPECT_NO_THROW({ exists = repo.DataPointExists("/dummy"_dppath); });
340 EXPECT_EQ(exists, false);
341
342 // Create first datapoint and check that only the created path exists.
343 repo.template CreateDataPoint<TypeParam>(path1);
344
345 EXPECT_NO_THROW({ exists = repo.DataPointExists(path1); });
346 EXPECT_EQ(exists, true);
347 EXPECT_NO_THROW({ exists = repo.DataPointExists(path2); });
348 EXPECT_EQ(exists, false);
349 EXPECT_NO_THROW({ exists = repo.DataPointExists("/test/subdir/dummy"_dppath); });
350 EXPECT_EQ(exists, false);
351 EXPECT_NO_THROW({ exists = repo.DataPointExists("/dummy"_dppath); });
352 EXPECT_EQ(exists, false);
353
354 // Create the second datapoint and check that they both exist.
355 repo.template CreateDataPoint<TypeParam>(path2);
356
357 EXPECT_NO_THROW({ exists = repo.DataPointExists(path1); });
358 EXPECT_EQ(exists, true);
359 EXPECT_NO_THROW({ exists = repo.DataPointExists(path2); });
360 EXPECT_EQ(exists, true);
361 EXPECT_NO_THROW({ exists = repo.DataPointExists("/test/subdir/dummy"_dppath); });
362 EXPECT_EQ(exists, false);
363 EXPECT_NO_THROW({ exists = repo.DataPointExists("/dummy"_dppath); });
364 EXPECT_EQ(exists, false);
365
366 // Now delete the first datapoint and see that only the second exists.
367 ASSERT_NO_THROW({ repo.DeleteDataPoint(path1); });
368
369 EXPECT_NO_THROW({ exists = repo.DataPointExists(path1); });
370 EXPECT_EQ(exists, false);
371 EXPECT_NO_THROW({ exists = repo.DataPointExists(path2); });
372 EXPECT_EQ(exists, true);
373 EXPECT_NO_THROW({ exists = repo.DataPointExists("/test/subdir/dummy"_dppath); });
374 EXPECT_EQ(exists, false);
375 EXPECT_NO_THROW({ exists = repo.DataPointExists("/dummy"_dppath); });
376 EXPECT_EQ(exists, false);
377
378 // Delete also the second datapoint and see that no datapoints are marked as existing.
379 ASSERT_NO_THROW({ repo.DeleteDataPoint(path2); });
380
381 EXPECT_NO_THROW({ exists = repo.DataPointExists(path1); });
382 EXPECT_EQ(exists, false);
383 EXPECT_NO_THROW({ exists = repo.DataPointExists(path2); });
384 EXPECT_EQ(exists, false);
385 EXPECT_NO_THROW({ exists = repo.DataPointExists("/test/subdir/dummy"_dppath); });
386 EXPECT_EQ(exists, false);
387 EXPECT_NO_THROW({ exists = repo.DataPointExists("/dummy"_dppath); });
388 EXPECT_EQ(exists, false);
389}
390
391TYPED_TEST(BasicOperation, DataPointCreationAndDeletion) {
392 auto path = this->dp_paths[0];
393 auto& repo = *this->repo;
394 auto create_value = this->MakeSomeTestValue();
395 TypeParam read_value;
396
397 EXPECT_NO_THROW({ repo.DataPointExists(path); });
398
399 ASSERT_FALSE(repo.DataPointExists(path));
400
401 repo.CreateDataPoint(path, create_value);
402 ASSERT_TRUE(repo.DataPointExists(path));
403
404 repo.ReadDataPoint(path, read_value);
405 ASSERT_EQ(create_value, read_value);
406
407 repo.DeleteDataPoint(path);
408 ASSERT_FALSE(repo.DataPointExists(path));
409
410 // creating again to test that recreating a previously deleted datapoint also works
411 repo.CreateDataPoint(path, create_value);
412 ASSERT_TRUE(repo.DataPointExists(path));
413}
414
415TYPED_TEST(BasicOperation, DataPointWriteAndRead) {
416 auto path = this->dp_paths[0];
417 auto& repo = *this->repo;
418 auto create_value = this->MakeSomeTestValue();
419 auto write_value = this->MakeOtherTestValue();
420 TypeParam read_value;
421
422 repo.CreateDataPoint(path, create_value);
423
424 repo.WriteDataPoint(path, write_value);
425 repo.ReadDataPoint(path, read_value);
426 ASSERT_EQ(write_value, read_value);
427
428 // writing again to test a subsequent write
429 repo.WriteDataPoint(path, create_value);
430 repo.ReadDataPoint(path, read_value);
431 ASSERT_EQ(create_value, read_value);
432}
433
434TYPED_TEST(BasicOperation, DataPointWriteAndReadConstValue) {
435 auto path = this->dp_paths[0];
436 auto& repo = *this->repo;
437 const auto create_value = this->MakeSomeTestValue();
438 const auto write_value = this->MakeOtherTestValue();
439 TypeParam read_value;
440
441 repo.CreateDataPoint(path, create_value);
442
443 repo.WriteDataPoint(path, write_value);
444 repo.ReadDataPoint(path, read_value);
445 ASSERT_EQ(write_value, read_value);
446
447 // writing again to test a subsequent write
448 repo.WriteDataPoint(path, create_value);
449 repo.ReadDataPoint(path, read_value);
450 ASSERT_EQ(create_value, read_value);
451}
452
453TYPED_TEST(BasicOperation, DataPointSetAndGet) {
454 auto path = this->dp_paths[0];
455 RepositoryIf& repo = *this->repo;
456 auto create_value = this->MakeSomeTestValue();
457 auto write_value = this->MakeOtherTestValue();
458
459 repo.CreateDataPoint(path, create_value);
460 repo.SetDataPoint(path, write_value);
461
462 ASSERT_EQ(write_value, repo.GetDataPoint<TypeParam>(path));
463
464 ASSERT_TRUE(repo.TryGetDataPoint<TypeParam>(path).has_value());
465 ASSERT_EQ(write_value, repo.TryGetDataPoint<TypeParam>(path).value());
466
467 ASSERT_FALSE(repo.TryGetDataPoint<TypeParam>("/non/existing/dp"_dppath).has_value());
468}
469
470TYPED_TEST(BasicOperation, DataPointTypeQuery) {
471 auto path = this->dp_paths[0];
472 auto& repo = *this->repo;
473 auto create_value = this->MakeSomeTestValue();
474
475 repo.CreateDataPoint(path, create_value);
476
477 const auto& type = repo.GetDataPointType(path);
478
479 EXPECT_EQ(type, typeid(TypeParam));
480}
481
482TYPED_TEST(BasicOperation, DataPointSizeQuery) {
483 auto path = this->dp_paths[0];
484 auto& repo = *this->repo;
485 auto create_value = this->MakeSomeTestValue();
486 auto create_value_size = this->GetExpectedSize(create_value);
487
488 repo.CreateDataPoint(path, create_value);
489 ASSERT_EQ(repo.GetDataPointSize(path), create_value_size);
490}
491
492TYPED_TEST(BasicOperation, DataPointShapeQuery) {
493 auto path = this->dp_paths[0];
494 auto& repo = *this->repo;
495 auto create_value = this->MakeSomeTestValue();
496
497 repo.CreateDataPoint(path, create_value);
498 auto shape = repo.GetDataPointShape(path);
499
500 if constexpr (std::is_same_v<TypeParam, std::byte>) {
501 ASSERT_TRUE(shape.empty());
502 } else if constexpr (std::is_arithmetic_v<TypeParam>) {
503 ASSERT_TRUE(shape.empty());
504 } else if constexpr (IS_MATRIX_BUFFER_TYPE<TypeParam>) {
505 ASSERT_EQ(shape.size(), 2);
506 ASSERT_EQ(shape[0], create_value.GetNrows());
507 ASSERT_EQ(shape[1], create_value.GetNcols());
508 } else if constexpr (IS_VECTOR_TYPE<TypeParam>) {
509 ASSERT_EQ(shape.size(), 1);
510 ASSERT_EQ(shape[0], create_value.size());
511 } else if constexpr (std::is_same_v<TypeParam, RtcString>) {
512 ASSERT_EQ(shape.size(), 1);
513 ASSERT_EQ(shape[0], create_value.size());
514 } else {
515 FAIL() << "Should never enter here. There is a bug in the test code.";
516 }
517}
518
519TYPED_TEST(BasicOperation, RequestApiCommonUsage) {
520 auto path = this->dp_paths[0];
521 auto& repo = *this->repo;
522
523 {
524 auto create_value = this->MakeSomeTestValue();
525 auto write_value = this->MakeOtherTestValue();
526 TypeParam read_value;
527 bool exists = false;
528
530 req.CreateDataPoint(path, create_value);
531 req.DataPointExists(path, exists);
532 req.WriteDataPoint(path, write_value);
533 req.ReadDataPoint(path, read_value);
534 repo.SendRequest(req).Wait();
535
536 ASSERT_EQ(exists, true);
537 ASSERT_EQ(write_value, read_value);
538 }
539
540 {
541 bool exists = false;
543
544 req.DeleteDataPoint(path);
545 req.DataPointExists(path, exists);
546 repo.SendRequest(req).Wait();
547
548 ASSERT_EQ(exists, false);
549 }
550}
551
552TYPED_TEST(BasicOperation, RequestApiCommonUsageConstValue) {
553 auto path = this->dp_paths[0];
554 auto& repo = *this->repo;
555
556 {
557 const auto create_value = this->MakeSomeTestValue();
558 const auto write_value = this->MakeOtherTestValue();
559 TypeParam read_value;
560 bool exists = false;
561
563 req.CreateDataPoint(path, create_value);
564 req.DataPointExists(path, exists);
565 req.WriteDataPoint(path, write_value);
566 req.ReadDataPoint(path, read_value);
567 repo.SendRequest(req).Wait();
568
569 ASSERT_EQ(exists, true);
570 ASSERT_EQ(write_value, read_value);
571 }
572
573 {
574 bool exists = false;
576
577 req.DeleteDataPoint(path);
578 req.DataPointExists(path, exists);
579 repo.SendRequest(req).Wait();
580
581 ASSERT_EQ(exists, false);
582 }
583}
584
586 auto& repo = *this->repo;
587 auto path_1 = this->dp_paths[0];
588 auto path_2 = this->dp_paths[1];
589 auto create_value_1 = this->MakeSomeTestValue();
590 auto create_value_2 = this->MakeOtherTestValue();
591 auto write_value_1 = create_value_2; // NOLINT(performance-unnecessary-copy-initialization)
592 auto write_value_2 = create_value_1; // NOLINT(performance-unnecessary-copy-initialization)
593 TypeParam read_value_1;
594 TypeParam read_value_2;
595
596 {
598 req.CreateDataPoint(path_1, create_value_1);
599 req.CreateDataPoint(path_2, create_value_2);
600 repo.SendRequest(req).Wait();
601 }
602
603 repo.WriteDataPoints(path_1, write_value_1, path_2, write_value_2);
604
605 {
607 req.ReadDataPoint(path_1, read_value_1);
608 req.ReadDataPoint(path_2, read_value_2);
609 repo.SendRequest(req).Wait();
610 }
611
612 ASSERT_EQ(read_value_1, write_value_1);
613 ASSERT_EQ(read_value_2, write_value_2);
614}
615
617 auto& repo = *this->repo;
618 auto path_1 = this->dp_paths[0];
619 auto path_2 = this->dp_paths[1];
620 auto create_value_1 = this->MakeSomeTestValue();
621 auto create_value_2 = this->MakeOtherTestValue();
622 TypeParam read_value_1;
623 TypeParam read_value_2;
624
625 {
627 req.CreateDataPoint(path_1, create_value_1);
628 req.CreateDataPoint(path_2, create_value_2);
629 repo.SendRequest(req).Wait();
630 }
631
632 repo.ReadDataPoints(path_1, read_value_1, path_2, read_value_2);
633
634 ASSERT_EQ(read_value_1, create_value_1);
635 ASSERT_EQ(read_value_2, create_value_2);
636}
637
638TYPED_TEST(BasicOperation, SetAndGetWithStdAny) {
639 auto path = this->dp_paths[0];
640 RepositoryIf& repo = *this->repo;
641 auto create_value = this->MakeSomeTestValue();
642 auto write_value = this->MakeOtherTestValue();
643 std::any any_write_value = write_value;
644
645 repo.CreateDataPoint(path, create_value);
646 repo.SetDataPoint(path, any_write_value);
647
648 {
649 std::any any_read_value = repo.GetDataPoint<std::any>(path);
650 TypeParam& read_value = std::any_cast<TypeParam&>(any_read_value);
651 EXPECT_EQ(write_value, read_value);
652 }
653
654 {
655 ASSERT_TRUE(repo.TryGetDataPoint<std::any>(path).has_value());
656
657 std::any any_read_value = repo.TryGetDataPoint<std::any>(path).value();
658 TypeParam& read_value = std::any_cast<TypeParam&>(any_read_value);
659 EXPECT_EQ(write_value, read_value);
660 }
661}
662
663TYPED_TEST(BasicOperation, WriteReadWithStdAny) {
664 auto path = this->dp_paths[0];
665 auto& repo = *this->repo;
666
667 {
668 auto create_value = this->MakeSomeTestValue();
669 std::any any_create_value = create_value;
670 repo.CreateDataPoint(path, any_create_value);
671
672 std::any any_read_value;
673 repo.ReadDataPoint(path, any_read_value);
674 TypeParam& read_value = std::any_cast<TypeParam&>(any_read_value);
675 EXPECT_EQ(create_value, read_value);
676 }
677
678 {
679 auto write_value = this->MakeOtherTestValue();
680 std::any any_write_value = write_value;
681 repo.WriteDataPoint(path, any_write_value);
682
683 std::any any_read_value;
684 repo.ReadDataPoint(path, any_read_value);
685 TypeParam& read_value = std::any_cast<TypeParam&>(any_read_value);
686 EXPECT_EQ(write_value, read_value);
687 }
688}
689
690TYPED_TEST(BasicOperation, MultiWriteWithStdAny) {
691 auto& repo = *this->repo;
692 auto path_1 = this->dp_paths[0];
693 auto path_2 = this->dp_paths[1];
694 auto create_value_1 = this->MakeSomeTestValue();
695 auto create_value_2 = this->MakeOtherTestValue();
696 auto write_value_1 = create_value_2; // NOLINT(performance-unnecessary-copy-initialization)
697 auto write_value_2 = create_value_1; // NOLINT(performance-unnecessary-copy-initialization)
698 TypeParam read_value_1;
699 TypeParam read_value_2;
700
701 {
703 req.CreateDataPoint(path_1, create_value_1);
704 req.CreateDataPoint(path_2, create_value_2);
705 repo.SendRequest(req).Wait();
706 }
707
708 std::any any_write_value_1 = write_value_1;
709 std::any any_write_value_2 = write_value_2;
710 repo.WriteDataPoints(path_1, any_write_value_1, path_2, any_write_value_2);
711
712 {
714 req.ReadDataPoint(path_1, read_value_1);
715 req.ReadDataPoint(path_2, read_value_2);
716 repo.SendRequest(req).Wait();
717 }
718
719 EXPECT_EQ(read_value_1, write_value_1);
720 EXPECT_EQ(read_value_2, write_value_2);
721}
722
723TYPED_TEST(BasicOperation, MultiReadWithStdAny) {
724 auto& repo = *this->repo;
725 auto path_1 = this->dp_paths[0];
726 auto path_2 = this->dp_paths[1];
727 auto create_value_1 = this->MakeSomeTestValue();
728 auto create_value_2 = this->MakeOtherTestValue();
729
730 {
732 req.CreateDataPoint(path_1, create_value_1);
733 req.CreateDataPoint(path_2, create_value_2);
734 repo.SendRequest(req).Wait();
735 }
736
737 std::any any_read_value_1;
738 std::any any_read_value_2;
739 repo.ReadDataPoints(path_1, any_read_value_1, path_2, any_read_value_2);
740
741 TypeParam& read_value_1 = std::any_cast<TypeParam&>(any_read_value_1);
742 TypeParam& read_value_2 = std::any_cast<TypeParam&>(any_read_value_2);
743 EXPECT_EQ(read_value_1, create_value_1);
744 EXPECT_EQ(read_value_2, create_value_2);
745}
746
748
749template <typename T>
751public:
753 if constexpr (std::is_same_v<T, RtcBinary>) {
754 return T(5000, std::byte{43});
755 } else if constexpr (std::is_same_v<T, RtcString>) {
756 return std::string(5000, 'c');
757 } else if constexpr (std::is_same_v<T, RtcMatrixString>) {
758 return T(500, 500, std::vector<std::string>(500 * 500, std::string("foo")));
759 } else if constexpr (std::is_same_v<T, RtcVectorString>) {
760 return T(5000, std::string("foo"));
761 } else if constexpr (IS_MATRIX_BUFFER_TYPE<T>) {
762 return {500, 500, std::vector<typename T::value_type>(500 * 500, 42)};
763 } else if constexpr (IS_VECTOR_TYPE<T>) {
764 return T(5000, 42);
765 } else {
766 return T(5000);
767 }
768 }
769
771 if constexpr (std::is_same_v<T, RtcBinary>) {
772 return {5000};
773 } else if constexpr (std::is_same_v<T, RtcString>) {
774 return {5000};
775 } else if constexpr (std::is_same_v<T, RtcMatrixString>) {
776 return {500, 500};
777 } else if constexpr (std::is_same_v<T, RtcVectorString>) {
778 return {5000};
779 } else if constexpr (IS_MATRIX_BUFFER_TYPE<T>) {
780 return {500, 500};
781 } else if constexpr (IS_VECTOR_TYPE<T>) {
782 return {5000};
783 } else {
784 return {5000};
785 }
786 }
787
789 if constexpr (std::is_same_v<T, RtcBinary>) {
790 return T(2, std::byte{42});
791 } else if constexpr (std::is_same_v<T, RtcString>) {
792 return std::string(2, 'b');
793 } else if constexpr (std::is_same_v<T, RtcMatrixString>) {
794 return T(2, 2, std::vector<std::string>(2 * 2, std::string("goo")));
795 } else if constexpr (std::is_same_v<T, RtcVectorString>) {
796 return T(2, std::string("goo"));
797 } else if constexpr (IS_MATRIX_BUFFER_TYPE<T>) {
798 return {2, 2, std::vector<typename T::value_type>(2 * 2, 43)};
799 } else if constexpr (IS_VECTOR_TYPE<T>) {
800 return T(2, 43);
801 } else {
802 return T(2);
803 }
804 }
805
807 if constexpr (std::is_same_v<T, RtcBinary>) {
808 return {2};
809 } else if constexpr (std::is_same_v<T, RtcString>) {
810 return {2};
811 } else if constexpr (std::is_same_v<T, RtcMatrixString>) {
812 return {2, 2};
813 } else if constexpr (std::is_same_v<T, RtcVectorString>) {
814 return {2};
815 } else if constexpr (IS_MATRIX_BUFFER_TYPE<T>) {
816 return {2, 2};
817 } else if constexpr (IS_VECTOR_TYPE<T>) {
818 return {2};
819 } else {
820 return {2};
821 }
822 }
823
825 if constexpr (std::is_same_v<T, RtcString>) {
826 return "0123456789abcdef";
827 } else if constexpr (std::is_same_v<T, RtcBinary>) {
828 // clang-format off
829 return { std::byte{1}, std::byte{2}, std::byte{3}, std::byte{4},
830 std::byte{5}, std::byte{6}, std::byte{7}, std::byte{8},
831 std::byte{9}, std::byte{10}, std::byte{11}, std::byte{12},
832 std::byte{13}, std::byte{14}, std::byte{15}, std::byte{16}};
833 // clang-format on
834 } else if constexpr (std::is_same_v<T, RtcMatrixBool>) {
835 // clang-format off
836 return {4, 4, { true, true, false, false,
837 false, false, true, false,
838 false, false, false, true,
839 false, false, false, false}};
840 // clang-format on
841 } else if constexpr (std::is_same_v<T, RtcMatrixString>) {
842 // clang-format off
843 return {4, 4, { "1", "2", "3", "4",
844 "5", "6", "7", "8",
845 "9", "10", "11", "12",
846 "13", "14", "15", "16"}};
847 // clang-format on
848 } else if constexpr (std::is_same_v<T, RtcVectorBool>) {
849 // clang-format off
850 return {true, false, true, false, true, false, true, false,
851 true, false, true, false, true, false, true, false};
852 // clang-format on
853 } else if constexpr (std::is_same_v<T, RtcVectorString>) {
854 // clang-format off
855 return {"1", "2", "3", "4", "5", "6", "7", "8",
856 "9", "10", "11", "12", "13", "14", "15", "16"};
857 // clang-format on
858 } else if constexpr (IS_MATRIX_BUFFER_TYPE<T>) {
859 // clang-format off
860 return {4, 4, { 1, 2, 3, 4,
861 5, 6, 7, 8,
862 9, 10, 11, 12,
863 13, 14, 15, 16}};
864 // clang-format on
865 } else if constexpr (IS_VECTOR_TYPE<T>) {
866 return {1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16};
867 } else {
868 static_assert(false, "Should never enter here. There is a bug in the test code.");
869 }
870 }
871
873 if constexpr (std::is_same_v<T, RtcString>) {
874 return "abcd";
875 } else if constexpr (std::is_same_v<T, RtcBinary>) {
876 return {std::byte{12}, std::byte{13}, std::byte{14}, std::byte{15}};
877 } else if constexpr (std::is_same_v<T, RtcMatrixBool>) {
878 return {1, 4, {false, false, true, true}};
879 } else if constexpr (std::is_same_v<T, RtcMatrixString>) {
880 return {1, 4, {"12", "13", "14", "15"}};
881 } else if constexpr (std::is_same_v<T, RtcVectorBool>) {
882 return {true, true, true, true};
883 } else if constexpr (std::is_same_v<T, RtcVectorString>) {
884 return {"12", "13", "14", "15"};
885 } else if constexpr (IS_MATRIX_BUFFER_TYPE<T>) {
886 return {1, 4, {12, 13, 14, 15}};
887 } else if constexpr (IS_VECTOR_TYPE<T>) {
888 return {12, 13, 14, 15};
889 } else {
890 static_assert(false, "Should never enter here. There is a bug in the test code.");
891 }
892 }
893
895 if constexpr (std::is_same_v<T, RtcString>) {
896 return "abcd456789abcdef";
897 } else if constexpr (std::is_same_v<T, RtcBinary>) {
898 // clang-format off
899 return {std::byte{12}, std::byte{13}, std::byte{14}, std::byte{15},
900 std::byte{5}, std::byte{6}, std::byte{7}, std::byte{8},
901 std::byte{9}, std::byte{10}, std::byte{11}, std::byte{12},
902 std::byte{13}, std::byte{14}, std::byte{15}, std::byte{16}};
903 // clang-format on
904 } else if constexpr (std::is_same_v<T, RtcMatrixBool>) {
905 // clang-format off
906 return {4, 4, {false, false, true, true,
907 false, false, true, false,
908 false, false, false, true,
909 false, false, false, false}};
910 // clang-format on
911 } else if constexpr (std::is_same_v<T, RtcMatrixString>) {
912 // clang-format off
913 return {4, 4, {"12", "13", "14", "15",
914 "5", "6", "7", "8",
915 "9", "10", "11", "12",
916 "13", "14", "15", "16"}};
917 // clang-format on
918 } else if constexpr (std::is_same_v<T, RtcVectorBool>) {
919 // clang-format off
920 return {true, true, true, true, true, false, true, false,
921 true, false, true, false, true, false, true, false};
922 // clang-format on
923 } else if constexpr (std::is_same_v<T, RtcVectorString>) {
924 // clang-format off
925 return {"12", "13", "14", "15", "5", "6", "7", "8",
926 "9", "10", "11", "12", "13", "14", "15", "16"};
927 // clang-format on
928 } else if constexpr (IS_MATRIX_BUFFER_TYPE<T>) {
929 // clang-format off
930 return {4, 4, {12, 13, 14, 15,
931 5, 6, 7, 8,
932 9, 10, 11, 12,
933 13, 14, 15, 16}};
934 // clang-format on
935 } else if constexpr (IS_VECTOR_TYPE<T>) {
936 return {12, 13, 14, 15, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16};
937 } else {
938 static_assert(false, "Should never enter here. There is a bug in the test code.");
939 }
940 }
941
943 if constexpr (std::is_same_v<T, RtcString>) {
944 return "0123";
945 } else if constexpr (std::is_same_v<T, RtcBinary>) {
946 return {std::byte{1}, std::byte{2}, std::byte{3}, std::byte{4}};
947 } else if constexpr (std::is_same_v<T, RtcMatrixBool>) {
948 return {1, 4, {true, true, false, false}};
949 } else if constexpr (std::is_same_v<T, RtcMatrixString>) {
950 return {1, 4, {"1", "2", "3", "4"}};
951 } else if constexpr (std::is_same_v<T, RtcVectorBool>) {
952 return {true, false, true, false};
953 } else if constexpr (std::is_same_v<T, RtcVectorString>) {
954 return {"1", "2", "3", "4"};
955 } else if constexpr (IS_MATRIX_BUFFER_TYPE<T>) {
956 return {1, 4, {1, 2, 3, 4}};
957 } else if constexpr (IS_VECTOR_TYPE<T>) {
958 return {1, 2, 3, 4};
959 } else {
960 static_assert(false, "Should never enter here. There is a bug in the test code.");
961 }
962 }
963
965 if constexpr (std::is_same_v<T, RtcString>) {
966 return "cdef";
967 } else if constexpr (std::is_same_v<T, RtcBinary>) {
968 return {std::byte{13}, std::byte{14}, std::byte{15}, std::byte{16}};
969 } else if constexpr (std::is_same_v<T, RtcMatrixBool>) {
970 return {1, 4, {false, false, false, false}};
971 } else if constexpr (std::is_same_v<T, RtcMatrixString>) {
972 return {1, 4, {"13", "14", "15", "16"}};
973 } else if constexpr (std::is_same_v<T, RtcVectorBool>) {
974 return {true, false, true, false};
975 } else if constexpr (std::is_same_v<T, RtcVectorString>) {
976 return {"13", "14", "15", "16"};
977 } else if constexpr (IS_MATRIX_BUFFER_TYPE<T>) {
978 return {1, 4, {13, 14, 15, 16}};
979 } else if constexpr (IS_VECTOR_TYPE<T>) {
980 return {13, 14, 15, 16};
981 } else {
982 static_assert(false, "Should never enter here. There is a bug in the test code.");
983 }
984 }
985
986 T MakeReadValueForPartialIo(const T& result_value) {
987 T read_value;
988 if constexpr (IS_MATRIX_BUFFER_TYPE<T>) {
989 read_value.resize(result_value.GetNrows(), result_value.GetNcols());
990 } else {
991 read_value.resize(result_value.size());
992 }
993 return read_value;
994 }
995};
996
997using TypeSetAdvancedOperation = ::testing::Types<RtcString,
998 RtcBinary,
1023
1025
1026TYPED_TEST(AdvancedOperation, ModifiedDataPointShapeIsDetected) {
1027 auto path = this->dp_paths[0];
1028 auto& repo = *this->repo;
1029 auto create_value = this->MakeSomeTestValue();
1030 auto write_value = this->MakeOtherTestValue();
1031
1032 repo.CreateDataPoint(path, create_value);
1033 auto create_shape = repo.GetDataPointShape(path);
1034 repo.WriteDataPoint(path, write_value);
1035 auto write_shape = repo.GetDataPointShape(path);
1036
1037 EXPECT_NE(create_shape, write_shape);
1038}
1039
1040TYPED_TEST(AdvancedOperation, CreateAndReadLargeData) {
1041 auto path = this->dp_paths[0];
1042 auto& repo = *this->repo;
1043
1044 auto create_value = this->MakeLargeTestValue();
1045 TypeParam read_value;
1046
1048 req.CreateDataPoint(path, create_value);
1049 req.ReadDataPoint(path, read_value);
1050 repo.SendRequest(req).Wait();
1051
1052 ASSERT_EQ(read_value, create_value);
1053}
1054
1055TYPED_TEST(AdvancedOperation, ResizeFromSmallToLarge) {
1056 auto path = this->dp_paths[0];
1057 auto& repo = *this->repo;
1058
1059 auto create_value = this->MakeSmallTestValue();
1060 auto write_value = this->MakeLargeTestValue();
1061 auto expected_shape = this->ExpectedLargeTestValueShape();
1062 TypeParam read_value;
1063
1064 auto val = this->MakeLargeTestValue();
1065 EXPECT_EQ(val, write_value);
1066
1068 req.CreateDataPoint(path, create_value);
1069 req.WriteDataPoint(path, write_value);
1070 req.ReadDataPoint(path, read_value);
1071 repo.SendRequest(req).Wait();
1072 EXPECT_EQ(read_value, write_value);
1073
1074 auto shape = repo.GetDataPointShape(path);
1075 EXPECT_EQ(shape, expected_shape);
1076}
1077
1078TYPED_TEST(AdvancedOperation, ResizeFromLargeToSmall) {
1079 auto path = this->dp_paths[0];
1080 auto& repo = *this->repo;
1081
1082 auto create_value = this->MakeLargeTestValue();
1083 auto write_value = this->MakeSmallTestValue();
1084 auto expected_shape = this->ExpectedSmallTestValueShape();
1085 TypeParam read_value;
1086
1088 req.CreateDataPoint(path, create_value);
1089 req.WriteDataPoint(path, write_value);
1090 req.ReadDataPoint(path, read_value);
1091 repo.SendRequest(req).Wait();
1092 ASSERT_EQ(read_value, write_value);
1093
1094 auto shape = repo.GetDataPointShape(path);
1095 EXPECT_EQ(shape, expected_shape);
1096}
1097
1098TYPED_TEST(AdvancedOperation, ResizeFromOneToEmpty) {
1099 auto path = this->dp_paths[0];
1100 auto& repo = *this->repo;
1101
1102 TypeParam create_value;
1103 TypeParam write_value;
1104 TypeParam read_value_1;
1105 TypeParam read_value_2;
1106 RtcVectorUInt64 expected_shape;
1107
1108 if constexpr (std::is_same_v<TypeParam, RtcBinary>) {
1109 create_value.resize(1, std::byte{42});
1110 expected_shape = {0};
1111 } else if constexpr (std::is_same_v<TypeParam, RtcMatrixString>) {
1112 create_value.resize(1, 1, "foo");
1113 expected_shape = {0, 0};
1114 } else if constexpr (std::is_same_v<TypeParam, RtcVectorString>) {
1115 create_value.resize(1, "foo");
1116 expected_shape = {0};
1117 } else if constexpr (std::is_same_v<TypeParam, RtcString>) {
1118 create_value = std::string(1, 'c');
1119 expected_shape = {0};
1120 } else if constexpr (IS_MATRIX_BUFFER_TYPE<TypeParam>) {
1121 create_value.resize(1, 1, 42);
1122 expected_shape = {0, 0};
1123 } else if constexpr (IS_VECTOR_TYPE<TypeParam>) {
1124 create_value.resize(1, 42);
1125 expected_shape = {0};
1126 } else {
1127 FAIL() << "Should never enter here. There is a bug in the test code.";
1128 }
1129
1131 req.CreateDataPoint(path, create_value);
1132 req.ReadDataPoint(path, read_value_1);
1133 req.WriteDataPoint(path, write_value);
1134 req.ReadDataPoint(path, read_value_2);
1135 repo.SendRequest(req).Wait();
1136 ASSERT_EQ(read_value_1, create_value);
1137 ASSERT_EQ(read_value_2, write_value);
1138
1139 auto shape = repo.GetDataPointShape(path);
1140 EXPECT_EQ(shape, expected_shape);
1141}
1142
1143TYPED_TEST(AdvancedOperation, ResizeFromLargeToEmpty) {
1144 auto path = this->dp_paths[0];
1145 auto& repo = *this->repo;
1146
1147 TypeParam create_value;
1148 TypeParam write_value;
1149 TypeParam read_value;
1150 RtcVectorUInt64 expected_shape;
1151
1152 if constexpr (std::is_same_v<TypeParam, RtcBinary>) {
1153 create_value.resize(5000, std::byte{42});
1154 expected_shape = {0};
1155 } else if constexpr (std::is_same_v<TypeParam, RtcMatrixString>) {
1156 create_value.resize(500, 500, "foo");
1157 expected_shape = {0, 0};
1158 } else if constexpr (std::is_same_v<TypeParam, RtcVectorString>) {
1159 create_value.resize(5000, "foo");
1160 expected_shape = {0};
1161 } else if constexpr (std::is_same_v<TypeParam, RtcString>) {
1162 create_value = std::string(5000, 'c');
1163 expected_shape = {0};
1164 } else if constexpr (IS_MATRIX_BUFFER_TYPE<TypeParam>) {
1165 create_value.resize(500, 500, 42);
1166 expected_shape = {0, 0};
1167 } else if constexpr (IS_VECTOR_TYPE<TypeParam>) {
1168 create_value.resize(5000, 42);
1169 expected_shape = {0};
1170 } else {
1171 FAIL() << "Should never enter here. There is a bug in the test code.";
1172 }
1173
1175 req.CreateDataPoint(path, create_value);
1176 req.WriteDataPoint(path, write_value);
1177 req.ReadDataPoint(path, read_value);
1178 repo.SendRequest(req).Wait();
1179 ASSERT_EQ(read_value, write_value);
1180
1181 auto shape = repo.GetDataPointShape(path);
1182 EXPECT_EQ(shape, expected_shape);
1183}
1184
1185TYPED_TEST(AdvancedOperation, PartialWritePattern) {
1186 auto path = this->dp_paths[0];
1187 auto& repo = *this->repo;
1188
1189 TypeParam create_value = this->MakeCreateValueForPartialIo();
1190 TypeParam write_value = this->MakeWriteValueForPartialIo();
1191 TypeParam read_value;
1192 TypeParam result_value = this->MakeExpectedResultValueForPartialWrite();
1193
1195 req.CreateDataPoint(path, create_value);
1196 req.PartialWriteDataPoint(path, write_value, 0, 4, 0);
1197 req.ReadDataPoint(path, read_value);
1198 repo.SendRequest(req).Wait();
1199
1200 EXPECT_EQ(read_value, result_value);
1201}
1202
1203TYPED_TEST(AdvancedOperation, PartialReadPattern) {
1204 auto path = this->dp_paths[0];
1205 auto& repo = *this->repo;
1206
1207 {
1208 // partial read first 4 elements
1209 TypeParam create_value = this->MakeCreateValueForPartialIo();
1210 TypeParam result_value = this->MakeExpectedResultValueForPartialRead();
1211 TypeParam read_value = this->MakeReadValueForPartialIo(result_value);
1212
1214 req.CreateDataPoint(path, create_value);
1215 req.PartialReadDataPoint(path, read_value, 0, 4, 0);
1216 repo.SendRequest(req).Wait();
1217 EXPECT_EQ(read_value, result_value);
1218 }
1219
1220 {
1221 // partial read last 4 elements
1222 TypeParam result_value = this->MakeExpectedResultValueForPartialReadEnd();
1223 TypeParam read_value = this->MakeReadValueForPartialIo(result_value);
1224
1226 req.PartialReadDataPoint(path, read_value, 12, 16, 0);
1227 repo.SendRequest(req).Wait();
1228 EXPECT_EQ(read_value, result_value);
1229 }
1230}
1231
1232TYPED_TEST(AdvancedOperation, PartialWritePatternWithStdAny) {
1233 auto path = this->dp_paths[0];
1234 auto& repo = *this->repo;
1235
1236 TypeParam create_value = this->MakeCreateValueForPartialIo();
1237 std::any any_write_value = this->MakeWriteValueForPartialIo();
1238 TypeParam read_value;
1239 TypeParam result_value = this->MakeExpectedResultValueForPartialWrite();
1240
1242 req.CreateDataPoint(path, create_value);
1243 req.PartialWriteDataPoint(path, any_write_value, 0, 4, 0);
1244 req.ReadDataPoint(path, read_value);
1245 repo.SendRequest(req).Wait();
1246
1247 EXPECT_EQ(read_value, result_value);
1248}
1249
1250TYPED_TEST(AdvancedOperation, PartialReadPatternWithStdAny) {
1251 auto path = this->dp_paths[0];
1252 auto& repo = *this->repo;
1253
1254 TypeParam create_value = this->MakeCreateValueForPartialIo();
1255 TypeParam result_value = this->MakeExpectedResultValueForPartialRead();
1256 std::any any_read_value = this->MakeReadValueForPartialIo(result_value);
1257
1259 req.CreateDataPoint(path, create_value);
1260 req.PartialReadDataPoint(path, any_read_value, 0, 4, 0);
1261 repo.SendRequest(req).Wait();
1262
1263 TypeParam& read_value = std::any_cast<TypeParam&>(any_read_value);
1264 EXPECT_EQ(read_value, result_value);
1265}
1266
1267template <typename T>
1268struct TypeMap {};
1269
1270template <>
1273 using SpanType = gsl::span<char>;
1274 using ConstSpanType = gsl::span<const char>;
1275};
1276
1277template <typename T, typename A>
1283
1284template <typename T, typename A>
1285struct TypeMap<std::vector<T, A>> {
1286 using BufferType = std::vector<T, A>;
1287 using SpanType = gsl::span<T>;
1288 using ConstSpanType = gsl::span<const T>;
1289};
1290
1291template <typename A>
1292struct TypeMap<std::vector<bool, A>> {
1293 using BufferType = boost::container::vector<bool, A>;
1294 using SpanType = gsl::span<bool>;
1295 using ConstSpanType = gsl::span<const bool>;
1296};
1297
1298template <typename A>
1299struct TypeMap<MatrixBuffer<bool, A>> {
1300 using BufferType = boost::container::vector<bool, A>;
1303};
1304
1306 auto path1 = this->dp_paths[0];
1307 auto path2 = this->dp_paths[1];
1308 auto& repo = *this->repo;
1309
1310 using BufferType = typename TypeMap<TypeParam>::BufferType;
1311 BufferType create_value;
1312 BufferType write_value;
1313 BufferType read_value;
1314
1315 if constexpr (std::is_same_v<TypeParam, RtcString>) {
1316 create_value = "abcd";
1317 write_value = "1234";
1318 read_value.resize(create_value.size());
1319 } else if constexpr (std::is_same_v<TypeParam, RtcBinary>) {
1320 create_value = {std::byte{1}, std::byte{2}, std::byte{3}, std::byte{4}};
1321 write_value = {std::byte{11}, std::byte{12}, std::byte{13}, std::byte{14}};
1322 read_value.resize(create_value.size());
1323 } else if constexpr (std::is_same_v<TypeParam, RtcMatrixBool>) {
1324 create_value = {true, true, false, false};
1325 write_value = {false, false, true, true};
1326 read_value.resize(create_value.size());
1327 } else if constexpr (std::is_same_v<TypeParam, RtcMatrixString>) {
1328 create_value = {2, 2, {"aa", "bb", "cc", "dd"}};
1329 write_value = {2, 2, {"00", "11", "22", "33"}};
1330 read_value.resize(create_value.GetNrows(), create_value.GetNcols());
1331 } else if constexpr (IS_MATRIX_BUFFER_TYPE<TypeParam>) {
1332 create_value = {2, 2, {1, 2, 3, 4}};
1333 write_value = {2, 2, {11, 12, 13, 14}};
1334 read_value.resize(create_value.GetNrows(), create_value.GetNcols());
1335 } else if constexpr (std::is_same_v<TypeParam, RtcVectorBool>) {
1336 create_value = {true, false, true, false};
1337 write_value = {false, true, false, true};
1338 read_value.resize(create_value.size());
1339 } else if constexpr (std::is_same_v<TypeParam, RtcVectorString>) {
1340 create_value = {"aa", "bb", "cc", "dd"};
1341 write_value = {"00", "11", "22", "33"};
1342 read_value.resize(create_value.size());
1343 } else if constexpr (IS_VECTOR_TYPE<TypeParam>) {
1344 create_value = {1, 2, 3, 4};
1345 write_value = {11, 12, 13, 14};
1346 read_value.resize(create_value.size());
1347 } else {
1348 FAIL() << "Should never enter here. There is a bug in the test code.";
1349 }
1350
1351 using SpanT = typename TypeMap<TypeParam>::SpanType;
1352 using ConstSpanT = typename TypeMap<TypeParam>::ConstSpanType;
1353 SpanT create_span;
1354 ConstSpanT create_const_span;
1355 SpanT write_span;
1356 ConstSpanT write_const_span;
1357 SpanT read_span;
1358
1359 if constexpr (std::is_same_v<TypeParam, RtcMatrixBool>) {
1360 create_span = SpanT(2, 2, create_value);
1361 create_const_span = ConstSpanT(2, 2, create_value);
1362 write_span = SpanT(2, 2, write_value);
1363 write_const_span = ConstSpanT(2, 2, write_value);
1364 read_span = SpanT(2, 2, read_value);
1365 } else {
1366 create_span = SpanT(create_value);
1367 create_const_span = ConstSpanT(create_value);
1368 write_span = SpanT(write_value);
1369 write_const_span = ConstSpanT(write_value);
1370 read_span = SpanT(read_value);
1371 }
1372
1373 // Create and write using non-const version of the spans.
1374 repo.CreateDataPoint(path1, create_span);
1375 ASSERT_EQ(repo.GetDataPointType(path1), typeid(TypeParam));
1376
1377 repo.ReadDataPoint(path1, read_span);
1378 ASSERT_THAT(read_value, ContainerEq(create_value));
1379
1380 repo.WriteDataPoint(path1, write_span);
1381 repo.ReadDataPoint(path1, read_span);
1382 ASSERT_THAT(read_value, ContainerEq(write_value));
1383
1384 // Attempt the creation and writing of the datapoint with a const version of the spans.
1385 repo.CreateDataPoint(path2, create_const_span);
1386 ASSERT_EQ(repo.GetDataPointType(path2), typeid(TypeParam));
1387
1388 repo.ReadDataPoint(path2, read_span);
1389 ASSERT_THAT(read_value, ContainerEq(create_value));
1390
1391 repo.WriteDataPoint(path2, write_const_span);
1392 repo.ReadDataPoint(path2, read_span);
1393 ASSERT_THAT(read_value, ContainerEq(write_value));
1394
1395 if constexpr (std::is_same_v<TypeParam, RtcString>) {
1396 // For a string datapoints we check that we can also create and write to them using
1397 // read-only string views. The std::string_view can be thought of as a read-only span.
1398 auto path3 = this->dp_paths[2];
1399 std::string_view create_view = create_value;
1400 std::string_view write_view = write_value;
1401
1402 repo.CreateDataPoint(path3, create_view);
1403 ASSERT_EQ(repo.GetDataPointType(path3), typeid(TypeParam));
1404
1405 repo.ReadDataPoint(path3, read_value);
1406 ASSERT_THAT(read_value, ContainerEq(create_value));
1407
1408 repo.WriteDataPoint(path3, write_view);
1409 repo.ReadDataPoint(path3, read_value);
1410 ASSERT_THAT(read_value, ContainerEq(write_value));
1411 }
1412}
1413
1415 auto path = this->dp_paths[0];
1416 auto& repo = *this->repo;
1417
1418 if constexpr (std::is_same_v<TypeParam, RtcString> or IS_VECTOR_TYPE<TypeParam>) {
1419 using ArrayType = std::array<typename TypeParam::value_type, 4>;
1420 ArrayType create_array;
1421 ArrayType write_array;
1422 ArrayType read_array;
1423 if constexpr (std::is_same_v<TypeParam, RtcString>) {
1424 create_array = {'a', 'b', 'c', 'd'};
1425 write_array = {'1', '2', '3', '4'};
1426 } else if constexpr (std::is_same_v<TypeParam, RtcBinary>) {
1427 create_array = {std::byte{1}, std::byte{2}, std::byte{3}, std::byte{4}};
1428 write_array = {std::byte{11}, std::byte{12}, std::byte{13}, std::byte{14}};
1429 } else if constexpr (std::is_same_v<TypeParam, RtcVectorBool>) {
1430 create_array = {true, false, true, false};
1431 write_array = {false, true, false, true};
1432 } else if constexpr (std::is_same_v<TypeParam, RtcVectorString>) {
1433 create_array = {"aa", "bb", "cc", "dd"};
1434 write_array = {"00", "11", "22", "33"};
1435 } else {
1436 create_array = {1, 2, 3, 4};
1437 write_array = {11, 12, 13, 14};
1438 }
1439
1440 repo.CreateDataPoint(path, create_array);
1441 ASSERT_EQ(repo.GetDataPointType(path), typeid(TypeParam));
1442
1443 repo.ReadDataPoint(path, read_array);
1444 ASSERT_EQ(create_array, read_array);
1445
1446 repo.WriteDataPoint(path, write_array);
1447 repo.ReadDataPoint(path, read_array);
1448 ASSERT_EQ(write_array, read_array);
1449
1450 } else if constexpr (IS_MATRIX_BUFFER_TYPE<TypeParam>) {
1451 using Row = std::array<typename TypeParam::value_type, 2>;
1452 using MatrixType = std::array<Row, 2>;
1453 MatrixType create_array;
1454 MatrixType write_array;
1455 MatrixType read_array;
1456 if constexpr (std::is_same_v<TypeParam, RtcMatrixBool>) {
1457 create_array = {Row{true, false}, Row{true, false}};
1458 write_array = {Row{false, true}, Row{false, true}};
1459 } else if constexpr (std::is_same_v<TypeParam, RtcMatrixString>) {
1460 create_array = {Row{"aa", "bb"}, Row{"cc", "dd"}};
1461 write_array = {Row{"00", "11"}, Row{"22", "33"}};
1462 } else {
1463 create_array = {Row{1, 2}, Row{3, 4}};
1464 write_array = {Row{11, 12}, Row{13, 14}};
1465 }
1466
1467 repo.CreateDataPoint(path, create_array);
1468 ASSERT_EQ(repo.GetDataPointType(path), typeid(TypeParam));
1469
1470 repo.ReadDataPoint(path, read_array);
1471 ASSERT_EQ(create_array, read_array);
1472
1473 repo.WriteDataPoint(path, write_array);
1474 repo.ReadDataPoint(path, read_array);
1475 ASSERT_EQ(write_array, read_array);
1476
1477 } else {
1478 FAIL() << "Should never enter here. There is a bug in the test code.";
1479 }
1480}
1481
1482TYPED_TEST(AdvancedOperation, CStyleArrayAccess) {
1483 using testing::ElementsAreArray;
1484 auto path = this->dp_paths[0];
1485 auto& repo = *this->repo;
1486
1487 if constexpr (std::is_same_v<TypeParam, RtcString> or IS_VECTOR_TYPE<TypeParam>) {
1488 using ValueType = typename TypeParam::value_type;
1489 ValueType create_array[4]; // NOLINT(modernize-avoid-c-arrays)
1490 ValueType write_array[4]; // NOLINT(modernize-avoid-c-arrays)
1491 ValueType read_array[4]; // NOLINT(modernize-avoid-c-arrays)
1492 if constexpr (std::is_same_v<TypeParam, RtcString>) {
1493 create_array[0] = 'a';
1494 create_array[1] = 'b';
1495 create_array[2] = 'c';
1496 create_array[3] = 'd';
1497 write_array[0] = '1';
1498 write_array[1] = '2';
1499 write_array[2] = '3';
1500 write_array[3] = '4';
1501 } else if constexpr (std::is_same_v<TypeParam, RtcBinary>) {
1502 create_array[0] = std::byte{1};
1503 create_array[1] = std::byte{2};
1504 create_array[2] = std::byte{3};
1505 create_array[3] = std::byte{4};
1506 write_array[0] = std::byte{11};
1507 write_array[1] = std::byte{12};
1508 write_array[2] = std::byte{13};
1509 write_array[3] = std::byte{14};
1510 } else if constexpr (std::is_same_v<TypeParam, RtcVectorBool>) {
1511 create_array[0] = true;
1512 create_array[1] = false;
1513 create_array[2] = false;
1514 create_array[3] = true;
1515 write_array[0] = false;
1516 write_array[1] = true;
1517 write_array[2] = true;
1518 write_array[3] = false;
1519 } else if constexpr (std::is_same_v<TypeParam, RtcVectorString>) {
1520 create_array[0] = "aa";
1521 create_array[1] = "bb";
1522 create_array[2] = "cc";
1523 create_array[3] = "dd";
1524 write_array[0] = "00";
1525 write_array[1] = "11";
1526 write_array[2] = "22";
1527 write_array[3] = "33";
1528 } else {
1529 create_array[0] = 1;
1530 create_array[1] = 2;
1531 create_array[2] = 3;
1532 create_array[3] = 4;
1533 write_array[0] = 11;
1534 write_array[1] = 12;
1535 write_array[2] = 13;
1536 write_array[3] = 14;
1537 }
1538
1539 repo.CreateDataPoint(path, create_array);
1540 ASSERT_EQ(repo.GetDataPointType(path), typeid(TypeParam));
1541
1542 repo.ReadDataPoint(path, read_array);
1543 gsl::span<ValueType, 4> create_span(std::begin(create_array), std::end(create_array));
1544 EXPECT_THAT(create_span, ElementsAreArray(std::begin(read_array), std::end(read_array)));
1545
1546 repo.WriteDataPoint(path, write_array);
1547 repo.ReadDataPoint(path, read_array);
1548 gsl::span<ValueType, 4> write_span(std::begin(write_array), std::end(write_array));
1549 EXPECT_THAT(write_span, ElementsAreArray(std::begin(read_array), std::end(read_array)));
1550
1551 } else if constexpr (IS_MATRIX_BUFFER_TYPE<TypeParam>) {
1552 using ValueType = typename TypeParam::value_type;
1553 ValueType create_array[2][2]; // NOLINT(modernize-avoid-c-arrays)
1554 ValueType write_array[2][2]; // NOLINT(modernize-avoid-c-arrays)
1555 ValueType read_array[2][2]; // NOLINT(modernize-avoid-c-arrays)
1556 if constexpr (std::is_same_v<TypeParam, RtcMatrixBool>) {
1557 create_array[0][0] = true;
1558 create_array[0][1] = false;
1559 create_array[1][0] = false;
1560 create_array[1][1] = true;
1561 write_array[0][0] = false;
1562 write_array[0][1] = true;
1563 write_array[1][0] = true;
1564 write_array[1][1] = false;
1565 } else if constexpr (std::is_same_v<TypeParam, RtcMatrixString>) {
1566 create_array[0][0] = "aa";
1567 create_array[0][1] = "bb";
1568 create_array[1][0] = "cc";
1569 create_array[1][1] = "dd";
1570 write_array[0][0] = "00";
1571 write_array[0][1] = "11";
1572 write_array[1][0] = "22";
1573 write_array[1][1] = "33";
1574 } else {
1575 create_array[0][0] = 1;
1576 create_array[0][1] = 2;
1577 create_array[1][0] = 3;
1578 create_array[1][1] = 4;
1579 write_array[0][0] = 11;
1580 write_array[0][1] = 12;
1581 write_array[1][0] = 13;
1582 write_array[1][1] = 14;
1583 }
1584 gsl::span<ValueType, 2 * 2> read_span(&read_array[0][0], 2 * 2);
1585
1586 repo.CreateDataPoint(path, create_array);
1587 ASSERT_EQ(repo.GetDataPointType(path), typeid(TypeParam));
1588
1589 repo.ReadDataPoint(path, read_array);
1590 gsl::span<ValueType, 2 * 2> create_span(&create_array[0][0], 2 * 2);
1591 EXPECT_THAT(create_span, ElementsAreArray(read_span.begin(), read_span.end()));
1592
1593 repo.WriteDataPoint(path, write_array);
1594 repo.ReadDataPoint(path, read_array);
1595 gsl::span<ValueType, 2 * 2> write_span(&write_array[0][0], 2 * 2);
1596 EXPECT_THAT(write_span, ElementsAreArray(read_span.begin(), read_span.end()));
1597
1598 } else {
1599 FAIL() << "Should never enter here. There is a bug in the test code.";
1600 }
1601}
1602
1604
1605class Callbacks : public testing::Test {
1606public:
1607 void SetUp() override {
1608 repo = MakeRepository();
1609 path1 = "/foo"_dppath;
1610 path2 = "/bar"_dppath;
1611 link1 = "/link1"_dppath;
1612 link2 = "/link2"_dppath;
1613 }
1614
1615 void TearDown() override {
1616 if (repo->DataPointExists(link1)) {
1617 repo->DeleteDataPoint(link1);
1618 }
1619 if (repo->DataPointExists(link2)) {
1620 repo->DeleteDataPoint(link2);
1621 }
1622 if (repo->DataPointExists(path1)) {
1623 repo->DeleteDataPoint(path1);
1624 }
1625 if (repo->DataPointExists(path2)) {
1626 repo->DeleteDataPoint(path2);
1627 }
1628 }
1629
1630 template <typename T = RtcInt64>
1631 void SetupDataPoints(const T& initial_value = 0) {
1633 req.CreateDataPoint(path1, initial_value);
1634 req.CreateDataPoint(path2, initial_value);
1635 repo->SendRequest(req).Wait();
1636 }
1637
1638protected:
1639 std::shared_ptr<RepositoryIf> repo;
1644};
1645
1647public:
1648 MOCK_METHOD(void, CreateCallback, (const DataPointPath& path));
1649 MOCK_METHOD(void, DeleteCallback, (const DataPointPath& path));
1650 MOCK_METHOD(void, ExistsCallback, (const DataPointPath& path));
1651 MOCK_METHOD(void, GetChildrenCallback, (const DataPointPath& path));
1652 MOCK_METHOD(void, WriteCallback, (const DataPointPath& path));
1653 MOCK_METHOD(void, ReadCallback, (const DataPointPath& path));
1654 MOCK_METHOD(void, PartialWriteCallback, (const DataPointPath& path));
1655 MOCK_METHOD(void, PartialReadCallback, (const DataPointPath& path));
1656 MOCK_METHOD(void, WriteMetaDataCallback, (const DataPointPath& path));
1657 MOCK_METHOD(void, ReadMetaDataCallback, (const DataPointPath& path));
1658 MOCK_METHOD(void, CreateSymlinkCallback, (const DataPointPath& path));
1659 MOCK_METHOD(void, UpdateSymlinkCallback, (const DataPointPath& path));
1660};
1661
1662TEST_F(Callbacks, CreateDataPointCallback) {
1663 MockCallbacks callbacks;
1664
1665 EXPECT_CALL(callbacks, CreateCallback(path1)).Times(1);
1666 EXPECT_CALL(callbacks, CreateCallback(path2)).Times(1);
1667
1668 auto cb = [&callbacks](const DataPointPath& path) { callbacks.CreateCallback(path); };
1669
1670 int value1 = 1;
1671 int value2 = 2;
1673 req.CreateDataPoint(path1, value1, std::nullopt, cb);
1674 req.CreateDataPoint(path2, value2, std::nullopt, cb);
1675 repo->SendRequest(req).Wait();
1676}
1677
1678TEST_F(Callbacks, DeleteDataPointCallback) {
1679 MockCallbacks callbacks;
1680
1681 EXPECT_CALL(callbacks, DeleteCallback(path1)).Times(1);
1682 EXPECT_CALL(callbacks, DeleteCallback(path2)).Times(1);
1683
1684 auto cb = [&callbacks](const DataPointPath& path) { callbacks.DeleteCallback(path); };
1685
1686 SetupDataPoints();
1687
1689 req.DeleteDataPoint(path1, cb);
1690 req.DeleteDataPoint(path2, cb);
1691 repo->SendRequest(req).Wait();
1692}
1693
1694TEST_F(Callbacks, DataPointExistsCallback) {
1695 MockCallbacks callbacks;
1696 bool exists_1, exists_2;
1697
1698 EXPECT_CALL(callbacks, ExistsCallback(path1)).Times(1);
1699 EXPECT_CALL(callbacks, ExistsCallback(path2)).Times(1);
1700
1701 auto cb = [&callbacks](const DataPointPath& path) { callbacks.ExistsCallback(path); };
1702
1704 req.DataPointExists(path1, exists_1, cb);
1705 req.DataPointExists(path2, exists_2, cb);
1706 repo->SendRequest(req).Wait();
1707}
1708
1709TEST_F(Callbacks, GetChildrenCallback) {
1710 MockCallbacks callbacks;
1711 std::pair<RepositoryIf::PathList, RepositoryIf::PathList> children_1, children_2;
1712
1713 EXPECT_CALL(callbacks, GetChildrenCallback(path1)).Times(1);
1714 EXPECT_CALL(callbacks, GetChildrenCallback(path2)).Times(1);
1715
1716 auto cb = [&callbacks](const DataPointPath& path) { callbacks.GetChildrenCallback(path); };
1717
1719 req.GetChildren(path1, children_1, true, cb);
1720 req.GetChildren(path2, children_2, false, cb);
1721 repo->SendRequest(req).Wait();
1722}
1723
1724TEST_F(Callbacks, WriteDataPointCallback) {
1725 MockCallbacks callbacks;
1726 RtcInt64 buffer1 = 1;
1727 RtcInt64 buffer2 = 2;
1728
1729 EXPECT_CALL(callbacks, WriteCallback(path1)).Times(1);
1730 EXPECT_CALL(callbacks, WriteCallback(path2)).Times(1);
1731
1732 auto cb = [&callbacks](const DataPointPath& path) { callbacks.WriteCallback(path); };
1733
1734 SetupDataPoints();
1735
1737 req.WriteDataPoint(path1, buffer1, std::nullopt, cb);
1738 req.WriteDataPoint(path2, buffer2, std::nullopt, cb);
1739 repo->SendRequest(req).Wait();
1740}
1741
1742TEST_F(Callbacks, ReadDataPointCallback) {
1743 MockCallbacks callbacks;
1744 RtcInt64 buffer1, buffer2;
1745
1746 EXPECT_CALL(callbacks, ReadCallback(path1)).Times(1);
1747 EXPECT_CALL(callbacks, ReadCallback(path2)).Times(1);
1748
1749 auto cb = [&callbacks](const DataPointPath& path) { callbacks.ReadCallback(path); };
1750
1751 SetupDataPoints();
1752
1754 req.ReadDataPoint(path1, buffer1, std::nullopt, cb);
1755 req.ReadDataPoint(path2, buffer2, std::nullopt, cb);
1756 repo->SendRequest(req).Wait();
1757}
1758
1759TEST_F(Callbacks, PartialWriteDataPointCallback) {
1760 MockCallbacks callbacks;
1761 RtcVectorInt64 buffer1{1, 2};
1762 RtcVectorInt64 buffer2{3, 4};
1763
1764 EXPECT_CALL(callbacks, PartialWriteCallback(path1)).Times(1);
1765 EXPECT_CALL(callbacks, PartialWriteCallback(path2)).Times(1);
1766
1767 auto cb = [&callbacks](const DataPointPath& path) { callbacks.PartialWriteCallback(path); };
1768
1769 SetupDataPoints(RtcVectorInt64{0, 0});
1770
1772 req.PartialWriteDataPoint(path1, buffer1, 0, 2, 0, std::nullopt, cb);
1773 req.PartialWriteDataPoint(path2, buffer2, 0, 2, 0, std::nullopt, cb);
1774 repo->SendRequest(req).Wait();
1775}
1776
1777TEST_F(Callbacks, PartialReadDataPointCallback) {
1778 MockCallbacks callbacks;
1779 RtcVectorInt64 buffer1{0, 0};
1780 RtcVectorInt64 buffer2{0, 0};
1781
1782 EXPECT_CALL(callbacks, PartialReadCallback(path1)).Times(1);
1783 EXPECT_CALL(callbacks, PartialReadCallback(path2)).Times(1);
1784
1785 auto cb = [&callbacks](const DataPointPath& path) { callbacks.PartialReadCallback(path); };
1786
1787 SetupDataPoints(RtcVectorInt64{1, 2});
1788
1790 req.PartialReadDataPoint(path1, buffer1, 0, 2, 0, std::nullopt, cb);
1791 req.PartialReadDataPoint(path2, buffer2, 0, 2, 0, std::nullopt, cb);
1792 repo->SendRequest(req).Wait();
1793}
1794
1795TEST_F(Callbacks, WriteMetaDataCallback) {
1796 MockCallbacks callbacks;
1797 RepositoryIf::MetaData metadata1, metadata2;
1798 metadata1["comment"] = std::string{"foo"};
1799 metadata2["comment"] = std::string{"bar"};
1800
1801 EXPECT_CALL(callbacks, WriteMetaDataCallback(path1)).Times(1);
1802 EXPECT_CALL(callbacks, WriteMetaDataCallback(path2)).Times(1);
1803
1804 auto cb = [&callbacks](const DataPointPath& path) { callbacks.WriteMetaDataCallback(path); };
1805
1806 SetupDataPoints();
1807
1809 req.WriteMetaData(path1, metadata1, cb);
1810 req.WriteMetaData(path2, metadata2, cb);
1811 repo->SendRequest(req).Wait();
1812}
1813
1814TEST_F(Callbacks, ReadMetaDataCallback) {
1815 MockCallbacks callbacks;
1816 RepositoryIf::MetaData metadata1, metadata2;
1817
1818 EXPECT_CALL(callbacks, ReadMetaDataCallback(path1)).Times(1);
1819 EXPECT_CALL(callbacks, ReadMetaDataCallback(path2)).Times(1);
1820
1821 auto cb = [&callbacks](const DataPointPath& path) { callbacks.ReadMetaDataCallback(path); };
1822
1823 SetupDataPoints();
1824
1826 req.ReadMetaData(path1, metadata1, cb);
1827 req.ReadMetaData(path2, metadata2, cb);
1828 repo->SendRequest(req).Wait();
1829}
1830
1831TEST_F(Callbacks, CreateSymlinkCallback) {
1832 MockCallbacks callbacks;
1833
1834 EXPECT_CALL(callbacks, CreateSymlinkCallback(link1)).Times(1);
1835 EXPECT_CALL(callbacks, CreateSymlinkCallback(link2)).Times(1);
1836
1837 auto cb = [&callbacks](const DataPointPath& path) { callbacks.CreateSymlinkCallback(path); };
1838
1839 SetupDataPoints();
1840
1842 req.CreateSymlink(path1, "/link1"_dppath, cb);
1843 req.CreateSymlink(path2, "/link2"_dppath, cb);
1844 repo->SendRequest(req).Wait();
1845}
1846
1847TEST_F(Callbacks, UpdateSymlinkCallback) {
1848 MockCallbacks callbacks;
1849
1850 EXPECT_CALL(callbacks, UpdateSymlinkCallback(link1)).Times(1);
1851 EXPECT_CALL(callbacks, UpdateSymlinkCallback(link2)).Times(1);
1852
1853 auto cb = [&callbacks](const DataPointPath& path) { callbacks.UpdateSymlinkCallback(path); };
1854
1855 SetupDataPoints();
1856
1858 req.CreateSymlink(path1, "/link1"_dppath);
1859 req.CreateSymlink(path2, "/link2"_dppath);
1860 // The update swaps the targets of the two links.
1861 req.UpdateSymlink(path2, "/link1"_dppath, cb);
1862 req.UpdateSymlink(path1, "/link2"_dppath, cb);
1863 repo->SendRequest(req).Wait();
1864}
1865
1866TEST_F(Callbacks, CreateDataPointCallbackMustBeReentrant) {
1867 // Send a second CreateDataPoint request within the callback and make sure it completes,
1868 // i.e it does not deadlock.
1869 MockCallbacks callbacks;
1870
1871 // Since the second request is executed within the callback cb1, the order of the callbacks is
1872 // defined by the following sequence.
1873 testing::InSequence seq;
1874 EXPECT_CALL(callbacks, CreateCallback(path1)).Times(1);
1875 EXPECT_CALL(callbacks, CreateCallback(path2)).Times(1);
1876
1877 auto cb2 = [&callbacks](const DataPointPath& path) { callbacks.CreateCallback(path); };
1878
1879 auto cb1 = [&](const DataPointPath& path) {
1880 callbacks.CreateCallback(path);
1881 int value2 = 2;
1883 req2.CreateDataPoint(path2, value2, std::nullopt, cb2);
1884 repo->SendRequest(req2).Wait();
1885 };
1886
1887 int value1 = 1;
1889 req1.CreateDataPoint(path1, value1, std::nullopt, cb1);
1890 repo->SendRequest(req1).Wait();
1891}
1892
1893TEST_F(Callbacks, DeleteDataPointCallbackMustBeReentrant) {
1894 // Send a second DeleteDataPoint request within the callback and make sure it completes,
1895 // i.e it does not deadlock.
1896 MockCallbacks callbacks;
1897
1898 // Since the second request is executed within the callback cb1, the order of the callbacks is
1899 // defined by the following sequence.
1900 testing::InSequence seq;
1901 EXPECT_CALL(callbacks, DeleteCallback(path1)).Times(1);
1902 EXPECT_CALL(callbacks, DeleteCallback(path2)).Times(1);
1903
1904 auto cb2 = [&callbacks](const DataPointPath& path) { callbacks.DeleteCallback(path); };
1905
1906 auto cb1 = [&](const DataPointPath& path) {
1907 callbacks.DeleteCallback(path);
1909 req2.DeleteDataPoint(path2, cb2);
1910 repo->SendRequest(req2).Wait();
1911 };
1912
1913 SetupDataPoints();
1914
1916 req1.DeleteDataPoint(path1, cb1);
1917 repo->SendRequest(req1).Wait();
1918}
1919
1920TEST_F(Callbacks, DataPointExistsCallbackMustBeReentrant) {
1921 // Send a second DataPointExists request within the callback and make sure it completes,
1922 // i.e it does not deadlock.
1923 MockCallbacks callbacks;
1924 bool result1, result2;
1925
1926 // Since the second request is executed within the callback cb1, the order of the callbacks is
1927 // defined by the following sequence.
1928 testing::InSequence seq;
1929 EXPECT_CALL(callbacks, ExistsCallback(path1)).Times(1);
1930 EXPECT_CALL(callbacks, ExistsCallback(path2)).Times(1);
1931
1932 auto cb2 = [&callbacks](const DataPointPath& path) { callbacks.ExistsCallback(path); };
1933
1934 auto cb1 = [&](const DataPointPath& path) {
1935 callbacks.ExistsCallback(path);
1937 req2.DataPointExists(path2, result2, cb2);
1938 repo->SendRequest(req2).Wait();
1939 };
1940
1941 SetupDataPoints();
1942
1944 req1.DataPointExists(path1, result1, cb1);
1945 repo->SendRequest(req1).Wait();
1946}
1947
1948TEST_F(Callbacks, GetChildrenCallbackMustBeReentrant) {
1949 // Send a second GetChildren request within the callback and make sure it completes,
1950 // i.e it does not deadlock.
1951 MockCallbacks callbacks;
1953 std::pair<PathList, PathList> result1, result2;
1954
1955 // Since the second request is executed within the callback cb1, the order of the callbacks is
1956 // defined by the following sequence.
1957 testing::InSequence seq;
1958 EXPECT_CALL(callbacks, GetChildrenCallback(path1)).Times(1);
1959 EXPECT_CALL(callbacks, GetChildrenCallback(path2)).Times(1);
1960
1961 auto cb2 = [&callbacks](const DataPointPath& path) { callbacks.GetChildrenCallback(path); };
1962
1963 auto cb1 = [&](const DataPointPath& path) {
1964 callbacks.GetChildrenCallback(path);
1966 req2.GetChildren(path2, result2, false, cb2);
1967 repo->SendRequest(req2).Wait();
1968 };
1969
1970 SetupDataPoints();
1971
1973 req1.GetChildren(path1, result1, true, cb1);
1974 repo->SendRequest(req1).Wait();
1975}
1976
1977TEST_F(Callbacks, WriteDataPointCallbackMustBeReentrant) {
1978 // Send a second WriteDataPoint request within the callback and make sure it completes,
1979 // i.e it does not deadlock.
1980 MockCallbacks callbacks;
1981 RtcInt64 buffer1 = 1;
1982 RtcInt64 buffer2 = 2;
1983
1984 // Since the second request is executed within the callback cb1, the order of the callbacks is
1985 // defined by the following sequence.
1986 testing::InSequence seq;
1987 EXPECT_CALL(callbacks, WriteCallback(path1)).Times(1);
1988 EXPECT_CALL(callbacks, WriteCallback(path2)).Times(1);
1989
1990 auto cb2 = [&callbacks](const DataPointPath& path) { callbacks.WriteCallback(path); };
1991
1992 auto cb1 = [&](const DataPointPath& path) {
1993 callbacks.WriteCallback(path);
1995 req2.WriteDataPoint(path2, buffer2, std::nullopt, cb2);
1996 repo->SendRequest(req2).Wait();
1997 };
1998
1999 SetupDataPoints();
2000
2002 req1.WriteDataPoint(path1, buffer1, std::nullopt, cb1);
2003 repo->SendRequest(req1).Wait();
2004}
2005
2006TEST_F(Callbacks, ReadDataPointCallbackMustBeReentrant) {
2007 // Send a second ReadDataPoint request within the callback and make sure it completes,
2008 // i.e it does not deadlock.
2009 MockCallbacks callbacks;
2010 RtcInt64 result1, result2;
2011
2012 // Since the second request is executed within the callback cb1, the order of the callbacks is
2013 // defined by the following sequence.
2014 testing::InSequence seq;
2015 EXPECT_CALL(callbacks, ReadCallback(path1)).Times(1);
2016 EXPECT_CALL(callbacks, ReadCallback(path2)).Times(1);
2017
2018 auto cb2 = [&callbacks](const DataPointPath& path) { callbacks.ReadCallback(path); };
2019
2020 auto cb1 = [&](const DataPointPath& path) {
2021 callbacks.ReadCallback(path);
2023 req2.ReadDataPoint(path2, result2, std::nullopt, cb2);
2024 repo->SendRequest(req2).Wait();
2025 };
2026
2027 SetupDataPoints();
2028
2030 req1.ReadDataPoint(path1, result1, std::nullopt, cb1);
2031 repo->SendRequest(req1).Wait();
2032}
2033
2034TEST_F(Callbacks, PartialWriteDataPointCallbackMustBeReentrant) {
2035 // Send a second PartialWriteDataPoint request within the callback and make sure it completes,
2036 // i.e it does not deadlock.
2037 MockCallbacks callbacks;
2038 RtcVectorInt64 buffer1{1, 2};
2039 RtcVectorInt64 buffer2{3, 4};
2040
2041 // Since the second request is executed within the callback cb1, the order of the callbacks is
2042 // defined by the following sequence.
2043 testing::InSequence seq;
2044 EXPECT_CALL(callbacks, WriteCallback(path1)).Times(1);
2045 EXPECT_CALL(callbacks, WriteCallback(path2)).Times(1);
2046
2047 auto cb2 = [&callbacks](const DataPointPath& path) { callbacks.WriteCallback(path); };
2048
2049 auto cb1 = [&](const DataPointPath& path) {
2050 callbacks.WriteCallback(path);
2052 req2.PartialWriteDataPoint(path2, buffer2, 0, 2, 0, std::nullopt, cb2);
2053 repo->SendRequest(req2).Wait();
2054 };
2055
2056 SetupDataPoints(RtcVectorInt64{0, 0});
2057
2059 req1.PartialWriteDataPoint(path1, buffer1, 0, 2, 0, std::nullopt, cb1);
2060 repo->SendRequest(req1).Wait();
2061}
2062
2063TEST_F(Callbacks, PartialReadDataPointCallbackMustBeReentrant) {
2064 // Send a second PartialReadDataPoint request within the callback and make sure it completes,
2065 // i.e it does not deadlock.
2066 MockCallbacks callbacks;
2067 RtcVectorInt64 result1{0, 0};
2068 RtcVectorInt64 result2{0, 0};
2069
2070 // Since the second request is executed within the callback cb1, the order of the callbacks is
2071 // defined by the following sequence.
2072 testing::InSequence seq;
2073 EXPECT_CALL(callbacks, ReadCallback(path1)).Times(1);
2074 EXPECT_CALL(callbacks, ReadCallback(path2)).Times(1);
2075
2076 auto cb2 = [&callbacks](const DataPointPath& path) { callbacks.ReadCallback(path); };
2077
2078 auto cb1 = [&](const DataPointPath& path) {
2079 callbacks.ReadCallback(path);
2081 req2.PartialReadDataPoint(path2, result2, 0, 2, 0, std::nullopt, cb2);
2082 repo->SendRequest(req2).Wait();
2083 };
2084
2085 SetupDataPoints(RtcVectorInt64{1, 2});
2086
2088 req1.PartialReadDataPoint(path1, result1, 0, 2, 0, std::nullopt, cb1);
2089 repo->SendRequest(req1).Wait();
2090}
2091
2092TEST_F(Callbacks, WriteMetaDataCallbackMustBeReentrant) {
2093 // Send a second WriteMetaData request within the callback and make sure it completes,
2094 // i.e it does not deadlock.
2095 MockCallbacks callbacks;
2096 RepositoryIf::MetaData metadata1, metadata2;
2097 metadata1["comment"] = std::string{"foo"};
2098 metadata2["comment"] = std::string{"bar"};
2099
2100 // Since the second request is executed within the callback cb1, the order of the callbacks is
2101 // defined by the following sequence.
2102 testing::InSequence seq;
2103 EXPECT_CALL(callbacks, WriteCallback(path1)).Times(1);
2104 EXPECT_CALL(callbacks, WriteCallback(path2)).Times(1);
2105
2106 auto cb2 = [&callbacks](const DataPointPath& path) { callbacks.WriteCallback(path); };
2107
2108 auto cb1 = [&](const DataPointPath& path) {
2109 callbacks.WriteCallback(path);
2111 req2.WriteMetaData(path2, metadata2, cb2);
2112 repo->SendRequest(req2).Wait();
2113 };
2114
2115 SetupDataPoints();
2116
2118 req1.WriteMetaData(path1, metadata1, cb1);
2119 repo->SendRequest(req1).Wait();
2120}
2121
2122TEST_F(Callbacks, ReadMetaDataCallbackMustBeReentrant) {
2123 // Send a second ReadMetaData request within the callback and make sure it completes,
2124 // i.e it does not deadlock.
2125 MockCallbacks callbacks;
2126 RepositoryIf::MetaData result1, result2;
2127
2128 // Since the second request is executed within the callback cb1, the order of the callbacks is
2129 // defined by the following sequence.
2130 testing::InSequence seq;
2131 EXPECT_CALL(callbacks, ReadCallback(path1)).Times(1);
2132 EXPECT_CALL(callbacks, ReadCallback(path2)).Times(1);
2133
2134 auto cb2 = [&callbacks](const DataPointPath& path) { callbacks.ReadCallback(path); };
2135
2136 auto cb1 = [&](const DataPointPath& path) {
2137 callbacks.ReadCallback(path);
2139 req2.ReadMetaData(path2, result2, cb2);
2140 repo->SendRequest(req2).Wait();
2141 };
2142
2143 SetupDataPoints();
2144
2146 req1.ReadMetaData(path1, result1, cb1);
2147 repo->SendRequest(req1).Wait();
2148}
2149
2150TEST_F(Callbacks, CreateSymlinkCallbackMustBeReentrant) {
2151 // Send a second CreateSymlink request within the callback and make sure it completes,
2152 // i.e it does not deadlock.
2153 MockCallbacks callbacks;
2154
2155 // Since the second request is executed within the callback cb1, the order of the callbacks is
2156 // defined by the following sequence.
2157 testing::InSequence seq;
2158 EXPECT_CALL(callbacks, CreateSymlinkCallback(link1)).Times(1);
2159 EXPECT_CALL(callbacks, CreateSymlinkCallback(link2)).Times(1);
2160
2161 auto cb2 = [&callbacks](const DataPointPath& path) { callbacks.CreateSymlinkCallback(path); };
2162
2163 auto cb1 = [&](const DataPointPath& path) {
2164 callbacks.CreateSymlinkCallback(path);
2166 req2.CreateSymlink(path2, "/link2"_dppath, cb2);
2167 repo->SendRequest(req2).Wait();
2168 };
2169
2170 SetupDataPoints();
2171
2173 req1.CreateSymlink(path1, "/link1"_dppath, cb1);
2174 repo->SendRequest(req1).Wait();
2175}
2176
2177TEST_F(Callbacks, UpdateSymlinkCallbackMustBeReentrant) {
2178 // Send a second UpdateSymlink request within the callback and make sure it completes,
2179 // i.e it does not deadlock.
2180 MockCallbacks callbacks;
2181 RepositoryIf::MetaData result1, result2;
2182
2183 // Since the second request is executed within the callback cb1, the order of the callbacks is
2184 // defined by the following sequence.
2185 testing::InSequence seq;
2186 EXPECT_CALL(callbacks, UpdateSymlinkCallback(link1)).Times(1);
2187 EXPECT_CALL(callbacks, UpdateSymlinkCallback(link2)).Times(1);
2188
2189 auto cb2 = [&callbacks](const DataPointPath& path) { callbacks.UpdateSymlinkCallback(path); };
2190
2191 auto cb1 = [&](const DataPointPath& path) {
2192 callbacks.UpdateSymlinkCallback(path);
2194 req2.UpdateSymlink(path2, "/link2"_dppath, cb2);
2195 repo->SendRequest(req2).Wait();
2196 };
2197
2198 SetupDataPoints();
2200 req0.CreateSymlink(path1, "/link1"_dppath);
2201 req0.CreateSymlink(path2, "/link2"_dppath);
2202 repo->SendRequest(req0).Wait();
2203
2205 // The updates will swap the targets of the two links.
2206 req1.UpdateSymlink(path1, "/link1"_dppath, cb1);
2207 repo->SendRequest(req1).Wait();
2208}
2209
2211
2212class GetChildren : public testing::Test {
2213public:
2214 void SetUp() override {
2215 repo = MakeRepository();
2216 repo->CreateDataPoint("/topdir/datapoint1"_dppath, 0);
2217 repo->CreateDataPoint("/topdir/subdir1/datapoint2"_dppath, 0);
2218 repo->CreateDataPoint("/topdir/subdir1/datapoint3"_dppath, 0);
2219 repo->CreateDataPoint("/topdir/subdir2/datapoint4"_dppath, 0);
2220 repo->CreateDataPoint("/topdir/subdir21/datapoint5"_dppath, 0);
2221 }
2222
2223 void TearDown() override {
2224 if (repo->DataPointExists("/topdir/datapoint1"_dppath)) {
2225 repo->DeleteDataPoint("/topdir/datapoint1"_dppath);
2226 }
2227 if (repo->DataPointExists("/topdir/subdir1/datapoint2"_dppath)) {
2228 repo->DeleteDataPoint("/topdir/subdir1/datapoint2"_dppath);
2229 }
2230 if (repo->DataPointExists("/topdir/subdir1/datapoint2"_dppath)) {
2231 repo->DeleteDataPoint("/topdir/subdir1/datapoint2"_dppath);
2232 }
2233 if (repo->DataPointExists("/topdir/subdir1/datapoint3"_dppath)) {
2234 repo->DeleteDataPoint("/topdir/subdir1/datapoint3"_dppath);
2235 }
2236 if (repo->DataPointExists("/topdir/subdir2/datapoint4"_dppath)) {
2237 repo->DeleteDataPoint("/topdir/subdir2/datapoint4"_dppath);
2238 }
2239 if (repo->DataPointExists("/topdir/subdir21/datapoint5"_dppath)) {
2240 repo->DeleteDataPoint("/topdir/subdir21/datapoint5"_dppath);
2241 }
2242 }
2243
2244protected:
2245 std::shared_ptr<RepositoryIf> repo;
2246};
2247
2248TEST_F(GetChildren, FromRootDir) {
2249 auto [dps, paths] = repo->GetChildren("/"_dppath);
2250 EXPECT_THAT(dps, IsEmpty());
2251 EXPECT_THAT(paths, UnorderedElementsAreArray({"/topdir"_dppath}));
2252}
2253
2254TEST_F(GetChildren, FromTopDir) {
2255 auto [dps, paths] = repo->GetChildren("/topdir"_dppath);
2256 EXPECT_THAT(dps, UnorderedElementsAreArray({"/topdir/datapoint1"_dppath}));
2257 EXPECT_THAT(
2258 paths,
2259 UnorderedElementsAreArray(
2260 {"/topdir/subdir1"_dppath, "/topdir/subdir2"_dppath, "/topdir/subdir21"_dppath}));
2261}
2262
2263TEST_F(GetChildren, FromSubDir1) {
2264 auto [dps, paths] = repo->GetChildren("/topdir/subdir1"_dppath);
2265 EXPECT_THAT(dps,
2266 UnorderedElementsAreArray(
2267 {"/topdir/subdir1/datapoint2"_dppath, "/topdir/subdir1/datapoint3"_dppath}));
2268 EXPECT_THAT(paths, IsEmpty());
2269}
2270
2271TEST_F(GetChildren, FromSubDir2) {
2272 auto [dps, paths] = repo->GetChildren("/topdir/subdir2"_dppath);
2273 EXPECT_THAT(dps, UnorderedElementsAreArray({"/topdir/subdir2/datapoint4"_dppath}));
2274 EXPECT_THAT(paths, IsEmpty());
2275}
2276
2277TEST_F(GetChildren, NoChildrenForExistingDataPoint) {
2278 auto [dps, paths] = repo->GetChildren("/topdir/datapoint1"_dppath);
2279 EXPECT_THAT(dps, IsEmpty());
2280 EXPECT_THAT(paths, IsEmpty());
2281}
2282
2283TEST_F(GetChildren, NoChildrenForNonExistingDataPoint) {
2284 auto [dps, paths] = repo->GetChildren("/does/not/exist"_dppath);
2285 EXPECT_THAT(dps, IsEmpty());
2286 EXPECT_THAT(paths, IsEmpty());
2287}
2288
2289TEST_F(GetChildren, RecursiveFromRootDir) {
2290 auto [dps, paths] = repo->GetChildren("/"_dppath, true);
2291 EXPECT_THAT(dps,
2292 UnorderedElementsAreArray({"/topdir/datapoint1"_dppath,
2293 "/topdir/subdir1/datapoint2"_dppath,
2294 "/topdir/subdir1/datapoint3"_dppath,
2295 "/topdir/subdir2/datapoint4"_dppath,
2296 "/topdir/subdir21/datapoint5"_dppath}));
2297 EXPECT_THAT(paths,
2298 UnorderedElementsAreArray({"/topdir"_dppath,
2299 "/topdir/subdir1"_dppath,
2300 "/topdir/subdir2"_dppath,
2301 "/topdir/subdir21"_dppath}));
2302}
2303
2304TEST_F(GetChildren, DeleteRecursiveFromRootDir) {
2305 repo->DeleteDataPoint("/"_dppath, true);
2306
2307 auto [dps, paths] = repo->GetChildren("/"_dppath, true);
2308 EXPECT_THAT(dps, IsEmpty());
2309 EXPECT_THAT(paths, IsEmpty());
2310}
2311
2312TEST_F(GetChildren, DeleteRecursiveFromTopDir) {
2313 repo->DeleteDataPoint("/topdir"_dppath, true);
2314
2315 auto [dps, paths] = repo->GetChildren("/"_dppath, true);
2316 EXPECT_THAT(dps, IsEmpty());
2317 EXPECT_THAT(paths, IsEmpty());
2318}
2319
2320TEST_F(GetChildren, DeleteRecursiveFromSubDir2) {
2321 repo->DeleteDataPoint("/topdir/subdir2"_dppath, true);
2322
2323 auto [dps, paths] = repo->GetChildren("/"_dppath, true);
2324 EXPECT_THAT(dps,
2325 UnorderedElementsAreArray({"/topdir/datapoint1"_dppath,
2326 "/topdir/subdir1/datapoint2"_dppath,
2327 "/topdir/subdir1/datapoint3"_dppath,
2328 "/topdir/subdir21/datapoint5"_dppath}));
2329 EXPECT_THAT(paths,
2330 UnorderedElementsAreArray(
2331 {"/topdir"_dppath, "/topdir/subdir1"_dppath, "/topdir/subdir21"_dppath}));
2332}
2333
2335
2336class Metadata : public testing::Test {
2337public:
2338 void SetUp() override {
2339 repo = MakeRepository();
2340 path = "/foo"_dppath;
2341 }
2342
2343 void TearDown() override {
2344 if (repo->DataPointExists(path)) {
2345 repo->DeleteDataPoint(path);
2346 }
2347 }
2348
2349protected:
2350 std::shared_ptr<RepositoryIf> repo;
2352};
2353
2354TEST_F(Metadata, CreateDataPointWithMetadata) {
2355 auto t_start = RepositoryIf::Timestamp{};
2356 int initial_value = 0;
2357
2359 md["timestamp"] = t_start;
2360 md["comment"] = std::string{"some comment"};
2361 md["units"] = std::string{"bar"};
2362
2363 RepositoryIf::MetaData md_read;
2365 req.CreateDataPoint(path, initial_value, md);
2366 req.ReadMetaData(path, md_read);
2367 repo->SendRequest(req).Wait();
2368
2369 ASSERT_TRUE(md_read.Contains("type"));
2370 ASSERT_TRUE(md_read.Contains("shape"));
2371 ASSERT_TRUE(md_read.Contains("timestamp"));
2372 ASSERT_TRUE(md_read.Contains("comment"));
2373 ASSERT_TRUE(md_read.Contains("units"));
2374
2375 EXPECT_TRUE(md_read["type"].Cast<const std::type_info&>() == typeid(int));
2376 EXPECT_EQ(md_read["shape"].Cast<RtcVectorUInt64>(), RtcVectorUInt64{});
2377 EXPECT_EQ(md_read["timestamp"].Cast<RepositoryIf::Timestamp>(), t_start);
2378 EXPECT_EQ(md_read["comment"].Cast<std::string>(), std::string{"some comment"});
2379 EXPECT_EQ(md_read["units"].Cast<std::string>(), std::string{"bar"});
2380}
2381
2382TEST_F(Metadata, WriteDataPointWithMetadata) {
2383 auto t_start = RepositoryIf::Timestamp{};
2384 int initial_value = 0;
2385
2387 md["timestamp"] = t_start;
2388 md["comment"] = std::string{"some comment"};
2389 md["units"] = std::string{"bar"};
2390
2391 RepositoryIf::MetaData md_read;
2393 req.CreateDataPoint(path, initial_value);
2394 req.WriteDataPoint(path, initial_value, md);
2395 req.ReadMetaData(path, md_read);
2396 repo->SendRequest(req).Wait();
2397
2398 ASSERT_TRUE(md_read.Contains("timestamp"));
2399 ASSERT_TRUE(md_read.Contains("comment"));
2400 ASSERT_TRUE(md_read.Contains("units"));
2401
2402 EXPECT_EQ(md_read["timestamp"].Cast<RepositoryIf::Timestamp>(), t_start);
2403 EXPECT_EQ(md_read["comment"].Cast<std::string>(), std::string{"some comment"});
2404 EXPECT_EQ(md_read["units"].Cast<std::string>(), std::string{"bar"});
2405}
2406
2407TEST_F(Metadata, ReadDataPointWithMetadata) {
2408 auto t_start = RepositoryIf::Timestamp{};
2409 int initial_value = 0;
2410 int read_value = 1;
2411
2413 md["timestamp"] = t_start;
2414 md["comment"] = std::string{"some comment"};
2415 md["units"] = std::string{"bar"};
2416
2417 RepositoryIf::MetaData md_read;
2419 req.CreateDataPoint(path, initial_value, md);
2420 req.ReadDataPoint(path, read_value, md_read);
2421 repo->SendRequest(req).Wait();
2422
2423 ASSERT_TRUE(md_read.Contains("type"));
2424 ASSERT_TRUE(md_read.Contains("shape"));
2425 ASSERT_TRUE(md_read.Contains("timestamp"));
2426 ASSERT_TRUE(md_read.Contains("comment"));
2427 ASSERT_TRUE(md_read.Contains("units"));
2428
2429 EXPECT_EQ(md_read["timestamp"].Cast<RepositoryIf::Timestamp>(), t_start);
2430 EXPECT_EQ(md_read["comment"].Cast<std::string>(), std::string{"some comment"});
2431 EXPECT_EQ(md_read["units"].Cast<std::string>(), std::string{"bar"});
2432 EXPECT_TRUE(md_read["type"].Cast<const std::type_info&>() == typeid(int));
2433 EXPECT_EQ(md_read["shape"].Cast<RtcVectorUInt64>(), RtcVectorUInt64{});
2434}
2435
2436TEST_F(Metadata, WriteMetadataOnly) {
2437 int initial_value = 0;
2438
2440 md["comment"] = std::string{"some comment"};
2441 md["units"] = std::string{"bar"};
2442
2443 RepositoryIf::MetaData md_read;
2445 req.CreateDataPoint(path, initial_value);
2446 req.WriteMetaData(path, md);
2447 req.ReadMetaData(path, md_read);
2448 repo->SendRequest(req).Wait();
2449
2450 ASSERT_TRUE(md_read.Contains("comment"));
2451 ASSERT_TRUE(md_read.Contains("units"));
2452
2453 EXPECT_EQ(md_read["comment"].Cast<std::string>(), std::string{"some comment"});
2454 EXPECT_EQ(md_read["units"].Cast<std::string>(), std::string{"bar"});
2455}
2456
2457TEST_F(Metadata, UserMetadata) {
2458 {
2459 int int_create = 0;
2460 RepositoryIf::MetaData metadata;
2461 metadata["min"] = static_cast<int>(-3);
2462 metadata["max"] = static_cast<int>(3);
2463 metadata["text"] = std::string{"This is a custom text description."};
2464 RepositoryIf::MetaData metadata_read;
2466 req.CreateDataPoint(path, int_create, metadata);
2467 req.ReadMetaData(path, metadata_read);
2468 repo->SendRequest(req).Wait();
2469 ASSERT_TRUE(metadata_read.Contains("min"));
2470 ASSERT_TRUE(metadata_read.Contains("max"));
2471 EXPECT_EQ(metadata_read["min"].Cast<int>(), -3);
2472 EXPECT_EQ(metadata_read["max"].Cast<int>(), 3);
2473 EXPECT_EQ(metadata_read["text"].Cast<std::string>(), metadata["text"].Cast<std::string>());
2474 }
2475
2476 {
2477 RepositoryIf::MetaData metadata;
2478 metadata["min"] = static_cast<int>(-5);
2479 metadata["max"] = static_cast<int>(5);
2480 metadata["text"] = std::string{"This is another description."};
2481 metadata["new_field"] = std::string{"A new field added."};
2482 RepositoryIf::MetaData metadata_read;
2484 req.WriteMetaData(path, metadata);
2485 req.ReadMetaData(path, metadata_read);
2486 repo->SendRequest(req).Wait();
2487 ASSERT_TRUE(metadata_read.Contains("min"));
2488 ASSERT_TRUE(metadata_read.Contains("max"));
2489 EXPECT_EQ(metadata_read["min"].Cast<int>(), -5);
2490 EXPECT_EQ(metadata_read["max"].Cast<int>(), 5);
2491 EXPECT_EQ(metadata_read["text"].Cast<std::string>(), metadata["text"].Cast<std::string>());
2492 }
2493
2494 {
2495 int int_write = 3;
2496 RepositoryIf::MetaData metadata;
2497 metadata["min"] = static_cast<int>(-7);
2498 metadata["max"] = static_cast<int>(7);
2499 metadata["text"] = std::string{"This is a description."};
2500 metadata.Remove("new_field");
2501 RepositoryIf::MetaData metadata_read;
2503 req.WriteDataPoint(path, int_write, metadata);
2504 req.ReadMetaData(path, metadata_read);
2505 repo->SendRequest(req).Wait();
2506 ASSERT_TRUE(metadata_read.Contains("min"));
2507 ASSERT_TRUE(metadata_read.Contains("max"));
2508 EXPECT_EQ(metadata_read["min"].Cast<int>(), -7);
2509 EXPECT_EQ(metadata_read["max"].Cast<int>(), 7);
2510 EXPECT_EQ(metadata_read["text"].Cast<std::string>(), metadata["text"].Cast<std::string>());
2511 }
2512
2513 {
2514 int int_write = 3;
2515 int int_read = 0;
2516 RepositoryIf::MetaData metadata;
2517 metadata["min"] = static_cast<int>(-9);
2518 metadata["max"] = static_cast<int>(9);
2519 metadata["text"] = std::string{"A description.\nBut on two lines."};
2520 metadata["new_field"] = static_cast<int>(9);
2521 RepositoryIf::MetaData metadata_read;
2523 req.WriteDataPoint(path, int_write, metadata);
2524 req.ReadDataPoint(path, int_read, metadata_read);
2525 repo->SendRequest(req).Wait();
2526 ASSERT_TRUE(metadata_read.Contains("min"));
2527 ASSERT_TRUE(metadata_read.Contains("max"));
2528 EXPECT_EQ(metadata_read["min"].Cast<int>(), -9);
2529 EXPECT_EQ(metadata_read["max"].Cast<int>(), 9);
2530 EXPECT_EQ(metadata_read["text"].Cast<std::string>(), metadata["text"].Cast<std::string>());
2531 }
2532}
2533
2535
2536class Symlinks : public testing::Test {
2537public:
2538 void SetUp() override {
2539 repo = MakeRepository();
2540 target_path = "/foo"_dppath;
2541 target_path_2 = "/bar"_dppath;
2542 }
2543
2544 void TearDown() override {
2545 if (repo->DataPointExists(target_path)) {
2546 repo->DeleteDataPoint(target_path);
2547 }
2548 if (repo->DataPointExists(target_path_2)) {
2549 repo->DeleteDataPoint(target_path_2);
2550 }
2551 if (repo->DataPointExists("/links/foo"_dppath)) {
2552 repo->DeleteDataPoint("/links/foo"_dppath);
2553 }
2554 if (repo->DataPointExists("/links/bar"_dppath)) {
2555 repo->DeleteDataPoint("/links/bar"_dppath);
2556 }
2557 }
2558
2559protected:
2560 std::shared_ptr<RepositoryIf> repo;
2563};
2564
2565TEST_F(Symlinks, BasicPattern) {
2566 int int_create = 0;
2567 int int_read = 0;
2568 int int_read_2 = 0;
2569 int int_write = 4;
2570 bool foo_exists = false;
2571 bool bar_exists = false;
2572 bool foo_exists_later = false;
2573 bool bar_exists_later = false;
2574
2575 repo->CreateDataPoint(target_path, int_create);
2576
2578 req.CreateSymlink(target_path, "/links/foo1"_dppath);
2579 req.CreateSymlink(target_path, "/links/bar"_dppath);
2580 req.DataPointExists("/links/foo1"_dppath, foo_exists);
2581 req.DataPointExists("/links/bar"_dppath, bar_exists);
2582 req.ReadDataPoint("/links/foo1"_dppath, int_read);
2583 req.WriteDataPoint("/links/bar"_dppath, int_write);
2584 req.ReadDataPoint("/links/foo1"_dppath, int_read_2);
2585 req.DeleteDataPoint("/links/foo1"_dppath);
2586 req.DeleteDataPoint("/links/bar"_dppath);
2587 req.DataPointExists("/links/foo1"_dppath, foo_exists_later);
2588 req.DataPointExists("/links/bar"_dppath, bar_exists_later);
2589 repo->SendRequest(req).Wait();
2590
2591 EXPECT_TRUE(foo_exists);
2592 EXPECT_TRUE(bar_exists);
2593 EXPECT_EQ(int_read, 0);
2594 EXPECT_EQ(int_read_2, 4);
2595 EXPECT_FALSE(foo_exists_later);
2596 EXPECT_FALSE(bar_exists_later);
2597}
2598
2599TEST_F(Symlinks, AdvancedPattern) {
2600 int int_create = 0;
2601 int int_read = 0;
2602 int int_read_2 = 0;
2603 int int_write = 4;
2605 RepositoryIf::MetaData md_dp_later;
2606 RepositoryIf::MetaData md_link;
2607 bool exists = false;
2608 std::set<DataPointPath> links_2;
2609
2611 repo->CreateDataPoint(target_path, int_create);
2612 req.CreateSymlink(target_path, "/links/foo"_dppath);
2613 req.CreateSymlink(target_path, "/links/bar"_dppath);
2614 req.ReadMetaData(target_path, md_dp);
2615 req.ReadMetaData("/links/foo"_dppath, md_link);
2616 req.ReadDataPoint("/links/foo"_dppath, int_read);
2617 req.WriteDataPoint("/links/bar"_dppath, int_write);
2618 req.ReadDataPoint("/links/foo"_dppath, int_read_2);
2619 req.DeleteDataPoint("/links/foo"_dppath);
2620 req.DeleteDataPoint("/links/bar"_dppath);
2621 req.ReadMetaData(target_path, md_dp_later);
2622 req.DataPointExists(target_path, exists);
2623 repo->SendRequest(req).Wait();
2624
2625 EXPECT_FALSE(md_dp.Contains("symlink_target"));
2626 EXPECT_TRUE(md_link.Contains("symlink_target"));
2627 EXPECT_EQ(md_link["symlink_target"].Cast<DataPointPath>(), DataPointPath{"/foo"});
2628
2629 EXPECT_EQ(int_read, 0);
2630 EXPECT_EQ(int_read_2, 4);
2631 EXPECT_TRUE(exists);
2632}
2633
2634TEST_F(Symlinks, LinksCanBeDeletedLikeRegularDataPoints) {
2635 DataPointPath link_path = "/links/foo"_dppath;
2636 int int_create = 0;
2637 bool link_exists_1 = false;
2638 bool link_exists_2 = true;
2639
2641 req.CreateDataPoint(target_path, int_create);
2642 req.CreateSymlink(target_path, link_path);
2643 req.DataPointExists(link_path, link_exists_1);
2644 req.DeleteDataPoint(link_path);
2645 req.DataPointExists(link_path, link_exists_2);
2646 repo->SendRequest(req).Wait();
2647
2648 EXPECT_TRUE(link_exists_1);
2649 EXPECT_FALSE(link_exists_2);
2650}
2651
2652TEST_F(Symlinks, DanglingLinksCanBeCreatedAndDeleted) {
2653 DataPointPath link_path = "/links/foo"_dppath;
2654 int int_read = 1;
2655 bool link_exists = false;
2656
2657 {
2658 // start with dangling symlink
2660 req.CreateSymlink(target_path, link_path);
2661 req.DataPointExists(link_path, link_exists);
2662 repo->SendRequest(req).Wait();
2663
2664 // the link still exists
2665 EXPECT_TRUE(link_exists);
2666
2667 // but we are unable to access the underlying datapoint
2668 EXPECT_THROW(
2669 { repo->ReadDataPoint(link_path, int_read); }, RepositoryIf::DataPointDoesNotExist);
2670 }
2671
2672 // delete it
2673 EXPECT_NO_THROW(repo->DeleteDataPoint(link_path));
2674}
2675
2676TEST_F(Symlinks, DanglingLinksCanBeFixedByCreatingTarget) {
2677 DataPointPath link_path = "/links/foo"_dppath;
2678 int int_read = 1;
2679 bool link_exists = false;
2680
2681 {
2682 // start with dangling symlink
2684 req.CreateSymlink(target_path, link_path);
2685 req.DataPointExists(link_path, link_exists);
2686 repo->SendRequest(req).Wait();
2687
2688 // the link still exists
2689 EXPECT_TRUE(link_exists);
2690
2691 // but we are unable to access the underlying datapoint
2692 EXPECT_THROW(
2693 { repo->ReadDataPoint(link_path, int_read); }, RepositoryIf::DataPointDoesNotExist);
2694 }
2695
2696 // fix it by creating the target datapoint
2697 repo->CreateDataPoint(target_path, int_read);
2698
2699 // reading should work now
2700 EXPECT_NO_THROW(repo->ReadDataPoint(link_path, int_read));
2701}
2702
2703TEST_F(Symlinks, LinksCanBeUpdated) {
2704 DataPointPath link_path = "/links/foo"_dppath;
2705 DataPointPath dangling_target_path = "/dangling_target"_dppath;
2706 int int_read = 1;
2707 bool link_exists = false;
2708
2709 {
2710 // start with dangling symlink
2712 req.CreateSymlink(target_path, link_path);
2713 req.DataPointExists(link_path, link_exists);
2714 repo->SendRequest(req).Wait();
2715 }
2716
2717 {
2718 // point it to a different datapoint
2720 req.CreateDataPoint(target_path_2, int_read);
2721 req.UpdateSymlink(target_path_2, link_path);
2722 repo->SendRequest(req).Wait();
2723
2724 // reading should work now
2725 EXPECT_NO_THROW(repo->ReadDataPoint(link_path, int_read));
2726 }
2727
2728 {
2729 // make it dangle again
2731 req.UpdateSymlink(dangling_target_path, link_path);
2732 repo->SendRequest(req).Wait();
2733
2734 // reading should no longer work
2735 EXPECT_THROW(
2736 { repo->ReadDataPoint(link_path, int_read); }, RepositoryIf::DataPointDoesNotExist);
2737 }
2738}
2739
2740TEST_F(Symlinks, DanglingLinksStillExistAsDataPoints) {
2741 DataPointPath link_path = "/links/foo"_dppath;
2742 int int_create = 0;
2743 int int_read = 1;
2744 bool link_exists = false;
2746
2748 req.CreateDataPoint(target_path, int_create);
2749 req.CreateSymlink(target_path, link_path);
2750 req.DeleteDataPoint(target_path);
2751 req.DataPointExists(link_path, link_exists);
2752 repo->SendRequest(req).Wait();
2753
2754 // the link still exists
2755 EXPECT_TRUE(link_exists);
2756
2757 // but we are unable to access the underlying datapoint
2758 EXPECT_THROW(
2759 { repo->ReadDataPoint(link_path, int_read); }, RepositoryIf::DataPointDoesNotExist);
2760}
2761
2763
2764class ExceptionInterface : public testing::Test {
2765public:
2766 void SetUp() override {
2767 repo = MakeRepository();
2768 path = "/foo"_dppath;
2769 link_path = "/links/foo"_dppath;
2770 link_path2 = "/links/bar"_dppath;
2771 }
2772
2773 void TearDown() override {
2774 if (repo->DataPointExists(link_path)) {
2775 repo->DeleteDataPoint(link_path);
2776 }
2777 if (repo->DataPointExists(link_path2)) {
2778 repo->DeleteDataPoint(link_path2);
2779 }
2780 if (repo->DataPointExists(path)) {
2781 repo->DeleteDataPoint(path);
2782 }
2783 }
2784
2785protected:
2786 std::shared_ptr<RepositoryIf> repo;
2790};
2791
2792// TODO: This test is no longer compilable. Decide what to do.
2793/*
2794TEST_F(ExceptionInterface, CreateDataPointThrowsForUnsupportedDataType) {
2795 struct UnsupportedDataType {};
2796 UnsupportedDataType value;
2797
2798 ASSERT_FALSE(repo->DataPointExists(path));
2799
2800 EXPECT_ANY_THROW({ repo->CreateDataPoint(path, value); });
2801}
2802*/
2803
2804TEST_F(ExceptionInterface, MethodsThrowForNonAbsoluteDataPointPath) {
2805 auto invalid_path = "relative/dp/path"_dppath;
2806 auto value = 42;
2807
2808 EXPECT_THROW({ repo->DataPointExists(invalid_path); }, RepositoryIf::DataPointPathNotAbsolute);
2809
2810 EXPECT_THROW({ repo->GetDataPointType(invalid_path); }, RepositoryIf::DataPointPathNotAbsolute);
2811
2812 EXPECT_THROW(
2813 { repo->GetDataPointShape(invalid_path); }, RepositoryIf::DataPointPathNotAbsolute);
2814
2815 EXPECT_THROW({ repo->GetDataPointSize(invalid_path); }, RepositoryIf::DataPointPathNotAbsolute);
2816
2817 EXPECT_THROW({ repo->GetChildren(invalid_path); }, RepositoryIf::DataPointPathNotAbsolute);
2818
2819 EXPECT_THROW(
2820 { repo->CreateDataPoint(invalid_path, value); }, RepositoryIf::DataPointPathNotAbsolute);
2821
2822 EXPECT_THROW(
2823 { repo->WriteDataPoint(invalid_path, value); }, RepositoryIf::DataPointPathNotAbsolute);
2824
2825 EXPECT_THROW(
2826 { repo->ReadDataPoint(invalid_path, value); }, RepositoryIf::DataPointPathNotAbsolute);
2827
2828 EXPECT_THROW({ repo->DeleteDataPoint(invalid_path); }, RepositoryIf::DataPointPathNotAbsolute);
2829}
2830
2831TEST_F(ExceptionInterface, CreateDataPointThrowsForExistingDataPoint) {
2832 auto create_value = 42;
2833
2834 ASSERT_FALSE(repo->DataPointExists(path));
2835
2836 repo->CreateDataPoint(path, create_value);
2837 ASSERT_TRUE(repo->DataPointExists(path));
2838
2839 EXPECT_THROW(
2840 { repo->CreateDataPoint(path, create_value); }, RepositoryIf::DataPointAlreadyExists);
2841}
2842
2843TEST_F(ExceptionInterface, DeleteDataPointThrowsForNonExistingDataPoint) {
2844 ASSERT_FALSE(repo->DataPointExists(path));
2845
2846 EXPECT_THROW({ repo->DeleteDataPoint(path); }, RepositoryIf::DataPointDoesNotExist);
2847}
2848
2849TEST_F(ExceptionInterface, WriteDataPointThrowsIfDataPointDoesNotExist) {
2850 ASSERT_FALSE(repo->DataPointExists(path));
2851
2852 EXPECT_THROW({ repo->WriteDataPoint(path, 14); }, RepositoryIf::DataPointDoesNotExist);
2853}
2854
2855TEST_F(ExceptionInterface, WriteDataPointThrowsForIncompatibleDataType) {
2856 RtcInt64 int_buffer = 14;
2857 repo->CreateDataPoint(path, int_buffer);
2858
2859 RtcFloat float_buffer = 14.0;
2860 EXPECT_THROW({ repo->WriteDataPoint(path, float_buffer); }, RepositoryIf::IncompatibleType);
2861}
2862
2863TEST_F(ExceptionInterface, WriteDataPointThrowsForIncompatibleShape) {
2864 RtcInt64 int_buffer = 14;
2865 repo->CreateDataPoint(path, int_buffer);
2866
2867 RtcVectorInt64 vec_buffer = {15, 16};
2868 EXPECT_THROW({ repo->WriteDataPoint(path, vec_buffer); }, RepositoryIf::IncompatibleType);
2869
2870 RtcMatrixInt64 mat_buffer = {2, 2, {1, 2, 3, 4}};
2871 EXPECT_THROW({ repo->WriteDataPoint(path, mat_buffer); }, RepositoryIf::IncompatibleType);
2872}
2873
2874TEST_F(ExceptionInterface, ReadDataPointThrowsForIncompatibleDataType) {
2875 RtcInt64 int_buffer = 14;
2877 repo->CreateDataPoint(path, int_buffer);
2878
2879 RtcFloat float_buffer;
2880 EXPECT_THROW({ repo->ReadDataPoint(path, float_buffer); }, RepositoryIf::IncompatibleType);
2881}
2882
2883TEST_F(ExceptionInterface, ReadDataPointThrowsForIncompatibleShape) {
2884 RtcInt64 int_buffer = 14;
2885 repo->CreateDataPoint(path, int_buffer);
2886
2887 RtcVectorInt64 vec_buffer;
2888 EXPECT_THROW({ repo->ReadDataPoint(path, vec_buffer); }, RepositoryIf::IncompatibleType);
2889
2890 RtcMatrixInt64 mat_buffer;
2891 EXPECT_THROW({ repo->ReadDataPoint(path, mat_buffer); }, RepositoryIf::IncompatibleType);
2892}
2893
2894TEST_F(ExceptionInterface, ReadDataPointThrowsForTooSmallBuffer) {
2895 RtcVectorInt64 write_buffer(10);
2896 repo->CreateDataPoint(path, write_buffer);
2897
2898 gsl::span<RtcInt64> read_buffer(write_buffer);
2899 auto too_small_read_buffer = read_buffer.subspan(0, 5);
2900 EXPECT_THROW(
2901 { repo->ReadDataPoint(path, too_small_read_buffer); }, RepositoryIf::BufferTooSmall);
2902}
2903
2904TEST_F(ExceptionInterface, PartialWriteDataPointThrowsForOutOfBoundsAccess) {
2905 RtcVectorInt64 write_buffer(10);
2906 repo->CreateDataPoint(path, write_buffer);
2907
2908 RtcVectorInt64 vec_buffer = {1, 2, 3, 4};
2910 req.PartialWriteDataPoint(path, vec_buffer, 0, 4, 8);
2911 EXPECT_THROW({ repo->SendRequest(req).Wait(); }, RepositoryIf::AccessOutOfBounds);
2912}
2913
2914TEST_F(ExceptionInterface, PartialReadDataPointThrowsForOutOfBoundsAccess) {
2915 RtcVectorInt64 write_buffer(10);
2916 RtcVectorInt64 read_buffer(50);
2917 repo->CreateDataPoint(path, write_buffer);
2918
2920 req.PartialReadDataPoint(path, read_buffer, 0, 15, 0);
2921 EXPECT_THROW({ repo->SendRequest(req).Wait(); }, RepositoryIf::AccessOutOfBounds);
2922}
2923
2924TEST_F(ExceptionInterface, SetDataPointThrowsForNonExistingDatapoint) {
2925 EXPECT_THROW({ repo->SetDataPoint(path, 42); }, RepositoryIf::DataPointDoesNotExist);
2926}
2927
2928TEST_F(ExceptionInterface, GetDataPointThrowsForNonExistingDatapoint) {
2929 EXPECT_THROW({ repo->GetDataPoint<RtcInt64>(path); }, RepositoryIf::DataPointDoesNotExist);
2930}
2931
2932TEST_F(ExceptionInterface, GetDataPointTypeThrowsForNonExistingDatapoint) {
2933 EXPECT_THROW({ repo->GetDataPointType(path); }, RepositoryIf::DataPointDoesNotExist);
2934}
2935
2936TEST_F(ExceptionInterface, GetDataPointSizeThrowsForNonExistingDatapoint) {
2937 EXPECT_THROW({ repo->GetDataPointSize(path); }, RepositoryIf::DataPointDoesNotExist);
2938}
2939
2940TEST_F(ExceptionInterface, GetDataPointShapeThrowsForNonExistingDatapoint) {
2941 EXPECT_THROW({ repo->GetDataPointShape(path); }, RepositoryIf::DataPointDoesNotExist);
2942}
2943
2944TEST_F(ExceptionInterface, WriteMetaDataThrowsForNonExistingDatapoint) {
2945 ASSERT_FALSE(repo->DataPointExists(path));
2946
2947 RepositoryIf::MetaData metadata;
2949 req.WriteMetaData(path, metadata);
2950 EXPECT_THROW({ repo->SendRequest(req).Wait(); }, RepositoryIf::DataPointDoesNotExist);
2951}
2952
2953TEST_F(ExceptionInterface, ExceptionIsThrownDuringCreationWhenUnsupportedMetaDataTypeIsUsed) {
2954 ASSERT_FALSE(repo->DataPointExists(path));
2955
2956 struct UnsupportedMetaDataType {};
2957
2958 EXPECT_THROW(
2959 {
2960 UnsupportedMetaDataType new_value;
2961 RepositoryIf::MetaData metadata;
2962 metadata["min"] = std::make_any<UnsupportedMetaDataType>(new_value);
2963 int initial_value = 12;
2965 req.CreateDataPoint(path, initial_value, metadata);
2966 repo->SendRequest(req).Wait();
2967 },
2969}
2970
2971TEST_F(ExceptionInterface, ExceptionIsThrownDuringWritingWhenUnsupportedMetaDataTypeIsUsed) {
2972 ASSERT_FALSE(repo->DataPointExists(path));
2973
2974 repo->CreateDataPoint(path, 12);
2975
2976 struct UnsupportedMetaDataType {};
2977
2978 EXPECT_THROW(
2979 {
2980 UnsupportedMetaDataType new_value;
2981 RepositoryIf::MetaData metadata;
2982 metadata["min"] = std::make_any<UnsupportedMetaDataType>(new_value);
2984 req.WriteMetaData(path, metadata);
2985 repo->SendRequest(req).Wait();
2986 },
2988}
2989
2990TEST_F(ExceptionInterface, ReadMetaDataThrowsForNonExistingDatapoint) {
2991 ASSERT_FALSE(repo->DataPointExists(path));
2992
2993 RepositoryIf::MetaData metadata;
2995 req.ReadMetaData(path, metadata);
2996 EXPECT_THROW({ repo->SendRequest(req).Wait(); }, RepositoryIf::DataPointDoesNotExist);
2997}
2998
2999// TODO we did not conclude our discussion regarding links to links, for now they are disallowed
3000TEST_F(ExceptionInterface, CreatingSymlinkToSymlinkThrows) {
3001 ASSERT_FALSE(repo->DataPointExists(path));
3002 repo->CreateDataPoint(path, 42);
3003
3004 {
3006 req.CreateSymlink(path, link_path);
3007 repo->SendRequest(req).Wait();
3008 }
3009
3011 req.CreateSymlink(link_path, link_path2);
3012 EXPECT_THROW({ repo->SendRequest(req).Wait(); }, RepositoryIf::OperationNotAllowed);
3013}
3014
3015TEST_F(ExceptionInterface, UpdateSymlinkThrowsForNonExistingSymlink) {
3016 ASSERT_FALSE(repo->DataPointExists(path));
3017 repo->CreateDataPoint(path, 42);
3018
3020 req.UpdateSymlink(path, link_path);
3021 EXPECT_THROW({ repo->SendRequest(req).Wait(); }, RepositoryIf::DataPointDoesNotExist);
3022}
3023
3024TEST_F(ExceptionInterface, UpdateSymlinkToSymlinkCycleThrows) {
3025 ASSERT_FALSE(repo->DataPointExists(path));
3026 repo->CreateDataPoint(path, 42);
3027
3028 {
3030 req.CreateSymlink(path, link_path);
3031 req.CreateSymlink(path, link_path2);
3032 repo->SendRequest(req).Wait();
3033 }
3034
3035 {
3037 req.UpdateSymlink(link_path2, link_path);
3038 EXPECT_THROW({ repo->SendRequest(req).Wait(); }, RepositoryIf::OperationNotAllowed);
3039 }
3040}
3041
3042TEST_F(ExceptionInterface, WritingToDanglingSymlinkThrows) {
3043 {
3044 int initial_value = 0;
3046 req.CreateDataPoint(path, initial_value);
3047 req.CreateSymlink(path, link_path);
3048 req.DeleteDataPoint(path);
3049 repo->SendRequest(req).Wait();
3050 }
3051
3052 {
3053 int write_value = 0;
3055 req.WriteDataPoint(link_path, write_value);
3056 EXPECT_THROW({ repo->SendRequest(req).Wait(); }, RepositoryIf::DataPointDoesNotExist);
3057 }
3058}
3059
3060TEST_F(ExceptionInterface, ReadingFromDanglingSymlinkThrows) {
3061 int buffer = 0;
3062
3063 {
3065 req.CreateDataPoint(path, buffer);
3066 req.CreateSymlink(path, link_path);
3067 req.DeleteDataPoint(path);
3068 repo->SendRequest(req).Wait();
3069 }
3070
3071 {
3073 req.ReadDataPoint(link_path, buffer);
3074 EXPECT_THROW({ repo->SendRequest(req).Wait(); }, RepositoryIf::DataPointDoesNotExist);
3075 }
3076}
3077
3078TEST_F(ExceptionInterface, MultipleRequestFail) {
3079 bool exists = false;
3080 RtcInt64 value = 42;
3081
3083 req.DataPointExists(path, exists);
3084 req.WriteDataPoint(path, value);
3085 req.ReadDataPoint(path, value);
3086 req.DataPointExists(path, exists);
3087 try {
3088 repo->SendRequest(req).Wait();
3089 FAIL() << "Call did not throw";
3090 } catch (const RepositoryIf::MultipleRequestsFailed& ex) {
3091 const auto& info = ex.GetInfo();
3092 ASSERT_EQ(info.size(), 4);
3093
3098
3099 EXPECT_EQ(info[0].exception, nullptr);
3100 ASSERT_NE(info[1].exception, nullptr);
3101 ASSERT_NE(info[2].exception, nullptr);
3102 EXPECT_EQ(info[3].exception, nullptr);
3103
3104 EXPECT_THROW(std::rethrow_exception(info[1].exception),
3106 EXPECT_THROW(std::rethrow_exception(info[2].exception),
3108
3109 // std::cout << ex.what(); // just to show that what() is available as wel
3110
3111 } catch (...) {
3112 FAIL() << "Incorrect exception type";
3113 }
3114}
3115
3117
3118class MassiveParallelAccess : public testing::Test {
3119public:
3120 void SetUp() override {
3121 repo = MakeRepository();
3122 for (unsigned i = 0; i < 500; i++) {
3123 std::string name = fmt::format("/test/datapoint_{:0>2}", i);
3124 dp_paths.emplace_back(name);
3125 }
3126 }
3127
3128 void TearDown() override {
3129 for (const auto& path : dp_paths) {
3130 if (repo->DataPointExists(path)) {
3131 repo->DeleteDataPoint(path);
3132 }
3133 }
3134 }
3135
3136protected:
3137 std::shared_ptr<RepositoryIf> repo;
3138 std::vector<DataPointPath> dp_paths;
3139};
3140
3141TEST_F(MassiveParallelAccess, BasicCrudOperations) {
3142 // parallel creation
3143 {
3144 std::vector<std::future<void>> futures;
3145
3146 futures.reserve(dp_paths.size());
3147 for (unsigned i = 0; i < dp_paths.size(); i++) {
3148 futures.emplace_back(std::async(std::launch::async, [this, idx = i] {
3149 repo->CreateDataPoint(dp_paths[idx], idx);
3150 }));
3151 }
3152
3153 for (auto& f : futures) {
3154 ASSERT_NO_THROW({ f.get(); });
3155 }
3156 }
3157
3158 // parallel exists
3159 {
3160 std::vector<std::future<bool>> futures;
3161
3162 futures.reserve(dp_paths.size());
3163 for (unsigned i = 0; i < dp_paths.size(); i++) {
3164 futures.emplace_back(std::async(std::launch::async, [this, idx = i] {
3165 return repo->DataPointExists(dp_paths[idx]);
3166 }));
3167 }
3168
3169 for (auto& f : futures) {
3170 bool result = false;
3171 ASSERT_NO_THROW({ result = f.get(); });
3172 ASSERT_TRUE(result);
3173 }
3174 }
3175
3176 // parallel set
3177 {
3178 std::vector<std::future<void>> futures;
3179
3180 futures.reserve(dp_paths.size());
3181 for (unsigned i = 0; i < dp_paths.size(); i++) {
3182 futures.emplace_back(std::async(std::launch::async, [this, idx = i] {
3183 repo->SetDataPoint<unsigned>(dp_paths[idx], idx + 1);
3184 }));
3185 }
3186
3187 for (auto& f : futures) {
3188 ASSERT_NO_THROW({ f.get(); });
3189 }
3190 }
3191
3192 // parallel get
3193 {
3194 std::vector<std::future<unsigned>> futures;
3195
3196 futures.reserve(dp_paths.size());
3197 for (unsigned i = 0; i < dp_paths.size(); i++) {
3198 futures.emplace_back(std::async(std::launch::async, [this, idx = i] {
3199 return repo->GetDataPoint<unsigned>(dp_paths[idx]);
3200 }));
3201 }
3202
3203 for (unsigned i = 0; i < dp_paths.size(); i++) {
3204 unsigned result = 0;
3205 ASSERT_NO_THROW({ result = futures.at(i).get(); });
3206 EXPECT_EQ(result, i + 1);
3207 }
3208 }
3209
3210 // parallel deletion
3211 {
3212 std::vector<std::future<void>> futures;
3213
3214 futures.reserve(dp_paths.size());
3215 for (unsigned i = 0; i < dp_paths.size(); i++) {
3216 futures.emplace_back(std::async(
3217 std::launch::async, [this, idx = i] { repo->DeleteDataPoint(dp_paths[idx]); }));
3218 }
3219
3220 for (auto& f : futures) {
3221 ASSERT_NO_THROW({ f.get(); });
3222 }
3223 }
3224
3225 // parallel exists
3226 {
3227 std::vector<std::future<bool>> futures;
3228
3229 futures.reserve(dp_paths.size());
3230 for (unsigned i = 0; i < dp_paths.size(); i++) {
3231 futures.emplace_back(std::async(std::launch::async, [this, idx = i] {
3232 return repo->DataPointExists(dp_paths[idx]);
3233 }));
3234 }
3235
3236 for (auto& f : futures) {
3237 bool result = true;
3238 ASSERT_NO_THROW({ result = f.get(); });
3239 ASSERT_FALSE(result);
3240 }
3241 }
3242}
3243
3244TEST_F(MassiveParallelAccess, ParallelReadFromSameDatapointWithSameValue) {
3245 auto path = dp_paths[0];
3246 unsigned create_value = 42;
3247 repo->CreateDataPoint(path, create_value);
3248
3249 {
3250 std::vector<std::future<unsigned>> futures;
3251
3252 futures.reserve(500);
3253 for (unsigned i = 0; i < 500; i++) {
3254 futures.emplace_back(
3255 std::async(std::launch::async, [&] { return repo->GetDataPoint<unsigned>(path); }));
3256 }
3257
3258 for (auto& f : futures) {
3259 auto result = 0;
3260 ASSERT_NO_THROW({ result = f.get(); });
3261 EXPECT_EQ(result, create_value);
3262 }
3263 }
3264}
3265
3266TEST_F(MassiveParallelAccess, ParallelWriteToSameDatapointWithSameValue) {
3267 auto path = dp_paths[0];
3268 unsigned create_value = 42;
3269 repo->CreateDataPoint(path, create_value);
3270
3271 {
3272 std::vector<std::future<void>> futures;
3273
3274 futures.reserve(500);
3275 for (unsigned i = 0; i < 500; i++) {
3276 futures.emplace_back(
3277 std::async(std::launch::async, [&] { repo->SetDataPoint<unsigned>(path, 43); }));
3278 }
3279
3280 for (auto& f : futures) {
3281 ASSERT_NO_THROW({ f.get(); });
3282 }
3283 }
3284
3285 unsigned result;
3288 req.ReadDataPoint(path, result, md);
3289 repo->SendRequest(req).Wait();
3290
3291 EXPECT_EQ(result, 43);
3292 EXPECT_EQ(md["sequence_id"].Cast<RtcUInt64>(), 500);
3293}
3294
3295TEST_F(MassiveParallelAccess, ParallelInterleavingWritesToSameDatapointWithSameValue) {
3296 auto path = dp_paths[0];
3297 unsigned create_value = 42;
3298 repo->CreateDataPoint(path, create_value);
3299
3300 {
3301 std::vector<std::future<void>> futures;
3302
3303 futures.reserve(50);
3304 for (unsigned i = 0; i < 50; i++) {
3305 futures.emplace_back(std::async(std::launch::async, [&] {
3306 unsigned buffer = 43;
3308 for (unsigned j = 0; j < 10; j++) {
3309 req.WriteDataPoint(path, buffer);
3310 }
3311 repo->SendRequest(req).Wait();
3312 }));
3313 }
3314
3315 for (auto& f : futures) {
3316 ASSERT_NO_THROW({ f.get(); });
3317 }
3318 }
3319
3320 unsigned result;
3323 req.ReadDataPoint(path, result, md);
3324 repo->SendRequest(req).Wait();
3325
3326 EXPECT_EQ(result, 43);
3327 EXPECT_EQ(md["sequence_id"].Cast<RtcUInt64>(), 500);
3328}
3329
3330TEST_F(MassiveParallelAccess, ParallelInterleavingReadsFromSameDatapointWithSameValue) {
3331 auto path = dp_paths[0];
3332 unsigned create_value = 42;
3333 repo->CreateDataPoint(path, create_value);
3334
3335 {
3336 std::vector<std::future<unsigned>> futures;
3337
3338 futures.reserve(50);
3339 for (unsigned i = 0; i < 50; i++) {
3340 futures.emplace_back(std::async(std::launch::async, [&] {
3341 unsigned buffer = 0;
3343 req.ReadDataPoint(path, buffer);
3344 req.ReadDataPoint(path, buffer);
3345 req.ReadDataPoint(path, buffer);
3346 req.ReadDataPoint(path, buffer);
3347 req.ReadDataPoint(path, buffer);
3348 req.ReadDataPoint(path, buffer);
3349 req.ReadDataPoint(path, buffer);
3350 req.ReadDataPoint(path, buffer);
3351 req.ReadDataPoint(path, buffer);
3352 req.ReadDataPoint(path, buffer);
3353 repo->SendRequest(req).Wait();
3354 return buffer;
3355 }));
3356 }
3357
3358 for (auto& f : futures) {
3359 unsigned result = 0;
3360 ASSERT_NO_THROW({ result = f.get(); });
3361 EXPECT_EQ(result, 42);
3362 }
3363 }
3364}
3365
3367
3368class CustomTypeHandling : public testing::Test {
3369public:
3370 void SetUp() override {
3371 repo = MakeRepository();
3372 for (unsigned i = 0; i < 500; i++) {
3373 std::string name = fmt::format("/test/datapoint_{:0>2}", i);
3374 dp_paths.emplace_back(name);
3375 }
3376 }
3377
3378 void TearDown() override {
3379 for (const auto& path : dp_paths) {
3380 if (repo->DataPointExists(path)) {
3381 repo->DeleteDataPoint(path);
3382 }
3383 }
3384 }
3385
3386protected:
3387 std::vector<DataPointPath> dp_paths;
3388 std::shared_ptr<RepositoryIf> repo;
3389};
3390
3392 DataPointPath path = dp_paths.front();
3393 ASSERT_FALSE(repo->DataPointExists(path));
3394 EXPECT_THROW({ repo->CreateDataPoint<ThrowInGetShape>(path); }, std::runtime_error);
3395 DataPointPath second_path = dp_paths.front();
3396 ASSERT_FALSE(repo->DataPointExists(second_path));
3397 EXPECT_THROW({ repo->CreateDataPoint<ThrowInGetShape>(second_path); }, std::runtime_error);
3398}
3399
3401 DataPointPath path = dp_paths.front();
3402 ASSERT_FALSE(repo->DataPointExists(path));
3403 EXPECT_THROW({ repo->CreateDataPoint<ThrowInMakeSpan>(path); }, std::runtime_error);
3404 DataPointPath second_path = dp_paths.back();
3405 ASSERT_FALSE(repo->DataPointExists(second_path));
3406 EXPECT_THROW({ repo->CreateDataPoint<ThrowInMakeSpan>(second_path); }, std::runtime_error);
3407}
3408
3410 DataPointPath path = dp_paths.front();
3411 ASSERT_FALSE(repo->DataPointExists(path));
3412 EXPECT_THROW(
3413 {
3414 repo->CreateDataPoint<ThrowInResizeBuffer>(path);
3415 repo->GetDataPoint<ThrowInResizeBuffer>(path);
3416 },
3417 std::runtime_error);
3418 DataPointPath second_path = dp_paths.back();
3419 ASSERT_FALSE(repo->DataPointExists(second_path));
3420 EXPECT_THROW(
3421 {
3422 repo->CreateDataPoint<ThrowInResizeBuffer>(second_path);
3423 repo->GetDataPoint<ThrowInResizeBuffer>(second_path);
3424 },
3425 std::runtime_error);
3426}
3427
3428} // namespace rtctk::componentFramework::test
3429
3430#endif // RTCTK_COMPONENTFRAMEWORK_TEST_REPOSITORYIFTESTSUITE_HPP
This class provides a wrapper for a data point path.
Definition dataPointPath.hpp:77
A buffer class representing 2D matrix data.
Definition matrixBuffer.hpp:28
A span referencing a 2D matrix buffer.
Definition matrixSpan.hpp:36
An object representing one or more asynchronous I/O requests to a repository.
Definition repositoryIf.hpp:634
void DataPointExists(const DataPointPath &path, bool &result, const CallbackType &callback=nullptr) const
Definition repositoryIf.cpp:349
void WriteDataPoint(const DataPointPath &path, const T &buffer, std::optional< std::reference_wrapper< MetaData > > metadata=std::nullopt, const CallbackType &callback=nullptr)
Definition repositoryIf.ipp:1538
void DeleteDataPoint(const DataPointPath &path, const CallbackType &callback=nullptr)
Definition repositoryIf.cpp:343
void ReadDataPoint(const DataPointPath &path, T &buffer, std::optional< std::reference_wrapper< MetaData > > metadata=std::nullopt, const CallbackType &callback=nullptr) const
Definition repositoryIf.ipp:1444
void GetChildren(const DataPointPath &path, std::pair< PathList, PathList > &result, bool recurse=false, const CallbackType &callback=nullptr) const
void PartialReadDataPoint(const DataPointPath &path, T &buffer, size_t first, size_t last, size_t d_first, std::optional< std::reference_wrapper< MetaData > > metadata=std::nullopt, const CallbackType &callback=nullptr) const
Definition repositoryIf.ipp:1595
void ReadMetaData(const DataPointPath &path, MetaData &metadata, const CallbackType &callback=nullptr) const
Definition repositoryIf.cpp:367
void CreateSymlink(const DataPointPath &dp, const DataPointPath &link, const CallbackType &callback=nullptr)
Definition repositoryIf.cpp:383
void PartialWriteDataPoint(const DataPointPath &path, const T &buffer, size_t first, size_t last, size_t d_first, std::optional< std::reference_wrapper< MetaData > > metadata=std::nullopt, const CallbackType &callback=nullptr)
Definition repositoryIf.ipp:1681
void CreateDataPoint(const DataPointPath &path, const T &initial_value, std::optional< std::reference_wrapper< const MetaData > > metadata=std::nullopt, const CallbackType &callback=nullptr)
Definition repositoryIf.ipp:1385
void UpdateSymlink(const DataPointPath &dp, const DataPointPath &link, const CallbackType &callback=nullptr)
Definition repositoryIf.cpp:392
void WriteMetaData(const DataPointPath &path, const MetaData &metadata, const CallbackType &callback=nullptr)
Definition repositoryIf.cpp:375
Exception indicating that an unsupported type was used for the metadata value.
Definition repositoryIf.hpp:441
Class for passing/receiving metadata to/from the repository.
Definition repositoryIf.hpp:146
bool Remove(const std::string &key)
Remove a metadata key.
Definition repositoryIf.cpp:262
bool Contains(const std::string &key) const
Check if the metadata contains a specific key.
Definition repositoryIf.ipp:1292
const std::vector< Info > & GetInfo() const
Definition repositoryIf.cpp:140
Abstract interface providing basic read and write facilities to a repository.
Definition repositoryIf.hpp:51
std::optional< T > TryGetDataPoint(const DataPointPath &path) const
Fetches a datapoint from the repository.
Definition repositoryIf.ipp:1861
Clock::time_point Timestamp
Definition repositoryIf.hpp:58
T GetDataPoint(const DataPointPath &path) const
Fetches a datapoint from the repository.
Definition repositoryIf.ipp:1843
void CreateDataPoint(const DataPointPath &path)
Creates a new empty datapoint in the repository.
Definition repositoryIf.ipp:1826
void SetDataPoint(const DataPointPath &path, const T &value)
Sets a datapoint in the repository.
Definition repositoryIf.ipp:1869
std::vector< DataPointPath > PathList
Definition repositoryIf.hpp:56
Definition repositoryIfTestSuite.hpp:750
T MakeWriteValueForPartialIo()
Definition repositoryIfTestSuite.hpp:872
T MakeReadValueForPartialIo(const T &result_value)
Definition repositoryIfTestSuite.hpp:986
T MakeExpectedResultValueForPartialRead()
Definition repositoryIfTestSuite.hpp:942
T MakeExpectedResultValueForPartialReadEnd()
Definition repositoryIfTestSuite.hpp:964
T MakeLargeTestValue()
Definition repositoryIfTestSuite.hpp:752
T MakeSmallTestValue()
Definition repositoryIfTestSuite.hpp:788
T MakeCreateValueForPartialIo()
Definition repositoryIfTestSuite.hpp:824
RtcVectorUInt64 ExpectedSmallTestValueShape()
Definition repositoryIfTestSuite.hpp:806
T MakeExpectedResultValueForPartialWrite()
Definition repositoryIfTestSuite.hpp:894
RtcVectorUInt64 ExpectedLargeTestValueShape()
Definition repositoryIfTestSuite.hpp:770
Definition repositoryIfTestSuite.hpp:1605
void TearDown() override
Definition repositoryIfTestSuite.hpp:1615
DataPointPath link1
Definition repositoryIfTestSuite.hpp:1642
DataPointPath path1
Definition repositoryIfTestSuite.hpp:1640
DataPointPath link2
Definition repositoryIfTestSuite.hpp:1643
void SetupDataPoints(const T &initial_value=0)
Definition repositoryIfTestSuite.hpp:1631
DataPointPath path2
Definition repositoryIfTestSuite.hpp:1641
std::shared_ptr< RepositoryIf > repo
Definition repositoryIfTestSuite.hpp:1639
void SetUp() override
Definition repositoryIfTestSuite.hpp:1607
Definition repositoryIfTestSuite.hpp:3368
void SetUp() override
Definition repositoryIfTestSuite.hpp:3370
std::vector< DataPointPath > dp_paths
Definition repositoryIfTestSuite.hpp:3387
std::shared_ptr< RepositoryIf > repo
Definition repositoryIfTestSuite.hpp:3388
void TearDown() override
Definition repositoryIfTestSuite.hpp:3378
Definition repositoryIfTestSuite.hpp:2764
std::shared_ptr< RepositoryIf > repo
Definition repositoryIfTestSuite.hpp:2786
void TearDown() override
Definition repositoryIfTestSuite.hpp:2773
DataPointPath link_path
Definition repositoryIfTestSuite.hpp:2788
void SetUp() override
Definition repositoryIfTestSuite.hpp:2766
DataPointPath link_path2
Definition repositoryIfTestSuite.hpp:2789
DataPointPath path
Definition repositoryIfTestSuite.hpp:2787
Definition repositoryIfTestSuite.hpp:2212
void TearDown() override
Definition repositoryIfTestSuite.hpp:2223
std::shared_ptr< RepositoryIf > repo
Definition repositoryIfTestSuite.hpp:2245
void SetUp() override
Definition repositoryIfTestSuite.hpp:2214
Definition repositoryIfTestSuite.hpp:3118
void TearDown() override
Definition repositoryIfTestSuite.hpp:3128
std::shared_ptr< RepositoryIf > repo
Definition repositoryIfTestSuite.hpp:3137
std::vector< DataPointPath > dp_paths
Definition repositoryIfTestSuite.hpp:3138
void SetUp() override
Definition repositoryIfTestSuite.hpp:3120
Definition repositoryIfTestSuite.hpp:2336
void TearDown() override
Definition repositoryIfTestSuite.hpp:2343
DataPointPath path
Definition repositoryIfTestSuite.hpp:2351
std::shared_ptr< RepositoryIf > repo
Definition repositoryIfTestSuite.hpp:2350
void SetUp() override
Definition repositoryIfTestSuite.hpp:2338
Definition repositoryIfTestSuite.hpp:1646
MOCK_METHOD(void, ReadMetaDataCallback,(const DataPointPath &path))
MOCK_METHOD(void, PartialReadCallback,(const DataPointPath &path))
MOCK_METHOD(void, DeleteCallback,(const DataPointPath &path))
MOCK_METHOD(void, ExistsCallback,(const DataPointPath &path))
MOCK_METHOD(void, CreateSymlinkCallback,(const DataPointPath &path))
MOCK_METHOD(void, CreateCallback,(const DataPointPath &path))
MOCK_METHOD(void, GetChildrenCallback,(const DataPointPath &path))
MOCK_METHOD(void, ReadCallback,(const DataPointPath &path))
MOCK_METHOD(void, WriteCallback,(const DataPointPath &path))
MOCK_METHOD(void, UpdateSymlinkCallback,(const DataPointPath &path))
MOCK_METHOD(void, PartialWriteCallback,(const DataPointPath &path))
MOCK_METHOD(void, WriteMetaDataCallback,(const DataPointPath &path))
Definition repositoryIfTestSuite.hpp:183
std::vector< DataPointPath > dp_paths
Definition repositoryIfTestSuite.hpp:270
T MakeSomeTestValue()
Definition repositoryIfTestSuite.hpp:203
void SetUp() override
Definition repositoryIfTestSuite.hpp:185
std::shared_ptr< RepositoryIf > repo
Definition repositoryIfTestSuite.hpp:271
size_t GetExpectedSize(const U &value)
Definition repositoryIfTestSuite.hpp:258
void TearDown() override
Definition repositoryIfTestSuite.hpp:194
T MakeOtherTestValue()
Definition repositoryIfTestSuite.hpp:229
virtual RtcVectorUInt64 GetShape() const
Definition repositoryIfTestSuite.hpp:43
TestingUserTypeBase(std::string value)
Definition repositoryIfTestSuite.hpp:41
virtual gsl::span< char > MakeSpan()
Definition repositoryIfTestSuite.hpp:47
std::string m_value
Definition repositoryIfTestSuite.hpp:63
virtual bool ResizeBuffer(const RtcVectorUInt64 &shape)
Definition repositoryIfTestSuite.hpp:54
virtual gsl::span< const char > MakeSpan() const
Definition repositoryIfTestSuite.hpp:50
Definition repositoryIfTestSuite.hpp:66
RtcVectorUInt64 GetShape() const override
Definition repositoryIfTestSuite.hpp:69
Definition repositoryIfTestSuite.hpp:74
gsl::span< char > MakeSpan() override
Definition repositoryIfTestSuite.hpp:77
gsl::span< const char > MakeSpan() const override
Definition repositoryIfTestSuite.hpp:80
Definition repositoryIfTestSuite.hpp:85
bool ResizeBuffer(const RtcVectorUInt64 &shape) override
Definition repositoryIfTestSuite.hpp:88
Definition measurable.hpp:26
RtcUInt64 GetNumOfElements(const RtcVectorUInt64 &shape)
Definition repositoryIf.ipp:136
Definition fakeClock.cpp:15
TYPED_TEST_SUITE(BasicOperation, TypeSetForBasicOperation)
::testing::Types< RtcBool, RtcInt8, RtcInt16, RtcInt32, RtcInt64, RtcUInt8, RtcUInt16, RtcUInt32, RtcUInt64, RtcFloat, RtcDouble, RtcString, RtcBinary, RtcVectorBool, RtcVectorInt8, RtcVectorInt16, RtcVectorInt32, RtcVectorInt64, RtcVectorUInt8, RtcVectorUInt16, RtcVectorUInt32, RtcVectorUInt64, RtcVectorFloat, RtcVectorDouble, RtcVectorString, RtcMatrixBool, RtcMatrixInt8, RtcMatrixInt16, RtcMatrixInt32, RtcMatrixInt64, RtcMatrixUInt8, RtcMatrixUInt16, RtcMatrixUInt32, RtcMatrixUInt64, RtcMatrixFloat, RtcMatrixDouble, RtcMatrixString > TypeSetForBasicOperation
Definition repositoryIfTestSuite.hpp:280
::testing::Types< RtcString, RtcBinary, RtcVectorBool, RtcVectorInt8, RtcVectorInt16, RtcVectorInt32, RtcVectorInt64, RtcVectorUInt8, RtcVectorUInt16, RtcVectorUInt32, RtcVectorUInt64, RtcVectorFloat, RtcVectorDouble, RtcVectorString, RtcMatrixBool, RtcMatrixInt8, RtcMatrixInt16, RtcMatrixInt32, RtcMatrixInt64, RtcMatrixUInt8, RtcMatrixUInt16, RtcMatrixUInt32, RtcMatrixUInt64, RtcMatrixFloat, RtcMatrixDouble, RtcMatrixString > TypeSetAdvancedOperation
Definition repositoryIfTestSuite.hpp:997
TEST_F(Callbacks, CreateDataPointCallback)
Definition repositoryIfTestSuite.hpp:1662
RepositoryIfTestSuite< T > BasicOperation
Definition repositoryIfTestSuite.hpp:277
TYPED_TEST(BasicOperation, DataPointExistanceConsistency)
Definition repositoryIfTestSuite.hpp:321
RepositoryIf::PathList PathList
Definition persistentRepoAdapter.cpp:96
constexpr bool IS_VECTOR_TYPE
Is true if the type is a std::vector<U> of some type U.
Definition typeTraits.hpp:47
constexpr bool IS_MATRIX_BUFFER_TYPE
Is true if the type is a MatrixBuffer<U> of some type U.
Definition typeTraits.hpp:77
Definition commandReplier.cpp:22
std::int64_t RtcInt64
Definition basicTypes.hpp:41
RtcMatrix< RtcInt8 > RtcMatrixInt8
Definition basicTypes.hpp:63
std::int16_t RtcInt16
Definition basicTypes.hpp:39
std::uint16_t RtcUInt16
Definition basicTypes.hpp:43
float RtcFloat
Definition basicTypes.hpp:46
RtcMatrix< RtcInt32 > RtcMatrixInt32
Definition basicTypes.hpp:65
std::int32_t RtcInt32
Definition basicTypes.hpp:40
std::int8_t RtcInt8
Definition basicTypes.hpp:38
RtcMatrix< RtcInt64 > RtcMatrixInt64
Definition basicTypes.hpp:66
RtcMatrix< RtcUInt64 > RtcMatrixUInt64
Definition basicTypes.hpp:70
RtcVector< RtcUInt32 > RtcVectorUInt32
Definition basicTypes.hpp:57
RtcMatrix< RtcUInt8 > RtcMatrixUInt8
Definition basicTypes.hpp:67
RtcMatrix< RtcString > RtcMatrixString
Definition basicTypes.hpp:73
RtcMatrix< RtcFloat > RtcMatrixFloat
Definition basicTypes.hpp:71
RtcVector< RtcDouble > RtcVectorDouble
Definition basicTypes.hpp:60
std::string RtcString
Definition basicTypes.hpp:48
RtcMatrix< RtcInt16 > RtcMatrixInt16
Definition basicTypes.hpp:64
RtcMatrix< RtcDouble > RtcMatrixDouble
Definition basicTypes.hpp:72
bool RtcBool
Definition basicTypes.hpp:37
RtcVector< RtcUInt16 > RtcVectorUInt16
Definition basicTypes.hpp:56
std::uint32_t RtcUInt32
Definition basicTypes.hpp:44
RtcVector< RtcInt16 > RtcVectorInt16
Definition basicTypes.hpp:52
RtcMatrix< RtcBool > RtcMatrixBool
Definition basicTypes.hpp:62
RtcVector< RtcFloat > RtcVectorFloat
Definition basicTypes.hpp:59
RtcVector< RtcInt8 > RtcVectorInt8
Definition basicTypes.hpp:51
std::uint8_t RtcUInt8
Definition basicTypes.hpp:42
RtcVector< RtcBool > RtcVectorBool
Definition basicTypes.hpp:50
RtcVector< RtcUInt64 > RtcVectorUInt64
Definition basicTypes.hpp:58
std::uint64_t RtcUInt64
Definition basicTypes.hpp:45
RtcVector< RtcString > RtcVectorString
Definition basicTypes.hpp:61
RtcVector< RtcInt32 > RtcVectorInt32
Definition basicTypes.hpp:53
std::vector< std::byte > RtcBinary
Definition basicTypes.hpp:49
RtcVector< RtcUInt8 > RtcVectorUInt8
Definition basicTypes.hpp:55
RtcMatrix< RtcUInt16 > RtcMatrixUInt16
Definition basicTypes.hpp:68
RtcVector< RtcInt64 > RtcVectorInt64
Definition basicTypes.hpp:54
RtcMatrix< RtcUInt32 > RtcMatrixUInt32
Definition basicTypes.hpp:69
double RtcDouble
Definition basicTypes.hpp:47
Definition ddsSub.hpp:156
Header file for RepositoryIf and related base classes.
static RtcVectorUInt64 GetShape(const BufferType &buffer)
Definition repositoryIfTestSuite.hpp:130
static bool ResizeBuffer(BufferType &buffer, const RtcVectorUInt64 &shape)
Definition repositoryIfTestSuite.hpp:142
std::remove_cv_t< typename std::string::value_type > ElementType
Definition repositoryIfTestSuite.hpp:125
static gsl::span< ElementType > MakeSpan(BufferType &buffer)
Definition repositoryIfTestSuite.hpp:134
static gsl::span< const ElementType > MakeSpan(const BufferType &buffer)
Definition repositoryIfTestSuite.hpp:138
static gsl::span< ElementType > MakeSpan(BufferType &buffer)
Definition repositoryIfTestSuite.hpp:159
static RtcVectorUInt64 GetShape(const BufferType &buffer)
Definition repositoryIfTestSuite.hpp:155
static bool ResizeBuffer(BufferType &buffer, const RtcVectorUInt64 &shape)
Definition repositoryIfTestSuite.hpp:167
static gsl::span< const ElementType > MakeSpan(const BufferType &buffer)
Definition repositoryIfTestSuite.hpp:163
std::remove_cv_t< typename std::string::value_type > ElementType
Definition repositoryIfTestSuite.hpp:150
static gsl::span< ElementType > MakeSpan(BufferType &buffer)
Definition repositoryIfTestSuite.hpp:109
static gsl::span< const ElementType > MakeSpan(const BufferType &buffer)
Definition repositoryIfTestSuite.hpp:113
static bool ResizeBuffer(BufferType &buffer, const RtcVectorUInt64 &shape)
Definition repositoryIfTestSuite.hpp:117
static RtcVectorUInt64 GetShape(const BufferType &buffer)
Definition repositoryIfTestSuite.hpp:105
MatrixSpan< T > SpanType
Definition repositoryIfTestSuite.hpp:1280
MatrixBuffer< T, A > BufferType
Definition repositoryIfTestSuite.hpp:1279
MatrixSpan< const T > ConstSpanType
Definition repositoryIfTestSuite.hpp:1281
boost::container::vector< bool, A > BufferType
Definition repositoryIfTestSuite.hpp:1300
MatrixSpan< const bool > ConstSpanType
Definition repositoryIfTestSuite.hpp:1302
MatrixSpan< bool > SpanType
Definition repositoryIfTestSuite.hpp:1301
gsl::span< char > SpanType
Definition repositoryIfTestSuite.hpp:1273
RtcString BufferType
Definition repositoryIfTestSuite.hpp:1272
gsl::span< const char > ConstSpanType
Definition repositoryIfTestSuite.hpp:1274
gsl::span< const T > ConstSpanType
Definition repositoryIfTestSuite.hpp:1288
std::vector< T, A > BufferType
Definition repositoryIfTestSuite.hpp:1286
gsl::span< T > SpanType
Definition repositoryIfTestSuite.hpp:1287
gsl::span< const bool > ConstSpanType
Definition repositoryIfTestSuite.hpp:1295
boost::container::vector< bool, A > BufferType
Definition repositoryIfTestSuite.hpp:1293
gsl::span< bool > SpanType
Definition repositoryIfTestSuite.hpp:1294
Definition repositoryIfTestSuite.hpp:1268
Provides useful mechanisms to test various type traits.