1 // Copyright (c) 2011 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
5 #import <Foundation/Foundation.h>
6 #include <objc/runtime.h>
8 #include "base/logging.h"
9 #import "base/mac/scoped_nsobject.h"
10 #import "chrome/common/mac/objc_zombie.h"
11 #include "testing/gtest/include/gtest/gtest.h"
12 #include "testing/platform_test.h"
14 @interface ZombieCxxDestructTest : NSObject
16 base::scoped_nsobject<id> aRef_;
18 - (id)initWith:(id)anObject;
21 @implementation ZombieCxxDestructTest
22 - (id)initWith:(id)anObject {
25 aRef_.reset([anObject retain]);
31 @interface ZombieAssociatedObjectTest : NSObject
32 - (id)initWithAssociatedObject:(id)anObject;
35 @implementation ZombieAssociatedObjectTest
37 - (id)initWithAssociatedObject:(id)anObject {
38 if ((self = [super init])) {
39 // The address of the variable itself is the unique key, the
40 // contents don't matter.
41 static char kAssociatedObjectKey = 'x';
42 objc_setAssociatedObject(
43 self, &kAssociatedObjectKey, anObject, OBJC_ASSOCIATION_RETAIN);
52 // Verify that the C++ destructors run when the last reference to the
53 // object is released.
54 // NOTE(shess): To test the negative, comment out the |g_objectDestruct()|
55 // call in |ZombieDealloc()|.
56 TEST(ObjcZombieTest, CxxDestructors) {
57 base::scoped_nsobject<id> anObject([[NSObject alloc] init]);
58 EXPECT_EQ(1u, [anObject retainCount]);
60 ASSERT_TRUE(ObjcEvilDoers::ZombieEnable(YES, 100));
62 base::scoped_nsobject<ZombieCxxDestructTest> soonInfected(
63 [[ZombieCxxDestructTest alloc] initWith:anObject]);
64 EXPECT_EQ(2u, [anObject retainCount]);
66 // When |soonInfected| becomes a zombie, the C++ destructors should
67 // run and release a reference to |anObject|.
69 EXPECT_EQ(1u, [anObject retainCount]);
71 // The local reference should remain (C++ destructors aren't re-run).
72 ObjcEvilDoers::ZombieDisable();
73 EXPECT_EQ(1u, [anObject retainCount]);
76 // Verify that the associated objects are released when the object is
78 TEST(ObjcZombieTest, AssociatedObjectsReleased) {
79 base::scoped_nsobject<id> anObject([[NSObject alloc] init]);
80 EXPECT_EQ(1u, [anObject retainCount]);
82 ASSERT_TRUE(ObjcEvilDoers::ZombieEnable(YES, 100));
84 base::scoped_nsobject<ZombieAssociatedObjectTest> soonInfected(
85 [[ZombieAssociatedObjectTest alloc] initWithAssociatedObject:anObject]);
86 EXPECT_EQ(2u, [anObject retainCount]);
88 // When |soonInfected| becomes a zombie, the associated object
89 // should be released.
91 EXPECT_EQ(1u, [anObject retainCount]);
93 // The local reference should remain (associated objects not re-released).
94 ObjcEvilDoers::ZombieDisable();
95 EXPECT_EQ(1u, [anObject retainCount]);