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.test;
  27 
  28 import static org.testng.Assert.assertEquals;
  29 import static org.testng.Assert.assertNotNull;
  30 import static org.testng.Assert.assertNull;
  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.InvocationHandler;
  37 import java.lang.reflect.Method;
  38 import java.lang.reflect.Proxy;
  39 import java.util.Collections;
  40 import java.util.concurrent.Callable;
  41 import java.util.concurrent.atomic.AtomicBoolean;
  42 import java.util.function.Consumer;
  43 import java.util.function.Function;
  44 import javax.script.Bindings;
  45 import javax.script.Compilable;
  46 import javax.script.CompiledScript;
  47 import javax.script.Invocable;
  48 import javax.script.ScriptContext;
  49 import javax.script.ScriptEngine;
  50 import javax.script.ScriptEngineFactory;
  51 import javax.script.ScriptEngineManager;
  52 import javax.script.ScriptException;
  53 import javax.script.SimpleScriptContext;
  54 import jdk.nashorn.api.scripting.ScriptObjectMirror;
  55 import org.testng.annotations.Test;
  56 
  57 /**
  58  * Tests for JSR-223 script engine for Nashorn.
  59  *
  60  * @test
  61  * @build jdk.nashorn.api.scripting.test.Window jdk.nashorn.api.scripting.test.WindowEventHandler jdk.nashorn.api.scripting.test.VariableArityTestInterface jdk.nashorn.api.scripting.test.ScriptEngineTest
  62  * @run testng/othervm jdk.nashorn.api.scripting.test.ScriptEngineTest
  63  */
  64 @SuppressWarnings("javadoc")
  65 public class ScriptEngineTest {
  66 
  67     private static void log(final String msg) {
  68         org.testng.Reporter.log(msg, true);
  69     }
  70 
  71     @Test
  72     public void argumentsTest() {
  73         final ScriptEngineManager m = new ScriptEngineManager();
  74         final ScriptEngine e = m.getEngineByName("nashorn");
  75 
  76         final String[] args = new String[] { "hello", "world" };
  77         try {
  78             e.put("arguments", args);
  79             final Object arg0 = e.eval("arguments[0]");
  80             final Object arg1 = e.eval("arguments[1]");
  81             assertEquals(args[0], arg0);
  82             assertEquals(args[1], arg1);
  83         } catch (final Exception exp) {
  84             exp.printStackTrace();
  85             fail(exp.getMessage());
  86         }
  87     }
  88 
  89     @Test
  90     public void argumentsWithTest() {
  91         final ScriptEngineManager m = new ScriptEngineManager();
  92         final ScriptEngine e = m.getEngineByName("nashorn");
  93 
  94         final String[] args = new String[] { "hello", "world" };
  95         try {
  96             e.put("arguments", args);
  97             final Object arg0 = e.eval("var imports = new JavaImporter(java.io); " +
  98                     " with(imports) { arguments[0] }");
  99             final Object arg1 = e.eval("var imports = new JavaImporter(java.util, java.io); " +
 100                     " with(imports) { arguments[1] }");
 101             assertEquals(args[0], arg0);
 102             assertEquals(args[1], arg1);
 103         } catch (final Exception exp) {
 104             exp.printStackTrace();
 105             fail(exp.getMessage());
 106         }
 107     }
 108 
 109     @Test
 110     public void argumentsEmptyTest() {
 111         final ScriptEngineManager m = new ScriptEngineManager();
 112         final ScriptEngine e = m.getEngineByName("nashorn");
 113 
 114         try {
 115             assertEquals(e.eval("arguments instanceof Array"), true);
 116             assertEquals(e.eval("arguments.length == 0"), true);
 117         } catch (final Exception exp) {
 118             exp.printStackTrace();
 119             fail(exp.getMessage());
 120         }
 121     }
 122 
 123     @Test
 124     public void factoryTests() {
 125         final ScriptEngineManager m = new ScriptEngineManager();
 126         final ScriptEngine e = m.getEngineByName("nashorn");
 127         assertNotNull(e);
 128 
 129         final ScriptEngineFactory fac = e.getFactory();
 130 
 131         assertEquals(fac.getLanguageName(), "ECMAScript");
 132         assertEquals(fac.getParameter(ScriptEngine.NAME), "javascript");
 133         assertEquals(fac.getLanguageVersion(), "ECMA - 262 Edition 5.1");
 134         assertEquals(fac.getEngineName(), "Oracle Nashorn");
 135         assertEquals(fac.getOutputStatement("context"), "print(context)");
 136         assertEquals(fac.getProgram("print('hello')", "print('world')"), "print('hello');print('world');");
 137         assertEquals(fac.getParameter(ScriptEngine.NAME), "javascript");
 138 
 139         boolean seenJS = false;
 140         for (final String ext : fac.getExtensions()) {
 141             if (ext.equals("js")) {
 142                 seenJS = true;
 143             }
 144         }
 145 
 146         assertEquals(seenJS, true);
 147         final String str = fac.getMethodCallSyntax("obj", "foo", "x");
 148         assertEquals(str, "obj.foo(x)");
 149 
 150         boolean seenNashorn = false, seenJavaScript = false, seenECMAScript = false;
 151         for (final String name : fac.getNames()) {
 152             switch (name) {
 153                 case "nashorn": seenNashorn = true; break;
 154                 case "javascript": seenJavaScript = true; break;
 155                 case "ECMAScript": seenECMAScript = true; break;
 156             default:
 157                 break;
 158             }
 159         }
 160 
 161         assertTrue(seenNashorn);
 162         assertTrue(seenJavaScript);
 163         assertTrue(seenECMAScript);
 164 
 165         boolean seenAppJS = false, seenAppECMA = false, seenTextJS = false, seenTextECMA = false;
 166         for (final String mime : fac.getMimeTypes()) {
 167             switch (mime) {
 168                 case "application/javascript": seenAppJS = true; break;
 169                 case "application/ecmascript": seenAppECMA = true; break;
 170                 case "text/javascript": seenTextJS = true; break;
 171                 case "text/ecmascript": seenTextECMA = true; break;
 172             default:
 173                 break;
 174             }
 175         }
 176 
 177         assertTrue(seenAppJS);
 178         assertTrue(seenAppECMA);
 179         assertTrue(seenTextJS);
 180         assertTrue(seenTextECMA);
 181     }
 182 
 183     @Test
 184     public void evalTests() {
 185         final ScriptEngineManager m = new ScriptEngineManager();
 186         final ScriptEngine e = m.getEngineByName("nashorn");
 187         e.put(ScriptEngine.FILENAME, "myfile.js");
 188 
 189         try {
 190             e.eval("print('hello')");
 191         } catch (final ScriptException se) {
 192             fail(se.getMessage());
 193         }
 194         try {
 195             e.eval("print('hello)");
 196             fail("script exception expected");
 197         } catch (final ScriptException se) {
 198             assertEquals(se.getLineNumber(), 1);
 199             assertEquals(se.getColumnNumber(), 13);
 200             assertEquals(se.getFileName(), "myfile.js");
 201             // se.printStackTrace();
 202         }
 203 
 204         try {
 205             Object obj = e.eval("34 + 41");
 206             assertTrue(34.0 + 41.0 == ((Number)obj).doubleValue());
 207             obj = e.eval("x = 5");
 208             assertTrue(5.0 == ((Number)obj).doubleValue());
 209         } catch (final ScriptException se) {
 210             se.printStackTrace();
 211             fail(se.getMessage());
 212         }
 213     }
 214 
 215     @Test
 216     public void compileTests() {
 217         final ScriptEngineManager m = new ScriptEngineManager();
 218         final ScriptEngine e = m.getEngineByName("nashorn");
 219         CompiledScript script = null;
 220 
 221         try {
 222             script = ((Compilable)e).compile("print('hello')");
 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         // try to compile from a Reader
 235         try {
 236             script = ((Compilable)e).compile(new StringReader("print('world')"));
 237         } catch (final ScriptException se) {
 238             fail(se.getMessage());
 239         }
 240 
 241         try {
 242             script.eval();
 243         } catch (final ScriptException | NullPointerException se) {
 244             se.printStackTrace();
 245             fail(se.getMessage());
 246         }
 247     }
 248 
 249     @Test
 250     public void compileAndEvalInDiffContextTest() throws ScriptException {
 251         final ScriptEngineManager m = new ScriptEngineManager();
 252         final ScriptEngine engine = m.getEngineByName("js");
 253         final Compilable compilable = (Compilable) engine;
 254         final CompiledScript compiledScript = compilable.compile("foo");
 255         final ScriptContext ctxt = new SimpleScriptContext();
 256         ctxt.setAttribute("foo", "hello", ScriptContext.ENGINE_SCOPE);
 257         assertEquals(compiledScript.eval(ctxt), "hello");
 258     }
 259 
 260     @Test
 261     public void accessGlobalTest() {
 262         final ScriptEngineManager m = new ScriptEngineManager();
 263         final ScriptEngine e = m.getEngineByName("nashorn");
 264 
 265         try {
 266             e.eval("var x = 'hello'");
 267             assertEquals(e.get("x"), "hello");
 268         } catch (final ScriptException exp) {
 269             exp.printStackTrace();
 270             fail(exp.getMessage());
 271         }
 272     }
 273 
 274     @Test
 275     public void exposeGlobalTest() {
 276         final ScriptEngineManager m = new ScriptEngineManager();
 277         final ScriptEngine e = m.getEngineByName("nashorn");
 278 
 279         try {
 280             e.put("y", "foo");
 281             e.eval("print(y)");
 282         } catch (final ScriptException exp) {
 283             exp.printStackTrace();
 284             fail(exp.getMessage());
 285         }
 286     }
 287 
 288     @Test
 289     public void putGlobalFunctionTest() {
 290         final ScriptEngineManager m = new ScriptEngineManager();
 291         final ScriptEngine e = m.getEngineByName("nashorn");
 292 
 293         e.put("callable", new Callable<String>() {
 294             @Override
 295             public String call() throws Exception {
 296                 return "callable was called";
 297             }
 298         });
 299 
 300         try {
 301             e.eval("print(callable.call())");
 302         } catch (final ScriptException exp) {
 303             exp.printStackTrace();
 304             fail(exp.getMessage());
 305         }
 306     }
 307 
 308     @Test
 309     public void windowAlertTest() {
 310         final ScriptEngineManager m = new ScriptEngineManager();
 311         final ScriptEngine e = m.getEngineByName("nashorn");
 312         final Window window = new Window();
 313 
 314         try {
 315             e.put("window", window);
 316             e.eval("print(window.alert)");
 317             e.eval("window.alert('calling window.alert...')");
 318         } catch (final Exception exp) {
 319             exp.printStackTrace();
 320             fail(exp.getMessage());
 321         }
 322     }
 323 
 324     @Test
 325     public void windowLocationTest() {
 326         final ScriptEngineManager m = new ScriptEngineManager();
 327         final ScriptEngine e = m.getEngineByName("nashorn");
 328         final Window window = new Window();
 329 
 330         try {
 331             e.put("window", window);
 332             e.eval("print(window.location)");
 333             final Object locationValue = e.eval("window.getLocation()");
 334             assertEquals(locationValue, "http://localhost:8080/window");
 335         } catch (final Exception exp) {
 336             exp.printStackTrace();
 337             fail(exp.getMessage());
 338         }
 339     }
 340 
 341     @Test
 342     public void windowItemTest() {
 343         final ScriptEngineManager m = new ScriptEngineManager();
 344         final ScriptEngine e = m.getEngineByName("nashorn");
 345         final Window window = new Window();
 346 
 347         try {
 348             e.put("window", window);
 349             final String item1 = (String)e.eval("window.item(65535)");
 350             assertEquals(item1, "ffff");
 351             final String item2 = (String)e.eval("window.item(255)");
 352             assertEquals(item2, "ff");
 353         } catch (final Exception exp) {
 354             exp.printStackTrace();
 355             fail(exp.getMessage());
 356         }
 357     }
 358 
 359     @Test
 360     public void windowEventTest() {
 361         final ScriptEngineManager m = new ScriptEngineManager();
 362         final ScriptEngine e = m.getEngineByName("nashorn");
 363         final Window window = new Window();
 364 
 365         try {
 366             e.put("window", window);
 367             e.eval("window.onload = function() { print('window load event fired'); return true }");
 368             assertTrue((Boolean)e.eval("window.onload.loaded()"));
 369             final WindowEventHandler handler = window.getOnload();
 370             assertNotNull(handler);
 371             assertTrue(handler.loaded());
 372         } catch (final Exception exp) {
 373             exp.printStackTrace();
 374             fail(exp.getMessage());
 375         }
 376     }
 377 
 378     @Test
 379     public void throwTest() {
 380         final ScriptEngineManager m = new ScriptEngineManager();
 381         final ScriptEngine e = m.getEngineByName("nashorn");
 382         e.put(ScriptEngine.FILENAME, "throwtest.js");
 383 
 384         try {
 385             e.eval("throw 'foo'");
 386         } catch (final ScriptException exp) {
 387             log(exp.getMessage());
 388             assertEquals(exp.getMessage(), "foo in throwtest.js at line number 1 at column number 0");
 389             assertEquals(exp.getFileName(), "throwtest.js");
 390             assertEquals(exp.getLineNumber(), 1);
 391         }
 392     }
 393 
 394     @Test
 395     public void setTimeoutTest() {
 396         final ScriptEngineManager m = new ScriptEngineManager();
 397         final ScriptEngine e = m.getEngineByName("nashorn");
 398         final Window window = new Window();
 399 
 400         try {
 401             final Class<?> setTimeoutParamTypes[] = { Window.class, String.class, int.class };
 402             final Method setTimeout = Window.class.getDeclaredMethod("setTimeout", setTimeoutParamTypes);
 403             assertNotNull(setTimeout);
 404             e.put("window", window);
 405             e.eval("window.setTimeout('foo()', 100)");
 406 
 407             // try to make setTimeout global
 408             e.put("setTimeout", setTimeout);
 409             // TODO: java.lang.ClassCastException: required class
 410             // java.lang.Integer but encountered class java.lang.Double
 411             // e.eval("setTimeout('foo2()', 200)");
 412         } catch (final Exception exp) {
 413             exp.printStackTrace();
 414             fail(exp.getMessage());
 415         }
 416     }
 417 
 418     @Test
 419     public void setWriterTest() {
 420         final ScriptEngineManager m = new ScriptEngineManager();
 421         final ScriptEngine e = m.getEngineByName("nashorn");
 422         final StringWriter sw = new StringWriter();
 423         e.getContext().setWriter(sw);
 424 
 425         try {
 426             e.eval("print('hello world')");
 427         } catch (final Exception exp) {
 428             exp.printStackTrace();
 429             fail(exp.getMessage());
 430         }
 431         assertEquals(sw.toString(), println("hello world"));
 432     }
 433 
 434     @Test
 435     public void redefineEchoTest() {
 436         final ScriptEngineManager m = new ScriptEngineManager();
 437         final ScriptEngine e = m.getEngineByName("nashorn");
 438 
 439         try {
 440             e.eval("var echo = {}; if (typeof echo !== 'object') { throw 'echo is a '+typeof echo; }");
 441         } catch (final Exception exp) {
 442             exp.printStackTrace();
 443             fail(exp.getMessage());
 444         }
 445     }
 446     @Test
 447     public void noEnumerablePropertiesTest() {
 448         final ScriptEngineManager m = new ScriptEngineManager();
 449         final ScriptEngine e = m.getEngineByName("nashorn");
 450         try {
 451             e.eval("for (i in this) { throw 'found property: ' + i }");
 452         } catch (final Exception exp) {
 453             exp.printStackTrace();
 454             fail(exp.getMessage());
 455         }
 456     }
 457 
 458     @Test
 459     public void noRefErrorForGlobalThisAccessTest() {
 460         final ScriptEngineManager m = new ScriptEngineManager();
 461         final ScriptEngine e = m.getEngineByName("nashorn");
 462         try {
 463             e.eval("this.foo");
 464         } catch (final Exception exp) {
 465             exp.printStackTrace();
 466             fail(exp.getMessage());
 467         }
 468     }
 469 
 470     @Test
 471     public void refErrorForUndeclaredAccessTest() {
 472         final ScriptEngineManager m = new ScriptEngineManager();
 473         final ScriptEngine e = m.getEngineByName("nashorn");
 474         try {
 475             e.eval("try { print(foo); throw 'no ref error' } catch (e) { if (!(e instanceof ReferenceError)) throw e; }");
 476         } catch (final Exception exp) {
 477             exp.printStackTrace();
 478             fail(exp.getMessage());
 479         }
 480     }
 481 
 482     @Test
 483     public void typeErrorForGlobalThisCallTest() {
 484         final ScriptEngineManager m = new ScriptEngineManager();
 485         final ScriptEngine e = m.getEngineByName("nashorn");
 486         try {
 487             e.eval("try { this.foo() } catch(e) { if (! (e instanceof TypeError)) throw 'no type error' }");
 488         } catch (final Exception exp) {
 489             exp.printStackTrace();
 490             fail(exp.getMessage());
 491         }
 492     }
 493 
 494     @Test
 495     public void refErrorForUndeclaredCallTest() {
 496         final ScriptEngineManager m = new ScriptEngineManager();
 497         final ScriptEngine e = m.getEngineByName("nashorn");
 498         try {
 499             e.eval("try { foo() } catch(e) { if (! (e instanceof ReferenceError)) throw 'no ref error' }");
 500         } catch (final Exception exp) {
 501             exp.printStackTrace();
 502             fail(exp.getMessage());
 503         }
 504     }
 505 
 506     @Test
 507     // check that print function prints arg followed by newline char
 508     public void printTest() {
 509         final ScriptEngineManager m = new ScriptEngineManager();
 510         final ScriptEngine e = m.getEngineByName("nashorn");
 511         final StringWriter sw = new StringWriter();
 512         e.getContext().setWriter(sw);
 513         try {
 514             e.eval("print('hello')");
 515         } catch (final Throwable t) {
 516             t.printStackTrace();
 517             fail(t.getMessage());
 518         }
 519 
 520         assertEquals(sw.toString(), println("hello"));
 521     }
 522 
 523     @Test
 524     // check that print prints all arguments (more than one)
 525     public void printManyTest() {
 526         final ScriptEngineManager m = new ScriptEngineManager();
 527         final ScriptEngine e = m.getEngineByName("nashorn");
 528         final StringWriter sw = new StringWriter();
 529         e.getContext().setWriter(sw);
 530         try {
 531             e.eval("print(34, true, 'hello')");
 532         } catch (final Throwable t) {
 533             t.printStackTrace();
 534             fail(t.getMessage());
 535         }
 536 
 537         assertEquals(sw.toString(), println("34 true hello"));
 538     }
 539 
 540     @Test
 541     public void scriptObjectAutoConversionTest() throws ScriptException {
 542         final ScriptEngineManager m = new ScriptEngineManager();
 543         final ScriptEngine e = m.getEngineByName("nashorn");
 544         e.eval("obj = { foo: 'hello' }");
 545         e.put("Window", e.eval("Packages.jdk.nashorn.api.scripting.test.Window"));
 546         assertEquals(e.eval("Window.funcJSObject(obj)"), "hello");
 547         assertEquals(e.eval("Window.funcScriptObjectMirror(obj)"), "hello");
 548         assertEquals(e.eval("Window.funcMap(obj)"), "hello");
 549         assertEquals(e.eval("Window.funcJSObject(obj)"), "hello");
 550     }
 551 
 552     // @bug 8032948: Nashorn linkages awry
 553     @Test
 554     public void checkProxyAccess() throws ScriptException {
 555         final ScriptEngineManager m = new ScriptEngineManager();
 556         final ScriptEngine e = m.getEngineByName("nashorn");
 557         final boolean[] reached = new boolean[1];
 558         final Runnable r = (Runnable)Proxy.newProxyInstance(
 559             ScriptEngineTest.class.getClassLoader(),
 560             new Class[] { Runnable.class },
 561             new InvocationHandler() {
 562                 @Override
 563                 public Object invoke(final Object p, final Method mtd, final Object[] a) {
 564                     reached[0] = true;
 565                     return null;
 566                 }
 567             });
 568 
 569         e.put("r", r);
 570         e.eval("r.run()");
 571 
 572         assertTrue(reached[0]);
 573     }
 574 
 575     // properties that can be read by any code
 576     private static final String[] PROP_NAMES = {
 577         "java.version",
 578         "java.vendor",
 579         "java.vendor.url",
 580         "java.class.version",
 581         "os.name",
 582         "os.version",
 583         "os.arch",
 584         "file.separator",
 585         "path.separator",
 586         "line.separator",
 587         "java.specification.version",
 588         "java.specification.vendor",
 589         "java.specification.name",
 590         "java.vm.specification.version",
 591         "java.vm.specification.vendor",
 592         "java.vm.specification.name",
 593         "java.vm.version",
 594         "java.vm.vendor",
 595         "java.vm.name"
 596     };
 597 
 598     // @bug 8033924: Default permissions are not given for eval code
 599     @Test
 600     public void checkPropertyReadPermissions() throws ScriptException {
 601         final ScriptEngineManager m = new ScriptEngineManager();
 602         final ScriptEngine e = m.getEngineByName("nashorn");
 603 
 604         for (final String name : PROP_NAMES) {
 605             checkProperty(e, name);
 606         }
 607     }
 608 
 609     // @bug 8046013: TypeError: Cannot apply "with" to non script object
 610     @Test
 611     public void withOnMirrorTest() throws ScriptException {
 612         final ScriptEngineManager m = new ScriptEngineManager();
 613         final ScriptEngine e = m.getEngineByName("nashorn");
 614 
 615         final Object obj = e.eval("({ foo: 'hello'})");
 616         final Object[] arr = new Object[1];
 617         arr[0] = obj;
 618         e.put("arr", arr);
 619         final Object res = e.eval("var res; with(arr[0]) { res = foo; }; res");
 620         assertEquals(res, "hello");
 621     }
 622 
 623     // @bug 8054223: Nashorn: AssertionError when use __DIR__ and ScriptEngine.eval()
 624     @Test
 625     public void check__DIR__Test() throws ScriptException {
 626         final ScriptEngineManager m = new ScriptEngineManager();
 627         final ScriptEngine e = m.getEngineByName("nashorn");
 628         e.eval("__DIR__");
 629     }
 630 
 631     // @bug 8050432:javax.script.filename variable should not be enumerable
 632     // with nashorn engine's ENGINE_SCOPE bindings
 633     @Test
 634     public void enumerableGlobalsTest() throws ScriptException {
 635         final ScriptEngineManager m = new ScriptEngineManager();
 636         final ScriptEngine e = m.getEngineByName("nashorn");
 637 
 638         e.put(ScriptEngine.FILENAME, "test");
 639         final Object enumerable = e.eval(
 640             "Object.getOwnPropertyDescriptor(this, " +
 641             " 'javax.script.filename').enumerable");
 642         assertEquals(enumerable, Boolean.FALSE);
 643     }
 644 
 645     public static class Context {
 646         private Object myobj;
 647 
 648         public void set(final Object o) {
 649             myobj = o;
 650         }
 651 
 652         public Object get() {
 653             return myobj;
 654         }
 655     }
 656 
 657     // @bug 8050977: Java8 Javascript Nashorn exception:
 658     // no current Global instance for nashorn
 659     @Test
 660     public void currentGlobalMissingTest() throws Exception {
 661         final ScriptEngineManager manager = new ScriptEngineManager();
 662         final ScriptEngine e = manager.getEngineByName("nashorn");
 663 
 664         final Context ctx = new Context();
 665         e.put("ctx", ctx);
 666         e.eval("var obj = { foo: function(str) { return str.toUpperCase() } }");
 667         e.eval("ctx.set(obj)");
 668         final Invocable inv = (Invocable)e;
 669         assertEquals("HELLO", inv.invokeMethod(ctx.get(), "foo", "hello"));
 670         // try object literal
 671         e.eval("ctx.set({ bar: function(str) { return str.toLowerCase() } })");
 672         assertEquals("hello", inv.invokeMethod(ctx.get(), "bar", "HELLO"));
 673         // try array literal
 674         e.eval("var arr = [ 'hello', 'world' ]");
 675         e.eval("ctx.set(arr)");
 676         assertEquals("helloworld", inv.invokeMethod(ctx.get(), "join", ""));
 677     }
 678 
 679     // @bug 8068524: NashornScriptEngineFactory.getParameter() throws IAE
 680     // for an unknown key, doesn't conform to the general spec
 681     @Test
 682     public void getParameterInvalidKeyTest() throws Exception {
 683         final ScriptEngineManager manager = new ScriptEngineManager();
 684         final ScriptEngine e = manager.getEngineByName("nashorn");
 685         // no exception expected here!
 686         final Object value = e.getFactory().getParameter("no value assigned to this key");
 687         assertNull(value);
 688     }
 689 
 690     // @bug JDK-8068889: ConsString arguments to a functional interface wasn't converted to string.
 691     @Test
 692     public void functionalInterfaceStringTest() throws Exception {
 693         final ScriptEngineManager manager = new ScriptEngineManager();
 694         final ScriptEngine e = manager.getEngineByName("nashorn");
 695         final AtomicBoolean invoked = new AtomicBoolean(false);
 696         e.put("f", new Function<String, String>() {
 697             @Override
 698             public String apply(final String t) {
 699                 invoked.set(true);
 700                 return t;
 701             }
 702         });
 703         assertEquals(e.eval("var x = 'a'; x += 'b'; f(x)"), "ab");
 704         assertTrue(invoked.get());
 705     }
 706 
 707     // @bug JDK-8068889: ScriptObject arguments to a functional interface wasn't converted to a mirror.
 708     @Test
 709     public void functionalInterfaceObjectTest() throws Exception {
 710         final ScriptEngineManager manager = new ScriptEngineManager();
 711         final ScriptEngine e = manager.getEngineByName("nashorn");
 712         final AtomicBoolean invoked = new AtomicBoolean(false);
 713         e.put("c", new Consumer<Object>() {
 714             @Override
 715             public void accept(final Object t) {
 716                 assertTrue(t instanceof ScriptObjectMirror);
 717                 assertEquals(((ScriptObjectMirror)t).get("a"), "xyz");
 718                 invoked.set(true);
 719             }
 720         });
 721         e.eval("var x = 'xy'; x += 'z';c({a:x})");
 722         assertTrue(invoked.get());
 723     }
 724 
 725     @Test
 726     public void testLengthOnArrayLikeObjects() throws Exception {
 727         final ScriptEngine e = new ScriptEngineManager().getEngineByName("nashorn");
 728         final Object val = e.eval("var arr = { length: 1, 0: 1}; arr.length");
 729 
 730         assertTrue(Number.class.isAssignableFrom(val.getClass()));
 731         assertTrue(((Number)val).intValue() == 1);
 732     }
 733 
 734     // @bug JDK-8068603: NashornScriptEngine.put/get() impls don't conform to NPE, IAE spec assertions
 735     @Test
 736     public void illegalBindingsValuesTest() throws Exception {
 737         final ScriptEngineManager manager = new ScriptEngineManager();
 738         final ScriptEngine e = manager.getEngineByName("nashorn");
 739 
 740         try {
 741             e.put(null, "null-value");
 742             fail();
 743         } catch (final NullPointerException x) {
 744             // expected
 745         }
 746 
 747         try {
 748             e.put("", "empty-value");
 749             fail();
 750         } catch (final IllegalArgumentException x) {
 751             // expected
 752         }
 753 
 754         final Bindings b = e.getBindings(ScriptContext.ENGINE_SCOPE);
 755         assertTrue(b instanceof ScriptObjectMirror);
 756 
 757         try {
 758             b.put(null, "null-value");
 759             fail();
 760         } catch (final NullPointerException x) {
 761             // expected
 762         }
 763 
 764         try {
 765             b.put("", "empty-value");
 766             fail();
 767         } catch (final IllegalArgumentException x) {
 768             // expected
 769         }
 770 
 771         try {
 772             b.get(null);
 773             fail();
 774         } catch (final NullPointerException x) {
 775             // expected
 776         }
 777 
 778         try {
 779             b.get("");
 780             fail();
 781         } catch (final IllegalArgumentException x) {
 782             // expected
 783         }
 784 
 785         try {
 786             b.get(1);
 787             fail();
 788         } catch (final ClassCastException x) {
 789             // expected
 790         }
 791 
 792         try {
 793             b.remove(null);
 794             fail();
 795         } catch (final NullPointerException x) {
 796             // expected
 797         }
 798 
 799         try {
 800             b.remove("");
 801             fail();
 802         } catch (final IllegalArgumentException x) {
 803             // expected
 804         }
 805 
 806         try {
 807             b.remove(1);
 808             fail();
 809         } catch (final ClassCastException x) {
 810             // expected
 811         }
 812 
 813         try {
 814             b.containsKey(null);
 815             fail();
 816         } catch (final NullPointerException x) {
 817             // expected
 818         }
 819 
 820         try {
 821             b.containsKey("");
 822             fail();
 823         } catch (final IllegalArgumentException x) {
 824             // expected
 825         }
 826 
 827         try {
 828             b.containsKey(1);
 829             fail();
 830         } catch (final ClassCastException x) {
 831             // expected
 832         }
 833 
 834         try {
 835             b.putAll(null);
 836             fail();
 837         } catch (final NullPointerException x) {
 838             // expected
 839         }
 840 
 841         try {
 842             b.putAll(Collections.singletonMap((String)null, "null-value"));
 843             fail();
 844         } catch (final NullPointerException x) {
 845             // expected
 846         }
 847 
 848         try {
 849             b.putAll(Collections.singletonMap("", "empty-value"));
 850             fail();
 851         } catch (final IllegalArgumentException x) {
 852             // expected
 853         }
 854     }
 855 
 856     // @bug 8071989: NashornScriptEngine returns javax.script.ScriptContext instance
 857     // with insonsistent get/remove methods behavior for undefined attributes
 858     @Test
 859     public void testScriptContextGetRemoveUndefined() throws Exception {
 860         final ScriptEngineManager manager = new ScriptEngineManager();
 861         final ScriptEngine e = manager.getEngineByName("nashorn");
 862         final ScriptContext ctx = e.getContext();
 863         assertNull(ctx.getAttribute("undefinedname", ScriptContext.ENGINE_SCOPE));
 864         assertNull(ctx.removeAttribute("undefinedname", ScriptContext.ENGINE_SCOPE));
 865     }
 866 
 867     private static void checkProperty(final ScriptEngine e, final String name)
 868         throws ScriptException {
 869         final String value = System.getProperty(name);
 870         e.put("name", name);
 871         assertEquals(value, e.eval("java.lang.System.getProperty(name)"));
 872     }
 873 
 874     private static final String LINE_SEPARATOR = System.getProperty("line.separator");
 875 
 876     // Returns String that would be the result of calling PrintWriter.println
 877     // of the given String. (This is to handle platform specific newline).
 878     private static String println(final String str) {
 879         return str + LINE_SEPARATOR;
 880     }
 881 }