blob: d6ee7674a0c06cb2d9ac354348676e05332d9043 [file] [log] [blame] [edit]
/*
* 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 <cstring>
#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<int> p1 = MakeUnique<int>();
// Verify that the typical null checks are implemented correctly
ASSERT_FALSE(p1.isNull());
EXPECT_TRUE(p1);
EXPECT_NE(p1, nullptr);
}
{
UniquePtr<int> p1;
EXPECT_FALSE(p1);
EXPECT_TRUE(p1.isNull());
EXPECT_EQ(p1, nullptr);
}
UniquePtr<int> p2(nullptr);
EXPECT_TRUE(p2.isNull());
}
TEST(UniquePtr, Construct) {
UniquePtr<Value> myInt = MakeUnique<Value>(0xcafe);
ASSERT_TRUE(myInt);
EXPECT_EQ(myInt.get()->value, 0xcafe);
EXPECT_EQ(myInt->value, 0xcafe);
EXPECT_EQ((*myInt).value, 0xcafe);
int *realInt = chre::memoryAlloc<int>();
ASSERT_NE(realInt, nullptr);
UniquePtr<int> 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<int> == false &&
is_unbounded_array_v<char[2]> == false &&
is_unbounded_array_v<char[]> == 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<char[]> ptr = MakeUniqueArray<char[]>(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<BigArray[]>(kSize);
ASSERT_FALSE(ptr.isNull());
std::memset(ptr.get(), 0x37, sizeof(BigArray) * kSize);
}
}
TEST(UniquePtr, MakeUniqueZeroFill) {
BigArray baseline = {};
auto myArray = MakeUniqueZeroFill<BigArray>();
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<Value> myInt = MakeUnique<Value>(0xcafe);
ASSERT_FALSE(myInt.isNull());
Value *value = myInt.get();
UniquePtr<Value> moved(std::move(myInt));
EXPECT_EQ(moved.get(), value);
EXPECT_EQ(myInt.get(), nullptr);
}
TEST(UniquePtr, Move) {
Value::constructionCounter = 0;
{
UniquePtr<Value> myInt = MakeUnique<Value>(0xcafe);
ASSERT_FALSE(myInt.isNull());
EXPECT_EQ(Value::constructionCounter, 1);
UniquePtr<Value> myMovedInt = MakeUnique<Value>(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<Value> myInt = MakeUnique<Value>(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<Value> myInt = MakeUnique<Value>(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<Value>(0xcafe);
UniquePtr<Value> myInt2 = MakeUnique<Value>(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<Value> myInt = MakeUnique<Value>(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<OverAlignedStruct> ptr = MakeUnique<OverAlignedStruct>();
ASSERT_EQ(reinterpret_cast<uintptr_t>(ptr.get()) % alignof(OverAlignedStruct),
0);
}