223 lines
5.8 KiB
C++
223 lines
5.8 KiB
C++
|
// Copyright 2017 The Abseil 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.
|
||
|
|
||
|
// Tests for pointer utilities.
|
||
|
|
||
|
#include "absl/memory/memory.h"
|
||
|
|
||
|
#include <sys/types.h>
|
||
|
|
||
|
#include <cstddef>
|
||
|
#include <memory>
|
||
|
#include <string>
|
||
|
#include <type_traits>
|
||
|
#include <utility>
|
||
|
#include <vector>
|
||
|
|
||
|
#include "gmock/gmock.h"
|
||
|
#include "gtest/gtest.h"
|
||
|
|
||
|
namespace {
|
||
|
|
||
|
using ::testing::ElementsAre;
|
||
|
using ::testing::Return;
|
||
|
|
||
|
// This class creates observable behavior to verify that a destructor has
|
||
|
// been called, via the instance_count variable.
|
||
|
class DestructorVerifier {
|
||
|
public:
|
||
|
DestructorVerifier() { ++instance_count_; }
|
||
|
DestructorVerifier(const DestructorVerifier&) = delete;
|
||
|
DestructorVerifier& operator=(const DestructorVerifier&) = delete;
|
||
|
~DestructorVerifier() { --instance_count_; }
|
||
|
|
||
|
// The number of instances of this class currently active.
|
||
|
static int instance_count() { return instance_count_; }
|
||
|
|
||
|
private:
|
||
|
// The number of instances of this class currently active.
|
||
|
static int instance_count_;
|
||
|
};
|
||
|
|
||
|
int DestructorVerifier::instance_count_ = 0;
|
||
|
|
||
|
TEST(WrapUniqueTest, WrapUnique) {
|
||
|
// Test that the unique_ptr is constructed properly by verifying that the
|
||
|
// destructor for its payload gets called at the proper time.
|
||
|
{
|
||
|
auto dv = new DestructorVerifier;
|
||
|
EXPECT_EQ(1, DestructorVerifier::instance_count());
|
||
|
std::unique_ptr<DestructorVerifier> ptr = absl::WrapUnique(dv);
|
||
|
EXPECT_EQ(1, DestructorVerifier::instance_count());
|
||
|
}
|
||
|
EXPECT_EQ(0, DestructorVerifier::instance_count());
|
||
|
}
|
||
|
|
||
|
// InitializationVerifier fills in a pattern when allocated so we can
|
||
|
// distinguish between its default and value initialized states (without
|
||
|
// accessing truly uninitialized memory).
|
||
|
struct InitializationVerifier {
|
||
|
static constexpr int kDefaultScalar = 0x43;
|
||
|
static constexpr int kDefaultArray = 0x4B;
|
||
|
|
||
|
static void* operator new(size_t n) {
|
||
|
void* ret = ::operator new(n);
|
||
|
memset(ret, kDefaultScalar, n);
|
||
|
return ret;
|
||
|
}
|
||
|
|
||
|
static void* operator new[](size_t n) {
|
||
|
void* ret = ::operator new[](n);
|
||
|
memset(ret, kDefaultArray, n);
|
||
|
return ret;
|
||
|
}
|
||
|
|
||
|
int a;
|
||
|
int b;
|
||
|
};
|
||
|
|
||
|
struct ArrayWatch {
|
||
|
void* operator new[](size_t n) {
|
||
|
allocs().push_back(n);
|
||
|
return ::operator new[](n);
|
||
|
}
|
||
|
void operator delete[](void* p) { return ::operator delete[](p); }
|
||
|
static std::vector<size_t>& allocs() {
|
||
|
static auto& v = *new std::vector<size_t>;
|
||
|
return v;
|
||
|
}
|
||
|
};
|
||
|
|
||
|
TEST(RawPtrTest, RawPointer) {
|
||
|
int i = 5;
|
||
|
EXPECT_EQ(&i, absl::RawPtr(&i));
|
||
|
}
|
||
|
|
||
|
TEST(RawPtrTest, SmartPointer) {
|
||
|
int* o = new int(5);
|
||
|
std::unique_ptr<int> p(o);
|
||
|
EXPECT_EQ(o, absl::RawPtr(p));
|
||
|
}
|
||
|
|
||
|
class IntPointerNonConstDeref {
|
||
|
public:
|
||
|
explicit IntPointerNonConstDeref(int* p) : p_(p) {}
|
||
|
friend bool operator!=(const IntPointerNonConstDeref& a, std::nullptr_t) {
|
||
|
return a.p_ != nullptr;
|
||
|
}
|
||
|
int& operator*() { return *p_; }
|
||
|
|
||
|
private:
|
||
|
std::unique_ptr<int> p_;
|
||
|
};
|
||
|
|
||
|
TEST(RawPtrTest, SmartPointerNonConstDereference) {
|
||
|
int* o = new int(5);
|
||
|
IntPointerNonConstDeref p(o);
|
||
|
EXPECT_EQ(o, absl::RawPtr(p));
|
||
|
}
|
||
|
|
||
|
TEST(RawPtrTest, NullValuedRawPointer) {
|
||
|
int* p = nullptr;
|
||
|
EXPECT_EQ(nullptr, absl::RawPtr(p));
|
||
|
}
|
||
|
|
||
|
TEST(RawPtrTest, NullValuedSmartPointer) {
|
||
|
std::unique_ptr<int> p;
|
||
|
EXPECT_EQ(nullptr, absl::RawPtr(p));
|
||
|
}
|
||
|
|
||
|
TEST(RawPtrTest, Nullptr) {
|
||
|
auto p = absl::RawPtr(nullptr);
|
||
|
EXPECT_TRUE((std::is_same<std::nullptr_t, decltype(p)>::value));
|
||
|
EXPECT_EQ(nullptr, p);
|
||
|
}
|
||
|
|
||
|
TEST(RawPtrTest, Null) {
|
||
|
auto p = absl::RawPtr(nullptr);
|
||
|
EXPECT_TRUE((std::is_same<std::nullptr_t, decltype(p)>::value));
|
||
|
EXPECT_EQ(nullptr, p);
|
||
|
}
|
||
|
|
||
|
TEST(RawPtrTest, Zero) {
|
||
|
auto p = absl::RawPtr(nullptr);
|
||
|
EXPECT_TRUE((std::is_same<std::nullptr_t, decltype(p)>::value));
|
||
|
EXPECT_EQ(nullptr, p);
|
||
|
}
|
||
|
|
||
|
TEST(ShareUniquePtrTest, Share) {
|
||
|
auto up = absl::make_unique<int>();
|
||
|
int* rp = up.get();
|
||
|
auto sp = absl::ShareUniquePtr(std::move(up));
|
||
|
EXPECT_EQ(sp.get(), rp);
|
||
|
}
|
||
|
|
||
|
TEST(ShareUniquePtrTest, ShareNull) {
|
||
|
struct NeverDie {
|
||
|
using pointer = void*;
|
||
|
void operator()(pointer) {
|
||
|
ASSERT_TRUE(false) << "Deleter should not have been called.";
|
||
|
}
|
||
|
};
|
||
|
|
||
|
std::unique_ptr<void, NeverDie> up;
|
||
|
auto sp = absl::ShareUniquePtr(std::move(up));
|
||
|
}
|
||
|
|
||
|
TEST(WeakenPtrTest, Weak) {
|
||
|
auto sp = std::make_shared<int>();
|
||
|
auto wp = absl::WeakenPtr(sp);
|
||
|
EXPECT_EQ(sp.get(), wp.lock().get());
|
||
|
sp.reset();
|
||
|
EXPECT_TRUE(wp.expired());
|
||
|
}
|
||
|
|
||
|
// Should not compile.
|
||
|
/*
|
||
|
TEST(RawPtrTest, NotAPointer) {
|
||
|
absl::RawPtr(1.5);
|
||
|
}
|
||
|
*/
|
||
|
|
||
|
TEST(AllocatorNoThrowTest, DefaultAllocator) {
|
||
|
#if defined(ABSL_ALLOCATOR_NOTHROW) && ABSL_ALLOCATOR_NOTHROW
|
||
|
EXPECT_TRUE(absl::default_allocator_is_nothrow::value);
|
||
|
#else
|
||
|
EXPECT_FALSE(absl::default_allocator_is_nothrow::value);
|
||
|
#endif
|
||
|
}
|
||
|
|
||
|
TEST(AllocatorNoThrowTest, StdAllocator) {
|
||
|
#if defined(ABSL_ALLOCATOR_NOTHROW) && ABSL_ALLOCATOR_NOTHROW
|
||
|
EXPECT_TRUE(absl::allocator_is_nothrow<std::allocator<int>>::value);
|
||
|
#else
|
||
|
EXPECT_FALSE(absl::allocator_is_nothrow<std::allocator<int>>::value);
|
||
|
#endif
|
||
|
}
|
||
|
|
||
|
TEST(AllocatorNoThrowTest, CustomAllocator) {
|
||
|
struct NoThrowAllocator {
|
||
|
using is_nothrow = std::true_type;
|
||
|
};
|
||
|
struct CanThrowAllocator {
|
||
|
using is_nothrow = std::false_type;
|
||
|
};
|
||
|
struct UnspecifiedAllocator {};
|
||
|
EXPECT_TRUE(absl::allocator_is_nothrow<NoThrowAllocator>::value);
|
||
|
EXPECT_FALSE(absl::allocator_is_nothrow<CanThrowAllocator>::value);
|
||
|
EXPECT_FALSE(absl::allocator_is_nothrow<UnspecifiedAllocator>::value);
|
||
|
}
|
||
|
|
||
|
} // namespace
|