|  | // Copyright 2019 The Pigweed Authors | 
|  | // | 
|  | // Licensed under the Apache License, Version 2.0 (the "License"); you may not | 
|  | // use this file except in compliance with the License. You may obtain a copy of | 
|  | // the License at | 
|  | // | 
|  | //     https://www.apache.org/licenses/LICENSE-2.0 | 
|  | // | 
|  | // Unless required by applicable law or agreed to in writing, software | 
|  | // distributed under the License is distributed on an "AS IS" BASIS, WITHOUT | 
|  | // WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the | 
|  | // License for the specific language governing permissions and limitations under | 
|  | // the License. | 
|  |  | 
|  | // Include all of the provided headers, even if they aren't tested. | 
|  | #include <algorithm> | 
|  | #include <array> | 
|  | #include <cinttypes> | 
|  | #include <cmath> | 
|  | #include <cstdarg> | 
|  | #include <cstddef> | 
|  | #include <cstdint> | 
|  | #include <cstdio> | 
|  | #include <cstring> | 
|  | #include <initializer_list> | 
|  | #include <iterator> | 
|  | #include <limits> | 
|  | #include <new> | 
|  | #include <string_view> | 
|  | #include <type_traits> | 
|  | #include <utility> | 
|  |  | 
|  | #include "gtest/gtest.h" | 
|  |  | 
|  | namespace { | 
|  |  | 
|  | TEST(Algorithm, Basic) { | 
|  | static_assert(std::min(1, 2) == 1); | 
|  | static_assert(std::max(1, 2) == 2); | 
|  |  | 
|  | EXPECT_EQ(std::forward<int>(2), 2); | 
|  | } | 
|  |  | 
|  | TEST(Algorithm, Copy) { | 
|  | constexpr size_t kCopyOffset = 1; | 
|  | std::array<int, 3> foo{3, 2, 1}; | 
|  | std::array<int, 5> bar{0}; | 
|  |  | 
|  | // Ensure zero-element iterator doesn't modify the destination object when | 
|  | // copied. | 
|  | int temp = foo[0]; | 
|  | std::copy(foo.end(), foo.end(), bar.begin()); | 
|  | EXPECT_EQ(foo[0], temp); | 
|  |  | 
|  | // Copy a single element. | 
|  | std::array<int, 1> one{-101}; | 
|  | std::copy(one.begin(), one.end(), foo.begin()); | 
|  | EXPECT_EQ(foo[0], -101); | 
|  |  | 
|  | auto copy_end = std::copy(foo.begin(), foo.end(), bar.begin() + kCopyOffset); | 
|  | // Verify the iterator points to the end of the copied region. | 
|  | EXPECT_EQ(copy_end, bar.begin() + foo.size() + kCopyOffset); | 
|  |  | 
|  | // Verify all the values were properly copied from foo to bar. | 
|  | { | 
|  | size_t i = 0; | 
|  | for (auto it = bar.begin() + kCopyOffset; it != copy_end; ++it) { | 
|  | EXPECT_EQ(*it, foo[i++]); | 
|  | } | 
|  | } | 
|  | } | 
|  |  | 
|  | TEST(Algorithm, Find) { | 
|  | std::array<int, 5> foo{3, 2, 1, 42, 17}; | 
|  | // Ensure a value in the middle of the array is properly found. | 
|  | EXPECT_EQ(*std::find(std::begin(foo), std::end(foo), 42), 42); | 
|  |  | 
|  | // Ensure the iterator returned by find() matches the expected location of the | 
|  | // element. | 
|  | EXPECT_EQ(std::find(std::begin(foo), std::end(foo), 42), std::begin(foo) + 3); | 
|  |  | 
|  | // Ensure an element at the beginning of an array is found. | 
|  | EXPECT_EQ(*std::find(std::begin(foo), std::end(foo), 3), foo[0]); | 
|  |  | 
|  | // Ensure an element at the end of an array is found. | 
|  | EXPECT_EQ(*std::find(std::begin(foo), std::end(foo), 17), | 
|  | foo[foo.size() - 1]); | 
|  | } | 
|  |  | 
|  | TEST(Algorithm, NotFound) { | 
|  | std::array<int, 3> foo{3, 2, 1}; | 
|  |  | 
|  | // Ensure that if an element is not found, an iterator matching foo.end() is | 
|  | // returned. | 
|  | EXPECT_EQ(std::find(std::begin(foo), std::end(foo), -99), std::end(foo)); | 
|  |  | 
|  | // Ensure that a zero-element iterator range returns the end iterator passed | 
|  | // to std::find(). | 
|  | EXPECT_EQ(std::find(std::end(foo), std::end(foo), 3), std::end(foo)); | 
|  | } | 
|  |  | 
|  | TEST(Array, Basic) { | 
|  | constexpr std::array<int, 4> array{0, 1, 2, 3}; | 
|  |  | 
|  | static_assert(array[2] == 2); | 
|  |  | 
|  | for (int i = 0; i < static_cast<int>(array.size()); ++i) { | 
|  | EXPECT_EQ(i, array[i]); | 
|  | } | 
|  | } | 
|  |  | 
|  | TEST(Cmath, Basic) PW_NO_SANITIZE("float-divide-by-zero") { | 
|  | EXPECT_EQ(std::abs(-1), 1); | 
|  | EXPECT_EQ(std::abs(1), 1); | 
|  |  | 
|  | // Although Clang/LLVM do not fully support __STDC_IEC_559__, they do have the | 
|  | // necessary IEEE 754 support for floating point division by zero. | 
|  | EXPECT_TRUE(std::isfinite(1.0)); | 
|  | EXPECT_FALSE(std::isfinite(1.0 / 0.0)); | 
|  |  | 
|  | EXPECT_FALSE(std::isnan(1.0)); | 
|  | EXPECT_TRUE(std::isnan(0.0 / 0.0)); | 
|  |  | 
|  | EXPECT_FALSE(std::signbit(1.0)); | 
|  | EXPECT_TRUE(std::signbit(-1.0)); | 
|  | } | 
|  |  | 
|  | TEST(Cstddef, Basic) { | 
|  | using std::byte; | 
|  | byte foo = byte{12}; | 
|  | EXPECT_EQ(foo, byte{12}); | 
|  | } | 
|  |  | 
|  | TEST(Iterator, Basic) { | 
|  | std::array<int, 3> foo{3, 2, 1}; | 
|  |  | 
|  | EXPECT_EQ(std::data(foo), foo.data()); | 
|  | EXPECT_EQ(std::size(foo), foo.size()); | 
|  |  | 
|  | EXPECT_EQ(*std::begin(foo), foo[0]); | 
|  | EXPECT_EQ(std::end(foo), std::begin(foo) + foo.size()); | 
|  |  | 
|  | foo.fill(99); | 
|  | EXPECT_EQ(foo[0], 99); | 
|  | EXPECT_EQ(foo[1], 99); | 
|  | EXPECT_EQ(foo[2], 99); | 
|  | } | 
|  |  | 
|  | template <typename T> | 
|  | int SumFromInitializerList(std::initializer_list<T> values) { | 
|  | int sum = 0; | 
|  | for (auto value : values) { | 
|  | sum += value; | 
|  | } | 
|  | return sum; | 
|  | } | 
|  | TEST(InitializerList, Empty) { | 
|  | std::initializer_list<int> mt; | 
|  | EXPECT_EQ(0, SumFromInitializerList(mt)); | 
|  |  | 
|  | EXPECT_EQ(0, SumFromInitializerList<float>({})); | 
|  | } | 
|  |  | 
|  | TEST(InitializerList, Declared) { | 
|  | std::initializer_list<char> list{'\3', '\3', '\4'}; | 
|  | EXPECT_EQ(10, SumFromInitializerList(list)); | 
|  | } | 
|  |  | 
|  | TEST(InitializerList, Inline) { | 
|  | EXPECT_EQ(42, SumFromInitializerList<long>({42})); | 
|  | EXPECT_EQ(2, SumFromInitializerList<bool>({true, false, true})); | 
|  | EXPECT_EQ(15, SumFromInitializerList({1, 2, 3, 4, 5})); | 
|  | } | 
|  |  | 
|  | TEST(Limits, Basic) { | 
|  | static_assert(std::numeric_limits<unsigned char>::is_specialized); | 
|  | static_assert(std::numeric_limits<unsigned char>::is_integer); | 
|  | static_assert(std::numeric_limits<unsigned char>::min() == 0u); | 
|  | static_assert(std::numeric_limits<unsigned char>::max() == 255u); | 
|  |  | 
|  | static_assert(std::numeric_limits<signed char>::is_specialized); | 
|  | static_assert(std::numeric_limits<signed char>::is_integer); | 
|  | static_assert(std::numeric_limits<signed char>::min() == -128); | 
|  | static_assert(std::numeric_limits<signed char>::max() == 127); | 
|  |  | 
|  | // Assume 64-bit long long | 
|  | static_assert(std::numeric_limits<long long>::is_specialized); | 
|  | static_assert(std::numeric_limits<long long>::is_integer); | 
|  | static_assert(std::numeric_limits<long long>::min() == | 
|  | (-9223372036854775807ll - 1)); | 
|  | static_assert(std::numeric_limits<long long>::max() == 9223372036854775807ll); | 
|  |  | 
|  | static_assert(std::numeric_limits<unsigned long long>::is_specialized); | 
|  | static_assert(std::numeric_limits<unsigned long long>::is_integer); | 
|  | static_assert(std::numeric_limits<unsigned long long>::min() == 0u); | 
|  | static_assert(std::numeric_limits<unsigned long long>::max() == | 
|  | 18446744073709551615ull); | 
|  | } | 
|  |  | 
|  | TEST(New, PlacementNew) { | 
|  | unsigned char value[4]; | 
|  | new (value) int(1234); | 
|  |  | 
|  | int int_value; | 
|  | std::memcpy(&int_value, value, sizeof(int_value)); | 
|  | EXPECT_EQ(1234, int_value); | 
|  | } | 
|  |  | 
|  | TEST(New, Launder) { | 
|  | unsigned char value[4]; | 
|  | int* int_ptr = std::launder(reinterpret_cast<int*>(value)); | 
|  | EXPECT_EQ(static_cast<void*>(int_ptr), static_cast<void*>(value)); | 
|  | } | 
|  |  | 
|  | TEST(StringView, Basic) { | 
|  | constexpr std::string_view value("1234567890"); | 
|  | static_assert(value.size() == 10); | 
|  | static_assert(value[1] == '2'); | 
|  |  | 
|  | char buffer[] = "!!!!!"; | 
|  | constexpr size_t buffer_size = sizeof(buffer) - 1;  // always keep the \0 | 
|  |  | 
|  | value.copy(buffer, buffer_size, 10); | 
|  | EXPECT_STREQ(buffer, "!!!!!"); | 
|  |  | 
|  | value.copy(buffer, buffer_size, 9); | 
|  | EXPECT_STREQ(buffer, "0!!!!"); | 
|  |  | 
|  | value.copy(buffer, buffer_size, 2); | 
|  | EXPECT_STREQ(buffer, "34567"); | 
|  |  | 
|  | value.copy(buffer, buffer_size); | 
|  | EXPECT_STREQ(buffer, "12345"); | 
|  | } | 
|  |  | 
|  | TEST(TypeTraits, Basic) { | 
|  | static_assert(std::is_integral_v<bool>); | 
|  | static_assert(!std::is_integral_v<float>); | 
|  |  | 
|  | static_assert(std::is_floating_point_v<float>); | 
|  | static_assert(!std::is_floating_point_v<bool>); | 
|  |  | 
|  | static_assert(std::is_same_v<float, float>); | 
|  | static_assert(!std::is_same_v<char, unsigned char>); | 
|  | } | 
|  |  | 
|  | struct MoveTester { | 
|  | MoveTester(int value) : magic_value(value), moved(false) {} | 
|  |  | 
|  | MoveTester(const MoveTester&) = default; | 
|  |  | 
|  | MoveTester(MoveTester&& other) : magic_value(other.magic_value), moved(true) { | 
|  | other.magic_value = 0xffff; | 
|  | } | 
|  |  | 
|  | int magic_value; | 
|  | bool moved; | 
|  | }; | 
|  |  | 
|  | TEST(Utility, Move) { | 
|  | MoveTester test(123); | 
|  |  | 
|  | MoveTester copied(test); | 
|  | EXPECT_EQ(copied.magic_value, 123); | 
|  | EXPECT_FALSE(copied.moved); | 
|  |  | 
|  | MoveTester moved(std::move(copied)); | 
|  | EXPECT_EQ(123, moved.magic_value); | 
|  | EXPECT_EQ(0xffff, copied.magic_value); | 
|  | EXPECT_TRUE(moved.moved); | 
|  | } | 
|  |  | 
|  | }  // namespace |