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 java.nio.ByteBuffer;
  29 import java.util.HashMap;
  30 import java.util.List;
  31 import java.util.Map;
  32 import javax.script.ScriptEngine;
  33 import javax.script.ScriptEngineManager;
  34 import javax.script.ScriptException;
  35 import static org.testng.Assert.assertEquals;
  36 import static org.testng.Assert.assertFalse;
  37 import static org.testng.Assert.assertTrue;
  38 import static org.testng.Assert.fail;
  39 import org.testng.annotations.Test;
  40 
  41 /**
  42  * Tests to check jdk.nashorn.api.scripting.ScriptObjectMirror API.
  43  */
  44 public class ScriptObjectMirrorTest {
  45 
  46     @SuppressWarnings("unchecked")
  47     @Test
  48     public void reflectionTest() throws ScriptException {
  49         final ScriptEngineManager m = new ScriptEngineManager();
  50         final ScriptEngine e = m.getEngineByName("nashorn");
  51 
  52         e.eval("var obj = { x: 344, y: 'nashorn' }");
  53 
  54         int count = 0;
  55         Map<Object, Object> map = (Map<Object, Object>) e.get("obj");
  56         assertFalse(map.isEmpty());
  57         assertTrue(map.keySet().contains("x"));
  58         assertTrue(map.containsKey("x"));
  59         assertTrue(map.values().contains("nashorn"));
  60         assertTrue(map.containsValue("nashorn"));
  61         for (final Map.Entry<?, ?> ex : map.entrySet()) {
  62             final Object key = ex.getKey();
  63             if (key.equals("x")) {
  64                 assertTrue(344 == ((Number) ex.getValue()).doubleValue());
  65                 count++;
  66             } else if (key.equals("y")) {
  67                 assertEquals(ex.getValue(), "nashorn");
  68                 count++;
  69             }
  70         }
  71         assertEquals(2, count);
  72         assertEquals(2, map.size());
  73 
  74         // add property
  75         map.put("z", "hello");
  76         assertEquals(e.eval("obj.z"), "hello");
  77         assertEquals(map.get("z"), "hello");
  78         assertTrue(map.keySet().contains("z"));
  79         assertTrue(map.containsKey("z"));
  80         assertTrue(map.values().contains("hello"));
  81         assertTrue(map.containsValue("hello"));
  82         assertEquals(map.size(), 3);
  83 
  84         final Map<Object, Object> newMap = new HashMap<>();
  85         newMap.put("foo", 23.0);
  86         newMap.put("bar", true);
  87         map.putAll(newMap);
  88 
  89         assertEquals(e.eval("obj.foo"), 23.0);
  90         assertEquals(e.eval("obj.bar"), true);
  91 
  92         // remove using map method
  93         map.remove("foo");
  94         assertEquals(e.eval("typeof obj.foo"), "undefined");
  95 
  96         count = 0;
  97         e.eval("var arr = [ true, 'hello' ]");
  98         map = (Map<Object, Object>) e.get("arr");
  99         assertFalse(map.isEmpty());
 100         assertTrue(map.containsKey("length"));
 101         assertTrue(map.containsValue("hello"));
 102         for (final Map.Entry<?, ?> ex : map.entrySet()) {
 103             final Object key = ex.getKey();
 104             if (key.equals("0")) {
 105                 assertEquals(ex.getValue(), Boolean.TRUE);
 106                 count++;
 107             } else if (key.equals("1")) {
 108                 assertEquals(ex.getValue(), "hello");
 109                 count++;
 110             }
 111         }
 112         assertEquals(count, 2);
 113         assertEquals(map.size(), 2);
 114 
 115         // add element
 116         map.put("2", "world");
 117         assertEquals(map.get("2"), "world");
 118         assertEquals(map.size(), 3);
 119 
 120         // remove all
 121         map.clear();
 122         assertTrue(map.isEmpty());
 123         assertEquals(e.eval("typeof arr[0]"), "undefined");
 124         assertEquals(e.eval("typeof arr[1]"), "undefined");
 125         assertEquals(e.eval("typeof arr[2]"), "undefined");
 126     }
 127 
 128     @Test
 129     public void jsobjectTest() {
 130         final ScriptEngineManager m = new ScriptEngineManager();
 131         final ScriptEngine e = m.getEngineByName("nashorn");
 132         try {
 133             e.eval("var obj = { '1': 'world', func: function() { return this.bar; }, bar: 'hello' }");
 134             ScriptObjectMirror obj = (ScriptObjectMirror) e.get("obj");
 135 
 136             // try basic get on existing properties
 137             if (!obj.getMember("bar").equals("hello")) {
 138                 fail("obj.bar != 'hello'");
 139             }
 140 
 141             if (!obj.getSlot(1).equals("world")) {
 142                 fail("obj[1] != 'world'");
 143             }
 144 
 145             if (!obj.callMember("func", new Object[0]).equals("hello")) {
 146                 fail("obj.func() != 'hello'");
 147             }
 148 
 149             // try setting properties
 150             obj.setMember("bar", "new-bar");
 151             obj.setSlot(1, "new-element-1");
 152             if (!obj.getMember("bar").equals("new-bar")) {
 153                 fail("obj.bar != 'new-bar'");
 154             }
 155 
 156             if (!obj.getSlot(1).equals("new-element-1")) {
 157                 fail("obj[1] != 'new-element-1'");
 158             }
 159 
 160             // try adding properties
 161             obj.setMember("prop", "prop-value");
 162             obj.setSlot(12, "element-12");
 163             if (!obj.getMember("prop").equals("prop-value")) {
 164                 fail("obj.prop != 'prop-value'");
 165             }
 166 
 167             if (!obj.getSlot(12).equals("element-12")) {
 168                 fail("obj[12] != 'element-12'");
 169             }
 170 
 171             // delete properties
 172             obj.removeMember("prop");
 173             if ("prop-value".equals(obj.getMember("prop"))) {
 174                 fail("obj.prop is not deleted!");
 175             }
 176 
 177             // Simple eval tests
 178             assertEquals(obj.eval("typeof Object"), "function");
 179             assertEquals(obj.eval("'nashorn'.substring(3)"), "horn");
 180         } catch (final Exception exp) {
 181             exp.printStackTrace();
 182             fail(exp.getMessage());
 183         }
 184     }
 185 
 186     @Test
 187     public void scriptObjectMirrorToStringTest() {
 188         final ScriptEngineManager m = new ScriptEngineManager();
 189         final ScriptEngine e = m.getEngineByName("nashorn");
 190         try {
 191             Object obj = e.eval("new TypeError('wrong type')");
 192             assertEquals(obj.toString(), "TypeError: wrong type", "toString returns wrong value");
 193         } catch (final Throwable t) {
 194             t.printStackTrace();
 195             fail(t.getMessage());
 196         }
 197 
 198         try {
 199             Object obj = e.eval("function func() { print('hello'); }");
 200             assertEquals(obj.toString(), "function func() { print('hello'); }", "toString returns wrong value");
 201         } catch (final Throwable t) {
 202             t.printStackTrace();
 203             fail(t.getMessage());
 204         }
 205     }
 206 
 207     @Test
 208     public void mirrorNewObjectGlobalFunctionTest() throws ScriptException {
 209         final ScriptEngineManager m = new ScriptEngineManager();
 210         final ScriptEngine e = m.getEngineByName("nashorn");
 211         final ScriptEngine e2 = m.getEngineByName("nashorn");
 212 
 213         e.eval("function func() {}");
 214         e2.put("foo", e.get("func"));
 215         final ScriptObjectMirror e2global = (ScriptObjectMirror)e2.eval("this");
 216         final Object newObj = ((ScriptObjectMirror)e2global.getMember("foo")).newObject();
 217         assertTrue(newObj instanceof ScriptObjectMirror);
 218     }
 219 
 220     @Test
 221     public void mirrorNewObjectInstanceFunctionTest() throws ScriptException {
 222         final ScriptEngineManager m = new ScriptEngineManager();
 223         final ScriptEngine e = m.getEngineByName("nashorn");
 224         final ScriptEngine e2 = m.getEngineByName("nashorn");
 225 
 226         e.eval("function func() {}");
 227         e2.put("func", e.get("func"));
 228         final ScriptObjectMirror e2obj = (ScriptObjectMirror)e2.eval("({ foo: func })");
 229         final Object newObj = ((ScriptObjectMirror)e2obj.getMember("foo")).newObject();
 230         assertTrue(newObj instanceof ScriptObjectMirror);
 231     }
 232 
 233     @Test
 234     public void indexPropertiesExternalBufferTest() throws ScriptException {
 235         final ScriptEngineManager m = new ScriptEngineManager();
 236         final ScriptEngine e = m.getEngineByName("nashorn");
 237         final ScriptObjectMirror obj = (ScriptObjectMirror)e.eval("var obj = {}; obj");
 238         final ByteBuffer buf = ByteBuffer.allocate(5);
 239         int i;
 240         for (i = 0; i < 5; i++) {
 241             buf.put(i, (byte)(i+10));
 242         }
 243         obj.setIndexedPropertiesToExternalArrayData(buf);
 244 
 245         for (i = 0; i < 5; i++) {
 246             assertEquals((byte)(i+10), ((Number)e.eval("obj[" + i + "]")).byteValue());
 247         }
 248 
 249         e.eval("for (i = 0; i < 5; i++) obj[i] = 0");
 250         for (i = 0; i < 5; i++) {
 251             assertEquals((byte)0, ((Number)e.eval("obj[" + i + "]")).byteValue());
 252             assertEquals((byte)0, buf.get(i));
 253         }
 254     }
 255 
 256     @Test
 257     public void conversionTest() throws ScriptException {
 258         final ScriptEngineManager m = new ScriptEngineManager();
 259         final ScriptEngine e = m.getEngineByName("nashorn");
 260         final ScriptObjectMirror arr = (ScriptObjectMirror)e.eval("[33, 45, 23]");
 261         final int[] intArr = arr.to(int[].class);
 262         assertEquals(intArr[0], 33);
 263         assertEquals(intArr[1], 45);
 264         assertEquals(intArr[2], 23);
 265 
 266         final List<?> list = arr.to(List.class);
 267         assertEquals(list.get(0), 33);
 268         assertEquals(list.get(1), 45);
 269         assertEquals(list.get(2), 23);
 270 
 271         ScriptObjectMirror obj = (ScriptObjectMirror)e.eval(
 272             "({ valueOf: function() { return 42 } })");
 273         assertEquals(Double.valueOf(42.0), obj.to(Double.class));
 274 
 275         obj = (ScriptObjectMirror)e.eval(
 276             "({ toString: function() { return 'foo' } })");
 277         assertEquals("foo", obj.to(String.class));
 278     }
 279 }