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