Thu, 09 Jan 2014 19:23:34 +0530
8031359: Invocable.getInterface() works incorrectly if interface has default methods
Reviewed-by: attila, hannesw
sundar@518 | 1 | /* |
sundar@518 | 2 | * Copyright (c) 2010, 2013, Oracle and/or its affiliates. All rights reserved. |
sundar@518 | 3 | * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. |
sundar@518 | 4 | * |
sundar@518 | 5 | * This code is free software; you can redistribute it and/or modify it |
sundar@518 | 6 | * under the terms of the GNU General Public License version 2 only, as |
sundar@518 | 7 | * published by the Free Software Foundation. Oracle designates this |
sundar@518 | 8 | * particular file as subject to the "Classpath" exception as provided |
sundar@518 | 9 | * by Oracle in the LICENSE file that accompanied this code. |
sundar@518 | 10 | * |
sundar@518 | 11 | * This code is distributed in the hope that it will be useful, but WITHOUT |
sundar@518 | 12 | * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or |
sundar@518 | 13 | * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License |
sundar@518 | 14 | * version 2 for more details (a copy is included in the LICENSE file that |
sundar@518 | 15 | * accompanied this code). |
sundar@518 | 16 | * |
sundar@518 | 17 | * You should have received a copy of the GNU General Public License version |
sundar@518 | 18 | * 2 along with this work; if not, write to the Free Software Foundation, |
sundar@518 | 19 | * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. |
sundar@518 | 20 | * |
sundar@518 | 21 | * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA |
sundar@518 | 22 | * or visit www.oracle.com if you need additional information or have any |
sundar@518 | 23 | * questions. |
sundar@518 | 24 | */ |
sundar@518 | 25 | |
sundar@518 | 26 | package jdk.nashorn.api.scripting; |
sundar@518 | 27 | |
sundar@518 | 28 | import java.util.Objects; |
sundar@755 | 29 | import java.util.function.Function; |
sundar@518 | 30 | import javax.script.Invocable; |
sundar@518 | 31 | import javax.script.ScriptContext; |
sundar@518 | 32 | import javax.script.ScriptEngine; |
sundar@518 | 33 | import javax.script.ScriptEngineManager; |
sundar@518 | 34 | import javax.script.ScriptException; |
sundar@518 | 35 | import javax.script.SimpleScriptContext; |
sundar@518 | 36 | import org.testng.Assert; |
sundar@518 | 37 | import static org.testng.Assert.assertEquals; |
sundar@518 | 38 | import static org.testng.Assert.fail; |
sundar@518 | 39 | import org.testng.annotations.Test; |
sundar@518 | 40 | |
sundar@518 | 41 | /** |
sundar@518 | 42 | * Tests for javax.script.Invocable implementation of nashorn. |
sundar@518 | 43 | */ |
sundar@518 | 44 | public class InvocableTest { |
sundar@518 | 45 | |
sundar@518 | 46 | private void log(String msg) { |
sundar@518 | 47 | org.testng.Reporter.log(msg, true); |
sundar@518 | 48 | } |
sundar@518 | 49 | |
sundar@518 | 50 | @Test |
sundar@518 | 51 | public void invokeMethodTest() { |
sundar@518 | 52 | final ScriptEngineManager m = new ScriptEngineManager(); |
sundar@518 | 53 | final ScriptEngine e = m.getEngineByName("nashorn"); |
sundar@518 | 54 | |
sundar@518 | 55 | try { |
sundar@518 | 56 | e.eval("var Example = function() { this.hello = function() { return 'Hello World!'; };}; myExample = new Example();"); |
sundar@518 | 57 | final Object obj = e.get("myExample"); |
sundar@518 | 58 | final Object res = ((Invocable) e).invokeMethod(obj, "hello"); |
sundar@518 | 59 | assertEquals(res, "Hello World!"); |
sundar@518 | 60 | } catch (final Exception exp) { |
sundar@518 | 61 | exp.printStackTrace(); |
sundar@518 | 62 | fail(exp.getMessage()); |
sundar@518 | 63 | } |
sundar@518 | 64 | } |
sundar@518 | 65 | |
sundar@518 | 66 | @Test |
sundar@518 | 67 | /** |
sundar@518 | 68 | * Check that we can call invokeMethod on an object that we got by |
sundar@518 | 69 | * evaluating script with different Context set. |
sundar@518 | 70 | */ |
sundar@518 | 71 | public void invokeMethodDifferentContextTest() { |
sundar@518 | 72 | ScriptEngineManager m = new ScriptEngineManager(); |
sundar@518 | 73 | ScriptEngine e = m.getEngineByName("nashorn"); |
sundar@518 | 74 | |
sundar@518 | 75 | try { |
sundar@518 | 76 | // define an object with method on it |
sundar@518 | 77 | Object obj = e.eval("({ hello: function() { return 'Hello World!'; } })"); |
sundar@518 | 78 | |
sundar@518 | 79 | final ScriptContext ctxt = new SimpleScriptContext(); |
sundar@518 | 80 | ctxt.setBindings(e.createBindings(), ScriptContext.ENGINE_SCOPE); |
sundar@518 | 81 | e.setContext(ctxt); |
sundar@518 | 82 | |
sundar@518 | 83 | // invoke 'func' on obj - but with current script context changed |
sundar@518 | 84 | final Object res = ((Invocable) e).invokeMethod(obj, "hello"); |
sundar@518 | 85 | assertEquals(res, "Hello World!"); |
sundar@518 | 86 | } catch (final Exception exp) { |
sundar@518 | 87 | exp.printStackTrace(); |
sundar@518 | 88 | fail(exp.getMessage()); |
sundar@518 | 89 | } |
sundar@518 | 90 | } |
sundar@518 | 91 | |
sundar@518 | 92 | @Test |
sundar@518 | 93 | /** |
sundar@518 | 94 | * Check that invokeMethod throws NPE on null method name. |
sundar@518 | 95 | */ |
sundar@518 | 96 | public void invokeMethodNullNameTest() { |
sundar@518 | 97 | final ScriptEngineManager m = new ScriptEngineManager(); |
sundar@518 | 98 | final ScriptEngine e = m.getEngineByName("nashorn"); |
sundar@518 | 99 | |
sundar@518 | 100 | try { |
sundar@518 | 101 | final Object obj = e.eval("({})"); |
sundar@518 | 102 | final Object res = ((Invocable) e).invokeMethod(obj, null); |
sundar@518 | 103 | fail("should have thrown NPE"); |
sundar@518 | 104 | } catch (final Exception exp) { |
sundar@518 | 105 | if (!(exp instanceof NullPointerException)) { |
sundar@518 | 106 | exp.printStackTrace(); |
sundar@518 | 107 | fail(exp.getMessage()); |
sundar@518 | 108 | } |
sundar@518 | 109 | } |
sundar@518 | 110 | } |
sundar@518 | 111 | |
sundar@518 | 112 | @Test |
sundar@518 | 113 | /** |
sundar@518 | 114 | * Check that invokeMethod throws NoSuchMethodException on missing method. |
sundar@518 | 115 | */ |
sundar@518 | 116 | public void invokeMethodMissingTest() { |
sundar@518 | 117 | final ScriptEngineManager m = new ScriptEngineManager(); |
sundar@518 | 118 | final ScriptEngine e = m.getEngineByName("nashorn"); |
sundar@518 | 119 | |
sundar@518 | 120 | try { |
sundar@518 | 121 | final Object obj = e.eval("({})"); |
sundar@518 | 122 | final Object res = ((Invocable) e).invokeMethod(obj, "nonExistentMethod"); |
sundar@518 | 123 | fail("should have thrown NoSuchMethodException"); |
sundar@518 | 124 | } catch (final Exception exp) { |
sundar@518 | 125 | if (!(exp instanceof NoSuchMethodException)) { |
sundar@518 | 126 | exp.printStackTrace(); |
sundar@518 | 127 | fail(exp.getMessage()); |
sundar@518 | 128 | } |
sundar@518 | 129 | } |
sundar@518 | 130 | } |
sundar@518 | 131 | |
sundar@518 | 132 | @Test |
sundar@518 | 133 | /** |
sundar@518 | 134 | * Check that calling method on non-script object 'thiz' results in |
sundar@518 | 135 | * IllegalArgumentException. |
sundar@518 | 136 | */ |
sundar@518 | 137 | public void invokeMethodNonScriptObjectThizTest() { |
sundar@518 | 138 | final ScriptEngineManager m = new ScriptEngineManager(); |
sundar@518 | 139 | final ScriptEngine e = m.getEngineByName("nashorn"); |
sundar@518 | 140 | |
sundar@518 | 141 | try { |
sundar@518 | 142 | ((Invocable) e).invokeMethod(new Object(), "toString"); |
sundar@518 | 143 | fail("should have thrown IllegalArgumentException"); |
sundar@518 | 144 | } catch (final Exception exp) { |
sundar@518 | 145 | if (!(exp instanceof IllegalArgumentException)) { |
sundar@518 | 146 | exp.printStackTrace(); |
sundar@518 | 147 | fail(exp.getMessage()); |
sundar@518 | 148 | } |
sundar@518 | 149 | } |
sundar@518 | 150 | } |
sundar@518 | 151 | |
sundar@518 | 152 | @Test |
sundar@518 | 153 | /** |
sundar@518 | 154 | * Check that calling method on null 'thiz' results in |
sundar@518 | 155 | * IllegalArgumentException. |
sundar@518 | 156 | */ |
sundar@518 | 157 | public void invokeMethodNullThizTest() { |
sundar@518 | 158 | final ScriptEngineManager m = new ScriptEngineManager(); |
sundar@518 | 159 | final ScriptEngine e = m.getEngineByName("nashorn"); |
sundar@518 | 160 | |
sundar@518 | 161 | try { |
sundar@518 | 162 | ((Invocable) e).invokeMethod(null, "toString"); |
sundar@518 | 163 | fail("should have thrown IllegalArgumentException"); |
sundar@518 | 164 | } catch (final Exception exp) { |
sundar@518 | 165 | if (!(exp instanceof IllegalArgumentException)) { |
sundar@518 | 166 | exp.printStackTrace(); |
sundar@518 | 167 | fail(exp.getMessage()); |
sundar@518 | 168 | } |
sundar@518 | 169 | } |
sundar@518 | 170 | } |
sundar@518 | 171 | |
sundar@518 | 172 | @Test |
sundar@518 | 173 | /** |
sundar@518 | 174 | * Check that calling method on mirror created by another engine results in |
sundar@518 | 175 | * IllegalArgumentException. |
sundar@518 | 176 | */ |
sundar@518 | 177 | public void invokeMethodMixEnginesTest() { |
sundar@518 | 178 | final ScriptEngineManager m = new ScriptEngineManager(); |
sundar@518 | 179 | final ScriptEngine engine1 = m.getEngineByName("nashorn"); |
sundar@518 | 180 | final ScriptEngine engine2 = m.getEngineByName("nashorn"); |
sundar@518 | 181 | |
sundar@518 | 182 | try { |
sundar@518 | 183 | Object obj = engine1.eval("({ run: function() {} })"); |
sundar@518 | 184 | // pass object from engine1 to engine2 as 'thiz' for invokeMethod |
sundar@518 | 185 | ((Invocable) engine2).invokeMethod(obj, "run"); |
sundar@518 | 186 | fail("should have thrown IllegalArgumentException"); |
sundar@518 | 187 | } catch (final Exception exp) { |
sundar@518 | 188 | if (!(exp instanceof IllegalArgumentException)) { |
sundar@518 | 189 | exp.printStackTrace(); |
sundar@518 | 190 | fail(exp.getMessage()); |
sundar@518 | 191 | } |
sundar@518 | 192 | } |
sundar@518 | 193 | } |
sundar@518 | 194 | |
sundar@518 | 195 | @Test |
sundar@518 | 196 | public void getInterfaceTest() { |
sundar@518 | 197 | final ScriptEngineManager m = new ScriptEngineManager(); |
sundar@518 | 198 | final ScriptEngine e = m.getEngineByName("nashorn"); |
sundar@518 | 199 | final Invocable inv = (Invocable) e; |
sundar@518 | 200 | |
sundar@518 | 201 | // try to get interface from global functions |
sundar@518 | 202 | try { |
sundar@518 | 203 | e.eval("function run() { print('run'); };"); |
sundar@518 | 204 | final Runnable runnable = inv.getInterface(Runnable.class); |
sundar@518 | 205 | runnable.run(); |
sundar@518 | 206 | } catch (final Exception exp) { |
sundar@518 | 207 | exp.printStackTrace(); |
sundar@518 | 208 | fail(exp.getMessage()); |
sundar@518 | 209 | } |
sundar@518 | 210 | |
sundar@518 | 211 | // try interface on specific script object |
sundar@518 | 212 | try { |
sundar@518 | 213 | e.eval("var obj = { run: function() { print('run from obj'); } };"); |
sundar@518 | 214 | Object obj = e.get("obj"); |
sundar@518 | 215 | final Runnable runnable = inv.getInterface(obj, Runnable.class); |
sundar@518 | 216 | runnable.run(); |
sundar@518 | 217 | } catch (final Exception exp) { |
sundar@518 | 218 | exp.printStackTrace(); |
sundar@518 | 219 | fail(exp.getMessage()); |
sundar@518 | 220 | } |
sundar@518 | 221 | } |
sundar@518 | 222 | |
sundar@518 | 223 | public interface Foo { |
sundar@518 | 224 | |
sundar@518 | 225 | public void bar(); |
sundar@518 | 226 | } |
sundar@518 | 227 | |
sundar@518 | 228 | public interface Foo2 extends Foo { |
sundar@518 | 229 | |
sundar@518 | 230 | public void bar2(); |
sundar@518 | 231 | } |
sundar@518 | 232 | |
sundar@518 | 233 | @Test |
sundar@518 | 234 | public void getInterfaceMissingTest() { |
sundar@518 | 235 | final ScriptEngineManager manager = new ScriptEngineManager(); |
sundar@518 | 236 | final ScriptEngine engine = manager.getEngineByName("nashorn"); |
sundar@518 | 237 | |
sundar@518 | 238 | // don't define any function. |
sundar@518 | 239 | try { |
sundar@518 | 240 | engine.eval(""); |
sundar@518 | 241 | } catch (final Exception exp) { |
sundar@518 | 242 | exp.printStackTrace(); |
sundar@518 | 243 | fail(exp.getMessage()); |
sundar@518 | 244 | } |
sundar@518 | 245 | |
sundar@518 | 246 | Runnable runnable = ((Invocable) engine).getInterface(Runnable.class); |
sundar@518 | 247 | if (runnable != null) { |
sundar@518 | 248 | fail("runnable is not null!"); |
sundar@518 | 249 | } |
sundar@518 | 250 | |
sundar@518 | 251 | // now define "run" |
sundar@518 | 252 | try { |
sundar@518 | 253 | engine.eval("function run() { print('this is run function'); }"); |
sundar@518 | 254 | } catch (final Exception exp) { |
sundar@518 | 255 | exp.printStackTrace(); |
sundar@518 | 256 | fail(exp.getMessage()); |
sundar@518 | 257 | } |
sundar@518 | 258 | runnable = ((Invocable) engine).getInterface(Runnable.class); |
sundar@518 | 259 | // should not return null now! |
sundar@518 | 260 | runnable.run(); |
sundar@518 | 261 | |
sundar@518 | 262 | // define only one method of "Foo2" |
sundar@518 | 263 | try { |
sundar@518 | 264 | engine.eval("function bar() { print('bar function'); }"); |
sundar@518 | 265 | } catch (final Exception exp) { |
sundar@518 | 266 | exp.printStackTrace(); |
sundar@518 | 267 | fail(exp.getMessage()); |
sundar@518 | 268 | } |
sundar@518 | 269 | |
sundar@518 | 270 | Foo2 foo2 = ((Invocable) engine).getInterface(Foo2.class); |
sundar@518 | 271 | if (foo2 != null) { |
sundar@518 | 272 | throw new RuntimeException("foo2 is not null!"); |
sundar@518 | 273 | } |
sundar@518 | 274 | |
sundar@518 | 275 | // now define other method of "Foo2" |
sundar@518 | 276 | try { |
sundar@518 | 277 | engine.eval("function bar2() { print('bar2 function'); }"); |
sundar@518 | 278 | } catch (final Exception exp) { |
sundar@518 | 279 | exp.printStackTrace(); |
sundar@518 | 280 | fail(exp.getMessage()); |
sundar@518 | 281 | } |
sundar@518 | 282 | foo2 = ((Invocable) engine).getInterface(Foo2.class); |
sundar@518 | 283 | foo2.bar(); |
sundar@518 | 284 | foo2.bar2(); |
sundar@518 | 285 | } |
sundar@518 | 286 | |
sundar@518 | 287 | @Test |
sundar@518 | 288 | /** |
sundar@518 | 289 | * Try passing non-interface Class object for interface implementation. |
sundar@518 | 290 | */ |
sundar@518 | 291 | public void getNonInterfaceGetInterfaceTest() { |
sundar@518 | 292 | final ScriptEngineManager manager = new ScriptEngineManager(); |
sundar@518 | 293 | final ScriptEngine engine = manager.getEngineByName("nashorn"); |
sundar@518 | 294 | try { |
sundar@518 | 295 | log(Objects.toString(((Invocable) engine).getInterface(Object.class))); |
sundar@518 | 296 | fail("Should have thrown IllegalArgumentException"); |
sundar@518 | 297 | } catch (final Exception exp) { |
sundar@518 | 298 | if (!(exp instanceof IllegalArgumentException)) { |
sundar@518 | 299 | fail("IllegalArgumentException expected, got " + exp); |
sundar@518 | 300 | } |
sundar@518 | 301 | } |
sundar@518 | 302 | } |
sundar@518 | 303 | |
sundar@518 | 304 | @Test |
sundar@518 | 305 | /** |
sundar@518 | 306 | * Check that we can get interface out of a script object even after |
sundar@518 | 307 | * switching to use different ScriptContext. |
sundar@518 | 308 | */ |
sundar@518 | 309 | public void getInterfaceDifferentContext() { |
sundar@518 | 310 | ScriptEngineManager m = new ScriptEngineManager(); |
sundar@518 | 311 | ScriptEngine e = m.getEngineByName("nashorn"); |
sundar@518 | 312 | try { |
sundar@518 | 313 | Object obj = e.eval("({ run: function() { } })"); |
sundar@518 | 314 | |
sundar@518 | 315 | // change script context |
sundar@518 | 316 | ScriptContext ctxt = new SimpleScriptContext(); |
sundar@518 | 317 | ctxt.setBindings(e.createBindings(), ScriptContext.ENGINE_SCOPE); |
sundar@518 | 318 | e.setContext(ctxt); |
sundar@518 | 319 | |
sundar@518 | 320 | Runnable r = ((Invocable) e).getInterface(obj, Runnable.class); |
sundar@518 | 321 | r.run(); |
sundar@518 | 322 | } catch (final Exception exp) { |
sundar@518 | 323 | exp.printStackTrace(); |
sundar@518 | 324 | fail(exp.getMessage()); |
sundar@518 | 325 | } |
sundar@518 | 326 | } |
sundar@518 | 327 | |
sundar@518 | 328 | @Test |
sundar@518 | 329 | /** |
sundar@518 | 330 | * Check that getInterface on non-script object 'thiz' results in |
sundar@518 | 331 | * IllegalArgumentException. |
sundar@518 | 332 | */ |
sundar@518 | 333 | public void getInterfaceNonScriptObjectThizTest() { |
sundar@518 | 334 | final ScriptEngineManager m = new ScriptEngineManager(); |
sundar@518 | 335 | final ScriptEngine e = m.getEngineByName("nashorn"); |
sundar@518 | 336 | |
sundar@518 | 337 | try { |
sundar@518 | 338 | ((Invocable) e).getInterface(new Object(), Runnable.class); |
sundar@518 | 339 | fail("should have thrown IllegalArgumentException"); |
sundar@518 | 340 | } catch (final Exception exp) { |
sundar@518 | 341 | if (!(exp instanceof IllegalArgumentException)) { |
sundar@518 | 342 | exp.printStackTrace(); |
sundar@518 | 343 | fail(exp.getMessage()); |
sundar@518 | 344 | } |
sundar@518 | 345 | } |
sundar@518 | 346 | } |
sundar@518 | 347 | |
sundar@518 | 348 | @Test |
sundar@518 | 349 | /** |
sundar@518 | 350 | * Check that getInterface on null 'thiz' results in |
sundar@518 | 351 | * IllegalArgumentException. |
sundar@518 | 352 | */ |
sundar@518 | 353 | public void getInterfaceNullThizTest() { |
sundar@518 | 354 | final ScriptEngineManager m = new ScriptEngineManager(); |
sundar@518 | 355 | final ScriptEngine e = m.getEngineByName("nashorn"); |
sundar@518 | 356 | |
sundar@518 | 357 | try { |
sundar@518 | 358 | ((Invocable) e).getInterface(null, Runnable.class); |
sundar@518 | 359 | fail("should have thrown IllegalArgumentException"); |
sundar@518 | 360 | } catch (final Exception exp) { |
sundar@518 | 361 | if (!(exp instanceof IllegalArgumentException)) { |
sundar@518 | 362 | exp.printStackTrace(); |
sundar@518 | 363 | fail(exp.getMessage()); |
sundar@518 | 364 | } |
sundar@518 | 365 | } |
sundar@518 | 366 | } |
sundar@518 | 367 | |
sundar@518 | 368 | @Test |
sundar@518 | 369 | /** |
sundar@518 | 370 | * Check that calling getInterface on mirror created by another engine |
sundar@518 | 371 | * results in IllegalArgumentException. |
sundar@518 | 372 | */ |
sundar@518 | 373 | public void getInterfaceMixEnginesTest() { |
sundar@518 | 374 | final ScriptEngineManager m = new ScriptEngineManager(); |
sundar@518 | 375 | final ScriptEngine engine1 = m.getEngineByName("nashorn"); |
sundar@518 | 376 | final ScriptEngine engine2 = m.getEngineByName("nashorn"); |
sundar@518 | 377 | |
sundar@518 | 378 | try { |
sundar@518 | 379 | Object obj = engine1.eval("({ run: function() {} })"); |
sundar@518 | 380 | // pass object from engine1 to engine2 as 'thiz' for getInterface |
sundar@518 | 381 | ((Invocable) engine2).getInterface(obj, Runnable.class); |
sundar@518 | 382 | fail("should have thrown IllegalArgumentException"); |
sundar@518 | 383 | } catch (final Exception exp) { |
sundar@518 | 384 | if (!(exp instanceof IllegalArgumentException)) { |
sundar@518 | 385 | exp.printStackTrace(); |
sundar@518 | 386 | fail(exp.getMessage()); |
sundar@518 | 387 | } |
sundar@518 | 388 | } |
sundar@518 | 389 | } |
sundar@518 | 390 | |
sundar@518 | 391 | @Test |
sundar@518 | 392 | /** |
sundar@518 | 393 | * check that null function name results in NPE. |
sundar@518 | 394 | */ |
sundar@518 | 395 | public void invokeFunctionNullNameTest() { |
sundar@518 | 396 | final ScriptEngineManager m = new ScriptEngineManager(); |
sundar@518 | 397 | final ScriptEngine e = m.getEngineByName("nashorn"); |
sundar@518 | 398 | |
sundar@518 | 399 | try { |
sundar@518 | 400 | final Object res = ((Invocable) e).invokeFunction(null); |
sundar@518 | 401 | fail("should have thrown NPE"); |
sundar@518 | 402 | } catch (final Exception exp) { |
sundar@518 | 403 | if (!(exp instanceof NullPointerException)) { |
sundar@518 | 404 | exp.printStackTrace(); |
sundar@518 | 405 | fail(exp.getMessage()); |
sundar@518 | 406 | } |
sundar@518 | 407 | } |
sundar@518 | 408 | } |
sundar@518 | 409 | |
sundar@518 | 410 | @Test |
sundar@518 | 411 | /** |
sundar@518 | 412 | * Check that attempt to call missing function results in |
sundar@518 | 413 | * NoSuchMethodException. |
sundar@518 | 414 | */ |
sundar@518 | 415 | public void invokeFunctionMissingTest() { |
sundar@518 | 416 | final ScriptEngineManager m = new ScriptEngineManager(); |
sundar@518 | 417 | final ScriptEngine e = m.getEngineByName("nashorn"); |
sundar@518 | 418 | |
sundar@518 | 419 | try { |
sundar@518 | 420 | final Object res = ((Invocable) e).invokeFunction("NonExistentFunc"); |
sundar@518 | 421 | fail("should have thrown NoSuchMethodException"); |
sundar@518 | 422 | } catch (final Exception exp) { |
sundar@518 | 423 | if (!(exp instanceof NoSuchMethodException)) { |
sundar@518 | 424 | exp.printStackTrace(); |
sundar@518 | 425 | fail(exp.getMessage()); |
sundar@518 | 426 | } |
sundar@518 | 427 | } |
sundar@518 | 428 | } |
sundar@518 | 429 | |
sundar@518 | 430 | @Test |
sundar@518 | 431 | /** |
sundar@518 | 432 | * Check that invokeFunction calls functions only from current context's |
sundar@518 | 433 | * Bindings. |
sundar@518 | 434 | */ |
sundar@518 | 435 | public void invokeFunctionDifferentContextTest() { |
sundar@518 | 436 | ScriptEngineManager m = new ScriptEngineManager(); |
sundar@518 | 437 | ScriptEngine e = m.getEngineByName("nashorn"); |
sundar@518 | 438 | |
sundar@518 | 439 | try { |
sundar@518 | 440 | // define an object with method on it |
sundar@518 | 441 | Object obj = e.eval("function hello() { return 'Hello World!'; }"); |
sundar@518 | 442 | final ScriptContext ctxt = new SimpleScriptContext(); |
sundar@518 | 443 | ctxt.setBindings(e.createBindings(), ScriptContext.ENGINE_SCOPE); |
sundar@518 | 444 | // change engine's current context |
sundar@518 | 445 | e.setContext(ctxt); |
sundar@518 | 446 | |
sundar@518 | 447 | ((Invocable) e).invokeFunction("hello"); // no 'hello' in new context! |
sundar@518 | 448 | fail("should have thrown NoSuchMethodException"); |
sundar@518 | 449 | } catch (final Exception exp) { |
sundar@518 | 450 | if (!(exp instanceof NoSuchMethodException)) { |
sundar@518 | 451 | exp.printStackTrace(); |
sundar@518 | 452 | fail(exp.getMessage()); |
sundar@518 | 453 | } |
sundar@518 | 454 | } |
sundar@518 | 455 | } |
sundar@518 | 456 | |
sundar@518 | 457 | @Test |
sundar@518 | 458 | public void invokeFunctionExceptionTest() { |
sundar@518 | 459 | final ScriptEngineManager m = new ScriptEngineManager(); |
sundar@518 | 460 | final ScriptEngine e = m.getEngineByName("nashorn"); |
sundar@518 | 461 | try { |
sundar@518 | 462 | e.eval("function func() { throw new TypeError(); }"); |
sundar@518 | 463 | } catch (final Throwable t) { |
sundar@518 | 464 | t.printStackTrace(); |
sundar@518 | 465 | fail(t.getMessage()); |
sundar@518 | 466 | } |
sundar@518 | 467 | |
sundar@518 | 468 | try { |
sundar@518 | 469 | ((Invocable) e).invokeFunction("func"); |
sundar@518 | 470 | fail("should have thrown exception"); |
sundar@518 | 471 | } catch (final ScriptException se) { |
sundar@518 | 472 | // ECMA TypeError property wrapped as a ScriptException |
sundar@518 | 473 | log("got " + se + " as expected"); |
sundar@518 | 474 | } catch (final Throwable t) { |
sundar@518 | 475 | t.printStackTrace(); |
sundar@518 | 476 | fail(t.getMessage()); |
sundar@518 | 477 | } |
sundar@518 | 478 | } |
sundar@518 | 479 | |
sundar@518 | 480 | @Test |
sundar@518 | 481 | public void invokeMethodExceptionTest() { |
sundar@518 | 482 | final ScriptEngineManager m = new ScriptEngineManager(); |
sundar@518 | 483 | final ScriptEngine e = m.getEngineByName("nashorn"); |
sundar@518 | 484 | try { |
sundar@518 | 485 | e.eval("var sobj = {}; sobj.foo = function func() { throw new TypeError(); }"); |
sundar@518 | 486 | } catch (final Throwable t) { |
sundar@518 | 487 | t.printStackTrace(); |
sundar@518 | 488 | fail(t.getMessage()); |
sundar@518 | 489 | } |
sundar@518 | 490 | |
sundar@518 | 491 | try { |
sundar@518 | 492 | final Object sobj = e.get("sobj"); |
sundar@518 | 493 | ((Invocable) e).invokeMethod(sobj, "foo"); |
sundar@518 | 494 | fail("should have thrown exception"); |
sundar@518 | 495 | } catch (final ScriptException se) { |
sundar@518 | 496 | // ECMA TypeError property wrapped as a ScriptException |
sundar@518 | 497 | log("got " + se + " as expected"); |
sundar@518 | 498 | } catch (final Throwable t) { |
sundar@518 | 499 | t.printStackTrace(); |
sundar@518 | 500 | fail(t.getMessage()); |
sundar@518 | 501 | } |
sundar@518 | 502 | } |
sundar@518 | 503 | |
sundar@518 | 504 | @Test |
sundar@518 | 505 | /** |
sundar@518 | 506 | * Tests whether invocation of a JavaScript method through a variable arity |
sundar@518 | 507 | * Java method will pass the vararg array. Both non-vararg and vararg |
sundar@518 | 508 | * JavaScript methods are tested. |
sundar@518 | 509 | * |
sundar@518 | 510 | * @throws ScriptException |
sundar@518 | 511 | */ |
sundar@518 | 512 | public void variableArityInterfaceTest() throws ScriptException { |
sundar@518 | 513 | final ScriptEngineManager m = new ScriptEngineManager(); |
sundar@518 | 514 | final ScriptEngine e = m.getEngineByName("nashorn"); |
sundar@518 | 515 | e.eval( |
sundar@518 | 516 | "function test1(i, strings) {" |
sundar@518 | 517 | + " return 'i == ' + i + ', strings instanceof java.lang.String[] == ' + (strings instanceof Java.type('java.lang.String[]')) + ', strings == ' + java.util.Arrays.toString(strings)" |
sundar@518 | 518 | + "}" |
sundar@518 | 519 | + "function test2() {" |
sundar@518 | 520 | + " return 'arguments[0] == ' + arguments[0] + ', arguments[1] instanceof java.lang.String[] == ' + (arguments[1] instanceof Java.type('java.lang.String[]')) + ', arguments[1] == ' + java.util.Arrays.toString(arguments[1])" |
sundar@518 | 521 | + "}"); |
sundar@518 | 522 | final VariableArityTestInterface itf = ((Invocable) e).getInterface(VariableArityTestInterface.class); |
sundar@518 | 523 | Assert.assertEquals(itf.test1(42, "a", "b"), "i == 42, strings instanceof java.lang.String[] == true, strings == [a, b]"); |
sundar@518 | 524 | Assert.assertEquals(itf.test2(44, "c", "d", "e"), "arguments[0] == 44, arguments[1] instanceof java.lang.String[] == true, arguments[1] == [c, d, e]"); |
sundar@518 | 525 | } |
sundar@755 | 526 | |
sundar@755 | 527 | @Test |
sundar@755 | 528 | @SuppressWarnings("unchecked") |
sundar@755 | 529 | public void defaultMethodTest() throws ScriptException { |
sundar@755 | 530 | final ScriptEngineManager m = new ScriptEngineManager(); |
sundar@755 | 531 | final ScriptEngine e = m.getEngineByName("nashorn"); |
sundar@755 | 532 | final Invocable inv = (Invocable) e; |
sundar@755 | 533 | |
sundar@755 | 534 | Object obj = e.eval("({ apply: function(arg) { return arg.toUpperCase(); }})"); |
sundar@755 | 535 | Function<String, String> func = inv.getInterface(obj, Function.class); |
sundar@755 | 536 | assertEquals(func.apply("hello"), "HELLO"); |
sundar@755 | 537 | } |
sundar@518 | 538 | } |