| Index: chrome/browser/ui/cocoa/objc_zombie_unittest.mm
|
| diff --git a/chrome/browser/ui/cocoa/objc_zombie_unittest.mm b/chrome/browser/ui/cocoa/objc_zombie_unittest.mm
|
| index 69f6ea0315806e2c83df6356598b322e2c3103f7..1cadf4a7888e7565dcc193dca226a393aabb9664 100644
|
| --- a/chrome/browser/ui/cocoa/objc_zombie_unittest.mm
|
| +++ b/chrome/browser/ui/cocoa/objc_zombie_unittest.mm
|
| @@ -3,12 +3,28 @@
|
| // found in the LICENSE file.
|
|
|
| #import <Cocoa/Cocoa.h>
|
| +#include <dlfcn.h>
|
|
|
| +#include "base/logging.h"
|
| #import "base/memory/scoped_nsobject.h"
|
| #import "chrome/browser/ui/cocoa/objc_zombie.h"
|
| #include "testing/gtest/include/gtest/gtest.h"
|
| #include "testing/platform_test.h"
|
|
|
| +namespace {
|
| +
|
| +// Dynamically look up |objc_setAssociatedObject()|, which isn't
|
| +// available until the 10.6 SDK.
|
| +
|
| +typedef void objc_setAssociatedObjectFn(id object, void *key, id value,
|
| + int policy);
|
| +objc_setAssociatedObjectFn* LookupSetAssociatedObjectFn() {
|
| + return reinterpret_cast<objc_setAssociatedObjectFn*>(
|
| + dlsym(RTLD_DEFAULT, "objc_setAssociatedObject"));
|
| +}
|
| +
|
| +} // namespace
|
| +
|
| @interface ZombieCxxDestructTest : NSObject
|
| {
|
| scoped_nsobject<id> aRef_;
|
| @@ -26,13 +42,45 @@
|
| }
|
| @end
|
|
|
| +@interface ZombieAssociatedObjectTest : NSObject
|
| ++ (BOOL)supportsAssociatedObjects;
|
| +- (id)initWithAssociatedObject:(id)anObject;
|
| +@end
|
| +
|
| +@implementation ZombieAssociatedObjectTest
|
| +
|
| ++ (BOOL)supportsAssociatedObjects {
|
| + if (LookupSetAssociatedObjectFn())
|
| + return YES;
|
| + return NO;
|
| +}
|
| +
|
| +- (id)initWithAssociatedObject:(id)anObject {
|
| + self = [super init];
|
| + if (self) {
|
| + objc_setAssociatedObjectFn* fn = LookupSetAssociatedObjectFn();
|
| + if (fn) {
|
| + // Cribbed from 10.6 <objc/runtime.h>.
|
| + static const int kObjcAssociationRetain = 01401;
|
| +
|
| + // The address of the variable itself is the unique key, the
|
| + // contents don't matter.
|
| + static char kAssociatedObjectKey = 'x';
|
| +
|
| + (*fn)(self, &kAssociatedObjectKey, anObject, kObjcAssociationRetain);
|
| + }
|
| + }
|
| + return self;
|
| +}
|
| +
|
| +@end
|
| +
|
| namespace {
|
|
|
| // Verify that the C++ destructors run when the last reference to the
|
| -// object is released. Unfortunately, testing the negative requires
|
| -// commenting out the |object_cxxDestruct()| call in
|
| -// |ZombieDealloc()|.
|
| -
|
| +// object is released.
|
| +// NOTE(shess): To test the negative, comment out the |g_objectDestruct()|
|
| +// call in |ZombieDealloc()|.
|
| TEST(ObjcZombieTest, CxxDestructors) {
|
| scoped_nsobject<id> anObject([[NSObject alloc] init]);
|
| EXPECT_EQ(1u, [anObject retainCount]);
|
| @@ -53,4 +101,34 @@ TEST(ObjcZombieTest, CxxDestructors) {
|
| EXPECT_EQ(1u, [anObject retainCount]);
|
| }
|
|
|
| +// Verify that the associated objects are released when the object is
|
| +// released.
|
| +// NOTE(shess): To test the negative, hardcode |g_objectDestruct| to
|
| +// the 10.5 version in |ZombieInit()|, and run this test on 10.6.
|
| +TEST(ObjcZombieTest, AssociatedObjectsReleased) {
|
| + if (![ZombieAssociatedObjectTest supportsAssociatedObjects]) {
|
| + LOG(ERROR)
|
| + << "ObjcZombieTest.AssociatedObjectsReleased not supported on 10.5";
|
| + return;
|
| + }
|
| +
|
| + scoped_nsobject<id> anObject([[NSObject alloc] init]);
|
| + EXPECT_EQ(1u, [anObject retainCount]);
|
| +
|
| + ASSERT_TRUE(ObjcEvilDoers::ZombieEnable(YES, 100));
|
| +
|
| + scoped_nsobject<ZombieAssociatedObjectTest> soonInfected(
|
| + [[ZombieAssociatedObjectTest alloc] initWithAssociatedObject:anObject]);
|
| + EXPECT_EQ(2u, [anObject retainCount]);
|
| +
|
| + // When |soonInfected| becomes a zombie, the associated object
|
| + // should be released.
|
| + soonInfected.reset();
|
| + EXPECT_EQ(1u, [anObject retainCount]);
|
| +
|
| + // The local reference should remain (associated objects not re-released).
|
| + ObjcEvilDoers::ZombieDisable();
|
| + EXPECT_EQ(1u, [anObject retainCount]);
|
| +}
|
| +
|
| } // namespace
|
|
|