Chromium Code Reviews| 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..f997c45fdf476093738633a4707b99e2c9e813ab 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 lookup |objc_setAssociatedObject()|, which isn't |
|
Mark Mentovai
2011/06/07 21:42:57
look up
Scott Hess - ex-Googler
2011/06/07 23:48:21
Done.
|
| +// 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,18 +42,54 @@ |
| } |
| @end |
| +@interface ZombieAssociatedObjectTest : NSObject |
| +{ |
|
Mark Mentovai
2011/06/07 21:42:57
You don’t need the { } for an instance variable-fr
Scott Hess - ex-Googler
2011/06/07 23:48:21
Done.
|
| +} |
| ++ (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]); |
| - ASSERT_TRUE(ObjcEvilDoers::ZombieEnable(YES, 100)); |
| + ASSERT_TRUE( |
| + ObjcEvilDoers::ZombieEnable(ObjcEvilDoers::RUNTIME_GUESS, YES, 100)); |
| scoped_nsobject<ZombieCxxDestructTest> soonInfected( |
| [[ZombieCxxDestructTest alloc] initWith:anObject]); |
| @@ -53,4 +105,35 @@ 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, enable zombies with |
| +// |RUNTIME_10_5|, and run this test in isolation 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(ObjcEvilDoers::RUNTIME_GUESS, YES, 100)); |
| + |
| + scoped_nsobject<ZombieAssociatedObjectTest> soonInfected( |
| + [[ZombieAssociatedObjectTest alloc] initWithAssociatedObject:anObject]); |
| + EXPECT_EQ(2u, [anObject retainCount]); |
| + |
| + // When |soonInfected| becomes a zombie, the associated object |
|
Mark Mentovai
2011/06/07 21:42:57
Good test.
|
| + // 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 |