// 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 #include "pw_compilation_testing/negative_compilation.h" #include "pw_unit_test/framework.h" namespace { template struct alignas(kAlign) Aligned { uint16_t val_ = 0; }; TEST(PackedPtrTest, NumBits) { EXPECT_EQ(pw::PackedPtr>::NumBits(), 1U); EXPECT_EQ(pw::PackedPtr>::NumBits(), 2U); EXPECT_EQ(pw::PackedPtr>::NumBits(), 3U); EXPECT_EQ(pw::PackedPtr>::NumBits(), 4U); EXPECT_EQ(pw::PackedPtr>::NumBits(), 5U); EXPECT_EQ(pw::PackedPtr>::NumBits(), 6U); EXPECT_EQ(pw::PackedPtr>::NumBits(), 7U); EXPECT_EQ(pw::PackedPtr>::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::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 bad; #endif // PW_NC_TEST TEST(PackedPtrTest, Construct_Default) { pw::PackedPtr> 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> 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> 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 ptr_; }; TEST(PackedPtrTest, Construct_Recursive) { pw::PackedPtr 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> 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> 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