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