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

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

Powered by Google App Engine
This is Rietveld 408576698