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