xref: /aosp_15_r20/external/pigweed/pw_sync/inline_borrowable_test.cc (revision 61c4878ac05f98d0ceed94b57d316916de578985)
1 // Copyright 2021 The Pigweed Authors
2 //
3 // Licensed under the Apache License, Version 2.0 (the "License"); you may not
4 // use this file except in compliance with the License. You may obtain a copy of
5 // the License at
6 //
7 //     https://www.apache.org/licenses/LICENSE-2.0
8 //
9 // Unless required by applicable law or agreed to in writing, software
10 // distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
11 // WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
12 // License for the specific language governing permissions and limitations under
13 // the License.
14 
15 #include "pw_sync/inline_borrowable.h"
16 
17 #include <array>
18 #include <chrono>
19 #include <tuple>
20 
21 #include "pw_sync/interrupt_spin_lock.h"
22 #include "pw_sync/lock_annotations.h"
23 #include "pw_sync/mutex.h"
24 #include "pw_unit_test/framework.h"
25 
26 namespace pw::sync {
27 namespace {
28 
29 using namespace std::chrono_literals;
30 
31 // A trivial type that is copyable and movable.
32 struct TrivialType {
yespw::sync::__anoneb6ea4cd0111::TrivialType33   bool yes() const { return true; }
34 };
35 
36 // A custom type that is neither copyable nor movable.
37 class CustomType {
38  public:
CustomType(int z)39   explicit constexpr CustomType(int z) : x_(z), y_(-z) {}
CustomType(int x,int y)40   constexpr CustomType(int x, int y) : x_(x), y_(y) {}
41 
42   CustomType(const CustomType&) = delete;
43   CustomType& operator=(const CustomType&) = delete;
44   CustomType(CustomType&&) = delete;
45   CustomType&& operator=(CustomType&&) = delete;
46 
data() const47   std::pair<int, int> data() const { return std::make_pair(x_, y_); }
48 
49  private:
50   int x_, y_;
51 };
52 
53 // A custom lockable interface.
54 class PW_LOCKABLE("VirtualCustomLocakble") VirtualCustomLockable {
55  public:
~VirtualCustomLockable()56   virtual ~VirtualCustomLockable() {}
57 
58   virtual void lock() PW_EXCLUSIVE_LOCK_FUNCTION() = 0;
59   virtual void unlock() PW_UNLOCK_FUNCTION() = 0;
60 };
61 
62 // A custom mutex type that requires a constructor parameter.
63 class PW_LOCKABLE("VirtualCustomMutex") VirtualCustomMutex
64     : public VirtualCustomLockable {
65  public:
VirtualCustomMutex(int id)66   explicit VirtualCustomMutex(int id) : mutex_{}, id_{id} {}
67 
lock()68   void lock() override PW_EXCLUSIVE_LOCK_FUNCTION() { mutex_.lock(); }
unlock()69   void unlock() override PW_UNLOCK_FUNCTION() { mutex_.unlock(); }
70 
id() const71   int id() const { return id_; }
72 
73  private:
74   pw::sync::Mutex mutex_;
75   int id_;
76 };
77 
TEST(InlineBorrowableTest,TestTrivialType)78 TEST(InlineBorrowableTest, TestTrivialType) {
79   InlineBorrowable<TrivialType> trivial;
80   EXPECT_TRUE(trivial.acquire()->yes());
81 }
82 
TEST(InlineBorrowableTest,TestCustomTypeInPlace1Arg)83 TEST(InlineBorrowableTest, TestCustomTypeInPlace1Arg) {
84   InlineBorrowable<CustomType> custom(std::in_place, 1);
85   EXPECT_EQ(custom.acquire()->data(), std::make_pair(1, -1));
86 }
87 
TEST(InlineBorrowableTest,TestCustomTypeInPlace1ArgLValue)88 TEST(InlineBorrowableTest, TestCustomTypeInPlace1ArgLValue) {
89   int x = 1;
90   InlineBorrowable<CustomType> custom(std::in_place, x);
91   EXPECT_EQ(custom.acquire()->data(), std::make_pair(x, -x));
92 }
93 
TEST(InlineBorrowableTest,TestCustomTypeInPlace2Arg)94 TEST(InlineBorrowableTest, TestCustomTypeInPlace2Arg) {
95   InlineBorrowable<CustomType> custom(std::in_place, 1, 2);
96   EXPECT_EQ(custom.acquire()->data(), std::make_pair(1, 2));
97 }
98 
TEST(InlineBorrowableTest,TestCustomTypeFromTuple)99 TEST(InlineBorrowableTest, TestCustomTypeFromTuple) {
100   InlineBorrowable<CustomType> custom(std::make_tuple(1, 2));
101   EXPECT_EQ(custom.acquire()->data(), std::make_pair(1, 2));
102 }
103 
TEST(InlineBorrowableTest,TestCustomTypeFromFactory)104 TEST(InlineBorrowableTest, TestCustomTypeFromFactory) {
105   InlineBorrowable<CustomType> custom([] { return CustomType(1, 2); });
106   EXPECT_EQ(custom.acquire()->data(), std::make_pair(1, 2));
107 }
108 
TEST(InlineBorrowableTest,TestCustomTypeFromMutableFactory)109 TEST(InlineBorrowableTest, TestCustomTypeFromMutableFactory) {
110   int i = 0;
111   auto factory = [&i]() mutable {
112     i++;
113     return CustomType(1, 2);
114   };
115   InlineBorrowable<CustomType> custom(factory);
116   EXPECT_EQ(custom.acquire()->data(), std::make_pair(1, 2));
117 }
118 
TEST(InlineBorrowableTest,TestTrivialTypeWithInterruptSpinLock)119 TEST(InlineBorrowableTest, TestTrivialTypeWithInterruptSpinLock) {
120   InlineBorrowable<TrivialType, VirtualInterruptSpinLock>
121       trivial_interrupt_safe;
122   EXPECT_TRUE(trivial_interrupt_safe.acquire()->yes());
123 }
124 
TEST(InlineBorrowableTest,TestCustomTypeWithInterruptSpinLock)125 TEST(InlineBorrowableTest, TestCustomTypeWithInterruptSpinLock) {
126   InlineBorrowable<CustomType, VirtualInterruptSpinLock> custom_interrupt_safe(
127       std::in_place, 1, 2);
128   EXPECT_EQ(custom_interrupt_safe.acquire()->data(), std::make_pair(1, 2));
129 }
130 
TEST(InlineBorrowableTest,TestCustomTypeWithCustomMutexFromTuple)131 TEST(InlineBorrowableTest, TestCustomTypeWithCustomMutexFromTuple) {
132   InlineBorrowable<CustomType, VirtualCustomMutex, VirtualCustomLockable>
133       custom_mutex(std::make_tuple(1, 2), std::make_tuple(42));
134   EXPECT_EQ(custom_mutex.acquire()->data(), std::make_pair(1, 2));
135 }
136 
TEST(InlineBorrowableTest,TestCustomTypeWithCustomMutexFromFactory)137 TEST(InlineBorrowableTest, TestCustomTypeWithCustomMutexFromFactory) {
138   InlineBorrowable<CustomType, VirtualCustomMutex, VirtualCustomLockable>
139       custom_mutex([] { return CustomType(1, 2); },
140                    [] { return VirtualCustomMutex(42); });
141   EXPECT_EQ(custom_mutex.acquire()->data(), std::make_pair(1, 2));
142 }
143 
TEST(InlineBorrowableTest,TestArrayAggregateInitializationInPlace)144 TEST(InlineBorrowableTest, TestArrayAggregateInitializationInPlace) {
145   using ArrayAggregate = std::array<int, 2>;
146   InlineBorrowable<ArrayAggregate> aggregate{std::in_place, 1, 2};
147   EXPECT_EQ((*aggregate.acquire())[0], 1);
148   EXPECT_EQ((*aggregate.acquire())[1], 2);
149 }
150 
151 struct StructAggregate {
152   int a;
153   int b;
154 };
155 
TEST(InlineBorrowableTest,TestStructAggregateInitializationInPlace)156 TEST(InlineBorrowableTest, TestStructAggregateInitializationInPlace) {
157   InlineBorrowable<StructAggregate> aggregate{std::in_place, 1, 2};
158   EXPECT_EQ(aggregate.acquire()->a, 1);
159   EXPECT_EQ(aggregate.acquire()->b, 2);
160 }
161 
TEST(InlineBorrowableTest,TestStructAggregateInitializationFromFactory)162 TEST(InlineBorrowableTest, TestStructAggregateInitializationFromFactory) {
163   InlineBorrowable<StructAggregate> aggregate(
164       []() -> StructAggregate { return {.a = 1, .b = 2}; });
165   EXPECT_EQ(aggregate.acquire()->a, 1);
166   EXPECT_EQ(aggregate.acquire()->b, 2);
167 }
168 
TEST(InlineBorrowableTest,TestStructAggregateInitializationFromMutableFactory)169 TEST(InlineBorrowableTest,
170      TestStructAggregateInitializationFromMutableFactory) {
171   int i = 0;
172   auto factory = [&i]() mutable -> StructAggregate {
173     i++;
174     return {.a = 1, .b = 2};
175   };
176   InlineBorrowable<StructAggregate> aggregate(factory);
177   EXPECT_EQ(aggregate.acquire()->a, 1);
178   EXPECT_EQ(aggregate.acquire()->b, 2);
179 }
180 
181 struct ReferenceTypes {
ReferenceTypespw::sync::__anoneb6ea4cd0111::ReferenceTypes182   ReferenceTypes(const int& a, int& b, BorrowedPointer<int>&& c)
183       : in(a), out(b), borrowed(std::move(c)) {}
184   const int& in;
185   int& out;
186   BorrowedPointer<int> borrowed;  // move-only type
187 };
188 
189 class InlineBorrowableReferenceTypesTest : public ::testing::Test {
190  protected:
191   int input_ = 1;
192   int output_ = 2;
193   InlineBorrowable<int> borrowable_{std::in_place, 3};
194 
Validate(BorrowedPointer<ReferenceTypes> && references)195   void Validate(BorrowedPointer<ReferenceTypes>&& references) {
196     EXPECT_EQ(references->in, 1);
197     EXPECT_EQ(references->out, 2);
198     EXPECT_EQ(*references->borrowed, 3);
199 
200     references->out = -2;
201     EXPECT_EQ(output_, -2);
202   }
203 };
204 
TEST_F(InlineBorrowableReferenceTypesTest,TestInPlace)205 TEST_F(InlineBorrowableReferenceTypesTest, TestInPlace) {
206   InlineBorrowable<ReferenceTypes> references(
207       std::in_place, input_, output_, borrowable_.acquire());
208   Validate(references.acquire());
209 }
210 
TEST_F(InlineBorrowableReferenceTypesTest,TestFromTuple)211 TEST_F(InlineBorrowableReferenceTypesTest, TestFromTuple) {
212   InlineBorrowable<ReferenceTypes> references(
213       std::forward_as_tuple(input_, output_, borrowable_.acquire()));
214   Validate(references.acquire());
215 }
216 
TEST_F(InlineBorrowableReferenceTypesTest,TestFromFactory)217 TEST_F(InlineBorrowableReferenceTypesTest, TestFromFactory) {
218   InlineBorrowable<ReferenceTypes> references(
219       [&] { return ReferenceTypes(input_, output_, borrowable_.acquire()); });
220   Validate(references.acquire());
221 }
222 
223 }  // namespace
224 }  // namespace pw::sync
225