/interpreter/tags/at2-build270707/test/edu/vub/at/objects/natives/ExceptionHandlingTest.java

http://ambienttalk.googlecode.com/ · Java · 263 lines · 152 code · 24 blank · 87 comment · 0 complexity · 63dee691cc07acffb71c90c5f22893ae MD5 · raw file

  1. /**
  2. * AmbientTalk/2 Project
  3. * ExceptionHandlingTest.java created on Oct 10, 2006 at 10:34:10 PM
  4. * (c) Programming Technology Lab, 2006 - 2007
  5. * Authors: Tom Van Cutsem & Stijn Mostinckx
  6. *
  7. * Permission is hereby granted, free of charge, to any person
  8. * obtaining a copy of this software and associated documentation
  9. * files (the "Software"), to deal in the Software without
  10. * restriction, including without limitation the rights to use,
  11. * copy, modify, merge, publish, distribute, sublicense, and/or
  12. * sell copies of the Software, and to permit persons to whom the
  13. * Software is furnished to do so, subject to the following
  14. * conditions:
  15. *
  16. * The above copyright notice and this permission notice shall be
  17. * included in all copies or substantial portions of the Software.
  18. *
  19. * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
  20. * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
  21. * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
  22. * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
  23. * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
  24. * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
  25. * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
  26. * OTHER DEALINGS IN THE SOFTWARE.
  27. */
  28. package edu.vub.at.objects.natives;
  29. import edu.vub.at.AmbientTalkTest;
  30. import edu.vub.at.AmbientTalkTestCase;
  31. import edu.vub.at.eval.Evaluator;
  32. import edu.vub.at.exceptions.InterpreterException;
  33. import edu.vub.at.exceptions.XSelectorNotFound;
  34. import edu.vub.at.objects.ATObject;
  35. import edu.vub.at.objects.coercion.NativeTypeTags;
  36. import edu.vub.at.objects.natives.grammar.AGSymbol;
  37. import edu.vub.at.objects.symbiosis.JavaClass;
  38. /**
  39. * This test documents and tests the behaviour of the exception handling primitives
  40. * provided in Ambienttalk. In AmbientTalk any object can be used and thrown as an
  41. * exception. Moreover, by relying on in types, all subtyping issues regarding to
  42. * handler selection are handled by the isTaggedAs meta operation.
  43. *
  44. * @author smostinc
  45. */
  46. public class ExceptionHandlingTest extends AmbientTalkTestCase {
  47. /**
  48. * Any AmbientTalk Language value can be used as an exception, proving there is nothing
  49. * special about exceptions. This test demonstrates this for a number of language values,
  50. * such as numbers, tables, closures and type tags themselves.
  51. *
  52. * This test also shows that objects can be caught using the type they are tagged with.
  53. * Note that most often, exceptions will be isolates, as these are objects (which can be
  54. * made arbitrarily complex) which are passed by copy between actors. However, as the
  55. * type tags of a far reference are identical to the one of the original object, this
  56. * semantics is a default upon which can be varied.
  57. */
  58. public void notestAllObjectsCanBeUsedAsExceptions() {
  59. try {
  60. evaluateInput(
  61. "def testCount := 0; \n" +
  62. "raise: 42 catch: Number do: { | exc | testCount := testCount + 1 }; \n" +
  63. "raise: [ 4, 8, 15, 16, 23, 42 ] catch: Table do: { | exc | testCount := testCount + 1 }; \n" +
  64. "raise: { testCount := testCount + 1 } catch: Closure do: { | exc | exc.apply([]) }; \n" +
  65. "raise: Number catch: TypeTag do: { | exc | testCount := testCount + 1 }; \n" +
  66. "if: testCount != 4 then: { fail() }", ctx_);
  67. } catch (InterpreterException e) {
  68. e.printStackTrace();
  69. fail("exception: "+ e);
  70. }
  71. };
  72. /**
  73. * Handler selection in AmbientTalk is purely based on the types an object is tagged with.
  74. * As such the correct handler selection can be delegated to the type system which ensures
  75. * correct handler selection.
  76. */
  77. public void testTypeBasedHandlerSelection() {
  78. try {
  79. evaluateInput(
  80. "deftype MyExceptions; \n" +
  81. "deftype IncorrectArguments <: MyExceptions; \n" +
  82. "def testCount := 0; \n" +
  83. "try: { \n" +
  84. " raise: (object: { def [ message, stackTrace ] := [ nil, nil ] } taggedAs: [ IncorrectArguments ]) catch: IncorrectArguments do: { | exc | testCount := testCount + 1 }; \n" +
  85. " raise: (object: { def [ message, stackTrace ] := [ nil, nil ] } taggedAs: [ IncorrectArguments ]) catch: MyExceptions do: { | exc | testCount := testCount + 1 }; \n" +
  86. " raise: (object: { def [ message, stackTrace ] := [ nil, nil ] } taggedAs: [ MyExceptions ]) catch: MyExceptions do: { | exc | testCount := testCount + 1 }; \n" +
  87. " raise: (object: { def [ message, stackTrace ] := [ nil, nil ] } taggedAs: [ MyExceptions ]) catch: IncorrectArguments do: { | exc | testCount := testCount + 1 }; \n" +
  88. "} catch: MyExceptions using: { | exc | \n" +
  89. // the last test will result in an uncaught exception, but all previous ones should have been handled.
  90. " if: testCount != 3 then: { fail() } \n" +
  91. "}", ctx_);
  92. } catch (InterpreterException e) {
  93. e.printStackTrace();
  94. fail("exception: "+ e);
  95. }
  96. }
  97. /**
  98. * The exceptions thrown by the interpreter can be intercepted by a program as they are also
  99. * typed objects, typed to identify their function. This test illustrates how to use this
  100. * mechanism to build a python-like object model where non-existant field are silently added
  101. * to the object upon use.
  102. *
  103. * Note that an altogether cleaner mechanism can be conceived by using the doesNotUnderstand
  104. * meta hook to achieve similar behaviour.
  105. */
  106. public void testInterpreterExceptionHandling() {
  107. try {
  108. evaluateInput(
  109. "def defaultValue := 42;" +
  110. "def pythonObjectMirror := \n" +
  111. " mirror: { \n" +
  112. " def invokeField(receiver, symbol) {" +
  113. " self.invoke(receiver,symbol,[])" +
  114. " };" +
  115. " def invoke( receiver, symbol, args ) { \n" +
  116. " try: { \n" +
  117. " super^invoke( receiver, symbol, args ); \n" +
  118. " } catch: SelectorNotFound using: { | e | \n" +
  119. " super^defineField( symbol, defaultValue ); \n" +
  120. " defaultValue; \n" +
  121. " } \n" +
  122. " } \n" +
  123. " }; \n" +
  124. "def test := object: { nil } \n" +
  125. " mirroredBy: pythonObjectMirror; \n" +
  126. "if: (test.x != defaultValue) then: { fail(); };",
  127. ctx_);
  128. } catch (InterpreterException e) {
  129. e.printStackTrace();
  130. fail("exception: "+ e);
  131. }
  132. }
  133. /**
  134. * To avoid improper interference with the interpreter, user code should never throw
  135. * interpreter exceptions. However, in the light that various components of the language
  136. * may be reimplemented in the language itself, this functionality is supported by the
  137. * interpreter anyhow.
  138. *
  139. * Note that given the ability to catch interpreter exceptions, the programmer automatically
  140. * has the right to throw them as well, either by rethrowing them, or by storing it as a
  141. * prototype, of which new clones can be instatiated whenever he feels like it.
  142. *
  143. * This test consist of an object model where access to a field can be forbidden by throwing
  144. * an interpreter exception (tagged with SelectorNotFound)
  145. */
  146. public void testInterpreterExceptionThrowing() {
  147. try {
  148. AmbientTalkTest.evalSnippet(ExceptionHandlingTest.class, "snippet1", ctx_);
  149. // fail if no exception was thrown by the code.
  150. fail();
  151. } catch (XSelectorNotFound e) {
  152. // 1. Raising a Java Exception Successfull
  153. } catch (InterpreterException e) {
  154. e.printStackTrace();
  155. fail("exception: "+ e);
  156. }
  157. }
  158. /**
  159. * When rethrowing an exception from a handler, the expected semantics apply : no handlers
  160. * from the same try block are tried, even if they also match the thrown exception. Handlers
  161. * from a try block higher up the stack can however apply.
  162. *
  163. */
  164. public void testRethrownExceptions() {
  165. try {
  166. evaluateInput(
  167. "deftype MyExceptions; \n" +
  168. "deftype IncorrectArguments <: MyExceptions; \n" +
  169. "\n" +
  170. "def result := false;" +
  171. "def test := object: { \n" +
  172. " def [ message, stackTrace ] := [ nil, nil ]; \n" +
  173. " def test := 0; \n" +
  174. "} taggedAs: [ IncorrectArguments ]; \n" +
  175. "\n" +
  176. "try: { \n" +
  177. " try: { \n" +
  178. " raise: test; \n" +
  179. " } catch: MyExceptions using: { | exc | \n" +
  180. " result := true; \n" +
  181. " raise: exc; \n" +
  182. " } catch: IncorrectArguments using: { | exc |" +
  183. " fail();" +
  184. " }" +
  185. "} catch: SelectorNotFound using: { | exc | \n" +
  186. " fail(); \n" +
  187. "} catch: IncorrectArguments using: { | exc | \n" +
  188. " result := result.and: { true }; \n" +
  189. "}; \n" +
  190. "\n" +
  191. "if: (! result) then: { fail(); }",
  192. ctx_);
  193. } catch (InterpreterException e) {
  194. e.printStackTrace();
  195. fail("exception: "+ e);
  196. }
  197. }
  198. public static void main(String[] args) {
  199. junit.swingui.TestRunner.run(ExceptionHandlingTest.class);
  200. }
  201. // For testing purposes we need access to a set of native type tags
  202. // These are introduced into the global lexical scope of the test
  203. private void setUpTestTypes(ATObject testScope) throws Exception {
  204. // Primitive type tags used to test all objects can be thrown
  205. testScope.meta_defineField(
  206. AGSymbol.jAlloc("Number"),
  207. NativeTypeTags._NUMBER_);
  208. testScope.meta_defineField(
  209. AGSymbol.jAlloc("Table"),
  210. NativeTypeTags._TABLE_);
  211. testScope.meta_defineField(
  212. AGSymbol.jAlloc("Closure"),
  213. NativeTypeTags._CLOSURE_);
  214. testScope.meta_defineField(
  215. AGSymbol.jAlloc("TypeTag"),
  216. NativeTypeTags._TYPETAG_);
  217. testScope.meta_defineField(
  218. AGSymbol.jAlloc("SelectorNotFound"),
  219. NativeTypeTags._SELECTORNOTFOUND_);
  220. }
  221. public void setUp() throws Exception {
  222. ATObject globalLexScope = Evaluator.getGlobalLexicalScope();
  223. ATObject testScope = new NATCallframe(globalLexScope);
  224. setUpTestTypes(testScope);
  225. // For throwing InterpreterExceptions, we provide a useful prototype to start from
  226. testScope.meta_defineField(
  227. AGSymbol.jAlloc("doesNotUnderstandX"),
  228. JavaClass.wrapperFor(XSelectorNotFound.class));
  229. ctx_ = new NATContext(testScope, globalLexScope);
  230. // Aux method to aid in shortening the test code
  231. evaluateInput(
  232. "def raise: exception catch: typetag do: closure { \n" +
  233. " try: {" +
  234. " raise: exception;" +
  235. " } catch: typetag using: closure; \n" +
  236. "}",
  237. ctx_);
  238. }
  239. }