/*
* Copyright 2007, 2008, 2009 Duncan McGregor
*
* This file is part of Rococoa, a library to allow Java to talk to Cocoa.
*
* Rococoa is free software: you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* Rococoa is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with Rococoa. If not, see <http://www.gnu.org/licenses/>.
*/
package org.rococoa.internal;
import static org.junit.Assert.assertNotNull;
import static org.junit.Assert.assertNull;
import static org.junit.Assert.assertTrue;
import java.lang.ref.WeakReference;
import org.junit.Test;
import org.rococoa.ID;
import org.rococoa.cocoa.foundation.NSData;
import org.rococoa.cocoa.foundation.NSDictionary;
import org.rococoa.cocoa.foundation.NSObject;
import org.rococoa.cocoa.foundation.NSString;
import org.rococoa.test.RococoaTestCase;
/**
* @version $Id: NSObjectInvocationHandlerTest.java 331 2009-11-28 19:48:12Z dkocher@sudo.ch $
*/
public class NSObjectInvocationHandlerTest extends RococoaTestCase {
public static abstract class NSImage extends NSObject {
private static final _Class CLASS = org.rococoa.Rococoa.createClass("NSImage", _Class.class);
public interface _Class extends org.rococoa.ObjCClass {
NSImage alloc();
}
public abstract NSImage initWithData(NSData data);
}
/**
* We test for the case when the init method is not able to complete the initialization
* In such a case,, the init... method could free the receiver and return nil, indicating that
* the requested object can’t be created.
* <p/>
* Therefore, Rococoa should not release such instances.
* <p/>
* Example:
* NSImage *img = [NSImage alloc];
* This instance can be released using [img release]
* [img initWithData:nil];
* The following would lead to a crash because the initializer above fails
* [img release];
* <p/>
* NSObjectInvocationHandler therefore must make sure to not release an
* object on finalization when there was an error in initialization and the receiver
* is already freed according to the recommendation in the documentation.
* <p/>
* Summary: If nil is returned from a initializer, one must assume the object is already released
*
* @see org.rococoa.internal.ObjCObjectInvocationHandler#invokeCocoa(java.lang.reflect.Method, Object[])
* @see "http://developer.apple.com/mac/library/documentation/Cocoa/Conceptual/ObjectiveC/Articles/ocAllocInit.html#//apple_ref/doc/uid/TP30001163-CH22-105952"
*/
@Test
public void testInitReturnsNil() {
NSImage image = NSImage.CLASS.alloc();
assertNotNull("Allocation must return valid reference", image);
NSImage failedInitializedImage = image.initWithData(null);
assertNull("Expected init to fail and return nil", failedInitializedImage);
assertTrue("Initial image should now be invalid too", image.id().isNull());
// TODO - I'm a little unsure about whether this is the best course
// We shall not crash after garbage collection when the NSObjectInvocationHandler is finalized
WeakReference<Object> reference = new WeakReference<Object>(failedInitializedImage);
failedInitializedImage = null;
while (reference.get() != null) {
gc();
}
}
@Test
public void testNilReturnValues() {
NSDictionary dict = NSDictionary.dictionaryWithObjectsAndKeys(
NSString.stringWithString("Value"), NSString.stringWithString("Key")
);
ID id = dict.objectForKey((ID) null);
assertNull(id);
NSObject nsObject = dict.objectForKey((NSObject) null);
assertNull(nsObject);
}
@Test
public void testReturnValues() {
NSDictionary dict = NSDictionary.dictionaryWithObjectsAndKeys(
NSString.stringWithString("Value"), NSString.stringWithString("Key")
);
ID id = dict.objectForKey(NSString.stringWithString("Key").id());
assertNotNull(id);
NSObject nsObject = dict.objectForKey(NSString.stringWithString("Key"));
assertNotNull(nsObject);
}
}