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