| |
| // Copyright 2022 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 "pw_bytes/packed_ptr.h" |
| |
| #include <cstdint> |
| |
| #include "pw_compilation_testing/negative_compilation.h" |
| #include "pw_unit_test/framework.h" |
| |
| namespace { |
| |
| template <size_t kAlign> |
| struct alignas(kAlign) Aligned { |
| uint16_t val_ = 0; |
| }; |
| |
| TEST(PackedPtrTest, NumBits) { |
| EXPECT_EQ(pw::PackedPtr<Aligned<2>>::NumBits(), 1U); |
| EXPECT_EQ(pw::PackedPtr<Aligned<4>>::NumBits(), 2U); |
| EXPECT_EQ(pw::PackedPtr<Aligned<8>>::NumBits(), 3U); |
| EXPECT_EQ(pw::PackedPtr<Aligned<16>>::NumBits(), 4U); |
| EXPECT_EQ(pw::PackedPtr<Aligned<32>>::NumBits(), 5U); |
| EXPECT_EQ(pw::PackedPtr<Aligned<64>>::NumBits(), 6U); |
| EXPECT_EQ(pw::PackedPtr<Aligned<128>>::NumBits(), 7U); |
| EXPECT_EQ(pw::PackedPtr<Aligned<256>>::NumBits(), 8U); |
| } |
| |
| #if PW_NC_TEST(NumBits_AlignmentIsOne) |
| PW_NC_EXPECT("Alignment must be more than one to pack any bits"); |
| TEST(PackedPtrTest, NumBits_Char) { |
| EXPECT_EQ(pw::PackedPtr<char>::NumBits(), 0U); |
| } |
| #elif PW_NC_TEST(Construct_AlignmentIsOne) |
| PW_NC_EXPECT("Alignment must be more than one to pack any bits"); |
| [[maybe_unused]] pw::PackedPtr<std::byte> bad; |
| #endif // PW_NC_TEST |
| |
| TEST(PackedPtrTest, Construct_Default) { |
| pw::PackedPtr<Aligned<4>> ptr; |
| EXPECT_EQ(ptr.get(), nullptr); |
| EXPECT_EQ(ptr.packed_value(), 0U); |
| } |
| |
| TEST(PackedPtrTest, Construct_FromArgs) { |
| Aligned<16> obj; |
| pw::PackedPtr ptr(&obj, 1); |
| EXPECT_EQ(ptr.get(), &obj); |
| EXPECT_EQ(ptr.packed_value(), 1U); |
| } |
| |
| TEST(PackedPtrTest, Construct_Copy) { |
| Aligned<16> obj; |
| pw::PackedPtr ptr1(&obj, 2); |
| pw::PackedPtr ptr2(ptr1); |
| EXPECT_EQ(ptr1.get(), &obj); |
| EXPECT_EQ(ptr1.packed_value(), 2U); |
| EXPECT_EQ(ptr2.get(), &obj); |
| EXPECT_EQ(ptr2.packed_value(), 2U); |
| } |
| |
| TEST(PackedPtrTest, Construct_Copy_AddConst) { |
| Aligned<16> obj; |
| pw::PackedPtr ptr1(&obj, 2); |
| pw::PackedPtr<const Aligned<16>> ptr2(ptr1); |
| EXPECT_EQ(ptr1.get(), &obj); |
| EXPECT_EQ(ptr1.packed_value(), 2U); |
| EXPECT_EQ(ptr2.get(), &obj); |
| EXPECT_EQ(ptr2.packed_value(), 2U); |
| } |
| |
| TEST(PackedPtrTest, Construct_Move) { |
| Aligned<16> obj; |
| pw::PackedPtr ptr1(&obj, 3); |
| pw::PackedPtr ptr2(std::move(ptr1)); |
| // NOLINTBEGIN(bugprone-use-after-move) |
| EXPECT_EQ(ptr1.get(), nullptr); |
| EXPECT_EQ(ptr1.packed_value(), 0U); |
| // NOLINTEND(bugprone-use-after-move) |
| EXPECT_EQ(ptr2.get(), &obj); |
| EXPECT_EQ(ptr2.packed_value(), 3U); |
| } |
| |
| TEST(PackedPtrTest, Construct_Move_AddConst) { |
| Aligned<16> obj; |
| pw::PackedPtr ptr1(&obj, 3); |
| pw::PackedPtr<const Aligned<16>> ptr2(std::move(ptr1)); |
| // NOLINTBEGIN(bugprone-use-after-move) |
| EXPECT_EQ(ptr1.get(), nullptr); |
| EXPECT_EQ(ptr1.packed_value(), 0U); |
| // NOLINTEND(bugprone-use-after-move) |
| EXPECT_EQ(ptr2.get(), &obj); |
| EXPECT_EQ(ptr2.packed_value(), 3U); |
| } |
| |
| // Ensure we can create PackedPtrs to types that include PackedPtrs to |
| // themsevles. |
| struct Recursive { |
| size_t field_ = 0; |
| pw::PackedPtr<Recursive> ptr_; |
| }; |
| |
| TEST(PackedPtrTest, Construct_Recursive) { |
| pw::PackedPtr<Recursive> ptr; |
| EXPECT_EQ(ptr.get(), nullptr); |
| EXPECT_EQ(ptr.packed_value(), 0U); |
| } |
| |
| TEST(PackedPtrTest, Copy) { |
| Aligned<16> obj; |
| pw::PackedPtr ptr1(&obj, 4); |
| pw::PackedPtr ptr2 = ptr1; |
| EXPECT_EQ(ptr1.get(), &obj); |
| EXPECT_EQ(ptr1.packed_value(), 4U); |
| EXPECT_EQ(ptr2.get(), &obj); |
| EXPECT_EQ(ptr2.packed_value(), 4U); |
| } |
| |
| TEST(PackedPtrTest, Copy_AddConst) { |
| Aligned<16> obj; |
| pw::PackedPtr ptr1(&obj, 4); |
| pw::PackedPtr<const Aligned<16>> ptr2 = ptr1; |
| EXPECT_EQ(ptr1.get(), &obj); |
| EXPECT_EQ(ptr1.packed_value(), 4U); |
| EXPECT_EQ(ptr2.get(), &obj); |
| EXPECT_EQ(ptr2.packed_value(), 4U); |
| } |
| |
| TEST(PackedPtrTest, Move) { |
| Aligned<16> obj; |
| pw::PackedPtr ptr1(&obj, 6); |
| pw::PackedPtr ptr2 = std::move(ptr1); |
| // NOLINTBEGIN(bugprone-use-after-move) |
| EXPECT_EQ(ptr1.get(), nullptr); |
| EXPECT_EQ(ptr1.packed_value(), 0U); |
| // NOLINTEND(bugprone-use-after-move) |
| EXPECT_EQ(ptr2.get(), &obj); |
| EXPECT_EQ(ptr2.packed_value(), 6U); |
| } |
| |
| TEST(PackedPtrTest, Move_AddConst) { |
| Aligned<16> obj; |
| pw::PackedPtr ptr1(&obj, 6); |
| pw::PackedPtr<const Aligned<16>> ptr2 = std::move(ptr1); |
| // NOLINTBEGIN(bugprone-use-after-move) |
| EXPECT_EQ(ptr1.get(), nullptr); |
| EXPECT_EQ(ptr1.packed_value(), 0U); |
| // NOLINTEND(bugprone-use-after-move) |
| EXPECT_EQ(ptr2.get(), &obj); |
| EXPECT_EQ(ptr2.packed_value(), 6U); |
| } |
| |
| TEST(PackedPtrTest, Dereference) { |
| Aligned<4> obj{1u}; |
| pw::PackedPtr ptr(&obj, 0); |
| EXPECT_EQ((*ptr).val_, 1u); |
| } |
| |
| TEST(PackedPtrTest, Dereference_Const) { |
| Aligned<4> obj{22u}; |
| const pw::PackedPtr ptr(&obj, 0); |
| EXPECT_EQ((*ptr).val_, 22u); |
| } |
| |
| TEST(PackedPtrTest, StructureDereference) { |
| Aligned<4> obj{333u}; |
| pw::PackedPtr ptr(&obj, 0); |
| EXPECT_EQ(ptr->val_, 333u); |
| } |
| |
| TEST(PackedPtrTest, StructureDereference_Const) { |
| Aligned<4> obj{4444u}; |
| const pw::PackedPtr ptr(&obj, 0); |
| EXPECT_EQ(ptr->val_, 4444u); |
| } |
| |
| } // namespace |