/* * Copyright (C) 2013-2015 RoboVM AB * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.robovm.objc; import static org.junit.Assert.*; import org.junit.Assume; import org.junit.Before; import org.junit.Test; import org.robovm.apple.corefoundation.CFString; import org.robovm.apple.foundation.NSCache; import org.robovm.apple.foundation.NSCacheDelegate; import org.robovm.apple.foundation.NSObject; import org.robovm.apple.uikit.UIView; import org.robovm.rt.bro.Bro; public class ObjCObjectOwnershipHelperTest { class CustomNSObject extends NSObject { String stringValue; long longValue; public CustomNSObject(String stringValue, long longValue) { this.stringValue = stringValue; this.longValue = longValue; } } class CustomUIView extends UIView {} class CustomNSCacheDelegateAdapter extends NSObject implements NSCacheDelegate { @Override public void willEvictObject(NSCache cache, NSObject obj) { } } class CustomCFString extends CFString { public CustomCFString(String str) { super(str); } } @Before public void setUp() { Assume.assumeTrue(Bro.IS_DARWIN); } /** * Every custom class extending from NSObject should be retained on the Java * side when retained on the Obj-C side. */ @Test public void testIfCustomObjectsAreRetained() { Assume.assumeTrue(System.getProperty("os.name").contains("iOS")); CustomUIView c1 = new CustomUIView(); CustomNSCacheDelegateAdapter c2 = new CustomNSCacheDelegateAdapter(); CustomCFString c3 = new CustomCFString(""); NSCache cache = new NSCache(); cache.put("1", c1); cache.put("2", c2); cache.put("3", c3.as(NSObject.class)); assertEquals(true, ObjCObject.ObjectOwnershipHelper.isObjectRetained(c1)); assertEquals(true, ObjCObject.ObjectOwnershipHelper.isObjectRetained(c2)); assertEquals(false, ObjCObject.ObjectOwnershipHelper.isObjectRetained(c3.as(NSObject.class))); } /** * Only custom objects should get the hooks to retain and release. */ @Test public void testIfOnlyCustomObjectsAreRetained() { Assume.assumeTrue(System.getProperty("os.name").contains("iOS")); CustomUIView custom = new CustomUIView(); NSObject default1 = new NSObject(); UIView default2 = new UIView(); NSCache cache = new NSCache(); cache.put("1", custom); cache.put("2", default1); cache.put("3", default2); assertEquals(true, ObjCObject.ObjectOwnershipHelper.isObjectRetained(custom)); assertEquals(false, ObjCObject.ObjectOwnershipHelper.isObjectRetained(default1)); assertEquals(false, ObjCObject.ObjectOwnershipHelper.isObjectRetained(default2)); } private void addNewCustomObjectToCache(NSCache cache, String id, String stringValue, long longValue) { cache.put(id, new CustomNSObject(stringValue, longValue)); } /** * Every retained object should not be GCed and lose the values of its variables. */ @Test public void testIfCustomObjectsVariablesAreRetained() { final String stringValue = "ABC"; final long longValue = 123; NSCache cache = new NSCache(); // We don't want to have any reference to the CustomNSObject. // If it were not stored with the ownership helper, it would get GCed immediately. addNewCustomObjectToCache(cache, "1", stringValue, longValue); forceGC(); CustomNSObject custom = (CustomNSObject) cache.get("1"); assertEquals(stringValue, custom.stringValue); assertEquals(longValue, custom.longValue); } /** * Custom objects that have been released shouldn't be referenced any longer * on the Java side. But if they are retained again, also reference them * again. */ @Test public void testIfCustomObjectsAreCorrectlyReferenced() { Assume.assumeTrue(System.getProperty("os.name").contains("iOS")); CustomUIView custom = new CustomUIView(); NSCache cache = new NSCache(); cache.put("1", custom); assertEquals(true, ObjCObject.ObjectOwnershipHelper.isObjectRetained(custom)); cache.remove("1"); assertEquals(false, ObjCObject.ObjectOwnershipHelper.isObjectRetained(custom)); cache.put("2", custom); assertEquals(true, ObjCObject.ObjectOwnershipHelper.isObjectRetained(custom)); cache.remove("2"); assertEquals(false, ObjCObject.ObjectOwnershipHelper.isObjectRetained(custom)); } private static void forceGC() { for (int i = 0; i < 10; i++) { System.gc(); } } }