Home | History | Annotate | Download | only in cctest
      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