PageRenderTime 26ms CodeModel.GetById 13ms app.highlight 10ms RepoModel.GetById 1ms app.codeStats 0ms

/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 */
 28package edu.vub.at.objects.natives;
 29
 30import edu.vub.at.AmbientTalkTest;
 31import edu.vub.at.AmbientTalkTestCase;
 32import edu.vub.at.eval.Evaluator;
 33import edu.vub.at.exceptions.InterpreterException;
 34import edu.vub.at.exceptions.XSelectorNotFound;
 35import edu.vub.at.objects.ATObject;
 36import edu.vub.at.objects.coercion.NativeTypeTags;
 37import edu.vub.at.objects.natives.grammar.AGSymbol;
 38import edu.vub.at.objects.symbiosis.JavaClass;
 39
 40/**
 41 * This test documents and tests the behaviour of the exception handling primitives 
 42 * provided in Ambienttalk. In AmbientTalk any object can be used and thrown as an 
 43 * exception. Moreover, by relying on in types, all subtyping issues regarding to
 44 * handler selection are handled by the isTaggedAs meta operation.
 45 *
 46 * @author smostinc
 47 */
 48public class ExceptionHandlingTest extends AmbientTalkTestCase {
 49	
 50	/**
 51	 * Any AmbientTalk Language value can be used as an exception, proving there is nothing 
 52	 * special about exceptions. This test demonstrates this for a number of language values,
 53	 * such as numbers, tables, closures and type tags themselves. 
 54	 * 
 55	 * This test also shows that objects can be caught using the type they are tagged with.
 56	 * Note that most often, exceptions will be isolates, as these are objects (which can be
 57	 * made arbitrarily complex) which are passed by copy between actors. However, as the 
 58	 * type tags of a far reference are identical to the one of the original object, this 
 59	 * semantics is a default upon which can be varied.
 60	 */
 61	public void notestAllObjectsCanBeUsedAsExceptions() {
 62		try {
 63			evaluateInput(
 64					"def testCount := 0; \n" +
 65					"raise: 42 catch: Number do: { | exc | testCount := testCount + 1 }; \n" +
 66					"raise: [ 4, 8, 15, 16, 23, 42 ] catch: Table do: { | exc | testCount := testCount + 1 }; \n" +
 67					"raise: { testCount := testCount + 1 } catch: Closure do: { | exc | exc.apply([]) }; \n" +
 68					"raise: Number catch: TypeTag do: { | exc | testCount := testCount + 1 }; \n" +
 69					"if: testCount != 4 then: { fail() }", ctx_);
 70		} catch (InterpreterException e) {
 71			e.printStackTrace();
 72			fail("exception: "+ e);
 73		}
 74	};
 75	
 76	/**
 77	 * Handler selection in AmbientTalk is purely based on the types an object is tagged with.
 78	 * As such the correct handler selection can be delegated to the type system which ensures
 79	 * correct handler selection.
 80	 */
 81	public void testTypeBasedHandlerSelection() {
 82		try {
 83			evaluateInput(
 84					"deftype MyExceptions; \n" +
 85					"deftype IncorrectArguments <: MyExceptions; \n" +
 86					"def testCount := 0; \n" +
 87					"try: { \n" +
 88					"  raise: (object: { def [ message, stackTrace ] := [ nil, nil ] } taggedAs: [ IncorrectArguments ]) catch: IncorrectArguments do: { | exc | testCount := testCount + 1 }; \n" +
 89					"  raise: (object: { def [ message, stackTrace ] := [ nil, nil ] } taggedAs: [ IncorrectArguments ]) catch: MyExceptions do: { | exc | testCount := testCount + 1 }; \n" +
 90					"  raise: (object: { def [ message, stackTrace ] := [ nil, nil ] } taggedAs: [ MyExceptions ]) catch: MyExceptions do: { | exc | testCount := testCount + 1 }; \n" +
 91					"  raise: (object: { def [ message, stackTrace ] := [ nil, nil ] } taggedAs: [ MyExceptions ]) catch: IncorrectArguments do: { | exc | testCount := testCount + 1 }; \n" +
 92					"} catch: MyExceptions using: { | exc | \n" +
 93					// the last test will result in an uncaught exception, but all previous ones should have been handled.
 94					"  if: testCount != 3 then: { fail() } \n" +
 95					"}", ctx_);
 96		} catch (InterpreterException e) {
 97			e.printStackTrace();
 98			fail("exception: "+ e);
 99		}
100		
101	}
102	
103	/**
104	 * The exceptions thrown by the interpreter can be intercepted by a program as they are also
105	 * typed objects, typed to identify their function. This test illustrates how to use this 
106	 * mechanism to build a python-like object model where non-existant field are silently added
107	 * to the object upon use.
108	 * 
109	 * Note that an altogether cleaner mechanism can be conceived by using the doesNotUnderstand 
110	 * meta hook to achieve similar behaviour.
111	 */
112	public void testInterpreterExceptionHandling() {
113		try {
114			evaluateInput(
115					"def defaultValue := 42;" +
116					"def pythonObjectMirror := \n" +
117					"  mirror: { \n" +
118					"    def invokeField(receiver, symbol) {" +
119					"      self.invoke(receiver,symbol,[])" +
120					"    };" +
121					"    def invoke( receiver, symbol, args ) { \n" +
122					"      try: { \n" +
123					"        super^invoke( receiver, symbol, args ); \n" +
124					"      } catch: SelectorNotFound using: { | e | \n" +
125					"        super^defineField( symbol, defaultValue ); \n" +
126					"        defaultValue; \n" +
127					"      } \n" +
128					"    } \n" +
129					"  }; \n" +
130					"def test := object: { nil } \n" +
131					"  mirroredBy: pythonObjectMirror; \n" +
132					"if: (test.x != defaultValue) then: { fail(); };",
133					ctx_);			
134		} catch (InterpreterException e) {
135			e.printStackTrace();
136			fail("exception: "+ e);
137		}
138	}
139	
140	/**
141	 * To avoid improper interference with the interpreter, user code should never throw  
142	 * interpreter exceptions. However, in the light that various components of the language 
143	 * may be reimplemented in the language itself, this functionality is supported by the 
144	 * interpreter anyhow.
145	 * 
146	 * Note that given the ability to catch interpreter exceptions, the programmer automatically
147	 * has the right to throw them as well, either by rethrowing them, or by storing it as a 
148	 * prototype, of which new clones can be instatiated whenever he feels like it.
149	 * 
150	 * This test consist of an object model where access to a field can be forbidden by throwing
151	 * an interpreter exception (tagged with SelectorNotFound)
152	 */
153	public void testInterpreterExceptionThrowing() {
154		try {
155			AmbientTalkTest.evalSnippet(ExceptionHandlingTest.class, "snippet1", ctx_);
156			// fail if no exception was thrown by the code. 
157			fail();
158		} catch (XSelectorNotFound e) {
159			// 1. Raising a Java Exception Successfull
160		} catch (InterpreterException e) {
161			e.printStackTrace();
162			fail("exception: "+ e);
163		}
164	}
165	
166	/**
167	 * When rethrowing an exception from a handler, the expected semantics apply : no handlers
168	 * from the same try block are tried, even if they also match the thrown exception. Handlers
169	 * from a try block higher up the stack can however apply.
170	 *
171	 */
172	public void testRethrownExceptions() {
173		try {
174			evaluateInput(
175					"deftype MyExceptions; \n" +
176					"deftype IncorrectArguments <: MyExceptions; \n" +
177					"\n" +
178					"def result := false;" +
179					"def test := object: { \n" +
180					"    def [ message, stackTrace ] := [ nil, nil ]; \n" +
181					"    def test := 0; \n" +
182					"} taggedAs: [ IncorrectArguments ]; \n" +
183					"\n" +
184					"try: { \n" +
185					"  try: { \n" +
186					"    raise: test; \n" +
187					"  } catch: MyExceptions using: { | exc | \n" +
188					"      result := true; \n" +
189					"      raise: exc; \n" +
190					"  } catch: IncorrectArguments using: { | exc |" +
191					"      fail();" +
192					"  }" +
193					"} catch: SelectorNotFound using: { | exc | \n" +
194					"  fail(); \n" +
195					"} catch: IncorrectArguments using: { | exc | \n" +
196					"  result := result.and: { true }; \n" +
197					"}; \n" +
198					"\n" +
199					"if: (! result) then: { fail(); }",					
200					ctx_);
201		} catch (InterpreterException e) {
202			e.printStackTrace();
203			fail("exception: "+ e);
204		}		
205	}
206	
207	public static void main(String[] args) {
208		junit.swingui.TestRunner.run(ExceptionHandlingTest.class);
209	}
210		
211	// For testing purposes we need access to a set of native type tags
212	// These are introduced into the global lexical scope of the test 
213	private void setUpTestTypes(ATObject testScope) throws Exception {
214		
215		// Primitive type tags used to test all objects can be thrown
216		testScope.meta_defineField(
217				AGSymbol.jAlloc("Number"),
218				NativeTypeTags._NUMBER_);
219
220		testScope.meta_defineField(
221				AGSymbol.jAlloc("Table"),
222				NativeTypeTags._TABLE_);
223
224		testScope.meta_defineField(
225				AGSymbol.jAlloc("Closure"),
226				NativeTypeTags._CLOSURE_);
227
228		testScope.meta_defineField(
229				AGSymbol.jAlloc("TypeTag"),
230				NativeTypeTags._TYPETAG_);
231		
232		testScope.meta_defineField(
233				AGSymbol.jAlloc("SelectorNotFound"),
234				NativeTypeTags._SELECTORNOTFOUND_);
235	}
236	
237	public void setUp() throws Exception {
238		ATObject globalLexScope = Evaluator.getGlobalLexicalScope();
239		ATObject testScope = new NATCallframe(globalLexScope);
240				
241		setUpTestTypes(testScope);
242
243		// For throwing InterpreterExceptions, we provide a useful prototype to start from
244		testScope.meta_defineField(
245				AGSymbol.jAlloc("doesNotUnderstandX"),
246				JavaClass.wrapperFor(XSelectorNotFound.class));
247		
248		ctx_ = new NATContext(testScope, globalLexScope);
249
250		// Aux method to aid in shortening the test code
251		evaluateInput(
252				"def raise: exception catch: typetag do: closure { \n" +
253				"  try: {" +
254				"    raise: exception;" +
255				"  } catch: typetag using: closure; \n" +
256				"}",
257				ctx_);
258	}
259	
260	
261	
262
263}