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/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                   0, 0, EXPECT_RESULT, Undefined(CcTest::isolate()));
    240   }
    241 
    242   { DeclarationContext context;
    243     context.Check("var x = 0; x",
    244                   1,  // access
    245                   1,  // initialization
    246                   0, EXPECT_RESULT, Number::New(CcTest::isolate(), 0));
    247   }
    248 
    249   { DeclarationContext context;
    250     context.Check("function x() { }; x",
    251                   1,  // access
    252                   0,
    253                   0,
    254                   EXPECT_RESULT);
    255   }
    256 
    257   { DeclarationContext context;
    258     context.Check("const x; x",
    259                   1,  // access
    260                   0, 0, EXPECT_RESULT, Undefined(CcTest::isolate()));
    261   }
    262 
    263   { DeclarationContext context;
    264     context.Check("const x = 0; x",
    265                   1,  // access
    266                   0,
    267                   0,
    268                   EXPECT_RESULT, Number::New(CcTest::isolate(), 0));
    269   }
    270 }
    271 
    272 
    273 class AbsentPropertyContext: public DeclarationContext {
    274  protected:
    275   virtual v8::Handle<Integer> Query(Local<String> key) {
    276     return v8::Handle<Integer>();
    277   }
    278 };
    279 
    280 
    281 TEST(Absent) {
    282   v8::Isolate* isolate = CcTest::isolate();
    283   v8::V8::Initialize();
    284   HandleScope scope(isolate);
    285 
    286   { AbsentPropertyContext context;
    287     context.Check("var x; x",
    288                   1,  // access
    289                   0, 0, EXPECT_RESULT, Undefined(isolate));
    290   }
    291 
    292   { AbsentPropertyContext context;
    293     context.Check("var x = 0; x",
    294                   1,  // access
    295                   1,  // initialization
    296                   0, EXPECT_RESULT, Number::New(isolate, 0));
    297   }
    298 
    299   { AbsentPropertyContext context;
    300     context.Check("function x() { }; x",
    301                   1,  // access
    302                   0,
    303                   0,
    304                   EXPECT_RESULT);
    305   }
    306 
    307   { AbsentPropertyContext context;
    308     context.Check("const x; x",
    309                   1,  // access
    310                   0, 0, EXPECT_RESULT, Undefined(isolate));
    311   }
    312 
    313   { AbsentPropertyContext context;
    314     context.Check("const x = 0; x",
    315                   1,  // access
    316                   0, 0, EXPECT_RESULT, Number::New(isolate, 0));
    317   }
    318 
    319   { AbsentPropertyContext context;
    320     context.Check("if (false) { var x = 0 }; x",
    321                   1,  // access
    322                   0, 0, EXPECT_RESULT, Undefined(isolate));
    323   }
    324 }
    325 
    326 
    327 
    328 class AppearingPropertyContext: public DeclarationContext {
    329  public:
    330   enum State {
    331     DECLARE,
    332     INITIALIZE_IF_ASSIGN,
    333     UNKNOWN
    334   };
    335 
    336   AppearingPropertyContext() : state_(DECLARE) { }
    337 
    338  protected:
    339   virtual v8::Handle<Integer> Query(Local<String> key) {
    340     switch (state_) {
    341       case DECLARE:
    342         // Force declaration by returning that the
    343         // property is absent.
    344         state_ = INITIALIZE_IF_ASSIGN;
    345         return Handle<Integer>();
    346       case INITIALIZE_IF_ASSIGN:
    347         // Return that the property is present so we only get the
    348         // setter called when initializing with a value.
    349         state_ = UNKNOWN;
    350         return Integer::New(isolate(), v8::None);
    351       default:
    352         CHECK(state_ == UNKNOWN);
    353         break;
    354     }
    355     // Do the lookup in the object.
    356     return v8::Handle<Integer>();
    357   }
    358 
    359  private:
    360   State state_;
    361 };
    362 
    363 
    364 TEST(Appearing) {
    365   v8::V8::Initialize();
    366   HandleScope scope(CcTest::isolate());
    367 
    368   { AppearingPropertyContext context;
    369     context.Check("var x; x",
    370                   1,  // access
    371                   0, 0, EXPECT_RESULT, Undefined(CcTest::isolate()));
    372   }
    373 
    374   { AppearingPropertyContext context;
    375     context.Check("var x = 0; x",
    376                   1,  // access
    377                   1,  // initialization
    378                   0, EXPECT_RESULT, Number::New(CcTest::isolate(), 0));
    379   }
    380 
    381   { AppearingPropertyContext context;
    382     context.Check("function x() { }; x",
    383                   1,  // access
    384                   0,
    385                   0,
    386                   EXPECT_RESULT);
    387   }
    388 
    389   { AppearingPropertyContext context;
    390     context.Check("const x; x",
    391                   1,  // access
    392                   0, 0, EXPECT_RESULT, Undefined(CcTest::isolate()));
    393   }
    394 
    395   { AppearingPropertyContext context;
    396     context.Check("const x = 0; x",
    397                   1,  // access
    398                   0, 0, EXPECT_RESULT, Number::New(CcTest::isolate(), 0));
    399   }
    400 }
    401 
    402 
    403 
    404 class ExistsInPrototypeContext: public DeclarationContext {
    405  public:
    406   ExistsInPrototypeContext() { InitializeIfNeeded(); }
    407  protected:
    408   virtual v8::Handle<Integer> Query(Local<String> key) {
    409     // Let it seem that the property exists in the prototype object.
    410     return Integer::New(isolate(), v8::None);
    411   }
    412 
    413   // Use the prototype as the holder for the interceptors.
    414   virtual Local<ObjectTemplate> GetHolder(Local<FunctionTemplate> function) {
    415     return function->PrototypeTemplate();
    416   }
    417 };
    418 
    419 
    420 TEST(ExistsInPrototype) {
    421   HandleScope scope(CcTest::isolate());
    422 
    423   // Sanity check to make sure that the holder of the interceptor
    424   // really is the prototype object.
    425   { ExistsInPrototypeContext context;
    426     context.Check("this.x = 87; this.x", 0, 0, 1, EXPECT_RESULT,
    427                   Number::New(CcTest::isolate(), 87));
    428   }
    429 
    430   { ExistsInPrototypeContext context;
    431     context.Check("var x; x",
    432                   0,
    433                   0,
    434                   0,
    435                   EXPECT_RESULT, Undefined(CcTest::isolate()));
    436   }
    437 
    438   { ExistsInPrototypeContext context;
    439     context.Check("var x = 0; x",
    440                   0,
    441                   0,
    442                   0,
    443                   EXPECT_RESULT, Number::New(CcTest::isolate(), 0));
    444   }
    445 
    446   { ExistsInPrototypeContext context;
    447     context.Check("const x; x",
    448                   0,
    449                   0,
    450                   0,
    451                   EXPECT_RESULT, Undefined(CcTest::isolate()));
    452   }
    453 
    454   { ExistsInPrototypeContext context;
    455     context.Check("const x = 0; x",
    456                   0,
    457                   0,
    458                   0,
    459                   EXPECT_RESULT, Number::New(CcTest::isolate(), 0));
    460   }
    461 }
    462 
    463 
    464 
    465 class AbsentInPrototypeContext: public DeclarationContext {
    466  protected:
    467   virtual v8::Handle<Integer> Query(Local<String> key) {
    468     // Let it seem that the property is absent in the prototype object.
    469     return Handle<Integer>();
    470   }
    471 
    472   // Use the prototype as the holder for the interceptors.
    473   virtual Local<ObjectTemplate> GetHolder(Local<FunctionTemplate> function) {
    474     return function->PrototypeTemplate();
    475   }
    476 };
    477 
    478 
    479 TEST(AbsentInPrototype) {
    480   v8::V8::Initialize();
    481   HandleScope scope(CcTest::isolate());
    482 
    483   { AbsentInPrototypeContext context;
    484     context.Check("if (false) { var x = 0; }; x",
    485                   0,
    486                   0,
    487                   0,
    488                   EXPECT_RESULT, Undefined(CcTest::isolate()));
    489   }
    490 }
    491 
    492 
    493 
    494 class ExistsInHiddenPrototypeContext: public DeclarationContext {
    495  public:
    496   ExistsInHiddenPrototypeContext() {
    497     hidden_proto_ = FunctionTemplate::New(CcTest::isolate());
    498     hidden_proto_->SetHiddenPrototype(true);
    499   }
    500 
    501  protected:
    502   virtual v8::Handle<Integer> Query(Local<String> key) {
    503     // Let it seem that the property exists in the hidden prototype object.
    504     return Integer::New(isolate(), v8::None);
    505   }
    506 
    507   // Install the hidden prototype after the global object has been created.
    508   virtual void PostInitializeContext(Handle<Context> context) {
    509     Local<Object> global_object = context->Global();
    510     Local<Object> hidden_proto = hidden_proto_->GetFunction()->NewInstance();
    511     Local<Object> inner_global =
    512         Local<Object>::Cast(global_object->GetPrototype());
    513     inner_global->SetPrototype(hidden_proto);
    514   }
    515 
    516   // Use the hidden prototype as the holder for the interceptors.
    517   virtual Local<ObjectTemplate> GetHolder(Local<FunctionTemplate> function) {
    518     return hidden_proto_->InstanceTemplate();
    519   }
    520 
    521  private:
    522   Local<FunctionTemplate> hidden_proto_;
    523 };
    524 
    525 
    526 TEST(ExistsInHiddenPrototype) {
    527   HandleScope scope(CcTest::isolate());
    528 
    529   { ExistsInHiddenPrototypeContext context;
    530     context.Check("var x; x", 0, 0, 0, EXPECT_RESULT,
    531                   Undefined(CcTest::isolate()));
    532   }
    533 
    534   { ExistsInHiddenPrototypeContext context;
    535     context.Check("var x = 0; x", 0, 0, 0, EXPECT_RESULT,
    536                   Number::New(CcTest::isolate(), 0));
    537   }
    538 
    539   { ExistsInHiddenPrototypeContext context;
    540     context.Check("function x() { }; x",
    541                   0,
    542                   0,
    543                   0,
    544                   EXPECT_RESULT);
    545   }
    546 
    547   // TODO(mstarzinger): The semantics of global const is vague.
    548   { ExistsInHiddenPrototypeContext context;
    549     context.Check("const x; x", 0, 0, 0, EXPECT_RESULT,
    550                   Undefined(CcTest::isolate()));
    551   }
    552 
    553   // TODO(mstarzinger): The semantics of global const is vague.
    554   { ExistsInHiddenPrototypeContext context;
    555     context.Check("const x = 0; x", 0, 0, 0, EXPECT_RESULT,
    556                   Number::New(CcTest::isolate(), 0));
    557   }
    558 }
    559 
    560 
    561 
    562 class SimpleContext {
    563  public:
    564   SimpleContext()
    565       : handle_scope_(CcTest::isolate()),
    566         context_(Context::New(CcTest::isolate())) {
    567     context_->Enter();
    568   }
    569 
    570   ~SimpleContext() {
    571     context_->Exit();
    572   }
    573 
    574   void Check(const char* source,
    575              Expectations expectations,
    576              v8::Handle<Value> value = Local<Value>()) {
    577     HandleScope scope(context_->GetIsolate());
    578     TryCatch catcher;
    579     catcher.SetVerbose(true);
    580     Local<Script> script =
    581         Script::Compile(String::NewFromUtf8(context_->GetIsolate(), source));
    582     if (expectations == EXPECT_ERROR) {
    583       CHECK(script.IsEmpty());
    584       return;
    585     }
    586     CHECK(!script.IsEmpty());
    587     Local<Value> result = script->Run();
    588     if (expectations == EXPECT_RESULT) {
    589       CHECK(!catcher.HasCaught());
    590       if (!value.IsEmpty()) {
    591         CHECK_EQ(value, result);
    592       }
    593     } else {
    594       CHECK(expectations == EXPECT_EXCEPTION);
    595       CHECK(catcher.HasCaught());
    596       if (!value.IsEmpty()) {
    597         CHECK_EQ(value, catcher.Exception());
    598       }
    599     }
    600   }
    601 
    602  private:
    603   HandleScope handle_scope_;
    604   Local<Context> context_;
    605 };
    606 
    607 
    608 TEST(CrossScriptReferences) {
    609   v8::Isolate* isolate = CcTest::isolate();
    610   HandleScope scope(isolate);
    611 
    612   { SimpleContext context;
    613     context.Check("var x = 1; x",
    614                   EXPECT_RESULT, Number::New(isolate, 1));
    615     context.Check("var x = 2; x",
    616                   EXPECT_RESULT, Number::New(isolate, 2));
    617     context.Check("const x = 3; x", EXPECT_EXCEPTION);
    618     context.Check("const x = 4; x", EXPECT_EXCEPTION);
    619     context.Check("x = 5; x",
    620                   EXPECT_RESULT, Number::New(isolate, 5));
    621     context.Check("var x = 6; x",
    622                   EXPECT_RESULT, Number::New(isolate, 6));
    623     context.Check("this.x",
    624                   EXPECT_RESULT, Number::New(isolate, 6));
    625     context.Check("function x() { return 7 }; x()",
    626                   EXPECT_RESULT, Number::New(isolate, 7));
    627   }
    628 
    629   { SimpleContext context;
    630     context.Check("const x = 1; x",
    631                   EXPECT_RESULT, Number::New(isolate, 1));
    632     context.Check("var x = 2; x",  // assignment ignored
    633                   EXPECT_RESULT, Number::New(isolate, 1));
    634     context.Check("const x = 3; x", EXPECT_EXCEPTION);
    635     context.Check("x = 4; x",  // assignment ignored
    636                   EXPECT_RESULT, Number::New(isolate, 1));
    637     context.Check("var x = 5; x",  // assignment ignored
    638                   EXPECT_RESULT, Number::New(isolate, 1));
    639     context.Check("this.x",
    640                   EXPECT_RESULT, Number::New(isolate, 1));
    641     context.Check("function x() { return 7 }; x",
    642                   EXPECT_EXCEPTION);
    643   }
    644 }
    645 
    646 
    647 TEST(CrossScriptReferencesHarmony) {
    648   i::FLAG_use_strict = true;
    649   i::FLAG_harmony_scoping = true;
    650   i::FLAG_harmony_modules = true;
    651 
    652   v8::Isolate* isolate = CcTest::isolate();
    653   HandleScope scope(isolate);
    654 
    655   const char* decs[] = {
    656     "var x = 1; x", "x", "this.x",
    657     "function x() { return 1 }; x()", "x()", "this.x()",
    658     "let x = 1; x", "x", "this.x",
    659     "const x = 1; x", "x", "this.x",
    660     "module x { export let a = 1 }; x.a", "x.a", "this.x.a",
    661     NULL
    662   };
    663 
    664   for (int i = 0; decs[i] != NULL; i += 3) {
    665     SimpleContext context;
    666     context.Check(decs[i], EXPECT_RESULT, Number::New(isolate, 1));
    667     context.Check(decs[i+1], EXPECT_RESULT, Number::New(isolate, 1));
    668     // TODO(rossberg): The current ES6 draft spec does not reflect lexical
    669     // bindings on the global object. However, this will probably change, in
    670     // which case we reactivate the following test.
    671     if (i/3 < 2) {
    672       context.Check(decs[i+2], EXPECT_RESULT, Number::New(isolate, 1));
    673     }
    674   }
    675 }
    676 
    677 
    678 TEST(CrossScriptConflicts) {
    679   i::FLAG_use_strict = true;
    680   i::FLAG_harmony_scoping = true;
    681   i::FLAG_harmony_modules = true;
    682 
    683   HandleScope scope(CcTest::isolate());
    684 
    685   const char* firsts[] = {
    686     "var x = 1; x",
    687     "function x() { return 1 }; x()",
    688     "let x = 1; x",
    689     "const x = 1; x",
    690     "module x { export let a = 1 }; x.a",
    691     NULL
    692   };
    693   const char* seconds[] = {
    694     "var x = 2; x",
    695     "function x() { return 2 }; x()",
    696     "let x = 2; x",
    697     "const x = 2; x",
    698     "module x { export let a = 2 }; x.a",
    699     NULL
    700   };
    701 
    702   for (int i = 0; firsts[i] != NULL; ++i) {
    703     for (int j = 0; seconds[j] != NULL; ++j) {
    704       SimpleContext context;
    705       context.Check(firsts[i], EXPECT_RESULT,
    706                     Number::New(CcTest::isolate(), 1));
    707       // TODO(rossberg): All tests should actually be errors in Harmony,
    708       // but we currently do not detect the cases where the first declaration
    709       // is not lexical.
    710       context.Check(seconds[j],
    711                     i < 2 ? EXPECT_RESULT : EXPECT_ERROR,
    712                     Number::New(CcTest::isolate(), 2));
    713     }
    714   }
    715 }
    716