PageRenderTime 67ms CodeModel.GetById 46ms app.highlight 15ms RepoModel.GetById 1ms app.codeStats 1ms

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

http://ambienttalk.googlecode.com/
Java | 260 lines | 149 code | 24 blank | 87 comment | 0 complexity | b2ed3deaf441d76fe35e5b8360857667 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 select( receiver, symbol ) { \n" +
119					"      try: { \n" +
120					"        super^select( receiver, symbol ); \n" +
121					"      } catch: SelectorNotFound using: { | e | \n" +
122					"        super^defineField( symbol, defaultValue ); \n" +
123					"        defaultValue; \n" +
124					"      } \n" +
125					"    } \n" +
126					"  }; \n" +
127					"def test := object: { nil } \n" +
128					"  mirroredBy: pythonObjectMirror; \n" +
129					"if: (test.x != defaultValue) then: { fail(); };",
130					ctx_);			
131		} catch (InterpreterException e) {
132			e.printStackTrace();
133			fail("exception: "+ e);
134		}
135	}
136	
137	/**
138	 * To avoid improper interference with the interpreter, user code should never throw  
139	 * interpreter exceptions. However, in the light that various components of the language 
140	 * may be reimplemented in the language itself, this functionality is supported by the 
141	 * interpreter anyhow.
142	 * 
143	 * Note that given the ability to catch interpreter exceptions, the programmer automatically
144	 * has the right to throw them as well, either by rethrowing them, or by storing it as a 
145	 * prototype, of which new clones can be instatiated whenever he feels like it.
146	 * 
147	 * This test consist of an object model where access to a field can be forbidden by throwing
148	 * an interpreter exception (tagged with SelectorNotFound)
149	 */
150	public void testInterpreterExceptionThrowing() {
151		try {
152			AmbientTalkTest.evalSnippet(ExceptionHandlingTest.class, "snippet1", ctx_);
153			// fail if no exception was thrown by the code. 
154			fail();
155		} catch (XSelectorNotFound e) {
156			// 1. Raising a Java Exception Successfull
157		} catch (InterpreterException e) {
158			e.printStackTrace();
159			fail("exception: "+ e);
160		}
161	}
162	
163	/**
164	 * When rethrowing an exception from a handler, the expected semantics apply : no handlers
165	 * from the same try block are tried, even if they also match the thrown exception. Handlers
166	 * from a try block higher up the stack can however apply.
167	 *
168	 */
169	public void testRethrownExceptions() {
170		try {
171			evaluateInput(
172					"deftype MyExceptions; \n" +
173					"deftype IncorrectArguments <: MyExceptions; \n" +
174					"\n" +
175					"def result := false;" +
176					"def test := object: { \n" +
177					"    def [ message, stackTrace ] := [ nil, nil ]; \n" +
178					"    def test := 0; \n" +
179					"} taggedAs: [ IncorrectArguments ]; \n" +
180					"\n" +
181					"try: { \n" +
182					"  try: { \n" +
183					"    raise: test; \n" +
184					"  } catch: MyExceptions using: { | exc | \n" +
185					"      result := true; \n" +
186					"      raise: exc; \n" +
187					"  } catch: IncorrectArguments using: { | exc |" +
188					"      fail();" +
189					"  }" +
190					"} catch: SelectorNotFound using: { | exc | \n" +
191					"  fail(); \n" +
192					"} catch: IncorrectArguments using: { | exc | \n" +
193					"  result := result.and: { true }; \n" +
194					"}; \n" +
195					"\n" +
196					"if: (! result) then: { fail(); }",					
197					ctx_);
198		} catch (InterpreterException e) {
199			e.printStackTrace();
200			fail("exception: "+ e);
201		}		
202	}
203	
204	public static void main(String[] args) {
205		junit.swingui.TestRunner.run(ExceptionHandlingTest.class);
206	}
207		
208	// For testing purposes we need access to a set of native type tags
209	// These are introduced into the global lexical scope of the test 
210	private void setUpTestTypes(ATObject testScope) throws Exception {
211		
212		// Primitive type tags used to test all objects can be thrown
213		testScope.meta_defineField(
214				AGSymbol.jAlloc("Number"),
215				NativeTypeTags._NUMBER_);
216
217		testScope.meta_defineField(
218				AGSymbol.jAlloc("Table"),
219				NativeTypeTags._TABLE_);
220
221		testScope.meta_defineField(
222				AGSymbol.jAlloc("Closure"),
223				NativeTypeTags._CLOSURE_);
224
225		testScope.meta_defineField(
226				AGSymbol.jAlloc("TypeTag"),
227				NativeTypeTags._TYPETAG_);
228		
229		testScope.meta_defineField(
230				AGSymbol.jAlloc("SelectorNotFound"),
231				NativeTypeTags._SELECTORNOTFOUND_);
232	}
233	
234	public void setUp() throws Exception {
235		ATObject globalLexScope = Evaluator.getGlobalLexicalScope();
236		ATObject testScope = new NATCallframe(globalLexScope);
237				
238		setUpTestTypes(testScope);
239
240		// For throwing InterpreterExceptions, we provide a useful prototype to start from
241		testScope.meta_defineField(
242				AGSymbol.jAlloc("doesNotUnderstandX"),
243				JavaClass.wrapperFor(XSelectorNotFound.class));
244		
245		ctx_ = new NATContext(testScope, globalLexScope);
246
247		// Aux method to aid in shortening the test code
248		evaluateInput(
249				"def raise: exception catch: typetag do: closure { \n" +
250				"  try: {" +
251				"    raise: exception;" +
252				"  } catch: typetag using: closure; \n" +
253				"}",
254				ctx_);
255	}
256	
257	
258	
259
260}