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 "v8.h" 31 32 #include "heap.h" 33 #include "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 = Isolate::GetCurrent(); 56 HandleScope scope(isolate); 57 Local<Context> context = Local<Context>::New(isolate, context_); 58 context->Exit(); 59 context_.Dispose(isolate); 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 private: 100 bool is_initialized_; 101 Persistent<Context> context_; 102 103 int get_count_; 104 int set_count_; 105 int query_count_; 106 107 static DeclarationContext* GetInstance(Local<Value> data); 108 }; 109 110 111 DeclarationContext::DeclarationContext() 112 : is_initialized_(false), get_count_(0), set_count_(0), query_count_(0) { 113 // Do nothing. 114 } 115 116 117 void DeclarationContext::InitializeIfNeeded() { 118 if (is_initialized_) return; 119 Isolate* isolate = Isolate::GetCurrent(); 120 HandleScope scope(isolate); 121 Local<FunctionTemplate> function = FunctionTemplate::New(); 122 Local<Value> data = External::New(this); 123 GetHolder(function)->SetNamedPropertyHandler(&HandleGet, 124 &HandleSet, 125 &HandleQuery, 126 0, 0, 127 data); 128 Local<Context> context = Context::New(isolate, 129 0, 130 function->InstanceTemplate(), 131 Local<Value>()); 132 context_.Reset(isolate, context); 133 context->Enter(); 134 is_initialized_ = true; 135 PostInitializeContext(context); 136 } 137 138 139 void DeclarationContext::Check(const char* source, 140 int get, int set, int query, 141 Expectations expectations, 142 v8::Handle<Value> value) { 143 InitializeIfNeeded(); 144 // A retry after a GC may pollute the counts, so perform gc now 145 // to avoid that. 146 HEAP->CollectGarbage(v8::internal::NEW_SPACE); 147 HandleScope scope(Isolate::GetCurrent()); 148 TryCatch catcher; 149 catcher.SetVerbose(true); 150 Local<Script> script = Script::Compile(String::New(source)); 151 if (expectations == EXPECT_ERROR) { 152 CHECK(script.IsEmpty()); 153 return; 154 } 155 CHECK(!script.IsEmpty()); 156 Local<Value> result = script->Run(); 157 CHECK_EQ(get, get_count()); 158 CHECK_EQ(set, set_count()); 159 CHECK_EQ(query, query_count()); 160 if (expectations == EXPECT_RESULT) { 161 CHECK(!catcher.HasCaught()); 162 if (!value.IsEmpty()) { 163 CHECK_EQ(value, result); 164 } 165 } else { 166 CHECK(expectations == EXPECT_EXCEPTION); 167 CHECK(catcher.HasCaught()); 168 if (!value.IsEmpty()) { 169 CHECK_EQ(value, catcher.Exception()); 170 } 171 } 172 HEAP->CollectAllAvailableGarbage(); // Clean slate for the next test. 173 } 174 175 176 void DeclarationContext::HandleGet( 177 Local<String> key, 178 const v8::PropertyCallbackInfo<v8::Value>& info) { 179 DeclarationContext* context = GetInstance(info.Data()); 180 context->get_count_++; 181 info.GetReturnValue().Set(context->Get(key)); 182 } 183 184 185 void DeclarationContext::HandleSet( 186 Local<String> key, 187 Local<Value> value, 188 const v8::PropertyCallbackInfo<v8::Value>& info) { 189 DeclarationContext* context = GetInstance(info.Data()); 190 context->set_count_++; 191 info.GetReturnValue().Set(context->Set(key, value)); 192 } 193 194 195 void DeclarationContext::HandleQuery( 196 Local<String> key, 197 const v8::PropertyCallbackInfo<v8::Integer>& info) { 198 DeclarationContext* context = GetInstance(info.Data()); 199 context->query_count_++; 200 info.GetReturnValue().Set(context->Query(key)); 201 } 202 203 204 DeclarationContext* DeclarationContext::GetInstance(Local<Value> data) { 205 void* value = Local<External>::Cast(data)->Value(); 206 return static_cast<DeclarationContext*>(value); 207 } 208 209 210 v8::Handle<Value> DeclarationContext::Get(Local<String> key) { 211 return v8::Handle<Value>(); 212 } 213 214 215 v8::Handle<Value> DeclarationContext::Set(Local<String> key, 216 Local<Value> value) { 217 return v8::Handle<Value>(); 218 } 219 220 221 v8::Handle<Integer> DeclarationContext::Query(Local<String> key) { 222 return v8::Handle<Integer>(); 223 } 224 225 226 // Test global declaration of a property the interceptor doesn't know 227 // about and doesn't handle. 228 TEST(Unknown) { 229 HandleScope scope(Isolate::GetCurrent()); 230 231 { DeclarationContext context; 232 context.Check("var x; x", 233 1, // access 234 1, // declaration 235 2, // declaration + initialization 236 EXPECT_RESULT, Undefined()); 237 } 238 239 { DeclarationContext context; 240 context.Check("var x = 0; x", 241 1, // access 242 2, // declaration + initialization 243 2, // declaration + initialization 244 EXPECT_RESULT, Number::New(0)); 245 } 246 247 { DeclarationContext context; 248 context.Check("function x() { }; x", 249 1, // access 250 0, 251 0, 252 EXPECT_RESULT); 253 } 254 255 { DeclarationContext context; 256 context.Check("const x; x", 257 1, // access 258 2, // declaration + initialization 259 1, // declaration 260 EXPECT_RESULT, Undefined()); 261 } 262 263 { DeclarationContext context; 264 context.Check("const x = 0; x", 265 1, // access 266 2, // declaration + initialization 267 1, // declaration 268 EXPECT_RESULT, Undefined()); // SB 0 - BUG 1213579 269 } 270 } 271 272 273 274 class PresentPropertyContext: public DeclarationContext { 275 protected: 276 virtual v8::Handle<Integer> Query(Local<String> key) { 277 return Integer::New(v8::None); 278 } 279 }; 280 281 282 283 TEST(Present) { 284 HandleScope scope(Isolate::GetCurrent()); 285 286 { PresentPropertyContext context; 287 context.Check("var x; x", 288 1, // access 289 0, 290 2, // declaration + initialization 291 EXPECT_EXCEPTION); // x is not defined! 292 } 293 294 { PresentPropertyContext context; 295 context.Check("var x = 0; x", 296 1, // access 297 1, // initialization 298 2, // declaration + initialization 299 EXPECT_RESULT, Number::New(0)); 300 } 301 302 { PresentPropertyContext context; 303 context.Check("function x() { }; x", 304 1, // access 305 0, 306 0, 307 EXPECT_RESULT); 308 } 309 310 { PresentPropertyContext context; 311 context.Check("const x; x", 312 1, // access 313 1, // initialization 314 1, // (re-)declaration 315 EXPECT_RESULT, Undefined()); 316 } 317 318 { PresentPropertyContext context; 319 context.Check("const x = 0; x", 320 1, // access 321 1, // initialization 322 1, // (re-)declaration 323 EXPECT_RESULT, Number::New(0)); 324 } 325 } 326 327 328 329 class AbsentPropertyContext: public DeclarationContext { 330 protected: 331 virtual v8::Handle<Integer> Query(Local<String> key) { 332 return v8::Handle<Integer>(); 333 } 334 }; 335 336 337 TEST(Absent) { 338 HandleScope scope(Isolate::GetCurrent()); 339 340 { AbsentPropertyContext context; 341 context.Check("var x; x", 342 1, // access 343 1, // declaration 344 2, // declaration + initialization 345 EXPECT_RESULT, Undefined()); 346 } 347 348 { AbsentPropertyContext context; 349 context.Check("var x = 0; x", 350 1, // access 351 2, // declaration + initialization 352 2, // declaration + initialization 353 EXPECT_RESULT, Number::New(0)); 354 } 355 356 { AbsentPropertyContext context; 357 context.Check("function x() { }; x", 358 1, // access 359 0, 360 0, 361 EXPECT_RESULT); 362 } 363 364 { AbsentPropertyContext context; 365 context.Check("const x; x", 366 1, // access 367 2, // declaration + initialization 368 1, // declaration 369 EXPECT_RESULT, Undefined()); 370 } 371 372 { AbsentPropertyContext context; 373 context.Check("const x = 0; x", 374 1, // access 375 2, // declaration + initialization 376 1, // declaration 377 EXPECT_RESULT, Undefined()); // SB 0 - BUG 1213579 378 } 379 380 { AbsentPropertyContext context; 381 context.Check("if (false) { var x = 0 }; x", 382 1, // access 383 1, // declaration 384 1, // declaration + initialization 385 EXPECT_RESULT, Undefined()); 386 } 387 } 388 389 390 391 class AppearingPropertyContext: public DeclarationContext { 392 public: 393 enum State { 394 DECLARE, 395 INITIALIZE_IF_ASSIGN, 396 UNKNOWN 397 }; 398 399 AppearingPropertyContext() : state_(DECLARE) { } 400 401 protected: 402 virtual v8::Handle<Integer> Query(Local<String> key) { 403 switch (state_) { 404 case DECLARE: 405 // Force declaration by returning that the 406 // property is absent. 407 state_ = INITIALIZE_IF_ASSIGN; 408 return Handle<Integer>(); 409 case INITIALIZE_IF_ASSIGN: 410 // Return that the property is present so we only get the 411 // setter called when initializing with a value. 412 state_ = UNKNOWN; 413 return Integer::New(v8::None); 414 default: 415 CHECK(state_ == UNKNOWN); 416 break; 417 } 418 // Do the lookup in the object. 419 return v8::Handle<Integer>(); 420 } 421 422 private: 423 State state_; 424 }; 425 426 427 TEST(Appearing) { 428 HandleScope scope(Isolate::GetCurrent()); 429 430 { AppearingPropertyContext context; 431 context.Check("var x; x", 432 1, // access 433 1, // declaration 434 2, // declaration + initialization 435 EXPECT_RESULT, Undefined()); 436 } 437 438 { AppearingPropertyContext context; 439 context.Check("var x = 0; x", 440 1, // access 441 2, // declaration + initialization 442 2, // declaration + initialization 443 EXPECT_RESULT, Number::New(0)); 444 } 445 446 { AppearingPropertyContext context; 447 context.Check("function x() { }; x", 448 1, // access 449 0, 450 0, 451 EXPECT_RESULT); 452 } 453 454 { AppearingPropertyContext context; 455 context.Check("const x; x", 456 1, // access 457 2, // declaration + initialization 458 1, // declaration 459 EXPECT_RESULT, Undefined()); 460 } 461 462 { AppearingPropertyContext context; 463 context.Check("const x = 0; x", 464 1, // access 465 2, // declaration + initialization 466 1, // declaration 467 EXPECT_RESULT, Undefined()); 468 // Result is undefined because declaration succeeded but 469 // initialization to 0 failed (due to context behavior). 470 } 471 } 472 473 474 475 class ReappearingPropertyContext: public DeclarationContext { 476 public: 477 enum State { 478 DECLARE, 479 DONT_DECLARE, 480 INITIALIZE, 481 UNKNOWN 482 }; 483 484 ReappearingPropertyContext() : state_(DECLARE) { } 485 486 protected: 487 virtual v8::Handle<Integer> Query(Local<String> key) { 488 switch (state_) { 489 case DECLARE: 490 // Force the first declaration by returning that 491 // the property is absent. 492 state_ = DONT_DECLARE; 493 return Handle<Integer>(); 494 case DONT_DECLARE: 495 // Ignore the second declaration by returning 496 // that the property is already there. 497 state_ = INITIALIZE; 498 return Integer::New(v8::None); 499 case INITIALIZE: 500 // Force an initialization by returning that 501 // the property is absent. This will make sure 502 // that the setter is called and it will not 503 // lead to redeclaration conflicts (yet). 504 state_ = UNKNOWN; 505 return Handle<Integer>(); 506 default: 507 CHECK(state_ == UNKNOWN); 508 break; 509 } 510 // Do the lookup in the object. 511 return Handle<Integer>(); 512 } 513 514 private: 515 State state_; 516 }; 517 518 519 TEST(Reappearing) { 520 HandleScope scope(Isolate::GetCurrent()); 521 522 { ReappearingPropertyContext context; 523 context.Check("const x; var x = 0", 524 0, 525 3, // const declaration+initialization, var initialization 526 3, // 2 x declaration + var initialization 527 EXPECT_RESULT, Undefined()); 528 } 529 } 530 531 532 533 class ExistsInPrototypeContext: public DeclarationContext { 534 protected: 535 virtual v8::Handle<Integer> Query(Local<String> key) { 536 // Let it seem that the property exists in the prototype object. 537 return Integer::New(v8::None); 538 } 539 540 // Use the prototype as the holder for the interceptors. 541 virtual Local<ObjectTemplate> GetHolder(Local<FunctionTemplate> function) { 542 return function->PrototypeTemplate(); 543 } 544 }; 545 546 547 TEST(ExistsInPrototype) { 548 i::FLAG_es52_globals = true; 549 HandleScope scope(Isolate::GetCurrent()); 550 551 // Sanity check to make sure that the holder of the interceptor 552 // really is the prototype object. 553 { ExistsInPrototypeContext context; 554 context.Check("this.x = 87; this.x", 555 0, 556 0, 557 0, 558 EXPECT_RESULT, Number::New(87)); 559 } 560 561 { ExistsInPrototypeContext context; 562 context.Check("var x; x", 563 0, 564 0, 565 0, 566 EXPECT_RESULT, Undefined()); 567 } 568 569 { ExistsInPrototypeContext context; 570 context.Check("var x = 0; x", 571 0, 572 0, 573 0, 574 EXPECT_RESULT, Number::New(0)); 575 } 576 577 { ExistsInPrototypeContext context; 578 context.Check("const x; x", 579 0, 580 0, 581 0, 582 EXPECT_RESULT, Undefined()); 583 } 584 585 { ExistsInPrototypeContext context; 586 context.Check("const x = 0; x", 587 0, 588 0, 589 0, 590 EXPECT_RESULT, Number::New(0)); 591 } 592 } 593 594 595 596 class AbsentInPrototypeContext: public DeclarationContext { 597 protected: 598 virtual v8::Handle<Integer> Query(Local<String> key) { 599 // Let it seem that the property is absent in the prototype object. 600 return Handle<Integer>(); 601 } 602 603 // Use the prototype as the holder for the interceptors. 604 virtual Local<ObjectTemplate> GetHolder(Local<FunctionTemplate> function) { 605 return function->PrototypeTemplate(); 606 } 607 }; 608 609 610 TEST(AbsentInPrototype) { 611 i::FLAG_es52_globals = true; 612 HandleScope scope(Isolate::GetCurrent()); 613 614 { AbsentInPrototypeContext context; 615 context.Check("if (false) { var x = 0; }; x", 616 0, 617 0, 618 0, 619 EXPECT_RESULT, Undefined()); 620 } 621 } 622 623 624 625 class ExistsInHiddenPrototypeContext: public DeclarationContext { 626 public: 627 ExistsInHiddenPrototypeContext() { 628 hidden_proto_ = FunctionTemplate::New(); 629 hidden_proto_->SetHiddenPrototype(true); 630 } 631 632 protected: 633 virtual v8::Handle<Integer> Query(Local<String> key) { 634 // Let it seem that the property exists in the hidden prototype object. 635 return Integer::New(v8::None); 636 } 637 638 // Install the hidden prototype after the global object has been created. 639 virtual void PostInitializeContext(Handle<Context> context) { 640 Local<Object> global_object = context->Global(); 641 Local<Object> hidden_proto = hidden_proto_->GetFunction()->NewInstance(); 642 context->DetachGlobal(); 643 context->Global()->SetPrototype(hidden_proto); 644 context->ReattachGlobal(global_object); 645 } 646 647 // Use the hidden prototype as the holder for the interceptors. 648 virtual Local<ObjectTemplate> GetHolder(Local<FunctionTemplate> function) { 649 return hidden_proto_->InstanceTemplate(); 650 } 651 652 private: 653 Local<FunctionTemplate> hidden_proto_; 654 }; 655 656 657 TEST(ExistsInHiddenPrototype) { 658 i::FLAG_es52_globals = true; 659 HandleScope scope(Isolate::GetCurrent()); 660 661 { ExistsInHiddenPrototypeContext context; 662 context.Check("var x; x", 663 1, // access 664 0, 665 2, // declaration + initialization 666 EXPECT_EXCEPTION); // x is not defined! 667 } 668 669 { ExistsInHiddenPrototypeContext context; 670 context.Check("var x = 0; x", 671 1, // access 672 1, // initialization 673 2, // declaration + initialization 674 EXPECT_RESULT, Number::New(0)); 675 } 676 677 { ExistsInHiddenPrototypeContext context; 678 context.Check("function x() { }; x", 679 0, 680 0, 681 0, 682 EXPECT_RESULT); 683 } 684 685 // TODO(mstarzinger): The semantics of global const is vague. 686 { ExistsInHiddenPrototypeContext context; 687 context.Check("const x; x", 688 0, 689 0, 690 1, // (re-)declaration 691 EXPECT_RESULT, Undefined()); 692 } 693 694 // TODO(mstarzinger): The semantics of global const is vague. 695 { ExistsInHiddenPrototypeContext context; 696 context.Check("const x = 0; x", 697 0, 698 0, 699 1, // (re-)declaration 700 EXPECT_RESULT, Number::New(0)); 701 } 702 } 703 704 705 706 class SimpleContext { 707 public: 708 SimpleContext() 709 : handle_scope_(Isolate::GetCurrent()), 710 context_(Context::New(Isolate::GetCurrent())) { 711 context_->Enter(); 712 } 713 714 ~SimpleContext() { 715 context_->Exit(); 716 } 717 718 void Check(const char* source, 719 Expectations expectations, 720 v8::Handle<Value> value = Local<Value>()) { 721 HandleScope scope(context_->GetIsolate()); 722 TryCatch catcher; 723 catcher.SetVerbose(true); 724 Local<Script> script = Script::Compile(String::New(source)); 725 if (expectations == EXPECT_ERROR) { 726 CHECK(script.IsEmpty()); 727 return; 728 } 729 CHECK(!script.IsEmpty()); 730 Local<Value> result = script->Run(); 731 if (expectations == EXPECT_RESULT) { 732 CHECK(!catcher.HasCaught()); 733 if (!value.IsEmpty()) { 734 CHECK_EQ(value, result); 735 } 736 } else { 737 CHECK(expectations == EXPECT_EXCEPTION); 738 CHECK(catcher.HasCaught()); 739 if (!value.IsEmpty()) { 740 CHECK_EQ(value, catcher.Exception()); 741 } 742 } 743 } 744 745 private: 746 HandleScope handle_scope_; 747 Local<Context> context_; 748 }; 749 750 751 TEST(CrossScriptReferences) { 752 HandleScope scope(Isolate::GetCurrent()); 753 754 { SimpleContext context; 755 context.Check("var x = 1; x", 756 EXPECT_RESULT, Number::New(1)); 757 context.Check("var x = 2; x", 758 EXPECT_RESULT, Number::New(2)); 759 context.Check("const x = 3; x", 760 EXPECT_RESULT, Number::New(3)); 761 context.Check("const x = 4; x", 762 EXPECT_RESULT, Number::New(4)); 763 context.Check("x = 5; x", 764 EXPECT_RESULT, Number::New(5)); 765 context.Check("var x = 6; x", 766 EXPECT_RESULT, Number::New(6)); 767 context.Check("this.x", 768 EXPECT_RESULT, Number::New(6)); 769 context.Check("function x() { return 7 }; x()", 770 EXPECT_RESULT, Number::New(7)); 771 } 772 773 { SimpleContext context; 774 context.Check("const x = 1; x", 775 EXPECT_RESULT, Number::New(1)); 776 context.Check("var x = 2; x", // assignment ignored 777 EXPECT_RESULT, Number::New(1)); 778 context.Check("const x = 3; x", 779 EXPECT_RESULT, Number::New(1)); 780 context.Check("x = 4; x", // assignment ignored 781 EXPECT_RESULT, Number::New(1)); 782 context.Check("var x = 5; x", // assignment ignored 783 EXPECT_RESULT, Number::New(1)); 784 context.Check("this.x", 785 EXPECT_RESULT, Number::New(1)); 786 context.Check("function x() { return 7 }; x", 787 EXPECT_EXCEPTION); 788 } 789 } 790 791 792 TEST(CrossScriptReferencesHarmony) { 793 i::FLAG_use_strict = true; 794 i::FLAG_harmony_scoping = true; 795 i::FLAG_harmony_modules = true; 796 797 HandleScope scope(Isolate::GetCurrent()); 798 799 const char* decs[] = { 800 "var x = 1; x", "x", "this.x", 801 "function x() { return 1 }; x()", "x()", "this.x()", 802 "let x = 1; x", "x", "this.x", 803 "const x = 1; x", "x", "this.x", 804 "module x { export let a = 1 }; x.a", "x.a", "this.x.a", 805 NULL 806 }; 807 808 for (int i = 0; decs[i] != NULL; i += 3) { 809 SimpleContext context; 810 context.Check(decs[i], EXPECT_RESULT, Number::New(1)); 811 context.Check(decs[i+1], EXPECT_RESULT, Number::New(1)); 812 // TODO(rossberg): The current ES6 draft spec does not reflect lexical 813 // bindings on the global object. However, this will probably change, in 814 // which case we reactivate the following test. 815 if (i/3 < 2) context.Check(decs[i+2], EXPECT_RESULT, Number::New(1)); 816 } 817 } 818 819 820 TEST(CrossScriptConflicts) { 821 i::FLAG_use_strict = true; 822 i::FLAG_harmony_scoping = true; 823 i::FLAG_harmony_modules = true; 824 825 HandleScope scope(Isolate::GetCurrent()); 826 827 const char* firsts[] = { 828 "var x = 1; x", 829 "function x() { return 1 }; x()", 830 "let x = 1; x", 831 "const x = 1; x", 832 "module x { export let a = 1 }; x.a", 833 NULL 834 }; 835 const char* seconds[] = { 836 "var x = 2; x", 837 "function x() { return 2 }; x()", 838 "let x = 2; x", 839 "const x = 2; x", 840 "module x { export let a = 2 }; x.a", 841 NULL 842 }; 843 844 for (int i = 0; firsts[i] != NULL; ++i) { 845 for (int j = 0; seconds[j] != NULL; ++j) { 846 SimpleContext context; 847 context.Check(firsts[i], EXPECT_RESULT, Number::New(1)); 848 // TODO(rossberg): All tests should actually be errors in Harmony, 849 // but we currently do not detect the cases where the first declaration 850 // is not lexical. 851 context.Check(seconds[j], 852 i < 2 ? EXPECT_RESULT : EXPECT_ERROR, Number::New(2)); 853 } 854 } 855 } 856