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. 4 5#import <Foundation/Foundation.h> 6 7#import "base/mac/objc_property_releaser.h" 8#import "base/mac/scoped_nsautorelease_pool.h" 9#include "testing/gtest/include/gtest/gtest.h" 10 11// "When I'm alone, I count myself." 12// --Count von Count, http://www.youtube.com/watch?v=FKzszqa9WA4 13 14namespace { 15 16// The number of CountVonCounts outstanding. 17int ah_ah_ah; 18 19// NumberHolder exists to exercise the property attribute string parser by 20// providing a named struct and an anonymous union. 21struct NumberHolder { 22 union { 23 long long sixty_four; 24 int thirty_two; 25 short sixteen; 26 char eight; 27 } what; 28 enum { 29 SIXTY_FOUR, 30 THIRTY_TWO, 31 SIXTEEN, 32 EIGHT 33 } how; 34}; 35 36} // namespace 37 38@interface CountVonCount : NSObject<NSCopying> 39 40+ (CountVonCount*)countVonCount; 41 42@end // @interface CountVonCount 43 44@implementation CountVonCount 45 46+ (CountVonCount*)countVonCount { 47 return [[[CountVonCount alloc] init] autorelease]; 48} 49 50- (id)init { 51 ++ah_ah_ah; 52 return [super init]; 53} 54 55- (void)dealloc { 56 --ah_ah_ah; 57 [super dealloc]; 58} 59 60- (id)copyWithZone:(NSZone*)zone { 61 return [[CountVonCount allocWithZone:zone] init]; 62} 63 64@end // @implementation CountVonCount 65 66@interface ObjCPropertyTestBase : NSObject { 67 @private 68 CountVonCount* baseCvcRetain_; 69 CountVonCount* baseCvcCopy_; 70 CountVonCount* baseCvcAssign_; 71 CountVonCount* baseCvcNotProperty_; 72 CountVonCount* baseCvcNil_; 73 CountVonCount* baseCvcCustom_; 74 int baseInt_; 75 double baseDouble_; 76 void* basePointer_; 77 NumberHolder baseStruct_; 78 79 base::mac::ObjCPropertyReleaser propertyReleaser_ObjCPropertyTestBase_; 80} 81 82@property(retain, nonatomic) CountVonCount* baseCvcRetain; 83@property(copy, nonatomic) CountVonCount* baseCvcCopy; 84@property(assign, nonatomic) CountVonCount* baseCvcAssign; 85@property(retain, nonatomic) CountVonCount* baseCvcNil; 86@property(retain, nonatomic, getter=baseCustom, setter=setBaseCustom:) 87 CountVonCount* baseCvcCustom; 88@property(retain, nonatomic) CountVonCount* baseCvcDynamic; 89@property(assign, nonatomic) int baseInt; 90@property(assign, nonatomic) double baseDouble; 91@property(assign, nonatomic) void* basePointer; 92@property(assign, nonatomic) NumberHolder baseStruct; 93 94- (void)setBaseCvcNotProperty:(CountVonCount*)cvc; 95 96@end // @interface ObjCPropertyTestBase 97 98@implementation ObjCPropertyTestBase 99 100@synthesize baseCvcRetain = baseCvcRetain_; 101@synthesize baseCvcCopy = baseCvcCopy_; 102@synthesize baseCvcAssign = baseCvcAssign_; 103@synthesize baseCvcNil = baseCvcNil_; 104@synthesize baseCvcCustom = baseCvcCustom_; 105@dynamic baseCvcDynamic; 106@synthesize baseInt = baseInt_; 107@synthesize baseDouble = baseDouble_; 108@synthesize basePointer = basePointer_; 109@synthesize baseStruct = baseStruct_; 110 111- (id)init { 112 if ((self = [super init])) { 113 propertyReleaser_ObjCPropertyTestBase_.Init( 114 self, [ObjCPropertyTestBase class]); 115 } 116 return self; 117} 118 119- (void)dealloc { 120 [baseCvcNotProperty_ release]; 121 [super dealloc]; 122} 123 124- (void)setBaseCvcNotProperty:(CountVonCount*)cvc { 125 if (cvc != baseCvcNotProperty_) { 126 [baseCvcNotProperty_ release]; 127 baseCvcNotProperty_ = [cvc retain]; 128 } 129} 130 131@end // @implementation ObjCPropertyTestBase 132 133@protocol ObjCPropertyTestProtocol 134 135@property(retain, nonatomic) CountVonCount* protoCvcRetain; 136@property(copy, nonatomic) CountVonCount* protoCvcCopy; 137@property(assign, nonatomic) CountVonCount* protoCvcAssign; 138@property(retain, nonatomic) CountVonCount* protoCvcNil; 139@property(retain, nonatomic, getter=protoCustom, setter=setProtoCustom:) 140 CountVonCount* protoCvcCustom; 141@property(retain, nonatomic) CountVonCount* protoCvcDynamic; 142@property(assign, nonatomic) int protoInt; 143@property(assign, nonatomic) double protoDouble; 144@property(assign, nonatomic) void* protoPointer; 145@property(assign, nonatomic) NumberHolder protoStruct; 146 147@end // @protocol ObjCPropertyTestProtocol 148 149@interface ObjCPropertyTestDerived 150 : ObjCPropertyTestBase<ObjCPropertyTestProtocol> { 151 @private 152 CountVonCount* derivedCvcRetain_; 153 CountVonCount* derivedCvcCopy_; 154 CountVonCount* derivedCvcAssign_; 155 CountVonCount* derivedCvcNotProperty_; 156 CountVonCount* derivedCvcNil_; 157 CountVonCount* derivedCvcCustom_; 158 int derivedInt_; 159 double derivedDouble_; 160 void* derivedPointer_; 161 NumberHolder derivedStruct_; 162 163 CountVonCount* protoCvcRetain_; 164 CountVonCount* protoCvcCopy_; 165 CountVonCount* protoCvcAssign_; 166 CountVonCount* protoCvcNil_; 167 CountVonCount* protoCvcCustom_; 168 int protoInt_; 169 double protoDouble_; 170 void* protoPointer_; 171 NumberHolder protoStruct_; 172 173 base::mac::ObjCPropertyReleaser propertyReleaser_ObjCPropertyTestDerived_; 174} 175 176@property(retain, nonatomic) CountVonCount* derivedCvcRetain; 177@property(copy, nonatomic) CountVonCount* derivedCvcCopy; 178@property(assign, nonatomic) CountVonCount* derivedCvcAssign; 179@property(retain, nonatomic) CountVonCount* derivedCvcNil; 180@property(retain, nonatomic, getter=derivedCustom, setter=setDerivedCustom:) 181 CountVonCount* derivedCvcCustom; 182@property(retain, nonatomic) CountVonCount* derivedCvcDynamic; 183@property(assign, nonatomic) int derivedInt; 184@property(assign, nonatomic) double derivedDouble; 185@property(assign, nonatomic) void* derivedPointer; 186@property(assign, nonatomic) NumberHolder derivedStruct; 187 188- (void)setDerivedCvcNotProperty:(CountVonCount*)cvc; 189 190@end // @interface ObjCPropertyTestDerived 191 192@implementation ObjCPropertyTestDerived 193 194@synthesize derivedCvcRetain = derivedCvcRetain_; 195@synthesize derivedCvcCopy = derivedCvcCopy_; 196@synthesize derivedCvcAssign = derivedCvcAssign_; 197@synthesize derivedCvcNil = derivedCvcNil_; 198@synthesize derivedCvcCustom = derivedCvcCustom_; 199@dynamic derivedCvcDynamic; 200@synthesize derivedInt = derivedInt_; 201@synthesize derivedDouble = derivedDouble_; 202@synthesize derivedPointer = derivedPointer_; 203@synthesize derivedStruct = derivedStruct_; 204 205@synthesize protoCvcRetain = protoCvcRetain_; 206@synthesize protoCvcCopy = protoCvcCopy_; 207@synthesize protoCvcAssign = protoCvcAssign_; 208@synthesize protoCvcNil = protoCvcNil_; 209@synthesize protoCvcCustom = protoCvcCustom_; 210@dynamic protoCvcDynamic; 211@synthesize protoInt = protoInt_; 212@synthesize protoDouble = protoDouble_; 213@synthesize protoPointer = protoPointer_; 214@synthesize protoStruct = protoStruct_; 215 216- (id)init { 217 if ((self = [super init])) { 218 propertyReleaser_ObjCPropertyTestDerived_.Init( 219 self, [ObjCPropertyTestDerived class]); 220 } 221 return self; 222} 223 224- (void)dealloc { 225 [derivedCvcNotProperty_ release]; 226 [super dealloc]; 227} 228 229- (void)setDerivedCvcNotProperty:(CountVonCount*)cvc { 230 if (cvc != derivedCvcNotProperty_) { 231 [derivedCvcNotProperty_ release]; 232 derivedCvcNotProperty_ = [cvc retain]; 233 } 234} 235 236@end // @implementation ObjCPropertyTestDerived 237 238namespace { 239 240TEST(ObjCPropertyReleaserTest, SesameStreet) { 241 ObjCPropertyTestDerived* test_object = [[ObjCPropertyTestDerived alloc] init]; 242 243 // Assure a clean slate. 244 EXPECT_EQ(0, ah_ah_ah); 245 EXPECT_EQ(1U, [test_object retainCount]); 246 247 CountVonCount* baseAssign = [[CountVonCount alloc] init]; 248 CountVonCount* derivedAssign = [[CountVonCount alloc] init]; 249 CountVonCount* protoAssign = [[CountVonCount alloc] init]; 250 251 // Make sure that worked before things get more involved. 252 EXPECT_EQ(3, ah_ah_ah); 253 254 { 255 base::mac::ScopedNSAutoreleasePool pool; 256 257 test_object.baseCvcRetain = [CountVonCount countVonCount]; 258 test_object.baseCvcCopy = [CountVonCount countVonCount]; 259 test_object.baseCvcAssign = baseAssign; 260 test_object.baseCvcCustom = [CountVonCount countVonCount]; 261 [test_object setBaseCvcNotProperty:[CountVonCount countVonCount]]; 262 263 // That added 4 objects, plus 1 more that was copied. 264 EXPECT_EQ(8, ah_ah_ah); 265 266 test_object.derivedCvcRetain = [CountVonCount countVonCount]; 267 test_object.derivedCvcCopy = [CountVonCount countVonCount]; 268 test_object.derivedCvcAssign = derivedAssign; 269 test_object.derivedCvcCustom = [CountVonCount countVonCount]; 270 [test_object setDerivedCvcNotProperty:[CountVonCount countVonCount]]; 271 272 // That added 4 objects, plus 1 more that was copied. 273 EXPECT_EQ(13, ah_ah_ah); 274 275 test_object.protoCvcRetain = [CountVonCount countVonCount]; 276 test_object.protoCvcCopy = [CountVonCount countVonCount]; 277 test_object.protoCvcAssign = protoAssign; 278 test_object.protoCvcCustom = [CountVonCount countVonCount]; 279 280 // That added 3 objects, plus 1 more that was copied. 281 EXPECT_EQ(17, ah_ah_ah); 282 } 283 284 // Now that the autorelease pool has been popped, the 3 objects that were 285 // copied when placed into the test object will have been deallocated. 286 EXPECT_EQ(14, ah_ah_ah); 287 288 // Make sure that the setters work and have the expected semantics. 289 test_object.baseCvcRetain = nil; 290 test_object.baseCvcCopy = nil; 291 test_object.baseCvcAssign = nil; 292 test_object.baseCvcCustom = nil; 293 test_object.derivedCvcRetain = nil; 294 test_object.derivedCvcCopy = nil; 295 test_object.derivedCvcAssign = nil; 296 test_object.derivedCvcCustom = nil; 297 test_object.protoCvcRetain = nil; 298 test_object.protoCvcCopy = nil; 299 test_object.protoCvcAssign = nil; 300 test_object.protoCvcCustom = nil; 301 302 // The CountVonCounts marked "retain" and "copy" should have been 303 // deallocated. Those marked assign should not have been. The only ones that 304 // should exist now are the ones marked "assign" and the ones held in 305 // non-property instance variables. 306 EXPECT_EQ(5, ah_ah_ah); 307 308 { 309 base::mac::ScopedNSAutoreleasePool pool; 310 311 // Put things back to how they were. 312 test_object.baseCvcRetain = [CountVonCount countVonCount]; 313 test_object.baseCvcCopy = [CountVonCount countVonCount]; 314 test_object.baseCvcAssign = baseAssign; 315 test_object.baseCvcCustom = [CountVonCount countVonCount]; 316 test_object.derivedCvcRetain = [CountVonCount countVonCount]; 317 test_object.derivedCvcCopy = [CountVonCount countVonCount]; 318 test_object.derivedCvcAssign = derivedAssign; 319 test_object.derivedCvcCustom = [CountVonCount countVonCount]; 320 test_object.protoCvcRetain = [CountVonCount countVonCount]; 321 test_object.protoCvcCopy = [CountVonCount countVonCount]; 322 test_object.protoCvcAssign = protoAssign; 323 test_object.protoCvcCustom = [CountVonCount countVonCount]; 324 325 // 9 more CountVonCounts, 3 of which were copied. 326 EXPECT_EQ(17, ah_ah_ah); 327 } 328 329 // Now that the autorelease pool has been popped, the 3 copies are gone. 330 EXPECT_EQ(14, ah_ah_ah); 331 332 // Releasing the test object should get rid of everything that it owns. 333 [test_object release]; 334 335 // The property releaser should have released all of the CountVonCounts 336 // associated with properties marked "retain" or "copy". The -dealloc 337 // methods in each should have released the single non-property objects in 338 // each. Only the CountVonCounts assigned to the properties marked "assign" 339 // should remain. 340 EXPECT_EQ(3, ah_ah_ah); 341 342 [baseAssign release]; 343 [derivedAssign release]; 344 [protoAssign release]; 345 346 // Zero! Zero counts! Ah, ah, ah. 347 EXPECT_EQ(0, ah_ah_ah); 348} 349 350} // namespace 351