James Robinson | 646469d | 2014-10-03 15:33:28 -0700 | [diff] [blame] | 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 |