1 /* 2 * Copyright (c) 2010, 2013, Oracle and/or its affiliates. All rights reserved. 3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. 4 * 5 * This code is free software; you can redistribute it and/or modify it 6 * under the terms of the GNU General Public License version 2 only, as 7 * published by the Free Software Foundation. Oracle designates this 8 * particular file as subject to the "Classpath" exception as provided 9 * by Oracle in the LICENSE file that accompanied this code. 10 * 11 * This code is distributed in the hope that it will be useful, but WITHOUT 12 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 13 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License 14 * version 2 for more details (a copy is included in the LICENSE file that 15 * accompanied this code). 16 * 17 * You should have received a copy of the GNU General Public License version 18 * 2 along with this work; if not, write to the Free Software Foundation, 19 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. 20 * 21 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA 22 * or visit www.oracle.com if you need additional information or have any 23 * questions. 24 */ 25 26 package jdk.nashorn.api.scripting; 27 28 import static org.testng.Assert.assertEquals; 29 import static org.testng.Assert.assertFalse; 30 import static org.testng.Assert.assertNotNull; 31 import static org.testng.Assert.assertTrue; 32 import static org.testng.Assert.fail; 33 34 import java.io.StringReader; 35 import java.io.StringWriter; 36 import java.lang.reflect.Method; 37 import java.util.HashMap; 38 import java.util.Map; 39 import java.util.Objects; 40 import java.util.concurrent.Callable; 41 import javax.script.Bindings; 42 import javax.script.Compilable; 43 import javax.script.CompiledScript; 44 import javax.script.Invocable; 45 import javax.script.ScriptContext; 46 import javax.script.ScriptEngine; 47 import javax.script.ScriptEngineFactory; 48 import javax.script.ScriptEngineManager; 49 import javax.script.ScriptException; 50 import javax.script.SimpleScriptContext; 51 import org.testng.Assert; 52 import org.testng.annotations.Test; 53 54 /** 55 * Tests for JSR-223 script engine for Nashorn. 56 * 57 * @test 58 * @build jdk.nashorn.api.scripting.Window jdk.nashorn.api.scripting.WindowEventHandler jdk.nashorn.api.scripting.VariableArityTestInterface jdk.nashorn.api.scripting.ScriptEngineTest 59 * @run testng jdk.nashorn.api.scripting.ScriptEngineTest 60 */ 61 public class ScriptEngineTest { 62 63 private void log(String msg) { 64 org.testng.Reporter.log(msg, true); 65 } 66 67 @Test 68 public void argumentsTest() { 69 final ScriptEngineManager m = new ScriptEngineManager(); 70 final ScriptEngine e = m.getEngineByName("nashorn"); 71 72 String[] args = new String[] { "hello", "world" }; 73 try { 74 e.put("arguments", args); 75 Object arg0 = e.eval("arguments[0]"); 76 Object arg1 = e.eval("arguments[1]"); 77 assertEquals(args[0], arg0); 78 assertEquals(args[1], arg1); 79 } catch (final Exception exp) { 80 exp.printStackTrace(); 81 fail(exp.getMessage()); 82 } 83 } 84 85 @Test 86 public void argumentsWithTest() { 87 final ScriptEngineManager m = new ScriptEngineManager(); 88 final ScriptEngine e = m.getEngineByName("nashorn"); 89 90 String[] args = new String[] { "hello", "world" }; 91 try { 92 e.put("arguments", args); 93 Object arg0 = e.eval("var imports = new JavaImporter(java.io); " + 94 " with(imports) { arguments[0] }"); 95 Object arg1 = e.eval("var imports = new JavaImporter(java.util, java.io); " + 96 " with(imports) { arguments[1] }"); 97 assertEquals(args[0], arg0); 98 assertEquals(args[1], arg1); 99 } catch (final Exception exp) { 100 exp.printStackTrace(); 101 fail(exp.getMessage()); 102 } 103 } 104 105 @Test 106 public void argumentsEmptyTest() { 107 final ScriptEngineManager m = new ScriptEngineManager(); 108 final ScriptEngine e = m.getEngineByName("nashorn"); 109 110 try { 111 assertEquals(e.eval("arguments instanceof Array"), true); 112 assertEquals(e.eval("arguments.length == 0"), true); 113 } catch (final Exception exp) { 114 exp.printStackTrace(); 115 fail(exp.getMessage()); 116 } 117 } 118 119 @Test 120 public void factoryTests() { 121 final ScriptEngineManager m = new ScriptEngineManager(); 122 final ScriptEngine e = m.getEngineByName("nashorn"); 123 assertNotNull(e); 124 125 final ScriptEngineFactory fac = e.getFactory(); 126 127 assertEquals(fac.getLanguageName(), "ECMAScript"); 128 assertEquals(fac.getParameter(ScriptEngine.NAME), "javascript"); 129 assertEquals(fac.getLanguageVersion(), "ECMA - 262 Edition 5.1"); 130 assertEquals(fac.getEngineName(), "Oracle Nashorn"); 131 assertEquals(fac.getOutputStatement("context"), "print(context)"); 132 assertEquals(fac.getProgram("print('hello')", "print('world')"), "print('hello');print('world');"); 133 assertEquals(fac.getParameter(ScriptEngine.NAME), "javascript"); 134 135 boolean seenJS = false; 136 for (String ext : fac.getExtensions()) { 137 if (ext.equals("js")) { 138 seenJS = true; 139 } 140 } 141 142 assertEquals(seenJS, true); 143 String str = fac.getMethodCallSyntax("obj", "foo", "x"); 144 assertEquals(str, "obj.foo(x)"); 145 146 boolean seenNashorn = false, seenJavaScript = false, seenECMAScript = false; 147 for (String name : fac.getNames()) { 148 switch (name) { 149 case "nashorn": seenNashorn = true; break; 150 case "javascript": seenJavaScript = true; break; 151 case "ECMAScript": seenECMAScript = true; break; 152 } 153 } 154 155 assertTrue(seenNashorn); 156 assertTrue(seenJavaScript); 157 assertTrue(seenECMAScript); 158 159 boolean seenAppJS = false, seenAppECMA = false, seenTextJS = false, seenTextECMA = false; 160 for (String mime : fac.getMimeTypes()) { 161 switch (mime) { 162 case "application/javascript": seenAppJS = true; break; 163 case "application/ecmascript": seenAppECMA = true; break; 164 case "text/javascript": seenTextJS = true; break; 165 case "text/ecmascript": seenTextECMA = true; break; 166 } 167 } 168 169 assertTrue(seenAppJS); 170 assertTrue(seenAppECMA); 171 assertTrue(seenTextJS); 172 assertTrue(seenTextECMA); 173 } 174 175 @Test 176 public void evalTests() { 177 final ScriptEngineManager m = new ScriptEngineManager(); 178 final ScriptEngine e = m.getEngineByName("nashorn"); 179 e.put(ScriptEngine.FILENAME, "myfile.js"); 180 181 try { 182 e.eval("print('hello')"); 183 } catch (final ScriptException se) { 184 fail(se.getMessage()); 185 } 186 try { 187 e.eval("print('hello)"); 188 fail("script exception expected"); 189 } catch (final ScriptException se) { 190 assertEquals(se.getLineNumber(), 1); 191 assertEquals(se.getColumnNumber(), 13); 192 assertEquals(se.getFileName(), "myfile.js"); 193 // se.printStackTrace(); 194 } 195 196 try { 197 Object obj = e.eval("34 + 41"); 198 assertTrue(34.0 + 41.0 == ((Number)obj).doubleValue()); 199 obj = e.eval("x = 5"); 200 assertTrue(5.0 == ((Number)obj).doubleValue()); 201 } catch (final ScriptException se) { 202 se.printStackTrace(); 203 fail(se.getMessage()); 204 } 205 } 206 207 @Test 208 public void compileTests() { 209 final ScriptEngineManager m = new ScriptEngineManager(); 210 final ScriptEngine e = m.getEngineByName("nashorn"); 211 CompiledScript script = null; 212 213 try { 214 script = ((Compilable)e).compile("print('hello')"); 215 } catch (final ScriptException se) { 216 fail(se.getMessage()); 217 } 218 219 try { 220 script.eval(); 221 } catch (final ScriptException | NullPointerException se) { 222 se.printStackTrace(); 223 fail(se.getMessage()); 224 } 225 226 // try to compile from a Reader 227 try { 228 script = ((Compilable)e).compile(new StringReader("print('world')")); 229 } catch (final ScriptException se) { 230 fail(se.getMessage()); 231 } 232 233 try { 234 script.eval(); 235 } catch (final ScriptException | NullPointerException se) { 236 se.printStackTrace(); 237 fail(se.getMessage()); 238 } 239 } 240 241 @Test 242 public void createBindingsTest() { 243 final ScriptEngineManager m = new ScriptEngineManager(); 244 final ScriptEngine e = m.getEngineByName("nashorn"); 245 Bindings b = e.createBindings(); 246 b.put("foo", 42.0); 247 Object res = null; 248 try { 249 res = e.eval("foo == 42.0", b); 250 } catch (final ScriptException | NullPointerException se) { 251 se.printStackTrace(); 252 fail(se.getMessage()); 253 } 254 255 assertEquals(res, Boolean.TRUE); 256 } 257 258 @Test 259 public void getInterfaceTest() { 260 final ScriptEngineManager m = new ScriptEngineManager(); 261 final ScriptEngine e = m.getEngineByName("nashorn"); 262 final Invocable inv = (Invocable)e; 263 264 // try to get interface from global functions 265 try { 266 e.eval("function run() { print('run'); };"); 267 final Runnable runnable = inv.getInterface(Runnable.class); 268 runnable.run(); 269 } catch (final Exception exp) { 270 exp.printStackTrace(); 271 fail(exp.getMessage()); 272 } 273 274 // try interface on specific script object 275 try { 276 e.eval("var obj = { run: function() { print('run from obj'); } };"); 277 Object obj = e.get("obj"); 278 final Runnable runnable = inv.getInterface(obj, Runnable.class); 279 runnable.run(); 280 } catch (final Exception exp) { 281 exp.printStackTrace(); 282 fail(exp.getMessage()); 283 } 284 } 285 286 public interface Foo { 287 public void bar(); 288 } 289 290 public interface Foo2 extends Foo { 291 public void bar2(); 292 } 293 294 @Test 295 public void getInterfaceMissingTest() { 296 final ScriptEngineManager manager = new ScriptEngineManager(); 297 final ScriptEngine engine = manager.getEngineByName("nashorn"); 298 299 // don't define any function. 300 try { 301 engine.eval(""); 302 } catch (final Exception exp) { 303 exp.printStackTrace(); 304 fail(exp.getMessage()); 305 } 306 307 Runnable runnable = ((Invocable)engine).getInterface(Runnable.class); 308 if (runnable != null) { 309 fail("runnable is not null!"); 310 } 311 312 // now define "run" 313 try { 314 engine.eval("function run() { print('this is run function'); }"); 315 } catch (final Exception exp) { 316 exp.printStackTrace(); 317 fail(exp.getMessage()); 318 } 319 runnable = ((Invocable)engine).getInterface(Runnable.class); 320 // should not return null now! 321 runnable.run(); 322 323 // define only one method of "Foo2" 324 try { 325 engine.eval("function bar() { print('bar function'); }"); 326 } catch (final Exception exp) { 327 exp.printStackTrace(); 328 fail(exp.getMessage()); 329 } 330 331 Foo2 foo2 = ((Invocable)engine).getInterface(Foo2.class); 332 if (foo2 != null) { 333 throw new RuntimeException("foo2 is not null!"); 334 } 335 336 // now define other method of "Foo2" 337 try { 338 engine.eval("function bar2() { print('bar2 function'); }"); 339 } catch (final Exception exp) { 340 exp.printStackTrace(); 341 fail(exp.getMessage()); 342 } 343 foo2 = ((Invocable)engine).getInterface(Foo2.class); 344 foo2.bar(); 345 foo2.bar2(); 346 } 347 348 @Test 349 /** 350 * Try passing non-interface Class object for interface implementation. 351 */ 352 public void getNonInterfaceGetInterfaceTest() { 353 final ScriptEngineManager manager = new ScriptEngineManager(); 354 final ScriptEngine engine = manager.getEngineByName("nashorn"); 355 try { 356 log(Objects.toString(((Invocable)engine).getInterface(Object.class))); 357 fail("Should have thrown IllegalArgumentException"); 358 } catch (final Exception exp) { 359 if (! (exp instanceof IllegalArgumentException)) { 360 fail("IllegalArgumentException expected, got " + exp); 361 } 362 } 363 } 364 365 @Test 366 /** 367 * Check that we can get interface out of a script object even after 368 * switching to use different ScriptContext. 369 */ 370 public void getInterfaceDifferentContext() { 371 ScriptEngineManager m = new ScriptEngineManager(); 372 ScriptEngine e = m.getEngineByName("nashorn"); 373 try { 374 Object obj = e.eval("({ run: function() { } })"); 375 376 // change script context 377 ScriptContext ctxt = new SimpleScriptContext(); 378 ctxt.setBindings(e.createBindings(), ScriptContext.ENGINE_SCOPE); 379 e.setContext(ctxt); 380 381 Runnable r = ((Invocable)e).getInterface(obj, Runnable.class); 382 r.run(); 383 }catch (final Exception exp) { 384 exp.printStackTrace(); 385 fail(exp.getMessage()); 386 } 387 } 388 389 @Test 390 /** 391 * Check that getInterface on non-script object 'thiz' results in IllegalArgumentException. 392 */ 393 public void getInterfaceNonScriptObjectThizTest() { 394 final ScriptEngineManager m = new ScriptEngineManager(); 395 final ScriptEngine e = m.getEngineByName("nashorn"); 396 397 try { 398 ((Invocable)e).getInterface(new Object(), Runnable.class); 399 fail("should have thrown IllegalArgumentException"); 400 } catch (final Exception exp) { 401 if (! (exp instanceof IllegalArgumentException)) { 402 exp.printStackTrace(); 403 fail(exp.getMessage()); 404 } 405 } 406 } 407 408 @Test 409 /** 410 * Check that getInterface on null 'thiz' results in IllegalArgumentException. 411 */ 412 public void getInterfaceNullThizTest() { 413 final ScriptEngineManager m = new ScriptEngineManager(); 414 final ScriptEngine e = m.getEngineByName("nashorn"); 415 416 try { 417 ((Invocable)e).getInterface(null, Runnable.class); 418 fail("should have thrown IllegalArgumentException"); 419 } catch (final Exception exp) { 420 if (! (exp instanceof IllegalArgumentException)) { 421 exp.printStackTrace(); 422 fail(exp.getMessage()); 423 } 424 } 425 } 426 427 @Test 428 /** 429 * Check that calling getInterface on mirror created by another engine results in IllegalArgumentException. 430 */ 431 public void getInterfaceMixEnginesTest() { 432 final ScriptEngineManager m = new ScriptEngineManager(); 433 final ScriptEngine engine1 = m.getEngineByName("nashorn"); 434 final ScriptEngine engine2 = m.getEngineByName("nashorn"); 435 436 try { 437 Object obj = engine1.eval("({ run: function() {} })"); 438 // pass object from engine1 to engine2 as 'thiz' for getInterface 439 ((Invocable)engine2).getInterface(obj, Runnable.class); 440 fail("should have thrown IllegalArgumentException"); 441 } catch (final Exception exp) { 442 if (! (exp instanceof IllegalArgumentException)) { 443 exp.printStackTrace(); 444 fail(exp.getMessage()); 445 } 446 } 447 } 448 449 @Test 450 public void accessGlobalTest() { 451 final ScriptEngineManager m = new ScriptEngineManager(); 452 final ScriptEngine e = m.getEngineByName("nashorn"); 453 454 try { 455 e.eval("var x = 'hello'"); 456 assertEquals(e.get("x"), "hello"); 457 } catch (final ScriptException exp) { 458 exp.printStackTrace(); 459 fail(exp.getMessage()); 460 } 461 } 462 463 @Test 464 public void exposeGlobalTest() { 465 final ScriptEngineManager m = new ScriptEngineManager(); 466 final ScriptEngine e = m.getEngineByName("nashorn"); 467 468 try { 469 e.put("y", "foo"); 470 e.eval("print(y)"); 471 } catch (final ScriptException exp) { 472 exp.printStackTrace(); 473 fail(exp.getMessage()); 474 } 475 } 476 477 @Test 478 public void putGlobalFunctionTest() { 479 final ScriptEngineManager m = new ScriptEngineManager(); 480 final ScriptEngine e = m.getEngineByName("nashorn"); 481 482 e.put("callable", new Callable<String>() { 483 @Override 484 public String call() throws Exception { 485 return "callable was called"; 486 } 487 }); 488 489 try { 490 e.eval("print(callable.call())"); 491 } catch (final ScriptException exp) { 492 exp.printStackTrace(); 493 fail(exp.getMessage()); 494 } 495 } 496 497 @Test 498 public void windowAlertTest() { 499 final ScriptEngineManager m = new ScriptEngineManager(); 500 final ScriptEngine e = m.getEngineByName("nashorn"); 501 final Window window = new Window(); 502 503 try { 504 e.put("window", window); 505 e.eval("print(window.alert)"); 506 e.eval("window.alert('calling window.alert...')"); 507 } catch (final Exception exp) { 508 exp.printStackTrace(); 509 fail(exp.getMessage()); 510 } 511 } 512 513 @Test 514 public void windowLocationTest() { 515 final ScriptEngineManager m = new ScriptEngineManager(); 516 final ScriptEngine e = m.getEngineByName("nashorn"); 517 final Window window = new Window(); 518 519 try { 520 e.put("window", window); 521 e.eval("print(window.location)"); 522 final Object locationValue = e.eval("window.getLocation()"); 523 assertEquals(locationValue, "http://localhost:8080/window"); 524 } catch (final Exception exp) { 525 exp.printStackTrace(); 526 fail(exp.getMessage()); 527 } 528 } 529 530 @Test 531 public void windowItemTest() { 532 final ScriptEngineManager m = new ScriptEngineManager(); 533 final ScriptEngine e = m.getEngineByName("nashorn"); 534 final Window window = new Window(); 535 536 try { 537 e.put("window", window); 538 final String item1 = (String)e.eval("window.item(65535)"); 539 assertEquals(item1, "ffff"); 540 final String item2 = (String)e.eval("window.item(255)"); 541 assertEquals(item2, "ff"); 542 } catch (final Exception exp) { 543 exp.printStackTrace(); 544 fail(exp.getMessage()); 545 } 546 } 547 548 @Test 549 public void windowEventTest() { 550 final ScriptEngineManager m = new ScriptEngineManager(); 551 final ScriptEngine e = m.getEngineByName("nashorn"); 552 final Window window = new Window(); 553 554 try { 555 e.put("window", window); 556 e.eval("window.onload = function() { print('window load event fired'); return true }"); 557 assertTrue((Boolean)e.eval("window.onload.loaded()")); 558 final WindowEventHandler handler = window.getOnload(); 559 assertNotNull(handler); 560 assertTrue(handler.loaded()); 561 } catch (final Exception exp) { 562 exp.printStackTrace(); 563 fail(exp.getMessage()); 564 } 565 } 566 567 @Test 568 public void throwTest() { 569 final ScriptEngineManager m = new ScriptEngineManager(); 570 final ScriptEngine e = m.getEngineByName("nashorn"); 571 e.put(ScriptEngine.FILENAME, "throwtest.js"); 572 573 try { 574 e.eval("throw 'foo'"); 575 } catch (final ScriptException exp) { 576 log(exp.getMessage()); 577 assertEquals(exp.getMessage(), "foo in throwtest.js at line number 1 at column number 0"); 578 assertEquals(exp.getFileName(), "throwtest.js"); 579 assertEquals(exp.getLineNumber(), 1); 580 } 581 } 582 583 @Test 584 public void setTimeoutTest() { 585 final ScriptEngineManager m = new ScriptEngineManager(); 586 final ScriptEngine e = m.getEngineByName("nashorn"); 587 final Window window = new Window(); 588 589 try { 590 final Class<?> setTimeoutParamTypes[] = { Window.class, String.class, int.class }; 591 final Method setTimeout = Window.class.getDeclaredMethod("setTimeout", setTimeoutParamTypes); 592 assertNotNull(setTimeout); 593 e.put("window", window); 594 e.eval("window.setTimeout('foo()', 100)"); 595 596 // try to make setTimeout global 597 e.put("setTimeout", setTimeout); 598 // TODO: java.lang.ClassCastException: required class 599 // java.lang.Integer but encountered class java.lang.Double 600 // e.eval("setTimeout('foo2()', 200)"); 601 } catch (final Exception exp) { 602 exp.printStackTrace(); 603 fail(exp.getMessage()); 604 } 605 } 606 607 @Test 608 public void setWriterTest() { 609 final ScriptEngineManager m = new ScriptEngineManager(); 610 final ScriptEngine e = m.getEngineByName("nashorn"); 611 final StringWriter sw = new StringWriter(); 612 e.getContext().setWriter(sw); 613 614 try { 615 e.eval("print('hello world')"); 616 } catch (final Exception exp) { 617 exp.printStackTrace(); 618 fail(exp.getMessage()); 619 } 620 // dos2unix - fix line endings if running on windows 621 assertEquals(sw.toString().replaceAll("\r", ""), "hello world\n"); 622 } 623 624 @SuppressWarnings("unchecked") 625 @Test 626 public void reflectionTest() throws ScriptException { 627 final ScriptEngineManager m = new ScriptEngineManager(); 628 final ScriptEngine e = m.getEngineByName("nashorn"); 629 630 e.eval("var obj = { x: 344, y: 'nashorn' }"); 631 632 int count = 0; 633 Map<Object, Object> map = (Map<Object, Object>)e.get("obj"); 634 assertFalse(map.isEmpty()); 635 assertTrue(map.keySet().contains("x")); 636 assertTrue(map.containsKey("x")); 637 assertTrue(map.values().contains("nashorn")); 638 assertTrue(map.containsValue("nashorn")); 639 for (final Map.Entry<?, ?> ex : map.entrySet()) { 640 final Object key = ex.getKey(); 641 if (key.equals("x")) { 642 assertTrue(344 == ((Number)ex.getValue()).doubleValue()); 643 count++; 644 } else if (key.equals("y")) { 645 assertEquals(ex.getValue(), "nashorn"); 646 count++; 647 } 648 } 649 assertEquals(2, count); 650 assertEquals(2, map.size()); 651 652 // add property 653 map.put("z", "hello"); 654 assertEquals(e.eval("obj.z"), "hello"); 655 assertEquals(map.get("z"), "hello"); 656 assertTrue(map.keySet().contains("z")); 657 assertTrue(map.containsKey("z")); 658 assertTrue(map.values().contains("hello")); 659 assertTrue(map.containsValue("hello")); 660 assertEquals(map.size(), 3); 661 662 final Map<Object, Object> newMap = new HashMap<>(); 663 newMap.put("foo", 23.0); 664 newMap.put("bar", true); 665 map.putAll(newMap); 666 667 assertEquals(e.eval("obj.foo"), 23.0); 668 assertEquals(e.eval("obj.bar"), true); 669 670 // remove using map method 671 map.remove("foo"); 672 assertEquals(e.eval("typeof obj.foo"), "undefined"); 673 674 count = 0; 675 e.eval("var arr = [ true, 'hello' ]"); 676 map = (Map<Object, Object>)e.get("arr"); 677 assertFalse(map.isEmpty()); 678 assertTrue(map.containsKey("length")); 679 assertTrue(map.containsValue("hello")); 680 for (final Map.Entry<?, ?> ex : map.entrySet()) { 681 final Object key = ex.getKey(); 682 if (key.equals("0")) { 683 assertEquals(ex.getValue(), Boolean.TRUE); 684 count++; 685 } else if (key.equals("1")) { 686 assertEquals(ex.getValue(), "hello"); 687 count++; 688 } 689 } 690 assertEquals(count, 2); 691 assertEquals(map.size(), 2); 692 693 // add element 694 map.put("2", "world"); 695 assertEquals(map.get("2"), "world"); 696 assertEquals(map.size(), 3); 697 698 // remove all 699 map.clear(); 700 assertTrue(map.isEmpty()); 701 assertEquals(e.eval("typeof arr[0]"), "undefined"); 702 assertEquals(e.eval("typeof arr[1]"), "undefined"); 703 assertEquals(e.eval("typeof arr[2]"), "undefined"); 704 } 705 706 @Test 707 public void redefineEchoTest() { 708 final ScriptEngineManager m = new ScriptEngineManager(); 709 final ScriptEngine e = m.getEngineByName("nashorn"); 710 711 try { 712 e.eval("var echo = {}; if (typeof echo !== 'object') { throw 'echo is a '+typeof echo; }"); 713 } catch (final Exception exp) { 714 exp.printStackTrace(); 715 fail(exp.getMessage()); 716 } 717 } 718 719 @Test 720 public void invokeMethodTest() { 721 final ScriptEngineManager m = new ScriptEngineManager(); 722 final ScriptEngine e = m.getEngineByName("nashorn"); 723 724 try { 725 e.eval("var Example = function() { this.hello = function() { return 'Hello World!'; };}; myExample = new Example();"); 726 final Object obj = e.get("myExample"); 727 final Object res = ((Invocable)e).invokeMethod(obj, "hello"); 728 assertEquals(res, "Hello World!"); 729 } catch (final Exception exp) { 730 exp.printStackTrace(); 731 fail(exp.getMessage()); 732 } 733 } 734 735 @Test 736 /** 737 * Check that we can call invokeMethod on an object that we got by evaluating 738 * script with different Context set. 739 */ 740 public void invokeMethodDifferentContextTest() { 741 ScriptEngineManager m = new ScriptEngineManager(); 742 ScriptEngine e = m.getEngineByName("nashorn"); 743 744 try { 745 // define an object with method on it 746 Object obj = e.eval("({ hello: function() { return 'Hello World!'; } })"); 747 748 final ScriptContext ctxt = new SimpleScriptContext(); 749 ctxt.setBindings(e.createBindings(), ScriptContext.ENGINE_SCOPE); 750 e.setContext(ctxt); 751 752 // invoke 'func' on obj - but with current script context changed 753 final Object res = ((Invocable)e).invokeMethod(obj, "hello"); 754 assertEquals(res, "Hello World!"); 755 } catch (final Exception exp) { 756 exp.printStackTrace(); 757 fail(exp.getMessage()); 758 } 759 } 760 761 @Test 762 /** 763 * Check that invokeMethod throws NPE on null method name. 764 */ 765 public void invokeMethodNullNameTest() { 766 final ScriptEngineManager m = new ScriptEngineManager(); 767 final ScriptEngine e = m.getEngineByName("nashorn"); 768 769 try { 770 final Object obj = e.eval("({})"); 771 final Object res = ((Invocable)e).invokeMethod(obj, null); 772 fail("should have thrown NPE"); 773 } catch (final Exception exp) { 774 if (! (exp instanceof NullPointerException)) { 775 exp.printStackTrace(); 776 fail(exp.getMessage()); 777 } 778 } 779 } 780 781 @Test 782 /** 783 * Check that invokeMethod throws NoSuchMethodException on missing method. 784 */ 785 public void invokeMethodMissingTest() { 786 final ScriptEngineManager m = new ScriptEngineManager(); 787 final ScriptEngine e = m.getEngineByName("nashorn"); 788 789 try { 790 final Object obj = e.eval("({})"); 791 final Object res = ((Invocable)e).invokeMethod(obj, "nonExistentMethod"); 792 fail("should have thrown NoSuchMethodException"); 793 } catch (final Exception exp) { 794 if (! (exp instanceof NoSuchMethodException)) { 795 exp.printStackTrace(); 796 fail(exp.getMessage()); 797 } 798 } 799 } 800 801 @Test 802 /** 803 * Check that calling method on non-script object 'thiz' results in IllegalArgumentException. 804 */ 805 public void invokeMethodNonScriptObjectThizTest() { 806 final ScriptEngineManager m = new ScriptEngineManager(); 807 final ScriptEngine e = m.getEngineByName("nashorn"); 808 809 try { 810 ((Invocable)e).invokeMethod(new Object(), "toString"); 811 fail("should have thrown IllegalArgumentException"); 812 } catch (final Exception exp) { 813 if (! (exp instanceof IllegalArgumentException)) { 814 exp.printStackTrace(); 815 fail(exp.getMessage()); 816 } 817 } 818 } 819 820 @Test 821 /** 822 * Check that calling method on null 'thiz' results in IllegalArgumentException. 823 */ 824 public void invokeMethodNullThizTest() { 825 final ScriptEngineManager m = new ScriptEngineManager(); 826 final ScriptEngine e = m.getEngineByName("nashorn"); 827 828 try { 829 ((Invocable)e).invokeMethod(null, "toString"); 830 fail("should have thrown IllegalArgumentException"); 831 } catch (final Exception exp) { 832 if (! (exp instanceof IllegalArgumentException)) { 833 exp.printStackTrace(); 834 fail(exp.getMessage()); 835 } 836 } 837 } 838 839 840 @Test 841 /** 842 * Check that calling method on mirror created by another engine results in IllegalArgumentException. 843 */ 844 public void invokeMethodMixEnginesTest() { 845 final ScriptEngineManager m = new ScriptEngineManager(); 846 final ScriptEngine engine1 = m.getEngineByName("nashorn"); 847 final ScriptEngine engine2 = m.getEngineByName("nashorn"); 848 849 try { 850 Object obj = engine1.eval("({ run: function() {} })"); 851 // pass object from engine1 to engine2 as 'thiz' for invokeMethod 852 ((Invocable)engine2).invokeMethod(obj, "run"); 853 fail("should have thrown IllegalArgumentException"); 854 } catch (final Exception exp) { 855 if (! (exp instanceof IllegalArgumentException)) { 856 exp.printStackTrace(); 857 fail(exp.getMessage()); 858 } 859 } 860 } 861 862 @Test 863 public void noEnumerablePropertiesTest() { 864 final ScriptEngineManager m = new ScriptEngineManager(); 865 final ScriptEngine e = m.getEngineByName("nashorn"); 866 try { 867 e.eval("for (i in this) { throw 'found property: ' + i }"); 868 } catch (final Exception exp) { 869 exp.printStackTrace(); 870 fail(exp.getMessage()); 871 } 872 } 873 874 @Test 875 public void noRefErrorForGlobalThisAccessTest() { 876 final ScriptEngineManager m = new ScriptEngineManager(); 877 final ScriptEngine e = m.getEngineByName("nashorn"); 878 try { 879 e.eval("this.foo"); 880 } catch (final Exception exp) { 881 exp.printStackTrace(); 882 fail(exp.getMessage()); 883 } 884 } 885 886 @Test 887 public void refErrorForUndeclaredAccessTest() { 888 final ScriptEngineManager m = new ScriptEngineManager(); 889 final ScriptEngine e = m.getEngineByName("nashorn"); 890 try { 891 e.eval("try { print(foo); throw 'no ref error' } catch (e) { if (!(e instanceof ReferenceError)) throw e; }"); 892 } catch (final Exception exp) { 893 exp.printStackTrace(); 894 fail(exp.getMessage()); 895 } 896 } 897 898 @Test 899 public void typeErrorForGlobalThisCallTest() { 900 final ScriptEngineManager m = new ScriptEngineManager(); 901 final ScriptEngine e = m.getEngineByName("nashorn"); 902 try { 903 e.eval("try { this.foo() } catch(e) { if (! (e instanceof TypeError)) throw 'no type error' }"); 904 } catch (final Exception exp) { 905 exp.printStackTrace(); 906 fail(exp.getMessage()); 907 } 908 } 909 910 @Test 911 public void refErrorForUndeclaredCallTest() { 912 final ScriptEngineManager m = new ScriptEngineManager(); 913 final ScriptEngine e = m.getEngineByName("nashorn"); 914 try { 915 e.eval("try { foo() } catch(e) { if (! (e instanceof ReferenceError)) throw 'no ref error' }"); 916 } catch (final Exception exp) { 917 exp.printStackTrace(); 918 fail(exp.getMessage()); 919 } 920 } 921 922 @Test 923 public void jsobjectTest() { 924 final ScriptEngineManager m = new ScriptEngineManager(); 925 final ScriptEngine e = m.getEngineByName("nashorn"); 926 try { 927 e.eval("var obj = { '1': 'world', func: function() { return this.bar; }, bar: 'hello' }"); 928 JSObject obj = (JSObject) e.get("obj"); 929 930 // try basic get on existing properties 931 if (! obj.getMember("bar").equals("hello")) { 932 fail("obj.bar != 'hello'"); 933 } 934 935 if (! obj.getSlot(1).equals("world")) { 936 fail("obj[1] != 'world'"); 937 } 938 939 if (! obj.call("func", new Object[0]).equals("hello")) { 940 fail("obj.call('func') != 'hello'"); 941 } 942 943 // try setting properties 944 obj.setMember("bar", "new-bar"); 945 obj.setSlot(1, "new-element-1"); 946 if (! obj.getMember("bar").equals("new-bar")) { 947 fail("obj.bar != 'new-bar'"); 948 } 949 950 if (! obj.getSlot(1).equals("new-element-1")) { 951 fail("obj[1] != 'new-element-1'"); 952 } 953 954 // try adding properties 955 obj.setMember("prop", "prop-value"); 956 obj.setSlot(12, "element-12"); 957 if (! obj.getMember("prop").equals("prop-value")) { 958 fail("obj.prop != 'prop-value'"); 959 } 960 961 if (! obj.getSlot(12).equals("element-12")) { 962 fail("obj[12] != 'element-12'"); 963 } 964 965 // delete properties 966 obj.removeMember("prop"); 967 if ("prop-value".equals(obj.getMember("prop"))) { 968 fail("obj.prop is not deleted!"); 969 } 970 971 // Simple eval tests 972 assertEquals(obj.eval("typeof Object"), "function"); 973 assertEquals(obj.eval("'nashorn'.substring(3)"), "horn"); 974 } catch (final Exception exp) { 975 exp.printStackTrace(); 976 fail(exp.getMessage()); 977 } 978 } 979 980 @Test 981 /** 982 * check that null function name results in NPE. 983 */ 984 public void invokeFunctionNullNameTest() { 985 final ScriptEngineManager m = new ScriptEngineManager(); 986 final ScriptEngine e = m.getEngineByName("nashorn"); 987 988 try { 989 final Object res = ((Invocable)e).invokeFunction(null); 990 fail("should have thrown NPE"); 991 } catch (final Exception exp) { 992 if (! (exp instanceof NullPointerException)) { 993 exp.printStackTrace(); 994 fail(exp.getMessage()); 995 } 996 } 997 } 998 999 @Test 1000 /** 1001 * Check that attempt to call missing function results in NoSuchMethodException. 1002 */ 1003 public void invokeFunctionMissingTest() { 1004 final ScriptEngineManager m = new ScriptEngineManager(); 1005 final ScriptEngine e = m.getEngineByName("nashorn"); 1006 1007 try { 1008 final Object res = ((Invocable)e).invokeFunction("NonExistentFunc"); 1009 fail("should have thrown NoSuchMethodException"); 1010 } catch (final Exception exp) { 1011 if (! (exp instanceof NoSuchMethodException)) { 1012 exp.printStackTrace(); 1013 fail(exp.getMessage()); 1014 } 1015 } 1016 } 1017 1018 @Test 1019 /** 1020 * Check that invokeFunction calls functions only from current context's Bindings. 1021 */ 1022 public void invokeFunctionDifferentContextTest() { 1023 ScriptEngineManager m = new ScriptEngineManager(); 1024 ScriptEngine e = m.getEngineByName("nashorn"); 1025 1026 try { 1027 // define an object with method on it 1028 Object obj = e.eval("function hello() { return 'Hello World!'; }"); 1029 final ScriptContext ctxt = new SimpleScriptContext(); 1030 ctxt.setBindings(e.createBindings(), ScriptContext.ENGINE_SCOPE); 1031 // change engine's current context 1032 e.setContext(ctxt); 1033 1034 ((Invocable)e).invokeFunction("hello"); // no 'hello' in new context! 1035 fail("should have thrown NoSuchMethodException"); 1036 } catch (final Exception exp) { 1037 if (! (exp instanceof NoSuchMethodException)) { 1038 exp.printStackTrace(); 1039 fail(exp.getMessage()); 1040 } 1041 } 1042 } 1043 1044 @Test 1045 public void invokeFunctionExceptionTest() { 1046 final ScriptEngineManager m = new ScriptEngineManager(); 1047 final ScriptEngine e = m.getEngineByName("nashorn"); 1048 try { 1049 e.eval("function func() { throw new TypeError(); }"); 1050 } catch (final Throwable t) { 1051 t.printStackTrace(); 1052 fail(t.getMessage()); 1053 } 1054 1055 try { 1056 ((Invocable)e).invokeFunction("func"); 1057 fail("should have thrown exception"); 1058 } catch (final ScriptException se) { 1059 // ECMA TypeError property wrapped as a ScriptException 1060 log("got " + se + " as expected"); 1061 } catch (final Throwable t) { 1062 t.printStackTrace(); 1063 fail(t.getMessage()); 1064 } 1065 } 1066 1067 @Test 1068 public void invokeMethodExceptionTest() { 1069 final ScriptEngineManager m = new ScriptEngineManager(); 1070 final ScriptEngine e = m.getEngineByName("nashorn"); 1071 try { 1072 e.eval("var sobj = {}; sobj.foo = function func() { throw new TypeError(); }"); 1073 } catch (final Throwable t) { 1074 t.printStackTrace(); 1075 fail(t.getMessage()); 1076 } 1077 1078 try { 1079 final Object sobj = e.get("sobj"); 1080 ((Invocable)e).invokeMethod(sobj, "foo"); 1081 fail("should have thrown exception"); 1082 } catch (final ScriptException se) { 1083 // ECMA TypeError property wrapped as a ScriptException 1084 log("got " + se + " as expected"); 1085 } catch (final Throwable t) { 1086 t.printStackTrace(); 1087 fail(t.getMessage()); 1088 } 1089 } 1090 1091 @Test 1092 public void scriptObjectMirrorToStringTest() { 1093 final ScriptEngineManager m = new ScriptEngineManager(); 1094 final ScriptEngine e = m.getEngineByName("nashorn"); 1095 try { 1096 Object obj = e.eval("new TypeError('wrong type')"); 1097 assertEquals(obj.toString(), "TypeError: wrong type", "toString returns wrong value"); 1098 } catch (final Throwable t) { 1099 t.printStackTrace(); 1100 fail(t.getMessage()); 1101 } 1102 1103 try { 1104 Object obj = e.eval("function func() { print('hello'); }"); 1105 assertEquals(obj.toString(), "function func() { print('hello'); }", "toString returns wrong value"); 1106 } catch (final Throwable t) { 1107 t.printStackTrace(); 1108 fail(t.getMessage()); 1109 } 1110 } 1111 1112 @Test 1113 public void engineScopeTest() { 1114 final ScriptEngineManager m = new ScriptEngineManager(); 1115 final ScriptEngine e = m.getEngineByName("nashorn"); 1116 Bindings engineScope = e.getBindings(ScriptContext.ENGINE_SCOPE); 1117 1118 // check few ECMA standard built-in global properties 1119 assertNotNull(engineScope.get("Object")); 1120 assertNotNull(engineScope.get("TypeError")); 1121 assertNotNull(engineScope.get("eval")); 1122 1123 // can access via ScriptEngine.get as well 1124 assertNotNull(e.get("Object")); 1125 assertNotNull(e.get("TypeError")); 1126 assertNotNull(e.get("eval")); 1127 1128 // Access by either way should return same object 1129 assertEquals(engineScope.get("Array"), e.get("Array")); 1130 assertEquals(engineScope.get("EvalError"), e.get("EvalError")); 1131 assertEquals(engineScope.get("undefined"), e.get("undefined")); 1132 1133 // try exposing a new variable from scope 1134 engineScope.put("myVar", "foo"); 1135 try { 1136 assertEquals(e.eval("myVar"), "foo"); 1137 } catch (final ScriptException se) { 1138 se.printStackTrace(); 1139 fail(se.getMessage()); 1140 } 1141 1142 // update "myVar" in script an check the value from scope 1143 try { 1144 e.eval("myVar = 'nashorn';"); 1145 } catch (final ScriptException se) { 1146 se.printStackTrace(); 1147 fail(se.getMessage()); 1148 } 1149 1150 // now check modified value from scope and engine 1151 assertEquals(engineScope.get("myVar"), "nashorn"); 1152 assertEquals(e.get("myVar"), "nashorn"); 1153 } 1154 1155 @Test 1156 public void multiGlobalTest() { 1157 final ScriptEngineManager m = new ScriptEngineManager(); 1158 final ScriptEngine e = m.getEngineByName("nashorn"); 1159 final Bindings b = e.createBindings(); 1160 final ScriptContext newCtxt = new SimpleScriptContext(); 1161 newCtxt.setBindings(b, ScriptContext.ENGINE_SCOPE); 1162 1163 try { 1164 Object obj1 = e.eval("Object"); 1165 Object obj2 = e.eval("Object", newCtxt); 1166 Assert.assertNotEquals(obj1, obj2); 1167 Assert.assertNotNull(obj1); 1168 Assert.assertNotNull(obj2); 1169 Assert.assertEquals(obj1.toString(), obj2.toString()); 1170 1171 e.eval("x = 'hello'"); 1172 e.eval("x = 'world'", newCtxt); 1173 Object x1 = e.getContext().getAttribute("x"); 1174 Object x2 = newCtxt.getAttribute("x"); 1175 Assert.assertNotEquals(x1, x2); 1176 Assert.assertEquals(x1, "hello"); 1177 Assert.assertEquals(x2, "world"); 1178 1179 x1 = e.eval("x"); 1180 x2 = e.eval("x", newCtxt); 1181 Assert.assertNotEquals(x1, x2); 1182 Assert.assertEquals(x1, "hello"); 1183 Assert.assertEquals(x2, "world"); 1184 1185 final ScriptContext origCtxt = e.getContext(); 1186 e.setContext(newCtxt); 1187 e.eval("y = new Object()"); 1188 e.eval("y = new Object()", origCtxt); 1189 1190 Object y1 = origCtxt.getAttribute("y"); 1191 Object y2 = newCtxt.getAttribute("y"); 1192 Assert.assertNotEquals(y1, y2); 1193 Assert.assertNotEquals(e.eval("y"), e.eval("y", origCtxt)); 1194 Assert.assertEquals("[object Object]", y1.toString()); 1195 Assert.assertEquals("[object Object]", y2.toString()); 1196 } catch (final ScriptException se) { 1197 se.printStackTrace(); 1198 fail(se.getMessage()); 1199 } 1200 } 1201 1202 @Test 1203 /** 1204 * Tests whether invocation of a JavaScript method through a variable arity Java method will pass the vararg array. 1205 * Both non-vararg and vararg JavaScript methods are tested. 1206 * @throws ScriptException 1207 */ 1208 public void variableArityInterfaceTest() throws ScriptException { 1209 final ScriptEngineManager m = new ScriptEngineManager(); 1210 final ScriptEngine e = m.getEngineByName("nashorn"); 1211 e.eval( 1212 "function test1(i, strings) {" + 1213 " return 'i == ' + i + ', strings instanceof java.lang.String[] == ' + (strings instanceof Java.type('java.lang.String[]')) + ', strings == ' + java.util.Arrays.toString(strings)" + 1214 "}" + 1215 "function test2() {" + 1216 " 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])" + 1217 "}" 1218 ); 1219 final VariableArityTestInterface itf = ((Invocable)e).getInterface(VariableArityTestInterface.class); 1220 Assert.assertEquals(itf.test1(42, "a", "b"), "i == 42, strings instanceof java.lang.String[] == true, strings == [a, b]"); 1221 Assert.assertEquals(itf.test2(44, "c", "d", "e"), "arguments[0] == 44, arguments[1] instanceof java.lang.String[] == true, arguments[1] == [c, d, e]"); 1222 } 1223 1224 @Test 1225 // check that print function prints arg followed by newline char 1226 public void printTest() { 1227 final ScriptEngineManager m = new ScriptEngineManager(); 1228 final ScriptEngine e = m.getEngineByName("nashorn"); 1229 final StringWriter sw = new StringWriter(); 1230 e.getContext().setWriter(sw); 1231 try { 1232 e.eval("print('hello')"); 1233 } catch (final Throwable t) { 1234 t.printStackTrace(); 1235 fail(t.getMessage()); 1236 } 1237 1238 // dos2unix - fix line endings if running on windows 1239 assertEquals(sw.toString().replaceAll("\r", ""), "hello\n"); 1240 } 1241 1242 @Test 1243 // check that print prints all arguments (more than one) 1244 public void printManyTest() { 1245 final ScriptEngineManager m = new ScriptEngineManager(); 1246 final ScriptEngine e = m.getEngineByName("nashorn"); 1247 final StringWriter sw = new StringWriter(); 1248 e.getContext().setWriter(sw); 1249 try { 1250 e.eval("print(34, true, 'hello')"); 1251 } catch (final Throwable t) { 1252 t.printStackTrace(); 1253 fail(t.getMessage()); 1254 } 1255 1256 // dos2unix - fix line endings if running on windows 1257 assertEquals(sw.toString().replaceAll("\r", ""), "34 true hello\n"); 1258 } 1259 1260 @Test 1261 public void mirrorNewObjectGlobalFunctionTest() throws ScriptException { 1262 final ScriptEngineManager m = new ScriptEngineManager(); 1263 final ScriptEngine e = m.getEngineByName("nashorn"); 1264 final ScriptEngine e2 = m.getEngineByName("nashorn"); 1265 1266 e.eval("function func() {}"); 1267 e2.put("foo", e.get("func")); 1268 final Object e2global = e2.eval("this"); 1269 final Object newObj = ((ScriptObjectMirror)e2global).newObject("foo"); 1270 assertTrue(newObj instanceof ScriptObjectMirror); 1271 } 1272 1273 @Test 1274 public void mirrorNewObjectInstanceFunctionTest() throws ScriptException { 1275 final ScriptEngineManager m = new ScriptEngineManager(); 1276 final ScriptEngine e = m.getEngineByName("nashorn"); 1277 final ScriptEngine e2 = m.getEngineByName("nashorn"); 1278 1279 e.eval("function func() {}"); 1280 e2.put("func", e.get("func")); 1281 final Object e2obj = e2.eval("({ foo: func })"); 1282 final Object newObj = ((ScriptObjectMirror)e2obj).newObject("foo"); 1283 assertTrue(newObj instanceof ScriptObjectMirror); 1284 } 1285 }