Home | History | Annotate | Download | only in mac
      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