// Copyright (c) 2011 The Chromium Authors. All rights reserved. // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. #import <Foundation/Foundation.h> #import "base/mac/objc_property_releaser.h" #import "base/mac/scoped_nsautorelease_pool.h" #include "testing/gtest/include/gtest/gtest.h" // "When I'm alone, I count myself." // --Count von Count, http://www.youtube.com/watch?v=FKzszqa9WA4 namespace { // The number of CountVonCounts outstanding. int ah_ah_ah; // NumberHolder exists to exercise the property attribute string parser by // providing a named struct and an anonymous union. struct NumberHolder { union { long long sixty_four; int thirty_two; short sixteen; char eight; } what; enum { SIXTY_FOUR, THIRTY_TWO, SIXTEEN, EIGHT } how; }; } // namespace @interface CountVonCount : NSObject<NSCopying> + (CountVonCount*)countVonCount; @end // @interface CountVonCount @implementation CountVonCount + (CountVonCount*)countVonCount { return [[[CountVonCount alloc] init] autorelease]; } - (id)init { ++ah_ah_ah; return [super init]; } - (void)dealloc { --ah_ah_ah; [super dealloc]; } - (id)copyWithZone:(NSZone*)zone { return [[CountVonCount allocWithZone:zone] init]; } @end // @implementation CountVonCount @interface ObjCPropertyTestBase : NSObject { @private CountVonCount* baseCvcRetain_; CountVonCount* baseCvcCopy_; CountVonCount* baseCvcAssign_; CountVonCount* baseCvcNotProperty_; CountVonCount* baseCvcNil_; CountVonCount* baseCvcCustom_; int baseInt_; double baseDouble_; void* basePointer_; NumberHolder baseStruct_; base::mac::ObjCPropertyReleaser propertyReleaser_ObjCPropertyTestBase_; } @property(retain, nonatomic) CountVonCount* baseCvcRetain; @property(copy, nonatomic) CountVonCount* baseCvcCopy; @property(assign, nonatomic) CountVonCount* baseCvcAssign; @property(retain, nonatomic) CountVonCount* baseCvcNil; @property(retain, nonatomic, getter=baseCustom, setter=setBaseCustom:) CountVonCount* baseCvcCustom; @property(retain, nonatomic) CountVonCount* baseCvcDynamic; @property(assign, nonatomic) int baseInt; @property(assign, nonatomic) double baseDouble; @property(assign, nonatomic) void* basePointer; @property(assign, nonatomic) NumberHolder baseStruct; - (void)setBaseCvcNotProperty:(CountVonCount*)cvc; @end // @interface ObjCPropertyTestBase @implementation ObjCPropertyTestBase @synthesize baseCvcRetain = baseCvcRetain_; @synthesize baseCvcCopy = baseCvcCopy_; @synthesize baseCvcAssign = baseCvcAssign_; @synthesize baseCvcNil = baseCvcNil_; @synthesize baseCvcCustom = baseCvcCustom_; @dynamic baseCvcDynamic; @synthesize baseInt = baseInt_; @synthesize baseDouble = baseDouble_; @synthesize basePointer = basePointer_; @synthesize baseStruct = baseStruct_; - (id)init { if ((self = [super init])) { propertyReleaser_ObjCPropertyTestBase_.Init( self, [ObjCPropertyTestBase class]); } return self; } - (void)dealloc { [baseCvcNotProperty_ release]; [super dealloc]; } - (void)setBaseCvcNotProperty:(CountVonCount*)cvc { if (cvc != baseCvcNotProperty_) { [baseCvcNotProperty_ release]; baseCvcNotProperty_ = [cvc retain]; } } @end // @implementation ObjCPropertyTestBase @protocol ObjCPropertyTestProtocol @property(retain, nonatomic) CountVonCount* protoCvcRetain; @property(copy, nonatomic) CountVonCount* protoCvcCopy; @property(assign, nonatomic) CountVonCount* protoCvcAssign; @property(retain, nonatomic) CountVonCount* protoCvcNil; @property(retain, nonatomic, getter=protoCustom, setter=setProtoCustom:) CountVonCount* protoCvcCustom; @property(retain, nonatomic) CountVonCount* protoCvcDynamic; @property(assign, nonatomic) int protoInt; @property(assign, nonatomic) double protoDouble; @property(assign, nonatomic) void* protoPointer; @property(assign, nonatomic) NumberHolder protoStruct; @end // @protocol ObjCPropertyTestProtocol @interface ObjCPropertyTestDerived : ObjCPropertyTestBase<ObjCPropertyTestProtocol> { @private CountVonCount* derivedCvcRetain_; CountVonCount* derivedCvcCopy_; CountVonCount* derivedCvcAssign_; CountVonCount* derivedCvcNotProperty_; CountVonCount* derivedCvcNil_; CountVonCount* derivedCvcCustom_; int derivedInt_; double derivedDouble_; void* derivedPointer_; NumberHolder derivedStruct_; CountVonCount* protoCvcRetain_; CountVonCount* protoCvcCopy_; CountVonCount* protoCvcAssign_; CountVonCount* protoCvcNil_; CountVonCount* protoCvcCustom_; int protoInt_; double protoDouble_; void* protoPointer_; NumberHolder protoStruct_; base::mac::ObjCPropertyReleaser propertyReleaser_ObjCPropertyTestDerived_; } @property(retain, nonatomic) CountVonCount* derivedCvcRetain; @property(copy, nonatomic) CountVonCount* derivedCvcCopy; @property(assign, nonatomic) CountVonCount* derivedCvcAssign; @property(retain, nonatomic) CountVonCount* derivedCvcNil; @property(retain, nonatomic, getter=derivedCustom, setter=setDerivedCustom:) CountVonCount* derivedCvcCustom; @property(retain, nonatomic) CountVonCount* derivedCvcDynamic; @property(assign, nonatomic) int derivedInt; @property(assign, nonatomic) double derivedDouble; @property(assign, nonatomic) void* derivedPointer; @property(assign, nonatomic) NumberHolder derivedStruct; - (void)setDerivedCvcNotProperty:(CountVonCount*)cvc; @end // @interface ObjCPropertyTestDerived @implementation ObjCPropertyTestDerived @synthesize derivedCvcRetain = derivedCvcRetain_; @synthesize derivedCvcCopy = derivedCvcCopy_; @synthesize derivedCvcAssign = derivedCvcAssign_; @synthesize derivedCvcNil = derivedCvcNil_; @synthesize derivedCvcCustom = derivedCvcCustom_; @dynamic derivedCvcDynamic; @synthesize derivedInt = derivedInt_; @synthesize derivedDouble = derivedDouble_; @synthesize derivedPointer = derivedPointer_; @synthesize derivedStruct = derivedStruct_; @synthesize protoCvcRetain = protoCvcRetain_; @synthesize protoCvcCopy = protoCvcCopy_; @synthesize protoCvcAssign = protoCvcAssign_; @synthesize protoCvcNil = protoCvcNil_; @synthesize protoCvcCustom = protoCvcCustom_; @dynamic protoCvcDynamic; @synthesize protoInt = protoInt_; @synthesize protoDouble = protoDouble_; @synthesize protoPointer = protoPointer_; @synthesize protoStruct = protoStruct_; - (id)init { if ((self = [super init])) { propertyReleaser_ObjCPropertyTestDerived_.Init( self, [ObjCPropertyTestDerived class]); } return self; } - (void)dealloc { [derivedCvcNotProperty_ release]; [super dealloc]; } - (void)setDerivedCvcNotProperty:(CountVonCount*)cvc { if (cvc != derivedCvcNotProperty_) { [derivedCvcNotProperty_ release]; derivedCvcNotProperty_ = [cvc retain]; } } @end // @implementation ObjCPropertyTestDerived namespace { TEST(ObjCPropertyReleaserTest, SesameStreet) { ObjCPropertyTestDerived* test_object = [[ObjCPropertyTestDerived alloc] init]; // Assure a clean slate. EXPECT_EQ(0, ah_ah_ah); EXPECT_EQ(1U, [test_object retainCount]); CountVonCount* baseAssign = [[CountVonCount alloc] init]; CountVonCount* derivedAssign = [[CountVonCount alloc] init]; CountVonCount* protoAssign = [[CountVonCount alloc] init]; // Make sure that worked before things get more involved. EXPECT_EQ(3, ah_ah_ah); { base::mac::ScopedNSAutoreleasePool pool; test_object.baseCvcRetain = [CountVonCount countVonCount]; test_object.baseCvcCopy = [CountVonCount countVonCount]; test_object.baseCvcAssign = baseAssign; test_object.baseCvcCustom = [CountVonCount countVonCount]; [test_object setBaseCvcNotProperty:[CountVonCount countVonCount]]; // That added 4 objects, plus 1 more that was copied. EXPECT_EQ(8, ah_ah_ah); test_object.derivedCvcRetain = [CountVonCount countVonCount]; test_object.derivedCvcCopy = [CountVonCount countVonCount]; test_object.derivedCvcAssign = derivedAssign; test_object.derivedCvcCustom = [CountVonCount countVonCount]; [test_object setDerivedCvcNotProperty:[CountVonCount countVonCount]]; // That added 4 objects, plus 1 more that was copied. EXPECT_EQ(13, ah_ah_ah); test_object.protoCvcRetain = [CountVonCount countVonCount]; test_object.protoCvcCopy = [CountVonCount countVonCount]; test_object.protoCvcAssign = protoAssign; test_object.protoCvcCustom = [CountVonCount countVonCount]; // That added 3 objects, plus 1 more that was copied. EXPECT_EQ(17, ah_ah_ah); } // Now that the autorelease pool has been popped, the 3 objects that were // copied when placed into the test object will have been deallocated. EXPECT_EQ(14, ah_ah_ah); // Make sure that the setters work and have the expected semantics. test_object.baseCvcRetain = nil; test_object.baseCvcCopy = nil; test_object.baseCvcAssign = nil; test_object.baseCvcCustom = nil; test_object.derivedCvcRetain = nil; test_object.derivedCvcCopy = nil; test_object.derivedCvcAssign = nil; test_object.derivedCvcCustom = nil; test_object.protoCvcRetain = nil; test_object.protoCvcCopy = nil; test_object.protoCvcAssign = nil; test_object.protoCvcCustom = nil; // The CountVonCounts marked "retain" and "copy" should have been // deallocated. Those marked assign should not have been. The only ones that // should exist now are the ones marked "assign" and the ones held in // non-property instance variables. EXPECT_EQ(5, ah_ah_ah); { base::mac::ScopedNSAutoreleasePool pool; // Put things back to how they were. test_object.baseCvcRetain = [CountVonCount countVonCount]; test_object.baseCvcCopy = [CountVonCount countVonCount]; test_object.baseCvcAssign = baseAssign; test_object.baseCvcCustom = [CountVonCount countVonCount]; test_object.derivedCvcRetain = [CountVonCount countVonCount]; test_object.derivedCvcCopy = [CountVonCount countVonCount]; test_object.derivedCvcAssign = derivedAssign; test_object.derivedCvcCustom = [CountVonCount countVonCount]; test_object.protoCvcRetain = [CountVonCount countVonCount]; test_object.protoCvcCopy = [CountVonCount countVonCount]; test_object.protoCvcAssign = protoAssign; test_object.protoCvcCustom = [CountVonCount countVonCount]; // 9 more CountVonCounts, 3 of which were copied. EXPECT_EQ(17, ah_ah_ah); } // Now that the autorelease pool has been popped, the 3 copies are gone. EXPECT_EQ(14, ah_ah_ah); // Releasing the test object should get rid of everything that it owns. [test_object release]; // The property releaser should have released all of the CountVonCounts // associated with properties marked "retain" or "copy". The -dealloc // methods in each should have released the single non-property objects in // each. Only the CountVonCounts assigned to the properties marked "assign" // should remain. EXPECT_EQ(3, ah_ah_ah); [baseAssign release]; [derivedAssign release]; [protoAssign release]; // Zero! Zero counts! Ah, ah, ah. EXPECT_EQ(0, ah_ah_ah); } } // namespace