Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(5)

Side by Side Diff: runtime/vm/isolate_reload_test.cc

Issue 1965823002: Initial isolate reload support (Closed) Base URL: git@github.com:dart-lang/sdk.git@master
Patch Set: Created 4 years, 7 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
OLDNEW
(Empty)
1 // Copyright (c) 2016, the Dart project authors. Please see the AUTHORS file
2 // for details. All rights reserved. Use of this source code is governed by a
3 // BSD-style license that can be found in the LICENSE file.
4
5 #include "include/dart_api.h"
6 #include "include/dart_tools_api.h"
7 #include "platform/assert.h"
8 #include "vm/globals.h"
9 #include "vm/isolate.h"
10 #include "vm/lockers.h"
11 #include "vm/thread_barrier.h"
12 #include "vm/thread_pool.h"
13 #include "vm/unit_test.h"
14
15 namespace dart {
16
17 #ifndef PRODUCT
18
19 // TODO(johnmccutchan):
20 // - Tests involving generics.
21
22 int64_t SimpleInvoke(Dart_Handle lib, const char* method) {
23 Dart_Handle result = Dart_Invoke(lib, NewString(method), 0, NULL);
24 EXPECT_VALID(result);
25 EXPECT(Dart_IsInteger(result));
26 int64_t integer_result = 0;
27 result = Dart_IntegerToInt64(result, &integer_result);
28 EXPECT_VALID(result);
29 return integer_result;
30 }
31
32
33 const char* SimpleInvokeStr(Dart_Handle lib, const char* method) {
34 Dart_Handle result = Dart_Invoke(lib, NewString(method), 0, NULL);
35 const char* result_str = NULL;
36 EXPECT(Dart_IsString(result));
37 EXPECT_VALID(Dart_StringToCString(result, &result_str));
38 return result_str;
39 }
40
41
42 Dart_Handle SimpleInvokeError(Dart_Handle lib, const char* method) {
43 Dart_Handle result = Dart_Invoke(lib, NewString(method), 0, NULL);
44 EXPECT(Dart_IsError(result));
45 return result;
46 }
47
48
49 TEST_CASE(IsolateReload_FunctionReplacement) {
50 const char* kScript =
51 "main() {\n"
52 " return 4;\n"
53 "}\n";
54
55 Dart_Handle lib = TestCase::LoadTestScript(kScript, NULL);
56 EXPECT_VALID(lib);
57
58 EXPECT_EQ(4, SimpleInvoke(lib, "main"));
59
60 const char* kReloadScript =
61 "var _unused;"
62 "main() {\n"
63 " return 10;\n"
64 "}\n";
65
66 lib = TestCase::ReloadTestScript(kReloadScript);
67 EXPECT_VALID(lib);
68
69 EXPECT_EQ(10, SimpleInvoke(lib, "main"));
70 }
71
72
73 TEST_CASE(IsolateReload_BadClass) {
74 const char* kScript =
75 "class Foo {\n"
76 " final a;\n"
77 " Foo(this.a);\n"
78 "}\n"
79 "main() {\n"
80 " new Foo(5);\n"
81 " return 4;\n"
82 "}\n";
83
84 Dart_Handle lib = TestCase::LoadTestScript(kScript, NULL);
85 EXPECT_VALID(lib);
86
87 EXPECT_EQ(4, SimpleInvoke(lib, "main"));
88
89 const char* kReloadScript =
90 "var _unused;"
91 "class Foo {\n"
92 " final a kjsdf ksjdf ;\n"
93 " Foo(this.a);\n"
94 "}\n"
95 "main() {\n"
96 " new Foo(5);\n"
97 " return 10;\n"
98 "}\n";
99
100 Dart_Handle result = TestCase::ReloadTestScript(kReloadScript);
101 EXPECT_ERROR(result, "unexpected token");
102
103 EXPECT_EQ(4, SimpleInvoke(lib, "main"));
104 }
105
106
107 TEST_CASE(IsolateReload_StaticValuePreserved) {
108 const char* kScript =
109 "init() => 'old value';\n"
110 "var value = init();\n"
111 "main() {\n"
112 " return 'init()=${init()},value=${value}';\n"
113 "}\n";
114
115 Dart_Handle lib = TestCase::LoadTestScript(kScript, NULL);
116 EXPECT_VALID(lib);
117
118 EXPECT_STREQ("init()=old value,value=old value",
119 SimpleInvokeStr(lib, "main"));
120
121 const char* kReloadScript =
122 "var _unused;"
123 "init() => 'new value';\n"
124 "var value = init();\n"
125 "main() {\n"
126 " return 'init()=${init()},value=${value}';\n"
127 "}\n";
128
129 lib = TestCase::ReloadTestScript(kReloadScript);
130 EXPECT_VALID(lib);
131
132 EXPECT_STREQ("init()=new value,value=old value",
133 SimpleInvokeStr(lib, "main"));
134 }
135
136
137 TEST_CASE(IsolateReload_SavedClosure) {
138 // Create a closure in main which only exists in the original source.
139 const char* kScript =
140 "magic() {\n"
141 " var x = 'ante';\n"
142 " return x + 'diluvian';\n"
143 "}\n"
144 "var closure;\n"
145 "main() {\n"
146 " closure = () { return magic().toString() + '!'; };\n"
147 " return closure();\n"
148 "}\n";
149
150 Dart_Handle lib = TestCase::LoadTestScript(kScript, NULL);
151 EXPECT_VALID(lib);
152
153 EXPECT_STREQ("antediluvian!", SimpleInvokeStr(lib, "main"));
154
155 // Remove the original closure from the source code. The closure is
156 // able to be recompiled because its source is preserved in a
157 // special patch class.
158 const char* kReloadScript =
159 "magic() {\n"
160 " return 'postapocalyptic';\n"
161 "}\n"
162 "var closure;\n"
163 "main() {\n"
164 " return closure();\n"
165 "}\n";
166
167 lib = TestCase::ReloadTestScript(kReloadScript);
168 EXPECT_VALID(lib);
169
170 EXPECT_STREQ("postapocalyptic!", SimpleInvokeStr(lib, "main"));
171 }
172
173
174 TEST_CASE(IsolateReload_TopLevelFieldAdded) {
175 const char* kScript =
176 "var value1 = 10;\n"
177 "main() {\n"
178 " return 'value1=${value1}';\n"
179 "}\n";
180
181 Dart_Handle lib = TestCase::LoadTestScript(kScript, NULL);
182 EXPECT_VALID(lib);
183
184 EXPECT_STREQ("value1=10", SimpleInvokeStr(lib, "main"));
185
186 const char* kReloadScript =
187 "var value1 = 10;\n"
188 "var value2 = 20;\n"
189 "main() {\n"
190 " return 'value1=${value1},value2=${value2}';\n"
191 "}\n";
192
193 lib = TestCase::ReloadTestScript(kReloadScript);
194 EXPECT_VALID(lib);
195
196 EXPECT_STREQ("value1=10,value2=20",
197 SimpleInvokeStr(lib, "main"));
198 }
199
200
201 TEST_CASE(IsolateReload_ClassFieldAdded) {
202 const char* kScript =
203 "class Foo {\n"
204 " var x;\n"
205 "}\n"
206 "main() {\n"
207 " new Foo();\n"
208 " return 44;\n"
209 "}\n";
210
211 Dart_Handle lib = TestCase::LoadTestScript(kScript, NULL);
212 EXPECT_VALID(lib);
213
214 EXPECT_EQ(44, SimpleInvoke(lib, "main"));
215
216 const char* kReloadScript =
217 "class Foo {\n"
218 " var x;\n"
219 " var y;\n"
220 "}\n"
221 "main() {\n"
222 " new Foo();\n"
223 " return 44;\n"
224 "}\n";
225
226 lib = TestCase::ReloadTestScript(kReloadScript);
227 EXPECT_ERROR(lib, "Number of instance fields changed");
228 }
229
230
231 TEST_CASE(IsolateReload_ClassFieldRemoved) {
232 const char* kScript =
233 "class Foo {\n"
234 " var x;\n"
235 " var y;\n"
236 "}\n"
237 "main() {\n"
238 " new Foo();\n"
239 " return 44;\n"
240 "}\n";
241
242 Dart_Handle lib = TestCase::LoadTestScript(kScript, NULL);
243 EXPECT_VALID(lib);
244
245 EXPECT_EQ(44, SimpleInvoke(lib, "main"));
246
247 const char* kReloadScript =
248 "class Foo {\n"
249 " var x;\n"
250 "}\n"
251 "main() {\n"
252 " new Foo();\n"
253 " return 44;\n"
254 "}\n";
255
256 lib = TestCase::ReloadTestScript(kReloadScript);
257 EXPECT_ERROR(lib, "Number of instance fields changed");
258 }
259
260
261 TEST_CASE(IsolateReload_ClassAdded) {
262 const char* kScript =
263 "main() {\n"
264 " return 'hello';\n"
265 "}\n";
266
267 Dart_Handle lib = TestCase::LoadTestScript(kScript, NULL);
268 EXPECT_VALID(lib);
269
270 EXPECT_STREQ("hello", SimpleInvokeStr(lib, "main"));
271
272 const char* kReloadScript =
273 "var _unused;"
274 "class A {\n"
275 " toString() => 'hello from A';\n"
276 "}\n"
277 "main() {\n"
278 " return new A().toString();\n"
279 "}\n";
280
281 lib = TestCase::ReloadTestScript(kReloadScript);
282 EXPECT_VALID(lib);
283
284 EXPECT_STREQ("hello from A", SimpleInvokeStr(lib, "main"));
285 }
286
287
288 TEST_CASE(IsolateReload_LibraryImportAdded) {
289 const char* kScript =
290 "main() {\n"
291 " return max(3, 4);\n"
292 "}\n";
293
294 Dart_Handle lib = TestCase::LoadTestScript(kScript, NULL);
295 EXPECT_VALID(lib);
296
297 EXPECT_ERROR(SimpleInvokeError(lib, "main"), "max");;
298
299 const char* kReloadScript =
300 "import 'dart:math';\n"
301 "main() {\n"
302 " return max(3, 4);\n"
303 "}\n";
304
305 lib = TestCase::ReloadTestScript(kReloadScript);
306 EXPECT_VALID(lib);
307
308 EXPECT_EQ(4, SimpleInvoke(lib, "main"));
309 }
310
311
312 TEST_CASE(IsolateReload_LibraryImportRemoved) {
313 const char* kScript =
314 "import 'dart:math';\n"
315 "main() {\n"
316 " return max(3, 4);\n"
317 "}\n";
318
319 Dart_Handle lib = TestCase::LoadTestScript(kScript, NULL);
320 EXPECT_VALID(lib);
321
322 EXPECT_EQ(4, SimpleInvoke(lib, "main"));
323
324 const char* kReloadScript =
325 "main() {\n"
326 " return max(3, 4);\n"
327 "}\n";
328
329 lib = TestCase::ReloadTestScript(kReloadScript);
330 EXPECT_VALID(lib);
331
332 EXPECT_ERROR(SimpleInvokeError(lib, "main"), "max");;
333 }
334
335
336 TEST_CASE(IsolateReload_LibraryDebuggable) {
337 const char* kScript =
338 "main() {\n"
339 " return 1;\n"
340 "}\n";
341
342 Dart_Handle lib = TestCase::LoadTestScript(kScript, NULL);
343 EXPECT_VALID(lib);
344
345 // The library is by default debuggable. Make it not debuggable.
346 intptr_t lib_id = -1;
347 bool debuggable = false;
348 EXPECT_VALID(Dart_LibraryId(lib, &lib_id));
349 EXPECT_VALID(Dart_GetLibraryDebuggable(lib_id, &debuggable));
350 EXPECT_EQ(true, debuggable);
351 EXPECT_VALID(Dart_SetLibraryDebuggable(lib_id, false));
352 EXPECT_VALID(Dart_GetLibraryDebuggable(lib_id, &debuggable));
353 EXPECT_EQ(false, debuggable);
354
355 EXPECT_EQ(1, SimpleInvoke(lib, "main"));
356
357 const char* kReloadScript =
358 "main() {\n"
359 " return 2;\n"
360 "}\n";
361
362 lib = TestCase::ReloadTestScript(kReloadScript);
363 EXPECT_VALID(lib);
364
365 EXPECT_EQ(2, SimpleInvoke(lib, "main"));
366
367 // Library debuggability is preserved.
368 intptr_t new_lib_id = -1;
369 EXPECT_VALID(Dart_LibraryId(lib, &new_lib_id));
370 EXPECT_VALID(Dart_GetLibraryDebuggable(new_lib_id, &debuggable));
371 EXPECT_EQ(false, debuggable);
372 }
373
374
375 TEST_CASE(IsolateReload_ImplicitConstructorChanged) {
376 // Note that we are checking that the value 20 gets cleared from the
377 // compile-time constants cache. To make this test work, "20" and
378 // "10" need to be at the same token position.
379 const char* kScript =
380 "class A {\n"
381 " int field = 20;\n"
382 "}\n"
383 "var savedA = new A();\n"
384 "main() {\n"
385 " var newA = new A();\n"
386 " return 'saved:${savedA.field} new:${newA.field}';\n"
387 "}\n";
388
389 Dart_Handle lib = TestCase::LoadTestScript(kScript, NULL);
390 EXPECT_VALID(lib);
391
392 EXPECT_STREQ("saved:20 new:20", SimpleInvokeStr(lib, "main"));
393
394 const char* kReloadScript =
395 "class A {\n"
396 " int field = 10;\n"
397 "}\n"
398 "var savedA = new A();\n"
399 "main() {\n"
400 " var newA = new A();\n"
401 " return 'saved:${savedA.field} new:${newA.field}';\n"
402 "}\n";
403
404 lib = TestCase::ReloadTestScript(kReloadScript);
405 EXPECT_VALID(lib);
406
407 EXPECT_STREQ("saved:20 new:10", SimpleInvokeStr(lib, "main"));
408 }
409
410
411 TEST_CASE(IsolateReload_ConstructorChanged) {
412 const char* kScript =
413 "class A {\n"
414 " int field;\n"
415 " A() { field = 20; }\n"
416 "}\n"
417 "var savedA = new A();\n"
418 "main() {\n"
419 " var newA = new A();\n"
420 " return 'saved:${savedA.field} new:${newA.field}';\n"
421 "}\n";
422
423 Dart_Handle lib = TestCase::LoadTestScript(kScript, NULL);
424 EXPECT_VALID(lib);
425
426 EXPECT_STREQ("saved:20 new:20", SimpleInvokeStr(lib, "main"));
427
428 const char* kReloadScript =
429 "var _unused;"
430 "class A {\n"
431 " int field;\n"
432 " A() { field = 10; }\n"
433 "}\n"
434 "var savedA = new A();\n"
435 "main() {\n"
436 " var newA = new A();\n"
437 " return 'saved:${savedA.field} new:${newA.field}';\n"
438 "}\n";
439
440 lib = TestCase::ReloadTestScript(kReloadScript);
441 EXPECT_VALID(lib);
442
443 EXPECT_STREQ("saved:20 new:10", SimpleInvokeStr(lib, "main"));
444 }
445
446
447 TEST_CASE(IsolateReload_SuperClassChanged) {
448 const char* kScript =
449 "class A {\n"
450 "}\n"
451 "class B extends A {\n"
452 "}\n"
453 "var list = [ new A(), new B() ];\n"
454 "main() {\n"
455 " return (list.map((x) => '${x is A}/${x is B}')).toString();\n"
456 "}\n";
457
458 Dart_Handle lib = TestCase::LoadTestScript(kScript, NULL);
459 EXPECT_VALID(lib);
460
461 EXPECT_STREQ("(true/false, true/true)", SimpleInvokeStr(lib, "main"));
462
463 const char* kReloadScript =
464 "var _unused;"
465 "class B{\n"
466 "}\n"
467 "class A extends B {\n"
468 "}\n"
469 "var list = [ new A(), new B() ];\n"
470 "main() {\n"
471 " return (list.map((x) => '${x is A}/${x is B}')).toString();\n"
472 "}\n";
473
474 lib = TestCase::ReloadTestScript(kReloadScript);
475 EXPECT_VALID(lib);
476
477 EXPECT_STREQ("(true/true, false/true)", SimpleInvokeStr(lib, "main"));
478 }
479
480
481 TEST_CASE(IsolateReload_Generics) {
482 // Reload a program with generics without changing the source. We
483 // do this to produce duplication TypeArguments and make sure that
484 // the system doesn't die.
485 const char* kScript =
486 "class A {\n"
487 "}\n"
488 "class B<T extends A> {\n"
489 "}\n"
490 "main() {\n"
491 " return new B<A>().toString();\n"
492 "}\n";
493
494 Dart_Handle lib = TestCase::LoadTestScript(kScript, NULL);
495 EXPECT_VALID(lib);
496
497 EXPECT_STREQ("Instance of 'B<A>'", SimpleInvokeStr(lib, "main"));
498
499 const char* kReloadScript =
500 "class A {\n"
501 "}\n"
502 "class B<T extends A> {\n"
503 "}\n"
504 "main() {\n"
505 " return new B<A>().toString();\n"
506 "}\n";
507
508 lib = TestCase::ReloadTestScript(kReloadScript);
509 EXPECT_VALID(lib);
510
511 EXPECT_STREQ("Instance of 'B<A>'", SimpleInvokeStr(lib, "main"));
512 }
513
514
515 TEST_CASE(IsolateReload_MixinChanged) {
516 const char* kScript =
517 "class Mixin1 {\n"
518 " var field = 'mixin1';\n"
519 " func() => 'mixin1';\n"
520 "}\n"
521 "class B extends Object with Mixin1 {\n"
522 "}\n"
523 "var saved = new B();\n"
524 "main() {\n"
525 " return 'saved:field=${saved.field},func=${saved.func()}';\n"
526 "}\n";
527
528 Dart_Handle lib = TestCase::LoadTestScript(kScript, NULL);
529 EXPECT_VALID(lib);
530
531 EXPECT_STREQ("saved:field=mixin1,func=mixin1",
532 SimpleInvokeStr(lib, "main"));
533
534 const char* kReloadScript =
535 "class Mixin2 {\n"
536 " var field = 'mixin2';\n"
537 " func() => 'mixin2';\n"
538 "}\n"
539 "class B extends Object with Mixin2 {\n"
540 "}\n"
541 "var saved = new B();\n"
542 "main() {\n"
543 " var newer = new B();\n"
544 " return 'saved:field=${saved.field},func=${saved.func()} '\n"
545 " 'newer:field=${newer.field},func=${newer.func()}';\n"
546 "}\n";
547
548 lib = TestCase::ReloadTestScript(kReloadScript);
549 EXPECT_VALID(lib);
550
551 // The saved instance of B retains its old field value from mixin1,
552 // but it gets the new implementation of func from mixin2.
553 EXPECT_STREQ("saved:field=mixin1,func=mixin2 "
554 "newer:field=mixin2,func=mixin2",
555 SimpleInvokeStr(lib, "main"));
556 }
557
558
559 TEST_CASE(IsolateReload_ComplexInheritanceChange) {
560 const char* kScript =
561 "class A {\n"
562 " String name;\n"
563 " A(this.name);\n"
564 "}\n"
565 "class B extends A {\n"
566 " B(name) : super(name);\n"
567 "}\n"
568 "class C extends B {\n"
569 " C(name) : super(name);\n"
570 "}\n"
571 "var list = [ new A('a'), new B('b'), new C('c') ];\n"
572 "main() {\n"
573 " return (list.map((x) {\n"
574 " return '${x.name} is A(${x is A})/ B(${x is B})/ C(${x is C})';\n"
575 " })).toString();\n"
576 "}\n";
577
578 Dart_Handle lib = TestCase::LoadTestScript(kScript, NULL);
579 EXPECT_VALID(lib);
580
581 EXPECT_STREQ("(a is A(true)/ B(false)/ C(false),"
582 " b is A(true)/ B(true)/ C(false),"
583 " c is A(true)/ B(true)/ C(true))",
584 SimpleInvokeStr(lib, "main"));
585
586 const char* kReloadScript =
587 "class C {\n"
588 " String name;\n"
589 " C(this.name);\n"
590 "}\n"
591 "class X extends C {\n"
592 " X(name) : super(name);\n"
593 "}\n"
594 "class A extends X {\n"
595 " A(name) : super(name);\n"
596 "}\n"
597 "var list;\n"
598 "main() {\n"
599 " list.add(new X('x'));\n"
600 " return (list.map((x) {\n"
601 " return '${x.name} is A(${x is A})/ C(${x is C})/ X(${x is X})';\n"
602 " })).toString();\n"
603 "}\n";
604
605 lib = TestCase::ReloadTestScript(kReloadScript);
606 EXPECT_VALID(lib);
607
608 EXPECT_STREQ("(a is A(true)/ C(true)/ X(true),"
609 " b is A(true)/ C(true)/ X(true)," // still extends A...
610 " c is A(false)/ C(true)/ X(false),"
611 " x is A(false)/ C(true)/ X(true))",
612 SimpleInvokeStr(lib, "main"));
613
614 // Revive the class B and make sure all allocated instances take
615 // their place in the inheritance hierarchy.
616 const char* kReloadScript2 =
617 "class X {\n"
618 " String name;\n"
619 " X(this.name);\n"
620 "}\n"
621 "class A extends X{\n"
622 " A(name) : super(name);\n"
623 "}\n"
624 "class B extends X {\n"
625 " B(name) : super(name);\n"
626 "}\n"
627 "class C extends A {\n"
628 " C(name) : super(name);\n"
629 "}\n"
630 "var list;\n"
631 "main() {\n"
632 " return (list.map((x) {\n"
633 " return '${x.name} is '\n"
634 " 'A(${x is A})/ B(${x is B})/ C(${x is C})/ X(${x is X})';\n"
635 " })).toString();\n"
636 "}\n";
637
638 lib = TestCase::ReloadTestScript(kReloadScript2);
639 EXPECT_VALID(lib);
640
641 EXPECT_STREQ("(a is A(true)/ B(false)/ C(false)/ X(true),"
642 " b is A(false)/ B(true)/ C(false)/ X(true),"
643 " c is A(true)/ B(false)/ C(true)/ X(true),"
644 " x is A(false)/ B(false)/ C(false)/ X(true))",
645 SimpleInvokeStr(lib, "main"));
646 }
647
648
649 TEST_CASE(IsolateReload_LiveStack) {
650 const char* kScript =
651 "import 'isolate_reload_test_helper';\n"
652 "helper() => 7;\n"
653 "alpha() { var x = helper(); reloadTest(); return x + helper(); }\n"
654 "foo() => alpha();\n"
655 "bar() => foo();\n"
656 "main() {\n"
657 " return bar();\n"
658 "}\n";
659
660 Dart_Handle lib = TestCase::LoadTestScript(kScript, NULL);
661 EXPECT_VALID(lib);
662
663 const char* kReloadScript =
664 "import 'isolate_reload_test_helper';\n"
665 "helper() => 100;\n"
666 "alpha() => 5 + helper();\n"
667 "foo() => alpha();\n"
668 "bar() => foo();\n"
669 "main() {\n"
670 " return bar();\n"
671 "}\n";
672
673 TestCase::SetReloadTestScript(kReloadScript);
674
675 EXPECT_EQ(107, SimpleInvoke(lib, "main"));
676
677 lib = TestCase::GetReloadErrorOrRootLibrary();
678 EXPECT_VALID(lib);
679
680 EXPECT_EQ(105, SimpleInvoke(lib, "main"));
681 }
682
683
684 TEST_CASE(IsolateReload_LibraryLookup) {
685 const char* kScript =
686 "main() {\n"
687 " return importedFunc();\n"
688 "}\n";
689
690 Dart_Handle result;
691
692 Dart_Handle lib = TestCase::LoadTestScript(kScript, NULL);
693 EXPECT_VALID(lib);
694
695 EXPECT_ERROR(SimpleInvokeError(lib, "main"), "importedFunc");
696
697 // Fail to find 'importable_test_lib' in the isolate.
698 result = Dart_LookupLibrary(NewString("importable_test_lib"));
699 EXPECT(Dart_IsError(result));
700
701 const char* kReloadScript =
702 "import 'importable_test_lib';\n"
703 "main() {\n"
704 " return importedFunc();\n"
705 "}\n";
706
707 // Reload and add 'importable_test_lib' to isolate.
708 lib = TestCase::ReloadTestScript(kReloadScript);
709 EXPECT_VALID(lib);
710
711 EXPECT_STREQ("a", SimpleInvokeStr(lib, "main"));
712
713 // Find 'importable_test_lib' in the isolate.
714 result = Dart_LookupLibrary(NewString("importable_test_lib"));
715 EXPECT(Dart_IsLibrary(result));
716
717 // Reload and remove 'dart:math' from isolate.
718 lib = TestCase::ReloadTestScript(kScript);
719 EXPECT_VALID(lib);
720
721 // Fail to find 'importable_test_lib' in the isolate.
722 result = Dart_LookupLibrary(NewString("importable_test_lib"));
723 EXPECT(Dart_IsError(result));
724 }
725
726
727 TEST_CASE(IsolateReload_LibraryHide) {
728 // Import 'importable_test_lib' with importedFunc hidden. Will result in an
729 // error.
730 const char* kScript =
731 "import 'importable_test_lib' hide importedFunc;\n"
732 "main() {\n"
733 " return importedFunc();\n"
734 "}\n";
735
736 // Dart_Handle result;
737
738 Dart_Handle lib = TestCase::LoadTestScript(kScript, NULL);
739 EXPECT_VALID(lib);
740
741 EXPECT_ERROR(SimpleInvokeError(lib, "main"), "importedFunc");
742
743 // Import 'importable_test_lib'.
744 const char* kReloadScript =
745 "import 'importable_test_lib';\n"
746 "main() {\n"
747 " return importedFunc();\n"
748 "}\n";
749
750 lib = TestCase::ReloadTestScript(kReloadScript);
751 EXPECT_VALID(lib);
752
753 EXPECT_STREQ("a", SimpleInvokeStr(lib, "main"));
754 }
755
756
757 TEST_CASE(IsolateReload_LibraryShow) {
758 // Import 'importable_test_lib' with importedIntFunc visible. Will result in
759 // an error when 'main' is invoked.
760 const char* kScript =
761 "import 'importable_test_lib' show importedIntFunc;\n"
762 "main() {\n"
763 " return importedFunc();\n"
764 "}\n"
765 "mainInt() {\n"
766 " return importedIntFunc();\n"
767 "}\n";
768
769
770 Dart_Handle lib = TestCase::LoadTestScript(kScript, NULL);
771 EXPECT_VALID(lib);
772
773 // Works.
774 EXPECT_EQ(4, SimpleInvoke(lib, "mainInt"));
775 // Results in an error.
776 EXPECT_ERROR(SimpleInvokeError(lib, "main"), "importedFunc");
777
778 // Import 'importable_test_lib' with importedFunc visible. Will result in
779 // an error when 'mainInt' is invoked.
780 const char* kReloadScript =
781 "import 'importable_test_lib' show importedFunc;\n"
782 "main() {\n"
783 " return importedFunc();\n"
784 "}\n"
785 "mainInt() {\n"
786 " return importedIntFunc();\n"
787 "}\n";
788
789 lib = TestCase::ReloadTestScript(kReloadScript);
790 EXPECT_VALID(lib);
791
792 // Works.
793 EXPECT_STREQ("a", SimpleInvokeStr(lib, "main"));
794 // Results in an error.
795 EXPECT_ERROR(SimpleInvokeError(lib, "mainInt"), "importedIntFunc");
796 }
797
798
799 // Verifies that we clear the ICs for the functions live on the stack in a way
800 // that is compatible with the fast path smi stubs.
801 TEST_CASE(IsolateReload_SmiFastPathStubs) {
802 const char* kScript =
803 "import 'isolate_reload_test_helper';\n"
804 "import 'importable_test_lib' show importedIntFunc;\n"
805 "main() {\n"
806 " var x = importedIntFunc();\n"
807 " var y = importedIntFunc();\n"
808 " reloadTest();\n"
809 " return x + y;\n"
810 "}\n";
811
812
813 Dart_Handle lib = TestCase::LoadTestScript(kScript, NULL);
814 EXPECT_VALID(lib);
815
816 // Identity reload.
817 TestCase::SetReloadTestScript(kScript);
818
819 EXPECT_EQ(8, SimpleInvoke(lib, "main"));
820 }
821
822
823 // Verifies that we assign the correct patch classes for imported
824 // mixins when we reload.
825 TEST_CASE(IsolateReload_ImportedMixinFunction) {
826 const char* kScript =
827 "import 'importable_test_lib' show ImportedMixin;\n"
828 "class A extends Object with ImportedMixin {\n"
829 "}"
830 "var func = new A().mixinFunc;\n"
831 "main() {\n"
832 " return func();\n"
833 "}\n";
834
835 Dart_Handle lib = TestCase::LoadTestScript(kScript, NULL);
836 EXPECT_VALID(lib);
837
838 EXPECT_STREQ("mixin", SimpleInvokeStr(lib, "main"));
839
840 const char* kReloadScript =
841 "import 'importable_test_lib' show ImportedMixin;\n"
842 "class A extends Object with ImportedMixin {\n"
843 "}"
844 "var func;\n"
845 "main() {\n"
846 " return func();\n"
847 "}\n";
848
849 lib = TestCase::ReloadTestScript(kReloadScript);
850 EXPECT_VALID(lib);
851
852 EXPECT_STREQ("mixin", SimpleInvokeStr(lib, "main"));
853 }
854
855
856 TEST_CASE(IsolateReload_TopLevelParseError) {
857 const char* kScript =
858 "main() {\n"
859 " return 4;\n"
860 "}\n";
861
862 Dart_Handle lib = TestCase::LoadTestScript(kScript, NULL);
863 EXPECT_VALID(lib);
864
865 EXPECT_EQ(4, SimpleInvoke(lib, "main"));
866
867 const char* kReloadScript =
868 "kjsadkfjaksldfjklsadf;\n"
869 "main() {\n"
870 " return 4;\n"
871 "}\n";
872
873 lib = TestCase::ReloadTestScript(kReloadScript);
874 EXPECT_ERROR(lib, "unexpected token");
875 }
876
877
878 TEST_CASE(IsolateReload_PendingUnqualifiedCall_StaticToInstance) {
879 const char* kScript =
880 "import 'isolate_reload_test_helper';\n"
881 "class C {\n"
882 " static foo() => 'static';\n"
883 " test() {\n"
884 " reloadTest();\n"
885 " return foo();\n"
886 " }\n"
887 "}\n"
888 "main() {\n"
889 " return new C().test();\n"
890 "}\n";
891
892 Dart_Handle lib = TestCase::LoadTestScript(kScript, NULL);
893 EXPECT_VALID(lib);
894
895 const char* kReloadScript =
896 "import 'isolate_reload_test_helper';\n"
897 "class C {\n"
898 " foo() => 'instance';\n"
899 " test() {\n"
900 " reloadTest();\n"
901 " return foo();\n"
902 " }\n"
903 "}\n"
904 "main() {\n"
905 " return new C().test();\n"
906 "}\n";
907
908 TestCase::SetReloadTestScript(kReloadScript);
909
910 EXPECT_EQ("instance", SimpleInvokeStr(lib, "main"));
911
912 lib = TestCase::GetReloadErrorOrRootLibrary();
913 EXPECT_VALID(lib);
914
915 EXPECT_EQ("instance", SimpleInvokeStr(lib, "main"));
916 }
917
918
919 TEST_CASE(IsolateReload_PendingUnqualifiedCall_InstanceToStatic) {
920 const char* kScript =
921 "import 'isolate_reload_test_helper';\n"
922 "class C {\n"
923 " foo() => 'instance';\n"
924 " test() {\n"
925 " reloadTest();\n"
926 " return foo();\n"
927 " }\n"
928 "}\n"
929 "main() {\n"
930 " return new C().test();\n"
931 "}\n";
932
933 Dart_Handle lib = TestCase::LoadTestScript(kScript, NULL);
934 EXPECT_VALID(lib);
935
936 const char* kReloadScript =
937 "import 'isolate_reload_test_helper';\n"
938 "class C {\n"
939 " static foo() => 'static';\n"
940 " test() {\n"
941 " reloadTest();\n"
942 " return foo();\n"
943 " }\n"
944 "}\n"
945 "main() {\n"
946 " return new C().test();\n"
947 "}\n";
948
949 TestCase::SetReloadTestScript(kReloadScript);
950
951 EXPECT_EQ("static", SimpleInvokeStr(lib, "main"));
952
953 lib = TestCase::GetReloadErrorOrRootLibrary();
954 EXPECT_VALID(lib);
955
956 EXPECT_EQ("static", SimpleInvokeStr(lib, "main"));
957 }
958
959
960 TEST_CASE(IsolateReload_PendingConstructorCall_AbstractToConcrete) {
961 const char* kScript =
962 "import 'isolate_reload_test_helper';\n"
963 "abstract class Foo {}\n"
964 "class C {\n"
965 " test() {\n"
966 " reloadTest();\n"
967 " return new Foo();\n"
968 " }\n"
969 "}\n"
970 "main() {\n"
971 " try {\n"
972 " new C().test();\n"
973 " return 'okay';\n"
974 " } catch (e) {\n"
975 " return 'exception';\n"
976 " }\n"
977 "}\n";
978
979 Dart_Handle lib = TestCase::LoadTestScript(kScript, NULL);
980 EXPECT_VALID(lib);
981
982 const char* kReloadScript =
983 "import 'isolate_reload_test_helper';\n"
984 "class Foo {}\n"
985 "class C {\n"
986 " test() {\n"
987 " reloadTest();\n"
988 " return new Foo();\n"
989 " }\n"
990 "}\n"
991 "main() {\n"
992 " try {\n"
993 " new C().test();\n"
994 " return 'okay';\n"
995 " } catch (e) {\n"
996 " return 'exception';\n"
997 " }\n"
998 "}\n";
999
1000 TestCase::SetReloadTestScript(kReloadScript);
1001
1002 EXPECT_EQ("okay", SimpleInvokeStr(lib, "main"));
1003
1004 lib = TestCase::GetReloadErrorOrRootLibrary();
1005 EXPECT_VALID(lib);
1006
1007 EXPECT_EQ("okay", SimpleInvokeStr(lib, "main"));
1008 }
1009
1010
1011 TEST_CASE(IsolateReload_PendingConstructorCall_ConcreteToAbstract) {
1012 const char* kScript =
1013 "import 'isolate_reload_test_helper';\n"
1014 "class Foo {}\n"
1015 "class C {\n"
1016 " test() {\n"
1017 " reloadTest();\n"
1018 " return new Foo();\n"
1019 " }\n"
1020 "}\n"
1021 "main() {\n"
1022 " try {\n"
1023 " new C().test();\n"
1024 " return 'okay';\n"
1025 " } catch (e) {\n"
1026 " return 'exception';\n"
1027 " }\n"
1028 "}\n";
1029
1030 Dart_Handle lib = TestCase::LoadTestScript(kScript, NULL);
1031 EXPECT_VALID(lib);
1032
1033 const char* kReloadScript =
1034 "import 'isolate_reload_test_helper';\n"
1035 "abstract class Foo {}\n"
1036 "class C {\n"
1037 " test() {\n"
1038 " reloadTest();\n"
1039 " return new Foo();\n"
1040 " }\n"
1041 "}\n"
1042 "main() {\n"
1043 " try {\n"
1044 " new C().test();\n"
1045 " return 'okay';\n"
1046 " } catch (e) {\n"
1047 " return 'exception';\n"
1048 " }\n"
1049 "}\n";
1050
1051 TestCase::SetReloadTestScript(kReloadScript);
1052
1053 EXPECT_EQ("exception", SimpleInvokeStr(lib, "main"));
1054
1055 lib = TestCase::GetReloadErrorOrRootLibrary();
1056 EXPECT_VALID(lib);
1057
1058 EXPECT_EQ("exception", SimpleInvokeStr(lib, "main"));
1059 }
1060
1061
1062 TEST_CASE(IsolateReload_PendingStaticCall_DefinedToNSM) {
1063 const char* kScript =
1064 "import 'isolate_reload_test_helper';\n"
1065 "class C {\n"
1066 " static foo() => 'static'\n"
1067 " test() {\n"
1068 " reloadTest();\n"
1069 " return C.foo();\n"
1070 " }\n"
1071 "}\n"
1072 "main() {\n"
1073 " try {\n"
1074 " return new C().test();\n"
1075 " } catch (e) {\n"
1076 " return 'exception';\n"
1077 " }\n"
1078 "}\n";
1079
1080 Dart_Handle lib = TestCase::LoadTestScript(kScript, NULL);
1081 EXPECT_VALID(lib);
1082
1083 const char* kReloadScript =
1084 "import 'isolate_reload_test_helper';\n"
1085 "class C {\n"
1086 " test() {\n"
1087 " reloadTest();\n"
1088 " return C.foo();\n"
1089 " }\n"
1090 "}\n"
1091 "main() {\n"
1092 " try {\n"
1093 " return new C().test();\n"
1094 " } catch (e) {\n"
1095 " return 'exception';\n"
1096 " }\n"
1097 "}\n";
1098
1099 TestCase::SetReloadTestScript(kReloadScript);
1100
1101 EXPECT_EQ("exception", SimpleInvokeStr(lib, "main"));
1102
1103 lib = TestCase::GetReloadErrorOrRootLibrary();
1104 EXPECT_VALID(lib);
1105
1106 EXPECT_EQ("exception", SimpleInvokeStr(lib, "main"));
1107 }
1108
1109
1110 TEST_CASE(IsolateReload_PendingStaticCall_NSMToDefined) {
1111 const char* kScript =
1112 "import 'isolate_reload_test_helper';\n"
1113 "class C {\n"
1114 " test() {\n"
1115 " reloadTest();\n"
1116 " return C.foo();\n"
1117 " }\n"
1118 "}\n"
1119 "main() {\n"
1120 " try {\n"
1121 " return new C().test();\n"
1122 " } catch (e) {\n"
1123 " return 'exception';\n"
1124 " }\n"
1125 "}\n";
1126
1127 Dart_Handle lib = TestCase::LoadTestScript(kScript, NULL);
1128 EXPECT_VALID(lib);
1129
1130 const char* kReloadScript =
1131 "import 'isolate_reload_test_helper';\n"
1132 "class C {\n"
1133 " static foo() => 'static'\n"
1134 " test() {\n"
1135 " reloadTest();\n"
1136 " return C.foo();\n"
1137 " }\n"
1138 "}\n"
1139 "main() {\n"
1140 " try {\n"
1141 " return new C().test();\n"
1142 " } catch (e) {\n"
1143 " return 'exception';\n"
1144 " }\n"
1145 "}\n";
1146
1147 TestCase::SetReloadTestScript(kReloadScript);
1148
1149 EXPECT_EQ("static", SimpleInvokeStr(lib, "main"));
1150
1151 lib = TestCase::GetReloadErrorOrRootLibrary();
1152 EXPECT_VALID(lib);
1153
1154 EXPECT_EQ("static", SimpleInvokeStr(lib, "main"));
1155 }
1156
1157
1158 TEST_CASE(IsolateReload_EnumEquality) {
1159 const char* kScript =
1160 "enum Fruit {\n"
1161 " Apple,\n"
1162 " Banana,\n"
1163 "}\n"
1164 "var x;\n"
1165 "main() {\n"
1166 " x = Fruit.Banana;\n"
1167 " return Fruit.Apple.toString();\n"
1168 "}\n";
1169
1170 Dart_Handle lib = TestCase::LoadTestScript(kScript, NULL);
1171 EXPECT_VALID(lib);
1172
1173 EXPECT_STREQ("Fruit.Apple", SimpleInvokeStr(lib, "main"));
1174
1175 const char* kReloadScript =
1176 "enum Fruit {\n"
1177 " Apple,\n"
1178 " Banana,\n"
1179 "}\n"
1180 "var x;\n"
1181 "main() {\n"
1182 " if (x == Fruit.Banana) {\n"
1183 " return 'yes';\n"
1184 " } else {\n"
1185 " return 'no';\n"
1186 " }\n"
1187 "}\n";
1188
1189 lib = TestCase::ReloadTestScript(kReloadScript);
1190 EXPECT_VALID(lib);
1191
1192 EXPECT_STREQ("yes", SimpleInvokeStr(lib, "main"));
1193 }
1194
1195
1196 TEST_CASE(IsolateReload_EnumIdentical) {
1197 const char* kScript =
1198 "enum Fruit {\n"
1199 " Apple,\n"
1200 " Banana,\n"
1201 "}\n"
1202 "var x;\n"
1203 "main() {\n"
1204 " x = Fruit.Banana;\n"
1205 " return Fruit.Apple.toString();\n"
1206 "}\n";
1207
1208 Dart_Handle lib = TestCase::LoadTestScript(kScript, NULL);
1209 EXPECT_VALID(lib);
1210
1211 EXPECT_STREQ("Fruit.Apple", SimpleInvokeStr(lib, "main"));
1212
1213 const char* kReloadScript =
1214 "enum Fruit {\n"
1215 " Apple,\n"
1216 " Banana,\n"
1217 "}\n"
1218 "var x;\n"
1219 "main() {\n"
1220 " if (identical(x, Fruit.Banana)) {\n"
1221 " return 'yes';\n"
1222 " } else {\n"
1223 " return 'no';\n"
1224 " }\n"
1225 "}\n";
1226
1227 lib = TestCase::ReloadTestScript(kReloadScript);
1228 EXPECT_VALID(lib);
1229
1230 EXPECT_STREQ("yes", SimpleInvokeStr(lib, "main"));
1231 }
1232
1233
1234 TEST_CASE(IsolateReload_EnumReorderIdentical) {
1235 const char* kScript =
1236 "enum Fruit {\n"
1237 " Apple,\n"
1238 " Banana,\n"
1239 "}\n"
1240 "var x;\n"
1241 "main() {\n"
1242 " x = Fruit.Banana;\n"
1243 " return Fruit.Apple.toString();\n"
1244 "}\n";
1245
1246 Dart_Handle lib = TestCase::LoadTestScript(kScript, NULL);
1247 EXPECT_VALID(lib);
1248
1249 EXPECT_STREQ("Fruit.Apple", SimpleInvokeStr(lib, "main"));
1250
1251 const char* kReloadScript =
1252 "enum Fruit {\n"
1253 " Banana,\n"
1254 " Apple,\n"
1255 "}\n"
1256 "var x;\n"
1257 "main() {\n"
1258 " if (identical(x, Fruit.Banana)) {\n"
1259 " return 'yes';\n"
1260 " } else {\n"
1261 " return 'no';\n"
1262 " }\n"
1263 "}\n";
1264
1265 lib = TestCase::ReloadTestScript(kReloadScript);
1266 EXPECT_VALID(lib);
1267
1268 EXPECT_STREQ("yes", SimpleInvokeStr(lib, "main"));
1269 }
1270
1271
1272 TEST_CASE(IsolateReload_EnumAddition) {
1273 const char* kScript =
1274 "enum Fruit {\n"
1275 " Apple,\n"
1276 " Banana,\n"
1277 "}\n"
1278 "var x;\n"
1279 "main() {\n"
1280 " return Fruit.Apple.toString();\n"
1281 "}\n";
1282
1283 Dart_Handle lib = TestCase::LoadTestScript(kScript, NULL);
1284 EXPECT_VALID(lib);
1285
1286 EXPECT_STREQ("Fruit.Apple", SimpleInvokeStr(lib, "main"));
1287
1288 const char* kReloadScript =
1289 "enum Fruit {\n"
1290 " Apple,\n"
1291 " Cantalope,\n"
1292 " Banana,\n"
1293 "}\n"
1294 "var x;\n"
1295 "main() {\n"
1296 " String r = '${Fruit.Apple.index}/${Fruit.Apple} ';\n"
1297 " r += '${Fruit.Cantalope.index}/${Fruit.Cantalope} ';\n"
1298 " r += '${Fruit.Banana.index}/${Fruit.Banana}';\n"
1299 " return r;\n"
1300 "}\n";
1301
1302 lib = TestCase::ReloadTestScript(kReloadScript);
1303 EXPECT_VALID(lib);
1304
1305 EXPECT_STREQ("0/Fruit.Apple 1/Fruit.Cantalope 2/Fruit.Banana",
1306 SimpleInvokeStr(lib, "main"));
1307 }
1308
1309
1310 TEST_CASE(IsolateReload_EnumToNotEnum) {
1311 const char* kScript =
1312 "enum Fruit {\n"
1313 " Apple\n"
1314 "}\n"
1315 "main() {\n"
1316 " return Fruit.Apple.toString();\n"
1317 "}\n";
1318
1319 Dart_Handle lib = TestCase::LoadTestScript(kScript, NULL);
1320 EXPECT_VALID(lib);
1321
1322 EXPECT_STREQ("Fruit.Apple", SimpleInvokeStr(lib, "main"));
1323
1324 const char* kReloadScript =
1325 "class Fruit {\n"
1326 " final int zero = 0;\n"
1327 "}\n"
1328 "main() {\n"
1329 "}\n";
1330
1331 Dart_Handle result = TestCase::ReloadTestScript(kReloadScript);
1332 EXPECT_ERROR(result, "Enum class cannot be redefined to be a non-enum class");
1333 }
1334
1335
1336 TEST_CASE(IsolateReload_NotEnumToEnum) {
1337 const char* kScript =
1338 "class Fruit {\n"
1339 " final int zero = 0;\n"
1340 "}\n"
1341 "main() {\n"
1342 " return 'yes';\n"
1343 "}\n";
1344
1345 Dart_Handle lib = TestCase::LoadTestScript(kScript, NULL);
1346 EXPECT_VALID(lib);
1347
1348 EXPECT_STREQ("yes", SimpleInvokeStr(lib, "main"));
1349
1350 const char* kReloadScript =
1351 "enum Fruit {\n"
1352 " Apple\n"
1353 "}\n"
1354 "main() {\n"
1355 " return Fruit.Apple.toString();\n"
1356 "}\n";
1357
1358 Dart_Handle result = TestCase::ReloadTestScript(kReloadScript);
1359 EXPECT_ERROR(result, "Class cannot be redefined to be a enum class");
1360 }
1361
1362
1363 TEST_CASE(IsolateReload_EnumDelete) {
1364 const char* kScript =
1365 "enum Fruit {\n"
1366 " Apple,\n"
1367 " Banana,\n"
1368 " Cantalope,\n"
1369 "}\n"
1370 "var x;\n"
1371 "main() {\n"
1372 " return Fruit.Apple.toString();\n"
1373 "}\n";
1374
1375 Dart_Handle lib = TestCase::LoadTestScript(kScript, NULL);
1376 EXPECT_VALID(lib);
1377
1378 EXPECT_STREQ("Fruit.Apple", SimpleInvokeStr(lib, "main"));
1379
1380 // Delete 'Cantalope'.
1381
1382 const char* kReloadScript =
1383 "enum Fruit {\n"
1384 " Apple,\n"
1385 " Banana,\n"
1386 "}\n"
1387 "var x;\n"
1388 "main() {\n"
1389 " String r = '${Fruit.Apple.index}/${Fruit.Apple} ';\n"
1390 " r += '${Fruit.Banana.index}/${Fruit.Banana} ';\n"
1391 " r += '${Fruit.Cantalope.index}/${Fruit.Cantalope}';\n"
1392 " return r;\n"
1393 "}\n";
1394
1395 lib = TestCase::ReloadTestScript(kReloadScript);
1396 EXPECT_VALID(lib);
1397
1398 EXPECT_STREQ("0/Fruit.Apple 1/Fruit.Banana 2/Fruit.Cantalope",
1399 SimpleInvokeStr(lib, "main"));
1400 }
1401
1402
1403 TEST_CASE(IsolateReload_EnumComplex) {
1404 const char* kScript =
1405 "enum Fruit {\n"
1406 " Apple,\n"
1407 " Banana,\n"
1408 " Cantalope,\n"
1409 "}\n"
1410 "var x;\n"
1411 "var y;\n"
1412 "var z;\n"
1413 "main() {\n"
1414 " x = Fruit.Apple;\n"
1415 " y = Fruit.Banana;\n"
1416 " z = Fruit.Cantalope;\n"
1417 " return Fruit.Apple.toString();\n"
1418 "}\n";
1419
1420 Dart_Handle lib = TestCase::LoadTestScript(kScript, NULL);
1421 EXPECT_VALID(lib);
1422
1423 EXPECT_STREQ("Fruit.Apple", SimpleInvokeStr(lib, "main"));
1424
1425 // Delete 'Cantalope'. Add 'Dragon'. Move 'Apple' and 'Banana'.
1426
1427 const char* kReloadScript =
1428 "enum Fruit {\n"
1429 " Dragon,\n"
1430 " Apple,\n"
1431 " Banana,\n"
1432 "}\n"
1433 "var x;\n"
1434 "var y;\n"
1435 "var z;\n"
1436 "main() {\n"
1437 " String r = '';\n"
1438 " r += '${identical(x, Fruit.Apple)}';\n"
1439 " r += ' ${identical(y, Fruit.Banana)}';\n"
1440 " r += ' ${identical(z, Fruit.Cantalope)}';\n"
1441 " r += ' ${Fruit.Dragon}';\n"
1442 " return r;\n"
1443 "}\n";
1444
1445 lib = TestCase::ReloadTestScript(kReloadScript);
1446 EXPECT_VALID(lib);
1447
1448 EXPECT_STREQ("true true true Fruit.Dragon", SimpleInvokeStr(lib, "main"));
1449 }
1450
1451
1452 TEST_CASE(IsolateReload_EnumValuesArray) {
1453 const char* kScript =
1454 "enum Fruit {\n"
1455 " Cantalope,\n"
1456 " Apple,\n"
1457 " Banana,\n"
1458 "}\n"
1459 "var x;\n"
1460 "main() {\n"
1461 " x = Fruit.Cantalope;\n"
1462 " return Fruit.Apple.toString();\n"
1463 "}\n";
1464
1465 Dart_Handle lib = TestCase::LoadTestScript(kScript, NULL);
1466 EXPECT_VALID(lib);
1467
1468 EXPECT_STREQ("Fruit.Apple", SimpleInvokeStr(lib, "main"));
1469
1470 // Delete 'Cantalope'.
1471
1472 const char* kReloadScript =
1473 "enum Fruit {\n"
1474 " Banana,\n"
1475 " Apple\n"
1476 "}\n"
1477 "var x;\n"
1478 "bool identityCheck(Fruit f) {\n"
1479 " return identical(Fruit.values[f.index], f);\n"
1480 "}\n"
1481 "main() {\n"
1482 " if ((x is Fruit) && identical(x, Fruit.Cantalope)) {\n"
1483 " String r = '${identityCheck(Fruit.Apple)}';\n"
1484 " r += ' ${identityCheck(Fruit.Banana)}';\n"
1485 " r += ' ${identityCheck(Fruit.Cantalope)}';\n"
1486 " r += ' ${identityCheck(x)}';\n"
1487 " return r;\n"
1488 " }\n"
1489 "}\n";
1490
1491 lib = TestCase::ReloadTestScript(kReloadScript);
1492 EXPECT_VALID(lib);
1493
1494 EXPECT_STREQ("true true true true",
1495 SimpleInvokeStr(lib, "main"));
1496 }
1497
1498
1499 TEST_CASE(IsolateReload_EnumIdentityReload) {
1500 const char* kScript =
1501 "enum Fruit {\n"
1502 " Apple,\n"
1503 " Banana,\n"
1504 " Cantalope,\n"
1505 "}\n"
1506 "var x;\n"
1507 "var y;\n"
1508 "var z;\n"
1509 "var w;\n"
1510 "main() {\n"
1511 " x = { Fruit.Apple: Fruit.Apple.index,\n"
1512 " Fruit.Banana: Fruit.Banana.index,\n"
1513 " Fruit.Cantalope: Fruit.Cantalope.index};\n"
1514 " y = Fruit.Apple;\n"
1515 " z = Fruit.Banana;\n"
1516 " w = Fruit.Cantalope;\n"
1517 " return Fruit.Apple.toString();\n"
1518 "}\n";
1519
1520 Dart_Handle lib = TestCase::LoadTestScript(kScript, NULL);
1521 EXPECT_VALID(lib);
1522
1523 EXPECT_STREQ("Fruit.Apple", SimpleInvokeStr(lib, "main"));
1524
1525 const char* kReloadScript =
1526 "enum Fruit {\n"
1527 " Apple,\n"
1528 " Banana,\n"
1529 " Cantalope,\n"
1530 "}\n"
1531 "var x;\n"
1532 "var y;\n"
1533 "var z;\n"
1534 "var w;\n"
1535 "bool identityCheck(Fruit f, int index) {\n"
1536 " return identical(Fruit.values[index], f);\n"
1537 "}\n"
1538 "main() {\n"
1539 " String r = '';\n"
1540 " x.forEach((key, value) {\n"
1541 " r += '${identityCheck(key, value)} ';\n"
1542 " });\n"
1543 " r += '${x[Fruit.Apple] == Fruit.Apple.index} ';\n"
1544 " r += '${x[Fruit.Banana] == Fruit.Banana.index} ';\n"
1545 " r += '${x[Fruit.Cantalope] == Fruit.Cantalope.index} ';\n"
1546 " r += '${identical(y, Fruit.values[x[Fruit.Apple]])} ';\n"
1547 " r += '${identical(z, Fruit.values[x[Fruit.Banana]])} ';\n"
1548 " r += '${identical(w, Fruit.values[x[Fruit.Cantalope]])} ';\n"
1549 " return r;\n"
1550 "}\n";
1551
1552 lib = TestCase::ReloadTestScript(kReloadScript);
1553 EXPECT_VALID(lib);
1554
1555 EXPECT_STREQ("true true true true true true true true true ",
1556 SimpleInvokeStr(lib, "main"));
1557 }
1558
1559
1560 TEST_CASE(IsolateReload_ConstantIdentical) {
1561 const char* kScript =
1562 "class Fruit {\n"
1563 " final String name;\n"
1564 " const Fruit(this.name);\n"
1565 " String toString() => name;\n"
1566 "}\n"
1567 "var x;\n"
1568 "main() {\n"
1569 " x = const Fruit('Pear');\n"
1570 " return x.toString();\n"
1571 "}\n";
1572
1573 Dart_Handle lib = TestCase::LoadTestScript(kScript, NULL);
1574 EXPECT_VALID(lib);
1575
1576 EXPECT_STREQ("Pear", SimpleInvokeStr(lib, "main"));
1577
1578 const char* kReloadScript =
1579 "class Fruit {\n"
1580 " final String name;\n"
1581 " const Fruit(this.name);\n"
1582 " String toString() => name;\n"
1583 "}\n"
1584 "var x;\n"
1585 "main() {\n"
1586 " if (identical(x, const Fruit('Pear'))) {\n"
1587 " return 'yes';\n"
1588 " } else {\n"
1589 " return 'no';\n"
1590 " }\n"
1591 "}\n";
1592
1593 lib = TestCase::ReloadTestScript(kReloadScript);
1594 EXPECT_VALID(lib);
1595
1596 EXPECT_STREQ("yes", SimpleInvokeStr(lib, "main"));
1597 }
1598
1599
1600 TEST_CASE(IsolateReload_EnumValuesToString) {
1601 const char* kScript =
1602 "enum Fruit {\n"
1603 " Apple,\n"
1604 " Banana,\n"
1605 "}\n"
1606 "var x;\n"
1607 "main() {\n"
1608 " String r = '';\n"
1609 " r += Fruit.Apple.toString();\n"
1610 " r += ' ';\n"
1611 " r += Fruit.Banana.toString();\n"
1612 " return r;\n"
1613 "}\n";
1614
1615 Dart_Handle lib = TestCase::LoadTestScript(kScript, NULL);
1616 EXPECT_VALID(lib);
1617
1618 EXPECT_STREQ("Fruit.Apple Fruit.Banana", SimpleInvokeStr(lib, "main"));
1619
1620 // Insert 'Cantalope'.
1621
1622 const char* kReloadScript =
1623 "enum Fruit {\n"
1624 " Apple,\n"
1625 " Cantalope,\n"
1626 " Banana\n"
1627 "}\n"
1628 "var x;\n"
1629 "main() {\n"
1630 " String r = '';\n"
1631 " r += Fruit.Apple.toString();\n"
1632 " r += ' ';\n"
1633 " r += Fruit.Cantalope.toString();\n"
1634 " r += ' ';\n"
1635 " r += Fruit.Banana.toString();\n"
1636 " return r;\n"
1637 "}\n";
1638
1639 lib = TestCase::ReloadTestScript(kReloadScript);
1640 EXPECT_VALID(lib);
1641
1642 EXPECT_STREQ("Fruit.Apple Fruit.Cantalope Fruit.Banana",
1643 SimpleInvokeStr(lib, "main"));
1644 }
1645
1646
1647 TEST_CASE(IsolateReload_DirectSubclasses_Success) {
1648 Object& new_subclass = Object::Handle();
1649 String& name = String::Handle();
1650
1651 // Lookup the Iterator class by name from the dart core library.
1652 ObjectStore* object_store = Isolate::Current()->object_store();
1653 const Library& core_lib = Library::Handle(object_store->core_library());
1654 name = String::New("Iterator");
1655 const Class& iterator_cls = Class::Handle(core_lib.LookupClass(name));
1656
1657 // Keep track of how many subclasses an Iterator has.
1658 const GrowableObjectArray& subclasses =
1659 GrowableObjectArray::Handle(iterator_cls.direct_subclasses());
1660 intptr_t saved_subclass_count = subclasses.Length();
1661
1662 const char* kScript =
1663 "class AIterator extends Iterator {\n"
1664 "}\n"
1665 "main() {\n"
1666 " return 1;\n"
1667 "}\n";
1668
1669 Dart_Handle lib = TestCase::LoadTestScript(kScript, NULL);
1670 EXPECT_VALID(lib);
1671 EXPECT_EQ(1, SimpleInvoke(lib, "main"));
1672
1673 // Iterator has one non-core subclass.
1674 EXPECT_EQ(saved_subclass_count + 1, subclasses.Length());
1675
1676 // The new subclass is named AIterator.
1677 new_subclass = subclasses.At(subclasses.Length() - 1);
1678 name = Class::Cast(new_subclass).Name();
1679 EXPECT_STREQ("AIterator", name.ToCString());
1680
1681 const char* kReloadScript =
1682 "class AIterator {\n"
1683 "}\n"
1684 "class BIterator extends Iterator {\n"
1685 "}\n"
1686 "main() {\n"
1687 " return 2;\n"
1688 "}\n";
1689
1690 lib = TestCase::ReloadTestScript(kReloadScript);
1691 EXPECT_VALID(lib);
1692 EXPECT_EQ(2, SimpleInvoke(lib, "main"));
1693
1694 // Iterator still has only one non-core subclass (AIterator is gone).
1695 EXPECT_EQ(saved_subclass_count + 1, subclasses.Length());
1696
1697 // The new subclass is named BIterator.
1698 new_subclass = subclasses.At(subclasses.Length() - 1);
1699 name = Class::Cast(new_subclass).Name();
1700 EXPECT_STREQ("BIterator", name.ToCString());
1701 }
1702
1703
1704 TEST_CASE(IsolateReload_DirectSubclasses_GhostSubclass) {
1705 Object& new_subclass = Object::Handle();
1706 String& name = String::Handle();
1707
1708 // Lookup the Iterator class by name from the dart core library.
1709 ObjectStore* object_store = Isolate::Current()->object_store();
1710 const Library& core_lib = Library::Handle(object_store->core_library());
1711 name = String::New("Iterator");
1712 const Class& iterator_cls = Class::Handle(core_lib.LookupClass(name));
1713
1714 // Keep track of how many subclasses an Iterator has.
1715 const GrowableObjectArray& subclasses =
1716 GrowableObjectArray::Handle(iterator_cls.direct_subclasses());
1717 intptr_t saved_subclass_count = subclasses.Length();
1718
1719 const char* kScript =
1720 "class AIterator extends Iterator {\n"
1721 "}\n"
1722 "main() {\n"
1723 " return 1;\n"
1724 "}\n";
1725
1726 Dart_Handle lib = TestCase::LoadTestScript(kScript, NULL);
1727 EXPECT_VALID(lib);
1728 EXPECT_EQ(1, SimpleInvoke(lib, "main"));
1729
1730 // Iterator has one new subclass.
1731 EXPECT_EQ(saved_subclass_count + 1, subclasses.Length());
1732
1733 // The new subclass is named AIterator.
1734 new_subclass = subclasses.At(subclasses.Length() - 1);
1735 name = Class::Cast(new_subclass).Name();
1736 EXPECT_STREQ("AIterator", name.ToCString());
1737
1738 const char* kReloadScript =
1739 "class BIterator extends Iterator {\n"
1740 "}\n"
1741 "main() {\n"
1742 " return 2;\n"
1743 "}\n";
1744
1745 lib = TestCase::ReloadTestScript(kReloadScript);
1746 EXPECT_VALID(lib);
1747 EXPECT_EQ(2, SimpleInvoke(lib, "main"));
1748
1749 // Iterator has two non-core subclasses.
1750 EXPECT_EQ(saved_subclass_count + 2, subclasses.Length());
1751
1752 // The non-core subclasses are AIterator and BIterator.
1753 new_subclass = subclasses.At(subclasses.Length() - 2);
1754 name = Class::Cast(new_subclass).Name();
1755 EXPECT_STREQ("AIterator", name.ToCString());
1756
1757 new_subclass = subclasses.At(subclasses.Length() - 1);
1758 name = Class::Cast(new_subclass).Name();
1759 EXPECT_STREQ("BIterator", name.ToCString());
1760 }
1761
1762
1763 // Make sure that we restore the direct subclass info when we revert.
1764 TEST_CASE(IsolateReload_DirectSubclasses_Failure) {
1765 Object& new_subclass = Object::Handle();
1766 String& name = String::Handle();
1767
1768 // Lookup the Iterator class by name from the dart core library.
1769 ObjectStore* object_store = Isolate::Current()->object_store();
1770 const Library& core_lib = Library::Handle(object_store->core_library());
1771 name = String::New("Iterator");
1772 const Class& iterator_cls = Class::Handle(core_lib.LookupClass(name));
1773
1774 // Keep track of how many subclasses an Iterator has.
1775 const GrowableObjectArray& subclasses =
1776 GrowableObjectArray::Handle(iterator_cls.direct_subclasses());
1777 intptr_t saved_subclass_count = subclasses.Length();
1778
1779 const char* kScript =
1780 "class AIterator extends Iterator {\n"
1781 "}\n"
1782 "class Foo {\n"
1783 " final a;\n"
1784 " Foo(this.a);\n"
1785 "}\n"
1786 "main() {\n"
1787 " new Foo(5);\n" // Force Foo to be finalized.
1788 " return 1;\n"
1789 "}\n";
1790
1791 Dart_Handle lib = TestCase::LoadTestScript(kScript, NULL);
1792 EXPECT_VALID(lib);
1793 EXPECT_EQ(1, SimpleInvoke(lib, "main"));
1794
1795 // Iterator has one non-core subclass...
1796 EXPECT_EQ(saved_subclass_count + 1, subclasses.Length());
1797
1798 // ... and the non-core subclass is named AIterator.
1799 new_subclass = subclasses.At(subclasses.Length() - 1);
1800 name = Class::Cast(new_subclass).Name();
1801 EXPECT_STREQ("AIterator", name.ToCString());
1802
1803 // Attempt to reload with a bogus script.
1804 const char* kReloadScript =
1805 "class BIterator extends Iterator {\n"
1806 "}\n"
1807 "class Foo {\n"
1808 " final a kjsdf ksjdf ;\n" // When we refinalize, we get an error.
1809 " Foo(this.a);\n"
1810 "}\n"
1811 "main() {\n"
1812 " new Foo(5);\n"
1813 " return 2;\n"
1814 "}\n";
1815
1816 lib = TestCase::ReloadTestScript(kReloadScript);
1817 EXPECT_ERROR(lib, "unexpected token");
1818
1819 // If we don't clean up the subclasses, we would find BIterator in
1820 // the list of subclasses, which would be bad. Make sure that
1821 // Iterator still has only one non-core subclass...
1822 EXPECT_EQ(saved_subclass_count + 1, subclasses.Length());
1823
1824 // ...and the non-core subclass is still named AIterator.
1825 new_subclass = subclasses.At(subclasses.Length() - 1);
1826 name = Class::Cast(new_subclass).Name();
1827 EXPECT_STREQ("AIterator", name.ToCString());
1828 }
1829
1830 #endif // !PRODUCT
1831
1832 } // namespace dart
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698