1 // Copyright 2007-2008 the V8 project authors. All rights reserved. 2 // Redistribution and use in source and binary forms, with or without 3 // modification, are permitted provided that the following conditions are 4 // met: 5 // 6 // * Redistributions of source code must retain the above copyright 7 // notice, this list of conditions and the following disclaimer. 8 // * Redistributions in binary form must reproduce the above 9 // copyright notice, this list of conditions and the following 10 // disclaimer in the documentation and/or other materials provided 11 // with the distribution. 12 // * Neither the name of Google Inc. nor the names of its 13 // contributors may be used to endorse or promote products derived 14 // from this software without specific prior written permission. 15 // 16 // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 17 // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 18 // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 19 // A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 20 // OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 21 // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 22 // LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 23 // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 24 // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 25 // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 26 // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 27 28 #include <stdlib.h> 29 30 #include "src/v8.h" 31 32 #include "src/heap.h" 33 #include "test/cctest/cctest.h" 34 35 using namespace v8; 36 37 38 enum Expectations { 39 EXPECT_RESULT, 40 EXPECT_EXCEPTION, 41 EXPECT_ERROR 42 }; 43 44 45 // A DeclarationContext holds a reference to a v8::Context and keeps 46 // track of various declaration related counters to make it easier to 47 // track if global declarations in the presence of interceptors behave 48 // the right way. 49 class DeclarationContext { 50 public: 51 DeclarationContext(); 52 53 virtual ~DeclarationContext() { 54 if (is_initialized_) { 55 Isolate* isolate = CcTest::isolate(); 56 HandleScope scope(isolate); 57 Local<Context> context = Local<Context>::New(isolate, context_); 58 context->Exit(); 59 context_.Reset(); 60 } 61 } 62 63 void Check(const char* source, 64 int get, int set, int has, 65 Expectations expectations, 66 v8::Handle<Value> value = Local<Value>()); 67 68 int get_count() const { return get_count_; } 69 int set_count() const { return set_count_; } 70 int query_count() const { return query_count_; } 71 72 protected: 73 virtual v8::Handle<Value> Get(Local<String> key); 74 virtual v8::Handle<Value> Set(Local<String> key, Local<Value> value); 75 virtual v8::Handle<Integer> Query(Local<String> key); 76 77 void InitializeIfNeeded(); 78 79 // Perform optional initialization steps on the context after it has 80 // been created. Defaults to none but may be overwritten. 81 virtual void PostInitializeContext(Handle<Context> context) {} 82 83 // Get the holder for the interceptor. Default to the instance template 84 // but may be overwritten. 85 virtual Local<ObjectTemplate> GetHolder(Local<FunctionTemplate> function) { 86 return function->InstanceTemplate(); 87 } 88 89 // The handlers are called as static functions that forward 90 // to the instance specific virtual methods. 91 static void HandleGet(Local<String> key, 92 const v8::PropertyCallbackInfo<v8::Value>& info); 93 static void HandleSet(Local<String> key, 94 Local<Value> value, 95 const v8::PropertyCallbackInfo<v8::Value>& info); 96 static void HandleQuery(Local<String> key, 97 const v8::PropertyCallbackInfo<v8::Integer>& info); 98 99 v8::Isolate* isolate() const { return CcTest::isolate(); } 100 101 private: 102 bool is_initialized_; 103 Persistent<Context> context_; 104 105 int get_count_; 106 int set_count_; 107 int query_count_; 108 109 static DeclarationContext* GetInstance(Local<Value> data); 110 }; 111 112 113 DeclarationContext::DeclarationContext() 114 : is_initialized_(false), get_count_(0), set_count_(0), query_count_(0) { 115 // Do nothing. 116 } 117 118 119 void DeclarationContext::InitializeIfNeeded() { 120 if (is_initialized_) return; 121 Isolate* isolate = CcTest::isolate(); 122 HandleScope scope(isolate); 123 Local<FunctionTemplate> function = FunctionTemplate::New(isolate); 124 Local<Value> data = External::New(CcTest::isolate(), this); 125 GetHolder(function)->SetNamedPropertyHandler(&HandleGet, 126 &HandleSet, 127 &HandleQuery, 128 0, 0, 129 data); 130 Local<Context> context = Context::New(isolate, 131 0, 132 function->InstanceTemplate(), 133 Local<Value>()); 134 context_.Reset(isolate, context); 135 context->Enter(); 136 is_initialized_ = true; 137 PostInitializeContext(context); 138 } 139 140 141 void DeclarationContext::Check(const char* source, 142 int get, int set, int query, 143 Expectations expectations, 144 v8::Handle<Value> value) { 145 InitializeIfNeeded(); 146 // A retry after a GC may pollute the counts, so perform gc now 147 // to avoid that. 148 CcTest::heap()->CollectGarbage(v8::internal::NEW_SPACE); 149 HandleScope scope(CcTest::isolate()); 150 TryCatch catcher; 151 catcher.SetVerbose(true); 152 Local<Script> script = 153 Script::Compile(String::NewFromUtf8(CcTest::isolate(), source)); 154 if (expectations == EXPECT_ERROR) { 155 CHECK(script.IsEmpty()); 156 return; 157 } 158 CHECK(!script.IsEmpty()); 159 Local<Value> result = script->Run(); 160 CHECK_EQ(get, get_count()); 161 CHECK_EQ(set, set_count()); 162 CHECK_EQ(query, query_count()); 163 if (expectations == EXPECT_RESULT) { 164 CHECK(!catcher.HasCaught()); 165 if (!value.IsEmpty()) { 166 CHECK_EQ(value, result); 167 } 168 } else { 169 CHECK(expectations == EXPECT_EXCEPTION); 170 CHECK(catcher.HasCaught()); 171 if (!value.IsEmpty()) { 172 CHECK_EQ(value, catcher.Exception()); 173 } 174 } 175 // Clean slate for the next test. 176 CcTest::heap()->CollectAllAvailableGarbage(); 177 } 178 179 180 void DeclarationContext::HandleGet( 181 Local<String> key, 182 const v8::PropertyCallbackInfo<v8::Value>& info) { 183 DeclarationContext* context = GetInstance(info.Data()); 184 context->get_count_++; 185 info.GetReturnValue().Set(context->Get(key)); 186 } 187 188 189 void DeclarationContext::HandleSet( 190 Local<String> key, 191 Local<Value> value, 192 const v8::PropertyCallbackInfo<v8::Value>& info) { 193 DeclarationContext* context = GetInstance(info.Data()); 194 context->set_count_++; 195 info.GetReturnValue().Set(context->Set(key, value)); 196 } 197 198 199 void DeclarationContext::HandleQuery( 200 Local<String> key, 201 const v8::PropertyCallbackInfo<v8::Integer>& info) { 202 DeclarationContext* context = GetInstance(info.Data()); 203 context->query_count_++; 204 info.GetReturnValue().Set(context->Query(key)); 205 } 206 207 208 DeclarationContext* DeclarationContext::GetInstance(Local<Value> data) { 209 void* value = Local<External>::Cast(data)->Value(); 210 return static_cast<DeclarationContext*>(value); 211 } 212 213 214 v8::Handle<Value> DeclarationContext::Get(Local<String> key) { 215 return v8::Handle<Value>(); 216 } 217 218 219 v8::Handle<Value> DeclarationContext::Set(Local<String> key, 220 Local<Value> value) { 221 return v8::Handle<Value>(); 222 } 223 224 225 v8::Handle<Integer> DeclarationContext::Query(Local<String> key) { 226 return v8::Handle<Integer>(); 227 } 228 229 230 // Test global declaration of a property the interceptor doesn't know 231 // about and doesn't handle. 232 TEST(Unknown) { 233 HandleScope scope(CcTest::isolate()); 234 v8::V8::Initialize(); 235 236 { DeclarationContext context; 237 context.Check("var x; x", 238 1, // access 239 1, // declaration 240 2, // declaration + initialization 241 EXPECT_RESULT, Undefined(CcTest::isolate())); 242 } 243 244 { DeclarationContext context; 245 context.Check("var x = 0; x", 246 1, // access 247 2, // declaration + initialization 248 2, // declaration + initialization 249 EXPECT_RESULT, Number::New(CcTest::isolate(), 0)); 250 } 251 252 { DeclarationContext context; 253 context.Check("function x() { }; x", 254 1, // access 255 0, 256 0, 257 EXPECT_RESULT); 258 } 259 260 { DeclarationContext context; 261 context.Check("const x; x", 262 1, // access 263 2, // declaration + initialization 264 1, // declaration 265 EXPECT_RESULT, Undefined(CcTest::isolate())); 266 } 267 268 { DeclarationContext context; 269 // SB 0 - BUG 1213579 270 context.Check("const x = 0; x", 271 1, // access 272 2, // declaration + initialization 273 1, // declaration 274 EXPECT_RESULT, Undefined(CcTest::isolate())); 275 } 276 } 277 278 279 280 class PresentPropertyContext: public DeclarationContext { 281 protected: 282 virtual v8::Handle<Integer> Query(Local<String> key) { 283 return Integer::New(isolate(), v8::None); 284 } 285 }; 286 287 288 289 TEST(Present) { 290 HandleScope scope(CcTest::isolate()); 291 292 { PresentPropertyContext context; 293 context.Check("var x; x", 294 1, // access 295 0, 296 2, // declaration + initialization 297 EXPECT_EXCEPTION); // x is not defined! 298 } 299 300 { PresentPropertyContext context; 301 context.Check("var x = 0; x", 302 1, // access 303 1, // initialization 304 2, // declaration + initialization 305 EXPECT_RESULT, Number::New(CcTest::isolate(), 0)); 306 } 307 308 { PresentPropertyContext context; 309 context.Check("function x() { }; x", 310 1, // access 311 0, 312 0, 313 EXPECT_RESULT); 314 } 315 316 { PresentPropertyContext context; 317 context.Check("const x; x", 318 1, // access 319 1, // initialization 320 1, // (re-)declaration 321 EXPECT_RESULT, Undefined(CcTest::isolate())); 322 } 323 324 { PresentPropertyContext context; 325 context.Check("const x = 0; x", 326 1, // access 327 1, // initialization 328 1, // (re-)declaration 329 EXPECT_RESULT, Number::New(CcTest::isolate(), 0)); 330 } 331 } 332 333 334 335 class AbsentPropertyContext: public DeclarationContext { 336 protected: 337 virtual v8::Handle<Integer> Query(Local<String> key) { 338 return v8::Handle<Integer>(); 339 } 340 }; 341 342 343 TEST(Absent) { 344 v8::Isolate* isolate = CcTest::isolate(); 345 v8::V8::Initialize(); 346 HandleScope scope(isolate); 347 348 { AbsentPropertyContext context; 349 context.Check("var x; x", 350 1, // access 351 1, // declaration 352 2, // declaration + initialization 353 EXPECT_RESULT, Undefined(isolate)); 354 } 355 356 { AbsentPropertyContext context; 357 context.Check("var x = 0; x", 358 1, // access 359 2, // declaration + initialization 360 2, // declaration + initialization 361 EXPECT_RESULT, Number::New(isolate, 0)); 362 } 363 364 { AbsentPropertyContext context; 365 context.Check("function x() { }; x", 366 1, // access 367 0, 368 0, 369 EXPECT_RESULT); 370 } 371 372 { AbsentPropertyContext context; 373 context.Check("const x; x", 374 1, // access 375 2, // declaration + initialization 376 1, // declaration 377 EXPECT_RESULT, Undefined(isolate)); 378 } 379 380 { AbsentPropertyContext context; 381 context.Check("const x = 0; x", 382 1, // access 383 2, // declaration + initialization 384 1, // declaration 385 EXPECT_RESULT, Undefined(isolate)); // SB 0 - BUG 1213579 386 } 387 388 { AbsentPropertyContext context; 389 context.Check("if (false) { var x = 0 }; x", 390 1, // access 391 1, // declaration 392 1, // declaration + initialization 393 EXPECT_RESULT, Undefined(isolate)); 394 } 395 } 396 397 398 399 class AppearingPropertyContext: public DeclarationContext { 400 public: 401 enum State { 402 DECLARE, 403 INITIALIZE_IF_ASSIGN, 404 UNKNOWN 405 }; 406 407 AppearingPropertyContext() : state_(DECLARE) { } 408 409 protected: 410 virtual v8::Handle<Integer> Query(Local<String> key) { 411 switch (state_) { 412 case DECLARE: 413 // Force declaration by returning that the 414 // property is absent. 415 state_ = INITIALIZE_IF_ASSIGN; 416 return Handle<Integer>(); 417 case INITIALIZE_IF_ASSIGN: 418 // Return that the property is present so we only get the 419 // setter called when initializing with a value. 420 state_ = UNKNOWN; 421 return Integer::New(isolate(), v8::None); 422 default: 423 CHECK(state_ == UNKNOWN); 424 break; 425 } 426 // Do the lookup in the object. 427 return v8::Handle<Integer>(); 428 } 429 430 private: 431 State state_; 432 }; 433 434 435 TEST(Appearing) { 436 v8::V8::Initialize(); 437 HandleScope scope(CcTest::isolate()); 438 439 { AppearingPropertyContext context; 440 context.Check("var x; x", 441 1, // access 442 1, // declaration 443 2, // declaration + initialization 444 EXPECT_RESULT, Undefined(CcTest::isolate())); 445 } 446 447 { AppearingPropertyContext context; 448 context.Check("var x = 0; x", 449 1, // access 450 2, // declaration + initialization 451 2, // declaration + initialization 452 EXPECT_RESULT, Number::New(CcTest::isolate(), 0)); 453 } 454 455 { AppearingPropertyContext context; 456 context.Check("function x() { }; x", 457 1, // access 458 0, 459 0, 460 EXPECT_RESULT); 461 } 462 463 { AppearingPropertyContext context; 464 context.Check("const x; x", 465 1, // access 466 2, // declaration + initialization 467 1, // declaration 468 EXPECT_RESULT, Undefined(CcTest::isolate())); 469 } 470 471 { AppearingPropertyContext context; 472 context.Check("const x = 0; x", 473 1, // access 474 2, // declaration + initialization 475 1, // declaration 476 EXPECT_RESULT, Undefined(CcTest::isolate())); 477 // Result is undefined because declaration succeeded but 478 // initialization to 0 failed (due to context behavior). 479 } 480 } 481 482 483 484 class ReappearingPropertyContext: public DeclarationContext { 485 public: 486 enum State { 487 DECLARE, 488 DONT_DECLARE, 489 INITIALIZE, 490 UNKNOWN 491 }; 492 493 ReappearingPropertyContext() : state_(DECLARE) { } 494 495 protected: 496 virtual v8::Handle<Integer> Query(Local<String> key) { 497 switch (state_) { 498 case DECLARE: 499 // Force the first declaration by returning that 500 // the property is absent. 501 state_ = DONT_DECLARE; 502 return Handle<Integer>(); 503 case DONT_DECLARE: 504 // Ignore the second declaration by returning 505 // that the property is already there. 506 state_ = INITIALIZE; 507 return Integer::New(isolate(), v8::None); 508 case INITIALIZE: 509 // Force an initialization by returning that 510 // the property is absent. This will make sure 511 // that the setter is called and it will not 512 // lead to redeclaration conflicts (yet). 513 state_ = UNKNOWN; 514 return Handle<Integer>(); 515 default: 516 CHECK(state_ == UNKNOWN); 517 break; 518 } 519 // Do the lookup in the object. 520 return Handle<Integer>(); 521 } 522 523 private: 524 State state_; 525 }; 526 527 528 TEST(Reappearing) { 529 v8::V8::Initialize(); 530 HandleScope scope(CcTest::isolate()); 531 532 { ReappearingPropertyContext context; 533 context.Check("const x; var x = 0", 534 0, 535 3, // const declaration+initialization, var initialization 536 3, // 2 x declaration + var initialization 537 EXPECT_RESULT, Undefined(CcTest::isolate())); 538 } 539 } 540 541 542 543 class ExistsInPrototypeContext: public DeclarationContext { 544 public: 545 ExistsInPrototypeContext() { InitializeIfNeeded(); } 546 protected: 547 virtual v8::Handle<Integer> Query(Local<String> key) { 548 // Let it seem that the property exists in the prototype object. 549 return Integer::New(isolate(), v8::None); 550 } 551 552 // Use the prototype as the holder for the interceptors. 553 virtual Local<ObjectTemplate> GetHolder(Local<FunctionTemplate> function) { 554 return function->PrototypeTemplate(); 555 } 556 }; 557 558 559 TEST(ExistsInPrototype) { 560 HandleScope scope(CcTest::isolate()); 561 562 // Sanity check to make sure that the holder of the interceptor 563 // really is the prototype object. 564 { ExistsInPrototypeContext context; 565 context.Check("this.x = 87; this.x", 566 0, 567 0, 568 0, 569 EXPECT_RESULT, Number::New(CcTest::isolate(), 87)); 570 } 571 572 { ExistsInPrototypeContext context; 573 context.Check("var x; x", 574 0, 575 0, 576 0, 577 EXPECT_RESULT, Undefined(CcTest::isolate())); 578 } 579 580 { ExistsInPrototypeContext context; 581 context.Check("var x = 0; x", 582 0, 583 0, 584 0, 585 EXPECT_RESULT, Number::New(CcTest::isolate(), 0)); 586 } 587 588 { ExistsInPrototypeContext context; 589 context.Check("const x; x", 590 0, 591 0, 592 0, 593 EXPECT_RESULT, Undefined(CcTest::isolate())); 594 } 595 596 { ExistsInPrototypeContext context; 597 context.Check("const x = 0; x", 598 0, 599 0, 600 0, 601 EXPECT_RESULT, Number::New(CcTest::isolate(), 0)); 602 } 603 } 604 605 606 607 class AbsentInPrototypeContext: public DeclarationContext { 608 protected: 609 virtual v8::Handle<Integer> Query(Local<String> key) { 610 // Let it seem that the property is absent in the prototype object. 611 return Handle<Integer>(); 612 } 613 614 // Use the prototype as the holder for the interceptors. 615 virtual Local<ObjectTemplate> GetHolder(Local<FunctionTemplate> function) { 616 return function->PrototypeTemplate(); 617 } 618 }; 619 620 621 TEST(AbsentInPrototype) { 622 v8::V8::Initialize(); 623 HandleScope scope(CcTest::isolate()); 624 625 { AbsentInPrototypeContext context; 626 context.Check("if (false) { var x = 0; }; x", 627 0, 628 0, 629 0, 630 EXPECT_RESULT, Undefined(CcTest::isolate())); 631 } 632 } 633 634 635 636 class ExistsInHiddenPrototypeContext: public DeclarationContext { 637 public: 638 ExistsInHiddenPrototypeContext() { 639 hidden_proto_ = FunctionTemplate::New(CcTest::isolate()); 640 hidden_proto_->SetHiddenPrototype(true); 641 } 642 643 protected: 644 virtual v8::Handle<Integer> Query(Local<String> key) { 645 // Let it seem that the property exists in the hidden prototype object. 646 return Integer::New(isolate(), v8::None); 647 } 648 649 // Install the hidden prototype after the global object has been created. 650 virtual void PostInitializeContext(Handle<Context> context) { 651 Local<Object> global_object = context->Global(); 652 Local<Object> hidden_proto = hidden_proto_->GetFunction()->NewInstance(); 653 Local<Object> inner_global = 654 Local<Object>::Cast(global_object->GetPrototype()); 655 inner_global->SetPrototype(hidden_proto); 656 } 657 658 // Use the hidden prototype as the holder for the interceptors. 659 virtual Local<ObjectTemplate> GetHolder(Local<FunctionTemplate> function) { 660 return hidden_proto_->InstanceTemplate(); 661 } 662 663 private: 664 Local<FunctionTemplate> hidden_proto_; 665 }; 666 667 668 TEST(ExistsInHiddenPrototype) { 669 HandleScope scope(CcTest::isolate()); 670 671 { ExistsInHiddenPrototypeContext context; 672 context.Check("var x; x", 673 1, // access 674 0, 675 2, // declaration + initialization 676 EXPECT_EXCEPTION); // x is not defined! 677 } 678 679 { ExistsInHiddenPrototypeContext context; 680 context.Check("var x = 0; x", 681 1, // access 682 1, // initialization 683 2, // declaration + initialization 684 EXPECT_RESULT, Number::New(CcTest::isolate(), 0)); 685 } 686 687 { ExistsInHiddenPrototypeContext context; 688 context.Check("function x() { }; x", 689 0, 690 0, 691 0, 692 EXPECT_RESULT); 693 } 694 695 // TODO(mstarzinger): The semantics of global const is vague. 696 { ExistsInHiddenPrototypeContext context; 697 context.Check("const x; x", 698 0, 699 0, 700 1, // (re-)declaration 701 EXPECT_RESULT, Undefined(CcTest::isolate())); 702 } 703 704 // TODO(mstarzinger): The semantics of global const is vague. 705 { ExistsInHiddenPrototypeContext context; 706 context.Check("const x = 0; x", 707 0, 708 0, 709 1, // (re-)declaration 710 EXPECT_RESULT, Number::New(CcTest::isolate(), 0)); 711 } 712 } 713 714 715 716 class SimpleContext { 717 public: 718 SimpleContext() 719 : handle_scope_(CcTest::isolate()), 720 context_(Context::New(CcTest::isolate())) { 721 context_->Enter(); 722 } 723 724 ~SimpleContext() { 725 context_->Exit(); 726 } 727 728 void Check(const char* source, 729 Expectations expectations, 730 v8::Handle<Value> value = Local<Value>()) { 731 HandleScope scope(context_->GetIsolate()); 732 TryCatch catcher; 733 catcher.SetVerbose(true); 734 Local<Script> script = 735 Script::Compile(String::NewFromUtf8(context_->GetIsolate(), source)); 736 if (expectations == EXPECT_ERROR) { 737 CHECK(script.IsEmpty()); 738 return; 739 } 740 CHECK(!script.IsEmpty()); 741 Local<Value> result = script->Run(); 742 if (expectations == EXPECT_RESULT) { 743 CHECK(!catcher.HasCaught()); 744 if (!value.IsEmpty()) { 745 CHECK_EQ(value, result); 746 } 747 } else { 748 CHECK(expectations == EXPECT_EXCEPTION); 749 CHECK(catcher.HasCaught()); 750 if (!value.IsEmpty()) { 751 CHECK_EQ(value, catcher.Exception()); 752 } 753 } 754 } 755 756 private: 757 HandleScope handle_scope_; 758 Local<Context> context_; 759 }; 760 761 762 TEST(CrossScriptReferences) { 763 v8::Isolate* isolate = CcTest::isolate(); 764 HandleScope scope(isolate); 765 766 { SimpleContext context; 767 context.Check("var x = 1; x", 768 EXPECT_RESULT, Number::New(isolate, 1)); 769 context.Check("var x = 2; x", 770 EXPECT_RESULT, Number::New(isolate, 2)); 771 context.Check("const x = 3; x", 772 EXPECT_RESULT, Number::New(isolate, 3)); 773 context.Check("const x = 4; x", 774 EXPECT_RESULT, Number::New(isolate, 4)); 775 context.Check("x = 5; x", 776 EXPECT_RESULT, Number::New(isolate, 5)); 777 context.Check("var x = 6; x", 778 EXPECT_RESULT, Number::New(isolate, 6)); 779 context.Check("this.x", 780 EXPECT_RESULT, Number::New(isolate, 6)); 781 context.Check("function x() { return 7 }; x()", 782 EXPECT_RESULT, Number::New(isolate, 7)); 783 } 784 785 { SimpleContext context; 786 context.Check("const x = 1; x", 787 EXPECT_RESULT, Number::New(isolate, 1)); 788 context.Check("var x = 2; x", // assignment ignored 789 EXPECT_RESULT, Number::New(isolate, 1)); 790 context.Check("const x = 3; x", 791 EXPECT_RESULT, Number::New(isolate, 1)); 792 context.Check("x = 4; x", // assignment ignored 793 EXPECT_RESULT, Number::New(isolate, 1)); 794 context.Check("var x = 5; x", // assignment ignored 795 EXPECT_RESULT, Number::New(isolate, 1)); 796 context.Check("this.x", 797 EXPECT_RESULT, Number::New(isolate, 1)); 798 context.Check("function x() { return 7 }; x", 799 EXPECT_EXCEPTION); 800 } 801 } 802 803 804 TEST(CrossScriptReferencesHarmony) { 805 i::FLAG_use_strict = true; 806 i::FLAG_harmony_scoping = true; 807 i::FLAG_harmony_modules = true; 808 809 v8::Isolate* isolate = CcTest::isolate(); 810 HandleScope scope(isolate); 811 812 const char* decs[] = { 813 "var x = 1; x", "x", "this.x", 814 "function x() { return 1 }; x()", "x()", "this.x()", 815 "let x = 1; x", "x", "this.x", 816 "const x = 1; x", "x", "this.x", 817 "module x { export let a = 1 }; x.a", "x.a", "this.x.a", 818 NULL 819 }; 820 821 for (int i = 0; decs[i] != NULL; i += 3) { 822 SimpleContext context; 823 context.Check(decs[i], EXPECT_RESULT, Number::New(isolate, 1)); 824 context.Check(decs[i+1], EXPECT_RESULT, Number::New(isolate, 1)); 825 // TODO(rossberg): The current ES6 draft spec does not reflect lexical 826 // bindings on the global object. However, this will probably change, in 827 // which case we reactivate the following test. 828 if (i/3 < 2) { 829 context.Check(decs[i+2], EXPECT_RESULT, Number::New(isolate, 1)); 830 } 831 } 832 } 833 834 835 TEST(CrossScriptConflicts) { 836 i::FLAG_use_strict = true; 837 i::FLAG_harmony_scoping = true; 838 i::FLAG_harmony_modules = true; 839 840 HandleScope scope(CcTest::isolate()); 841 842 const char* firsts[] = { 843 "var x = 1; x", 844 "function x() { return 1 }; x()", 845 "let x = 1; x", 846 "const x = 1; x", 847 "module x { export let a = 1 }; x.a", 848 NULL 849 }; 850 const char* seconds[] = { 851 "var x = 2; x", 852 "function x() { return 2 }; x()", 853 "let x = 2; x", 854 "const x = 2; x", 855 "module x { export let a = 2 }; x.a", 856 NULL 857 }; 858 859 for (int i = 0; firsts[i] != NULL; ++i) { 860 for (int j = 0; seconds[j] != NULL; ++j) { 861 SimpleContext context; 862 context.Check(firsts[i], EXPECT_RESULT, 863 Number::New(CcTest::isolate(), 1)); 864 // TODO(rossberg): All tests should actually be errors in Harmony, 865 // but we currently do not detect the cases where the first declaration 866 // is not lexical. 867 context.Check(seconds[j], 868 i < 2 ? EXPECT_RESULT : EXPECT_ERROR, 869 Number::New(CcTest::isolate(), 2)); 870 } 871 } 872 } 873