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 "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