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