Wed, 11 Sep 2013 20:49:28 +0530
8024615: Refactor ScriptObjectMirror and JSObject to support external JSObject implementations
Reviewed-by: jlaskey, hannesw
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 */
26 package jdk.nashorn.api.scripting;
28 import java.nio.IntBuffer;
29 import java.util.Collection;
30 import java.util.HashMap;
31 import java.util.Set;
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.assertTrue;
37 import static org.testng.Assert.assertFalse;
38 import static org.testng.Assert.fail;
39 import org.testng.annotations.Test;
41 /**
42 * Tests for pluggable external impls. of jdk.nashorn.api.scripting.JSObject.
43 *
44 * JDK-8024615: Refactor ScriptObjectMirror and JSObject to support external
45 * JSObject implementations.
46 */
47 public class PluggableJSObjectTest {
48 public static class MapWrapperObject extends JSObject {
49 private final HashMap<String, Object> map = new HashMap<>();
51 public HashMap<String, Object> getMap() {
52 return map;
53 }
55 @Override
56 public Object getMember(String name) {
57 return map.get(name);
58 }
60 @Override
61 public void setMember(String name, Object value) {
62 map.put(name, value);
63 }
65 @Override
66 public boolean hasMember(String name) {
67 return map.containsKey(name);
68 }
70 @Override
71 public void removeMember(String name) {
72 map.remove(name);
73 }
75 @Override
76 public Set<String> keySet() {
77 return map.keySet();
78 }
80 @Override
81 public Collection<Object> values() {
82 return map.values();
83 }
84 }
86 @Test
87 // Named property access on a JSObject
88 public void namedAccessTest() {
89 final ScriptEngineManager m = new ScriptEngineManager();
90 final ScriptEngine e = m.getEngineByName("nashorn");
91 try {
92 final MapWrapperObject obj = new MapWrapperObject();
93 e.put("obj", obj);
94 obj.getMap().put("foo", "bar");
96 // property-like access on MapWrapperObject objects
97 assertEquals(e.eval("obj.foo"), "bar");
98 e.eval("obj.foo = 'hello'");
99 assertEquals(e.eval("'foo' in obj"), Boolean.TRUE);
100 assertEquals(e.eval("obj.foo"), "hello");
101 assertEquals(obj.getMap().get("foo"), "hello");
102 e.eval("delete obj.foo");
103 assertFalse(obj.getMap().containsKey("foo"));
104 assertEquals(e.eval("'foo' in obj"), Boolean.FALSE);
105 } catch (final Exception exp) {
106 exp.printStackTrace();
107 fail(exp.getMessage());
108 }
109 }
111 public static class BufferObject extends JSObject {
112 private final IntBuffer buf;
114 public BufferObject(int size) {
115 buf = IntBuffer.allocate(size);
116 }
118 public IntBuffer getBuffer() {
119 return buf;
120 }
122 @Override
123 public Object getMember(String name) {
124 return name.equals("length")? buf.capacity() : null;
125 }
127 @Override
128 public boolean hasSlot(int i) {
129 return i > -1 && i < buf.capacity();
130 }
132 @Override
133 public Object getSlot(int i) {
134 return buf.get(i);
135 }
137 @Override
138 public void setSlot(int i, Object value) {
139 buf.put(i, ((Number)value).intValue());
140 }
142 @Override
143 public boolean isArray() {
144 return true;
145 }
146 }
148 @Test
149 // array-like indexed access for a JSObject
150 public void indexedAccessTest() {
151 final ScriptEngineManager m = new ScriptEngineManager();
152 final ScriptEngine e = m.getEngineByName("nashorn");
153 try {
154 final BufferObject buf = new BufferObject(2);
155 e.put("buf", buf);
157 // array-like access on BufferObject objects
158 assertEquals(e.eval("buf.length"), buf.getBuffer().capacity());
159 e.eval("buf[0] = 23");
160 assertEquals(buf.getBuffer().get(0), 23);
161 assertEquals(e.eval("buf[0]"), 23);
162 assertEquals(e.eval("buf[1]"), 0);
163 buf.getBuffer().put(1, 42);
164 assertEquals(e.eval("buf[1]"), 42);
165 assertEquals(e.eval("Array.isArray(buf)"), Boolean.TRUE);
166 } catch (final Exception exp) {
167 exp.printStackTrace();
168 fail(exp.getMessage());
169 }
170 }
172 public static class Adder extends JSObject {
173 @Override
174 public Object call(Object thiz, Object... args) {
175 double res = 0.0;
176 for (Object arg : args) {
177 res += ((Number)arg).doubleValue();
178 }
179 return res;
180 }
182 @Override
183 public boolean isFunction() {
184 return true;
185 }
186 }
188 @Test
189 // a callable JSObject
190 public void callableJSObjectTest() {
191 final ScriptEngineManager m = new ScriptEngineManager();
192 final ScriptEngine e = m.getEngineByName("nashorn");
193 try {
194 e.put("sum", new Adder());
195 // check callability of Adder objects
196 assertEquals(e.eval("typeof sum"), "function");
197 assertEquals(((Number)e.eval("sum(1, 2, 3, 4, 5)")).intValue(), 15);
198 } catch (final Exception exp) {
199 exp.printStackTrace();
200 fail(exp.getMessage());
201 }
202 }
204 public static class Factory extends JSObject {
205 @Override
206 public Object newObject(Object... args) {
207 return new HashMap<Object, Object>();
208 }
210 @Override
211 public boolean isFunction() {
212 return true;
213 }
214 }
216 @Test
217 // a factory JSObject
218 public void factoryJSObjectTest() {
219 final ScriptEngineManager m = new ScriptEngineManager();
220 final ScriptEngine e = m.getEngineByName("nashorn");
221 try {
222 e.put("Factory", new Factory());
224 // check new on Factory
225 assertEquals(e.eval("typeof Factory"), "function");
226 assertEquals(e.eval("typeof new Factory()"), "object");
227 assertEquals(e.eval("(new Factory()) instanceof java.util.Map"), Boolean.TRUE);
228 } catch (final Exception exp) {
229 exp.printStackTrace();
230 fail(exp.getMessage());
231 }
232 }
234 @Test
235 // iteration tests
236 public void iteratingJSObjectTest() {
237 final ScriptEngineManager m = new ScriptEngineManager();
238 final ScriptEngine e = m.getEngineByName("nashorn");
239 try {
240 final MapWrapperObject obj = new MapWrapperObject();
241 obj.setMember("foo", "hello");
242 obj.setMember("bar", "world");
243 e.put("obj", obj);
245 // check for..in
246 Object val = e.eval("var str = ''; for (i in obj) str += i; str");
247 assertEquals(val.toString(), "foobar");
249 // check for..each..in
250 val = e.eval("var str = ''; for each (i in obj) str += i; str");
251 assertEquals(val.toString(), "helloworld");
252 } catch (final Exception exp) {
253 exp.printStackTrace();
254 fail(exp.getMessage());
255 }
256 }
257 }