/interpreter/tags/at_build150307/test/edu/vub/at/objects/symbiosis/SymbiosisTest.java
Java | 821 lines | 479 code | 76 blank | 266 comment | 4 complexity | 678fca8132687e55bc50eb6bea25b99a MD5 | raw file
1/** 2 * AmbientTalk/2 Project 3 * SymbiosisTest.java created on 13-nov-2006 at 15:10:58 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.symbiosis; 29 30import edu.vub.at.AmbientTalkTest; 31import edu.vub.at.eval.Evaluator; 32import edu.vub.at.exceptions.InterpreterException; 33import edu.vub.at.exceptions.XArityMismatch; 34import edu.vub.at.exceptions.XClassNotFound; 35import edu.vub.at.exceptions.XDuplicateSlot; 36import edu.vub.at.exceptions.XIllegalOperation; 37import edu.vub.at.exceptions.XNotInstantiatable; 38import edu.vub.at.exceptions.XSelectorNotFound; 39import edu.vub.at.exceptions.XSymbiosisFailure; 40import edu.vub.at.exceptions.XTypeMismatch; 41import edu.vub.at.exceptions.XUnassignableField; 42import edu.vub.at.objects.ATClosure; 43import edu.vub.at.objects.ATField; 44import edu.vub.at.objects.ATMethod; 45import edu.vub.at.objects.ATObject; 46import edu.vub.at.objects.ATStripe; 47import edu.vub.at.objects.natives.NATContext; 48import edu.vub.at.objects.natives.NATException; 49import edu.vub.at.objects.natives.NATFraction; 50import edu.vub.at.objects.natives.NATNil; 51import edu.vub.at.objects.natives.NATNumber; 52import edu.vub.at.objects.natives.NATObject; 53import edu.vub.at.objects.natives.NATTable; 54import edu.vub.at.objects.natives.NATText; 55import edu.vub.at.objects.natives.grammar.AGSymbol; 56import edu.vub.at.objects.natives.grammar.TestEval; 57 58import java.io.Serializable; 59import java.util.Collection; 60import java.util.List; 61import java.util.Set; 62import java.util.Vector; 63 64/** 65 * Tests the symbiosis with Java. This is primarily done by wrapping 66 * the SymbiosisTest class and instances itself and invoking some of 67 * their non-test prefixed methods. 68 * 69 * @author tvcutsem 70 */ 71public class SymbiosisTest extends AmbientTalkTest { 72 73 public static void main(String[] args) { 74 junit.swingui.TestRunner.run(TestEval.class); 75 /*Test test= new SymbiosisTest() { 76 public void runTest() throws Exception { 77 testBugfixOverloadedConstructor(); 78 } 79 }; 80 junit.textui.TestRunner.run(test);*/ 81 } 82 83 // test fixture 84 private Class jTestClass; 85 private JavaClass atTestClass; 86 87 private SymbiosisTest jTestObject; 88 private JavaObject atTestObject; 89 90 private JavaPackage jLobby_; 91 92 // these fields and methods will be reflectively invoked from within AmbientTalk 93 public int xtest; 94 public static String ytest = "AmbientTalk"; 95 96 public SymbiosisTest(int xval) { 97 xtest = xval; 98 } 99 100 public SymbiosisTest() { 101 xtest = 0; 102 } 103 104 public SymbiosisTest(SymbiosisTest t) { 105 xtest = -1; 106 } 107 108 public SymbiosisTest(AmbientTalkTest t) { 109 xtest = -1; 110 } 111 112 private static class ExceptionTest extends Exception { 113 private static final long serialVersionUID = 1L; 114 } 115 116 public SymbiosisTest(JavaClass c) throws ExceptionTest { 117 throw new ExceptionTest(); 118 } 119 120 public static final int TEST_OBJECT_INIT = 42; 121 122 public int gettertest() { return xtest; } 123 public void settertest(int xval) { xtest = xval; } 124 public static String prefix(String msg) { return msg + ytest; } 125 public boolean identitytest(Object obj) { return obj == this; } 126 127 public String overloadedtest() { return "()"; } 128 public String overloadedtest(int x) { return "(int)"; } 129 public String overloadedtest(Object[] vals) { return "(Object[])"; } 130 public String overloadedtest(double x) { return "(double)"; } 131 public String overloadedtest(SymbiosisTest x) { return "(SymbiosisTest)"; } 132 133 public Object overloadedvararg(ATObject[] varargs) { return null; } 134 public int overloadedvararg(int x) { return x; } 135 136 public String overloadedmatch2(Object x) { return "(Object)"; } 137 public String overloadedmatch2(SymbiosisTest x) { return "(SymbiosisTest)"; } 138 139 public void setUp() { 140 jTestClass = SymbiosisTest.class; 141 atTestClass = JavaClass.wrapperFor(SymbiosisTest.class); 142 143 jTestObject = new SymbiosisTest(TEST_OBJECT_INIT); 144 atTestObject = JavaObject.wrapperFor(jTestObject); 145 146 jLobby_ = new JavaPackage(""); 147 } 148 149 /** 150 * Test the conversion function Symbiosis.ambientTalkToJava for various kinds of input. 151 */ 152 public void testAT2JavaConversion() { 153 try { 154 // -- WRAPPED JAVA OBJECTS -- 155 assertEquals(jTestObject, Symbiosis.ambientTalkToJava(atTestObject, SymbiosisTest.class)); 156 // -- PRIMITIVE TYPES -- 157 assertEquals(new Integer(5), Symbiosis.ambientTalkToJava(NATNumber.atValue(5), int.class)); 158 // -- STRINGS -- 159 assertEquals(ytest, Symbiosis.ambientTalkToJava(NATText.atValue(ytest), String.class)); 160 // -- ARRAYS -- 161 assertEquals(0.5, ((double[]) Symbiosis.ambientTalkToJava(NATTable.atValue(new ATObject[] { NATFraction.atValue(0.5) }), double[].class))[0], 0.0); 162 // -- EXCEPTIONS -- 163 assertEquals(XIllegalOperation.class, Symbiosis.ambientTalkToJava(new NATException(new XIllegalOperation()), Exception.class).getClass()); 164 // -- CLASS OBJECTS -- 165 assertEquals(jTestClass, Symbiosis.ambientTalkToJava(atTestClass, Class.class)); 166 // -- nil => NULL if converting to Java -- 167 assertEquals(null, Symbiosis.ambientTalkToJava(NATNil._INSTANCE_, Runnable.class)); 168 // -- nil => nil if remaining within AT -- 169 assertEquals(NATNil._INSTANCE_, Symbiosis.ambientTalkToJava(NATNil._INSTANCE_, ATObject.class)); 170 // beware with types such as java.lang.Object that match both Java and AT types! 171 // if the ATObject can be assigned to the Java type, the ATObject will be kept 172 assertEquals(NATNil._INSTANCE_, Symbiosis.ambientTalkToJava(NATNil._INSTANCE_, Object.class)); 173 // -- INTERFACE TYPES AND NAT CLASSES -- 174 assertTrue(Symbiosis.ambientTalkToJava(new NATObject(), Runnable.class) instanceof Runnable); 175 try { 176 Symbiosis.ambientTalkToJava(new NATObject(), Symbiosis.class); 177 fail(); 178 } catch (XTypeMismatch e) { 179 // expected: coercion does not work for non-interface class types 180 } 181 } catch (InterpreterException e) { 182 fail(e.getMessage()); 183 } 184 } 185 186 /** 187 * Test the conversion function Symbiosis.javaToAmbientTalk for various kinds of input. 188 */ 189 public void testJava2ATConversion() { 190 try { 191 // -- WRAPPED JAVA OBJECTS -- 192 assertEquals(atTestObject, Symbiosis.javaToAmbientTalk(jTestObject)); 193 // -- PRIMITIVE TYPES -- 194 assertEquals(NATNumber.atValue(5), Symbiosis.javaToAmbientTalk(new Integer(5))); 195 // -- STRINGS -- 196 assertEquals(NATText.atValue(ytest), Symbiosis.javaToAmbientTalk(ytest)); 197 // -- ARRAYS -- 198 assertEquals(NATFraction.atValue(0.5), Symbiosis.javaToAmbientTalk(new double[] { 0.5 }).asNativeTable().elements_[0]); 199 // -- EXCEPTIONS -- 200 assertEquals(XIllegalOperation.class, Symbiosis.javaToAmbientTalk(new XIllegalOperation()).asNativeException().getWrappedException().getClass()); 201 // -- CLASS OBJECTS -- 202 assertEquals(atTestClass, Symbiosis.javaToAmbientTalk(jTestClass)); 203 // -- nil => NULL -- 204 assertEquals(NATNil._INSTANCE_, Symbiosis.javaToAmbientTalk(null)); 205 // -- INTERFACE TYPES AND NAT CLASSES -- 206 ATObject orig = new NATObject(); 207 Object proxy = Symbiosis.ambientTalkToJava(orig, Runnable.class); 208 assertEquals(orig, Symbiosis.javaToAmbientTalk(proxy)); 209 } catch (InterpreterException e) { 210 fail(e.getMessage()); 211 } 212 } 213 214 /** 215 * Invokes the two instance methods gettertest and settertest on atTestObject. 216 * Also performs a selection of the field 'xtest' 217 * 218 * Also invokes the method 'identitytest' to see whether AT->Java conversion does proper unwrapping 219 */ 220 public void testWorkingInstanceInvocation() { 221 try { 222 // def result := atTestObject.gettertest(); assert(42 == result) 223 ATObject result = atTestObject.meta_invoke(atTestObject, AGSymbol.jAlloc("gettertest"), NATTable.EMPTY); 224 assertEquals(TEST_OBJECT_INIT, result.asNativeNumber().javaValue); 225 226 // result := atTestObject.settertest(1); assert(result == nil); assert(atTestObject.xtest == 1) 227 result = atTestObject.meta_invoke(atTestObject, AGSymbol.jAlloc("settertest"), NATTable.atValue(new ATObject[] { NATNumber.ONE })); 228 assertEquals(NATNil._INSTANCE_, result); 229 assertEquals(1, jTestObject.xtest); 230 // result := atTestObject.xtest 231 result = atTestObject.meta_select(atTestObject, AGSymbol.jAlloc("xtest")); 232 assertEquals(NATNumber.ONE, result); 233 234 // atTestObject.identitytest(atTestObject) == atTestObject 235 assertTrue(atTestObject.meta_invoke(atTestObject, AGSymbol.jAlloc("identitytest"), 236 NATTable.atValue(new ATObject[] { atTestObject })).asNativeBoolean().javaValue); 237 } catch (InterpreterException e) { 238 fail(e.getMessage()); 239 } 240 } 241 242 /** 243 * Invokes the class method 'prefix' and performs a selection and assignment of the static 'ytest' field 244 */ 245 public void testWorkingClassInvocation() { 246 try { 247 // def result := atTestClass.prefix("Hello, "); assert("Hello, " + ytest == result) 248 String txt = "Hello, "; 249 NATText prefix = NATText.atValue(txt); 250 ATObject result = atTestClass.meta_invoke(atTestClass, AGSymbol.jAlloc("prefix"), NATTable.atValue(new ATObject[] { prefix })); 251 assertEquals(txt + ytest, result.asNativeText().javaValue); 252 253 // result := atTestClass.ytest; assert(result == ytest); 254 result = atTestClass.meta_select(atTestClass, AGSymbol.jAlloc("ytest")); 255 assertEquals(ytest, result.asNativeText().javaValue); 256 257 // atTestClass.ytest := "Hello, "; assert(ytest == "Hello, ") 258 result = atTestClass.meta_assignField(atTestClass, AGSymbol.jAlloc("ytest"), prefix); 259 assertEquals(NATNil._INSTANCE_, result); 260 assertEquals(txt, ytest); 261 } catch (InterpreterException e) { 262 fail(e.getMessage()); 263 } 264 } 265 266 /** 267 * Invokes the method 'gettertest' with one argument instead of zero. 268 */ 269 public void testFaultyArity() { 270 try { 271 atTestObject.meta_invoke(atTestObject, AGSymbol.jAlloc("gettertest"), NATTable.atValue(new ATObject[] { NATNil._INSTANCE_ })); 272 fail("Expected an arity mismatch exception"); 273 } catch(XArityMismatch e) { 274 // expected exception: success 275 } catch(InterpreterException e) { 276 fail(e.getMessage()); 277 } 278 } 279 280 /** 281 * Invokes the method 'settertest' with a double (fraction) instead of an int (number) 282 */ 283 public void testIllegalArgs() { 284 try { 285 atTestObject.meta_invoke(atTestObject, AGSymbol.jAlloc("settertest"), NATTable.atValue(new ATObject[] { NATFraction.atValue(0.1) })); 286 fail("Expected an illegal argument exception"); 287 } catch(XTypeMismatch e) { 288 // Java expects an int, so AT expects a native number, but is given a native fraction 289 if (e.getExpectedType() == NATNumber.class) { 290 // expected exception: success 291 } else { 292 fail(e.getMessage()); 293 } 294 } catch(InterpreterException e) { 295 fail(e.getMessage()); 296 } 297 } 298 299 /** 300 * Tries to assign to a final public field 301 */ 302 public void testIllegalAssignment() { 303 try { 304 atTestClass.meta_assignField(atTestClass, AGSymbol.jAlloc("TEST_OBJECT_INIT"), NATNumber.atValue(0)); 305 fail("Expected an illegal assignment exception"); 306 } catch(XUnassignableField e) { 307 // expected exception: success 308 } catch(InterpreterException e) { 309 fail(e.getMessage()); 310 } 311 } 312 313 /** 314 * Test whether variable arguments work 315 */ 316 public void testVarArgInvocation() { 317 try { 318 ATObject result = atTestObject.meta_invoke(atTestObject, 319 AGSymbol.jAlloc("overloadedvararg"), 320 NATTable.atValue(new ATObject[] { NATNumber.ZERO, NATNumber.ONE })); 321 assertEquals(NATNil._INSTANCE_, result); 322 } catch (InterpreterException e) { 323 fail(e.getMessage()); 324 } 325 } 326 327 /** 328 * Tests whether overloaded methods can be properly invoked if they can be resolved 329 * to one method using the actual arguments. 330 */ 331 public void testOverloadedInvWithOneMatch() { 332 try { 333 // invokes overloadedtest(int) 334 ATObject result = atTestObject.meta_invoke(atTestObject, 335 AGSymbol.jAlloc("overloadedtest"), 336 NATTable.atValue(new ATObject[] { NATNumber.ZERO })); 337 assertEquals("(int)", result.asNativeText().javaValue); 338 // invokes overloadedtest(SymbiosisTest) 339 result = atTestObject.meta_invoke(atTestObject, 340 AGSymbol.jAlloc("overloadedtest"), 341 NATTable.atValue(new ATObject[] { atTestObject })); 342 assertEquals("(SymbiosisTest)", result.asNativeText().javaValue); 343 // invokes overloadedtest() 344 result = atTestObject.meta_invoke(atTestObject, 345 AGSymbol.jAlloc("overloadedtest"), 346 NATTable.EMPTY); 347 assertEquals("()", result.asNativeText().javaValue); 348 } catch (InterpreterException e) { 349 fail(e.getMessage()); 350 } 351 } 352 353 /** 354 * Invokes an overloaded method where the symbiosis cannot disambiguate automatically. 355 */ 356 public void testOverloadedInvWithMultipleMatches() { 357 try { 358 // invokes overloadedmatch2(Object|SymbiosisTest) => error 359 atTestObject.meta_invoke(atTestObject, AGSymbol.jAlloc("overloadedmatch2"), 360 NATTable.atValue(new ATObject[] { atTestObject })); 361 fail("Expected a symbiosis exception"); 362 } catch (XSymbiosisFailure e) { 363 // success: expected exception 364 } catch (InterpreterException e) { 365 fail(e.getMessage()); 366 } 367 } 368 369 /** 370 * Invokes an overloaded method that does not match the specified argument type 371 */ 372 public void testOverloadedInvWithNoMatch() { 373 try { 374 // invokes overloadedtest(NATObject) => error 375 atTestObject.meta_invoke(atTestObject, AGSymbol.jAlloc("overloadedtest"), 376 NATTable.atValue(new ATObject[] { new NATObject() })); 377 fail("Expected a symbiosis exception"); 378 } catch (XSymbiosisFailure e) { 379 // success: expected exception 380 } catch (InterpreterException e) { 381 fail(e.getMessage()); 382 } 383 } 384 385 /** 386 * Invokes a method that is not defined in the class. 387 */ 388 public void testNonExistentMethod() { 389 try { 390 // invokes foo(1) => error 391 atTestObject.meta_invoke(atTestObject, AGSymbol.jAlloc("foo"), 392 NATTable.atValue(new ATObject[] { NATNumber.ONE })); 393 fail("Expected a selector not found exception"); 394 } catch (XSelectorNotFound e) { 395 // success: expected exception 396 } catch (InterpreterException e) { 397 fail(e.getMessage()); 398 } 399 } 400 401 /** 402 * Tests first-class field access for both instances and classes 403 */ 404 public void testFirstClassFields() { 405 try { 406 // def result := (reflect: atTestObject).grabField("xtest") 407 ATField result = atTestObject.meta_grabField(AGSymbol.jAlloc("xtest")).asField(); 408 assertEquals("xtest", result.base_getName().toString()); 409 assertEquals(TEST_OBJECT_INIT, result.base_readField().asNativeNumber().javaValue); 410 411 // result := (reflect: atTestClass).grabField("ytest") 412 result = atTestClass.meta_grabField(AGSymbol.jAlloc("ytest")).asField(); 413 assertEquals("ytest", result.base_getName().toString()); 414 assertEquals(ytest, result.base_readField().asNativeText().javaValue); 415 } catch (InterpreterException e) { 416 fail(e.getMessage()); 417 } 418 } 419 420 /** 421 * Tests first-class method access for both instances and classes 422 */ 423 public void testFirstClassMethods() { 424 try { 425 // def result := (reflect: atTestObject).grabMethod("gettertest") 426 ATMethod result = atTestObject.meta_grabMethod(AGSymbol.jAlloc("gettertest")).asMethod(); 427 assertEquals("gettertest", result.base_getName().toString()); 428 // assert (42 == result()) 429 assertEquals(TEST_OBJECT_INIT, result.base_apply(NATTable.EMPTY, 430 new NATContext(atTestObject, atTestObject)).asNativeNumber().javaValue); 431 432 // clo := atTestObject.gettertest 433 ATClosure clo = atTestObject.meta_select(atTestObject, AGSymbol.jAlloc("gettertest")).asClosure(); 434 // assert (42 == clo()) 435 assertEquals(TEST_OBJECT_INIT, clo.base_apply(NATTable.EMPTY).asNativeNumber().javaValue); 436 437 // result := (reflect: atTestClass).grabMethod("prefix") 438 result = atTestClass.meta_grabMethod(AGSymbol.jAlloc("prefix")).asMethod(); 439 assertEquals("prefix", result.base_getName().toString()); 440 // assert ("AmbientTalk" == result("")) 441 assertEquals(ytest, result.base_apply(NATTable.atValue(new ATObject[] { NATText.atValue("") }), 442 new NATContext(atTestClass, atTestClass)).asNativeText().javaValue); 443 } catch (InterpreterException e) { 444 fail(e.getMessage()); 445 } 446 } 447 448 /** 449 * Tests casting to manually resolve overloaded method invocations 450 * Selecting a method from a Java object results in a JavaClosure instance. Such a Java 451 * closure understands the message 'cast', which allows the programmer to manually restrict 452 * the wrapped JavaMethods to specific type signatures. In this case, the two choices 453 * overloadedmatch2(Object) 454 * overloadedmatch2(SymbiosisTest) 455 * are manually restricted such that only the second one remains applicable 456 */ 457 public void testCasting() { 458 try { 459 // invokes overloadedmatch2(SymbiosisTest) via explicit casting 460 ATClosure method = atTestObject.meta_select(atTestObject, AGSymbol.jAlloc("overloadedmatch2")).asClosure(); 461 ATClosure castedMethod = method.meta_invoke(method, AGSymbol.jAlloc("cast"), NATTable.atValue(new ATObject[] { atTestClass })).asClosure(); 462 castedMethod.base_apply(NATTable.atValue(new ATObject[] { atTestObject })); 463 } catch (InterpreterException e) { 464 fail(e.getMessage()); 465 } 466 } 467 468 /** 469 * Tests whether the parent pointers of the AT symbionts refer to the proper objects. 470 */ 471 public void testSymbiontParents() { 472 try { 473 // the dynamic parent of atTestObject is atTestClass 474 assertEquals(atTestClass, atTestObject.base_getSuper()); 475 // the dynamic parent of atTestClass is nil 476 assertEquals(NATNil._INSTANCE_, atTestClass.base_getSuper()); 477 478 // the lexical parent of atTestObject is the lexical root 479 assertEquals(Evaluator.getGlobalLexicalScope(), atTestObject.meta_getLexicalParent()); 480 // the lexical parent of atTestClass is the lexical root 481 assertEquals(Evaluator.getGlobalLexicalScope(), atTestClass.meta_getLexicalParent()); 482 } catch (InterpreterException e) { 483 fail(e.getMessage()); 484 } 485 } 486 487 /** 488 * Tests whether new per-instance methods and fields can be added to a wrapped Java object. 489 */ 490 public void testSymbiontInstanceAdditions() { 491 try { 492 // (reflect: atTestObject).defineField("x", 1) 493 atTestObject.meta_defineField(AGSymbol.jAlloc("x"), NATNumber.ONE); 494 // assert(atTestObject.x == 1) 495 assertEquals(NATNumber.ONE, atTestObject.meta_select(atTestObject, AGSymbol.jAlloc("x"))); 496 497 // (reflect: atTestObject).addMethod(<method:"foo",[x],{x}>) 498 ATMethod foo = evalAndReturn("def foo(x) { x }; foo").asClosure().base_getMethod(); 499 atTestObject.meta_addMethod(foo); 500 // assert(atTestObject.foo(0) == 0) 501 assertEquals(NATNumber.ZERO, atTestObject.meta_invoke(atTestObject, AGSymbol.jAlloc("foo"), 502 NATTable.atValue(new ATObject[] { NATNumber.ZERO }))); 503 } catch (InterpreterException e) { 504 fail(e.getMessage()); 505 } 506 } 507 508 /** 509 * Tests whether no duplicate methods or fields can be added to a wrapped Java object. 510 */ 511 public void testSymbiontDuplicates() { 512 try { 513 try { 514 // def atTestObject.xtest := 1 515 atTestObject.meta_defineField(AGSymbol.jAlloc("xtest"), NATNumber.ONE); 516 fail("expected a duplicate slot exception"); 517 } catch (XDuplicateSlot e) { 518 // expected exception: success 519 } 520 try { 521 // def atTestObject.gettertest() { nil } 522 ATMethod getter = evalAndReturn("def gettertest() { nil }; gettertest").asClosure().base_getMethod(); 523 atTestObject.meta_addMethod(getter); 524 fail("expected a duplicate slot exception"); 525 } catch (XDuplicateSlot e) { 526 // expected exception: success 527 } 528 } catch (InterpreterException e) { 529 fail(e.getMessage()); 530 } 531 } 532 533 /** 534 * Tests whether new per-class methods and fields can be added to a wrapped Java class. 535 * Also tests whether existing instances can make use of these newly added methods 536 */ 537 public void testSymbiontClassAdditions() { 538 try { 539 // (reflect: atTestClass).defineField("z", 1) 540 atTestClass.meta_defineField(AGSymbol.jAlloc("z"), NATNumber.ONE); 541 // assert(atTestClass.z == 1) 542 assertEquals(NATNumber.ONE, atTestClass.meta_select(atTestClass, AGSymbol.jAlloc("z"))); 543 // assert(aTestObject.z == 1) -> delegation to class 544 assertEquals(NATNumber.ONE, atTestObject.meta_select(atTestObject, AGSymbol.jAlloc("z"))); 545 546 // (reflect: atTestClass).addMethod(<method:"get",[],{self.xtest}>) 547 ATMethod get = evalAndReturn("def get() { self.xtest }; get").asClosure().base_getMethod(); 548 atTestClass.meta_addMethod(get); 549 // assert(atTestObject.xtest == atTestObject.get()) 550 assertEquals(atTestObject.meta_select(atTestObject, AGSymbol.jAlloc("xtest")), 551 atTestObject.meta_invoke(atTestObject, AGSymbol.jAlloc("get"), NATTable.EMPTY)); 552 } catch (InterpreterException e) { 553 fail(e.getMessage()); 554 } 555 } 556 557 /** 558 * Tests cloning behaviour for both wrapped class instances and classes. 559 */ 560 public void testCloning() { 561 try { 562 // cloning a class results in the same class 563 assertEquals(atTestClass, atTestClass.meta_clone()); 564 565 try { 566 // cloning a java object results in an error 567 atTestObject.meta_clone(); 568 fail("expected an illegal operation exception"); 569 } catch (XIllegalOperation e) { 570 // expected exception: success 571 } 572 } catch (InterpreterException e) { 573 fail(e.getMessage()); 574 } 575 } 576 577 /** 578 * Tests the invocation of new on a wrapped Java Class. 579 * Instantiates the Java class via the default init implementation. 580 */ 581 public void testWorkingInstanceCreation() { 582 try { 583 // def instance := atTestClass.new(1) 584 ATObject instance = atTestClass.meta_newInstance(NATTable.atValue(new ATObject[] { NATNumber.ONE })); 585 assertEquals(JavaObject.class, instance.getClass()); 586 assertEquals(NATNumber.ONE, instance.meta_select(instance, AGSymbol.jAlloc("xtest"))); 587 588 Object realInstance = instance.asJavaObjectUnderSymbiosis().getWrappedObject(); 589 assertEquals(SymbiosisTest.class, realInstance.getClass()); 590 assertEquals(1, ((SymbiosisTest) realInstance).xtest); 591 } catch (InterpreterException e) { 592 fail(e.getMessage()); 593 } 594 } 595 596 /** 597 * Tests whether classes with private constructors terminate cleanly. 598 */ 599 public void testNonInstantiatableCreation() { 600 try { 601 // def instance := JavaObject.new(1) 602 JavaClass.wrapperFor(JavaObject.class).meta_newInstance(NATTable.atValue(new ATObject[] { NATNumber.ONE })); 603 fail("expected a not instantiatable exception"); 604 } catch (XNotInstantiatable e) { 605 // expected exception: success 606 } catch (InterpreterException e) { 607 fail(e.getMessage()); 608 } 609 } 610 611 /** 612 * Tests whether incorrect arguments passed to constructor terminate cleanly. 613 */ 614 public void testIllegalArgsInstanceCreation() { 615 try { 616 // def instance := atTestClass.new(1.0) 617 atTestClass.meta_newInstance(NATTable.atValue(new ATObject[] { NATFraction.atValue(1.0) })); 618 fail("expected a symbiosis failure with 0 matches"); 619 } catch (XSymbiosisFailure e) { 620 // expected exception: success 621 } catch (InterpreterException e) { 622 fail(e.getMessage()); 623 } 624 } 625 626 /** 627 * Tests whether overloaded constructors which cannot be resolved terminates cleanly. 628 */ 629 public void testOverloadedInstanceCreation() { 630 try { 631 // def instance := atTestClass.new(atTestObject) => 2 matches 632 atTestClass.meta_newInstance(NATTable.atValue(new ATObject[] { atTestObject })); 633 fail("expected a symbiosis failure with 2 matches"); 634 } catch (XSymbiosisFailure e) { 635 // expected exception: success 636 } catch (InterpreterException e) { 637 fail(e.getMessage()); 638 } 639 } 640 641 /** 642 * Tests an instance creation that raises an exception 643 */ 644 public void testExceptionInInstanceCreation() { 645 try { 646 // def instance := atTestClass.new(atTestClass) 647 atTestClass.meta_newInstance(NATTable.atValue(new ATObject[] { atTestClass })); 648 fail("expected the constructor to throw an exception"); 649 } catch (XJavaException e) { 650 // expected exception: success if it was an ExceptionTest instance 651 assertEquals(ExceptionTest.class, e.getWrappedJavaException().getClass()); 652 } catch (InterpreterException e) { 653 fail(e.getMessage()); 654 } 655 } 656 657 /** 658 * Tests the invocation of new on a wrapped Java Object, rather than on a Java Class. 659 */ 660 public void testCreationViaJavaObject() { 661 try { 662 // def instance := atTestObject.new(55) 663 ATObject instance = atTestObject.meta_newInstance( 664 NATTable.atValue(new ATObject[] { NATNumber.atValue(55) })); 665 666 assertEquals(55, instance.meta_select(instance, AGSymbol.jAlloc("xtest")).asNativeNumber().javaValue); 667 assertEquals(atTestClass, instance.base_getSuper()); 668 assertEquals(jTestObject.xtest, atTestObject.meta_select(atTestObject, 669 AGSymbol.jAlloc("xtest")).asNativeNumber().javaValue); 670 } catch (InterpreterException e) { 671 fail(e.getMessage()); 672 } 673 } 674 675 /** 676 * Tests the invocation of new on a wrapped Java Class. 677 * Instantiates the Java class via a custom new implementation. 678 * 679 * BEWARE: this test should be the last for testing symbiotic instance creation as it 680 * MODIFIES the test fixture (the JavaClass wrapper object)! Ths is because the JavaClass wrapper 681 * is pooled and reused throughout subsequent tests. 682 */ 683 public void testCustomInstanceCreation() { 684 try { 685 // def orignew := atTestClass.new; def atTestClass.new(x,y) { def o := orignew(x); def o.ytest := y; o } 686 ATClosure newClo = evalAndReturn("def new(x,y) { def o := orignew(x); def o.ytest := y; o }; new").asClosure(); 687 atTestClass.meta_defineField(AGSymbol.jAlloc("orignew"), atTestClass.meta_select(atTestClass, AGSymbol.jAlloc("new"))); 688 atTestClass.meta_addMethod(newClo.base_getMethod()); 689 690 // def instance := atTestClass.new(10, 11) 691 ATObject instance = atTestClass.meta_invoke(atTestClass, AGSymbol.jAlloc("new"), 692 NATTable.atValue(new ATObject[] { NATNumber.atValue(10), NATNumber.atValue(11) })); 693 694 assertEquals(10, instance.meta_select(instance, AGSymbol.jAlloc("xtest")).asNativeNumber().javaValue); 695 assertEquals(11, instance.meta_select(instance, AGSymbol.jAlloc("ytest")).asNativeNumber().javaValue); 696 } catch (InterpreterException e) { 697 fail(e.getMessage()); 698 } 699 } 700 701 /** 702 * Tests whether jlobby.java results in a new JavaPackage. 703 * Tests whether jlobby.java.lang results in a new JavaPackage. 704 * Tests whether jlobby.java.lang.Object results in the proper loading of that class 705 */ 706 public void testJLobbyPackageLoading() throws InterpreterException { 707 ATObject jpkg = jLobby_.meta_select(jLobby_, AGSymbol.jAlloc("java")); 708 assertEquals(JavaPackage.class, jpkg.getClass()); 709 assertTrue(jLobby_.meta_respondsTo(AGSymbol.jAlloc("java")).asNativeBoolean().javaValue); 710 ATObject jlpkg = jpkg.meta_select(jpkg, AGSymbol.jAlloc("lang")); 711 assertEquals(JavaPackage.class, jlpkg.getClass()); 712 assertTrue(jpkg.meta_respondsTo(AGSymbol.jAlloc("lang")).asNativeBoolean().javaValue); 713 ATObject jObject = jlpkg.meta_select(jlpkg, AGSymbol.jAlloc("Object")); 714 assertEquals(JavaClass.class, jObject.getClass()); 715 assertTrue(jlpkg.meta_respondsTo(AGSymbol.jAlloc("Object")).asNativeBoolean().javaValue); 716 } 717 718 /** 719 * Tests whether lowercase classes can be loaded via the class method of a JavaPackage. 720 */ 721 public void testJLobbyExplicitClassLoading() throws InterpreterException { 722 ATObject eduVubAtObjectsSymbiosisPkg = new JavaPackage("edu.vub.at.objects.symbiosis."); 723 724 // load the class manually: invoke pkg.class("lowercaseClassTest") 725 ATObject cls = eduVubAtObjectsSymbiosisPkg.meta_invoke( 726 eduVubAtObjectsSymbiosisPkg, 727 AGSymbol.jAlloc("class"), 728 NATTable.atValue(new ATObject[] { AGSymbol.jAlloc("lowercaseClassTest") })); 729 assertEquals(JavaClass.class, cls.getClass()); 730 assertTrue(eduVubAtObjectsSymbiosisPkg.meta_respondsTo( 731 AGSymbol.jAlloc("lowercaseClassTest")).asNativeBoolean().javaValue); 732 } 733 734 /** 735 * Tests whether access to a nonexistent class gives rise to a selector not found exception. 736 */ 737 public void testJLobbyNonexistentClassLoading() throws InterpreterException { 738 try { 739 jLobby_.meta_select(jLobby_, AGSymbol.jAlloc("Foo")); 740 fail("expected a class not found exception"); 741 } catch (XClassNotFound e) { 742 // success: expected exception 743 } 744 } 745 746 /** 747 * Tests whether the uppercase package 'foo.Bar' can be loaded via the package method of a JavaPackage. 748 */ 749 public void testJLobbyExplicitPackageLoading() throws InterpreterException { 750 // def fooPkg := jLobby.foo; 751 ATObject fooPkg = jLobby_.meta_select(jLobby_, AGSymbol.jAlloc("foo")); 752 // def BarPkg := foo.package(`Bar); 753 ATObject BarPkg = fooPkg.meta_invoke(fooPkg, 754 AGSymbol.jAlloc("package"), 755 NATTable.atValue(new ATObject[] { AGSymbol.jAlloc("Bar") })); 756 assertEquals(JavaPackage.class, BarPkg.getClass()); 757 assertTrue(fooPkg.meta_respondsTo(AGSymbol.jAlloc("Bar")).asNativeBoolean().javaValue); 758 } 759 760 /** 761 * BUGFIX TEST: jlobby.java.lang.StringBuffer.new(10) failed to discriminate between constructors 762 * StringBuffer(String) and StringBuffer(int), reason was that anything native was convertible to 763 * NATText and also to String. Fixed by reimplementing asNativeText in NATNil to throw a type 764 * exception as usual. 765 */ 766 public void testBugfixOverloadedConstructor() throws InterpreterException { 767 // def jStringBuffer := jLobby.java.lang.StringBuffer; 768 ATObject jStringBuffer = JavaClass.wrapperFor(StringBuffer.class); 769 // jStringBuffer.new(10) 770 jStringBuffer.meta_invoke(jStringBuffer, AGSymbol.jAlloc("new"), NATTable.atValue(new ATObject[] { NATNumber.atValue(10) })); 771 } 772 773 /** 774 * Tests whether Java interface types are correctly treated as AT/2 stripes. 775 * Test cases: interface java.util.Set extends java.util.Collection 776 */ 777 public void testInterfacesAndStripes() throws InterpreterException { 778 JavaClass jSet = JavaClass.wrapperFor(Set.class); 779 JavaClass jCollection = JavaClass.wrapperFor(Collection.class); 780 ATStripe atSet = jSet.asStripe(); 781 ATStripe atCollection = jCollection.asStripe(); 782 // stripe name = 'java.util.Set' 783 assertEquals(AGSymbol.jAlloc("java.util.Set"), atSet.base_getStripeName()); 784 // stripe parents = [ java.util.Collection ] 785 assertEquals(jCollection, atSet.base_getParentStripes().base_at(NATNumber.ONE)); 786 // Set isSubstripeOf Collection? true 787 assertTrue(atSet.base_isSubstripeOf(atCollection).asNativeBoolean().javaValue); 788 // Collection isSubstripeOf Set? false 789 assertFalse(atCollection.base_isSubstripeOf(atSet).asNativeBoolean().javaValue); 790 // Set isSubstripeOf Set? true 791 assertTrue(atSet.base_isSubstripeOf(atSet).asNativeBoolean().javaValue); 792 } 793 794 /** 795 * Test whether JavaObject wrappers are correctly striped with all 796 * of the interfaces of the wrapped instance's class. 797 * 798 * Test case: java.util.Vector implements List, RandomAccess, Cloneable, Serializable 799 */ 800 public void testStripedJavaObject() throws InterpreterException { 801 JavaClass jVector = JavaClass.wrapperFor(Vector.class); 802 JavaObject vec = jVector.meta_newInstance(NATTable.EMPTY).asJavaObjectUnderSymbiosis(); 803 804 ATStripe jListStripe = JavaClass.wrapperFor(List.class).asStripe(); 805 ATStripe jCollectionStripe = JavaClass.wrapperFor(Collection.class).asStripe(); 806 ATStripe jSerializableStripe = JavaClass.wrapperFor(Serializable.class).asStripe(); 807 ATStripe jSetStripe = JavaClass.wrapperFor(Set.class).asStripe(); 808 809 // vec is striped with List? true 810 assertTrue(vec.meta_isStripedWith(jListStripe).asNativeBoolean().javaValue); 811 // vec is striped with Collection? true 812 assertTrue(vec.meta_isStripedWith(jCollectionStripe).asNativeBoolean().javaValue); 813 // vec is striped with Serializable? true 814 assertTrue(vec.meta_isStripedWith(jSerializableStripe).asNativeBoolean().javaValue); 815 // vec is striped with Set? false 816 assertFalse(vec.meta_isStripedWith(jSetStripe).asNativeBoolean().javaValue); 817 } 818 819} 820 821class lowercaseClassTest { }