/interpreter/tags/at2dist030708/test/edu/vub/at/objects/natives/grammar/TestParameterBinding.java
Java | 362 lines | 184 code | 41 blank | 137 comment | 1 complexity | e3338303607f0154d79ba37d07864a57 MD5 | raw file
1/** 2 * AmbientTalk/2 Project 3 * TestParameterBinding.java created on 26-dec-2006 at 13:43:59 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.grammar; 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.XIllegalParameter; 35import edu.vub.at.objects.ATObject; 36import edu.vub.at.objects.grammar.ATSymbol; 37import edu.vub.at.objects.natives.NATContext; 38import edu.vub.at.objects.natives.NATMethod; 39import edu.vub.at.objects.natives.NATNumber; 40import edu.vub.at.objects.natives.NATObject; 41import edu.vub.at.objects.natives.NATTable; 42 43/** 44 * Unit test for parameter binding during e.g. function call. 45 * 46 * @author tvcutsem 47 */ 48public class TestParameterBinding extends AmbientTalkTest { 49 50 private void ensureBound(ATSymbol var, ATObject value) throws InterpreterException { 51 assertEquals(value, bindScope_.impl_invokeAccessor(bindScope_, var, NATTable.EMPTY)); 52 } 53 54 private void ensureBoundToTable(ATSymbol var, ATObject[] expected) throws InterpreterException { 55 NATTable val = bindScope_.impl_invokeAccessor(bindScope_, var, NATTable.EMPTY).asNativeTable(); 56 ATObject[] values = val.elements_; 57 assertEquals(expected.length, values.length); 58 for (int i = 0; i < values.length; i++) { 59 assertEquals(expected[i], values[i]); 60 } 61 } 62 63 /** 64 * Given a name and parameters, returns a method 65 * def name(parameters) { nil } 66 */ 67 private NATMethod makeTestMethod(String nam, NATTable pars) { 68 try { 69 return new NATMethod(AGSymbol.jAlloc(nam), pars, 70 new AGBegin(NATTable.atValue(new ATObject[] { Evaluator.getNil() })), NATTable.EMPTY); 71 } catch (InterpreterException e) { 72 fail("unexpected exception while creating test fixture: " + e.getMessage()); 73 return null; 74 } 75 } 76 77 private NATContext bindCtx_; 78 private NATObject bindScope_; 79 80 private final AGSymbol at_a = AGSymbol.jAlloc("a"); 81 private final AGSymbol at_b = AGSymbol.jAlloc("b"); 82 private final AGSymbol at_rest = AGSymbol.jAlloc("rest"); 83 private final AGSymbol at_x = AGSymbol.jAlloc("x"); 84 private final AGSymbol at_y = AGSymbol.jAlloc("y"); 85 86 // TEST FUNCTIONS 87 88 // def fun1() { nil } 89 private NATMethod fun1 = makeTestMethod("fun1", NATTable.EMPTY); 90 91 // def fun2(a,b) { nil } 92 private NATMethod fun2 = makeTestMethod("fun2", NATTable.atValue(new ATObject[] { at_a, at_b })); 93 94 // def fun3(a,b,x := 1) { nil } 95 private NATMethod fun3 = makeTestMethod("fun3", 96 NATTable.atValue(new ATObject[] { at_a, at_b, new AGAssignVariable(at_x, NATNumber.ONE) })); 97 98 // def fun4(a, x:=a, @rest) { nil } 99 private NATMethod fun4 = makeTestMethod("fun4", 100 NATTable.atValue(new ATObject[] { at_a, new AGAssignVariable(at_x, at_a), new AGSplice(at_rest) })); 101 102 // def fun5(x := self, y := 0) { nil } 103 private NATMethod fun5 = makeTestMethod("fun5", 104 NATTable.atValue(new ATObject[] { new AGAssignVariable(at_x, AGSelf._INSTANCE_), new AGAssignVariable(at_y, NATNumber.ZERO) })); 105 106 // def fun6(a, @rest) { nil } 107 private NATMethod fun6 = makeTestMethod("fun6", NATTable.atValue(new ATObject[] { at_a, new AGSplice(at_rest) })); 108 109 // def fun7(@rest) { nil } 110 private NATMethod fun7 = makeTestMethod("fun7", NATTable.atValue(new ATObject[] { new AGSplice(at_rest) })); 111 112 113 public void setUp() throws InterpreterException { 114 bindScope_ = new NATObject(); 115 bindCtx_ = new NATContext(bindScope_, bindScope_); 116 } 117 118 /** 119 * Tests parameter binding for 0-arity methods 120 */ 121 public void testZeroArity() throws InterpreterException { 122 // fun1() 123 fun1.base_applyInScope(NATTable.EMPTY, bindCtx_); 124 125 // fun1(0) => arity mismatch 126 try { 127 fun1.base_applyInScope(NATTable.atValue(new ATObject[] { NATNumber.ZERO }), bindCtx_); 128 fail("Expected XArityMismatch exception"); 129 } catch(XArityMismatch e) { } 130 } 131 132 /** 133 * Tests parameter binding for methods with mandatory arguments only. 134 */ 135 public void testMandatory() throws InterpreterException { 136 // normal case: fun2(0,1) 137 fun2.base_applyInScope(NATTable.atValue(new ATObject[] { NATNumber.ZERO, NATNumber.ONE }), bindCtx_); 138 ensureBound(at_a, NATNumber.ZERO); 139 ensureBound(at_b, NATNumber.ONE); 140 } 141 142 /** 143 * Tests for too few mandatory arguments 144 */ 145 public void testTooFewMandatory() throws InterpreterException { 146 // too few arguments: fun2(0) 147 try { 148 fun2.base_applyInScope(NATTable.atValue(new ATObject[] { NATNumber.ZERO }), bindCtx_); 149 fail("Expected XArityMismatch exception"); 150 } catch(XArityMismatch e) { } 151 } 152 153 /** 154 * Tests for too many mandatory arguments 155 */ 156 public void testTooManyMandatory() throws InterpreterException { 157 // too many arguments: fun2(0,1,2) 158 try { 159 fun2.base_applyInScope(NATTable.atValue(new ATObject[] { NATNumber.ZERO, NATNumber.ONE, NATNumber.atValue(2) }), bindCtx_); 160 fail("Expected XArityMismatch exception"); 161 } catch(XArityMismatch e) { } 162 } 163 164 /** 165 * Tests parameter binding for methods with mandatory arguments and optional arguments. 166 */ 167 public void testMandatoryAndOptional() throws InterpreterException { 168 // normal case: fun3(0,1,2) 169 fun3.base_applyInScope(NATTable.atValue(new ATObject[] { NATNumber.ZERO, NATNumber.ONE, NATNumber.atValue(2) }), bindCtx_); 170 ensureBound(at_a, NATNumber.ZERO); 171 ensureBound(at_b, NATNumber.ONE); 172 ensureBound(at_x, NATNumber.atValue(2)); 173 } 174 175 /** 176 * Tests parameter binding for methods with mandatory arguments and an 177 * optional argument that is not given. 178 */ 179 public void testMandatoryAndDefaultOptional() throws InterpreterException { 180 // fun3(0,1) => ensure optional argument x is bound to default 1 181 fun3.base_applyInScope(NATTable.atValue(new ATObject[] { NATNumber.ZERO, NATNumber.ONE }), bindCtx_); 182 ensureBound(at_a, NATNumber.ZERO); 183 ensureBound(at_b, NATNumber.ONE); 184 ensureBound(at_x, NATNumber.ONE); 185 } 186 187 /** 188 * Tests whether parameter binding fails if given too many optional arguments. 189 */ 190 public void testMandatoryAndTooManyOptional() throws InterpreterException { 191 // fun3(0,1,2,3) 192 try { 193 fun3.base_applyInScope(NATTable.atValue(new ATObject[] { NATNumber.ZERO, NATNumber.ONE, NATNumber.atValue(2), NATNumber.atValue(3) }), bindCtx_); 194 fail("Expected XArityMismatch exception"); 195 } catch(XArityMismatch e) { } 196 } 197 198 /** 199 * Tests application with both mandatory, optional and rest arguments 200 */ 201 public void testMandOptAndRest() throws InterpreterException { 202 // fun4(0,1,2,3) 203 fun4.base_applyInScope(NATTable.atValue(new ATObject[] { 204 NATNumber.ZERO, NATNumber.ONE, NATNumber.atValue(2), NATNumber.atValue(3) }), bindCtx_); 205 ensureBound(at_a, NATNumber.ZERO); 206 ensureBound(at_x, NATNumber.ONE); 207 ensureBoundToTable(at_rest, new ATObject[] { NATNumber.atValue(2), NATNumber.atValue(3) }); 208 } 209 210 /** 211 * Tests application with mandatory and optional arguments. 212 * The rest arguments should be [] 213 */ 214 public void testMandOptAndNoRest() throws InterpreterException { 215 // fun4(0,1) 216 fun4.base_applyInScope(NATTable.atValue(new ATObject[] { NATNumber.ZERO, NATNumber.ONE }), bindCtx_); 217 ensureBound(at_a, NATNumber.ZERO); 218 ensureBound(at_x, NATNumber.ONE); 219 ensureBound(at_rest, NATTable.EMPTY); 220 } 221 222 /** 223 * Tests application with mandatory arguments. 224 * The optional argument should be initialized to its default expression. 225 * Note that this default expression also tests for let*-like behaviour! 226 * The rest arguments should be [] 227 */ 228 public void testMandNoOptAndNoRest() throws InterpreterException { 229 // fun4(3) 230 fun4.base_applyInScope(NATTable.atValue(new ATObject[] { NATNumber.atValue(3) }), bindCtx_); 231 ensureBound(at_a, NATNumber.atValue(3)); 232 ensureBound(at_x, NATNumber.atValue(3)); 233 ensureBound(at_rest, NATTable.EMPTY); 234 } 235 236 /** 237 * Tests application with only optional arguments, all of which are given at call time. 238 */ 239 public void testOnlyOptionalArguments() throws InterpreterException { 240 // fun5(0,1) 241 fun5.base_applyInScope(NATTable.atValue(new ATObject[] { NATNumber.ZERO, NATNumber.ONE }), bindCtx_); 242 ensureBound(at_x, NATNumber.ZERO); 243 ensureBound(at_y, NATNumber.ONE); 244 } 245 246 /** 247 * Tests application with only optional arguments, only one of which is given at call time. 248 */ 249 public void testOnlyOptArgsWithOneFilledIn() throws InterpreterException { 250 // fun5(0) 251 fun5.base_applyInScope(NATTable.atValue(new ATObject[] { NATNumber.ZERO }), bindCtx_); 252 ensureBound(at_x, NATNumber.ZERO); 253 ensureBound(at_y, NATNumber.ZERO); 254 } 255 256 /** 257 * Tests application with only optional arguments, none of which are given at call time. 258 */ 259 public void testOnlyOptArgsWithNoneFilledIn() throws InterpreterException { 260 // fun5() 261 fun5.base_applyInScope(NATTable.EMPTY, bindCtx_); 262 ensureBound(at_x, bindScope_); 263 ensureBound(at_y, NATNumber.ZERO); 264 } 265 266 /** 267 * Tests application with one mandatory argument and zero rest arguments. 268 */ 269 public void testOneMandatoryAndNoRestArgs() throws InterpreterException { 270 // fun6(0) 271 fun6.base_applyInScope(NATTable.atValue(new ATObject[] { NATNumber.ZERO }), bindCtx_); 272 ensureBound(at_a, NATNumber.ZERO); 273 ensureBound(at_rest, NATTable.EMPTY); 274 } 275 276 /** 277 * Tests application with one mandatory argument and two rest arguments. 278 */ 279 public void testOneMandatoryAndTwoRestArgs() throws InterpreterException { 280 // fun6(0,1,2) 281 fun6.base_applyInScope(NATTable.atValue( 282 new ATObject[] { NATNumber.ZERO, NATNumber.ONE, NATNumber.atValue(2) }), bindCtx_); 283 ensureBound(at_a, NATNumber.ZERO); 284 ensureBoundToTable(at_rest, new ATObject[] { NATNumber.ONE, NATNumber.atValue(2)}); 285 } 286 287 /** 288 * Tests only rest arguments, with none given. 289 */ 290 public void testZeroRestArgs() throws InterpreterException { 291 // fun7() 292 fun7.base_applyInScope(NATTable.EMPTY, bindCtx_); 293 ensureBound(at_rest, NATTable.EMPTY); 294 } 295 296 /** 297 * Tests only rest arguments, with one given. 298 */ 299 public void testOneRestArg() throws InterpreterException { 300 // fun7(0) 301 fun7.base_applyInScope(NATTable.atValue(new ATObject[] { NATNumber.ZERO }), bindCtx_); 302 ensureBoundToTable(at_rest, new ATObject[] { NATNumber.ZERO }); 303 } 304 305 306 /** 307 * Tests whether mandatory arguments specified after optional arguments 308 * results in a proper XIllegalParameter exception. 309 */ 310 public void testIllegalMandatoryAfterOptional() throws InterpreterException { 311 // def fun8(x:=0, a) { nil } 312 try { 313 new NATMethod(AGSymbol.jAlloc("fun8"), 314 NATTable.atValue(new ATObject[] { new AGAssignVariable(at_x, NATNumber.ZERO), at_a }), 315 new AGBegin(NATTable.atValue(new ATObject[] { Evaluator.getNil() })), NATTable.EMPTY); 316 fail("Expected XIllegalParameter exception"); 317 } catch(XIllegalParameter e) { } 318 } 319 320 /** 321 * Tests whether mandatory arguments specified after the rest parameter 322 * results in a proper XIllegalParameter exception. 323 */ 324 public void testIllegalMandatoryAfterRest() throws InterpreterException { 325 // def fun8(x:=0, a) { nil } 326 try { 327 new NATMethod(AGSymbol.jAlloc("fun9"), 328 NATTable.atValue(new ATObject[] { new AGSplice(at_rest), at_a }), 329 new AGBegin(NATTable.atValue(new ATObject[] { Evaluator.getNil() })), NATTable.EMPTY); 330 fail("Expected XIllegalParameter exception"); 331 } catch(XIllegalParameter e) { } 332 } 333 334 /** 335 * Tests whether optional arguments specified after the rest parameter 336 * results in a proper XIllegalParameter exception. 337 */ 338 public void testIllegalOptionalAfterRest() throws InterpreterException { 339 // def fun8(x:=0, a) { nil } 340 try { 341 new NATMethod(AGSymbol.jAlloc("fun10"), 342 NATTable.atValue(new ATObject[] { new AGSplice(at_rest), new AGAssignVariable(at_x, NATNumber.ZERO) }), 343 new AGBegin(NATTable.atValue(new ATObject[] { Evaluator.getNil() })), NATTable.EMPTY); 344 fail("Expected XIllegalParameter exception"); 345 } catch(XIllegalParameter e) { } 346 } 347 348 /** 349 * Tests whether optional and rest parameters also work using multiple-definition 350 */ 351 public void testMultiAssignmentWithOptionalAndRestParameters() throws InterpreterException { 352 // def [a,x:=a,@rest] := [0,1,2] 353 AGMultiDefinition multiDef = new AGMultiDefinition( 354 fun4.base_parameters(), 355 NATTable.atValue(new ATObject[] { NATNumber.ZERO, NATNumber.ONE, NATNumber.atValue(2) })); 356 multiDef.meta_eval(bindCtx_); 357 ensureBound(at_a, NATNumber.ZERO); 358 ensureBound(at_x, NATNumber.ONE); 359 ensureBoundToTable(at_rest, new ATObject[] { NATNumber.atValue(2)}); 360 } 361 362}