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