ScopeTest.java revision 1295:53e839cab67e
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 */ 25package jdk.nashorn.api.scripting.test; 26 27import static org.testng.Assert.assertEquals; 28import static org.testng.Assert.assertNotNull; 29import static org.testng.Assert.assertTrue; 30import static org.testng.Assert.fail; 31import javax.script.Bindings; 32import javax.script.ScriptContext; 33import javax.script.ScriptEngine; 34import javax.script.ScriptEngineFactory; 35import javax.script.ScriptEngineManager; 36import javax.script.ScriptException; 37import javax.script.SimpleBindings; 38import javax.script.SimpleScriptContext; 39import jdk.nashorn.api.scripting.NashornScriptEngineFactory; 40import jdk.nashorn.api.scripting.ScriptObjectMirror; 41import jdk.nashorn.api.scripting.URLReader; 42import org.testng.Assert; 43import org.testng.annotations.Test; 44 45/** 46 * Tests for jsr223 Bindings "scope" (engine, global scopes) 47 */ 48@SuppressWarnings("javadoc") 49public class ScopeTest { 50 51 @Test 52 public void createBindingsTest() { 53 final ScriptEngineManager m = new ScriptEngineManager(); 54 final ScriptEngine e = m.getEngineByName("nashorn"); 55 final Bindings b = e.createBindings(); 56 b.put("foo", 42.0); 57 Object res = null; 58 try { 59 res = e.eval("foo == 42.0", b); 60 } catch (final ScriptException | NullPointerException se) { 61 se.printStackTrace(); 62 fail(se.getMessage()); 63 } 64 65 assertEquals(res, Boolean.TRUE); 66 } 67 68 @Test 69 public void engineScopeTest() { 70 final ScriptEngineManager m = new ScriptEngineManager(); 71 final ScriptEngine e = m.getEngineByName("nashorn"); 72 final Bindings engineScope = e.getBindings(ScriptContext.ENGINE_SCOPE); 73 74 // check few ECMA standard built-in global properties 75 assertNotNull(engineScope.get("Object")); 76 assertNotNull(engineScope.get("TypeError")); 77 assertNotNull(engineScope.get("eval")); 78 79 // can access via ScriptEngine.get as well 80 assertNotNull(e.get("Object")); 81 assertNotNull(e.get("TypeError")); 82 assertNotNull(e.get("eval")); 83 84 // Access by either way should return same object 85 assertEquals(engineScope.get("Array"), e.get("Array")); 86 assertEquals(engineScope.get("EvalError"), e.get("EvalError")); 87 assertEquals(engineScope.get("undefined"), e.get("undefined")); 88 89 // try exposing a new variable from scope 90 engineScope.put("myVar", "foo"); 91 try { 92 assertEquals(e.eval("myVar"), "foo"); 93 } catch (final ScriptException se) { 94 se.printStackTrace(); 95 fail(se.getMessage()); 96 } 97 98 // update "myVar" in script an check the value from scope 99 try { 100 e.eval("myVar = 'nashorn';"); 101 } catch (final ScriptException se) { 102 se.printStackTrace(); 103 fail(se.getMessage()); 104 } 105 106 // now check modified value from scope and engine 107 assertEquals(engineScope.get("myVar"), "nashorn"); 108 assertEquals(e.get("myVar"), "nashorn"); 109 } 110 111 @Test 112 public void multiGlobalTest() { 113 final ScriptEngineManager m = new ScriptEngineManager(); 114 final ScriptEngine e = m.getEngineByName("nashorn"); 115 final Bindings b = e.createBindings(); 116 final ScriptContext newCtxt = new SimpleScriptContext(); 117 newCtxt.setBindings(b, ScriptContext.ENGINE_SCOPE); 118 119 try { 120 final Object obj1 = e.eval("Object"); 121 final Object obj2 = e.eval("Object", newCtxt); 122 Assert.assertNotEquals(obj1, obj2); 123 Assert.assertNotNull(obj1); 124 Assert.assertNotNull(obj2); 125 Assert.assertEquals(obj1.toString(), obj2.toString()); 126 127 e.eval("x = 'hello'"); 128 e.eval("x = 'world'", newCtxt); 129 Object x1 = e.getContext().getAttribute("x"); 130 Object x2 = newCtxt.getAttribute("x"); 131 Assert.assertNotEquals(x1, x2); 132 Assert.assertEquals(x1, "hello"); 133 Assert.assertEquals(x2, "world"); 134 135 x1 = e.eval("x"); 136 x2 = e.eval("x", newCtxt); 137 Assert.assertNotEquals(x1, x2); 138 Assert.assertEquals(x1, "hello"); 139 Assert.assertEquals(x2, "world"); 140 141 final ScriptContext origCtxt = e.getContext(); 142 e.setContext(newCtxt); 143 e.eval("y = new Object()"); 144 e.eval("y = new Object()", origCtxt); 145 146 final Object y1 = origCtxt.getAttribute("y"); 147 final Object y2 = newCtxt.getAttribute("y"); 148 Assert.assertNotEquals(y1, y2); 149 final Object yeval1 = e.eval("y"); 150 final Object yeval2 = e.eval("y", origCtxt); 151 Assert.assertNotEquals(yeval1, yeval2); 152 Assert.assertEquals("[object Object]", y1.toString()); 153 Assert.assertEquals("[object Object]", y2.toString()); 154 } catch (final ScriptException se) { 155 se.printStackTrace(); 156 fail(se.getMessage()); 157 } 158 } 159 160 @Test 161 public void userEngineScopeBindingsTest() throws ScriptException { 162 final ScriptEngineManager m = new ScriptEngineManager(); 163 final ScriptEngine e = m.getEngineByName("nashorn"); 164 e.eval("function func() {}"); 165 166 final ScriptContext newContext = new SimpleScriptContext(); 167 newContext.setBindings(new SimpleBindings(), ScriptContext.ENGINE_SCOPE); 168 // we are using a new bindings - so it should have 'func' defined 169 final Object value = e.eval("typeof func", newContext); 170 assertTrue(value.equals("undefined")); 171 } 172 173 @Test 174 public void userEngineScopeBindingsNoLeakTest() throws ScriptException { 175 final ScriptEngineManager m = new ScriptEngineManager(); 176 final ScriptEngine e = m.getEngineByName("nashorn"); 177 final ScriptContext newContext = new SimpleScriptContext(); 178 newContext.setBindings(new SimpleBindings(), ScriptContext.ENGINE_SCOPE); 179 e.eval("function foo() {}", newContext); 180 181 // in the default context's ENGINE_SCOPE, 'foo' shouldn't exist 182 assertTrue(e.eval("typeof foo").equals("undefined")); 183 } 184 185 @Test 186 public void userEngineScopeBindingsRetentionTest() throws ScriptException { 187 final ScriptEngineManager m = new ScriptEngineManager(); 188 final ScriptEngine e = m.getEngineByName("nashorn"); 189 final ScriptContext newContext = new SimpleScriptContext(); 190 newContext.setBindings(new SimpleBindings(), ScriptContext.ENGINE_SCOPE); 191 e.eval("function foo() {}", newContext); 192 193 // definition retained with user's ENGINE_SCOPE Binding 194 assertTrue(e.eval("typeof foo", newContext).equals("function")); 195 196 final Bindings oldBindings = newContext.getBindings(ScriptContext.ENGINE_SCOPE); 197 // but not in another ENGINE_SCOPE binding 198 newContext.setBindings(new SimpleBindings(), ScriptContext.ENGINE_SCOPE); 199 assertTrue(e.eval("typeof foo", newContext).equals("undefined")); 200 201 // restore ENGINE_SCOPE and check again 202 newContext.setBindings(oldBindings, ScriptContext.ENGINE_SCOPE); 203 assertTrue(e.eval("typeof foo", newContext).equals("function")); 204 } 205 206 @Test 207 // check that engine.js definitions are visible in all new global instances 208 public void checkBuiltinsInNewBindingsTest() throws ScriptException { 209 final ScriptEngineManager m = new ScriptEngineManager(); 210 final ScriptEngine e = m.getEngineByName("nashorn"); 211 212 // check default global instance has engine.js definitions 213 final Bindings g = (Bindings) e.eval("this"); 214 Object value = g.get("__noSuchProperty__"); 215 assertTrue(value instanceof ScriptObjectMirror && ((ScriptObjectMirror)value).isFunction()); 216 value = g.get("print"); 217 assertTrue(value instanceof ScriptObjectMirror && ((ScriptObjectMirror)value).isFunction()); 218 219 // check new global instance created has engine.js definitions 220 final Bindings b = e.createBindings(); 221 value = b.get("__noSuchProperty__"); 222 assertTrue(value instanceof ScriptObjectMirror && ((ScriptObjectMirror)value).isFunction()); 223 value = b.get("print"); 224 assertTrue(value instanceof ScriptObjectMirror && ((ScriptObjectMirror)value).isFunction()); 225 226 // put a mapping into GLOBAL_SCOPE 227 final Bindings globalScope = e.getContext().getBindings(ScriptContext.GLOBAL_SCOPE); 228 globalScope.put("x", "hello"); 229 230 // GLOBAL_SCOPE mapping should be visible from default ScriptContext eval 231 assertTrue(e.eval("x").equals("hello")); 232 233 final ScriptContext ctx = new SimpleScriptContext(); 234 ctx.setBindings(globalScope, ScriptContext.GLOBAL_SCOPE); 235 ctx.setBindings(b, ScriptContext.ENGINE_SCOPE); 236 237 // GLOBAL_SCOPE mapping should be visible from non-default ScriptContext eval 238 assertTrue(e.eval("x", ctx).equals("hello")); 239 240 // try some arbitray Bindings for ENGINE_SCOPE 241 final Bindings sb = new SimpleBindings(); 242 ctx.setBindings(sb, ScriptContext.ENGINE_SCOPE); 243 244 // GLOBAL_SCOPE mapping should be visible from non-default ScriptContext eval 245 assertTrue(e.eval("x", ctx).equals("hello")); 246 247 // engine.js builtins are still defined even with arbitrary Bindings 248 assertTrue(e.eval("typeof print", ctx).equals("function")); 249 assertTrue(e.eval("typeof __noSuchProperty__", ctx).equals("function")); 250 251 // ENGINE_SCOPE definition should 'hide' GLOBAL_SCOPE definition 252 sb.put("x", "newX"); 253 assertTrue(e.eval("x", ctx).equals("newX")); 254 } 255 256 /** 257 * Test multi-threaded access to defined global variables for shared script classes with multiple globals. 258 */ 259 @Test 260 public static void multiThreadedVarTest() throws ScriptException, InterruptedException { 261 final ScriptEngineManager m = new ScriptEngineManager(); 262 final ScriptEngine e = m.getEngineByName("nashorn"); 263 final Bindings b = e.createBindings(); 264 final ScriptContext origContext = e.getContext(); 265 final ScriptContext newCtxt = new SimpleScriptContext(); 266 newCtxt.setBindings(b, ScriptContext.ENGINE_SCOPE); 267 final String sharedScript = "foo"; 268 269 assertEquals(e.eval("var foo = 'original context';", origContext), null); 270 assertEquals(e.eval("var foo = 'new context';", newCtxt), null); 271 272 final Thread t1 = new Thread(new ScriptRunner(e, origContext, sharedScript, "original context", 1000)); 273 final Thread t2 = new Thread(new ScriptRunner(e, newCtxt, sharedScript, "new context", 1000)); 274 t1.start(); 275 t2.start(); 276 t1.join(); 277 t2.join(); 278 279 assertEquals(e.eval("var foo = 'newer context';", newCtxt), null); 280 final Thread t3 = new Thread(new ScriptRunner(e, origContext, sharedScript, "original context", 1000)); 281 final Thread t4 = new Thread(new ScriptRunner(e, newCtxt, sharedScript, "newer context", 1000)); 282 283 t3.start(); 284 t4.start(); 285 t3.join(); 286 t4.join(); 287 288 assertEquals(e.eval(sharedScript), "original context"); 289 assertEquals(e.eval(sharedScript, newCtxt), "newer context"); 290 } 291 292 /** 293 * Test multi-threaded access to undefined global variables for shared script classes with multiple globals. 294 */ 295 @Test 296 public static void multiThreadedGlobalTest() throws ScriptException, InterruptedException { 297 final ScriptEngineManager m = new ScriptEngineManager(); 298 final ScriptEngine e = m.getEngineByName("nashorn"); 299 final Bindings b = e.createBindings(); 300 final ScriptContext origContext = e.getContext(); 301 final ScriptContext newCtxt = new SimpleScriptContext(); 302 newCtxt.setBindings(b, ScriptContext.ENGINE_SCOPE); 303 304 assertEquals(e.eval("foo = 'original context';", origContext), "original context"); 305 assertEquals(e.eval("foo = 'new context';", newCtxt), "new context"); 306 final String sharedScript = "foo"; 307 308 final Thread t1 = new Thread(new ScriptRunner(e, origContext, sharedScript, "original context", 1000)); 309 final Thread t2 = new Thread(new ScriptRunner(e, newCtxt, sharedScript, "new context", 1000)); 310 t1.start(); 311 t2.start(); 312 t1.join(); 313 t2.join(); 314 315 final Object obj3 = e.eval("delete foo; foo = 'newer context';", newCtxt); 316 assertEquals(obj3, "newer context"); 317 final Thread t3 = new Thread(new ScriptRunner(e, origContext, sharedScript, "original context", 1000)); 318 final Thread t4 = new Thread(new ScriptRunner(e, newCtxt, sharedScript, "newer context", 1000)); 319 320 t3.start(); 321 t4.start(); 322 t3.join(); 323 t4.join(); 324 325 Assert.assertEquals(e.eval(sharedScript), "original context"); 326 Assert.assertEquals(e.eval(sharedScript, newCtxt), "newer context"); 327 } 328 329 /** 330 * Test multi-threaded access using the postfix ++ operator for shared script classes with multiple globals. 331 */ 332 @Test 333 public static void multiThreadedIncTest() throws ScriptException, InterruptedException { 334 final ScriptEngineManager m = new ScriptEngineManager(); 335 final ScriptEngine e = m.getEngineByName("nashorn"); 336 final Bindings b = e.createBindings(); 337 final ScriptContext origContext = e.getContext(); 338 final ScriptContext newCtxt = new SimpleScriptContext(); 339 newCtxt.setBindings(b, ScriptContext.ENGINE_SCOPE); 340 341 assertEquals(e.eval("var x = 0;", origContext), null); 342 assertEquals(e.eval("var x = 2;", newCtxt), null); 343 final String sharedScript = "x++;"; 344 345 final Thread t1 = new Thread(new Runnable() { 346 @Override 347 public void run() { 348 try { 349 for (int i = 0; i < 1000; i++) { 350 assertEquals(e.eval(sharedScript, origContext), (double)i); 351 } 352 } catch (final ScriptException se) { 353 fail(se.toString()); 354 } 355 } 356 }); 357 final Thread t2 = new Thread(new Runnable() { 358 @Override 359 public void run() { 360 try { 361 for (int i = 2; i < 1000; i++) { 362 assertEquals(e.eval(sharedScript, newCtxt), (double)i); 363 } 364 } catch (final ScriptException se) { 365 fail(se.toString()); 366 } 367 } 368 }); 369 t1.start(); 370 t2.start(); 371 t1.join(); 372 t2.join(); 373 } 374 375 /** 376 * Test multi-threaded access to primitive prototype properties for shared script classes with multiple globals. 377 */ 378 @Test 379 public static void multiThreadedPrimitiveTest() throws ScriptException, InterruptedException { 380 final ScriptEngineManager m = new ScriptEngineManager(); 381 final ScriptEngine e = m.getEngineByName("nashorn"); 382 final Bindings b = e.createBindings(); 383 final ScriptContext origContext = e.getContext(); 384 final ScriptContext newCtxt = new SimpleScriptContext(); 385 newCtxt.setBindings(b, ScriptContext.ENGINE_SCOPE); 386 387 final Object obj1 = e.eval("String.prototype.foo = 'original context';", origContext); 388 final Object obj2 = e.eval("String.prototype.foo = 'new context';", newCtxt); 389 assertEquals(obj1, "original context"); 390 assertEquals(obj2, "new context"); 391 final String sharedScript = "''.foo"; 392 393 final Thread t1 = new Thread(new ScriptRunner(e, origContext, sharedScript, "original context", 1000)); 394 final Thread t2 = new Thread(new ScriptRunner(e, newCtxt, sharedScript, "new context", 1000)); 395 t1.start(); 396 t2.start(); 397 t1.join(); 398 t2.join(); 399 400 final Object obj3 = e.eval("delete String.prototype.foo; Object.prototype.foo = 'newer context';", newCtxt); 401 assertEquals(obj3, "newer context"); 402 final Thread t3 = new Thread(new ScriptRunner(e, origContext, sharedScript, "original context", 1000)); 403 final Thread t4 = new Thread(new ScriptRunner(e, newCtxt, sharedScript, "newer context", 1000)); 404 405 t3.start(); 406 t4.start(); 407 t3.join(); 408 t4.join(); 409 410 Assert.assertEquals(e.eval(sharedScript), "original context"); 411 Assert.assertEquals(e.eval(sharedScript, newCtxt), "newer context"); 412 } 413 414 415 /** 416 * Test multi-threaded access to prototype user accessor properties for shared script classes with multiple globals. 417 */ 418 @Test 419 public static void multiThreadedAccessorTest() throws ScriptException, InterruptedException { 420 final ScriptEngineManager m = new ScriptEngineManager(); 421 final ScriptEngine e = m.getEngineByName("nashorn"); 422 final Bindings b = e.createBindings(); 423 final ScriptContext origContext = e.getContext(); 424 final ScriptContext newCtxt = new SimpleScriptContext(); 425 newCtxt.setBindings(b, ScriptContext.ENGINE_SCOPE); 426 427 e.eval("Object.defineProperty(Object.prototype, 'foo', { get: function() 'original context' })", origContext); 428 e.eval("Object.defineProperty(Object.prototype, 'foo', { get: function() 'new context', configurable: true })", newCtxt); 429 final String sharedScript = "({}).foo"; 430 431 final Thread t1 = new Thread(new ScriptRunner(e, origContext, sharedScript, "original context", 1000)); 432 final Thread t2 = new Thread(new ScriptRunner(e, newCtxt, sharedScript, "new context", 1000)); 433 t1.start(); 434 t2.start(); 435 t1.join(); 436 t2.join(); 437 438 final Object obj3 = e.eval("delete Object.prototype.foo; Object.prototype.foo = 'newer context';", newCtxt); 439 assertEquals(obj3, "newer context"); 440 final Thread t3 = new Thread(new ScriptRunner(e, origContext, sharedScript, "original context", 1000)); 441 final Thread t4 = new Thread(new ScriptRunner(e, newCtxt, sharedScript, "newer context", 1000)); 442 443 t3.start(); 444 t4.start(); 445 t3.join(); 446 t4.join(); 447 } 448 449 /** 450 * Test multi-threaded access to primitive prototype user accessor properties for shared script classes with multiple globals. 451 */ 452 @Test 453 public static void multiThreadedPrimitiveAccessorTest() throws ScriptException, InterruptedException { 454 final ScriptEngineManager m = new ScriptEngineManager(); 455 final ScriptEngine e = m.getEngineByName("nashorn"); 456 final Bindings b = e.createBindings(); 457 final ScriptContext origContext = e.getContext(); 458 final ScriptContext newCtxt = new SimpleScriptContext(); 459 newCtxt.setBindings(b, ScriptContext.ENGINE_SCOPE); 460 461 e.eval("Object.defineProperty(String.prototype, 'foo', { get: function() 'original context' })", origContext); 462 e.eval("Object.defineProperty(String.prototype, 'foo', { get: function() 'new context' })", newCtxt); 463 final String sharedScript = "''.foo"; 464 465 final Thread t1 = new Thread(new ScriptRunner(e, origContext, sharedScript, "original context", 1000)); 466 final Thread t2 = new Thread(new ScriptRunner(e, newCtxt, sharedScript, "new context", 1000)); 467 t1.start(); 468 t2.start(); 469 t1.join(); 470 t2.join(); 471 472 final Object obj3 = e.eval("delete String.prototype.foo; Object.prototype.foo = 'newer context';", newCtxt); 473 assertEquals(obj3, "newer context"); 474 final Thread t3 = new Thread(new ScriptRunner(e, origContext, sharedScript, "original context", 1000)); 475 final Thread t4 = new Thread(new ScriptRunner(e, newCtxt, sharedScript, "newer context", 1000)); 476 477 t3.start(); 478 t4.start(); 479 t3.join(); 480 t4.join(); 481 } 482 483 /** 484 * Test multi-threaded scope function invocation for shared script classes with multiple globals. 485 */ 486 @Test 487 public static void multiThreadedFunctionTest() throws ScriptException, InterruptedException { 488 final ScriptEngineManager m = new ScriptEngineManager(); 489 final ScriptEngine e = m.getEngineByName("nashorn"); 490 final Bindings b = e.createBindings(); 491 final ScriptContext origContext = e.getContext(); 492 final ScriptContext newCtxt = new SimpleScriptContext(); 493 newCtxt.setBindings(b, ScriptContext.ENGINE_SCOPE); 494 495 e.eval(new URLReader(ScopeTest.class.getResource("resources/func.js")), origContext); 496 assertEquals(origContext.getAttribute("scopeVar"), 1); 497 assertEquals(e.eval("scopeTest()"), 1); 498 499 e.eval(new URLReader(ScopeTest.class.getResource("resources/func.js")), newCtxt); 500 assertEquals(newCtxt.getAttribute("scopeVar"), 1); 501 assertEquals(e.eval("scopeTest();", newCtxt), 1); 502 503 assertEquals(e.eval("scopeVar = 3;", newCtxt), 3); 504 assertEquals(newCtxt.getAttribute("scopeVar"), 3); 505 506 507 final Thread t1 = new Thread(new ScriptRunner(e, origContext, "scopeTest()", 1, 1000)); 508 final Thread t2 = new Thread(new ScriptRunner(e, newCtxt, "scopeTest()", 3, 1000)); 509 510 t1.start(); 511 t2.start(); 512 t1.join(); 513 t2.join(); 514 515 } 516 517 /** 518 * Test multi-threaded access to global getters and setters for shared script classes with multiple globals. 519 */ 520 @Test 521 public static void getterSetterTest() throws ScriptException, InterruptedException { 522 final ScriptEngineManager m = new ScriptEngineManager(); 523 final ScriptEngine e = m.getEngineByName("nashorn"); 524 final Bindings b = e.createBindings(); 525 final ScriptContext origContext = e.getContext(); 526 final ScriptContext newCtxt = new SimpleScriptContext(); 527 newCtxt.setBindings(b, ScriptContext.ENGINE_SCOPE); 528 final String sharedScript = "accessor1"; 529 530 e.eval(new URLReader(ScopeTest.class.getResource("resources/gettersetter.js")), origContext); 531 assertEquals(e.eval("accessor1 = 1;"), 1); 532 assertEquals(e.eval(sharedScript), 1); 533 534 e.eval(new URLReader(ScopeTest.class.getResource("resources/gettersetter.js")), newCtxt); 535 assertEquals(e.eval("accessor1 = 2;", newCtxt), 2); 536 assertEquals(e.eval(sharedScript, newCtxt), 2); 537 538 539 final Thread t1 = new Thread(new ScriptRunner(e, origContext, sharedScript, 1, 1000)); 540 final Thread t2 = new Thread(new ScriptRunner(e, newCtxt, sharedScript, 2, 1000)); 541 542 t1.start(); 543 t2.start(); 544 t1.join(); 545 t2.join(); 546 547 assertEquals(e.eval(sharedScript), 1); 548 assertEquals(e.eval(sharedScript, newCtxt), 2); 549 assertEquals(e.eval("v"), 1); 550 assertEquals(e.eval("v", newCtxt), 2); 551 } 552 553 /** 554 * Test multi-threaded access to global getters and setters for shared script classes with multiple globals. 555 */ 556 @Test 557 public static void getterSetter2Test() throws ScriptException, InterruptedException { 558 final ScriptEngineManager m = new ScriptEngineManager(); 559 final ScriptEngine e = m.getEngineByName("nashorn"); 560 final Bindings b = e.createBindings(); 561 final ScriptContext origContext = e.getContext(); 562 final ScriptContext newCtxt = new SimpleScriptContext(); 563 newCtxt.setBindings(b, ScriptContext.ENGINE_SCOPE); 564 final String sharedScript = "accessor2"; 565 566 e.eval(new URLReader(ScopeTest.class.getResource("resources/gettersetter.js")), origContext); 567 assertEquals(e.eval("accessor2 = 1;"), 1); 568 assertEquals(e.eval(sharedScript), 1); 569 570 e.eval(new URLReader(ScopeTest.class.getResource("resources/gettersetter.js")), newCtxt); 571 assertEquals(e.eval("accessor2 = 2;", newCtxt), 2); 572 assertEquals(e.eval(sharedScript, newCtxt), 2); 573 574 575 final Thread t1 = new Thread(new ScriptRunner(e, origContext, sharedScript, 1, 1000)); 576 final Thread t2 = new Thread(new ScriptRunner(e, newCtxt, sharedScript, 2, 1000)); 577 578 t1.start(); 579 t2.start(); 580 t1.join(); 581 t2.join(); 582 583 assertEquals(e.eval(sharedScript), 1); 584 assertEquals(e.eval(sharedScript, newCtxt), 2); 585 assertEquals(e.eval("x"), 1); 586 assertEquals(e.eval("x", newCtxt), 2); 587 } 588 589 // @bug 8058422: Users should be able to overwrite "context" and "engine" variables 590 @Test 591 public static void contextOverwriteTest() throws ScriptException { 592 final ScriptEngineManager m = new ScriptEngineManager(); 593 final ScriptEngine e = m.getEngineByName("nashorn"); 594 final Bindings b = new SimpleBindings(); 595 b.put("context", "hello"); 596 b.put("foo", 32); 597 final ScriptContext newCtxt = new SimpleScriptContext(); 598 newCtxt.setBindings(b, ScriptContext.ENGINE_SCOPE); 599 e.setContext(newCtxt); 600 assertEquals(e.eval("context"), "hello"); 601 assertEquals(((Number)e.eval("foo")).intValue(), 32); 602 } 603 604 // @bug 8058422: Users should be able to overwrite "context" and "engine" variables 605 @Test 606 public static void contextOverwriteInScriptTest() throws ScriptException { 607 final ScriptEngineManager m = new ScriptEngineManager(); 608 final ScriptEngine e = m.getEngineByName("nashorn"); 609 e.put("foo", 32); 610 611 assertEquals(((Number)e.eval("foo")).intValue(), 32); 612 assertEquals(e.eval("context = 'bar'"), "bar"); 613 assertEquals(((Number)e.eval("foo")).intValue(), 32); 614 } 615 616 // @bug 8058422: Users should be able to overwrite "context" and "engine" variables 617 @Test 618 public static void engineOverwriteTest() throws ScriptException { 619 final ScriptEngineManager m = new ScriptEngineManager(); 620 final ScriptEngine e = m.getEngineByName("nashorn"); 621 final Bindings b = new SimpleBindings(); 622 b.put("engine", "hello"); 623 b.put("foo", 32); 624 final ScriptContext newCtxt = new SimpleScriptContext(); 625 newCtxt.setBindings(b, ScriptContext.ENGINE_SCOPE); 626 e.setContext(newCtxt); 627 assertEquals(e.eval("engine"), "hello"); 628 assertEquals(((Number)e.eval("foo")).intValue(), 32); 629 } 630 631 // @bug 8058422: Users should be able to overwrite "context" and "engine" variables 632 @Test 633 public static void engineOverwriteInScriptTest() throws ScriptException { 634 final ScriptEngineManager m = new ScriptEngineManager(); 635 final ScriptEngine e = m.getEngineByName("nashorn"); 636 e.put("foo", 32); 637 638 assertEquals(((Number)e.eval("foo")).intValue(), 32); 639 assertEquals(e.eval("engine = 'bar'"), "bar"); 640 assertEquals(((Number)e.eval("foo")).intValue(), 32); 641 } 642 643 // @bug 8044750: megamorphic getter for scope objects does not call __noSuchProperty__ hook 644 @Test 645 public static void testMegamorphicGetInGlobal() throws Exception { 646 final ScriptEngineManager m = new ScriptEngineManager(); 647 final ScriptEngine engine = m.getEngineByName("nashorn"); 648 final String script = "foo"; 649 // "foo" is megamorphic because of different global scopes. 650 // Make sure ScriptContext variable search works even after 651 // it becomes megamorphic. 652 for (int index = 0; index < 25; index++) { 653 final Bindings bindings = new SimpleBindings(); 654 bindings.put("foo", index); 655 final Number value = (Number)engine.eval(script, bindings); 656 assertEquals(index, value.intValue()); 657 } 658 } 659 660 /** 661 * Test "slow" scopes involving {@code with} and {@code eval} statements for shared script classes with multiple globals. 662 * @throws ScriptException 663 * @throws InterruptedException 664 */ 665 @Test 666 public static void testSlowScope() throws ScriptException, InterruptedException { 667 final ScriptEngineManager m = new ScriptEngineManager(); 668 final ScriptEngine e = m.getEngineByName("nashorn"); 669 670 for (int i = 0; i < 100; i++) { 671 final Bindings b = e.createBindings(); 672 final ScriptContext ctxt = new SimpleScriptContext(); 673 ctxt.setBindings(b, ScriptContext.ENGINE_SCOPE); 674 675 e.eval(new URLReader(ScopeTest.class.getResource("resources/witheval.js")), ctxt); 676 assertEquals(e.eval("a", ctxt), 1); 677 assertEquals(b.get("a"), 1); 678 assertEquals(e.eval("b", ctxt), 3); 679 assertEquals(b.get("b"), 3); 680 assertEquals(e.eval("c", ctxt), 10); 681 assertEquals(b.get("c"), 10); 682 } 683 } 684 685 private static class ScriptRunner implements Runnable { 686 687 final ScriptEngine engine; 688 final ScriptContext context; 689 final String source; 690 final Object expected; 691 final int iterations; 692 693 ScriptRunner(final ScriptEngine engine, final ScriptContext context, final String source, final Object expected, final int iterations) { 694 this.engine = engine; 695 this.context = context; 696 this.source = source; 697 this.expected = expected; 698 this.iterations = iterations; 699 } 700 701 @Override 702 public void run() { 703 try { 704 for (int i = 0; i < iterations; i++) { 705 assertEquals(engine.eval(source, context), expected); 706 } 707 } catch (final ScriptException se) { 708 throw new RuntimeException(se); 709 } 710 } 711 } 712 713 // @bug 8071678: NashornScriptEngine returns javax.script.ScriptContext instance 714 // with get/setAttribute methods insonsistent for GLOBAL_SCOPE 715 @Test 716 public void testGlobalScopeSearch() throws Exception { 717 final ScriptEngineManager m = new ScriptEngineManager(); 718 final ScriptEngine e = m.getEngineByName("nashorn"); 719 final ScriptContext c = e.getContext(); 720 c.setAttribute("name1234", "value", ScriptContext.GLOBAL_SCOPE); 721 assertEquals(c.getAttribute("name1234"), "value"); 722 assertEquals(c.getAttributesScope("name1234"), 723 ScriptContext.GLOBAL_SCOPE); 724 } 725 726 // @bug 8071594: NashornScriptEngine returns javax.script.ScriptContext instance 727 // which doesn't completely conform to the spec regarding exceptions throwing 728 @Test 729 public void testScriptContext_NPE_IAE() throws Exception { 730 final ScriptEngineManager m = new ScriptEngineManager(); 731 final ScriptEngine e = m.getEngineByName("nashorn"); 732 final ScriptContext c = e.getContext(); 733 try { 734 c.getAttribute(""); 735 throw new AssertionError("should have thrown IAE"); 736 } catch (IllegalArgumentException iae1) {} 737 738 try { 739 c.getAttribute(null); 740 throw new AssertionError("should have thrown NPE"); 741 } catch (NullPointerException npe1) {} 742 743 try { 744 c.getAttribute("", ScriptContext.ENGINE_SCOPE); 745 throw new AssertionError("should have thrown IAE"); 746 } catch (IllegalArgumentException iae2) {} 747 748 try { 749 c.getAttribute(null, ScriptContext.ENGINE_SCOPE); 750 throw new AssertionError("should have thrown NPE"); 751 } catch (NullPointerException npe2) {} 752 753 try { 754 c.removeAttribute("", ScriptContext.ENGINE_SCOPE); 755 throw new AssertionError("should have thrown IAE"); 756 } catch (IllegalArgumentException iae3) {} 757 758 try { 759 c.removeAttribute(null, ScriptContext.ENGINE_SCOPE); 760 throw new AssertionError("should have thrown NPE"); 761 } catch (NullPointerException npe3) {} 762 763 try { 764 c.setAttribute("", "value", ScriptContext.ENGINE_SCOPE); 765 throw new AssertionError("should have thrown IAE"); 766 } catch (IllegalArgumentException iae4) {} 767 768 try { 769 c.setAttribute(null, "value", ScriptContext.ENGINE_SCOPE); 770 throw new AssertionError("should have thrown NPE"); 771 } catch (NullPointerException npe4) {} 772 773 try { 774 c.getAttributesScope(""); 775 throw new AssertionError("should have thrown IAE"); 776 } catch (IllegalArgumentException iae5) {} 777 778 try { 779 c.getAttributesScope(null); 780 throw new AssertionError("should have thrown NPE"); 781 } catch (NullPointerException npe5) {} 782 } 783 784 public static class RecursiveEval { 785 private final ScriptEngineFactory factory = new NashornScriptEngineFactory(); 786 private final ScriptEngine engine = factory.getScriptEngine(); 787 private final Bindings engineBindings = engine.getBindings(ScriptContext.ENGINE_SCOPE); 788 789 public void program() throws ScriptException { 790 ScriptContext sc = new SimpleScriptContext(); 791 Bindings global = new SimpleBindings(); 792 sc.setBindings(global, ScriptContext.GLOBAL_SCOPE); 793 sc.setBindings(engineBindings, ScriptContext.ENGINE_SCOPE); 794 global.put("text", "programText"); 795 String value = engine.eval("text", sc).toString(); 796 Assert.assertEquals(value, "programText"); 797 engine.put("program", this); 798 engine.eval("program.method()"); 799 // eval again from here! 800 value = engine.eval("text", sc).toString(); 801 Assert.assertEquals(value, "programText"); 802 } 803 804 public void method() throws ScriptException { 805 // a context with a new global bindings, same engine bindings 806 final ScriptContext sc = new SimpleScriptContext(); 807 final Bindings global = new SimpleBindings(); 808 sc.setBindings(global, ScriptContext.GLOBAL_SCOPE); 809 sc.setBindings(engineBindings, ScriptContext.ENGINE_SCOPE); 810 global.put("text", "methodText"); 811 String value = engine.eval("text", sc).toString(); 812 Assert.assertEquals(value, "methodText"); 813 } 814 } 815 816 // @bug 8081609: engine.eval call from a java method which 817 // was called from a previous engine.eval results in wrong 818 // ScriptContext being used. 819 @Test 820 public void recursiveEvalCallScriptContextTest() throws ScriptException { 821 new RecursiveEval().program(); 822 } 823} 824