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
~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
isolate() const99 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
DeclarationContext()113 DeclarationContext::DeclarationContext()
114 : is_initialized_(false), get_count_(0), set_count_(0), query_count_(0) {
115 // Do nothing.
116 }
117
118
InitializeIfNeeded()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
Check(const char * source,int get,int set,int query,Expectations expectations,v8::Handle<Value> value)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
HandleGet(Local<String> key,const v8::PropertyCallbackInfo<v8::Value> & info)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
HandleSet(Local<String> key,Local<Value> value,const v8::PropertyCallbackInfo<v8::Value> & info)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
HandleQuery(Local<String> key,const v8::PropertyCallbackInfo<v8::Integer> & info)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
GetInstance(Local<Value> data)208 DeclarationContext* DeclarationContext::GetInstance(Local<Value> data) {
209 void* value = Local<External>::Cast(data)->Value();
210 return static_cast<DeclarationContext*>(value);
211 }
212
213
Get(Local<String> key)214 v8::Handle<Value> DeclarationContext::Get(Local<String> key) {
215 return v8::Handle<Value>();
216 }
217
218
Set(Local<String> key,Local<Value> value)219 v8::Handle<Value> DeclarationContext::Set(Local<String> key,
220 Local<Value> value) {
221 return v8::Handle<Value>();
222 }
223
224
Query(Local<String> key)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.
TEST(Unknown)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:
Query(Local<String> key)275 virtual v8::Handle<Integer> Query(Local<String> key) {
276 return v8::Handle<Integer>();
277 }
278 };
279
280
TEST(Absent)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
AppearingPropertyContext()336 AppearingPropertyContext() : state_(DECLARE) { }
337
338 protected:
Query(Local<String> key)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
TEST(Appearing)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:
ExistsInPrototypeContext()406 ExistsInPrototypeContext() { InitializeIfNeeded(); }
407 protected:
Query(Local<String> key)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.
GetHolder(Local<FunctionTemplate> function)414 virtual Local<ObjectTemplate> GetHolder(Local<FunctionTemplate> function) {
415 return function->PrototypeTemplate();
416 }
417 };
418
419
TEST(ExistsInPrototype)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:
Query(Local<String> key)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.
GetHolder(Local<FunctionTemplate> function)473 virtual Local<ObjectTemplate> GetHolder(Local<FunctionTemplate> function) {
474 return function->PrototypeTemplate();
475 }
476 };
477
478
TEST(AbsentInPrototype)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:
ExistsInHiddenPrototypeContext()496 ExistsInHiddenPrototypeContext() {
497 hidden_proto_ = FunctionTemplate::New(CcTest::isolate());
498 hidden_proto_->SetHiddenPrototype(true);
499 }
500
501 protected:
Query(Local<String> key)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.
PostInitializeContext(Handle<Context> context)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.
GetHolder(Local<FunctionTemplate> function)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
TEST(ExistsInHiddenPrototype)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:
SimpleContext()564 SimpleContext()
565 : handle_scope_(CcTest::isolate()),
566 context_(Context::New(CcTest::isolate())) {
567 context_->Enter();
568 }
569
~SimpleContext()570 ~SimpleContext() {
571 context_->Exit();
572 }
573
Check(const char * source,Expectations expectations,v8::Handle<Value> value=Local<Value> ())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
TEST(CrossScriptReferences)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
TEST(CrossScriptReferencesHarmony)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
TEST(CrossScriptConflicts)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