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

http://ambienttalk.googlecode.com/ · Java · 118 lines · 62 code · 15 blank · 41 comment · 2 complexity · 86315ea746549a8a3c2943c70eb6bc00 MD5 · raw file

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