[K/N] Support CF objects in ObjectPtr ^KT-63423
This commit is contained in:
committed by
Space Team
parent
e5269daa74
commit
2dd7a9ef21
@@ -11,6 +11,7 @@
|
||||
#error "Assumes that ARC is not used"
|
||||
#endif
|
||||
|
||||
#include <CoreFoundation/CFBase.h>
|
||||
#include <functional>
|
||||
#include <utility>
|
||||
|
||||
@@ -20,35 +21,35 @@ OBJC_FORWARD_DECLARE(NSObject);
|
||||
|
||||
namespace kotlin::objc_support {
|
||||
|
||||
struct object_ptr_retain_t{};
|
||||
struct object_ptr_retain_t {};
|
||||
inline constexpr object_ptr_retain_t object_ptr_retain{};
|
||||
|
||||
namespace internal {
|
||||
|
||||
class ObjectPtrImpl {
|
||||
class NSObjectPtrImpl {
|
||||
public:
|
||||
ObjectPtrImpl() noexcept;
|
||||
explicit ObjectPtrImpl(NSObject* object) noexcept;
|
||||
ObjectPtrImpl(object_ptr_retain_t, NSObject* object) noexcept;
|
||||
NSObjectPtrImpl() noexcept;
|
||||
explicit NSObjectPtrImpl(NSObject* object) noexcept;
|
||||
NSObjectPtrImpl(object_ptr_retain_t, NSObject* object) noexcept;
|
||||
|
||||
ObjectPtrImpl(const ObjectPtrImpl& rhs) noexcept;
|
||||
ObjectPtrImpl(ObjectPtrImpl&& rhs) noexcept;
|
||||
NSObjectPtrImpl(const NSObjectPtrImpl& rhs) noexcept;
|
||||
NSObjectPtrImpl(NSObjectPtrImpl&& rhs) noexcept;
|
||||
|
||||
~ObjectPtrImpl();
|
||||
~NSObjectPtrImpl();
|
||||
|
||||
ObjectPtrImpl& operator=(const ObjectPtrImpl& rhs) noexcept {
|
||||
ObjectPtrImpl tmp(rhs);
|
||||
NSObjectPtrImpl& operator=(const NSObjectPtrImpl& rhs) noexcept {
|
||||
NSObjectPtrImpl tmp(rhs);
|
||||
swap(tmp);
|
||||
return *this;
|
||||
}
|
||||
|
||||
ObjectPtrImpl& operator=(ObjectPtrImpl&& rhs) noexcept {
|
||||
ObjectPtrImpl tmp(std::move(rhs));
|
||||
NSObjectPtrImpl& operator=(NSObjectPtrImpl&& rhs) noexcept {
|
||||
NSObjectPtrImpl tmp(std::move(rhs));
|
||||
swap(tmp);
|
||||
return *this;
|
||||
}
|
||||
|
||||
void swap(ObjectPtrImpl& rhs) noexcept;
|
||||
void swap(NSObjectPtrImpl& rhs) noexcept;
|
||||
|
||||
NSObject* get() const noexcept;
|
||||
bool valid() const noexcept;
|
||||
@@ -57,20 +58,60 @@ public:
|
||||
void reset(NSObject* object) noexcept;
|
||||
void reset(object_ptr_retain_t, NSObject* object) noexcept;
|
||||
|
||||
bool operator==(const ObjectPtrImpl& rhs) const noexcept;
|
||||
bool operator<(const ObjectPtrImpl& rhs) const noexcept;
|
||||
|
||||
std::size_t computeHash() const noexcept;
|
||||
bool operator==(const NSObjectPtrImpl& rhs) const noexcept;
|
||||
bool operator<(const NSObjectPtrImpl& rhs) const noexcept;
|
||||
|
||||
private:
|
||||
NSObject* object_;
|
||||
};
|
||||
|
||||
class CFObjectPtrImpl {
|
||||
public:
|
||||
CFObjectPtrImpl() noexcept : object_(nullptr) {}
|
||||
explicit CFObjectPtrImpl(CFTypeRef object) noexcept : object_(object) {}
|
||||
CFObjectPtrImpl(object_ptr_retain_t, CFTypeRef object) noexcept : object_(CFRetain(object)) {}
|
||||
|
||||
CFObjectPtrImpl(const CFObjectPtrImpl& rhs) noexcept : object_(CFRetain(rhs.object_)) {}
|
||||
CFObjectPtrImpl(CFObjectPtrImpl&& rhs) noexcept : object_(rhs.object_) { rhs.object_ = nullptr; }
|
||||
|
||||
~CFObjectPtrImpl();
|
||||
|
||||
CFObjectPtrImpl& operator=(const CFObjectPtrImpl& rhs) noexcept {
|
||||
CFObjectPtrImpl tmp(rhs);
|
||||
swap(tmp);
|
||||
return *this;
|
||||
}
|
||||
|
||||
CFObjectPtrImpl& operator=(CFObjectPtrImpl&& rhs) noexcept {
|
||||
CFObjectPtrImpl tmp(std::move(rhs));
|
||||
swap(tmp);
|
||||
return *this;
|
||||
}
|
||||
|
||||
void swap(CFObjectPtrImpl& rhs) noexcept {
|
||||
using std::swap;
|
||||
swap(object_, rhs.object_);
|
||||
}
|
||||
|
||||
CFTypeRef get() const noexcept { return object_; }
|
||||
bool valid() const noexcept { return object_ != nullptr; }
|
||||
|
||||
void reset() noexcept { reset(nullptr); }
|
||||
void reset(CFTypeRef object) noexcept;
|
||||
void reset(object_ptr_retain_t, CFTypeRef object) noexcept { reset(CFRetain(object)); }
|
||||
|
||||
bool operator==(const CFObjectPtrImpl& rhs) const noexcept { return object_ == rhs.object_; }
|
||||
bool operator<(const CFObjectPtrImpl& rhs) const noexcept { return std::less<>()(object_, rhs.object_); }
|
||||
|
||||
private:
|
||||
CFTypeRef object_;
|
||||
};
|
||||
|
||||
} // namespace internal
|
||||
|
||||
// `std::shared_ptr`-like smart pointer for ObjC objects.
|
||||
// `std::shared_ptr`-like smart pointer for ObjC/CF objects.
|
||||
//
|
||||
// IMPORTANT: By default constructed from a retained ObjC object.
|
||||
// IMPORTANT: By default constructed from a retained ObjC/CF object.
|
||||
// This optimizes for the common case of constructing directly from `[[T alloc] init...]`.
|
||||
// To construct and additionally retain the object, use `object_ptr_retain` as the first argument
|
||||
// to the constructor.
|
||||
@@ -86,23 +127,28 @@ private:
|
||||
// When transfering ownership, prefer to move because it avoids calling `retain` and `release`.
|
||||
template <typename T>
|
||||
class object_ptr {
|
||||
// All CF types are known only as CF...Ref which are always pointers.
|
||||
static inline constexpr bool useCF = std::is_pointer_v<T>;
|
||||
|
||||
public:
|
||||
using element_type = std::conditional_t<useCF, std::remove_pointer_t<T>, T>;
|
||||
|
||||
// Construct empty `object_ptr`.
|
||||
object_ptr() noexcept = default;
|
||||
|
||||
// Construct from ObjC object.
|
||||
// Construct from ObjC/CF object.
|
||||
//
|
||||
// IMPORTANT: this does not `retain` `ptr`.
|
||||
explicit object_ptr(T* ptr) noexcept : impl_(ptr) {}
|
||||
explicit object_ptr(element_type* ptr) noexcept : impl_(ptr) {}
|
||||
|
||||
// Construct from ObjC object, additionally retaining `ptr`.
|
||||
object_ptr(object_ptr_retain_t, T* ptr) noexcept : impl_(object_ptr_retain, ptr) {}
|
||||
// Construct from ObjC/CF object, additionally retaining `ptr`.
|
||||
object_ptr(object_ptr_retain_t, element_type* ptr) noexcept : impl_(object_ptr_retain, ptr) {}
|
||||
|
||||
void swap(object_ptr<T>& rhs) noexcept { impl_.swap(rhs.impl_); }
|
||||
|
||||
T* get() const noexcept { return (T*)impl_.get(); }
|
||||
T* operator*() const noexcept { return (T*)impl_.get(); }
|
||||
T* operator->() const noexcept { return (T*)impl_.get(); }
|
||||
element_type* get() const noexcept { return (element_type*)impl_.get(); }
|
||||
element_type* operator*() const noexcept { return (element_type*)impl_.get(); }
|
||||
element_type* operator->() const noexcept { return (element_type*)impl_.get(); }
|
||||
|
||||
explicit operator bool() const noexcept { return impl_.valid(); }
|
||||
|
||||
@@ -112,10 +158,10 @@ public:
|
||||
// Release stored pointer and store `ptr` instead.
|
||||
//
|
||||
// IMPORTANT: this does not `retain` `ptr`.
|
||||
void reset(T* ptr) noexcept { impl_.reset(ptr); }
|
||||
void reset(element_type* ptr) noexcept { impl_.reset(ptr); }
|
||||
|
||||
// Release stored pointer and store `ptr` instead, additionally retaining `ptr`.
|
||||
void reset(object_ptr_retain_t, T* ptr) noexcept { impl_.reset(object_ptr_retain, ptr); }
|
||||
void reset(object_ptr_retain_t, element_type* ptr) noexcept { impl_.reset(object_ptr_retain, ptr); }
|
||||
|
||||
template <typename U>
|
||||
bool operator==(const object_ptr<U>& rhs) const noexcept {
|
||||
@@ -133,7 +179,7 @@ private:
|
||||
template <typename U>
|
||||
friend class object_ptr;
|
||||
|
||||
internal::ObjectPtrImpl impl_;
|
||||
std::conditional_t<useCF, internal::CFObjectPtrImpl, internal::NSObjectPtrImpl> impl_;
|
||||
};
|
||||
|
||||
template <typename T, typename U>
|
||||
@@ -167,7 +213,7 @@ void swap(kotlin::objc_support::object_ptr<T>& lhs, kotlin::objc_support::object
|
||||
|
||||
template <typename T>
|
||||
struct hash<kotlin::objc_support::object_ptr<T>> {
|
||||
std::size_t operator()(const kotlin::objc_support::object_ptr<T>& value) { return std::hash<NSObject*>()(value.impl_.get()); }
|
||||
std::size_t operator()(const kotlin::objc_support::object_ptr<T>& value) { return std::hash<const void*>()(value.impl_.get()); }
|
||||
};
|
||||
|
||||
// TODO: std::atomic specialization?
|
||||
|
||||
@@ -11,62 +11,75 @@
|
||||
|
||||
using namespace kotlin;
|
||||
|
||||
objc_support::internal::ObjectPtrImpl::ObjectPtrImpl() noexcept : object_(nil) {}
|
||||
objc_support::internal::NSObjectPtrImpl::NSObjectPtrImpl() noexcept : object_(nil) {}
|
||||
|
||||
objc_support::internal::ObjectPtrImpl::ObjectPtrImpl(NSObject* object) noexcept : object_(object) {}
|
||||
objc_support::internal::NSObjectPtrImpl::NSObjectPtrImpl(NSObject* object) noexcept : object_(object) {}
|
||||
|
||||
objc_support::internal::ObjectPtrImpl::ObjectPtrImpl(object_ptr_retain_t, NSObject* object) noexcept : object_([object retain]) {}
|
||||
objc_support::internal::NSObjectPtrImpl::NSObjectPtrImpl(object_ptr_retain_t, NSObject* object) noexcept : object_([object retain]) {}
|
||||
|
||||
objc_support::internal::ObjectPtrImpl::ObjectPtrImpl(const ObjectPtrImpl& rhs) noexcept : object_([rhs.object_ retain]) {}
|
||||
objc_support::internal::NSObjectPtrImpl::NSObjectPtrImpl(const NSObjectPtrImpl& rhs) noexcept : object_([rhs.object_ retain]) {}
|
||||
|
||||
objc_support::internal::ObjectPtrImpl::ObjectPtrImpl(ObjectPtrImpl&& rhs) noexcept : object_(rhs.object_) {
|
||||
objc_support::internal::NSObjectPtrImpl::NSObjectPtrImpl(NSObjectPtrImpl&& rhs) noexcept : object_(rhs.object_) {
|
||||
rhs.object_ = nil;
|
||||
}
|
||||
|
||||
objc_support::internal::ObjectPtrImpl::~ObjectPtrImpl() {
|
||||
objc_support::internal::NSObjectPtrImpl::~NSObjectPtrImpl() {
|
||||
@autoreleasepool {
|
||||
[object_ release];
|
||||
}
|
||||
}
|
||||
|
||||
void objc_support::internal::ObjectPtrImpl::swap(ObjectPtrImpl& rhs) noexcept {
|
||||
void objc_support::internal::NSObjectPtrImpl::swap(NSObjectPtrImpl& rhs) noexcept {
|
||||
using std::swap;
|
||||
swap(object_, rhs.object_);
|
||||
}
|
||||
|
||||
NSObject* objc_support::internal::ObjectPtrImpl::get() const noexcept {
|
||||
NSObject* objc_support::internal::NSObjectPtrImpl::get() const noexcept {
|
||||
return object_;
|
||||
}
|
||||
|
||||
bool objc_support::internal::ObjectPtrImpl::valid() const noexcept {
|
||||
bool objc_support::internal::NSObjectPtrImpl::valid() const noexcept {
|
||||
return object_ != nil;
|
||||
}
|
||||
|
||||
void objc_support::internal::ObjectPtrImpl::reset() noexcept {
|
||||
void objc_support::internal::NSObjectPtrImpl::reset() noexcept {
|
||||
reset(nil);
|
||||
}
|
||||
|
||||
void objc_support::internal::ObjectPtrImpl::reset(NSObject* object) noexcept {
|
||||
void objc_support::internal::NSObjectPtrImpl::reset(NSObject* object) noexcept {
|
||||
@autoreleasepool {
|
||||
[object_ release];
|
||||
object_ = object;
|
||||
}
|
||||
}
|
||||
|
||||
void objc_support::internal::ObjectPtrImpl::reset(object_ptr_retain_t, NSObject* object) noexcept {
|
||||
void objc_support::internal::NSObjectPtrImpl::reset(object_ptr_retain_t, NSObject* object) noexcept {
|
||||
reset([object retain]);
|
||||
}
|
||||
|
||||
std::size_t objc_support::internal::ObjectPtrImpl::computeHash() const noexcept {
|
||||
return object_.hash;
|
||||
}
|
||||
|
||||
bool objc_support::internal::ObjectPtrImpl::operator==(const ObjectPtrImpl& rhs) const noexcept {
|
||||
bool objc_support::internal::NSObjectPtrImpl::operator==(const NSObjectPtrImpl& rhs) const noexcept {
|
||||
return object_ == rhs.object_;
|
||||
}
|
||||
|
||||
bool objc_support::internal::ObjectPtrImpl::operator<(const ObjectPtrImpl& rhs) const noexcept {
|
||||
bool objc_support::internal::NSObjectPtrImpl::operator<(const NSObjectPtrImpl& rhs) const noexcept {
|
||||
return std::less<>()(object_, rhs.object_);
|
||||
}
|
||||
|
||||
objc_support::internal::CFObjectPtrImpl::~CFObjectPtrImpl() {
|
||||
if (object_) {
|
||||
@autoreleasepool {
|
||||
CFRelease(object_);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void objc_support::internal::CFObjectPtrImpl::reset(CFTypeRef object) noexcept {
|
||||
if (object_) {
|
||||
@autoreleasepool {
|
||||
CFRelease(object_);
|
||||
}
|
||||
}
|
||||
object_ = object;
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
@@ -7,6 +7,8 @@
|
||||
|
||||
#include "ObjectPtr.hpp"
|
||||
|
||||
#import <CoreFoundation/CFArray.h>
|
||||
#import <Foundation/NSArray.h>
|
||||
#import <Foundation/NSObject.h>
|
||||
#include <functional>
|
||||
#include <memory>
|
||||
@@ -61,145 +63,201 @@ private:
|
||||
|
||||
@end
|
||||
|
||||
template <typename T>
|
||||
class ObjectPtrTest : public testing::Test {};
|
||||
|
||||
struct ObjectPtrTestCF {
|
||||
using TestedType = objc_support::object_ptr<CFArrayRef>;
|
||||
using OtherType = objc_support::object_ptr<CFTypeRef>;
|
||||
|
||||
static CFArrayRef withDestructorHook(std::function<DestructorHook> hook) noexcept {
|
||||
auto* contents = [[WithDestructorHookObjC alloc] initWithDestructorHook:std::move(hook)];
|
||||
auto* array = @[contents];
|
||||
[contents release];
|
||||
return (__bridge CFArrayRef)array;
|
||||
}
|
||||
|
||||
static WithDestructorHook* getHook(CFArrayRef ptr) noexcept {
|
||||
auto* array = (__bridge NSArray<WithDestructorHookObjC*>*)ptr;
|
||||
return array[0].impl;
|
||||
}
|
||||
|
||||
static void release(CFArrayRef ptr) noexcept { CFRelease(ptr); }
|
||||
|
||||
static CFArrayRef retain(CFArrayRef ptr) noexcept {
|
||||
CFRetain(ptr);
|
||||
return ptr;
|
||||
}
|
||||
};
|
||||
|
||||
struct ObjectPtrTestNS {
|
||||
using TestedType = objc_support::object_ptr<WithDestructorHookObjC>;
|
||||
using OtherType = objc_support::object_ptr<NSObject>;
|
||||
|
||||
static WithDestructorHookObjC* withDestructorHook(std::function<DestructorHook> hook) noexcept {
|
||||
return [[WithDestructorHookObjC alloc] initWithDestructorHook:std::move(hook)];
|
||||
}
|
||||
|
||||
static WithDestructorHook* getHook(WithDestructorHookObjC* ptr) noexcept { return ptr.impl; }
|
||||
|
||||
static void release(WithDestructorHookObjC* ptr) noexcept { [ptr release]; }
|
||||
|
||||
static WithDestructorHookObjC* retain(WithDestructorHookObjC* ptr) noexcept { return [ptr retain]; }
|
||||
};
|
||||
|
||||
using ObjectPtrTestTypes = testing::Types<ObjectPtrTestCF, ObjectPtrTestNS>;
|
||||
class ObjectPtrTestNames {
|
||||
public:
|
||||
template <typename T>
|
||||
static std::string GetName(int) {
|
||||
if constexpr (std::is_same_v<T, ObjectPtrTestCF>) {
|
||||
return "CF";
|
||||
} else if constexpr (std::is_same_v<T, ObjectPtrTestNS>) {
|
||||
return "NS";
|
||||
}
|
||||
}
|
||||
};
|
||||
TYPED_TEST_SUITE(ObjectPtrTest, ObjectPtrTestTypes, ObjectPtrTestNames);
|
||||
|
||||
#define EXPECT_CONTAINS(smartPtr, ptr) \
|
||||
do { \
|
||||
EXPECT_THAT(static_cast<bool>(smartPtr), (ptr) != nil); \
|
||||
EXPECT_THAT(static_cast<bool>(smartPtr), (ptr) != nullptr); \
|
||||
EXPECT_THAT(*(smartPtr), (ptr)); \
|
||||
EXPECT_THAT((smartPtr).get(), (ptr)); \
|
||||
} while (false)
|
||||
|
||||
TEST(ObjectPtrTest, DefaultCtor) {
|
||||
objc_support::object_ptr<WithDestructorHookObjC> obj;
|
||||
TYPED_TEST(ObjectPtrTest, DefaultCtor) {
|
||||
typename TypeParam::TestedType obj;
|
||||
EXPECT_CONTAINS(obj, nil);
|
||||
}
|
||||
|
||||
TEST(ObjectPtrTest, ObjectCtor) {
|
||||
TYPED_TEST(ObjectPtrTest, ObjectCtor) {
|
||||
testing::StrictMock<testing::MockFunction<DestructorHook>> destructorHook;
|
||||
|
||||
auto* ptr = [[WithDestructorHookObjC alloc] initWithDestructorHook:destructorHook.AsStdFunction()];
|
||||
auto* ptr = TypeParam::withDestructorHook(destructorHook.AsStdFunction());
|
||||
{
|
||||
objc_support::object_ptr<WithDestructorHookObjC> obj(ptr);
|
||||
typename TypeParam::TestedType obj(ptr);
|
||||
EXPECT_CONTAINS(obj, ptr);
|
||||
EXPECT_CALL(destructorHook, Call(ptr.impl));
|
||||
EXPECT_CALL(destructorHook, Call(TypeParam::getHook(ptr)));
|
||||
}
|
||||
testing::Mock::VerifyAndClearExpectations(&destructorHook);
|
||||
}
|
||||
|
||||
TEST(ObjectPtrTest, ObjectCtorWithRetain) {
|
||||
TYPED_TEST(ObjectPtrTest, ObjectCtorWithRetain) {
|
||||
testing::StrictMock<testing::MockFunction<DestructorHook>> destructorHook;
|
||||
|
||||
auto* ptr = [[WithDestructorHookObjC alloc] initWithDestructorHook:destructorHook.AsStdFunction()];
|
||||
auto* ptr = TypeParam::withDestructorHook(destructorHook.AsStdFunction());
|
||||
{
|
||||
objc_support::object_ptr<WithDestructorHookObjC> obj(objc_support::object_ptr_retain, ptr);
|
||||
typename TypeParam::TestedType obj(objc_support::object_ptr_retain, ptr);
|
||||
EXPECT_CONTAINS(obj, ptr);
|
||||
EXPECT_CALL(destructorHook, Call(ptr.impl)).Times(0);
|
||||
EXPECT_CALL(destructorHook, Call(TypeParam::getHook(ptr))).Times(0);
|
||||
}
|
||||
testing::Mock::VerifyAndClearExpectations(&destructorHook);
|
||||
|
||||
EXPECT_CALL(destructorHook, Call(ptr.impl));
|
||||
[ptr release];
|
||||
EXPECT_CALL(destructorHook, Call(TypeParam::getHook(ptr)));
|
||||
TypeParam::release(ptr);
|
||||
}
|
||||
|
||||
TEST(ObjectPtrTest, CopyCtor) {
|
||||
TYPED_TEST(ObjectPtrTest, CopyCtor) {
|
||||
testing::StrictMock<testing::MockFunction<DestructorHook>> destructorHook;
|
||||
|
||||
auto* ptr = [[WithDestructorHookObjC alloc] initWithDestructorHook:destructorHook.AsStdFunction()];
|
||||
auto* ptr = TypeParam::withDestructorHook(destructorHook.AsStdFunction());
|
||||
{
|
||||
objc_support::object_ptr<WithDestructorHookObjC> obj1(ptr);
|
||||
objc_support::object_ptr<WithDestructorHookObjC> obj2(obj1);
|
||||
typename TypeParam::TestedType obj1(ptr);
|
||||
typename TypeParam::TestedType obj2(obj1);
|
||||
EXPECT_CONTAINS(obj1, ptr);
|
||||
EXPECT_CONTAINS(obj2, ptr);
|
||||
|
||||
EXPECT_CALL(destructorHook, Call(ptr.impl)).Times(0);
|
||||
EXPECT_CALL(destructorHook, Call(TypeParam::getHook(ptr))).Times(0);
|
||||
obj1.reset();
|
||||
testing::Mock::VerifyAndClearExpectations(&destructorHook);
|
||||
EXPECT_CONTAINS(obj1, nil);
|
||||
EXPECT_CONTAINS(obj2, ptr);
|
||||
|
||||
EXPECT_CALL(destructorHook, Call(ptr.impl));
|
||||
EXPECT_CALL(destructorHook, Call(TypeParam::getHook(ptr)));
|
||||
}
|
||||
testing::Mock::VerifyAndClearExpectations(&destructorHook);
|
||||
}
|
||||
|
||||
TEST(ObjectPtrTest, MoveCtor) {
|
||||
TYPED_TEST(ObjectPtrTest, MoveCtor) {
|
||||
testing::StrictMock<testing::MockFunction<DestructorHook>> destructorHook;
|
||||
|
||||
auto* ptr = [[WithDestructorHookObjC alloc] initWithDestructorHook:destructorHook.AsStdFunction()];
|
||||
auto* ptr = TypeParam::withDestructorHook(destructorHook.AsStdFunction());
|
||||
{
|
||||
objc_support::object_ptr<WithDestructorHookObjC> obj1(ptr);
|
||||
typename TypeParam::TestedType obj1(ptr);
|
||||
|
||||
EXPECT_CALL(destructorHook, Call(ptr.impl)).Times(0);
|
||||
objc_support::object_ptr<WithDestructorHookObjC> obj2(std::move(obj1));
|
||||
EXPECT_CALL(destructorHook, Call(TypeParam::getHook(ptr))).Times(0);
|
||||
typename TypeParam::TestedType obj2(std::move(obj1));
|
||||
testing::Mock::VerifyAndClearExpectations(&destructorHook);
|
||||
EXPECT_CONTAINS(obj1, nil);
|
||||
EXPECT_CONTAINS(obj2, ptr);
|
||||
|
||||
EXPECT_CALL(destructorHook, Call(ptr.impl));
|
||||
EXPECT_CALL(destructorHook, Call(TypeParam::getHook(ptr)));
|
||||
}
|
||||
testing::Mock::VerifyAndClearExpectations(&destructorHook);
|
||||
}
|
||||
|
||||
TEST(ObjectPtrTest, CopyAssignmentIntoEmpty) {
|
||||
TYPED_TEST(ObjectPtrTest, CopyAssignmentIntoEmpty) {
|
||||
testing::StrictMock<testing::MockFunction<DestructorHook>> destructorHook;
|
||||
|
||||
auto* ptr = [[WithDestructorHookObjC alloc] initWithDestructorHook:destructorHook.AsStdFunction()];
|
||||
auto* ptr = TypeParam::withDestructorHook(destructorHook.AsStdFunction());
|
||||
{
|
||||
objc_support::object_ptr<WithDestructorHookObjC> obj2;
|
||||
typename TypeParam::TestedType obj2;
|
||||
{
|
||||
objc_support::object_ptr<WithDestructorHookObjC> obj1(ptr);
|
||||
typename TypeParam::TestedType obj1(ptr);
|
||||
obj2 = obj1;
|
||||
EXPECT_CONTAINS(obj1, ptr);
|
||||
EXPECT_CONTAINS(obj2, ptr);
|
||||
|
||||
EXPECT_CALL(destructorHook, Call(ptr.impl)).Times(0);
|
||||
EXPECT_CALL(destructorHook, Call(TypeParam::getHook(ptr))).Times(0);
|
||||
}
|
||||
testing::Mock::VerifyAndClearExpectations(&destructorHook);
|
||||
|
||||
EXPECT_CONTAINS(obj2, ptr);
|
||||
|
||||
EXPECT_CALL(destructorHook, Call(ptr.impl));
|
||||
EXPECT_CALL(destructorHook, Call(TypeParam::getHook(ptr)));
|
||||
}
|
||||
testing::Mock::VerifyAndClearExpectations(&destructorHook);
|
||||
}
|
||||
|
||||
TEST(ObjectPtrTest, CopyAssignmentIntoSet) {
|
||||
TYPED_TEST(ObjectPtrTest, CopyAssignmentIntoSet) {
|
||||
testing::StrictMock<testing::MockFunction<DestructorHook>> destructorHook;
|
||||
|
||||
auto* ptr1 = [[WithDestructorHookObjC alloc] initWithDestructorHook:destructorHook.AsStdFunction()];
|
||||
auto* ptr2 = [[WithDestructorHookObjC alloc] initWithDestructorHook:destructorHook.AsStdFunction()];
|
||||
auto* ptr1 = TypeParam::withDestructorHook(destructorHook.AsStdFunction());
|
||||
auto* ptr2 = TypeParam::withDestructorHook(destructorHook.AsStdFunction());
|
||||
{
|
||||
objc_support::object_ptr<WithDestructorHookObjC> obj2(ptr2);
|
||||
typename TypeParam::TestedType obj2(ptr2);
|
||||
{
|
||||
objc_support::object_ptr<WithDestructorHookObjC> obj1(ptr1);
|
||||
typename TypeParam::TestedType obj1(ptr1);
|
||||
|
||||
EXPECT_CALL(destructorHook, Call(ptr2.impl));
|
||||
EXPECT_CALL(destructorHook, Call(TypeParam::getHook(ptr2)));
|
||||
obj2 = obj1;
|
||||
testing::Mock::VerifyAndClearExpectations(&destructorHook);
|
||||
|
||||
EXPECT_CONTAINS(obj1, ptr1);
|
||||
EXPECT_CONTAINS(obj2, ptr1);
|
||||
|
||||
EXPECT_CALL(destructorHook, Call(ptr1.impl)).Times(0);
|
||||
EXPECT_CALL(destructorHook, Call(TypeParam::getHook(ptr1))).Times(0);
|
||||
}
|
||||
testing::Mock::VerifyAndClearExpectations(&destructorHook);
|
||||
|
||||
EXPECT_CONTAINS(obj2, ptr1);
|
||||
|
||||
EXPECT_CALL(destructorHook, Call(ptr1.impl));
|
||||
EXPECT_CALL(destructorHook, Call(TypeParam::getHook(ptr1)));
|
||||
}
|
||||
testing::Mock::VerifyAndClearExpectations(&destructorHook);
|
||||
}
|
||||
|
||||
TEST(ObjectPtrTest, MoveAssignmentIntoEmpty) {
|
||||
TYPED_TEST(ObjectPtrTest, MoveAssignmentIntoEmpty) {
|
||||
testing::StrictMock<testing::MockFunction<DestructorHook>> destructorHook;
|
||||
|
||||
auto* ptr = [[WithDestructorHookObjC alloc] initWithDestructorHook:destructorHook.AsStdFunction()];
|
||||
auto* ptr = TypeParam::withDestructorHook(destructorHook.AsStdFunction());
|
||||
{
|
||||
objc_support::object_ptr<WithDestructorHookObjC> obj2;
|
||||
typename TypeParam::TestedType obj2;
|
||||
{
|
||||
EXPECT_CALL(destructorHook, Call(ptr.impl)).Times(0);
|
||||
EXPECT_CALL(destructorHook, Call(TypeParam::getHook(ptr))).Times(0);
|
||||
|
||||
objc_support::object_ptr<WithDestructorHookObjC> obj1(ptr);
|
||||
typename TypeParam::TestedType obj1(ptr);
|
||||
obj2 = std::move(obj1);
|
||||
EXPECT_CONTAINS(obj1, nil);
|
||||
EXPECT_CONTAINS(obj2, ptr);
|
||||
@@ -208,23 +266,23 @@ TEST(ObjectPtrTest, MoveAssignmentIntoEmpty) {
|
||||
|
||||
EXPECT_CONTAINS(obj2, ptr);
|
||||
|
||||
EXPECT_CALL(destructorHook, Call(ptr.impl));
|
||||
EXPECT_CALL(destructorHook, Call(TypeParam::getHook(ptr)));
|
||||
}
|
||||
testing::Mock::VerifyAndClearExpectations(&destructorHook);
|
||||
}
|
||||
|
||||
TEST(ObjectPtrTest, MoveAssignmentIntoSet) {
|
||||
TYPED_TEST(ObjectPtrTest, MoveAssignmentIntoSet) {
|
||||
testing::StrictMock<testing::MockFunction<DestructorHook>> destructorHook;
|
||||
|
||||
auto* ptr1 = [[WithDestructorHookObjC alloc] initWithDestructorHook:destructorHook.AsStdFunction()];
|
||||
auto* ptr2 = [[WithDestructorHookObjC alloc] initWithDestructorHook:destructorHook.AsStdFunction()];
|
||||
auto* ptr1 = TypeParam::withDestructorHook(destructorHook.AsStdFunction());
|
||||
auto* ptr2 = TypeParam::withDestructorHook(destructorHook.AsStdFunction());
|
||||
{
|
||||
objc_support::object_ptr<WithDestructorHookObjC> obj2(ptr2);
|
||||
typename TypeParam::TestedType obj2(ptr2);
|
||||
{
|
||||
objc_support::object_ptr<WithDestructorHookObjC> obj1(ptr1);
|
||||
typename TypeParam::TestedType obj1(ptr1);
|
||||
|
||||
EXPECT_CALL(destructorHook, Call(ptr2.impl));
|
||||
EXPECT_CALL(destructorHook, Call(ptr1.impl)).Times(0);
|
||||
EXPECT_CALL(destructorHook, Call(TypeParam::getHook(ptr2)));
|
||||
EXPECT_CALL(destructorHook, Call(TypeParam::getHook(ptr1))).Times(0);
|
||||
obj2 = std::move(obj1);
|
||||
testing::Mock::VerifyAndClearExpectations(&destructorHook);
|
||||
|
||||
@@ -235,142 +293,142 @@ TEST(ObjectPtrTest, MoveAssignmentIntoSet) {
|
||||
|
||||
EXPECT_CONTAINS(obj2, ptr1);
|
||||
|
||||
EXPECT_CALL(destructorHook, Call(ptr1.impl));
|
||||
EXPECT_CALL(destructorHook, Call(TypeParam::getHook(ptr1)));
|
||||
}
|
||||
testing::Mock::VerifyAndClearExpectations(&destructorHook);
|
||||
}
|
||||
|
||||
TEST(ObjectPtrTest, SwapEmptyEmpty) {
|
||||
objc_support::object_ptr<WithDestructorHookObjC> obj1;
|
||||
objc_support::object_ptr<WithDestructorHookObjC> obj2;
|
||||
TYPED_TEST(ObjectPtrTest, SwapEmptyEmpty) {
|
||||
typename TypeParam::TestedType obj1;
|
||||
typename TypeParam::TestedType obj2;
|
||||
obj1.swap(obj2);
|
||||
EXPECT_CONTAINS(obj1, nil);
|
||||
EXPECT_CONTAINS(obj2, nil);
|
||||
}
|
||||
|
||||
TEST(ObjectPtrTest, SwapEmptySet) {
|
||||
TYPED_TEST(ObjectPtrTest, SwapEmptySet) {
|
||||
testing::StrictMock<testing::MockFunction<DestructorHook>> destructorHook;
|
||||
|
||||
auto* ptr2 = [[WithDestructorHookObjC alloc] initWithDestructorHook:destructorHook.AsStdFunction()];
|
||||
objc_support::object_ptr<WithDestructorHookObjC> obj1;
|
||||
objc_support::object_ptr<WithDestructorHookObjC> obj2(ptr2);
|
||||
auto* ptr2 = TypeParam::withDestructorHook(destructorHook.AsStdFunction());
|
||||
typename TypeParam::TestedType obj1;
|
||||
typename TypeParam::TestedType obj2(ptr2);
|
||||
obj1.swap(obj2);
|
||||
EXPECT_CONTAINS(obj1, ptr2);
|
||||
EXPECT_CONTAINS(obj2, nil);
|
||||
|
||||
EXPECT_CALL(destructorHook, Call(ptr2.impl));
|
||||
EXPECT_CALL(destructorHook, Call(TypeParam::getHook(ptr2)));
|
||||
}
|
||||
|
||||
TEST(ObjectPtrTest, SwapSetEmpty) {
|
||||
TYPED_TEST(ObjectPtrTest, SwapSetEmpty) {
|
||||
testing::StrictMock<testing::MockFunction<DestructorHook>> destructorHook;
|
||||
|
||||
auto* ptr1 = [[WithDestructorHookObjC alloc] initWithDestructorHook:destructorHook.AsStdFunction()];
|
||||
objc_support::object_ptr<WithDestructorHookObjC> obj1(ptr1);
|
||||
objc_support::object_ptr<WithDestructorHookObjC> obj2;
|
||||
auto* ptr1 = TypeParam::withDestructorHook(destructorHook.AsStdFunction());
|
||||
typename TypeParam::TestedType obj1(ptr1);
|
||||
typename TypeParam::TestedType obj2;
|
||||
obj1.swap(obj2);
|
||||
EXPECT_CONTAINS(obj1, nil);
|
||||
EXPECT_CONTAINS(obj2, ptr1);
|
||||
|
||||
EXPECT_CALL(destructorHook, Call(ptr1.impl));
|
||||
EXPECT_CALL(destructorHook, Call(TypeParam::getHook(ptr1)));
|
||||
}
|
||||
|
||||
TEST(ObjectPtrTest, SwapSetSet) {
|
||||
TYPED_TEST(ObjectPtrTest, SwapSetSet) {
|
||||
testing::StrictMock<testing::MockFunction<DestructorHook>> destructorHook;
|
||||
|
||||
auto* ptr1 = [[WithDestructorHookObjC alloc] initWithDestructorHook:destructorHook.AsStdFunction()];
|
||||
auto* ptr2 = [[WithDestructorHookObjC alloc] initWithDestructorHook:destructorHook.AsStdFunction()];
|
||||
objc_support::object_ptr<WithDestructorHookObjC> obj1(ptr1);
|
||||
objc_support::object_ptr<WithDestructorHookObjC> obj2(ptr2);
|
||||
auto* ptr1 = TypeParam::withDestructorHook(destructorHook.AsStdFunction());
|
||||
auto* ptr2 = TypeParam::withDestructorHook(destructorHook.AsStdFunction());
|
||||
typename TypeParam::TestedType obj1(ptr1);
|
||||
typename TypeParam::TestedType obj2(ptr2);
|
||||
obj1.swap(obj2);
|
||||
EXPECT_CONTAINS(obj1, ptr2);
|
||||
EXPECT_CONTAINS(obj2, ptr1);
|
||||
|
||||
EXPECT_CALL(destructorHook, Call(ptr1.impl));
|
||||
EXPECT_CALL(destructorHook, Call(ptr2.impl));
|
||||
EXPECT_CALL(destructorHook, Call(TypeParam::getHook(ptr1)));
|
||||
EXPECT_CALL(destructorHook, Call(TypeParam::getHook(ptr2)));
|
||||
}
|
||||
|
||||
TEST(ObjectPtrTest, ResetEmptyFromEmpty) {
|
||||
objc_support::object_ptr<WithDestructorHookObjC> obj;
|
||||
TYPED_TEST(ObjectPtrTest, ResetEmptyFromEmpty) {
|
||||
typename TypeParam::TestedType obj;
|
||||
obj.reset();
|
||||
EXPECT_CONTAINS(obj, nil);
|
||||
}
|
||||
|
||||
TEST(ObjectPtrTest, ResetEmptyFromSet) {
|
||||
TYPED_TEST(ObjectPtrTest, ResetEmptyFromSet) {
|
||||
testing::StrictMock<testing::MockFunction<DestructorHook>> destructorHook;
|
||||
|
||||
auto* ptr = [[WithDestructorHookObjC alloc] initWithDestructorHook:destructorHook.AsStdFunction()];
|
||||
objc_support::object_ptr<WithDestructorHookObjC> obj(ptr);
|
||||
auto* ptr = TypeParam::withDestructorHook(destructorHook.AsStdFunction());
|
||||
typename TypeParam::TestedType obj(ptr);
|
||||
|
||||
EXPECT_CALL(destructorHook, Call(ptr.impl));
|
||||
EXPECT_CALL(destructorHook, Call(TypeParam::getHook(ptr)));
|
||||
obj.reset();
|
||||
testing::Mock::VerifyAndClearExpectations(&destructorHook);
|
||||
EXPECT_CONTAINS(obj, nil);
|
||||
}
|
||||
|
||||
TEST(ObjectPtrTest, ResetObjectFromEmpty) {
|
||||
TYPED_TEST(ObjectPtrTest, ResetObjectFromEmpty) {
|
||||
testing::StrictMock<testing::MockFunction<DestructorHook>> destructorHook;
|
||||
|
||||
auto* ptr = [[WithDestructorHookObjC alloc] initWithDestructorHook:destructorHook.AsStdFunction()];
|
||||
objc_support::object_ptr<WithDestructorHookObjC> obj;
|
||||
auto* ptr = TypeParam::withDestructorHook(destructorHook.AsStdFunction());
|
||||
typename TypeParam::TestedType obj;
|
||||
|
||||
obj.reset(ptr);
|
||||
EXPECT_CONTAINS(obj, ptr);
|
||||
|
||||
EXPECT_CALL(destructorHook, Call(ptr.impl));
|
||||
EXPECT_CALL(destructorHook, Call(TypeParam::getHook(ptr)));
|
||||
}
|
||||
|
||||
TEST(ObjectPtrTest, ResetObjectFromEmptyWithRetain) {
|
||||
TYPED_TEST(ObjectPtrTest, ResetObjectFromEmptyWithRetain) {
|
||||
testing::StrictMock<testing::MockFunction<DestructorHook>> destructorHook;
|
||||
|
||||
auto* ptr = [[WithDestructorHookObjC alloc] initWithDestructorHook:destructorHook.AsStdFunction()];
|
||||
auto* ptr = TypeParam::withDestructorHook(destructorHook.AsStdFunction());
|
||||
{
|
||||
objc_support::object_ptr<WithDestructorHookObjC> obj;
|
||||
typename TypeParam::TestedType obj;
|
||||
|
||||
obj.reset(objc_support::object_ptr_retain, ptr);
|
||||
EXPECT_CONTAINS(obj, ptr);
|
||||
|
||||
EXPECT_CALL(destructorHook, Call(ptr.impl)).Times(0);
|
||||
EXPECT_CALL(destructorHook, Call(TypeParam::getHook(ptr))).Times(0);
|
||||
}
|
||||
testing::Mock::VerifyAndClearExpectations(&destructorHook);
|
||||
|
||||
EXPECT_CALL(destructorHook, Call(ptr.impl));
|
||||
[ptr release];
|
||||
EXPECT_CALL(destructorHook, Call(TypeParam::getHook(ptr)));
|
||||
TypeParam::release(ptr);
|
||||
}
|
||||
|
||||
TEST(ObjectPtrTest, ResetObjectFromSet) {
|
||||
TYPED_TEST(ObjectPtrTest, ResetObjectFromSet) {
|
||||
testing::StrictMock<testing::MockFunction<DestructorHook>> destructorHook;
|
||||
|
||||
auto* ptr1 = [[WithDestructorHookObjC alloc] initWithDestructorHook:destructorHook.AsStdFunction()];
|
||||
auto* ptr2 = [[WithDestructorHookObjC alloc] initWithDestructorHook:destructorHook.AsStdFunction()];
|
||||
objc_support::object_ptr<WithDestructorHookObjC> obj(ptr1);
|
||||
auto* ptr1 = TypeParam::withDestructorHook(destructorHook.AsStdFunction());
|
||||
auto* ptr2 = TypeParam::withDestructorHook(destructorHook.AsStdFunction());
|
||||
typename TypeParam::TestedType obj(ptr1);
|
||||
|
||||
EXPECT_CALL(destructorHook, Call(ptr1.impl));
|
||||
EXPECT_CALL(destructorHook, Call(TypeParam::getHook(ptr1)));
|
||||
obj.reset(ptr2);
|
||||
testing::Mock::VerifyAndClearExpectations(&destructorHook);
|
||||
EXPECT_CONTAINS(obj, ptr2);
|
||||
|
||||
EXPECT_CALL(destructorHook, Call(ptr2.impl));
|
||||
EXPECT_CALL(destructorHook, Call(TypeParam::getHook(ptr2)));
|
||||
}
|
||||
|
||||
TEST(ObjectPtrTest, ResetObjectFromSetWithRetain) {
|
||||
TYPED_TEST(ObjectPtrTest, ResetObjectFromSetWithRetain) {
|
||||
testing::StrictMock<testing::MockFunction<DestructorHook>> destructorHook;
|
||||
|
||||
auto* ptr1 = [[WithDestructorHookObjC alloc] initWithDestructorHook:destructorHook.AsStdFunction()];
|
||||
auto* ptr2 = [[WithDestructorHookObjC alloc] initWithDestructorHook:destructorHook.AsStdFunction()];
|
||||
auto* ptr1 = TypeParam::withDestructorHook(destructorHook.AsStdFunction());
|
||||
auto* ptr2 = TypeParam::withDestructorHook(destructorHook.AsStdFunction());
|
||||
{
|
||||
objc_support::object_ptr<WithDestructorHookObjC> obj(ptr1);
|
||||
typename TypeParam::TestedType obj(ptr1);
|
||||
|
||||
EXPECT_CALL(destructorHook, Call(ptr1.impl));
|
||||
EXPECT_CALL(destructorHook, Call(TypeParam::getHook(ptr1)));
|
||||
obj.reset(objc_support::object_ptr_retain, ptr2);
|
||||
testing::Mock::VerifyAndClearExpectations(&destructorHook);
|
||||
EXPECT_CONTAINS(obj, ptr2);
|
||||
|
||||
EXPECT_CALL(destructorHook, Call(ptr2.impl)).Times(0);
|
||||
EXPECT_CALL(destructorHook, Call(TypeParam::getHook(ptr2))).Times(0);
|
||||
}
|
||||
testing::Mock::VerifyAndClearExpectations(&destructorHook);
|
||||
|
||||
EXPECT_CALL(destructorHook, Call(ptr2.impl));
|
||||
[ptr2 release];
|
||||
EXPECT_CALL(destructorHook, Call(TypeParam::getHook(ptr2)));
|
||||
TypeParam::release(ptr2);
|
||||
}
|
||||
|
||||
#define EXPECT_EQUAL(expr1, expr2) \
|
||||
@@ -403,19 +461,19 @@ TEST(ObjectPtrTest, ResetObjectFromSetWithRetain) {
|
||||
EXPECT_TRUE((expr1) >= (expr2)); \
|
||||
} while (false)
|
||||
|
||||
TEST(ObjectPtrTest, ComparisonsEmpty) {
|
||||
TYPED_TEST(ObjectPtrTest, ComparisonsEmpty) {
|
||||
testing::StrictMock<testing::MockFunction<DestructorHook>> destructorHook;
|
||||
|
||||
auto* ptr = [[WithDestructorHookObjC alloc] initWithDestructorHook:destructorHook.AsStdFunction()];
|
||||
objc_support::object_ptr<WithDestructorHookObjC> empty;
|
||||
objc_support::object_ptr<WithDestructorHookObjC> reset(ptr);
|
||||
EXPECT_CALL(destructorHook, Call(ptr.impl));
|
||||
auto* ptr = TypeParam::withDestructorHook(destructorHook.AsStdFunction());
|
||||
typename TypeParam::TestedType empty;
|
||||
typename TypeParam::TestedType reset(ptr);
|
||||
EXPECT_CALL(destructorHook, Call(TypeParam::getHook(ptr)));
|
||||
reset.reset();
|
||||
testing::Mock::VerifyAndClearExpectations(&destructorHook);
|
||||
objc_support::object_ptr<NSObject> emptyOtherType;
|
||||
typename TypeParam::OtherType emptyOtherType;
|
||||
|
||||
EXPECT_EQUAL(empty, empty);
|
||||
EXPECT_EQUAL(empty, objc_support::object_ptr<WithDestructorHookObjC>());
|
||||
EXPECT_EQUAL(empty, typename TypeParam::TestedType());
|
||||
EXPECT_EQUAL(empty, reset);
|
||||
EXPECT_EQUAL(empty, emptyOtherType);
|
||||
EXPECT_EQUAL(reset, empty);
|
||||
@@ -423,20 +481,20 @@ TEST(ObjectPtrTest, ComparisonsEmpty) {
|
||||
EXPECT_EQUAL(reset, emptyOtherType);
|
||||
}
|
||||
|
||||
TEST(ObjectPtrTest, ComparisonsEmptySet) {
|
||||
TYPED_TEST(ObjectPtrTest, ComparisonsEmptySet) {
|
||||
testing::StrictMock<testing::MockFunction<DestructorHook>> destructorHook;
|
||||
|
||||
auto* ptr1 = [[WithDestructorHookObjC alloc] initWithDestructorHook:destructorHook.AsStdFunction()];
|
||||
auto* ptr2 = [[WithDestructorHookObjC alloc] initWithDestructorHook:destructorHook.AsStdFunction()];
|
||||
auto* ptr3 = [[WithDestructorHookObjC alloc] initWithDestructorHook:destructorHook.AsStdFunction()];
|
||||
objc_support::object_ptr<WithDestructorHookObjC> obj(ptr1);
|
||||
objc_support::object_ptr<WithDestructorHookObjC> empty;
|
||||
objc_support::object_ptr<WithDestructorHookObjC> reset(ptr2);
|
||||
EXPECT_CALL(destructorHook, Call(ptr2.impl));
|
||||
auto* ptr1 = TypeParam::withDestructorHook(destructorHook.AsStdFunction());
|
||||
auto* ptr2 = TypeParam::withDestructorHook(destructorHook.AsStdFunction());
|
||||
auto* ptr3 = TypeParam::withDestructorHook(destructorHook.AsStdFunction());
|
||||
typename TypeParam::TestedType obj(ptr1);
|
||||
typename TypeParam::TestedType empty;
|
||||
typename TypeParam::TestedType reset(ptr2);
|
||||
EXPECT_CALL(destructorHook, Call(TypeParam::getHook(ptr2)));
|
||||
reset.reset();
|
||||
testing::Mock::VerifyAndClearExpectations(&destructorHook);
|
||||
objc_support::object_ptr<NSObject> emptyOtherType;
|
||||
objc_support::object_ptr<WithDestructorHookObjC> objOtherType(ptr3);
|
||||
typename TypeParam::OtherType emptyOtherType;
|
||||
typename TypeParam::TestedType objOtherType(ptr3);
|
||||
|
||||
EXPECT_GREATER(obj, empty);
|
||||
EXPECT_GREATER(obj, reset);
|
||||
@@ -448,24 +506,24 @@ TEST(ObjectPtrTest, ComparisonsEmptySet) {
|
||||
EXPECT_GREATER(objOtherType, empty);
|
||||
EXPECT_GREATER(objOtherType, reset);
|
||||
|
||||
EXPECT_CALL(destructorHook, Call(ptr1.impl));
|
||||
EXPECT_CALL(destructorHook, Call(ptr3.impl));
|
||||
EXPECT_CALL(destructorHook, Call(TypeParam::getHook(ptr1)));
|
||||
EXPECT_CALL(destructorHook, Call(TypeParam::getHook(ptr3)));
|
||||
}
|
||||
|
||||
TEST(ObjectPtrTest, ComparisonsSetSet) {
|
||||
TYPED_TEST(ObjectPtrTest, ComparisonsSetSet) {
|
||||
testing::StrictMock<testing::MockFunction<DestructorHook>> destructorHook;
|
||||
|
||||
auto* ptr1 = [[WithDestructorHookObjC alloc] initWithDestructorHook:destructorHook.AsStdFunction()];
|
||||
auto* ptr2 = [[WithDestructorHookObjC alloc] initWithDestructorHook:destructorHook.AsStdFunction()];
|
||||
auto* ptr1 = TypeParam::withDestructorHook(destructorHook.AsStdFunction());
|
||||
auto* ptr2 = TypeParam::withDestructorHook(destructorHook.AsStdFunction());
|
||||
if (ptr2 < ptr1) {
|
||||
std::swap(ptr1, ptr2);
|
||||
}
|
||||
ASSERT_LT(ptr1, ptr2);
|
||||
|
||||
objc_support::object_ptr<WithDestructorHookObjC> obj1(ptr1);
|
||||
objc_support::object_ptr<WithDestructorHookObjC> obj2(ptr2);
|
||||
objc_support::object_ptr<WithDestructorHookObjC> obj3(obj1);
|
||||
objc_support::object_ptr<NSObject> objOtherType([ptr1 retain]);
|
||||
typename TypeParam::TestedType obj1(ptr1);
|
||||
typename TypeParam::TestedType obj2(ptr2);
|
||||
typename TypeParam::TestedType obj3(obj1);
|
||||
typename TypeParam::OtherType objOtherType(TypeParam::retain(ptr1));
|
||||
|
||||
EXPECT_EQUAL(obj1, obj1);
|
||||
EXPECT_LESS(obj1, obj2);
|
||||
@@ -484,30 +542,30 @@ TEST(ObjectPtrTest, ComparisonsSetSet) {
|
||||
EXPECT_EQUAL(objOtherType, obj3);
|
||||
EXPECT_EQUAL(objOtherType, objOtherType);
|
||||
|
||||
EXPECT_CALL(destructorHook, Call(ptr1.impl));
|
||||
EXPECT_CALL(destructorHook, Call(ptr2.impl));
|
||||
EXPECT_CALL(destructorHook, Call(TypeParam::getHook(ptr1)));
|
||||
EXPECT_CALL(destructorHook, Call(TypeParam::getHook(ptr2)));
|
||||
}
|
||||
|
||||
TEST(ObjectPtrTest, Hashing) {
|
||||
TYPED_TEST(ObjectPtrTest, Hashing) {
|
||||
testing::StrictMock<testing::MockFunction<DestructorHook>> destructorHook;
|
||||
|
||||
auto* ptr1 = [[WithDestructorHookObjC alloc] initWithDestructorHook:destructorHook.AsStdFunction()];
|
||||
auto* ptr2 = [[WithDestructorHookObjC alloc] initWithDestructorHook:destructorHook.AsStdFunction()];
|
||||
objc_support::object_ptr<WithDestructorHookObjC> obj(ptr1);
|
||||
objc_support::object_ptr<WithDestructorHookObjC> empty;
|
||||
objc_support::object_ptr<WithDestructorHookObjC> reset(ptr2);
|
||||
EXPECT_CALL(destructorHook, Call(ptr2.impl));
|
||||
auto* ptr1 = TypeParam::withDestructorHook(destructorHook.AsStdFunction());
|
||||
auto* ptr2 = TypeParam::withDestructorHook(destructorHook.AsStdFunction());
|
||||
typename TypeParam::TestedType obj(ptr1);
|
||||
typename TypeParam::TestedType empty;
|
||||
typename TypeParam::TestedType reset(ptr2);
|
||||
EXPECT_CALL(destructorHook, Call(TypeParam::getHook(ptr2)));
|
||||
reset.reset();
|
||||
testing::Mock::VerifyAndClearExpectations(&destructorHook);
|
||||
|
||||
using Hash = std::hash<objc_support::object_ptr<WithDestructorHookObjC>>;
|
||||
using HashImpl = std::hash<NSObject*>;
|
||||
using Hash = std::hash<typename TypeParam::TestedType>;
|
||||
using HashImpl = std::hash<const void*>;
|
||||
|
||||
EXPECT_THAT(Hash()(obj), HashImpl()(ptr1));
|
||||
EXPECT_THAT(Hash()(empty), HashImpl()(nullptr));
|
||||
EXPECT_THAT(Hash()(reset), HashImpl()(nullptr));
|
||||
|
||||
EXPECT_CALL(destructorHook, Call(ptr1.impl));
|
||||
EXPECT_CALL(destructorHook, Call(TypeParam::getHook(ptr1)));
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
Reference in New Issue
Block a user