ScriptEngineTest.java revision 1243:df6c3e9c1a0b
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
26package jdk.nashorn.api.scripting.test;
27
28import static org.testng.Assert.assertEquals;
29import static org.testng.Assert.assertNotNull;
30import static org.testng.Assert.assertNull;
31import static org.testng.Assert.assertTrue;
32import static org.testng.Assert.fail;
33
34import java.io.StringReader;
35import java.io.StringWriter;
36import java.lang.reflect.InvocationHandler;
37import java.lang.reflect.Method;
38import java.lang.reflect.Proxy;
39import java.util.Collections;
40import java.util.concurrent.Callable;
41import java.util.concurrent.atomic.AtomicBoolean;
42import java.util.function.Consumer;
43import java.util.function.Function;
44import javax.script.Bindings;
45import javax.script.Compilable;
46import javax.script.CompiledScript;
47import javax.script.Invocable;
48import javax.script.ScriptContext;
49import javax.script.ScriptEngine;
50import javax.script.ScriptEngineFactory;
51import javax.script.ScriptEngineManager;
52import javax.script.ScriptException;
53import javax.script.SimpleScriptContext;
54import jdk.nashorn.api.scripting.ScriptObjectMirror;
55import 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")
65public 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 String[] propNames = {
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 : propNames) {
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        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(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(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 (NullPointerException x) {
744            // expected
745        }
746
747        try {
748            e.put("", "empty-value");
749            fail();
750        } catch (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 (NullPointerException x) {
761            // expected
762        }
763
764        try {
765            b.put("", "empty-value");
766            fail();
767        } catch (IllegalArgumentException x) {
768            // expected
769        }
770
771        try {
772            b.get(null);
773            fail();
774        } catch (NullPointerException x) {
775            // expected
776        }
777
778        try {
779            b.get("");
780            fail();
781        } catch (IllegalArgumentException x) {
782            // expected
783        }
784
785        try {
786            b.get(1);
787            fail();
788        } catch (ClassCastException x) {
789            // expected
790        }
791
792        try {
793            b.remove(null);
794            fail();
795        } catch (NullPointerException x) {
796            // expected
797        }
798
799        try {
800            b.remove("");
801            fail();
802        } catch (IllegalArgumentException x) {
803            // expected
804        }
805
806        try {
807            b.remove(1);
808            fail();
809        } catch (ClassCastException x) {
810            // expected
811        }
812
813        try {
814            b.containsKey(null);
815            fail();
816        } catch (NullPointerException x) {
817            // expected
818        }
819
820        try {
821            b.containsKey("");
822            fail();
823        } catch (IllegalArgumentException x) {
824            // expected
825        }
826
827        try {
828            b.containsKey(1);
829            fail();
830        } catch (ClassCastException x) {
831            // expected
832        }
833
834        try {
835            b.putAll(null);
836            fail();
837        } catch (NullPointerException x) {
838            // expected
839        }
840
841        try {
842            b.putAll(Collections.singletonMap((String)null, "null-value"));
843            fail();
844        } catch (NullPointerException x) {
845            // expected
846        }
847
848        try {
849            b.putAll(Collections.singletonMap("", "empty-value"));
850            fail();
851        } catch (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}
882