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 14 namespace { 15 16 // The number of CountVonCounts outstanding. 17 int ah_ah_ah; 18 19 // NumberHolder exists to exercise the property attribute string parser by 20 // providing a named struct and an anonymous union. 21 struct 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 238 namespace { 239 240 TEST(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