|  | /* | 
|  | * 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::MakeUniqueZeroFill; | 
|  | using chre::UniquePtr; | 
|  |  | 
|  | 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, Construct) { | 
|  | UniquePtr<Value> myInt = MakeUnique<Value>(0xcafe); | 
|  | ASSERT_FALSE(myInt.isNull()); | 
|  | EXPECT_EQ(myInt.get()->value, 0xcafe); | 
|  | EXPECT_EQ(myInt->value, 0xcafe); | 
|  | EXPECT_EQ((*myInt).value, 0xcafe); | 
|  | EXPECT_EQ(myInt[0].value, 0xcafe); | 
|  | } | 
|  |  | 
|  | struct BigArray { | 
|  | int x[2048]; | 
|  | }; | 
|  |  | 
|  | 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); | 
|  | } |