1 /*
   2  * Copyright (c) 2016, 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 package jdk.nashorn.internal.runtime.linker.test;
  26 
  27 import java.util.Collection;
  28 import java.util.Deque;
  29 import java.util.List;
  30 import java.util.Map;
  31 import java.util.Queue;
  32 import java.util.function.Function;
  33 import java.util.function.Supplier;
  34 import javax.script.Bindings;
  35 import javax.script.ScriptContext;
  36 import javax.script.ScriptEngine;
  37 import javax.script.ScriptException;
  38 import jdk.nashorn.api.scripting.JSObject;
  39 import jdk.nashorn.api.scripting.NashornScriptEngine;
  40 import jdk.nashorn.api.scripting.NashornScriptEngineFactory;
  41 import jdk.nashorn.api.scripting.ScriptObjectMirror;
  42 import jdk.nashorn.internal.runtime.Context;
  43 import org.testng.Assert;
  44 import org.testng.annotations.Test;
  45 
  46 public class JavaAdapterTest {
  47     public interface TestConversions {
  48         public byte getByte(byte b);
  49         public short getShort(short b);
  50         public char getChar(char c);
  51         public int getInt(int i);
  52         public float getFloat(float f);
  53         public long getLong(long l);
  54         public double getDouble(double d);
  55     }
  56 
  57     @Test
  58     public static void testBlah() throws ScriptException {
  59         final ScriptEngine e = createEngine();
  60         e.eval("new java.util.Comparator({})");
  61     }
  62 
  63     @Test
  64     public static void testConversions() throws ScriptException {
  65         final ScriptEngine e = createEngine();
  66         e.put("TestConversionsClass", TestConversions.class);
  67         final TestConversions tc = (TestConversions)e.eval(
  68                 "function id(x) { return x };" +
  69                 "new TestConversionsClass.static({" +
  70                 "  getByte: id, getShort: id, getChar: id, getInt: id," +
  71                 "  getFloat: id, getLong: id, getDouble: id });");
  72 
  73         Assert.assertEquals(Byte.MIN_VALUE, tc.getByte(Byte.MIN_VALUE));
  74         Assert.assertEquals(Byte.MAX_VALUE, tc.getByte(Byte.MAX_VALUE));
  75 
  76         Assert.assertEquals(Short.MIN_VALUE, tc.getShort(Short.MIN_VALUE));
  77         Assert.assertEquals(Short.MAX_VALUE, tc.getShort(Short.MAX_VALUE));
  78 
  79         Assert.assertEquals(Character.MIN_VALUE, tc.getChar(Character.MIN_VALUE));
  80         Assert.assertEquals(Character.MAX_VALUE, tc.getChar(Character.MAX_VALUE));
  81 
  82         Assert.assertEquals(Integer.MIN_VALUE, tc.getInt(Integer.MIN_VALUE));
  83         Assert.assertEquals(Integer.MAX_VALUE, tc.getInt(Integer.MAX_VALUE));
  84 
  85         Assert.assertEquals(Long.MIN_VALUE, tc.getLong(Long.MIN_VALUE));
  86         Assert.assertEquals(Long.MAX_VALUE, tc.getLong(Long.MAX_VALUE));
  87 
  88         Assert.assertEquals(Float.MIN_VALUE, tc.getFloat(Float.MIN_VALUE));
  89         Assert.assertEquals(Float.MAX_VALUE, tc.getFloat(Float.MAX_VALUE));
  90         Assert.assertEquals(Float.MIN_NORMAL, tc.getFloat(Float.MIN_NORMAL));
  91         Assert.assertEquals(Float.POSITIVE_INFINITY, tc.getFloat(Float.POSITIVE_INFINITY));
  92         Assert.assertEquals(Float.NEGATIVE_INFINITY, tc.getFloat(Float.NEGATIVE_INFINITY));
  93         Assert.assertTrue(Float.isNaN(tc.getFloat(Float.NaN)));
  94 
  95         Assert.assertEquals(Double.MIN_VALUE, tc.getDouble(Double.MIN_VALUE));
  96         Assert.assertEquals(Double.MAX_VALUE, tc.getDouble(Double.MAX_VALUE));
  97         Assert.assertEquals(Double.MIN_NORMAL, tc.getDouble(Double.MIN_NORMAL));
  98         Assert.assertEquals(Double.POSITIVE_INFINITY, tc.getDouble(Double.POSITIVE_INFINITY));
  99         Assert.assertEquals(Double.NEGATIVE_INFINITY, tc.getDouble(Double.NEGATIVE_INFINITY));
 100         Assert.assertTrue(Double.isNaN(tc.getDouble(Double.NaN)));
 101     }
 102 
 103     private static ScriptEngine createEngine() {
 104         // Use no optimistic typing so we run faster; short-running tests.
 105         return new NashornScriptEngineFactory().getScriptEngine("-ot=false");
 106     }
 107 
 108     @Test
 109     public static void testUnimplemented() throws ScriptException {
 110         final ScriptEngine e = createEngine();
 111         final Runnable r = (Runnable) e.eval("new java.lang.Runnable({})");
 112         Assert.assertNull(Context.getGlobal());
 113         try {
 114             r.run();
 115             Assert.fail();
 116         } catch(final UnsupportedOperationException x) {
 117             // This is expected
 118         }
 119         // Check global has been restored
 120         Assert.assertNull(Context.getGlobal());
 121     }
 122 
 123     public interface ThrowingRunnable {
 124         public void run() throws Throwable;
 125     }
 126 
 127     @Test
 128     public static void testUnimplementedWithThrowable() throws Throwable {
 129         final ScriptEngine e = createEngine();
 130         e.put("ThrowingRunnableClass", ThrowingRunnable.class);
 131         final ThrowingRunnable r = (ThrowingRunnable) e.eval("new ThrowingRunnableClass.static({})");
 132         Assert.assertNull(Context.getGlobal());
 133         try {
 134             r.run();
 135             Assert.fail();
 136         } catch(final UnsupportedOperationException x) {
 137             // This is expected
 138         }
 139         // Check global has been restored
 140         Assert.assertNull(Context.getGlobal());
 141     }
 142 
 143     public interface IntSupplierWithDefault {
 144         public default int get() { return 42; }
 145     }
 146 
 147     @Test
 148     public static void testUnimplementedWithDefault() throws ScriptException {
 149         final ScriptEngine e = createEngine();
 150         e.put("IntSupplierWithDefault", IntSupplierWithDefault.class);
 151         final IntSupplierWithDefault s1 = (IntSupplierWithDefault) e.eval("new IntSupplierWithDefault.static({})");
 152         Assert.assertEquals(42, s1.get());
 153         final IntSupplierWithDefault s2 = (IntSupplierWithDefault) e.eval("new IntSupplierWithDefault.static({ get: function() { return 43 }})");
 154         Assert.assertEquals(43, s2.get());
 155     }
 156 
 157     public interface SupplierSupplier {
 158         public Supplier<Object> getSupplier();
 159     }
 160 
 161     @Test
 162     public static void testReturnAdapter() throws ScriptException {
 163         final ScriptEngine e = createEngine();
 164         e.put("SupplierSupplier", SupplierSupplier.class);
 165         final SupplierSupplier s = (SupplierSupplier) e.eval("new SupplierSupplier.static(function(){ return function() { return 'foo' } })");
 166         Assert.assertEquals("foo", s.getSupplier().get());
 167     }
 168 
 169     public interface MaxParams {
 170         public Object method(boolean p1, byte p2, short p3, char p4, int p5, float p6, long p7, double p8,
 171                 Object p9, Object p10, Object p11, Object p12, Object p13, Object p14, Object p15, Object p16,
 172                 Object p17, Object p18, Object p19, Object p20, Object p21, Object p22, Object p23, Object p24,
 173                 Object p25, Object p26, Object p27, Object p28, Object p29, Object p30, Object p31, Object p32,
 174                 Object p33, Object p34, Object p35, Object p36, Object p37, Object p38, Object p39, Object p40,
 175                 Object p41, Object p42, Object p43, Object p44, Object p45, Object p46, Object p47, Object p48,
 176                 Object p49, Object p50, Object p51, Object p52, Object p53, Object p54, Object p55, Object p56,
 177                 Object p57, Object p58, Object p59, Object p60, Object p61, Object p62, Object p63, Object p64,
 178                 Object p65, Object p66, Object p67, Object p68, Object p69, Object p70, Object p71, Object p72,
 179                 Object p73, Object p74, Object p75, Object p76, Object p77, Object p78, Object p79, Object p80,
 180                 Object p81, Object p82, Object p83, Object p84, Object p85, Object p86, Object p87, Object p88,
 181                 Object p89, Object p90, Object p91, Object p92, Object p93, Object p94, Object p95, Object p96,
 182                 Object p97, Object p98, Object p99, Object p100, Object p101, Object p102, Object p103, Object p104,
 183                 Object p105, Object p106, Object p107, Object p108, Object p109, Object p110, Object p111, Object p112,
 184                 Object p113, Object p114, Object p115, Object p116, Object p117, Object p118, Object p119, Object p120,
 185                 Object p121, Object p122, Object p123, Object p124, Object p125, Object p126, Object p127, Object p128,
 186                 Object p129, Object p130, Object p131, Object p132, Object p133, Object p134, Object p135, Object p136,
 187                 Object p137, Object p138, Object p139, Object p140, Object p141, Object p142, Object p143, Object p144,
 188                 Object p145, Object p146, Object p147, Object p148, Object p149, Object p150, Object p151, Object p152,
 189                 Object p153, Object p154, Object p155, Object p156, Object p157, Object p158, Object p159, Object p160,
 190                 Object p161, Object p162, Object p163, Object p164, Object p165, Object p166, Object p167, Object p168,
 191                 Object p169, Object p170, Object p171, Object p172, Object p173, Object p174, Object p175, Object p176,
 192                 Object p177, Object p178, Object p179, Object p180, Object p181, Object p182, Object p183, Object p184,
 193                 Object p185, Object p186, Object p187, Object p188, Object p189, Object p190, Object p191, Object p192,
 194                 Object p193, Object p194, Object p195, Object p196, Object p197, Object p198, Object p199, Object p200,
 195                 Object p201, Object p202, Object p203, Object p204, Object p205, Object p206, Object p207, Object p208,
 196                 Object p209, Object p210, Object p211, Object p212, Object p213, Object p214, Object p215, Object p216,
 197                 Object p217, Object p218, Object p219, Object p220, Object p221, Object p222, Object p223, Object p224,
 198                 Object p225, Object p226, Object p227, Object p228, Object p229, Object p230, Object p231, Object p232,
 199                 Object p233, Object p234, Object p235, Object p236, Object p237, Object p238, Object p239, Object p240,
 200                 Object p241, Object p242, Object p243, Object p244, Object p245, Object p246, Object p247, Object p248,
 201                 Object p249, Object p250, Object p251, Object p252);
 202     }
 203 
 204     @Test
 205     public static void testMaxLengthAdapter() throws ScriptException {
 206         final ScriptEngine e = createEngine();
 207         e.put("MaxParams", MaxParams.class);
 208         final MaxParams s = (MaxParams) e.eval("new MaxParams.static(function(){ return arguments })");
 209         final ScriptObjectMirror m = (ScriptObjectMirror)s.method(true, Byte.MIN_VALUE, Short.MIN_VALUE, 'a', Integer.MAX_VALUE, Float.MAX_VALUE, Long.MAX_VALUE, Double.MAX_VALUE,
 210                 "8", "9", "10", "11", "12", "13", "14", "15", "16", "17", "18", "19", "20", "21", "22", "23", "24", "25", "26",
 211                 "27", "28", "29", "30", "31", "32", "33", "34", "35", "36", "37", "38", "39", "40", "41", "42", "43", "44",
 212                 "45", "46", "47", "48", "49", "50", "51", "52", "53", "54", "55", "56", "57", "58", "59", "60", "61", "62",
 213                 "63", "64", "65", "66", "67", "68", "69", "70", "71", "72", "73", "74", "75", "76", "77", "78", "79", "80",
 214                 "81", "82", "83", "84", "85", "86", "87", "88", "89", "90", "91", "92", "93", "94", "95", "96", "97", "98",
 215                 "99", "100", "101", "102", "103", "104", "105", "106", "107", "108", "109", "110", "111", "112", "113", "114",
 216                 "115", "116", "117", "118", "119", "120", "121", "122", "123", "124", "125", "126", "127", "128", "129", "130",
 217                 "131", "132", "133", "134", "135", "136", "137", "138", "139", "140", "141", "142", "143", "144", "145", "146",
 218                 "147", "148", "149", "150", "151", "152", "153", "154", "155", "156", "157", "158", "159", "160", "161", "162",
 219                 "163", "164", "165", "166", "167", "168", "169", "170", "171", "172", "173", "174", "175", "176", "177", "178",
 220                 "179", "180", "181", "182", "183", "184", "185", "186", "187", "188", "189", "190", "191", "192", "193", "194",
 221                 "195", "196", "197", "198", "199", "200", "201", "202", "203", "204", "205", "206", "207", "208", "209", "210",
 222                 "211", "212", "213", "214", "215", "216", "217", "218", "219", "220", "221", "222", "223", "224", "225", "226",
 223                 "227", "228", "229", "230", "231", "232", "233", "234", "235", "236", "237", "238", "239", "240", "241", "242",
 224                 "243", "244", "245", "246", "247", "248", "249", "250", "251");
 225         Assert.assertEquals(true, m.getSlot(0));
 226         Assert.assertEquals(Integer.valueOf(Byte.MIN_VALUE), m.getSlot(1)); // Byte becomes Integer
 227         Assert.assertEquals(Integer.valueOf(Short.MIN_VALUE), m.getSlot(2)); // Short becomes Integer
 228         Assert.assertEquals(Character.valueOf('a'), m.getSlot(3));
 229         Assert.assertEquals(Integer.valueOf(Integer.MAX_VALUE), m.getSlot(4));
 230         Assert.assertEquals(Double.valueOf(Float.MAX_VALUE), m.getSlot(5)); // Float becomes Double
 231         Assert.assertEquals(Long.valueOf(Long.MAX_VALUE), m.getSlot(6)); // Long was untouched
 232         Assert.assertEquals(Double.valueOf(Double.MAX_VALUE), m.getSlot(7));
 233         for (int i = 8; i < 252; ++i) {
 234             Assert.assertEquals(String.valueOf(i), m.getSlot(i));
 235         }
 236     }
 237 
 238     public interface TestScriptObjectMirror {
 239         public JSObject getJSObject();
 240         public ScriptObjectMirror getScriptObjectMirror();
 241         public Map<Object, Object> getMap();
 242         public Bindings getBindings();
 243     }
 244 
 245     @Test
 246     public static void testReturnsScriptObjectMirror() throws ScriptException {
 247         final ScriptEngine e = createEngine();
 248         e.put("TestScriptObjectMirrorClass", TestScriptObjectMirror.class);
 249         final TestScriptObjectMirror tsom = (TestScriptObjectMirror)e.eval(
 250                 "new TestScriptObjectMirrorClass.static({\n" +
 251                 "  getJSObject: function() { return { 'kind': 'JSObject' } },\n" +
 252                 "  getScriptObjectMirror: function() { return { 'kind': 'ScriptObjectMirror' } },\n" +
 253                 "  getMap: function() { return { 'kind': 'Map' } },\n" +
 254                 "  getBindings: function() { return { 'kind': 'Bindings' } } })\n");
 255         Assert.assertEquals(tsom.getJSObject().getMember("kind"), "JSObject");
 256         Assert.assertEquals(tsom.getScriptObjectMirror().getMember("kind"), "ScriptObjectMirror");
 257         Assert.assertEquals(tsom.getMap().get("kind"), "Map");
 258         Assert.assertEquals(tsom.getBindings().get("kind"), "Bindings");
 259     }
 260 
 261     public interface TestListAdapter {
 262         public List<Object> getList();
 263         public Collection<Object> getCollection();
 264         public Queue<Object> getQueue();
 265         public Deque<Object> getDequeue();
 266     }
 267 
 268     @Test
 269     public static void testReturnsListAdapter() throws ScriptException {
 270         final ScriptEngine e = createEngine();
 271         e.put("TestListAdapterClass", TestListAdapter.class);
 272         final TestListAdapter tla = (TestListAdapter)e.eval(
 273                 "new TestListAdapterClass.static({\n" +
 274                 "  getList: function() { return [ 'List' ] },\n" +
 275                 "  getCollection: function() { return [ 'Collection' ] },\n" +
 276                 "  getQueue: function() { return [ 'Queue' ] },\n" +
 277                 "  getDequeue: function() { return [ 'Dequeue' ] } })\n");
 278         Assert.assertEquals(tla.getList().get(0), "List");
 279         Assert.assertEquals(tla.getCollection().iterator().next(), "Collection");
 280         Assert.assertEquals(tla.getQueue().peek(), "Queue");
 281         Assert.assertEquals(tla.getDequeue().peek(), "Dequeue");
 282     }
 283 
 284     @Test
 285     public static void testMirrorAdapter() throws ScriptException {
 286         final NashornScriptEngine e = (NashornScriptEngine) createEngine();
 287         e.setBindings(e.createBindings(), ScriptContext.GLOBAL_SCOPE); // Null by default
 288 
 289         // Referencing functions from across scopes causes them to be wrapped in ScriptObjectMirrors
 290         e.eval("function convertObjectFromEngineScope(){ return new java.util.concurrent.Callable(o).call(); }", e.getBindings(ScriptContext.ENGINE_SCOPE));
 291         e.eval("function convertObjectFromGlobalScope(){ return new java.util.concurrent.Callable(o).call(); }", e.getBindings(ScriptContext.GLOBAL_SCOPE));
 292         e.eval("function convertFuncFromEngineScope(){ return new java.util.concurrent.Callable(g).call(); }", e.getBindings(ScriptContext.ENGINE_SCOPE));
 293         e.eval("function convertFuncFromGlobalScope(){ return new java.util.concurrent.Callable(g).call(); }", e.getBindings(ScriptContext.GLOBAL_SCOPE));
 294         e.eval("function convertParamFromEngineScope(){ return Java.type('jdk.nashorn.internal.runtime.linker.test.JavaAdapterTest').m(f);}", e.getBindings(ScriptContext.ENGINE_SCOPE));
 295         e.eval("function convertParamFromGlobalScope(){ return Java.type('jdk.nashorn.internal.runtime.linker.test.JavaAdapterTest').m(f);}", e.getBindings(ScriptContext.GLOBAL_SCOPE));
 296 
 297         e.eval("var o = { call: function () { return 'ok from o'; } }", e.getBindings(ScriptContext.ENGINE_SCOPE));
 298         e.eval("function g() { return 'ok from g'; }", e.getBindings(ScriptContext.ENGINE_SCOPE));
 299         e.eval("function f(a) { return a.toUpperCase(); }", e.getBindings(ScriptContext.ENGINE_SCOPE));
 300 
 301         try {
 302             Assert.assertEquals(e.invokeFunction("convertObjectFromEngineScope"), "ok from o");
 303             Assert.assertEquals(e.invokeFunction("convertObjectFromGlobalScope"), "ok from o");
 304             Assert.assertEquals(e.invokeFunction("convertFuncFromEngineScope"), "ok from g");
 305             Assert.assertEquals(e.invokeFunction("convertFuncFromGlobalScope"), "ok from g");
 306             Assert.assertEquals(e.invokeFunction("convertParamFromEngineScope"), "OK");
 307             Assert.assertEquals(e.invokeFunction("convertParamFromGlobalScope"), "OK");
 308         } catch (final NoSuchMethodException x) {
 309             throw new RuntimeException(x);
 310         }
 311     }
 312 
 313     public static String m(final Function<String, String> f){
 314         return f.apply("ok");
 315     }
 316 }