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