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