1 /*
2 * Copyright 2020 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17 #define LOG_TAG "FlattenableHelpersTest"
18
19 #include <ui/FlattenableHelpers.h>
20
21 #include <gtest/gtest.h>
22 #include <utils/Flattenable.h>
23 #include <cstdint>
24 #include <memory>
25 #include <optional>
26 #include <string>
27 #include <vector>
28
29 namespace android {
30
31 namespace {
32
33 struct TestLightFlattenable : LightFlattenable<TestLightFlattenable> {
34 std::unique_ptr<int32_t> ptr;
35
isFixedSizeandroid::__anonb0c1d3b90111::TestLightFlattenable36 bool isFixedSize() const { return true; }
getFlattenedSizeandroid::__anonb0c1d3b90111::TestLightFlattenable37 size_t getFlattenedSize() const { return sizeof(int32_t); }
38
flattenandroid::__anonb0c1d3b90111::TestLightFlattenable39 status_t flatten(void* buffer, size_t size) const {
40 FlattenableUtils::write(buffer, size, *ptr);
41 return OK;
42 }
43
unflattenandroid::__anonb0c1d3b90111::TestLightFlattenable44 status_t unflatten(void const* buffer, size_t size) {
45 int32_t value;
46 FlattenableUtils::read(buffer, size, value);
47 ptr = std::make_unique<int32_t>(value);
48 return OK;
49 }
50 };
51
52 class FlattenableHelpersTest : public testing::Test {
53 public:
54 template <class T>
testWriteThenRead(const T & value,size_t bufferSize)55 void testWriteThenRead(const T& value, size_t bufferSize) {
56 std::vector<int8_t> buffer(bufferSize);
57 auto rawBuffer = reinterpret_cast<void*>(buffer.data());
58 size_t size = buffer.size();
59 ASSERT_EQ(OK, FlattenableHelpers::flatten(&rawBuffer, &size, value));
60
61 auto rawReadBuffer = reinterpret_cast<const void*>(buffer.data());
62 size = buffer.size();
63 T valueRead;
64 ASSERT_EQ(OK, FlattenableHelpers::unflatten(&rawReadBuffer, &size, &valueRead));
65 EXPECT_EQ(value, valueRead);
66 }
67
68 template <class T>
testTriviallyCopyable(const T & value)69 void testTriviallyCopyable(const T& value) {
70 testWriteThenRead(value, sizeof(T));
71 }
72
73 template <class T>
testWriteThenRead(const T & value)74 void testWriteThenRead(const T& value) {
75 testWriteThenRead(value, FlattenableHelpers::getFlattenedSize(value));
76 }
77 };
78
TEST_F(FlattenableHelpersTest,TriviallyCopyable)79 TEST_F(FlattenableHelpersTest, TriviallyCopyable) {
80 testTriviallyCopyable(42);
81 testTriviallyCopyable(1LL << 63);
82 testTriviallyCopyable(false);
83 testTriviallyCopyable(true);
84 testTriviallyCopyable(std::optional<int>());
85 testTriviallyCopyable(std::optional<int>(4));
86 }
87
TEST_F(FlattenableHelpersTest,String)88 TEST_F(FlattenableHelpersTest, String) {
89 testWriteThenRead(std::string("Android"));
90 testWriteThenRead(std::string());
91 }
92
TEST_F(FlattenableHelpersTest,Vector)93 TEST_F(FlattenableHelpersTest, Vector) {
94 testWriteThenRead(std::vector<int>({1, 2, 3}));
95 testWriteThenRead(std::vector<int>());
96 }
97
TEST_F(FlattenableHelpersTest,OptionalOfLightFlattenable)98 TEST_F(FlattenableHelpersTest, OptionalOfLightFlattenable) {
99 std::vector<size_t> buffer;
100 constexpr int kInternalValue = 16;
101 {
102 std::optional<TestLightFlattenable> value =
103 TestLightFlattenable{.ptr = std::make_unique<int32_t>(kInternalValue)};
104 buffer.assign(FlattenableHelpers::getFlattenedSize(value), 0);
105 void* rawBuffer = reinterpret_cast<void*>(buffer.data());
106 size_t size = buffer.size();
107 ASSERT_EQ(OK, FlattenableHelpers::flatten(&rawBuffer, &size, value));
108 }
109
110 const void* rawReadBuffer = reinterpret_cast<const void*>(buffer.data());
111 size_t size = buffer.size();
112 std::optional<TestLightFlattenable> valueRead;
113 ASSERT_EQ(OK, FlattenableHelpers::unflatten(&rawReadBuffer, &size, &valueRead));
114 ASSERT_TRUE(valueRead.has_value());
115 EXPECT_EQ(kInternalValue, *valueRead->ptr);
116 }
117
TEST_F(FlattenableHelpersTest,NullOptionalOfLightFlattenable)118 TEST_F(FlattenableHelpersTest, NullOptionalOfLightFlattenable) {
119 std::vector<size_t> buffer;
120 {
121 std::optional<TestLightFlattenable> value;
122 buffer.assign(FlattenableHelpers::getFlattenedSize(value), 0);
123 void* rawBuffer = reinterpret_cast<void*>(buffer.data());
124 size_t size = buffer.size();
125 ASSERT_EQ(OK, FlattenableHelpers::flatten(&rawBuffer, &size, value));
126 }
127
128 const void* rawReadBuffer = reinterpret_cast<const void*>(buffer.data());
129 size_t size = buffer.size();
130 std::optional<TestLightFlattenable> valueRead;
131 ASSERT_EQ(OK, FlattenableHelpers::unflatten(&rawReadBuffer, &size, &valueRead));
132 ASSERT_FALSE(valueRead.has_value());
133 }
134
135 // If a struct is both trivially copyable and light flattenable we should treat it
136 // as LigthFlattenable.
TEST_F(FlattenableHelpersTest,TriviallyCopyableAndLightFlattenableIsFlattenedAsLightFlattenable)137 TEST_F(FlattenableHelpersTest, TriviallyCopyableAndLightFlattenableIsFlattenedAsLightFlattenable) {
138 static constexpr int32_t kSizeTag = 1234567;
139 static constexpr int32_t kFlattenTag = 987654;
140 static constexpr int32_t kUnflattenTag = 5926582;
141
142 struct LightFlattenableAndTriviallyCopyable
143 : LightFlattenable<LightFlattenableAndTriviallyCopyable> {
144 int32_t value;
145
146 bool isFixedSize() const { return true; }
147 size_t getFlattenedSize() const { return kSizeTag; }
148
149 status_t flatten(void* buffer, size_t size) const {
150 FlattenableUtils::write(buffer, size, kFlattenTag);
151 return OK;
152 }
153
154 status_t unflatten(void const*, size_t) {
155 value = kUnflattenTag;
156 return OK;
157 }
158 };
159
160 {
161 // Verify that getFlattenedSize uses the LightFlattenable overload
162 LightFlattenableAndTriviallyCopyable foo;
163 EXPECT_EQ(kSizeTag, FlattenableHelpers::getFlattenedSize(foo));
164 }
165
166 {
167 // Verify that flatten uses the LightFlattenable overload
168 std::vector<int8_t> buffer(sizeof(int32_t));
169 auto rawBuffer = reinterpret_cast<void*>(buffer.data());
170 size_t size = buffer.size();
171 LightFlattenableAndTriviallyCopyable foo;
172 ASSERT_EQ(OK, FlattenableHelpers::flatten(&rawBuffer, &size, foo));
173
174 auto rawReadBuffer = reinterpret_cast<const void*>(buffer.data());
175 int32_t value;
176 FlattenableHelpers::unflatten(&rawReadBuffer, &size, &value);
177 EXPECT_EQ(kFlattenTag, value);
178 }
179
180 {
181 // Verify that unflatten uses the LightFlattenable overload
182 std::vector<int8_t> buffer(sizeof(int32_t));
183 auto rawBuffer = reinterpret_cast<void*>(buffer.data());
184 size_t size = buffer.size();
185 int32_t value = 4;
186 ASSERT_EQ(OK, FlattenableHelpers::flatten(&rawBuffer, &size, value));
187
188 auto rawReadBuffer = reinterpret_cast<const void*>(buffer.data());
189
190 LightFlattenableAndTriviallyCopyable foo;
191 FlattenableHelpers::unflatten(&rawReadBuffer, &size, &foo);
192 EXPECT_EQ(kUnflattenTag, foo.value);
193 }
194 }
195
196 } // namespace
197 } // namespace android
198