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.concurrent.Callable;
  40 import javax.script.Bindings;
  41 import javax.script.Compilable;
  42 import javax.script.CompiledScript;
  43 import javax.script.Invocable;
  44 import javax.script.ScriptContext;
  45 import javax.script.ScriptEngine;
  46 import javax.script.ScriptEngineFactory;
  47 import javax.script.ScriptEngineManager;
  48 import javax.script.ScriptException;
  49 import javax.script.SimpleScriptContext;
  50 import netscape.javascript.JSObject;
  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     public void accessGlobalTest() {
 350         final ScriptEngineManager m = new ScriptEngineManager();
 351         final ScriptEngine e = m.getEngineByName("nashorn");
 352 
 353         try {
 354             e.eval("var x = 'hello'");
 355             assertEquals(e.get("x"), "hello");
 356         } catch (final ScriptException exp) {
 357             exp.printStackTrace();
 358             fail(exp.getMessage());
 359         }
 360     }
 361 
 362     @Test
 363     public void exposeGlobalTest() {
 364         final ScriptEngineManager m = new ScriptEngineManager();
 365         final ScriptEngine e = m.getEngineByName("nashorn");
 366 
 367         try {
 368             e.put("y", "foo");
 369             e.eval("print(y)");
 370         } catch (final ScriptException exp) {
 371             exp.printStackTrace();
 372             fail(exp.getMessage());
 373         }
 374     }
 375 
 376     @Test
 377     public void putGlobalFunctionTest() {
 378         final ScriptEngineManager m = new ScriptEngineManager();
 379         final ScriptEngine e = m.getEngineByName("nashorn");
 380 
 381         e.put("callable", new Callable<String>() {
 382             @Override
 383             public String call() throws Exception {
 384                 return "callable was called";
 385             }
 386         });
 387 
 388         try {
 389             e.eval("print(callable.call())");
 390         } catch (final ScriptException exp) {
 391             exp.printStackTrace();
 392             fail(exp.getMessage());
 393         }
 394     }
 395 
 396     @Test
 397     public void windowAlertTest() {
 398         final ScriptEngineManager m = new ScriptEngineManager();
 399         final ScriptEngine e = m.getEngineByName("nashorn");
 400         final Window window = new Window();
 401 
 402         try {
 403             e.put("window", window);
 404             e.eval("print(window.alert)");
 405             e.eval("window.alert('calling window.alert...')");
 406         } catch (final Exception exp) {
 407             exp.printStackTrace();
 408             fail(exp.getMessage());
 409         }
 410     }
 411 
 412     @Test
 413     public void windowLocationTest() {
 414         final ScriptEngineManager m = new ScriptEngineManager();
 415         final ScriptEngine e = m.getEngineByName("nashorn");
 416         final Window window = new Window();
 417 
 418         try {
 419             e.put("window", window);
 420             e.eval("print(window.location)");
 421             final Object locationValue = e.eval("window.getLocation()");
 422             assertEquals(locationValue, "http://localhost:8080/window");
 423         } catch (final Exception exp) {
 424             exp.printStackTrace();
 425             fail(exp.getMessage());
 426         }
 427     }
 428 
 429     @Test
 430     public void windowItemTest() {
 431         final ScriptEngineManager m = new ScriptEngineManager();
 432         final ScriptEngine e = m.getEngineByName("nashorn");
 433         final Window window = new Window();
 434 
 435         try {
 436             e.put("window", window);
 437             final String item1 = (String)e.eval("window.item(65535)");
 438             assertEquals(item1, "ffff");
 439             final String item2 = (String)e.eval("window.item(255)");
 440             assertEquals(item2, "ff");
 441         } catch (final Exception exp) {
 442             exp.printStackTrace();
 443             fail(exp.getMessage());
 444         }
 445     }
 446 
 447     @Test
 448     public void windowEventTest() {
 449         final ScriptEngineManager m = new ScriptEngineManager();
 450         final ScriptEngine e = m.getEngineByName("nashorn");
 451         final Window window = new Window();
 452 
 453         try {
 454             e.put("window", window);
 455             e.eval("window.onload = function() { print('window load event fired'); return true }");
 456             assertTrue((Boolean)e.eval("window.onload.loaded()"));
 457             final WindowEventHandler handler = window.getOnload();
 458             assertNotNull(handler);
 459             assertTrue(handler.loaded());
 460         } catch (final Exception exp) {
 461             exp.printStackTrace();
 462             fail(exp.getMessage());
 463         }
 464     }
 465 
 466     @Test
 467     public void throwTest() {
 468         final ScriptEngineManager m = new ScriptEngineManager();
 469         final ScriptEngine e = m.getEngineByName("nashorn");
 470         e.put(ScriptEngine.FILENAME, "throwtest.js");
 471 
 472         try {
 473             e.eval("throw 'foo'");
 474         } catch (final ScriptException exp) {
 475             log(exp.getMessage());
 476             assertEquals(exp.getMessage(), "foo in throwtest.js at line number 1 at column number 0");
 477             assertEquals(exp.getFileName(), "throwtest.js");
 478             assertEquals(exp.getLineNumber(), 1);
 479         }
 480     }
 481 
 482     @Test
 483     public void setTimeoutTest() {
 484         final ScriptEngineManager m = new ScriptEngineManager();
 485         final ScriptEngine e = m.getEngineByName("nashorn");
 486         final Window window = new Window();
 487 
 488         try {
 489             final Class<?> setTimeoutParamTypes[] = { Window.class, String.class, int.class };
 490             final Method setTimeout = Window.class.getDeclaredMethod("setTimeout", setTimeoutParamTypes);
 491             assertNotNull(setTimeout);
 492             e.put("window", window);
 493             e.eval("window.setTimeout('foo()', 100)");
 494 
 495             // try to make setTimeout global
 496             e.put("setTimeout", setTimeout);
 497             // TODO: java.lang.ClassCastException: required class
 498             // java.lang.Integer but encountered class java.lang.Double
 499             // e.eval("setTimeout('foo2()', 200)");
 500         } catch (final Exception exp) {
 501             exp.printStackTrace();
 502             fail(exp.getMessage());
 503         }
 504     }
 505 
 506     @Test
 507     public void setWriterTest() {
 508         final ScriptEngineManager m = new ScriptEngineManager();
 509         final ScriptEngine e = m.getEngineByName("nashorn");
 510         final StringWriter sw = new StringWriter();
 511         e.getContext().setWriter(sw);
 512 
 513         try {
 514             e.eval("print('hello world')");
 515         } catch (final Exception exp) {
 516             exp.printStackTrace();
 517             fail(exp.getMessage());
 518         }
 519         // dos2unix - fix line endings if running on windows
 520         assertEquals(sw.toString().replaceAll("\r", ""), "hello world\n");
 521     }
 522 
 523     @SuppressWarnings("unchecked")
 524     @Test
 525     public void reflectionTest() throws ScriptException {
 526         final ScriptEngineManager m = new ScriptEngineManager();
 527         final ScriptEngine e = m.getEngineByName("nashorn");
 528 
 529         e.eval("var obj = { x: 344, y: 'nashorn' }");
 530 
 531         int count = 0;
 532         Map<Object, Object> map = (Map<Object, Object>)e.get("obj");
 533         assertFalse(map.isEmpty());
 534         assertTrue(map.keySet().contains("x"));
 535         assertTrue(map.containsKey("x"));
 536         assertTrue(map.values().contains("nashorn"));
 537         assertTrue(map.containsValue("nashorn"));
 538         for (final Map.Entry<?, ?> ex : map.entrySet()) {
 539             final Object key = ex.getKey();
 540             if (key.equals("x")) {
 541                 assertTrue(344 == ((Number)ex.getValue()).doubleValue());
 542                 count++;
 543             } else if (key.equals("y")) {
 544                 assertEquals(ex.getValue(), "nashorn");
 545                 count++;
 546             }
 547         }
 548         assertEquals(2, count);
 549         assertEquals(2, map.size());
 550 
 551         // add property
 552         map.put("z", "hello");
 553         assertEquals(e.eval("obj.z"), "hello");
 554         assertEquals(map.get("z"), "hello");
 555         assertTrue(map.keySet().contains("z"));
 556         assertTrue(map.containsKey("z"));
 557         assertTrue(map.values().contains("hello"));
 558         assertTrue(map.containsValue("hello"));
 559         assertEquals(map.size(), 3);
 560 
 561         final Map<Object, Object> newMap = new HashMap<>();
 562         newMap.put("foo", 23.0);
 563         newMap.put("bar", true);
 564         map.putAll(newMap);
 565 
 566         assertEquals(e.eval("obj.foo"), 23.0);
 567         assertEquals(e.eval("obj.bar"), true);
 568 
 569         // remove using map method
 570         map.remove("foo");
 571         assertEquals(e.eval("typeof obj.foo"), "undefined");
 572 
 573         count = 0;
 574         e.eval("var arr = [ true, 'hello' ]");
 575         map = (Map<Object, Object>)e.get("arr");
 576         assertFalse(map.isEmpty());
 577         assertTrue(map.containsKey("length"));
 578         assertTrue(map.containsValue("hello"));
 579         for (final Map.Entry<?, ?> ex : map.entrySet()) {
 580             final Object key = ex.getKey();
 581             if (key.equals("0")) {
 582                 assertEquals(ex.getValue(), Boolean.TRUE);
 583                 count++;
 584             } else if (key.equals("1")) {
 585                 assertEquals(ex.getValue(), "hello");
 586                 count++;
 587             }
 588         }
 589         assertEquals(count, 2);
 590         assertEquals(map.size(), 2);
 591 
 592         // add element
 593         map.put("2", "world");
 594         assertEquals(map.get("2"), "world");
 595         assertEquals(map.size(), 3);
 596 
 597         // remove all
 598         map.clear();
 599         assertTrue(map.isEmpty());
 600         assertEquals(e.eval("typeof arr[0]"), "undefined");
 601         assertEquals(e.eval("typeof arr[1]"), "undefined");
 602         assertEquals(e.eval("typeof arr[2]"), "undefined");
 603     }
 604 
 605     @Test
 606     public void redefineEchoTest() {
 607         final ScriptEngineManager m = new ScriptEngineManager();
 608         final ScriptEngine e = m.getEngineByName("nashorn");
 609 
 610         try {
 611             e.eval("var echo = {}; if (typeof echo !== 'object') { throw 'echo is a '+typeof echo; }");
 612         } catch (final Exception exp) {
 613             exp.printStackTrace();
 614             fail(exp.getMessage());
 615         }
 616     }
 617 
 618     @Test
 619     public void invokeMethodTest() {
 620         final ScriptEngineManager m = new ScriptEngineManager();
 621         final ScriptEngine e = m.getEngineByName("nashorn");
 622 
 623         try {
 624             e.eval("var Example = function() { this.hello = function() { return 'Hello World!'; };}; myExample = new Example();");
 625             final Object obj = e.get("myExample");
 626             final Object res = ((Invocable)e).invokeMethod(obj, "hello");
 627             assertEquals(res, "Hello World!");
 628         } catch (final Exception exp) {
 629             exp.printStackTrace();
 630             fail(exp.getMessage());
 631         }
 632     }
 633 
 634     @Test
 635     public void noEnumerablePropertiesTest() {
 636         final ScriptEngineManager m = new ScriptEngineManager();
 637         final ScriptEngine e = m.getEngineByName("nashorn");
 638         try {
 639             e.eval("for (i in this) { throw 'found property: ' + i }");
 640         } catch (final Exception exp) {
 641             exp.printStackTrace();
 642             fail(exp.getMessage());
 643         }
 644     }
 645 
 646     @Test
 647     public void noRefErrorForGlobalThisAccessTest() {
 648         final ScriptEngineManager m = new ScriptEngineManager();
 649         final ScriptEngine e = m.getEngineByName("nashorn");
 650         try {
 651             e.eval("this.foo");
 652         } catch (final Exception exp) {
 653             exp.printStackTrace();
 654             fail(exp.getMessage());
 655         }
 656     }
 657 
 658     @Test
 659     public void refErrorForUndeclaredAccessTest() {
 660         final ScriptEngineManager m = new ScriptEngineManager();
 661         final ScriptEngine e = m.getEngineByName("nashorn");
 662         try {
 663             e.eval("try { print(foo); throw 'no ref error' } catch (e) { if (!(e instanceof ReferenceError)) throw e; }");
 664         } catch (final Exception exp) {
 665             exp.printStackTrace();
 666             fail(exp.getMessage());
 667         }
 668     }
 669 
 670     @Test
 671     public void typeErrorForGlobalThisCallTest() {
 672         final ScriptEngineManager m = new ScriptEngineManager();
 673         final ScriptEngine e = m.getEngineByName("nashorn");
 674         try {
 675             e.eval("try { this.foo() } catch(e) { if (! (e instanceof TypeError)) throw 'no type error' }");
 676         } catch (final Exception exp) {
 677             exp.printStackTrace();
 678             fail(exp.getMessage());
 679         }
 680     }
 681 
 682     @Test
 683     public void refErrorForUndeclaredCallTest() {
 684         final ScriptEngineManager m = new ScriptEngineManager();
 685         final ScriptEngine e = m.getEngineByName("nashorn");
 686         try {
 687             e.eval("try { foo() } catch(e) { if (! (e instanceof ReferenceError)) throw 'no ref error' }");
 688         } catch (final Exception exp) {
 689             exp.printStackTrace();
 690             fail(exp.getMessage());
 691         }
 692     }
 693 
 694     @Test
 695     public void jsobjectTest() {
 696         final ScriptEngineManager m = new ScriptEngineManager();
 697         final ScriptEngine e = m.getEngineByName("nashorn");
 698         try {
 699             e.eval("var obj = { '1': 'world', func: function() { return this.bar; }, bar: 'hello' }");
 700             JSObject obj = (JSObject) e.get("obj");
 701 
 702             // try basic get on existing properties
 703             if (! obj.getMember("bar").equals("hello")) {
 704                 fail("obj.bar != 'hello'");
 705             }
 706 
 707             if (! obj.getSlot(1).equals("world")) {
 708                 fail("obj[1] != 'world'");
 709             }
 710 
 711             if (! obj.call("func", new Object[0]).equals("hello")) {
 712                 fail("obj.call('func') != 'hello'");
 713             }
 714 
 715             // try setting properties
 716             obj.setMember("bar", "new-bar");
 717             obj.setSlot(1, "new-element-1");
 718             if (! obj.getMember("bar").equals("new-bar")) {
 719                 fail("obj.bar != 'new-bar'");
 720             }
 721 
 722             if (! obj.getSlot(1).equals("new-element-1")) {
 723                 fail("obj[1] != 'new-element-1'");
 724             }
 725 
 726             // try adding properties
 727             obj.setMember("prop", "prop-value");
 728             obj.setSlot(12, "element-12");
 729             if (! obj.getMember("prop").equals("prop-value")) {
 730                 fail("obj.prop != 'prop-value'");
 731             }
 732 
 733             if (! obj.getSlot(12).equals("element-12")) {
 734                 fail("obj[12] != 'element-12'");
 735             }
 736 
 737             // delete properties
 738             obj.removeMember("prop");
 739             if ("prop-value".equals(obj.getMember("prop"))) {
 740                 fail("obj.prop is not deleted!");
 741             }
 742 
 743             // Simple eval tests
 744             assertEquals(obj.eval("typeof Object"), "function");
 745             assertEquals(obj.eval("'nashorn'.substring(3)"), "horn");
 746         } catch (final Exception exp) {
 747             exp.printStackTrace();
 748             fail(exp.getMessage());
 749         }
 750     }
 751 
 752     @Test
 753     public void invokeFunctionExceptionTest() {
 754         final ScriptEngineManager m = new ScriptEngineManager();
 755         final ScriptEngine e = m.getEngineByName("nashorn");
 756         try {
 757             e.eval("function func() { throw new TypeError(); }");
 758         } catch (final Throwable t) {
 759             t.printStackTrace();
 760             fail(t.getMessage());
 761         }
 762 
 763         try {
 764             ((Invocable)e).invokeFunction("func");
 765             fail("should have thrown exception");
 766         } catch (final ScriptException se) {
 767             // ECMA TypeError property wrapped as a ScriptException
 768             log("got " + se + " as expected");
 769         } catch (final Throwable t) {
 770             t.printStackTrace();
 771             fail(t.getMessage());
 772         }
 773     }
 774 
 775     @Test
 776     public void invokeMethodExceptionTest() {
 777         final ScriptEngineManager m = new ScriptEngineManager();
 778         final ScriptEngine e = m.getEngineByName("nashorn");
 779         try {
 780             e.eval("var sobj = {}; sobj.foo = function func() { throw new TypeError(); }");
 781         } catch (final Throwable t) {
 782             t.printStackTrace();
 783             fail(t.getMessage());
 784         }
 785 
 786         try {
 787             final Object sobj = e.get("sobj");
 788             ((Invocable)e).invokeMethod(sobj, "foo");
 789             fail("should have thrown exception");
 790         } catch (final ScriptException se) {
 791             // ECMA TypeError property wrapped as a ScriptException
 792             log("got " + se + " as expected");
 793         } catch (final Throwable t) {
 794             t.printStackTrace();
 795             fail(t.getMessage());
 796         }
 797     }
 798 
 799     @Test
 800     public void scriptObjectMirrorToStringTest() {
 801         final ScriptEngineManager m = new ScriptEngineManager();
 802         final ScriptEngine e = m.getEngineByName("nashorn");
 803         try {
 804             Object obj = e.eval("new TypeError('wrong type')");
 805             assertEquals(obj.toString(), "TypeError: wrong type", "toString returns wrong value");
 806         } catch (final Throwable t) {
 807             t.printStackTrace();
 808             fail(t.getMessage());
 809         }
 810 
 811         try {
 812             Object obj = e.eval("function func() { print('hello'); }");
 813             assertEquals(obj.toString(), "function func() { print('hello'); }", "toString returns wrong value");
 814         } catch (final Throwable t) {
 815             t.printStackTrace();
 816             fail(t.getMessage());
 817         }
 818     }
 819 
 820     @Test
 821     public void engineScopeTest() {
 822         final ScriptEngineManager m = new ScriptEngineManager();
 823         final ScriptEngine e = m.getEngineByName("nashorn");
 824         Bindings engineScope = e.getBindings(ScriptContext.ENGINE_SCOPE);
 825 
 826         // check few ECMA standard built-in global properties
 827         assertNotNull(engineScope.get("Object"));
 828         assertNotNull(engineScope.get("TypeError"));
 829         assertNotNull(engineScope.get("eval"));
 830 
 831         // can access via ScriptEngine.get as well
 832         assertNotNull(e.get("Object"));
 833         assertNotNull(e.get("TypeError"));
 834         assertNotNull(e.get("eval"));
 835 
 836         // Access by either way should return same object
 837         assertEquals(engineScope.get("Array"), e.get("Array"));
 838         assertEquals(engineScope.get("EvalError"), e.get("EvalError"));
 839         assertEquals(engineScope.get("undefined"), e.get("undefined"));
 840 
 841         // try exposing a new variable from scope
 842         engineScope.put("myVar", "foo");
 843         try {
 844             assertEquals(e.eval("myVar"), "foo");
 845         } catch (final ScriptException se) {
 846             se.printStackTrace();
 847             fail(se.getMessage());
 848         }
 849 
 850         // update "myVar" in script an check the value from scope
 851         try {
 852             e.eval("myVar = 'nashorn';");
 853         } catch (final ScriptException se) {
 854             se.printStackTrace();
 855             fail(se.getMessage());
 856         }
 857 
 858         // now check modified value from scope and engine
 859         assertEquals(engineScope.get("myVar"), "nashorn");
 860         assertEquals(e.get("myVar"), "nashorn");
 861     }
 862 
 863     @Test
 864     public void multiGlobalTest() {
 865         final ScriptEngineManager m = new ScriptEngineManager();
 866         final ScriptEngine e = m.getEngineByName("nashorn");
 867         final Bindings b = e.createBindings();
 868         final ScriptContext newCtxt = new SimpleScriptContext();
 869         newCtxt.setBindings(b, ScriptContext.ENGINE_SCOPE);
 870 
 871         try {
 872             Object obj1 = e.eval("Object");
 873             Object obj2 = e.eval("Object", newCtxt);
 874             Assert.assertNotEquals(obj1, obj2);
 875             Assert.assertNotNull(obj1);
 876             Assert.assertNotNull(obj2);
 877             Assert.assertEquals(obj1.toString(), obj2.toString());
 878 
 879             e.eval("x = 'hello'");
 880             e.eval("x = 'world'", newCtxt);
 881             Object x1 = e.getContext().getAttribute("x");
 882             Object x2 = newCtxt.getAttribute("x");
 883             Assert.assertNotEquals(x1, x2);
 884             Assert.assertEquals(x1, "hello");
 885             Assert.assertEquals(x2, "world");
 886 
 887             x1 = e.eval("x");
 888             x2 = e.eval("x", newCtxt);
 889             Assert.assertNotEquals(x1, x2);
 890             Assert.assertEquals(x1, "hello");
 891             Assert.assertEquals(x2, "world");
 892 
 893             final ScriptContext origCtxt = e.getContext();
 894             e.setContext(newCtxt);
 895             e.eval("y = new Object()");
 896             e.eval("y = new Object()", origCtxt);
 897 
 898             Object y1 = origCtxt.getAttribute("y");
 899             Object y2 = newCtxt.getAttribute("y");
 900             Assert.assertNotEquals(y1, y2);
 901             Assert.assertNotEquals(e.eval("y"), e.eval("y", origCtxt));
 902             Assert.assertEquals("[object Object]", y1.toString());
 903             Assert.assertEquals("[object Object]", y2.toString());
 904         } catch (final ScriptException se) {
 905             se.printStackTrace();
 906             fail(se.getMessage());
 907         }
 908     }
 909 
 910     @Test
 911     /**
 912      * Tests whether invocation of a JavaScript method through a variable arity Java method will pass the vararg array.
 913      * Both non-vararg and vararg JavaScript methods are tested.
 914      * @throws ScriptException
 915      */
 916     public void variableArityInterfaceTest() throws ScriptException {
 917         final ScriptEngineManager m = new ScriptEngineManager();
 918         final ScriptEngine e = m.getEngineByName("nashorn");
 919         e.eval(
 920             "function test1(i, strings) {" +
 921             "    return 'i == ' + i + ', strings instanceof java.lang.String[] == ' + (strings instanceof Java.type('java.lang.String[]')) + ', strings == ' + java.util.Arrays.toString(strings)" +
 922             "}" +
 923             "function test2() {" +
 924             "    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])" +
 925             "}"
 926         );
 927         final VariableArityTestInterface itf = ((Invocable)e).getInterface(VariableArityTestInterface.class);
 928         Assert.assertEquals(itf.test1(42, "a", "b"), "i == 42, strings instanceof java.lang.String[] == true, strings == [a, b]");
 929         Assert.assertEquals(itf.test2(44, "c", "d", "e"), "arguments[0] == 44, arguments[1] instanceof java.lang.String[] == true, arguments[1] == [c, d, e]");
 930     }
 931 }
--- EOF ---