PageRenderTime 47ms CodeModel.GetById 38ms app.highlight 6ms RepoModel.GetById 1ms app.codeStats 0ms

/interpreter/tags/at2dist030708/test/edu/vub/at/objects/symbiosis/CoercionTest.java

http://ambienttalk.googlecode.com/
Java | 118 lines | 62 code | 15 blank | 41 comment | 2 complexity | a7972f4b9a7414f7afaaaccf0e9694ac MD5 | raw file
  1/**
  2 * 
  3 */
  4package edu.vub.at.objects.symbiosis;
  5
  6import edu.vub.at.AmbientTalkTest;
  7import edu.vub.at.eval.Evaluator;
  8import edu.vub.at.exceptions.InterpreterException;
  9import edu.vub.at.objects.ATObject;
 10import edu.vub.at.objects.ATTable;
 11import edu.vub.at.objects.base.BaseClosure;
 12import edu.vub.at.objects.coercion.Coercer;
 13import edu.vub.at.objects.natives.NATNumber;
 14import edu.vub.at.objects.natives.NATObject;
 15import edu.vub.at.objects.natives.NATTable;
 16import edu.vub.at.objects.natives.grammar.AGSymbol;
 17
 18/**
 19 * Tests the coercion of both objects and native data types to an interface. The use of coercion is required not
 20 * only to absorb AmbientTalk objects and use them instead of native types (i.e. passing an object with at and 
 21 * atPut methods where a table is expected) but is also used to ensure the proper use of AmbientTalk objects 
 22 * which are passed outside their enclosing actor and handed to another Java thread.
 23 * 
 24 * @author smostinc
 25 */
 26public class CoercionTest extends AmbientTalkTest {
 27
 28	public static void main(String[] args) {
 29		junit.swingui.TestRunner.run(CoercionTest.class);
 30	}
 31	
 32	/** 
 33	 * Tests the coercion of an AmbientTalk object which is to be used as a native table type.
 34	 */
 35	public void testTypeCoercion() throws InterpreterException {
 36		ATObject cubbyhole = evalAndReturn(
 37				"def cubbyhole := object: { \n" +
 38				"  def content := nil; \n" +
 39				"  def at(i) { \n" +
 40				"    if: (i = 1) then: { content } else: { `error }; \n" +
 41				"  }; \n" +
 42				"  def atPut(i, val) { \n" +
 43				"    if: (i = 1) then: { content := val } else: { `error }; \n" +
 44				"  }; \n" +
 45				"} \n");
 46		
 47		// under normal circumstances the cubbyhole object would be implicitly coerced to a table once it is
 48		// passed to a function which expects a table as an argument. Here we explicitly coerce by performing 
 49		// such an invocation at the Java level.
 50		
 51		ATTable coercedCubbyhole = (ATTable)Coercer.coerce(cubbyhole, ATTable.class);
 52		ATObject result = coercedCubbyhole.base_at(NATNumber.ONE);
 53		
 54		assertEquals(Evaluator.getNil(), result);
 55	}
 56
 57	/**
 58	 * Tests the coercion of an AmbientTalk object onto a classical Java Interface for symbiotic use.
 59	 * Such coercions typically happen when passing an AmbientTalk object to a Java method which expects 
 60	 * a given interface. At that point in time the passed AmbientTalk object will be implictly coerced 
 61	 * to the requested type. 
 62	 */
 63	public void testSymbioticCoercion() throws InterpreterException {
 64		ATObject listener = evalAndReturn(
 65			"def result := `error;" +
 66			"def listener := object: { \n" +
 67			"  def run() { result := `ok; }; \n" +
 68			"}; \n");
 69				
 70		Runnable coercedListener = (Runnable)Coercer.coerce(listener, Runnable.class);
 71		coercedListener.run();
 72		
 73		ATObject result = evalAndReturn("result");
 74		assertEquals(AGSymbol.jAlloc("ok"), result);
 75	}
 76	
 77	/**
 78	 * Tests the coercion of an AmbientTalk native type onto a Java Interface corresponding to its base-level 
 79	 * interface for symbiotic use. The reason to support this is that coercion ensures that invoking a method
 80	 * respects the event loop concurrency properties of AmbientTalk actors. 
 81	 * <p>
 82	 * Hence, the difference between <closure:lambda>.base_apply([]) and <coercer on:<closure:lambda> >.apply([])
 83	 * is that is the latter is called from a separate Java thread, it will schedule a message in the owning
 84	 * actor's queue whereas the latter would proceed and thus activate a second thread within the boundaries
 85	 * of a single actor.
 86	 */
 87	public void testSymbioticNativeCoercion() throws InterpreterException {
 88		ATObject lambda = evalAndReturn(
 89			"def result := `error;" +
 90			"def lambda := { result := `ok; }; \n");
 91		
 92		
 93		BaseClosure coercedListener = (BaseClosure)Coercer.coerce(lambda, BaseClosure.class);
 94		coercedListener.apply(NATTable.EMPTY);
 95		
 96		ATObject result = evalAndReturn("result");
 97		assertEquals(AGSymbol.jAlloc("ok"), result);
 98	}
 99	
100	/**
101	 * Tests whether a coercer is AT-equals and Java-equals to its original
102	 * unwrapped AmbientTalk object.
103	 */
104	public void testEqualityOnCoercers() throws InterpreterException {
105		ATObject unwrapped = new NATObject();
106		ATObject coercedObject = (ATObject) Coercer.coerce(unwrapped, Runnable.class);
107		// they should not be the same Java object
108		assertFalse(unwrapped == coercedObject);
109		// they should be Java-equals
110		assertTrue(unwrapped.equals(coercedObject));
111		assertTrue(coercedObject.equals(unwrapped));
112		// they should be AmbientTalk-equals
113		assertTrue(unwrapped.base__opeql__opeql_(coercedObject).asNativeBoolean().javaValue);
114		assertTrue(coercedObject.base__opeql__opeql_(unwrapped).asNativeBoolean().javaValue);
115		// their hashcodes should be equal as well
116		assertTrue(unwrapped.hashCode() == coercedObject.hashCode());
117	}
118}