blob: 1be96627f4d2770744d9ec901c8968ed4bc1aae5 [file] [log] [blame]
Wyatt Hepler023f35b2020-07-01 09:40:50 -07001// 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
35namespace {
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.
43class SimpleTest {
44 public:
45 virtual ~SimpleTest() = default;
46
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:
58 SimpleTest() : next_(all_tests) { all_tests = this; }
59
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
71SimpleTest* 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
91TEST(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
98TEST(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
127TEST(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
144TEST(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
156TEST(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
166TEST(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
182TEST(Cstddef, Basic) {
183 using std::byte;
184 byte foo = byte{12};
185 EXPECT_EQ(foo, byte{12});
186}
187
188TEST(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
203template <typename T>
204int SumFromInitializerList(std::initializer_list<T> values) {
205 int sum = 0;
206 for (auto value : values) {
207 sum += value;
208 }
209 return sum;
210}
211TEST(InitializerList, Empty) {
212 std::initializer_list<int> mt;
213 EXPECT_EQ(0, SumFromInitializerList(mt));
214
215 EXPECT_EQ(0, SumFromInitializerList<float>({}));
216}
217
218TEST(InitializerList, Declared) {
219 std::initializer_list<char> list{'\3', '\3', '\4'};
220 EXPECT_EQ(10, SumFromInitializerList(list));
221}
222
223TEST(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
229TEST(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
254TEST(New, PlacementNew) {
Prashanth Swaminathanbe29ad92021-02-02 22:16:29 -0800255 alignas(sizeof(int)) unsigned char value[sizeof(int)];
Wyatt Hepler023f35b2020-07-01 09:40:50 -0700256 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
263TEST(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
269TEST(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
290TEST(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
301struct MoveTester {
302 MoveTester(int value) : magic_value(value), moved(false) {}
303
304 MoveTester(const MoveTester&) = default;
305
306 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
314TEST(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
329namespace pw::minimal_cpp_stdlib {
330
331bool RunAllTests() { return SimpleTest::RunAllTests(); }
332
333} // namespace pw::minimal_cpp_stdlib