xref: /aosp_15_r20/external/pigweed/pw_minimal_cpp_stdlib/isolated_test.cc (revision 61c4878ac05f98d0ceed94b57d316916de578985)
1 // Copyright 2019 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 all of the provided headers, even if they aren't tested.
16 #include <algorithm>
17 #include <array>
18 #include <cinttypes>
19 #include <cmath>
20 #include <cstdarg>
21 #include <cstddef>
22 #include <cstdint>
23 #include <cstdio>
24 #include <cstring>
25 #include <functional>
26 #include <initializer_list>
27 #include <iterator>
28 #include <limits>
29 #include <memory>
30 #include <new>
31 #include <string>
32 #include <string_view>
33 #include <type_traits>
34 #include <utility>
35 
36 #include "pw_polyfill/standard.h"
37 #include "pw_preprocessor/compiler.h"
38 
39 namespace {
40 
41 // In order to test this file without dependencies on the C++ standard library,
42 // this file needs to be fully isolated from the regular Pigweed testing
43 // infrastructure. pw_unit_test's dependencies do compile with the C++ standard
44 // library, which could conflict with pw_minimal_cpp_stdlib.
45 //
46 // SimpleTest provides the basic features of pw_unit_test without dependencies.
47 class SimpleTest {
48  public:
49   virtual ~SimpleTest() = default;
50 
RunAllTests()51   static bool RunAllTests() {
52     for (SimpleTest* test = all_tests; test != nullptr; test = test->next_) {
53       test->Run();
54       if (!test->passed_) {
55         return false;
56       }
57     }
58     return true;
59   }
60 
61  protected:
SimpleTest()62   SimpleTest() : next_(all_tests) { all_tests = this; }
63 
RecordTestFailure()64   void RecordTestFailure() { passed_ = false; }
65 
66  private:
67   virtual void Run() = 0;
68 
69   static SimpleTest* all_tests;
70 
71   bool passed_ = true;
72   SimpleTest* next_;
73 };
74 
75 SimpleTest* SimpleTest::all_tests = nullptr;
76 
77 #define EXPECT_EQ(lhs, rhs) \
78   do {                      \
79     if ((lhs) != (rhs)) {   \
80       RecordTestFailure();  \
81     }                       \
82   } while (0)
83 
84 #define EXPECT_NE(lhs, rhs) \
85   do {                      \
86     if ((lhs) == (rhs)) {   \
87       RecordTestFailure();  \
88     }                       \
89   } while (0)
90 
91 #define EXPECT_LT(lhs, rhs) \
92   do {                      \
93     if ((lhs) < (rhs)) {    \
94       RecordTestFailure();  \
95     }                       \
96   } while (0)
97 
98 #define EXPECT_GT(lhs, rhs) \
99   do {                      \
100     if ((lhs) > (rhs)) {    \
101       RecordTestFailure();  \
102     }                       \
103   } while (0)
104 
105 #define EXPECT_TRUE(expr) EXPECT_EQ(true, expr)
106 #define EXPECT_FALSE(expr) EXPECT_EQ(false, expr)
107 #define EXPECT_STREQ(lhs, rhs) EXPECT_EQ(std::strcmp((lhs), (rhs)), 0)
108 
109 #define TEST(suite, name)                                 \
110   class SimpleTest_##suite##_##name : public SimpleTest { \
111     void Run() override;                                  \
112   } test_##suite##_##name;                                \
113                                                           \
114   void SimpleTest_##suite##_##name::Run()
115 
TEST(Algorithm,Basic)116 TEST(Algorithm, Basic) {
117   static_assert(std::min(1, 2) == 1);
118   static_assert(std::max(1, 2) == 2);
119 
120   EXPECT_EQ(std::forward<int>(2), 2);
121 }
122 
TEST(Algorithm,Copy)123 TEST(Algorithm, Copy) {
124   constexpr size_t kCopyOffset = 1;
125   std::array<int, 3> foo{3, 2, 1};
126   std::array<int, 5> bar{0};
127 
128   // Ensure zero-element iterator doesn't modify the destination object when
129   // copied.
130   int temp = foo[0];
131   std::copy(foo.end(), foo.end(), bar.begin());
132   EXPECT_EQ(foo[0], temp);
133 
134   // Copy a single element.
135   std::array<int, 1> one{-101};
136   std::copy(one.begin(), one.end(), foo.begin());
137   EXPECT_EQ(foo[0], -101);
138 
139   auto copy_end = std::copy(foo.begin(), foo.end(), bar.begin() + kCopyOffset);
140   // Verify the iterator points to the end of the copied region.
141   EXPECT_EQ(copy_end, bar.begin() + foo.size() + kCopyOffset);
142 
143   // Verify all the values were properly copied from foo to bar.
144   {
145     size_t i = 0;
146     for (auto it = bar.begin() + kCopyOffset; it != copy_end; ++it) {
147       EXPECT_EQ(*it, foo[i++]);
148     }
149   }
150 }
151 
TEST(Algorithm,Find)152 TEST(Algorithm, Find) {
153   std::array<int, 5> foo{3, 2, 1, 42, 17};
154   // Ensure a value in the middle of the array is properly found.
155   EXPECT_EQ(*std::find(std::begin(foo), std::end(foo), 42), 42);
156 
157   // Ensure the iterator returned by find() matches the expected location of the
158   // element.
159   EXPECT_EQ(std::find(std::begin(foo), std::end(foo), 42), std::begin(foo) + 3);
160 
161   // Ensure an element at the beginning of an array is found.
162   EXPECT_EQ(*std::find(std::begin(foo), std::end(foo), 3), foo[0]);
163 
164   // Ensure an element at the end of an array is found.
165   EXPECT_EQ(*std::find(std::begin(foo), std::end(foo), 17),
166             foo[foo.size() - 1]);
167 }
168 
TEST(Algorithm,NotFound)169 TEST(Algorithm, NotFound) {
170   std::array<int, 3> foo{3, 2, 1};
171 
172   // Ensure that if an element is not found, an iterator matching foo.end() is
173   // returned.
174   EXPECT_EQ(std::find(std::begin(foo), std::end(foo), -99), std::end(foo));
175 
176   // Ensure that a zero-element iterator range returns the end iterator passed
177   // to std::find().
178   EXPECT_EQ(std::find(std::end(foo), std::end(foo), 3), std::end(foo));
179 }
180 
TEST(Array,Basic)181 TEST(Array, Basic) {
182   constexpr std::array<int, 4> array{0, 1, 2, 3};
183 
184   static_assert(array[2] == 2);
185 
186   for (int i = 0; i < static_cast<int>(array.size()); ++i) {
187     EXPECT_EQ(i, array[i]);
188   }
189 }
190 
TEST(Cmath,Basic)191 TEST(Cmath, Basic) PW_NO_SANITIZE("float-divide-by-zero") {
192   EXPECT_EQ(std::abs(-1), 1);
193   EXPECT_EQ(std::abs(1), 1);
194 
195   // Although Clang/LLVM do not fully support __STDC_IEC_559__, they do have the
196   // necessary IEEE 754 support for floating point division by zero.
197   EXPECT_TRUE(std::isfinite(1.0));
198   EXPECT_FALSE(std::isfinite(1.0 / 0.0));
199 
200   EXPECT_FALSE(std::isnan(1.0));
201   EXPECT_TRUE(std::isnan(0.0 / 0.0));
202 
203   EXPECT_FALSE(std::signbit(1.0));
204   EXPECT_TRUE(std::signbit(-1.0));
205 }
206 
TEST(Cstddef,Basic)207 TEST(Cstddef, Basic) {
208   using std::byte;
209   byte foo = byte{12};
210   EXPECT_EQ(foo, byte{12});
211 }
212 
TEST(Iterator,Basic)213 TEST(Iterator, Basic) {
214   std::array<int, 3> foo{3, 2, 1};
215 
216   EXPECT_EQ(std::data(foo), foo.data());
217   EXPECT_EQ(std::size(foo), foo.size());
218 
219   EXPECT_EQ(*std::begin(foo), foo[0]);
220   EXPECT_EQ(std::end(foo), std::begin(foo) + foo.size());
221 
222   foo.fill(99);
223   EXPECT_EQ(foo[0], 99);
224   EXPECT_EQ(foo[1], 99);
225   EXPECT_EQ(foo[2], 99);
226 }
227 
228 template <typename T>
SumFromInitializerList(std::initializer_list<T> values)229 int SumFromInitializerList(std::initializer_list<T> values) {
230   int sum = 0;
231   for (auto value : values) {
232     sum += value;
233   }
234   return sum;
235 }
TEST(InitializerList,Empty)236 TEST(InitializerList, Empty) {
237   std::initializer_list<int> mt;
238   EXPECT_EQ(0, SumFromInitializerList(mt));
239 
240   EXPECT_EQ(0, SumFromInitializerList<float>({}));
241 }
242 
TEST(InitializerList,Declared)243 TEST(InitializerList, Declared) {
244   std::initializer_list<char> list{'\3', '\3', '\4'};
245   EXPECT_EQ(10, SumFromInitializerList(list));
246 }
247 
TEST(InitializerList,Inline)248 TEST(InitializerList, Inline) {
249   EXPECT_EQ(42, SumFromInitializerList<long>({42}));
250   EXPECT_EQ(2, SumFromInitializerList<bool>({true, false, true}));
251   EXPECT_EQ(15, SumFromInitializerList({1, 2, 3, 4, 5}));
252 }
253 
TEST(Limits,Basic)254 TEST(Limits, Basic) {
255   static_assert(std::numeric_limits<unsigned char>::is_specialized);
256   static_assert(std::numeric_limits<unsigned char>::is_integer);
257   static_assert(std::numeric_limits<unsigned char>::min() == 0u);
258   static_assert(std::numeric_limits<unsigned char>::max() == 255u);
259 
260   static_assert(std::numeric_limits<signed char>::is_specialized);
261   static_assert(std::numeric_limits<signed char>::is_integer);
262   static_assert(std::numeric_limits<signed char>::min() == -128);
263   static_assert(std::numeric_limits<signed char>::max() == 127);
264 
265   // Assume 64-bit long long
266   static_assert(std::numeric_limits<long long>::is_specialized);
267   static_assert(std::numeric_limits<long long>::is_integer);
268   static_assert(std::numeric_limits<long long>::min() ==
269                 (-9223372036854775807ll - 1));
270   static_assert(std::numeric_limits<long long>::max() == 9223372036854775807ll);
271 
272   static_assert(std::numeric_limits<unsigned long long>::is_specialized);
273   static_assert(std::numeric_limits<unsigned long long>::is_integer);
274   static_assert(std::numeric_limits<unsigned long long>::min() == 0u);
275   static_assert(std::numeric_limits<unsigned long long>::max() ==
276                 18446744073709551615ull);
277 }
278 
TEST(New,PlacementNew)279 TEST(New, PlacementNew) {
280   alignas(sizeof(int)) unsigned char value[sizeof(int)];
281   new (value) int(1234);
282 
283   int int_value;
284   std::memcpy(&int_value, value, sizeof(int_value));
285   EXPECT_EQ(1234, int_value);
286 }
287 
TEST(New,Launder)288 TEST(New, Launder) {
289   unsigned char value[4];
290   int* int_ptr = std::launder(reinterpret_cast<int*>(value));
291   EXPECT_EQ(static_cast<void*>(int_ptr), static_cast<void*>(value));
292 }
293 
TEST(StringView,Basic)294 TEST(StringView, Basic) {
295   constexpr std::string_view value("1234567890");
296   static_assert(value.size() == 10);
297   static_assert(value[1] == '2');
298 
299   char buffer[] = "!!!!!";
300   constexpr size_t buffer_size = sizeof(buffer) - 1;  // always keep the \0
301 
302   value.copy(buffer, buffer_size, 10);
303   EXPECT_STREQ(buffer, "!!!!!");
304 
305   value.copy(buffer, buffer_size, 9);
306   EXPECT_STREQ(buffer, "0!!!!");
307 
308   value.copy(buffer, buffer_size, 2);
309   EXPECT_STREQ(buffer, "34567");
310 
311   value.copy(buffer, buffer_size);
312   EXPECT_STREQ(buffer, "12345");
313 }
314 
TEST(TypeTraits,Basic)315 TEST(TypeTraits, Basic) {
316   static_assert(std::is_integral_v<bool>);
317   static_assert(!std::is_integral_v<float>);
318 
319   static_assert(std::is_floating_point_v<float>);
320   static_assert(!std::is_floating_point_v<bool>);
321 
322   static_assert(std::is_same_v<float, float>);
323   static_assert(!std::is_same_v<char, unsigned char>);
324   static_assert(std::is_same_v<const int, std::add_const_t<int>>);
325   static_assert(std::is_same_v<const int, std::add_const_t<const int>>);
326   static_assert(!std::is_same_v<int, std::add_const_t<int>>);
327 }
328 
TEST(TypeTraits,LogicalTraits)329 TEST(TypeTraits, LogicalTraits) {
330   static_assert(std::conjunction_v<>);
331   static_assert(!std::conjunction_v<std::false_type>);
332   static_assert(std::conjunction_v<std::true_type>);
333   static_assert(!std::conjunction_v<std::false_type, std::true_type>);
334   static_assert(std::conjunction_v<std::true_type, std::true_type>);
335   static_assert(!std::conjunction_v<std::false_type, std::false_type>);
336 
337   static_assert(!std::disjunction_v<>);
338   static_assert(!std::disjunction_v<std::false_type>);
339   static_assert(std::disjunction_v<std::true_type>);
340   static_assert(std::disjunction_v<std::false_type, std::true_type>);
341   static_assert(std::disjunction_v<std::true_type, std::true_type>);
342   static_assert(!std::disjunction_v<std::false_type, std::false_type>);
343 
344   static_assert(std::negation_v<std::false_type>);
345   static_assert(!std::negation_v<std::true_type>);
346 }
347 
TEST(TypeTraits,AlignmentOf)348 TEST(TypeTraits, AlignmentOf) {
349   struct Foo {
350     char x;
351     double y;
352   };
353 
354   static_assert(std::alignment_of_v<int> == alignof(int));
355   static_assert(std::alignment_of_v<Foo> == alignof(Foo));
356 }
357 
358 struct MoveTester {
MoveTester__anon0a5057420111::MoveTester359   MoveTester(int value) : magic_value(value), moved(false) {}
360 
361   MoveTester(const MoveTester&) = default;
362 
MoveTester__anon0a5057420111::MoveTester363   MoveTester(MoveTester&& other) : magic_value(other.magic_value), moved(true) {
364     other.magic_value = 0xffff;
365   }
366 
367   int magic_value;
368   bool moved;
369 };
370 
TEST(Utility,Move)371 TEST(Utility, Move) {
372   MoveTester test(123);
373 
374   MoveTester copied(test);
375   EXPECT_EQ(copied.magic_value, 123);
376   EXPECT_FALSE(copied.moved);
377 
378   MoveTester moved(std::move(copied));
379   EXPECT_EQ(123, moved.magic_value);
380   // NOLINTNEXTLINE(bugprone-use-after-move)
381   EXPECT_EQ(0xffff, copied.magic_value);
382   EXPECT_TRUE(moved.moved);
383 }
384 
TEST(Utility,MakeIntegerSequence)385 TEST(Utility, MakeIntegerSequence) {
386   static_assert(std::is_same_v<std::make_integer_sequence<int, 0>,
387                                std::integer_sequence<int>>);
388   static_assert(std::is_same_v<std::make_integer_sequence<int, 1>,
389                                std::integer_sequence<int, 0>>);
390   static_assert(std::is_same_v<std::make_integer_sequence<int, 3>,
391                                std::integer_sequence<int, 0, 1, 2>>);
392 
393   static_assert(std::is_same_v<std::make_index_sequence<0>,
394                                std::integer_sequence<size_t>>);
395   static_assert(std::is_same_v<std::make_index_sequence<1>,
396                                std::integer_sequence<size_t, 0>>);
397   static_assert(std::is_same_v<std::make_index_sequence<3>,
398                                std::integer_sequence<size_t, 0, 1, 2>>);
399 }
400 
TEST(Iterator,Tags)401 TEST(Iterator, Tags) {
402   static_assert(std::is_convertible_v<std::forward_iterator_tag,
403                                       std::input_iterator_tag>);
404 
405   static_assert(std::is_convertible_v<std::bidirectional_iterator_tag,
406                                       std::input_iterator_tag>);
407   static_assert(std::is_convertible_v<std::bidirectional_iterator_tag,
408                                       std::forward_iterator_tag>);
409 
410   static_assert(std::is_convertible_v<std::random_access_iterator_tag,
411                                       std::input_iterator_tag>);
412   static_assert(std::is_convertible_v<std::random_access_iterator_tag,
413                                       std::forward_iterator_tag>);
414   static_assert(std::is_convertible_v<std::random_access_iterator_tag,
415                                       std::bidirectional_iterator_tag>);
416 
417 #if PW_CXX_STANDARD_IS_SUPPORTED(20)
418   static_assert(std::is_convertible_v<std::contiguous_iterator_tag,
419                                       std::input_iterator_tag>);
420   static_assert(std::is_convertible_v<std::contiguous_iterator_tag,
421                                       std::forward_iterator_tag>);
422   static_assert(std::is_convertible_v<std::contiguous_iterator_tag,
423                                       std::bidirectional_iterator_tag>);
424   static_assert(std::is_convertible_v<std::contiguous_iterator_tag,
425                                       std::random_access_iterator_tag>);
426 #endif  // PW_CXX_STANDARD_IS_SUPPORTED(20)
427 }
428 
TEST(Memory,AddressOf)429 TEST(Memory, AddressOf) {
430   struct Foo {
431     Foo** operator&() { return nullptr; }  // NOLINT
432   } nullptr_address;
433 
434   EXPECT_EQ(&nullptr_address, nullptr);
435   EXPECT_NE(std::addressof(nullptr_address), nullptr);
436 }
437 
TEST(String,CharTraits)438 TEST(String, CharTraits) {
439   static_assert(std::char_traits<char>::compare("1234a", "1234z", 4) == 0);
440   static_assert(std::char_traits<char>::compare("1234a", "1234z", 5) < 0);
441   static_assert(std::char_traits<char>::compare("1234z", "1234a", 5) > 0);
442 }
443 
444 }  // namespace
445 
446 namespace pw::minimal_cpp_stdlib {
447 
RunAllTests()448 bool RunAllTests() { return SimpleTest::RunAllTests(); }
449 
450 }  // namespace pw::minimal_cpp_stdlib
451