[ffigen] Test assign/retain/copy properties (#390)
* Test autorelease pools and more copying cases
* Test assign/retain/copy properties
diff --git a/pkgs/ffigen/test/native_objc_test/automated_ref_count_test.dart b/pkgs/ffigen/test/native_objc_test/automated_ref_count_test.dart
index 74302f9..63ed706 100644
--- a/pkgs/ffigen/test/native_objc_test/automated_ref_count_test.dart
+++ b/pkgs/ffigen/test/native_objc_test/automated_ref_count_test.dart
@@ -132,6 +132,98 @@
calloc.free(counter);
});
+ assignPropertiesInnerInner(Pointer<Int32> counter, ArcTestObject outerObj) {
+ final assignObj = ArcTestObject.newWithCounter_(lib, counter);
+ expect(counter.value, 2);
+ outerObj.assignedProperty = assignObj;
+ expect(counter.value, 2);
+ expect(assignObj, outerObj.assignedProperty);
+ // To test that outerObj isn't holding a reference to assignObj, we let
+ // assignObj go out of scope, but keep outerObj in scope. This is
+ // dangerous because outerObj now has a dangling reference, so don't
+ // access that reference.
+ }
+
+ assignPropertiesInner(Pointer<Int32> counter) {
+ final outerObj = ArcTestObject.newWithCounter_(lib, counter);
+ expect(counter.value, 1);
+ assignPropertiesInnerInner(counter, outerObj);
+ doGC();
+ // assignObj has been cleaned up.
+ expect(counter.value, 1);
+ }
+
+ test('assign properties ref count correctly', () {
+ final counter = calloc<Int32>();
+ counter.value = 0;
+ assignPropertiesInner(counter);
+ doGC();
+ expect(counter.value, 0);
+ calloc.free(counter);
+ });
+
+ retainPropertiesInnerInner(Pointer<Int32> counter, ArcTestObject outerObj) {
+ final retainObj = ArcTestObject.newWithCounter_(lib, counter);
+ expect(counter.value, 2);
+ outerObj.retainedProperty = retainObj;
+ expect(counter.value, 2);
+ expect(retainObj, outerObj.retainedProperty);
+ }
+
+ retainPropertiesInner(Pointer<Int32> counter) {
+ final outerObj = ArcTestObject.newWithCounter_(lib, counter);
+ expect(counter.value, 1);
+ retainPropertiesInnerInner(counter, outerObj);
+ doGC();
+ // retainObj is still around, because outerObj retains a reference to it.
+ expect(counter.value, 2);
+ }
+
+ test('retain properties ref count correctly', () {
+ final counter = calloc<Int32>();
+ counter.value = 0;
+ // The getters of retain properties retain+autorelease the value. So we
+ // need an autorelease pool.
+ final pool = lib.createAutoreleasePool();
+ retainPropertiesInner(counter);
+ doGC();
+ expect(counter.value, 1);
+ lib.destroyAutoreleasePool(pool);
+ expect(counter.value, 0);
+ calloc.free(counter);
+ });
+
+ copyPropertiesInner(Pointer<Int32> counter) {
+ final outerObj = ArcTestObject.newWithCounter_(lib, counter);
+ expect(counter.value, 1);
+
+ final copyObj = ArcTestObject.newWithCounter_(lib, counter);
+ expect(counter.value, 2);
+ outerObj.copiedProperty = copyObj;
+ // Copy properties make a copy of the object, so now we have 3 objects.
+ expect(counter.value, 3);
+ expect(copyObj, isNot(outerObj.copiedProperty));
+
+ final anotherCopy = outerObj.copiedProperty;
+ // The getter doesn't copy the object.
+ expect(counter.value, 3);
+ expect(anotherCopy, outerObj.copiedProperty);
+ }
+
+ test('copy properties ref count correctly', () {
+ final counter = calloc<Int32>();
+ counter.value = 0;
+ // The getters of copy properties retain+autorelease the value. So we need
+ // an autorelease pool.
+ final pool = lib.createAutoreleasePool();
+ copyPropertiesInner(counter);
+ doGC();
+ expect(counter.value, 1);
+ lib.destroyAutoreleasePool(pool);
+ expect(counter.value, 0);
+ calloc.free(counter);
+ });
+
castFromPointerInnerReleaseAndRetain(int address) {
final fromCast = RefCounted.castFromPointer(
lib, Pointer<ObjCObject>.fromAddress(address),
diff --git a/pkgs/ffigen/test/native_objc_test/automated_ref_count_test.m b/pkgs/ffigen/test/native_objc_test/automated_ref_count_test.m
index f4a4fc9..d249389 100644
--- a/pkgs/ffigen/test/native_objc_test/automated_ref_count_test.m
+++ b/pkgs/ffigen/test/native_objc_test/automated_ref_count_test.m
@@ -21,6 +21,10 @@
- (id)copyWithZone:(NSZone*) zone;
- (ArcTestObject*)returnsRetained NS_RETURNS_RETAINED;
+@property (assign) ArcTestObject* assignedProperty;
+@property (retain) ArcTestObject* retainedProperty;
+@property (copy) ArcTestObject* copiedProperty;
+
@end
@interface RefCounted : NSObject
@@ -58,6 +62,8 @@
- (void)dealloc {
--*counter;
+ [_retainedProperty release];
+ [_copiedProperty release];
[super dealloc];
}