/* * Copyright (C) 2017 The Android Open Source Project * * 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 * * http://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 #include "gtest/gtest.h" #include "chre/util/unique_ptr.h" using chre::MakeUnique; using chre::MakeUniqueArray; using chre::MakeUniqueZeroFill; using chre::UniquePtr; using chre::util::internal::is_unbounded_array_v; struct Value { Value(int value) : value(value) { constructionCounter++; } ~Value() { constructionCounter--; } Value &operator=(Value &&other) { value = other.value; return *this; } int value; static int constructionCounter; }; int Value::constructionCounter = 0; TEST(UniquePtr, NullInit) { // Put something on the stack to help catch uninitialized memory errors { UniquePtr p1 = MakeUnique(); // Verify that the typical null checks are implemented correctly ASSERT_FALSE(p1.isNull()); EXPECT_TRUE(p1); EXPECT_NE(p1, nullptr); } { UniquePtr p1; EXPECT_FALSE(p1); EXPECT_TRUE(p1.isNull()); EXPECT_EQ(p1, nullptr); } UniquePtr p2(nullptr); EXPECT_TRUE(p2.isNull()); } TEST(UniquePtr, Construct) { UniquePtr myInt = MakeUnique(0xcafe); ASSERT_TRUE(myInt); EXPECT_EQ(myInt.get()->value, 0xcafe); EXPECT_EQ(myInt->value, 0xcafe); EXPECT_EQ((*myInt).value, 0xcafe); int *realInt = chre::memoryAlloc(); ASSERT_NE(realInt, nullptr); UniquePtr wrapped(realInt); ASSERT_TRUE(realInt); } struct BigArray { int x[2048]; }; // Check the is_unbounded_array_v backport used in memoryAllocArray to help // constrain usage of MakeUniqueArray to only the proper type category static_assert(is_unbounded_array_v == false && is_unbounded_array_v == false && is_unbounded_array_v == true, "is_unbounded_array_v implemented incorrectly"); TEST(UniquePtr, MakeUniqueArray) { // For these tests, we are just allocating and writing to the array - the main // thing we are looking for is that the allocation is of an appropriate size, // which should be checked when running this test with sanitizers enabled { constexpr size_t kSize = 32; UniquePtr ptr = MakeUniqueArray(kSize); ASSERT_FALSE(ptr.isNull()); std::memset(ptr.get(), 0x98, kSize); ptr[0] = 0x11; EXPECT_EQ(*ptr.get(), 0x11); } { constexpr size_t kSize = 4; auto ptr = MakeUniqueArray(kSize); ASSERT_FALSE(ptr.isNull()); std::memset(ptr.get(), 0x37, sizeof(BigArray) * kSize); } } TEST(UniquePtr, MakeUniqueZeroFill) { BigArray baseline = {}; auto myArray = MakeUniqueZeroFill(); ASSERT_FALSE(myArray.isNull()); // Note that this doesn't actually test things properly, because we don't // guarantee that malloc is not already giving us zeroed out memory. To // properly do it, we could inject the allocator, but this function is simple // enough that it's not really worth the effort. EXPECT_EQ(std::memcmp(&baseline, myArray.get(), sizeof(baseline)), 0); } TEST(UniquePtr, MoveConstruct) { UniquePtr myInt = MakeUnique(0xcafe); ASSERT_FALSE(myInt.isNull()); Value *value = myInt.get(); UniquePtr moved(std::move(myInt)); EXPECT_EQ(moved.get(), value); EXPECT_EQ(myInt.get(), nullptr); } TEST(UniquePtr, Move) { Value::constructionCounter = 0; { UniquePtr myInt = MakeUnique(0xcafe); ASSERT_FALSE(myInt.isNull()); EXPECT_EQ(Value::constructionCounter, 1); UniquePtr myMovedInt = MakeUnique(0); ASSERT_FALSE(myMovedInt.isNull()); EXPECT_EQ(Value::constructionCounter, 2); myMovedInt = std::move(myInt); ASSERT_FALSE(myMovedInt.isNull()); ASSERT_TRUE(myInt.isNull()); EXPECT_EQ(myMovedInt.get()->value, 0xcafe); } EXPECT_EQ(Value::constructionCounter, 0); } TEST(UniquePtr, Release) { Value::constructionCounter = 0; Value *value1, *value2; { UniquePtr myInt = MakeUnique(0xcafe); ASSERT_FALSE(myInt.isNull()); EXPECT_EQ(Value::constructionCounter, 1); value1 = myInt.get(); EXPECT_NE(value1, nullptr); value2 = myInt.release(); EXPECT_EQ(value1, value2); EXPECT_EQ(myInt.get(), nullptr); EXPECT_TRUE(myInt.isNull()); } EXPECT_EQ(Value::constructionCounter, 1); EXPECT_EQ(value2->value, 0xcafe); value2->~Value(); chre::memoryFree(value2); } TEST(UniquePtr, Reset) { Value::constructionCounter = 0; { UniquePtr myInt = MakeUnique(0xcafe); EXPECT_EQ(myInt.get()->value, 0xcafe); EXPECT_EQ(Value::constructionCounter, 1); myInt.reset(nullptr); EXPECT_EQ(myInt.get(), nullptr); EXPECT_EQ(Value::constructionCounter, 0); myInt = MakeUnique(0xcafe); UniquePtr myInt2 = MakeUnique(0xface); EXPECT_EQ(Value::constructionCounter, 2); myInt.reset(myInt2.release()); EXPECT_EQ(Value::constructionCounter, 1); EXPECT_EQ(myInt.get()->value, 0xface); EXPECT_EQ(myInt2.get(), nullptr); myInt.reset(); EXPECT_EQ(myInt.get(), nullptr); } EXPECT_EQ(Value::constructionCounter, 0); } TEST(UniquePtr, EqualityOperator) { Value::constructionCounter = 0; { UniquePtr myInt = MakeUnique(0xcafe); EXPECT_TRUE(myInt != nullptr); myInt.reset(); EXPECT_TRUE(myInt == nullptr); } EXPECT_EQ(Value::constructionCounter, 0); } TEST(UniquePtr, OverAlignedTest) { // Explicitly overaligned structure larger than std::max_align_t. struct alignas(32) OverAlignedStruct { uint32_t x[32]; }; static_assert(alignof(OverAlignedStruct) > alignof(std::max_align_t)); UniquePtr ptr = MakeUnique(); ASSERT_EQ(reinterpret_cast(ptr.get()) % alignof(OverAlignedStruct), 0); }