1 /*
2 * Copyright (C) 2019 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 #include <errno.h>
18
19 #include <algorithm>
20 #include <iostream>
21 #include <memory>
22 #include <string>
23 #include <type_traits>
24 #include <vector>
25
26 #if defined(TRUSTY_USERSPACE)
27 #include <trusty_unittest.h>
28 #else
29 #include <lib/unittest/unittest.h>
30 #include <lk/trusty_unittest.h>
31 #endif
32
33 int global_count;
34
35 #define CHECK_ERRNO(e) \
36 do { \
37 ASSERT_EQ(e, errno); \
38 errno = 0; \
39 } while (0)
40 #define CLEAR_ERRNO() \
41 do { \
42 errno = 0; \
43 } while (0)
44
45 typedef struct libcxx {
46 } libcxx_t;
47
TEST_F_SETUP(libcxx)48 TEST_F_SETUP(libcxx) {
49 /* Isolate the tests. */
50 CLEAR_ERRNO();
51 global_count = 0;
52 }
53
TEST_F_TEARDOWN(libcxx)54 TEST_F_TEARDOWN(libcxx) {
55 /* errno should have been checked and cleared if the test sets errno. */
56 CHECK_ERRNO(0);
57 ASSERT_EQ(0, global_count);
58
59 test_abort:
60 global_count = 0;
61 }
62
63 class Stub {};
64
TEST_F(libcxx,new_and_delete)65 TEST_F(libcxx, new_and_delete) {
66 Stub* tmp = new Stub();
67 ASSERT_NE(nullptr, tmp);
68 delete tmp;
69 test_abort:;
70 }
71
72 /*
73 * NOTE currently -fno-threadsafe-statics is suppressing threadsafe statics.
74 * When this is no longer the case, this test will link against __cxa_guard_*.
75 * This test is mainly checking that static initializers are executed only once
76 * and that all required ABI functions are provided. Thread safety is outside
77 * the scope of this test.
78 */
static_stub_getter()79 static Stub* static_stub_getter() {
80 static Stub* d = new Stub();
81 return d;
82 }
83
TEST_F(libcxx,safe_static)84 TEST_F(libcxx, safe_static) {
85 ASSERT_NE(nullptr, static_stub_getter());
86 ASSERT_EQ(static_stub_getter(), static_stub_getter());
87
88 test_abort:;
89 }
90
91 /*
92 * Inspecting the generated code, it appears this variable can be optimized out
93 * if it is not declared volatile.
94 */
95 volatile bool did_init;
96
97 class GlobalSetter {
98 public:
GlobalSetter()99 GlobalSetter() { did_init = true; }
100 };
101
102 GlobalSetter setter;
103
TEST_F(libcxx,global_constructor)104 TEST_F(libcxx, global_constructor) {
105 /* Did a global constructor run? */
106 ASSERT_EQ(true, did_init);
107 test_abort:;
108 }
109
110 class Counter {
111 public:
Counter()112 Counter() { global_count++; }
113
Counter(const Counter & other)114 Counter(const Counter& other) { global_count++; }
115
~Counter()116 ~Counter() { global_count--; }
117 };
118
TEST_F(libcxx,unique_ptr)119 TEST_F(libcxx, unique_ptr) {
120 ASSERT_EQ(0, global_count);
121 {
122 std::unique_ptr<Counter> u(new Counter());
123 ASSERT_EQ(1, global_count);
124 }
125 ASSERT_EQ(0, global_count);
126 test_abort:;
127 }
128
TEST_F(libcxx,unique_ptr_move)129 TEST_F(libcxx, unique_ptr_move) {
130 Counter* p = new Counter();
131 std::unique_ptr<Counter> a(p);
132 std::unique_ptr<Counter> b;
133
134 ASSERT_EQ(1, global_count);
135 ASSERT_EQ(p, a.get());
136 ASSERT_EQ(nullptr, b.get());
137
138 b = std::move(a);
139
140 ASSERT_EQ(1, global_count);
141 ASSERT_EQ(nullptr, a.get());
142 ASSERT_EQ(p, b.get());
143
144 b.reset();
145 ASSERT_EQ(0, global_count);
146 ASSERT_EQ(nullptr, b.get());
147
148 test_abort:;
149 }
150
TEST_F(libcxx,shared_ptr)151 TEST_F(libcxx, shared_ptr) {
152 std::shared_ptr<Counter> a;
153 std::shared_ptr<Counter> b;
154 ASSERT_EQ(0, global_count);
155 a.reset(new Counter());
156 ASSERT_EQ(1, global_count);
157 b = a;
158 ASSERT_EQ(1, global_count);
159 ASSERT_NE(nullptr, a.get());
160 ASSERT_EQ(a.get(), b.get());
161 a.reset();
162 ASSERT_EQ(1, global_count);
163 b.reset();
164 ASSERT_EQ(0, global_count);
165
166 test_abort:;
167 }
168
TEST_F(libcxx,shared_ptr_move)169 TEST_F(libcxx, shared_ptr_move) {
170 Counter* p = new Counter();
171 std::shared_ptr<Counter> a(p);
172 std::shared_ptr<Counter> b;
173
174 ASSERT_EQ(1, global_count);
175 ASSERT_EQ(p, a.get());
176 ASSERT_EQ(nullptr, b.get());
177
178 b = std::move(a);
179
180 ASSERT_EQ(1, global_count);
181 ASSERT_EQ(nullptr, a.get());
182 ASSERT_EQ(p, b.get());
183
184 b.reset();
185 ASSERT_EQ(0, global_count);
186 ASSERT_EQ(nullptr, b.get());
187
188 test_abort:;
189 }
190
TEST_F(libcxx,weak_ptr)191 TEST_F(libcxx, weak_ptr) {
192 std::weak_ptr<Counter> w;
193 ASSERT_EQ(0, global_count);
194 {
195 std::shared_ptr<Counter> s(new Counter());
196 w = s;
197 ASSERT_EQ(1, global_count);
198 ASSERT_EQ(1, w.use_count());
199 {
200 auto t = w.lock();
201 ASSERT_EQ(1, global_count);
202 ASSERT_EQ(2, w.use_count());
203 ASSERT_EQ(s.get(), t.get());
204 }
205 ASSERT_EQ(1, global_count);
206 ASSERT_EQ(1, w.use_count());
207 }
208 ASSERT_EQ(0, global_count);
209 ASSERT_EQ(0, w.use_count());
210
211 test_abort:;
212 }
213
TEST_F(libcxx,weak_ptr_move)214 TEST_F(libcxx, weak_ptr_move) {
215 std::shared_ptr<Counter> s(new Counter());
216 std::weak_ptr<Counter> a(s);
217 std::weak_ptr<Counter> b;
218
219 ASSERT_EQ(1, global_count);
220 ASSERT_EQ(1, a.use_count());
221 ASSERT_EQ(0, b.use_count());
222
223 b = std::move(a);
224
225 ASSERT_EQ(1, global_count);
226 ASSERT_EQ(0, a.use_count());
227 ASSERT_EQ(1, b.use_count());
228
229 s.reset();
230
231 ASSERT_EQ(0, global_count);
232 ASSERT_EQ(0, b.use_count());
233
234 test_abort:;
235 }
236
237 // TODO test framework does not compare anything that can't be cast to long.
TEST_F(libcxx,string_append)238 TEST_F(libcxx, string_append) {
239 std::string a("abcdefghijklmnopqrstuvwxyz!!!");
240 std::string b("abcdefghijklmnopqrstuvwxyz");
241 ASSERT_NE(0, strcmp(a.c_str(), b.c_str()));
242 b += "!!!";
243 ASSERT_EQ(0, strcmp(a.c_str(), b.c_str()));
244
245 test_abort:;
246 }
247
TEST_F(libcxx,string_move)248 TEST_F(libcxx, string_move) {
249 std::string a("foo");
250 std::string b;
251 ASSERT_EQ(0, strcmp(a.c_str(), "foo"));
252 ASSERT_NE(0, strcmp(b.c_str(), "foo"));
253
254 b = std::move(a);
255
256 ASSERT_NE(0, strcmp(a.c_str(), "foo"));
257 ASSERT_EQ(0, strcmp(b.c_str(), "foo"));
258
259 test_abort:;
260 }
261
TEST_F(libcxx,to_string)262 TEST_F(libcxx, to_string) {
263 ASSERT_EQ(0, strcmp(std::to_string(123).c_str(), "123"));
264
265 test_abort:;
266 }
267
TEST_F(libcxx,vector)268 TEST_F(libcxx, vector) {
269 const int limit = 20;
270 std::vector<int> v = {1, 2, 3, 4, 5, 6, 7};
271 for (int i = 8; i <= limit; ++i) {
272 v.push_back(i);
273 }
274 int sum = 0;
275 for (auto it = v.begin(); it != v.end(); ++it) {
276 sum += *it;
277 }
278 ASSERT_EQ(limit * (limit + 1) / 2, sum);
279
280 test_abort:;
281 }
282
TEST_F(libcxx,vector_move)283 TEST_F(libcxx, vector_move) {
284 std::vector<Counter> a(3);
285 std::vector<Counter> b;
286
287 EXPECT_EQ(3, global_count);
288 EXPECT_EQ(3U, a.size());
289 EXPECT_EQ(0U, b.size());
290
291 b = std::move(a);
292
293 // Note: can't say much about the state of "a".
294 EXPECT_EQ(3U, b.size());
295
296 a = {};
297 b = {};
298
299 EXPECT_EQ(0, global_count);
300
301 test_abort:;
302 }
303
304 // libcxx's headers "extern template" common parameterizations of std::sort.
305 // These parameterizations must be explicitly instantiated inside libcxx or
306 // else there will be a link error.
TEST_F(libcxx,vector_sort)307 TEST_F(libcxx, vector_sort) {
308 std::vector<int> v = {2, 3, 1};
309 std::sort(v.begin(), v.end());
310
311 EXPECT_EQ(1, v[0]);
312 EXPECT_EQ(2, v[1]);
313 EXPECT_EQ(3, v[2]);
314
315 test_abort:;
316 }
317
318 // Make sure a simple use of cout can compile and run.
TEST_F(libcxx,iostream_smoke_test)319 TEST_F(libcxx, iostream_smoke_test) {
320 std::cout << "Hello, world. " << 123 << "!" << std::endl;
321 }
322
323 class Parent {};
324
325 class Child : Parent {};
326
327 class Stranger {};
328
329 // Do we have full C++17 support?
TEST_F(libcxx,is_base_of_v)330 TEST_F(libcxx, is_base_of_v) {
331 // Extra parentheses needed because templates create lexical ambiguity for
332 // preprocessor.
333 EXPECT_EQ(true, (std::is_base_of_v<Parent, Parent>));
334 EXPECT_EQ(true, (std::is_base_of_v<Child, Child>));
335 EXPECT_EQ(true, (std::is_base_of_v<Stranger, Stranger>));
336 EXPECT_EQ(true, (std::is_base_of_v<Parent, Child>));
337 EXPECT_EQ(false, (std::is_base_of_v<Child, Parent>));
338 EXPECT_EQ(false, (std::is_base_of_v<Parent, Stranger>));
339 EXPECT_EQ(false, (std::is_base_of_v<Stranger, Parent>));
340 EXPECT_EQ(false, (std::is_base_of_v<Child, Stranger>));
341 EXPECT_EQ(false, (std::is_base_of_v<Stranger, Child>));
342 }
343
344 #if defined(TRUSTY_USERSPACE)
345 PORT_TEST(libcxx, "com.android.libcxxtest");
346 #else
347 PORT_TEST(libcxx, "com.android.kernel.libcxxtest");
348 #endif
349