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