/interpreter/tags/at2dist110511/test/edu/vub/at/objects/natives/LexicalRootTest.java
Java | 185 lines | 96 code | 29 blank | 60 comment | 0 complexity | ccfa33221712d8c0a078184d07622fec MD5 | raw file
1package edu.vub.at.objects.natives; 2 3import edu.vub.at.AmbientTalkTest; 4import edu.vub.at.eval.Evaluator; 5import edu.vub.at.exceptions.InterpreterException; 6import edu.vub.at.exceptions.XImportConflict; 7import edu.vub.at.objects.natives.grammar.AGBegin; 8import edu.vub.at.objects.natives.grammar.AGImport; 9import edu.vub.at.objects.natives.grammar.AGSelf; 10import edu.vub.at.objects.natives.grammar.AGSymbol; 11 12/** 13 * @author tvcutsem 14 * 15 * The unit test LexicalRootTest tests globally visible methods in the lexical root. 16 * 17 * TODO: finish me 18 */ 19public class LexicalRootTest extends AmbientTalkTest { 20 21 public static void main(String[] args) { 22 junit.swingui.TestRunner.run(LexicalRootTest.class); 23 } 24 25 //private OBJLexicalRoot root_ = (OBJLexicalRoot) OBJLexicalRoot.getGlobalLexicalScope().lexicalParent_; 26 27 public void testLexicalRootFields() { 28 evalAndCompareTo("nil", Evaluator.getNil()); 29 evalAndCompareTo("true", NATBoolean._TRUE_); 30 evalAndCompareTo("false", NATBoolean._FALSE_); 31 evalAndCompareTo("/", Evaluator.getLobbyNamespace()); 32 } 33 34 private NATObject trait_; 35 36 public static final AGSymbol atX_ = AGSymbol.jAlloc("x"); 37 public static final AGSymbol atM_ = AGSymbol.jAlloc("m"); 38 public static final AGSymbol atN_ = AGSymbol.jAlloc("n"); 39 40 /** 41 * Initialize the trait used for testing import: 42 * 43 * def parent := object: { def n() { nil }; def m() { nil } } 44 * def trait := extend: parent with: { 45 * def x := 0; 46 * def m() { self } 47 * } 48 */ 49 public void setUp() throws Exception { 50 super.setUp(); 51 NATObject parent = new NATObject(); 52 parent.meta_addMethod(new NATMethod(atN_, NATTable.EMPTY, new AGBegin(NATTable.of(Evaluator.getNil())), NATTable.EMPTY)); 53 parent.meta_addMethod(new NATMethod(atM_, NATTable.EMPTY, new AGBegin(NATTable.of(Evaluator.getNil())), NATTable.EMPTY)); 54 trait_ = new NATObject(parent, Evaluator.getGlobalLexicalScope(), NATObject._IS_A_); 55 trait_.meta_defineField(atX_, NATNumber.ZERO); 56 trait_.meta_addMethod(new NATMethod(atM_, 57 NATTable.EMPTY, 58 new AGBegin(NATTable.of(AGSelf._INSTANCE_)), NATTable.EMPTY)); 59 } 60 61 /** 62 * Tests whether a basic import of fields and methods from a 63 * 'trait' object into a 'host' object works properly. 64 */ 65 public void testBasicImport() throws InterpreterException { 66 // def host := object: { def test() { x } } 67 NATObject host = new NATObject(); 68 AGSymbol atTest = AGSymbol.jAlloc("test"); 69 // test method accesses 'x' unqualified 70 host.meta_addMethod(new NATMethod(atTest, NATTable.EMPTY, 71 new AGBegin(NATTable.of(atX_)), NATTable.EMPTY)); 72 73 // < import trait > . eval(ctx[lex=host;self=host]) 74 new AGImport(trait_, NATTable.EMPTY, NATTable.EMPTY).meta_eval(new NATContext(host, host)); 75 76 // check whether host contains the appropriate fields and methods of the traits 77 assertTrue(host.meta_respondsTo(atX_).asNativeBoolean().javaValue); 78 assertTrue(host.meta_respondsTo(atM_).asNativeBoolean().javaValue); 79 80 // check whether the methods and fields of the parents of traits are also present 81 assertTrue(host.meta_respondsTo(atN_).asNativeBoolean().javaValue); 82 83 // ensure that 'self' is correctly late bound to host when invoking m() 84 assertEquals(host, host.impl_invoke(host, atM_, NATTable.EMPTY)); 85 // when invoking m() directly on the trait, self should be bound to the trait 86 assertEquals(trait_, trait_.impl_invoke(trait_, atM_, NATTable.EMPTY)); 87 88 // when someone delegates m() to host, the trait's self should be bound to the original delegator 89 NATObject delegator = new NATObject(); 90 assertEquals(delegator, host.impl_invoke(delegator, atM_, NATTable.EMPTY)); 91 92 // ensure that when invoking test() on host, it can access x unqualified 93 assertEquals(NATNumber.ZERO, host.impl_invoke(host, atTest, NATTable.EMPTY)); 94 95 // when assigning x in host, trait's x field should not be modified 96 host.impl_invoke(host, atX_.asAssignmentSymbol(), NATTable.of(NATNumber.ONE)); 97 assertEquals(NATNumber.ZERO, trait_.impl_invokeAccessor(trait_, atX_, NATTable.EMPTY)); 98 99 // host's primitive methods should be left untouched, i.e. 100 // host != trait and host == host 101 assertTrue(host.impl_invoke(host, NATNil._EQL_NAME_, NATTable.of(host)).asNativeBoolean().javaValue); 102 assertFalse(host.impl_invoke(host, NATNil._EQL_NAME_, NATTable.of(trait_)).asNativeBoolean().javaValue); 103 } 104 105 /** 106 * Tests whether conflicts are successfully detected. 107 */ 108 public void testConflictingImport() throws InterpreterException { 109 NATObject host = new NATObject(); 110 111 // host defines x itself, so import should fail 112 host.meta_defineField(atX_, NATNumber.ONE); 113 114 try { 115 // < import trait > . eval(ctx[lex=host;self=host]) 116 new AGImport(trait_, NATTable.EMPTY, NATTable.EMPTY).meta_eval(new NATContext(host, host)); 117 fail("Expected an XImportConflict exception"); 118 } catch (XImportConflict e) { 119 assertEquals(atX_, e.getConflictingNames().base_at(NATNumber.ONE)); 120 } 121 } 122 123 /** 124 * Tests whether traits can be transitively imported into objects. 125 */ 126 public void testTransitiveImport() throws InterpreterException { 127 NATObject hostA = new NATObject(); 128 NATObject hostB = new NATObject(); 129 // < import trait > . eval(ctx[lex=hostA;self=hostA]) 130 new AGImport(trait_, NATTable.EMPTY, NATTable.EMPTY).meta_eval(new NATContext(hostA, hostA)); 131 // < import trait > . eval(ctx[lex=hostB;self=hostB]) 132 new AGImport(trait_, NATTable.EMPTY, NATTable.EMPTY).meta_eval(new NATContext(hostB, hostB)); 133 134 // check whether m() can be invoked from hostB and that self equals hostB 135 assertEquals(hostB, hostB.impl_invoke(hostB, atM_, NATTable.EMPTY)); 136 } 137 138 /** 139 * Tests whether aliasing works properly. 140 */ 141 public void testImportAndAliasing() throws InterpreterException { 142 NATObject host = new NATObject(); 143 AGSymbol foo = AGSymbol.jAlloc("foo"); 144 NATTable alias = NATTable.of(NATTable.of(atM_, foo)); // [[m,foo]] 145 // < import trait alias m := foo > . eval(ctx[lex=host;self=host]) 146 new AGImport(trait_, alias, NATTable.EMPTY).meta_eval(new NATContext(host, host)); 147 148 // check whether m() can be invoked as foo() 149 assertTrue(host.meta_respondsTo(foo).asNativeBoolean().javaValue); 150 assertEquals(host, host.impl_invoke(host, foo, NATTable.EMPTY)); 151 } 152 153 /** 154 * Tests whether exclusion works properly. 155 */ 156 public void testImportAndExclusion() throws InterpreterException { 157 NATObject host = new NATObject(); 158 NATTable exclude = NATTable.of(atN_); 159 // < import trait exclude n > . eval(ctx[lex=host;self=host]) 160 new AGImport(trait_, NATTable.EMPTY, exclude).meta_eval(new NATContext(host, host)); 161 162 // check whether m is present and n is not present 163 assertTrue(host.meta_respondsTo(atM_).asNativeBoolean().javaValue); 164 assertFalse(host.meta_respondsTo(atN_).asNativeBoolean().javaValue); 165 } 166 167 /** 168 * Tests whether aliasing and exclusion work properly together. 169 */ 170 public void testImportAndAliasingAndExclusion() throws InterpreterException { 171 NATObject host = new NATObject(); 172 AGSymbol foo = AGSymbol.jAlloc("foo"); 173 NATTable alias = NATTable.of(NATTable.of(atM_, foo)); // [[m,foo]] 174 NATTable exclude = NATTable.of(atN_); 175 // < import trait alias m := foo exclude n> . eval(ctx[lex=host;self=host]) 176 new AGImport(trait_, alias, exclude).meta_eval(new NATContext(host, host)); 177 178 // check whether m() can be invoked as foo() 179 assertTrue(host.meta_respondsTo(foo).asNativeBoolean().javaValue); 180 assertEquals(host, host.impl_invoke(host, foo, NATTable.EMPTY)); 181 182 // check whether n is not present 183 assertFalse(host.meta_respondsTo(atN_).asNativeBoolean().javaValue); 184 } 185}