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.assertNotNull; 30 import static org.testng.Assert.assertTrue; 31 import static org.testng.Assert.fail; 32 33 import java.io.StringReader; 34 import java.io.StringWriter; 35 import java.lang.reflect.InvocationHandler; 36 import java.lang.reflect.Method; 37 import java.lang.reflect.Proxy; 38 import java.util.concurrent.Callable; 39 import javax.script.Compilable; 40 import javax.script.CompiledScript; 41 import javax.script.ScriptContext; 42 import javax.script.ScriptEngine; 43 import javax.script.ScriptEngineFactory; 44 import javax.script.ScriptEngineManager; 45 import javax.script.ScriptException; 46 import javax.script.SimpleScriptContext; 47 import org.testng.annotations.Test; 48 49 /** 50 * Tests for JSR-223 script engine for Nashorn. 51 * 52 * @test 53 * @build jdk.nashorn.api.scripting.Window jdk.nashorn.api.scripting.WindowEventHandler jdk.nashorn.api.scripting.VariableArityTestInterface jdk.nashorn.api.scripting.ScriptEngineTest 54 * @run testng/othervm jdk.nashorn.api.scripting.ScriptEngineTest 55 */ 56 public class ScriptEngineTest { 57 58 private void log(final String msg) { 59 org.testng.Reporter.log(msg, true); 60 } 61 62 @Test 63 public void argumentsTest() { 64 final ScriptEngineManager m = new ScriptEngineManager(); 65 final ScriptEngine e = m.getEngineByName("nashorn"); 66 67 final String[] args = new String[] { "hello", "world" }; 68 try { 69 e.put("arguments", args); 70 final Object arg0 = e.eval("arguments[0]"); 71 final Object arg1 = e.eval("arguments[1]"); 72 assertEquals(args[0], arg0); 73 assertEquals(args[1], arg1); 74 } catch (final Exception exp) { 75 exp.printStackTrace(); 76 fail(exp.getMessage()); 77 } 78 } 79 80 @Test 81 public void argumentsWithTest() { 82 final ScriptEngineManager m = new ScriptEngineManager(); 83 final ScriptEngine e = m.getEngineByName("nashorn"); 84 85 final String[] args = new String[] { "hello", "world" }; 86 try { 87 e.put("arguments", args); 88 final Object arg0 = e.eval("var imports = new JavaImporter(java.io); " + 89 " with(imports) { arguments[0] }"); 90 final Object arg1 = e.eval("var imports = new JavaImporter(java.util, java.io); " + 91 " with(imports) { arguments[1] }"); 92 assertEquals(args[0], arg0); 93 assertEquals(args[1], arg1); 94 } catch (final Exception exp) { 95 exp.printStackTrace(); 96 fail(exp.getMessage()); 97 } 98 } 99 100 @Test 101 public void argumentsEmptyTest() { 102 final ScriptEngineManager m = new ScriptEngineManager(); 103 final ScriptEngine e = m.getEngineByName("nashorn"); 104 105 try { 106 assertEquals(e.eval("arguments instanceof Array"), true); 107 assertEquals(e.eval("arguments.length == 0"), true); 108 } catch (final Exception exp) { 109 exp.printStackTrace(); 110 fail(exp.getMessage()); 111 } 112 } 113 114 @Test 115 public void factoryTests() { 116 final ScriptEngineManager m = new ScriptEngineManager(); 117 final ScriptEngine e = m.getEngineByName("nashorn"); 118 assertNotNull(e); 119 120 final ScriptEngineFactory fac = e.getFactory(); 121 122 assertEquals(fac.getLanguageName(), "ECMAScript"); 123 assertEquals(fac.getParameter(ScriptEngine.NAME), "javascript"); 124 assertEquals(fac.getLanguageVersion(), "ECMA - 262 Edition 5.1"); 125 assertEquals(fac.getEngineName(), "Oracle Nashorn"); 126 assertEquals(fac.getOutputStatement("context"), "print(context)"); 127 assertEquals(fac.getProgram("print('hello')", "print('world')"), "print('hello');print('world');"); 128 assertEquals(fac.getParameter(ScriptEngine.NAME), "javascript"); 129 130 boolean seenJS = false; 131 for (final String ext : fac.getExtensions()) { 132 if (ext.equals("js")) { 133 seenJS = true; 134 } 135 } 136 137 assertEquals(seenJS, true); 138 final String str = fac.getMethodCallSyntax("obj", "foo", "x"); 139 assertEquals(str, "obj.foo(x)"); 140 141 boolean seenNashorn = false, seenJavaScript = false, seenECMAScript = false; 142 for (final String name : fac.getNames()) { 143 switch (name) { 144 case "nashorn": seenNashorn = true; break; 145 case "javascript": seenJavaScript = true; break; 146 case "ECMAScript": seenECMAScript = true; break; 147 } 148 } 149 150 assertTrue(seenNashorn); 151 assertTrue(seenJavaScript); 152 assertTrue(seenECMAScript); 153 154 boolean seenAppJS = false, seenAppECMA = false, seenTextJS = false, seenTextECMA = false; 155 for (final String mime : fac.getMimeTypes()) { 156 switch (mime) { 157 case "application/javascript": seenAppJS = true; break; 158 case "application/ecmascript": seenAppECMA = true; break; 159 case "text/javascript": seenTextJS = true; break; 160 case "text/ecmascript": seenTextECMA = true; break; 161 } 162 } 163 164 assertTrue(seenAppJS); 165 assertTrue(seenAppECMA); 166 assertTrue(seenTextJS); 167 assertTrue(seenTextECMA); 168 } 169 170 @Test 171 public void evalTests() { 172 final ScriptEngineManager m = new ScriptEngineManager(); 173 final ScriptEngine e = m.getEngineByName("nashorn"); 174 e.put(ScriptEngine.FILENAME, "myfile.js"); 175 176 try { 177 e.eval("print('hello')"); 178 } catch (final ScriptException se) { 179 fail(se.getMessage()); 180 } 181 try { 182 e.eval("print('hello)"); 183 fail("script exception expected"); 184 } catch (final ScriptException se) { 185 assertEquals(se.getLineNumber(), 1); 186 assertEquals(se.getColumnNumber(), 13); 187 assertEquals(se.getFileName(), "myfile.js"); 188 // se.printStackTrace(); 189 } 190 191 try { 192 Object obj = e.eval("34 + 41"); 193 assertTrue(34.0 + 41.0 == ((Number)obj).doubleValue()); 194 obj = e.eval("x = 5"); 195 assertTrue(5.0 == ((Number)obj).doubleValue()); 196 } catch (final ScriptException se) { 197 se.printStackTrace(); 198 fail(se.getMessage()); 199 } 200 } 201 202 @Test 203 public void compileTests() { 204 final ScriptEngineManager m = new ScriptEngineManager(); 205 final ScriptEngine e = m.getEngineByName("nashorn"); 206 CompiledScript script = null; 207 208 try { 209 script = ((Compilable)e).compile("print('hello')"); 210 } catch (final ScriptException se) { 211 fail(se.getMessage()); 212 } 213 214 try { 215 script.eval(); 216 } catch (final ScriptException | NullPointerException se) { 217 se.printStackTrace(); 218 fail(se.getMessage()); 219 } 220 221 // try to compile from a Reader 222 try { 223 script = ((Compilable)e).compile(new StringReader("print('world')")); 224 } catch (final ScriptException se) { 225 fail(se.getMessage()); 226 } 227 228 try { 229 script.eval(); 230 } catch (final ScriptException | NullPointerException se) { 231 se.printStackTrace(); 232 fail(se.getMessage()); 233 } 234 } 235 236 @Test 237 public void compileAndEvalInDiffContextTest() throws ScriptException { 238 final ScriptEngineManager m = new ScriptEngineManager(); 239 final ScriptEngine engine = m.getEngineByName("js"); 240 final Compilable compilable = (Compilable) engine; 241 final CompiledScript compiledScript = compilable.compile("foo"); 242 final ScriptContext ctxt = new SimpleScriptContext(); 243 ctxt.setAttribute("foo", "hello", ScriptContext.ENGINE_SCOPE); 244 assertEquals(compiledScript.eval(ctxt), "hello"); 245 } 246 247 @Test 248 public void accessGlobalTest() { 249 final ScriptEngineManager m = new ScriptEngineManager(); 250 final ScriptEngine e = m.getEngineByName("nashorn"); 251 252 try { 253 e.eval("var x = 'hello'"); 254 assertEquals(e.get("x"), "hello"); 255 } catch (final ScriptException exp) { 256 exp.printStackTrace(); 257 fail(exp.getMessage()); 258 } 259 } 260 261 @Test 262 public void exposeGlobalTest() { 263 final ScriptEngineManager m = new ScriptEngineManager(); 264 final ScriptEngine e = m.getEngineByName("nashorn"); 265 266 try { 267 e.put("y", "foo"); 268 e.eval("print(y)"); 269 } catch (final ScriptException exp) { 270 exp.printStackTrace(); 271 fail(exp.getMessage()); 272 } 273 } 274 275 @Test 276 public void putGlobalFunctionTest() { 277 final ScriptEngineManager m = new ScriptEngineManager(); 278 final ScriptEngine e = m.getEngineByName("nashorn"); 279 280 e.put("callable", new Callable<String>() { 281 @Override 282 public String call() throws Exception { 283 return "callable was called"; 284 } 285 }); 286 287 try { 288 e.eval("print(callable.call())"); 289 } catch (final ScriptException exp) { 290 exp.printStackTrace(); 291 fail(exp.getMessage()); 292 } 293 } 294 295 @Test 296 public void windowAlertTest() { 297 final ScriptEngineManager m = new ScriptEngineManager(); 298 final ScriptEngine e = m.getEngineByName("nashorn"); 299 final Window window = new Window(); 300 301 try { 302 e.put("window", window); 303 e.eval("print(window.alert)"); 304 e.eval("window.alert('calling window.alert...')"); 305 } catch (final Exception exp) { 306 exp.printStackTrace(); 307 fail(exp.getMessage()); 308 } 309 } 310 311 @Test 312 public void windowLocationTest() { 313 final ScriptEngineManager m = new ScriptEngineManager(); 314 final ScriptEngine e = m.getEngineByName("nashorn"); 315 final Window window = new Window(); 316 317 try { 318 e.put("window", window); 319 e.eval("print(window.location)"); 320 final Object locationValue = e.eval("window.getLocation()"); 321 assertEquals(locationValue, "http://localhost:8080/window"); 322 } catch (final Exception exp) { 323 exp.printStackTrace(); 324 fail(exp.getMessage()); 325 } 326 } 327 328 @Test 329 public void windowItemTest() { 330 final ScriptEngineManager m = new ScriptEngineManager(); 331 final ScriptEngine e = m.getEngineByName("nashorn"); 332 final Window window = new Window(); 333 334 try { 335 e.put("window", window); 336 final String item1 = (String)e.eval("window.item(65535)"); 337 assertEquals(item1, "ffff"); 338 final String item2 = (String)e.eval("window.item(255)"); 339 assertEquals(item2, "ff"); 340 } catch (final Exception exp) { 341 exp.printStackTrace(); 342 fail(exp.getMessage()); 343 } 344 } 345 346 @Test 347 public void windowEventTest() { 348 final ScriptEngineManager m = new ScriptEngineManager(); 349 final ScriptEngine e = m.getEngineByName("nashorn"); 350 final Window window = new Window(); 351 352 try { 353 e.put("window", window); 354 e.eval("window.onload = function() { print('window load event fired'); return true }"); 355 assertTrue((Boolean)e.eval("window.onload.loaded()")); 356 final WindowEventHandler handler = window.getOnload(); 357 assertNotNull(handler); 358 assertTrue(handler.loaded()); 359 } catch (final Exception exp) { 360 exp.printStackTrace(); 361 fail(exp.getMessage()); 362 } 363 } 364 365 @Test 366 public void throwTest() { 367 final ScriptEngineManager m = new ScriptEngineManager(); 368 final ScriptEngine e = m.getEngineByName("nashorn"); 369 e.put(ScriptEngine.FILENAME, "throwtest.js"); 370 371 try { 372 e.eval("throw 'foo'"); 373 } catch (final ScriptException exp) { 374 log(exp.getMessage()); 375 assertEquals(exp.getMessage(), "foo in throwtest.js at line number 1 at column number 0"); 376 assertEquals(exp.getFileName(), "throwtest.js"); 377 assertEquals(exp.getLineNumber(), 1); 378 } 379 } 380 381 @Test 382 public void setTimeoutTest() { 383 final ScriptEngineManager m = new ScriptEngineManager(); 384 final ScriptEngine e = m.getEngineByName("nashorn"); 385 final Window window = new Window(); 386 387 try { 388 final Class<?> setTimeoutParamTypes[] = { Window.class, String.class, int.class }; 389 final Method setTimeout = Window.class.getDeclaredMethod("setTimeout", setTimeoutParamTypes); 390 assertNotNull(setTimeout); 391 e.put("window", window); 392 e.eval("window.setTimeout('foo()', 100)"); 393 394 // try to make setTimeout global 395 e.put("setTimeout", setTimeout); 396 // TODO: java.lang.ClassCastException: required class 397 // java.lang.Integer but encountered class java.lang.Double 398 // e.eval("setTimeout('foo2()', 200)"); 399 } catch (final Exception exp) { 400 exp.printStackTrace(); 401 fail(exp.getMessage()); 402 } 403 } 404 405 @Test 406 public void setWriterTest() { 407 final ScriptEngineManager m = new ScriptEngineManager(); 408 final ScriptEngine e = m.getEngineByName("nashorn"); 409 final StringWriter sw = new StringWriter(); 410 e.getContext().setWriter(sw); 411 412 try { 413 e.eval("print('hello world')"); 414 } catch (final Exception exp) { 415 exp.printStackTrace(); 416 fail(exp.getMessage()); 417 } 418 assertEquals(sw.toString(), println("hello world")); 419 } 420 421 @Test 422 public void redefineEchoTest() { 423 final ScriptEngineManager m = new ScriptEngineManager(); 424 final ScriptEngine e = m.getEngineByName("nashorn"); 425 426 try { 427 e.eval("var echo = {}; if (typeof echo !== 'object') { throw 'echo is a '+typeof echo; }"); 428 } catch (final Exception exp) { 429 exp.printStackTrace(); 430 fail(exp.getMessage()); 431 } 432 } 433 @Test 434 public void noEnumerablePropertiesTest() { 435 final ScriptEngineManager m = new ScriptEngineManager(); 436 final ScriptEngine e = m.getEngineByName("nashorn"); 437 try { 438 e.eval("for (i in this) { throw 'found property: ' + i }"); 439 } catch (final Exception exp) { 440 exp.printStackTrace(); 441 fail(exp.getMessage()); 442 } 443 } 444 445 @Test 446 public void noRefErrorForGlobalThisAccessTest() { 447 final ScriptEngineManager m = new ScriptEngineManager(); 448 final ScriptEngine e = m.getEngineByName("nashorn"); 449 try { 450 e.eval("this.foo"); 451 } catch (final Exception exp) { 452 exp.printStackTrace(); 453 fail(exp.getMessage()); 454 } 455 } 456 457 @Test 458 public void refErrorForUndeclaredAccessTest() { 459 final ScriptEngineManager m = new ScriptEngineManager(); 460 final ScriptEngine e = m.getEngineByName("nashorn"); 461 try { 462 e.eval("try { print(foo); throw 'no ref error' } catch (e) { if (!(e instanceof ReferenceError)) throw e; }"); 463 } catch (final Exception exp) { 464 exp.printStackTrace(); 465 fail(exp.getMessage()); 466 } 467 } 468 469 @Test 470 public void typeErrorForGlobalThisCallTest() { 471 final ScriptEngineManager m = new ScriptEngineManager(); 472 final ScriptEngine e = m.getEngineByName("nashorn"); 473 try { 474 e.eval("try { this.foo() } catch(e) { if (! (e instanceof TypeError)) throw 'no type error' }"); 475 } catch (final Exception exp) { 476 exp.printStackTrace(); 477 fail(exp.getMessage()); 478 } 479 } 480 481 @Test 482 public void refErrorForUndeclaredCallTest() { 483 final ScriptEngineManager m = new ScriptEngineManager(); 484 final ScriptEngine e = m.getEngineByName("nashorn"); 485 try { 486 e.eval("try { foo() } catch(e) { if (! (e instanceof ReferenceError)) throw 'no ref error' }"); 487 } catch (final Exception exp) { 488 exp.printStackTrace(); 489 fail(exp.getMessage()); 490 } 491 } 492 493 @Test 494 // check that print function prints arg followed by newline char 495 public void printTest() { 496 final ScriptEngineManager m = new ScriptEngineManager(); 497 final ScriptEngine e = m.getEngineByName("nashorn"); 498 final StringWriter sw = new StringWriter(); 499 e.getContext().setWriter(sw); 500 try { 501 e.eval("print('hello')"); 502 } catch (final Throwable t) { 503 t.printStackTrace(); 504 fail(t.getMessage()); 505 } 506 507 assertEquals(sw.toString(), println("hello")); 508 } 509 510 @Test 511 // check that print prints all arguments (more than one) 512 public void printManyTest() { 513 final ScriptEngineManager m = new ScriptEngineManager(); 514 final ScriptEngine e = m.getEngineByName("nashorn"); 515 final StringWriter sw = new StringWriter(); 516 e.getContext().setWriter(sw); 517 try { 518 e.eval("print(34, true, 'hello')"); 519 } catch (final Throwable t) { 520 t.printStackTrace(); 521 fail(t.getMessage()); 522 } 523 524 assertEquals(sw.toString(), println("34 true hello")); 525 } 526 527 @Test 528 public void scriptObjectAutoConversionTest() throws ScriptException { 529 final ScriptEngineManager m = new ScriptEngineManager(); 530 final ScriptEngine e = m.getEngineByName("nashorn"); 531 e.eval("obj = { foo: 'hello' }"); 532 e.put("Window", e.eval("Packages.jdk.nashorn.api.scripting.Window")); 533 assertEquals(e.eval("Window.funcJSObject(obj)"), "hello"); 534 assertEquals(e.eval("Window.funcScriptObjectMirror(obj)"), "hello"); 535 assertEquals(e.eval("Window.funcMap(obj)"), "hello"); 536 assertEquals(e.eval("Window.funcJSObject(obj)"), "hello"); 537 } 538 539 // @bug 8032948: Nashorn linkages awry 540 @Test 541 public void checkProxyAccess() throws ScriptException { 542 final ScriptEngineManager m = new ScriptEngineManager(); 543 final ScriptEngine e = m.getEngineByName("nashorn"); 544 final boolean[] reached = new boolean[1]; 545 final Runnable r = (Runnable)Proxy.newProxyInstance( 546 ScriptEngineTest.class.getClassLoader(), 547 new Class[] { Runnable.class }, 548 new InvocationHandler() { 549 @Override 550 public Object invoke(final Object p, final Method m, final Object[] a) { 551 reached[0] = true; 552 return null; 553 } 554 }); 555 556 e.put("r", r); 557 e.eval("r.run()"); 558 559 assertTrue(reached[0]); 560 } 561 562 // properties that can be read by any code 563 private static String[] propNames = { 564 "java.version", 565 "java.vendor", 566 "java.vendor.url", 567 "java.class.version", 568 "os.name", 569 "os.version", 570 "os.arch", 571 "file.separator", 572 "path.separator", 573 "line.separator", 574 "java.specification.version", 575 "java.specification.vendor", 576 "java.specification.name", 577 "java.vm.specification.version", 578 "java.vm.specification.vendor", 579 "java.vm.specification.name", 580 "java.vm.version", 581 "java.vm.vendor", 582 "java.vm.name" 583 }; 584 585 // @bug 8033924: Default permissions are not given for eval code 586 @Test 587 public void checkPropertyReadPermissions() throws ScriptException { 588 final ScriptEngineManager m = new ScriptEngineManager(); 589 final ScriptEngine e = m.getEngineByName("nashorn"); 590 591 for (final String name : propNames) { 592 checkProperty(e, name); 593 } 594 } 595 596 // @bug 8046013: TypeError: Cannot apply "with" to non script object 597 @Test 598 public void withOnMirrorTest() throws ScriptException { 599 final ScriptEngineManager m = new ScriptEngineManager(); 600 final ScriptEngine e = m.getEngineByName("nashorn"); 601 602 final Object obj = e.eval("({ foo: 'hello'})"); 603 final Object[] arr = new Object[1]; 604 arr[0] = obj; 605 e.put("arr", arr); 606 final Object res = e.eval("var res; with(arr[0]) { res = foo; }; res"); 607 assertEquals(res, "hello"); 608 } 609 610 // @bug 8050432:javax.script.filename variable should not be enumerable 611 // with nashorn engine's ENGINE_SCOPE bindings 612 @Test 613 public void enumerableGlobalsTest() throws ScriptException { 614 final ScriptEngineManager m = new ScriptEngineManager(); 615 final ScriptEngine e = m.getEngineByName("nashorn"); 616 617 e.put(ScriptEngine.FILENAME, "test"); 618 Object enumerable = e.eval( 619 "Object.getOwnPropertyDescriptor(this, " + 620 " 'javax.script.filename').enumerable"); 621 assertEquals(enumerable, Boolean.FALSE); 622 } 623 624 private static void checkProperty(final ScriptEngine e, final String name) 625 throws ScriptException { 626 final String value = System.getProperty(name); 627 e.put("name", name); 628 assertEquals(value, e.eval("java.lang.System.getProperty(name)")); 629 } 630 631 private static final String LINE_SEPARATOR = System.getProperty("line.separator"); 632 633 // Returns String that would be the result of calling PrintWriter.println 634 // of the given String. (This is to handle platform specific newline). 635 private static String println(final String str) { 636 return str + LINE_SEPARATOR; 637 } 638 } --- EOF ---