blob: 0775ee2c84535d0cf6f9ec99f8e5bc97fe091f7f [file] [log] [blame]
// Copyright (c) 2016, the Dart project authors. Please see the AUTHORS file
// for details. All rights reserved. Use of this source code is governed by a
// BSD-style license that can be found in the LICENSE file.
#include <array>
#include "include/dart_api.h"
#include "include/dart_tools_api.h"
#include "platform/assert.h"
#include "vm/debugger_api_impl_test.h"
#include "vm/globals.h"
#include "vm/isolate.h"
#include "vm/kernel_loader.h"
#include "vm/lockers.h"
#include "vm/thread_barrier.h"
#include "vm/thread_pool.h"
#include "vm/unit_test.h"
namespace dart {
#if !defined(PRODUCT) && !defined(DART_PRECOMPILED_RUNTIME)
int64_t SimpleInvoke(Dart_Handle lib, const char* method) {
Dart_Handle result = Dart_Invoke(lib, NewString(method), 0, nullptr);
EXPECT_VALID(result);
EXPECT(Dart_IsInteger(result));
int64_t integer_result = 0;
result = Dart_IntegerToInt64(result, &integer_result);
EXPECT_VALID(result);
return integer_result;
}
const char* SimpleInvokeStr(Dart_Handle lib, const char* method) {
Dart_Handle result = Dart_Invoke(lib, NewString(method), 0, nullptr);
const char* result_str = nullptr;
EXPECT(Dart_IsString(result));
EXPECT_VALID(Dart_StringToCString(result, &result_str));
return result_str;
}
Dart_Handle SimpleInvokeError(Dart_Handle lib, const char* method) {
Dart_Handle result = Dart_Invoke(lib, NewString(method), 0, nullptr);
EXPECT(Dart_IsError(result));
return result;
}
TEST_CASE(IsolateReload_FunctionReplacement) {
const char* kScript =
"main() {\n"
" return 4;\n"
"}\n";
Dart_Handle lib = TestCase::LoadTestScript(kScript, nullptr);
EXPECT_VALID(lib);
EXPECT_EQ(4, SimpleInvoke(lib, "main"));
const char* kReloadScript =
"var _unused;"
"main() {\n"
" return 10;\n"
"}\n";
lib = TestCase::ReloadTestScript(kReloadScript);
EXPECT_VALID(lib);
EXPECT_EQ(10, SimpleInvoke(lib, "main"));
}
TEST_CASE(IsolateReload_IncrementalCompile) {
const char* kScriptChars =
"main() {\n"
" return 42;\n"
"}\n";
Dart_Handle lib = TestCase::LoadTestScript(kScriptChars, nullptr);
EXPECT_VALID(lib);
Dart_Handle result = Dart_Invoke(lib, NewString("main"), 0, nullptr);
int64_t value = 0;
result = Dart_IntegerToInt64(result, &value);
EXPECT_VALID(result);
EXPECT_EQ(42, value);
const char* kUpdatedScriptChars =
"main() {\n"
" return 24;\n"
"}\n"
"";
lib = TestCase::ReloadTestScript(kUpdatedScriptChars);
EXPECT_VALID(lib);
result = Dart_Invoke(lib, NewString("main"), 0, nullptr);
result = Dart_IntegerToInt64(result, &value);
EXPECT_VALID(result);
EXPECT_EQ(24, value);
}
TEST_CASE(IsolateReload_KernelIncrementalCompile) {
// clang-format off
Dart_SourceFile sourcefiles[] = {
{
"file:///test-app",
"main() {\n"
" return 42;\n"
"}\n",
}};
// clang-format on
Dart_Handle lib = TestCase::LoadTestScriptWithDFE(
sizeof(sourcefiles) / sizeof(Dart_SourceFile), sourcefiles,
nullptr /* resolver */, true /* finalize */, true /* incrementally */);
Dart_Handle result = Dart_Invoke(lib, NewString("main"), 0, nullptr);
int64_t value = 0;
result = Dart_IntegerToInt64(result, &value);
EXPECT_VALID(result);
EXPECT_EQ(42, value);
// clang-format off
Dart_SourceFile updated_sourcefiles[] = {
{
"file:///test-app",
"main() {\n"
" return 24;\n"
"}\n"
""
}};
// clang-format on
{
const uint8_t* kernel_buffer = nullptr;
intptr_t kernel_buffer_size = 0;
char* error = TestCase::CompileTestScriptWithDFE(
"file:///test-app",
sizeof(updated_sourcefiles) / sizeof(Dart_SourceFile),
updated_sourcefiles, &kernel_buffer, &kernel_buffer_size,
true /* incrementally */);
EXPECT(error == nullptr);
EXPECT_NOTNULL(kernel_buffer);
lib = TestCase::ReloadTestKernel(kernel_buffer, kernel_buffer_size);
EXPECT_VALID(lib);
}
result = Dart_Invoke(lib, NewString("main"), 0, nullptr);
result = Dart_IntegerToInt64(result, &value);
EXPECT_VALID(result);
EXPECT_EQ(24, value);
}
TEST_CASE(IsolateReload_KernelIncrementalCompileAppAndLib) {
// clang-format off
Dart_SourceFile sourcefiles[] = {
{
"file:///test-app.dart",
"import 'test-lib.dart';\n"
"main() {\n"
" return WhatsTheMeaningOfAllThis();\n"
"}\n",
},
{
"file:///test-lib.dart",
"WhatsTheMeaningOfAllThis() {\n"
" return 42;\n"
"}\n",
}};
// clang-format on
Dart_Handle lib = TestCase::LoadTestScriptWithDFE(
sizeof(sourcefiles) / sizeof(Dart_SourceFile), sourcefiles,
nullptr /* resolver */, true /* finalize */, true /* incrementally */);
EXPECT_VALID(lib);
Dart_Handle result = Dart_Invoke(lib, NewString("main"), 0, nullptr);
int64_t value = 0;
result = Dart_IntegerToInt64(result, &value);
EXPECT_VALID(result);
EXPECT_EQ(42, value);
// clang-format off
Dart_SourceFile updated_sourcefiles[] = {
{
"file:///test-lib.dart",
"WhatsTheMeaningOfAllThis() {\n"
" return 24;\n"
"}\n"
""
}};
// clang-format on
{
const uint8_t* kernel_buffer = nullptr;
intptr_t kernel_buffer_size = 0;
char* error = TestCase::CompileTestScriptWithDFE(
"file:///test-app.dart",
sizeof(updated_sourcefiles) / sizeof(Dart_SourceFile),
updated_sourcefiles, &kernel_buffer, &kernel_buffer_size,
true /* incrementally */);
EXPECT(error == nullptr);
EXPECT_NOTNULL(kernel_buffer);
lib = TestCase::ReloadTestKernel(kernel_buffer, kernel_buffer_size);
EXPECT_VALID(lib);
}
result = Dart_Invoke(lib, NewString("main"), 0, nullptr);
result = Dart_IntegerToInt64(result, &value);
EXPECT_VALID(result);
EXPECT_EQ(24, value);
}
TEST_CASE(IsolateReload_KernelIncrementalCompileGenerics) {
// clang-format off
Dart_SourceFile sourcefiles[] = {
{
"file:///test-app.dart",
"import 'test-lib.dart';\n"
"class Account {\n"
" int balance() => 42;\n"
"}\n"
"class MyAccountState extends State<Account> {\n"
" MyAccountState(Account a): super(a) {}\n"
"}\n"
"main() {\n"
" return (new MyAccountState(new Account()))\n"
" .howAreTheThings().balance();\n"
"}\n",
},
{
"file:///test-lib.dart",
"class State<T> {\n"
" T t;"
" State(this.t);\n"
" T howAreTheThings() => t;\n"
"}\n",
}};
// clang-format on
Dart_Handle lib = TestCase::LoadTestScriptWithDFE(
sizeof(sourcefiles) / sizeof(Dart_SourceFile), sourcefiles,
nullptr /* resolver */, true /* finalize */, true /* incrementally */);
EXPECT_VALID(lib);
Dart_Handle result = Dart_Invoke(lib, NewString("main"), 0, nullptr);
int64_t value = 0;
result = Dart_IntegerToInt64(result, &value);
EXPECT_VALID(result);
EXPECT_EQ(42, value);
// clang-format off
Dart_SourceFile updated_sourcefiles[] = {
{
"file:///test-app.dart",
"import 'test-lib.dart';\n"
"class Account {\n"
" int balance() => 24;\n"
"}\n"
"class MyAccountState extends State<Account> {\n"
" MyAccountState(Account a): super(a) {}\n"
"}\n"
"main() {\n"
" return (new MyAccountState(new Account()))\n"
" .howAreTheThings().balance();\n"
"}\n",
}};
// clang-format on
{
const uint8_t* kernel_buffer = nullptr;
intptr_t kernel_buffer_size = 0;
char* error = TestCase::CompileTestScriptWithDFE(
"file:///test-app.dart",
sizeof(updated_sourcefiles) / sizeof(Dart_SourceFile),
updated_sourcefiles, &kernel_buffer, &kernel_buffer_size,
true /* incrementally */);
EXPECT(error == nullptr);
EXPECT_NOTNULL(kernel_buffer);
lib = TestCase::ReloadTestKernel(kernel_buffer, kernel_buffer_size);
EXPECT_VALID(lib);
}
result = Dart_Invoke(lib, NewString("main"), 0, nullptr);
result = Dart_IntegerToInt64(result, &value);
EXPECT_VALID(result);
EXPECT_EQ(24, value);
}
TEST_CASE(IsolateReload_KernelIncrementalCompileBaseClass) {
// clang-format off
const char* kSourceFile1 =
"class State<T, U> {\n"
" T? t;\n"
" U? u;\n"
" State(List l) {\n"
" t = l[0] is T ? l[0] : null;\n"
" u = l[1] is U ? l[1] : null;\n"
" }\n"
"}\n";
Dart_SourceFile sourcefiles[3] = {
{
"file:///test-app.dart",
"import 'test-util.dart';\n"
"main() {\n"
" var v = doWork();"
" return v == 42 ? 1 : v == null ? -1 : 0;\n"
"}\n",
},
{
"file:///test-lib.dart",
kSourceFile1
},
{
"file:///test-util.dart",
"import 'test-lib.dart';\n"
"class MyAccountState extends State<int, String> {\n"
" MyAccountState(List l): super(l) {}\n"
" first() => t;\n"
"}\n"
"doWork() => new MyAccountState(<dynamic>[42, 'abc']).first();\n"
}
};
// clang-format on
Dart_Handle lib = TestCase::LoadTestScriptWithDFE(
sizeof(sourcefiles) / sizeof(Dart_SourceFile), sourcefiles,
nullptr /* resolver */, true /* finalize */, true /* incrementally */);
EXPECT_VALID(lib);
Dart_Handle result = Dart_Invoke(lib, NewString("main"), 0, nullptr);
int64_t value = 0;
result = Dart_IntegerToInt64(result, &value);
EXPECT_VALID(result);
EXPECT_EQ(1, value);
const char* kUpdatedSourceFile =
"class State<U, T> {\n"
" T? t;\n"
" U? u;\n"
" State(List l) {\n"
" t = l[0] is T ? l[0] : null;\n"
" u = l[1] is U ? l[1] : null;\n"
" }\n"
"}\n";
Dart_SourceFile updated_sourcefiles[1] = {{
"file:///test-lib.dart",
kUpdatedSourceFile,
}};
{
const uint8_t* kernel_buffer = nullptr;
intptr_t kernel_buffer_size = 0;
char* error = TestCase::CompileTestScriptWithDFE(
"file:///test-app.dart",
sizeof(updated_sourcefiles) / sizeof(Dart_SourceFile),
updated_sourcefiles, &kernel_buffer, &kernel_buffer_size,
true /* incrementally */);
EXPECT(error == nullptr);
EXPECT_NOTNULL(kernel_buffer);
lib = TestCase::ReloadTestKernel(kernel_buffer, kernel_buffer_size);
EXPECT_VALID(lib);
}
result = Dart_Invoke(lib, NewString("main"), 0, nullptr);
result = Dart_IntegerToInt64(result, &value);
EXPECT_VALID(result);
EXPECT_EQ(-1, value);
}
TEST_CASE(IsolateReload_BadClass) {
const char* kScript =
"class Foo {\n"
" final a;\n"
" Foo(this.a);\n"
"}\n"
"main() {\n"
" new Foo(5);\n"
" return 4;\n"
"}\n";
Dart_Handle lib = TestCase::LoadTestScript(kScript, nullptr);
EXPECT_VALID(lib);
EXPECT_EQ(4, SimpleInvoke(lib, "main"));
const char* kReloadScript =
"var _unused;"
"class Foo {\n"
" final a kjsdf ksjdf ;\n"
" Foo(this.a);\n"
"}\n"
"main() {\n"
" new Foo(5);\n"
" return 10;\n"
"}\n";
Dart_Handle result = TestCase::ReloadTestScript(kReloadScript);
EXPECT_ERROR(result, "Expected ';' after this");
EXPECT_EQ(4, SimpleInvoke(lib, "main"));
}
TEST_CASE(IsolateReload_StaticValuePreserved) {
const char* kScript =
"init() => 'old value';\n"
"var value = init();\n"
"main() {\n"
" return 'init()=${init()},value=${value}';\n"
"}\n";
Dart_Handle lib = TestCase::LoadTestScript(kScript, nullptr);
EXPECT_VALID(lib);
EXPECT_STREQ("init()=old value,value=old value",
SimpleInvokeStr(lib, "main"));
const char* kReloadScript =
"var _unused;"
"init() => 'new value';\n"
"var value = init();\n"
"main() {\n"
" return 'init()=${init()},value=${value}';\n"
"}\n";
lib = TestCase::ReloadTestScript(kReloadScript);
EXPECT_VALID(lib);
EXPECT_STREQ("init()=new value,value=old value",
SimpleInvokeStr(lib, "main"));
}
TEST_CASE(IsolateReload_SavedClosure) {
// Create a closure in main which only exists in the original source.
const char* kScript =
"magic() {\n"
" var x = 'ante';\n"
" return x + 'diluvian';\n"
"}\n"
"var closure;\n"
"main() {\n"
" closure = () { return magic().toString() + '!'; };\n"
" return closure();\n"
"}\n";
Dart_Handle lib = TestCase::LoadTestScript(kScript, nullptr);
EXPECT_VALID(lib);
EXPECT_STREQ("antediluvian!", SimpleInvokeStr(lib, "main"));
// Remove the original closure from the source code. The closure is
// able to be recompiled because its source is preserved in a
// special patch class.
const char* kReloadScript =
"magic() {\n"
" return 'postapocalyptic';\n"
"}\n"
"var closure;\n"
"main() {\n"
" return closure();\n"
"}\n";
lib = TestCase::ReloadTestScript(kReloadScript);
EXPECT_VALID(lib);
EXPECT_STREQ("postapocalyptic!", SimpleInvokeStr(lib, "main"));
}
TEST_CASE(IsolateReload_TopLevelFieldAdded) {
const char* kScript =
"var value1 = 10;\n"
"main() {\n"
" return 'value1=${value1}';\n"
"}\n";
Dart_Handle lib = TestCase::LoadTestScript(kScript, nullptr);
EXPECT_VALID(lib);
EXPECT_STREQ("value1=10", SimpleInvokeStr(lib, "main"));
const char* kReloadScript =
"var value1 = 10;\n"
"var value2 = 20;\n"
"main() {\n"
" return 'value1=${value1},value2=${value2}';\n"
"}\n";
lib = TestCase::ReloadTestScript(kReloadScript);
EXPECT_VALID(lib);
EXPECT_STREQ("value1=10,value2=20", SimpleInvokeStr(lib, "main"));
}
TEST_CASE(IsolateReload_ClassFieldAdded) {
const char* kScript =
"class Foo {\n"
" var x;\n"
"}\n"
"main() {\n"
" new Foo();\n"
" return 44;\n"
"}\n";
Dart_Handle lib = TestCase::LoadTestScript(kScript, nullptr);
EXPECT_VALID(lib);
EXPECT_EQ(44, SimpleInvoke(lib, "main"));
const char* kReloadScript =
"class Foo {\n"
" var x;\n"
" var y;\n"
"}\n"
"main() {\n"
" new Foo();\n"
" return 44;\n"
"}\n";
lib = TestCase::ReloadTestScript(kReloadScript);
EXPECT_VALID(lib);
EXPECT_EQ(44, SimpleInvoke(lib, "main"));
}
TEST_CASE(IsolateReload_ClassFieldAdded2) {
const char* kScript =
"class Foo {\n"
" var x;\n"
" var y;\n"
"}\n"
"main() {\n"
" new Foo();\n"
" return 44;\n"
"}\n";
Dart_Handle lib = TestCase::LoadTestScript(kScript, nullptr);
EXPECT_VALID(lib);
EXPECT_EQ(44, SimpleInvoke(lib, "main"));
const char* kReloadScript =
"class Foo {\n"
" var x;\n"
" var y;\n"
" var z;\n"
"}\n"
"main() {\n"
" new Foo();\n"
" return 44;\n"
"}\n";
lib = TestCase::ReloadTestScript(kReloadScript);
EXPECT_VALID(lib);
EXPECT_EQ(44, SimpleInvoke(lib, "main"));
}
TEST_CASE(IsolateReload_ClassFieldRemoved) {
const char* kScript =
"class Foo {\n"
" var x;\n"
" var y;\n"
"}\n"
"main() {\n"
" new Foo();\n"
" return 44;\n"
"}\n";
Dart_Handle lib = TestCase::LoadTestScript(kScript, nullptr);
EXPECT_VALID(lib);
EXPECT_EQ(44, SimpleInvoke(lib, "main"));
const char* kReloadScript =
"class Foo {\n"
" var x;\n"
"}\n"
"main() {\n"
" new Foo();\n"
" return 44;\n"
"}\n";
lib = TestCase::ReloadTestScript(kReloadScript);
EXPECT_VALID(lib);
EXPECT_EQ(44, SimpleInvoke(lib, "main"));
}
TEST_CASE(IsolateReload_ClassAdded) {
const char* kScript =
"main() {\n"
" return 'hello';\n"
"}\n";
Dart_Handle lib = TestCase::LoadTestScript(kScript, nullptr);
EXPECT_VALID(lib);
EXPECT_STREQ("hello", SimpleInvokeStr(lib, "main"));
const char* kReloadScript =
"var _unused;"
"class A {\n"
" toString() => 'hello from A';\n"
"}\n"
"main() {\n"
" return new A().toString();\n"
"}\n";
lib = TestCase::ReloadTestScript(kReloadScript);
EXPECT_VALID(lib);
EXPECT_STREQ("hello from A", SimpleInvokeStr(lib, "main"));
}
TEST_CASE(IsolateReload_ClassRemoved) {
const char* kScript =
"class A {\n"
" toString() => 'hello from A';\n"
"}\n"
"List<dynamic> list = <dynamic>[];"
"main() {\n"
" list.add(new A());\n"
" return list[0].toString();\n"
"}\n";
Dart_Handle lib = TestCase::LoadTestScript(kScript, nullptr);
EXPECT_VALID(lib);
EXPECT_STREQ("hello from A", SimpleInvokeStr(lib, "main"));
const char* kReloadScript =
"List<dynamic> list = <dynamic>[];\n"
"main() {\n"
" return list[0].toString();\n"
"}\n";
lib = TestCase::ReloadTestScript(kReloadScript);
EXPECT_VALID(lib);
EXPECT_STREQ("hello from A", SimpleInvokeStr(lib, "main"));
}
TEST_CASE(IsolateReload_LibraryImportAdded) {
const char* kScript =
"main() {\n"
" return max(3, 4);\n"
"}\n";
const char* kReloadScript =
"import 'dart:math';\n"
"main() {\n"
" return max(3, 4);\n"
"}\n";
Dart_Handle lib = TestCase::LoadTestScriptWithErrors(kScript);
EXPECT_VALID(lib);
EXPECT_ERROR(SimpleInvokeError(lib, "main"), "max");
lib = TestCase::ReloadTestScript(kReloadScript);
EXPECT_VALID(lib);
EXPECT_EQ(4, SimpleInvoke(lib, "main"));
}
TEST_CASE(IsolateReload_LibraryImportRemoved) {
const char* kScript =
"import 'dart:math';\n"
"main() {\n"
" return max(3, 4);\n"
"}\n";
Dart_Handle lib = TestCase::LoadTestScript(kScript, nullptr);
EXPECT_VALID(lib);
EXPECT_EQ(4, SimpleInvoke(lib, "main"));
const char* kReloadScript =
"main() {\n"
" return max(3, 4);\n"
"}\n";
lib = TestCase::ReloadTestScript(kReloadScript);
EXPECT_ERROR(SimpleInvokeError(lib, "main"), "max");
}
TEST_CASE(IsolateReload_LibraryDebuggable) {
const char* kScript =
"main() {\n"
" return 1;\n"
"}\n";
Dart_Handle lib = TestCase::LoadTestScript(kScript, nullptr);
EXPECT_VALID(lib);
// The library is by default debuggable. Make it not debuggable.
intptr_t lib_id = -1;
bool debuggable = false;
EXPECT_VALID(Dart_LibraryId(lib, &lib_id));
EXPECT_VALID(Dart_GetLibraryDebuggable(lib_id, &debuggable));
EXPECT_EQ(true, debuggable);
EXPECT_VALID(Dart_SetLibraryDebuggable(lib_id, false));
EXPECT_VALID(Dart_GetLibraryDebuggable(lib_id, &debuggable));
EXPECT_EQ(false, debuggable);
EXPECT_EQ(1, SimpleInvoke(lib, "main"));
const char* kReloadScript =
"main() {\n"
" return 2;\n"
"}\n";
lib = TestCase::ReloadTestScript(kReloadScript);
EXPECT_VALID(lib);
EXPECT_EQ(2, SimpleInvoke(lib, "main"));
// Library debuggability is preserved.
intptr_t new_lib_id = -1;
EXPECT_VALID(Dart_LibraryId(lib, &new_lib_id));
EXPECT_VALID(Dart_GetLibraryDebuggable(new_lib_id, &debuggable));
EXPECT_EQ(false, debuggable);
}
TEST_CASE(IsolateReload_ImplicitConstructorChanged) {
// Note that we are checking that the value 20 gets cleared from the
// compile-time constants cache. To make this test work, "20" and
// "10" need to be at the same token position.
const char* kScript =
"class A {\n"
" int field = 20;\n"
"}\n"
"var savedA = new A();\n"
"main() {\n"
" var newA = new A();\n"
" return 'saved:${savedA.field} new:${newA.field}';\n"
"}\n";
Dart_Handle lib = TestCase::LoadTestScript(kScript, nullptr);
EXPECT_VALID(lib);
EXPECT_STREQ("saved:20 new:20", SimpleInvokeStr(lib, "main"));
const char* kReloadScript =
"class A {\n"
" int field = 10;\n"
"}\n"
"var savedA = new A();\n"
"main() {\n"
" var newA = new A();\n"
" return 'saved:${savedA.field} new:${newA.field}';\n"
"}\n";
lib = TestCase::ReloadTestScript(kReloadScript);
EXPECT_VALID(lib);
EXPECT_STREQ("saved:20 new:10", SimpleInvokeStr(lib, "main"));
}
TEST_CASE(IsolateReload_ConstructorChanged) {
// clang-format off
const char* kScript =
"class A {\n"
" late int field;\n"
" A() { field = 20; }\n"
"}\n"
"var savedA = A();\n"
"main() {\n"
" var newA = A();\n"
" return 'saved:${savedA.field} new:${newA.field}';\n"
"}\n";
// clang-format on
Dart_Handle lib = TestCase::LoadTestScript(kScript, nullptr);
EXPECT_VALID(lib);
EXPECT_STREQ("saved:20 new:20", SimpleInvokeStr(lib, "main"));
// clang-format off
const char* kReloadScript =
"var _unused;"
"class A {\n"
" late int field;\n"
" A() { field = 10; }\n"
"}\n"
"var savedA = A();\n"
"main() {\n"
" var newA = A();\n"
" return 'saved:${savedA.field} new:${newA.field}';\n"
"}\n";
// clang-format on
lib = TestCase::ReloadTestScript(kReloadScript);
EXPECT_VALID(lib);
EXPECT_STREQ("saved:20 new:10", SimpleInvokeStr(lib, "main"));
}
TEST_CASE(IsolateReload_SuperClassChanged) {
const char* kScript =
"class A {\n"
"}\n"
"class B extends A {\n"
"}\n"
"var list = [ new A(), new B() ];\n"
"main() {\n"
" return (list.map((x) => '${x is A}/${x is B}')).toString();\n"
"}\n";
Dart_Handle lib = TestCase::LoadTestScript(kScript, nullptr);
EXPECT_VALID(lib);
EXPECT_STREQ("(true/false, true/true)", SimpleInvokeStr(lib, "main"));
const char* kReloadScript =
"var _unused;"
"class B{\n"
"}\n"
"class A extends B {\n"
"}\n"
"var list = [ new A(), new B() ];\n"
"main() {\n"
" return (list.map((x) => '${x is A}/${x is B}')).toString();\n"
"}\n";
lib = TestCase::ReloadTestScript(kReloadScript);
EXPECT_VALID(lib);
EXPECT_STREQ("(true/true, false/true)", SimpleInvokeStr(lib, "main"));
}
TEST_CASE(IsolateReload_Generics) {
// Reload a program with generics without changing the source. We
// do this to produce duplication TypeArguments and make sure that
// the system doesn't die.
const char* kScript =
"class A {\n"
"}\n"
"class B<T extends A> {\n"
"}\n"
"main() {\n"
" return new B<A>().toString();\n"
"}\n";
Dart_Handle lib = TestCase::LoadTestScript(kScript, nullptr);
EXPECT_VALID(lib);
EXPECT_STREQ("Instance of 'B<A>'", SimpleInvokeStr(lib, "main"));
const char* kReloadScript =
"class A {\n"
"}\n"
"class B<T extends A> {\n"
"}\n"
"main() {\n"
" return new B<A>().toString();\n"
"}\n";
lib = TestCase::ReloadTestScript(kReloadScript);
EXPECT_VALID(lib);
EXPECT_STREQ("Instance of 'B<A>'", SimpleInvokeStr(lib, "main"));
}
TEST_CASE(IsolateReload_TypeIdentity) {
const char* kScript =
"import 'file:///test:isolate_reload_helper';\n"
"class T { }\n"
"getType() => T;\n"
"main() {\n"
" var oldType = getType();\n"
" reloadTest();\n"
" var newType = getType();\n"
" return identical(oldType, newType).toString();\n"
"}\n";
Dart_Handle lib = TestCase::LoadTestScript(kScript, nullptr);
EXPECT_VALID(lib);
const char* kReloadScript =
"import 'file:///test:isolate_reload_helper';\n"
"class T extends Stopwatch { }\n"
"getType() => T;\n"
"main() {\n"
" var oldType = getType();\n"
" reloadTest();\n"
" var newType = getType();\n"
" return identical(oldType, newType).toString();\n"
"}\n";
EXPECT_VALID(TestCase::SetReloadTestScript(kReloadScript));
EXPECT_STREQ("true", SimpleInvokeStr(lib, "main"));
}
TEST_CASE(IsolateReload_TypeIdentityGeneric) {
const char* kScript =
"import 'file:///test:isolate_reload_helper';\n"
"class T<G> { }\n"
"getType() => new T<int>().runtimeType;\n"
"main() {\n"
" var oldType = getType();\n"
" reloadTest();\n"
" var newType = getType();\n"
" return identical(oldType, newType).toString();\n"
"}\n";
Dart_Handle lib = TestCase::LoadTestScript(kScript, nullptr);
EXPECT_VALID(lib);
const char* kReloadScript =
"import 'file:///test:isolate_reload_helper';\n"
"class T<G> extends Stopwatch { }\n"
"getType() => new T<int>().runtimeType;\n"
"main() {\n"
" var oldType = getType();\n"
" reloadTest();\n"
" var newType = getType();\n"
" return identical(oldType, newType).toString();\n"
"}\n";
EXPECT_VALID(TestCase::SetReloadTestScript(kReloadScript));
EXPECT_STREQ("true", SimpleInvokeStr(lib, "main"));
}
TEST_CASE(IsolateReload_TypeIdentityParameter) {
const char* kScript =
"import 'dart:mirrors';\n"
"import 'file:///test:isolate_reload_helper';\n"
"class T<G> { }\n"
"getTypeVar() => reflectType(T).typeVariables[0];\n"
"main() {\n"
" var oldType = getTypeVar();\n"
" reloadTest();\n"
" var newType = getTypeVar();\n"
" return (oldType == newType).toString();\n"
"}\n";
Dart_Handle lib = TestCase::LoadTestScript(kScript, nullptr);
EXPECT_VALID(lib);
const char* kReloadScript =
"import 'dart:mirrors';\n"
"import 'file:///test:isolate_reload_helper';\n"
"class T<G> extends Stopwatch { }\n"
"getTypeVar() => reflectType(T).typeVariables[0];\n"
"main() {\n"
" var oldType = getTypeVar();\n"
" reloadTest();\n"
" var newType = getTypeVar();\n"
" return (oldType == newType).toString();\n"
"}\n";
EXPECT_VALID(TestCase::SetReloadTestScript(kReloadScript));
EXPECT_STREQ("true", SimpleInvokeStr(lib, "main"));
}
TEST_CASE(IsolateReload_MixinChanged) {
const char* kScript =
"mixin Mixin1 {\n"
" var field = 'mixin1';\n"
" func() => 'mixin1';\n"
"}\n"
"class B extends Object with Mixin1 {\n"
"}\n"
"var saved = new B();\n"
"main() {\n"
" return 'saved:field=${saved.field},func=${saved.func()}';\n"
"}\n";
Dart_Handle lib = TestCase::LoadTestScript(kScript, nullptr);
EXPECT_VALID(lib);
EXPECT_STREQ("saved:field=mixin1,func=mixin1", SimpleInvokeStr(lib, "main"));
const char* kReloadScript =
"mixin Mixin2 {\n"
" var field = 'mixin2';\n"
" func() => 'mixin2';\n"
"}\n"
"class B extends Object with Mixin2 {\n"
"}\n"
"var saved = new B();\n"
"main() {\n"
" var newer = new B();\n"
" return 'saved:field=${saved.field},func=${saved.func()} '\n"
" 'newer:field=${newer.field},func=${newer.func()}';\n"
"}\n";
lib = TestCase::ReloadTestScript(kReloadScript);
EXPECT_VALID(lib);
// The saved instance of B retains its old field value from mixin1,
// but it gets the new implementation of func from mixin2.
EXPECT_STREQ(
"saved:field=mixin1,func=mixin2 "
"newer:field=mixin2,func=mixin2",
SimpleInvokeStr(lib, "main"));
}
TEST_CASE(IsolateReload_ComplexInheritanceChange) {
const char* kScript =
"class A {\n"
" String name;\n"
" A(this.name);\n"
"}\n"
"class B extends A {\n"
" B(name) : super(name);\n"
"}\n"
"class C extends B {\n"
" C(name) : super(name);\n"
"}\n"
"var list = <dynamic>[ new A('a'), new B('b'), new C('c') ];\n"
"main() {\n"
" return (list.map((x) {\n"
" return '${x.name} is A(${x is A})/ B(${x is B})/ C(${x is C})';\n"
" })).toString();\n"
"}\n";
Dart_Handle lib = TestCase::LoadTestScript(kScript, nullptr);
EXPECT_VALID(lib);
EXPECT_STREQ(
"(a is A(true)/ B(false)/ C(false),"
" b is A(true)/ B(true)/ C(false),"
" c is A(true)/ B(true)/ C(true))",
SimpleInvokeStr(lib, "main"));
const char* kReloadScript =
"class C {\n"
" String name;\n"
" C(this.name);\n"
"}\n"
"class X extends C {\n"
" X(name) : super(name);\n"
"}\n"
"class A extends X {\n"
" A(name) : super(name);\n"
"}\n"
"var list;\n"
"main() {\n"
" list.add(new X('x'));\n"
" return (list.map((x) {\n"
" return '${x.name} is A(${x is A})/ C(${x is C})/ X(${x is X})';\n"
" })).toString();\n"
"}\n";
lib = TestCase::ReloadTestScript(kReloadScript);
EXPECT_VALID(lib);
EXPECT_STREQ(
"(a is A(true)/ C(true)/ X(true),"
" b is A(true)/ C(true)/ X(true)," // still extends A...
" c is A(false)/ C(true)/ X(false),"
" x is A(false)/ C(true)/ X(true))",
SimpleInvokeStr(lib, "main"));
// Revive the class B and make sure all allocated instances take
// their place in the inheritance hierarchy.
const char* kReloadScript2 =
"class X {\n"
" String name;\n"
" X(this.name);\n"
"}\n"
"class A extends X{\n"
" A(name) : super(name);\n"
"}\n"
"class B extends X {\n"
" B(name) : super(name);\n"
"}\n"
"class C extends A {\n"
" C(name) : super(name);\n"
"}\n"
"var list;\n"
"main() {\n"
" return (list.map((x) {\n"
" return '${x.name} is '\n"
" 'A(${x is A})/ B(${x is B})/ C(${x is C})/ X(${x is X})';\n"
" })).toString();\n"
"}\n";
lib = TestCase::ReloadTestScript(kReloadScript2);
EXPECT_VALID(lib);
EXPECT_STREQ(
"(a is A(true)/ B(false)/ C(false)/ X(true),"
" b is A(false)/ B(true)/ C(false)/ X(true),"
" c is A(true)/ B(false)/ C(true)/ X(true),"
" x is A(false)/ B(false)/ C(false)/ X(true))",
SimpleInvokeStr(lib, "main"));
}
TEST_CASE(IsolateReload_LiveStack) {
const char* kScript =
"import 'file:///test:isolate_reload_helper';\n"
"helper() => 7;\n"
"alpha() { var x = helper(); reloadTest(); return x + helper(); }\n"
"foo() => alpha();\n"
"bar() => foo();\n"
"main() {\n"
" return bar();\n"
"}\n";
Dart_Handle lib = TestCase::LoadTestScript(kScript, nullptr);
EXPECT_VALID(lib);
const char* kReloadScript =
"import 'file:///test:isolate_reload_helper';\n"
"helper() => 100;\n"
"alpha() => 5 + helper();\n"
"foo() => alpha();\n"
"bar() => foo();\n"
"main() {\n"
" return bar();\n"
"}\n";
EXPECT_VALID(TestCase::SetReloadTestScript(kReloadScript));
EXPECT_EQ(107, SimpleInvoke(lib, "main"));
lib = Dart_RootLibrary();
EXPECT_NON_NULL(lib);
EXPECT_EQ(105, SimpleInvoke(lib, "main"));
}
TEST_CASE(IsolateReload_LibraryLookup) {
const char* kImportScript = "importedFunc() => 'a';\n";
TestCase::AddTestLib("test:lib1", kImportScript);
const char* kScript =
"main() {\n"
" return 'b';\n"
"}\n";
Dart_Handle result;
Dart_Handle lib = TestCase::LoadTestScript(kScript, nullptr);
EXPECT_VALID(lib);
EXPECT_STREQ("b", SimpleInvokeStr(lib, "main"));
// Fail to find 'test:lib1' in the isolate.
result = Dart_LookupLibrary(NewString("test:lib1"));
EXPECT(Dart_IsError(result));
const char* kReloadScript =
"import 'test:lib1';\n"
"main() {\n"
" return importedFunc();\n"
"}\n";
// Reload and add 'test:lib1' to isolate.
lib = TestCase::ReloadTestScript(kReloadScript);
EXPECT_VALID(lib);
EXPECT_STREQ("a", SimpleInvokeStr(lib, "main"));
// Find 'test:lib1' in the isolate.
result = Dart_LookupLibrary(NewString("test:lib1"));
EXPECT(Dart_IsLibrary(result));
// Reload and remove 'test:lib1' from isolate.
lib = TestCase::ReloadTestScript(kScript);
EXPECT_VALID(lib);
// Fail to find 'test:lib1' in the isolate.
result = Dart_LookupLibrary(NewString("test:lib1"));
EXPECT(Dart_IsError(result));
}
TEST_CASE(IsolateReload_LibraryHide) {
const char* kImportScript = "importedFunc() => 'a';\n";
TestCase::AddTestLib("test:lib1", kImportScript);
// Import 'test:lib1' with importedFunc hidden. Will result in an
// error.
const char* kScript =
"import 'test:lib1' hide importedFunc;\n"
"main() {\n"
" return importedFunc();\n"
"}\n";
// Dart_Handle result;
Dart_Handle lib = TestCase::LoadTestScriptWithErrors(kScript);
EXPECT_VALID(lib);
EXPECT_ERROR(SimpleInvokeError(lib, "main"), "importedFunc");
// Import 'test:lib1'.
const char* kReloadScript =
"import 'test:lib1';\n"
"main() {\n"
" return importedFunc();\n"
"}\n";
lib = TestCase::ReloadTestScript(kReloadScript);
EXPECT_VALID(lib);
EXPECT_STREQ("a", SimpleInvokeStr(lib, "main"));
}
TEST_CASE(IsolateReload_LibraryShow) {
const char* kImportScript =
"importedFunc() => 'a';\n"
"importedIntFunc() => 4;\n";
TestCase::AddTestLib("test:lib1", kImportScript);
// Import 'test:lib1' with importedIntFunc visible. Will result in
// an error when 'main' is invoked.
const char* kScript =
"import 'test:lib1' show importedIntFunc;\n"
"main() {\n"
" return importedFunc();\n"
"}\n"
"mainInt() {\n"
" return importedIntFunc();\n"
"}\n";
Dart_Handle lib = TestCase::LoadTestScriptWithErrors(kScript);
EXPECT_VALID(lib);
// Works.
EXPECT_EQ(4, SimpleInvoke(lib, "mainInt"));
// Results in an error.
EXPECT_ERROR(SimpleInvokeError(lib, "main"), "importedFunc");
// Import 'test:lib1' with importedFunc visible. Will result in
// an error when 'mainInt' is invoked.
const char* kReloadScript =
"import 'test:lib1' show importedFunc;\n"
"main() {\n"
" return importedFunc();\n"
"}\n"
"mainInt() {\n"
" return importedIntFunc();\n"
"}\n";
lib = TestCase::ReloadTestScript(kReloadScript);
EXPECT_ERROR(lib, "importedIntFunc");
}
// Verifies that we clear the ICs for the functions live on the stack in a way
// that is compatible with the fast path smi stubs.
TEST_CASE(IsolateReload_SmiFastPathStubs) {
const char* kImportScript = "importedIntFunc() => 4;\n";
TestCase::AddTestLib("test:lib1", kImportScript);
const char* kScript =
"import 'file:///test:isolate_reload_helper';\n"
"import 'test:lib1' show importedIntFunc;\n"
"main() {\n"
" var x = importedIntFunc();\n"
" var y = importedIntFunc();\n"
" reloadTest();\n"
" return x + y;\n"
"}\n";
Dart_Handle lib = TestCase::LoadTestScript(kScript, nullptr);
EXPECT_VALID(lib);
// Identity reload.
EXPECT_VALID(TestCase::SetReloadTestScript(kScript));
EXPECT_EQ(8, SimpleInvoke(lib, "main"));
}
// Verifies that we assign the correct patch classes for imported
// mixins when we reload.
TEST_CASE(IsolateReload_ImportedMixinFunction) {
const char* kImportScript =
"mixin ImportedMixin {\n"
" mixinFunc() => 'mixin';\n"
"}\n";
TestCase::AddTestLib("test:lib1", kImportScript);
const char* kScript =
"import 'test:lib1' show ImportedMixin;\n"
"class A extends Object with ImportedMixin {\n"
"}"
"var func = new A().mixinFunc;\n"
"main() {\n"
" return func();\n"
"}\n";
Dart_Handle lib = TestCase::LoadTestScript(kScript, nullptr);
EXPECT_VALID(lib);
EXPECT_STREQ("mixin", SimpleInvokeStr(lib, "main"));
const char* kReloadScript =
"import 'test:lib1' show ImportedMixin;\n"
"class A extends Object with ImportedMixin {\n"
"}"
"var func;\n"
"main() {\n"
" return func();\n"
"}\n";
lib = TestCase::ReloadTestScript(kReloadScript);
EXPECT_VALID(lib);
EXPECT_STREQ("mixin", SimpleInvokeStr(lib, "main"));
}
TEST_CASE(IsolateReload_TopLevelParseError) {
const char* kScript =
"main() {\n"
" return 4;\n"
"}\n";
Dart_Handle lib = TestCase::LoadTestScript(kScript, nullptr);
EXPECT_VALID(lib);
EXPECT_EQ(4, SimpleInvoke(lib, "main"));
const char* kReloadScript =
"kjsadkfjaksldfjklsadf;\n"
"main() {\n"
" return 4;\n"
"}\n";
lib = TestCase::ReloadTestScript(kReloadScript);
EXPECT_ERROR(lib,
"Variables must be declared using the keywords"
" 'const', 'final', 'var' or a type name.");
}
TEST_CASE(IsolateReload_PendingUnqualifiedCall_StaticToInstance) {
const char* kScript =
"import 'file:///test:isolate_reload_helper';\n"
"class C {\n"
" static foo() => 'static';\n"
" test() {\n"
" reloadTest();\n"
" return foo();\n"
" }\n"
"}\n"
"main() {\n"
" return new C().test();\n"
"}\n";
Dart_Handle lib = TestCase::LoadTestScript(kScript, nullptr);
EXPECT_VALID(lib);
const char* kReloadScript =
"import 'file:///test:isolate_reload_helper';\n"
"class C {\n"
" foo() => 'instance';\n"
" test() {\n"
" reloadTest();\n"
" return foo();\n"
" }\n"
"}\n"
"main() {\n"
" return new C().test();\n"
"}\n";
EXPECT_VALID(TestCase::SetReloadTestScript(kReloadScript));
const char* expected = "instance";
const char* result = SimpleInvokeStr(lib, "main");
EXPECT_STREQ(expected, result);
// Bail out if we've already failed so we don't crash in the tag handler.
if ((result == nullptr) || (strcmp(expected, result) != 0)) {
return;
}
lib = Dart_RootLibrary();
EXPECT_NON_NULL(lib);
EXPECT_STREQ(expected, SimpleInvokeStr(lib, "main"));
}
TEST_CASE(IsolateReload_PendingUnqualifiedCall_InstanceToStatic) {
const char* kScript =
"import 'file:///test:isolate_reload_helper';\n"
"class C {\n"
" foo() => 'instance';\n"
" test() {\n"
" reloadTest();\n"
" return foo();\n"
" }\n"
"}\n"
"main() {\n"
" return new C().test();\n"
"}\n";
Dart_Handle lib = TestCase::LoadTestScript(kScript, nullptr);
EXPECT_VALID(lib);
const char* kReloadScript =
"import 'file:///test:isolate_reload_helper';\n"
"class C {\n"
" static foo() => 'static';\n"
" test() {\n"
" reloadTest();\n"
" return foo();\n"
" }\n"
"}\n"
"main() {\n"
" return new C().test();\n"
"}\n";
EXPECT_VALID(TestCase::SetReloadTestScript(kReloadScript));
const char* expected = "static";
const char* result = SimpleInvokeStr(lib, "main");
EXPECT_NOTNULL(result);
// Bail out if we've already failed so we don't crash in StringEquals.
if (result == nullptr) {
return;
}
EXPECT_STREQ(expected, result);
lib = Dart_RootLibrary();
EXPECT_NON_NULL(lib);
EXPECT_STREQ(expected, SimpleInvokeStr(lib, "main"));
}
TEST_CASE(IsolateReload_PendingConstructorCall_AbstractToConcrete) {
const char* kScript =
"import 'file:///test:isolate_reload_helper';\n"
"abstract class Foo {}\n"
"class C {\n"
" test() {\n"
" reloadTest();\n"
" }\n"
"}\n"
"main() {\n"
" try {\n"
" new C().test();\n"
" return 'okay';\n"
" } catch (e) {\n"
" return 'exception';\n"
" }\n"
"}\n";
Dart_Handle lib = TestCase::LoadTestScript(kScript, nullptr);
EXPECT_VALID(lib);
const char* kReloadScript =
"import 'file:///test:isolate_reload_helper';\n"
"class Foo {}\n"
"class C {\n"
" test() {\n"
" reloadTest();\n"
" return new Foo();\n"
" }\n"
"}\n"
"main() {\n"
" try {\n"
" new C().test();\n"
" return 'okay';\n"
" } catch (e) {\n"
" return 'exception';\n"
" }\n"
"}\n";
EXPECT_VALID(TestCase::SetReloadTestScript(kReloadScript));
const char* expected = "okay";
const char* result = SimpleInvokeStr(lib, "main");
EXPECT_STREQ(expected, result);
// Bail out if we've already failed so we don't crash in the tag handler.
if ((result == nullptr) || (strcmp(expected, result) != 0)) {
return;
}
lib = Dart_RootLibrary();
EXPECT_NON_NULL(lib);
EXPECT_STREQ(expected, SimpleInvokeStr(lib, "main"));
}
TEST_CASE(IsolateReload_PendingConstructorCall_ConcreteToAbstract) {
const char* kScript =
"import 'file:///test:isolate_reload_helper';\n"
"class Foo {}\n"
"class C {\n"
" test() {\n"
" reloadTest();\n"
" return new Foo();\n"
" }\n"
"}\n"
"main() {\n"
" try {\n"
" new C().test();\n"
" return 'okay';\n"
" } catch (e) {\n"
" return 'exception';\n"
" }\n"
"}\n";
Dart_Handle lib = TestCase::LoadTestScript(kScript, nullptr);
EXPECT_VALID(lib);
const char* kReloadScript =
"import 'file:///test:isolate_reload_helper';\n"
"abstract class Foo {}\n"
"class C {\n"
" test() {\n"
" reloadTest();\n"
" return new Foo();\n"
" }\n"
"}\n"
"main() {\n"
" try {\n"
" new C().test();\n"
" return 'okay';\n"
" } catch (e) {\n"
" return 'exception';\n"
" }\n"
"}\n";
EXPECT_VALID(TestCase::SetReloadTestScript(kReloadScript));
EXPECT_ERROR(SimpleInvokeError(lib, "main"), "is abstract");
}
TEST_CASE(IsolateReload_PendingStaticCall_DefinedToNSM) {
const char* kScript =
"import 'file:///test:isolate_reload_helper';\n"
"class C {\n"
" static foo() => 'static';\n"
" test() {\n"
" reloadTest();\n"
" return C.foo();\n"
" }\n"
"}\n"
"main() {\n"
" try {\n"
" return new C().test();\n"
" } catch (e) {\n"
" return 'exception';\n"
" }\n"
"}\n";
Dart_Handle lib = TestCase::LoadTestScript(kScript, nullptr);
EXPECT_VALID(lib);
const char* kReloadScript =
"import 'file:///test:isolate_reload_helper';\n"
"class C {\n"
" test() {\n"
" reloadTest();\n"
" return C.foo();\n"
" }\n"
"}\n"
"main() {\n"
" try {\n"
" return new C().test();\n"
" } catch (e) {\n"
" return 'exception';\n"
" }\n"
"}\n";
EXPECT_VALID(TestCase::SetReloadTestScript(kReloadScript));
const char* expected = "exception";
const char* result = SimpleInvokeStr(lib, "main");
EXPECT_NOTNULL(result);
// Bail out if we've already failed so we don't crash in StringEquals.
if (result == nullptr) {
return;
}
EXPECT_STREQ(expected, result);
lib = Dart_RootLibrary();
EXPECT_NON_NULL(lib);
EXPECT_STREQ(expected, SimpleInvokeStr(lib, "main"));
}
TEST_CASE(IsolateReload_PendingStaticCall_NSMToDefined) {
const char* kScript =
"import 'file:///test:isolate_reload_helper';\n"
"class C {\n"
" test() {\n"
" reloadTest();\n"
" return C.foo();\n"
" }\n"
"}\n"
"main() {\n"
" try {\n"
" return new C().test();\n"
" } catch (e) {\n"
" return 'exception';\n"
" }\n"
"}\n";
Dart_Handle lib = TestCase::LoadTestScript(kScript, nullptr);
EXPECT_VALID(lib);
const char* kReloadScript =
"import 'file:///test:isolate_reload_helper';\n"
"class C {\n"
" static foo() => 'static';\n"
" test() {\n"
" reloadTest();\n"
" return C.foo();\n"
" }\n"
"}\n"
"main() {\n"
" try {\n"
" return new C().test();\n"
" } catch (e) {\n"
" return 'exception';\n"
" }\n"
"}\n";
EXPECT_VALID(TestCase::SetReloadTestScript(kReloadScript));
const char* expected = "static";
const char* result = SimpleInvokeStr(lib, "main");
// Bail out if we've already failed so we don't crash in the tag handler.
if (result == nullptr) {
return;
}
EXPECT_STREQ(expected, result);
lib = Dart_RootLibrary();
EXPECT_NON_NULL(lib);
EXPECT_STREQ(expected, SimpleInvokeStr(lib, "main"));
}
TEST_CASE(IsolateReload_PendingSuperCall) {
const char* kScript =
"import 'file:///test:isolate_reload_helper';\n"
"class S {\n"
" foo() => 1;\n"
"}\n"
"class C extends S {\n"
" foo() => 100;\n"
" test() {\n"
" var n = super.foo();\n"
" reloadTest();\n"
" return n + super.foo();\n"
" }\n"
"}\n"
"main() {\n"
" return new C().test();\n"
"}\n";
Dart_Handle lib = TestCase::LoadTestScript(kScript, nullptr);
EXPECT_VALID(lib);
const char* kReloadScript =
"import 'file:///test:isolate_reload_helper';\n"
"class S {\n"
" foo() => 10;\n"
"}\n"
"class C extends S {\n"
" foo() => 100;\n"
" test() {\n"
" var n = super.foo();\n"
" reloadTest();\n"
" return n + super.foo();\n"
" }\n"
"}\n"
"main() {\n"
" return new C().test();\n"
"}\n";
EXPECT_VALID(TestCase::SetReloadTestScript(kReloadScript));
EXPECT_EQ(11, SimpleInvoke(lib, "main"));
}
TEST_CASE(IsolateReload_TearOff_Instance_Equality) {
const char* kScript =
"import 'file:///test:isolate_reload_helper';\n"
"class C {\n"
" foo() => 'old';\n"
"}\n"
"main() {\n"
" var c = new C();\n"
" var f1 = c.foo;\n"
" reloadTest();\n"
" var f2 = c.foo;\n"
" return '${f1()} ${f2()} ${f1 == f2} ${identical(f1, f2)}';\n"
"}\n";
Dart_Handle lib = TestCase::LoadTestScript(kScript, nullptr);
EXPECT_VALID(lib);
const char* kReloadScript =
"import 'file:///test:isolate_reload_helper';\n"
"class C {\n"
" foo() => 'new';\n"
"}\n"
"main() {\n"
" var c = new C();\n"
" var f1 = c.foo;\n"
" reloadTest();\n"
" var f2 = c.foo;\n"
" return '${f1()} ${f2()} ${f1 == f2} ${identical(f1, f2)}';\n"
"}\n";
EXPECT_VALID(TestCase::SetReloadTestScript(kReloadScript));
EXPECT_STREQ("new new true false", SimpleInvokeStr(lib, "main"));
lib = Dart_RootLibrary();
EXPECT_NON_NULL(lib);
}
TEST_CASE(IsolateReload_TearOff_Parameter_Count_Mismatch) {
const char* kScript =
"import 'file:///test:isolate_reload_helper';\n"
"class C {\n"
" static foo() => 'old';\n"
"}\n"
"main() {\n"
" var f1 = C.foo;\n"
" reloadTest();\n"
" return f1();\n"
"}\n";
Dart_Handle lib = TestCase::LoadTestScript(kScript, nullptr);
EXPECT_VALID(lib);
const char* kReloadScript =
"import 'file:///test:isolate_reload_helper';\n"
"class C {\n"
" static foo(i) => 'new:$i';\n"
"}\n"
"main() {\n"
" var f1 = C.foo;\n"
" reloadTest();\n"
" return f1();\n"
"}\n";
TestCase::SetReloadTestScript(kReloadScript);
Dart_Handle error_handle = SimpleInvokeError(lib, "main");
const char* error;
error =
"/test-lib:8:12: Error: Too few positional"
" arguments: 1 required, 0 given.\n"
" return f1();";
EXPECT_ERROR(error_handle, error);
}
TEST_CASE(IsolateReload_TearOff_Remove) {
const char* kScript =
"import 'file:///test:isolate_reload_helper';\n"
"class C {\n"
" static foo({String bar = 'bar'}) => 'old';\n"
"}\n"
"main() {\n"
" var f1 = C.foo;\n"
" reloadTest();\n"
" try {\n"
" return f1();\n"
" } catch(e) { return '$e'; }\n"
"}\n";
Dart_Handle lib = TestCase::LoadTestScript(kScript, nullptr);
EXPECT_VALID(lib);
const char* kReloadScript =
"import 'file:///test:isolate_reload_helper';\n"
"class C {\n"
"}\n"
"main() {\n"
" var f1;\n"
" reloadTest();\n"
" try {\n"
" return f1();\n"
" } catch(e) { return '$e'; }\n"
"}\n";
TestCase::SetReloadTestScript(kReloadScript);
EXPECT_SUBSTRING(
"NoSuchMethodError: No static method 'foo' declared in class 'C'.",
SimpleInvokeStr(lib, "main"));
lib = Dart_RootLibrary();
EXPECT_NON_NULL(lib);
}
TEST_CASE(IsolateReload_TearOff_Class_Identity) {
const char* kScript =
"import 'file:///test:isolate_reload_helper';\n"
"class C {\n"
" static foo() => 'old';\n"
"}\n"
"getFoo() => C.foo;\n"
"main() {\n"
" var f1 = getFoo();\n"
" reloadTest();\n"
" var f2 = getFoo();\n"
" return '${f1()} ${f2()} ${f1 == f2} ${identical(f1, f2)}';\n"
"}\n";
Dart_Handle lib = TestCase::LoadTestScript(kScript, nullptr);
EXPECT_VALID(lib);
const char* kReloadScript =
"import 'file:///test:isolate_reload_helper';\n"
"class C {\n"
" static foo() => 'new';\n"
"}\n"
"getFoo() => C.foo;\n"
"main() {\n"
" var f1 = getFoo();\n"
" reloadTest();\n"
" var f2 = getFoo();\n"
" return '${f1()} ${f2()} ${f1 == f2} ${identical(f1, f2)}';\n"
"}\n";
EXPECT_VALID(TestCase::SetReloadTestScript(kReloadScript));
EXPECT_STREQ("new new true true", SimpleInvokeStr(lib, "main"));
lib = Dart_RootLibrary();
EXPECT_NON_NULL(lib);
}
TEST_CASE(IsolateReload_TearOff_Library_Identity) {
const char* kScript =
"import 'file:///test:isolate_reload_helper';\n"
"foo() => 'old';\n"
"getFoo() => foo;\n"
"main() {\n"
" var f1 = getFoo();\n"
" reloadTest();\n"
" var f2 = getFoo();\n"
" return '${f1()} ${f2()} ${f1 == f2} ${identical(f1, f2)}';\n"
"}\n";
Dart_Handle lib = TestCase::LoadTestScript(kScript, nullptr);
EXPECT_VALID(lib);
const char* kReloadScript =
"import 'file:///test:isolate_reload_helper';\n"
"foo() => 'new';\n"
"getFoo() => foo;\n"
"main() {\n"
" var f1 = getFoo();\n"
" reloadTest();\n"
" var f2 = getFoo();\n"
" return '${f1()} ${f2()} ${f1 == f2} ${identical(f1, f2)}';\n"
"}\n";
EXPECT_VALID(TestCase::SetReloadTestScript(kReloadScript));
EXPECT_STREQ("new new true true", SimpleInvokeStr(lib, "main"));
lib = Dart_RootLibrary();
EXPECT_NON_NULL(lib);
}
TEST_CASE(IsolateReload_TearOff_List_Set) {
const char* kScript =
"import 'file:///test:isolate_reload_helper';\n"
"class C {\n"
" foo() => 'old';\n"
"}\n"
"List list = List<dynamic>.filled(2, null);\n"
"Set set = Set();\n"
"main() {\n"
" var c = C();\n"
" list[0] = c.foo;\n"
" list[1] = c.foo;\n"
" set.add(c.foo);\n"
" set.add(c.foo);\n"
" int countBefore = set.length;\n"
" reloadTest();\n"
" list[1] = c.foo;\n"
" set.add(c.foo);\n"
" set.add(c.foo);\n"
" int countAfter = set.length;\n"
" return '${list[0]()} ${list[1]()} ${list[0] == list[1]} '\n"
" '${countBefore == 1} ${countAfter == 1} ${(set.first)()} '\n"
" '${set.first == c.foo} ${set.first == c.foo} '\n"
" '${set.remove(c.foo)}';\n"
"}\n";
Dart_Handle lib = TestCase::LoadTestScript(kScript, nullptr);
EXPECT_VALID(lib);
const char* kReloadScript =
"import 'file:///test:isolate_reload_helper';\n"
"class C {\n"
" foo() => 'new';\n"
"}\n"
"List list = List<dynamic>.filled(2, null);\n"
"Set set = Set();\n"
"main() {\n"
" var c = C();\n"
" list[0] = c.foo;\n"
" list[1] = c.foo;\n"
" set.add(c.foo);\n"
" set.add(c.foo);\n"
" int countBefore = set.length;\n"
" reloadTest();\n"
" list[1] = c.foo;\n"
" set.add(c.foo);\n"
" set.add(c.foo);\n"
" int countAfter = set.length;\n"
" return '${list[0]()} ${list[1]()} ${list[0] == list[1]} '\n"
" '${countBefore == 1} ${countAfter == 1} ${(set.first)()} '\n"
" '${set.first == c.foo} ${set.first == c.foo} '\n"
" '${set.remove(c.foo)}';\n"
"}\n";
EXPECT_VALID(TestCase::SetReloadTestScript(kReloadScript));
EXPECT_STREQ("new new true true true new true true true",
SimpleInvokeStr(lib, "main"));
lib = Dart_RootLibrary();
EXPECT_NON_NULL(lib);
}
TEST_CASE(IsolateReload_TearOff_AddArguments) {
const char* kScript =
"import 'file:///test:isolate_reload_helper';\n"
"class C {\n"
" foo(x) => x;\n"
"}\n"
"invoke(f, a) {\n"
" try {\n"
" return f(a);\n"
" } catch (e) {\n"
" return e.toString().split('\\n').first;\n"
" }\n"
"}\n"
"main() {\n"
" var c = new C();\n"
" var f = c.foo;\n"
" var r1 = invoke(f, 1);\n"
" reloadTest();\n"
" var r2 = invoke(f, 1);\n"
" return '$r1 $r2';\n"
"}\n";
Dart_Handle lib = TestCase::LoadTestScript(kScript, nullptr);
EXPECT_VALID(lib);
const char* kReloadScript =
"import 'file:///test:isolate_reload_helper';\n"
"class C {\n"
" foo(x, y, z) => x + y + z;\n"
"}\n"
"invoke(f, a) {\n"
" try {\n"
" return f(a);\n"
" } catch (e) {\n"
" return e.toString().split('\\n').first;\n"
" }\n"
"}\n"
"main() {\n"
" var c = new C();\n"
" var f = c.foo;\n"
" var r1 = invoke(f, 1);\n"
" reloadTest();\n"
" var r2 = invoke(f, 1);\n"
" return '$r1 $r2';\n"
"}\n";
EXPECT_VALID(TestCase::SetReloadTestScript(kReloadScript));
EXPECT_STREQ(
"1 NoSuchMethodError: Class 'C' has no instance method "
"'foo' with matching arguments.",
SimpleInvokeStr(lib, "main"));
lib = Dart_RootLibrary();
EXPECT_NON_NULL(lib);
}
TEST_CASE(IsolateReload_TearOff_AddArguments2) {
const char* kScript =
"import 'file:///test:isolate_reload_helper';\n"
"class C {\n"
" static foo(x) => x;\n"
"}\n"
"invoke(f, a) {\n"
" try {\n"
" return f(a);\n"
" } catch (e) {\n"
" return e.toString().split('\\n').first;\n"
" }\n"
"}\n"
"main() {\n"
" var f = C.foo;\n"
" var r1 = invoke(f, 1);\n"
" reloadTest();\n"
" var r2 = invoke(f, 1);\n"
" return '$r1 $r2';\n"
"}\n";
Dart_Handle lib = TestCase::LoadTestScript(kScript, nullptr);
EXPECT_VALID(lib);
const char* kReloadScript =
"import 'file:///test:isolate_reload_helper';\n"
"class C {\n"
" static foo(x, y, z) => x + y + z;\n"
"}\n"
"invoke(f, a) {\n"
" try {\n"
" return f(a);\n"
" } catch (e) {\n"
" return e.toString().split('\\n').first;\n"
" }\n"
"}\n"
"main() {\n"
" var f = C.foo;\n"
" var r1 = invoke(f, 1);\n"
" reloadTest();\n"
" var r2 = invoke(f, 1);\n"
" return '$r1 $r2';\n"
"}\n";
EXPECT_VALID(TestCase::SetReloadTestScript(kReloadScript));
EXPECT_STREQ(
"1 NoSuchMethodError: Closure call with mismatched arguments: "
"function 'C.foo'",
SimpleInvokeStr(lib, "main"));
lib = Dart_RootLibrary();
EXPECT_NON_NULL(lib);
}
TEST_CASE(IsolateReload_EnumEquality) {
const char* kScript =
"enum Fruit {\n"
" Apple,\n"
" Banana,\n"
"}\n"
"var x;\n"
"main() {\n"
" x = Fruit.Banana;\n"
" return Fruit.Apple.toString();\n"
"}\n";
Dart_Handle lib = TestCase::LoadTestScript(kScript, nullptr);
EXPECT_VALID(lib);
EXPECT_STREQ("Fruit.Apple", SimpleInvokeStr(lib, "main"));
const char* kReloadScript =
"enum Fruit {\n"
" Apple,\n"
" Banana,\n"
"}\n"
"var x;\n"
"main() {\n"
" if (x == Fruit.Banana) {\n"
" return 'yes';\n"
" } else {\n"
" return 'no';\n"
" }\n"
"}\n";
lib = TestCase::ReloadTestScript(kReloadScript);
EXPECT_VALID(lib);
EXPECT_STREQ("yes", SimpleInvokeStr(lib, "main"));
}
TEST_CASE(IsolateReload_EnumIdentical) {
const char* kScript =
"enum Fruit {\n"
" Apple,\n"
" Banana,\n"
"}\n"
"var x;\n"
"main() {\n"
" x = Fruit.Banana;\n"
" return Fruit.Apple.toString();\n"
"}\n";
Dart_Handle lib = TestCase::LoadTestScript(kScript, nullptr);
EXPECT_VALID(lib);
EXPECT_STREQ("Fruit.Apple", SimpleInvokeStr(lib, "main"));
const char* kReloadScript =
"enum Fruit {\n"
" Apple,\n"
" Banana,\n"
"}\n"
"var x;\n"
"main() {\n"
" if (identical(x, Fruit.Banana)) {\n"
" return 'yes';\n"
" } else {\n"
" return 'no';\n"
" }\n"
"}\n";
lib = TestCase::ReloadTestScript(kReloadScript);
EXPECT_VALID(lib);
EXPECT_STREQ("yes", SimpleInvokeStr(lib, "main"));
}
TEST_CASE(IsolateReload_EnumReorderIdentical) {
const char* kScript =
"enum Fruit {\n"
" Apple,\n"
" Banana,\n"
"}\n"
"var x;\n"
"main() {\n"
" x = Fruit.Banana;\n"
" return Fruit.Apple.toString();\n"
"}\n";
Dart_Handle lib = TestCase::LoadTestScript(kScript, nullptr);
EXPECT_VALID(lib);
EXPECT_STREQ("Fruit.Apple", SimpleInvokeStr(lib, "main"));
const char* kReloadScript =
"enum Fruit {\n"
" Banana,\n"
" Apple,\n"
"}\n"
"var x;\n"
"main() {\n"
" if (identical(x, Fruit.Banana)) {\n"
" return 'yes';\n"
" } else {\n"
" return 'no';\n"
" }\n"
"}\n";
lib = TestCase::ReloadTestScript(kReloadScript);
EXPECT_VALID(lib);
EXPECT_STREQ("yes", SimpleInvokeStr(lib, "main"));
}
TEST_CASE(IsolateReload_EnumAddition) {
const char* kScript =
"enum Fruit {\n"
" Apple,\n"
" Banana,\n"
"}\n"
"var x;\n"
"main() {\n"
" return Fruit.Apple.toString();\n"
"}\n";
Dart_Handle lib = TestCase::LoadTestScript(kScript, nullptr);
EXPECT_VALID(lib);
EXPECT_STREQ("Fruit.Apple", SimpleInvokeStr(lib, "main"));
const char* kReloadScript =
"enum Fruit {\n"
" Apple,\n"
" Cantaloupe,\n"
" Banana,\n"
"}\n"
"var x;\n"
"main() {\n"
" String r = '${Fruit.Apple.index}/${Fruit.Apple} ';\n"
" r += '${Fruit.Cantaloupe.index}/${Fruit.Cantaloupe} ';\n"
" r += '${Fruit.Banana.index}/${Fruit.Banana}';\n"
" return r;\n"
"}\n";
lib = TestCase::ReloadTestScript(kReloadScript);
EXPECT_VALID(lib);
EXPECT_STREQ("0/Fruit.Apple 1/Fruit.Cantaloupe 2/Fruit.Banana",
SimpleInvokeStr(lib, "main"));
}
TEST_CASE(IsolateReload_EnumToNotEnum) {
const char* kScript =
"enum Fruit {\n"
" Apple\n"
"}\n"
"main() {\n"
" return Fruit.Apple.toString();\n"
"}\n";
Dart_Handle lib = TestCase::LoadTestScript(kScript, nullptr);
EXPECT_VALID(lib);
EXPECT_STREQ("Fruit.Apple", SimpleInvokeStr(lib, "main"));
const char* kReloadScript =
"class Fruit {\n"
" final int zero = 0;\n"
"}\n"
"main() {\n"
" return new Fruit().zero.toString();\n"
"}\n";
Dart_Handle result = TestCase::ReloadTestScript(kReloadScript);
EXPECT_ERROR(result, "Enum class cannot be redefined to be a non-enum class");
}
TEST_CASE(IsolateReload_NotEnumToEnum) {
const char* kScript =
"class Fruit {\n"
" final int zero = 0;\n"
"}\n"
"main() {\n"
" return new Fruit().zero.toString();\n"
"}\n";
Dart_Handle lib = TestCase::LoadTestScript(kScript, nullptr);
EXPECT_VALID(lib);
EXPECT_STREQ("0", SimpleInvokeStr(lib, "main"));
const char* kReloadScript =
"enum Fruit {\n"
" Apple\n"
"}\n"
"main() {\n"
" return Fruit.Apple.toString();\n"
"}\n";
Dart_Handle result = TestCase::ReloadTestScript(kReloadScript);
EXPECT_ERROR(result, "Class cannot be redefined to be a enum class");
}
TEST_CASE(IsolateReload_EnumDelete) {
const char* kScript =
"enum Fruit {\n"
" Apple,\n"
" Banana,\n"
" Cantaloupe,\n"
"}\n"
"var x;\n"
"main() {\n"
" x = Fruit.Cantaloupe;\n"
" return Fruit.Apple.toString();\n"
"}\n";
Dart_Handle lib = TestCase::LoadTestScript(kScript, nullptr);
EXPECT_VALID(lib);
EXPECT_STREQ("Fruit.Apple", SimpleInvokeStr(lib, "main"));
// Delete 'Cantaloupe' but make sure that we can still invoke toString,
// and access the hashCode and index properties.
const char* kReloadScript =
"enum Fruit {\n"
" Apple,\n"
" Banana,\n"
"}\n"
"var x;\n"
"main() {\n"
" String r = '$x ${x.hashCode is int} ${x.index}';\n"
" return r;\n"
"}\n";
lib = TestCase::ReloadTestScript(kReloadScript);
EXPECT_VALID(lib);
EXPECT_STREQ("Fruit.Deleted enum value from Fruit true -1",
SimpleInvokeStr(lib, "main"));
}
TEST_CASE(IsolateReload_EnumIdentityReload) {
const char* kScript =
"enum Fruit {\n"
" Apple,\n"
" Banana,\n"
" Cantaloupe,\n"
"}\n"
"var x;\n"
"var y;\n"
"var z;\n"
"var w;\n"
"main() {\n"
" x = { Fruit.Apple: Fruit.Apple.index,\n"
" Fruit.Banana: Fruit.Banana.index,\n"
" Fruit.Cantaloupe: Fruit.Cantaloupe.index};\n"
" y = Fruit.Apple;\n"
" z = Fruit.Banana;\n"
" w = Fruit.Cantaloupe;\n"
" return Fruit.Apple.toString();\n"
"}\n";
Dart_Handle lib = TestCase::LoadTestScript(kScript, nullptr);
EXPECT_VALID(lib);
EXPECT_STREQ("Fruit.Apple", SimpleInvokeStr(lib, "main"));
const char* kReloadScript =
"enum Fruit {\n"
" Apple,\n"
" Banana,\n"
" Cantaloupe,\n"
"}\n"
"var x;\n"
"var y;\n"
"var z;\n"
"var w;\n"
"bool identityCheck(Fruit f, int index) {\n"
" return identical(Fruit.values[index], f);\n"
"}\n"
"main() {\n"
" String r = '';\n"
" x.forEach((key, value) {\n"
" r += '${identityCheck(key, value)} ';\n"
" });\n"
" r += '${x[Fruit.Apple] == Fruit.Apple.index} ';\n"
" r += '${x[Fruit.Banana] == Fruit.Banana.index} ';\n"
" r += '${x[Fruit.Cantaloupe] == Fruit.Cantaloupe.index} ';\n"
" r += '${identical(y, Fruit.values[x[Fruit.Apple]])} ';\n"
" r += '${identical(z, Fruit.values[x[Fruit.Banana]])} ';\n"
" r += '${identical(w, Fruit.values[x[Fruit.Cantaloupe]])} ';\n"
" return r;\n"
"}\n";
lib = TestCase::ReloadTestScript(kReloadScript);
EXPECT_VALID(lib);
EXPECT_STREQ("true true true true true true true true true ",
SimpleInvokeStr(lib, "main"));
}
TEST_CASE(IsolateReload_EnumShapeChange) {
const char* kScript =
"enum Fruit { Apple, Banana }\n"
"var retained;\n"
"main() {\n"
" retained = Fruit.Apple;\n"
" return retained.toString();\n"
"}\n";
Dart_Handle lib = TestCase::LoadTestScript(kScript, nullptr);
EXPECT_VALID(lib);
EXPECT_STREQ("Fruit.Apple", SimpleInvokeStr(lib, "main"));
const char* kReloadScript =
"enum Fruit {\n"
" Apple('Apple', 'A'),\n"
" Banana('Banana', 'B');\n"
" const Fruit(this.name, this.initial);\n"
" final String name;\n"
" final String initial;\n"
"}\n"
"var retained;\n"
"main() {\n"
" return retained.initial;\n"
"}\n";
lib = TestCase::ReloadTestScript(kReloadScript);
EXPECT_VALID(lib);
EXPECT_STREQ("A", SimpleInvokeStr(lib, "main"));
}
TEST_CASE(IsolateReload_EnumShapeChangeAdd) {
const char* kScript =
"enum Fruit { Apple, Banana }\n"
"var retained;\n"
"main() {\n"
" retained = Fruit.Apple;\n"
" return retained.toString();\n"
"}\n";
Dart_Handle lib = TestCase::LoadTestScript(kScript, nullptr);
EXPECT_VALID(lib);
EXPECT_STREQ("Fruit.Apple", SimpleInvokeStr(lib, "main"));
const char* kReloadScript =
"enum Fruit {\n"
" Apple('Apple', 'A'),\n"
" Banana('Banana', 'B'),\n"
" Cherry('Cherry', 'C');\n"
" const Fruit(this.name, this.initial);\n"
" final String name;\n"
" final String initial;\n"
"}\n"
"var retained;\n"
"main() {\n"
" return Fruit.Cherry.initial;\n"
"}\n";
lib = TestCase::ReloadTestScript(kReloadScript);
EXPECT_VALID(lib);
EXPECT_STREQ("C", SimpleInvokeStr(lib, "main"));
}
TEST_CASE(IsolateReload_EnumShapeChangeRemove) {
const char* kScript =
"enum Fruit { Apple, Banana }\n"
"var retained;\n"
"main() {\n"
" retained = Fruit.Banana;\n"
" return retained.toString();\n"
"}\n";
Dart_Handle lib = TestCase::LoadTestScript(kScript, nullptr);
EXPECT_VALID(lib);
EXPECT_STREQ("Fruit.Banana", SimpleInvokeStr(lib, "main"));
const char* kReloadScript =
"enum Fruit {\n"
" Apple('Apple', 'A');\n"
" const Fruit(this.name, this.initial);\n"
" final String name;\n"
" final String initial;\n"
"}\n"
"var retained;\n"
"main() {\n"
" return retained.toString();\n"
"}\n";
lib = TestCase::ReloadTestScript(kReloadScript);
EXPECT_VALID(lib);
EXPECT_STREQ("Fruit.Deleted enum value from Fruit",
SimpleInvokeStr(lib, "main"));
}
TEST_CASE(IsolateReload_EnumReferentShapeChangeAdd) {
const char* kScript =
"class Box {\n"
" final x;\n"
" const Box(this.x);\n"
"}\n"
"enum Fruit {\n"
" Apple('Apple', const Box('A')),\n"
" Banana('Banana', const Box('B')),\n"
" Cherry('Cherry', const Box('C')),\n"
" Durian('Durian', const Box('D')),\n"
" Elderberry('Elderberry', const Box('E')),\n"
" Fig('Fig', const Box('F')),\n"
" Grape('Grape', const Box('G')),\n"
" Huckleberry('Huckleberry', const Box('H')),\n"
" Jackfruit('Jackfruit', const Box('J'));\n"
" const Fruit(this.name, this.initial);\n"
" final String name;\n"
" final Box initial;\n"
"}\n"
"var retained;\n"
"main() {\n"
" retained = Fruit.Apple;\n"
" return retained.toString();\n"
"}\n";
Dart_Handle lib = TestCase::LoadTestScript(kScript, nullptr);
EXPECT_VALID(lib);
EXPECT_STREQ("Fruit.Apple", SimpleInvokeStr(lib, "main"));
const char* kReloadScript =
"class Box {\n"
" final x;\n"
" final y;\n"
" final z;\n"
" const Box(this.x, this.y, this.z);\n"
"}\n"
"enum Fruit {\n"
" Apple('Apple', const Box('A', 0, 0)),\n"
" Banana('Banana', const Box('B', 0, 0)),\n"
" Cherry('Cherry', const Box('C', 0, 0)),\n"
" Durian('Durian', const Box('D', 0, 0)),\n"
" Elderberry('Elderberry', const Box('E', 0, 0)),\n"
" Fig('Fig', const Box('F', 0, 0)),\n"
" Grape('Grape', const Box('G', 0, 0)),\n"
" Huckleberry('Huckleberry', const Box('H', 0, 0)),\n"
" Jackfruit('Jackfruit', const Box('J', 0, 0)),\n"
" Lemon('Lemon', const Box('L', 0, 0));\n"
" const Fruit(this.name, this.initial);\n"
" final String name;\n"
" final Box initial;\n"
"}\n"
"var retained;\n"
"main() {\n"
" return retained.toString();\n"
"}\n";
lib = TestCase::ReloadTestScript(kReloadScript);
EXPECT_VALID(lib);
EXPECT_STREQ("Fruit.Apple", SimpleInvokeStr(lib, "main"));
}
TEST_CASE(IsolateReload_EnumRetainedHash) {
const char* kScript = R"(
enum A {
A1(B.B1, 1),
A2(null, 2),
A3(B.B3, 3);
const A(this.a, this.x);
final a;
final x;
}
enum B {
B1(C.C1),
B2(C.C2),
B3(null);
const B(this.b);
final b;
}
enum C {
C1(null),
C2(A.A2),
C3(A.A3);
const C(this.c);
final c;
}
var a1;
var a1_hash;
var a2;
var a2_hash;
var a3;
var a3_hash;
var b1;
var b1_hash;
var b2;
var b2_hash;
var b3;
var b3_hash;
var c1;
var c1_hash;
var c2;
var c2_hash;
var c3;
var c3_hash;
main() {
a1 = A.A1;
a1_hash = a1.hashCode;
a2 = A.A2;
a2_hash = a2.hashCode;
a3 = A.A3;
a3_hash = a3.hashCode;
b1 = B.B1;
b1_hash = b1.hashCode;
b2 = B.B2;
b2_hash = b2.hashCode;
b3 = B.B3;
b3_hash = b3.hashCode;
c1 = C.C1;
c1_hash = c1.hashCode;
c2 = C.C2;
c2_hash = c2.hashCode;
c3 = C.C3;
c3_hash = c3.hashCode;
return 'okay';
}
)";
Dart_Handle lib = TestCase::LoadTestScript(kScript, nullptr);
EXPECT_VALID(lib);
EXPECT_STREQ("okay", SimpleInvokeStr(lib, "main"));
const char* kReloadScript = R"(
enum A {
A1(B.B1),
A2(null),
A3(B.B3);
const A(this.a);
final a;
}
enum B {
B1(C.C1, 1),
B2(C.C2, 2),
B3(null, 3);
const B(this.b, this.x);
final b;
final x;
}
enum C {
C1(null),
C2(A.A2),
C3(A.A3);
const C(this.c);
final c;
}
var a1;
var a1_hash;
var a2;
var a2_hash;
var a3;
var a3_hash;
var b1;
var b1_hash;
var b2;
var b2_hash;
var b3;
var b3_hash;
var c1;
var c1_hash;
var c2;
var c2_hash;
var c3;
var c3_hash;
main() {
if (!identical(a1, A.A1)) return "i-a1";
if (a1.hashCode != A.A1.hashCode) return "h-a1";
if (!identical(a2, A.A2)) return "i-a2";
if (a2.hashCode != A.A2.hashCode) return "h-a2";
if (!identical(a3, A.A3)) return "i-a3";
if (a3.hashCode != A.A3.hashCode) return "h-a3";
if (!identical(b1, B.B1)) return "i-b1";
if (b1.hashCode != B.B1.hashCode) return "h-b1";
if (!identical(b2, B.B2)) return "i-b2";
if (b2.hashCode != B.B2.hashCode) return "h-b2";
if (!identical(b3, B.B3)) return "i-b3";
if (b3.hashCode != B.B3.hashCode) return "h-b3";
if (!identical(c1, C.C1)) return "i-c1";
if (c1.hashCode != C.C1.hashCode) return "h-c1";
if (!identical(c2, C.C2)) return "i-c2";
if (c2.hashCode != C.C2.hashCode) return "h-c2";
if (!identical(c3, C.C3)) return "i-c3";
if (c3.hashCode != C.C3.hashCode) return "h-c3";
return 'okay';
}
)";
lib = TestCase::ReloadTestScript(kReloadScript);
EXPECT_VALID(lib);
EXPECT_STREQ("okay", SimpleInvokeStr(lib, "main"));
}
TEST_CASE(IsolateReload_ConstantIdentical) {
const char* kScript =
"class Fruit {\n"
" final String name;\n"
" const Fruit(this.name);\n"
" String toString() => name;\n"
"}\n"
"var x;\n"
"main() {\n"
" x = const Fruit('Pear');\n"
" return x.toString();\n"
"}\n";
Dart_Handle lib = TestCase::LoadTestScript(kScript, nullptr);
EXPECT_VALID(lib);
EXPECT_STREQ("Pear", SimpleInvokeStr(lib, "main"));
const char* kReloadScript =
"class Fruit {\n"
" final String name;\n"
" const Fruit(this.name);\n"
" String toString() => name;\n"
"}\n"
"var x;\n"
"main() {\n"
" if (identical(x, const Fruit('Pear'))) {\n"
" return 'yes';\n"
" } else {\n"
" return 'no';\n"
" }\n"
"}\n";
lib = TestCase::ReloadTestScript(kReloadScript);
EXPECT_VALID(lib);
EXPECT_STREQ("yes", SimpleInvokeStr(lib, "main"));
}
TEST_CASE(IsolateReload_CallDeleted_TopLevelFunction) {
const char* kScript =
"deleted() { return 'hello'; }\n"
"var retained;\n"
"main() {\n"
" retained = () => deleted();\n"
" return retained();\n"
"}\n";
Dart_Handle lib = TestCase::LoadTestScript(kScript, NULL);
EXPECT_VALID(lib);
EXPECT_STREQ("hello", SimpleInvokeStr(lib, "main"));
const char* kReloadScript =
"var retained;\n"
"main() {\n"
" try {\n"
" return retained();\n"
" } catch (e) {\n"
" return e.toString();\n"
" }\n"
"}\n";
lib = TestCase::ReloadTestScript(kReloadScript);
EXPECT_VALID(lib);
const char* result = SimpleInvokeStr(lib, "main");
EXPECT_SUBSTRING("NoSuchMethodError", result);
EXPECT_SUBSTRING("deleted", result);
}
TEST_CASE(IsolateReload_CallDeleted_TopLevelFunctionArityChange) {
const char* kScript =
"deleted() { return 'hello'; }\n"
"var retained;\n"
"main() {\n"
" retained = () => deleted();\n"
" return retained();\n"
"}\n";
Dart_Handle lib = TestCase::LoadTestScript(kScript, NULL);
EXPECT_VALID(lib);
EXPECT_STREQ("hello", SimpleInvokeStr(lib, "main"));
const char* kReloadScript =
"deleted(newParameter) { return 'hello'; }\n"
"var retained;\n"
"main() {\n"
" try {\n"
" return retained();\n"
" } catch (e) {\n"
" return e.toString();\n"
" }\n"
"}\n";
lib = TestCase::ReloadTestScript(kReloadScript);
EXPECT_VALID(lib);
const char* result = SimpleInvokeStr(lib, "main");
EXPECT_SUBSTRING("NoSuchMethodError", result);
EXPECT_SUBSTRING("deleted", result);
}
TEST_CASE(IsolateReload_CallDeleted_TopLevelAddTypeArguments) {
const char* kScript =
"deleted() { return 'hello'; }\n"
"var retained;\n"
"main() {\n"
" retained = () => deleted();\n"
" return retained();\n"
"}\n";
Dart_Handle lib = TestCase::LoadTestScript(kScript, NULL);
EXPECT_VALID(lib);
EXPECT_STREQ("hello", SimpleInvokeStr(lib, "main"));
const char* kReloadScript =
"deleted<A, B, C>() { return 'hello'; }\n"
"var retained;\n"
"main() {\n"
" try {\n"
" return retained();\n"
" } catch (e) {\n"
" return e.toString();\n"
" }\n"
"}\n";
lib = TestCase::ReloadTestScript(kReloadScript);
EXPECT_VALID(lib);
EXPECT_STREQ("hello", SimpleInvokeStr(lib, "main"));
}
TEST_CASE(IsolateReload_CallDeleted_TopLevelRemoveTypeArguments) {
const char* kScript =
"deleted<A, B, C>() { return 'hello'; }\n"
"var retained;\n"
"main() {\n"
" retained = () => deleted<int, int, int>();\n"
" return retained();\n"
"}\n";
Dart_Handle lib = TestCase::LoadTestScript(kScript, NULL);
EXPECT_VALID(lib);
EXPECT_STREQ("hello", SimpleInvokeStr(lib, "main"));
const char* kReloadScript =
"deleted() { return 'hello'; }\n"
"var retained;\n"
"main() {\n"
" try {\n"
" return retained();\n"
" } catch (e) {\n"
" return e.toString();\n"
" }\n"
"}\n";
lib = TestCase::ReloadTestScript(kReloadScript);
EXPECT_VALID(lib);
const char* result = SimpleInvokeStr(lib, "main");
EXPECT_SUBSTRING("NoSuchMethodError", result);
EXPECT_SUBSTRING("deleted", result);
}
TEST_CASE(IsolateReload_CallDeleted_TopLevelMissingPassingTypeArguments) {
const char* kScript =
"deleted<A, B, C>() { return 'hello'; }\n"
"var retained;\n"
"main() {\n"
" retained = () => deleted<int, int, int>();\n"
" return retained();\n"
"}\n";
Dart_Handle lib = TestCase::LoadTestScript(kScript, NULL);
EXPECT_VALID(lib);
EXPECT_STREQ("hello", SimpleInvokeStr(lib, "main"));
const char* kReloadScript =
"var retained;\n"
"main() {\n"
" try {\n"
" return retained();\n"
" } catch (e) {\n"
" return e.toString();\n"
" }\n"
"}\n";
lib = TestCase::ReloadTestScript(kReloadScript);
EXPECT_VALID(lib);
const char* result = SimpleInvokeStr(lib, "main");
EXPECT_SUBSTRING("NoSuchMethodError", result);
EXPECT_SUBSTRING("deleted", result);
}
TEST_CASE(IsolateReload_CallDeleted_TopLevelFunctionEvaluationOrder) {
const char* kScript =
"first(flag) { if (flag) throw 'first!'; }\n"
"deleted(_) { return 'hello'; }\n"
"var retained;\n"
"main() {\n"
" retained = (bool flag) => deleted(first(flag));\n"
" return retained(false);\n"
"}\n";
Dart_Handle lib = TestCase::LoadTestScript(kScript, NULL);
EXPECT_VALID(lib);
EXPECT_STREQ("hello", SimpleInvokeStr(lib, "main"));
const char* kReloadScript =
"first(flag) { if (flag) throw 'first!'; }\n"
"var retained;\n"
"main() {\n"
" try {\n"
" return retained(true);\n"
" } catch (e) {\n"
" return e.toString();\n"
" }\n"
"}\n";
lib = TestCase::ReloadTestScript(kReloadScript);
EXPECT_VALID(lib);
const char* result = SimpleInvokeStr(lib, "main");
EXPECT_STREQ("first!", result); // Not NoSuchMethodError
}
TEST_CASE(IsolateReload_CallDeleted_TopLevelFunctionLibraryDeleted) {
// clang-format off
Dart_SourceFile sourcefiles[] = {
{
"file:///test-app.dart",
"import 'test-lib.dart';\n"
"var retained;\n"
"main() {\n"
" retained = () => deleted();\n"
" return retained();\n"
"}\n",
},
{
"file:///test-lib.dart",
"deleted() { return 'hello'; }\n",
},
};
// clang-format on
Dart_Handle lib = TestCase::LoadTestScriptWithDFE(
sizeof(sourcefiles) / sizeof(Dart_SourceFile), sourcefiles,
NULL /* resolver */, true /* finalize */, true /* incrementally */);
EXPECT_VALID(lib);
EXPECT_STREQ("hello", SimpleInvokeStr(lib, "main"));
// clang-format off
Dart_SourceFile updated_sourcefiles[] = {
{
"file:///test-app.dart",
"var retained;\n"
"main() {\n"
" try {\n"
" return retained();\n"
" } catch (e) {\n"
" return e.toString();\n"
" }\n"
"}\n",
},
};
// clang-format on
const uint8_t* kernel_buffer = NULL;
intptr_t kernel_buffer_size = 0;
char* error = TestCase::CompileTestScriptWithDFE(
"file:///test-app.dart",
sizeof(updated_sourcefiles) / sizeof(Dart_SourceFile),
updated_sourcefiles, &kernel_buffer, &kernel_buffer_size,
true /* incrementally */);
EXPECT(error == NULL);
EXPECT_NOTNULL(kernel_buffer);
lib = TestCase::ReloadTestKernel(kernel_buffer, kernel_buffer_size);
EXPECT_VALID(lib);
const char* result = SimpleInvokeStr(lib, "main");
// What actually happens because we don't re-search imported libraries.
EXPECT_STREQ(result, "hello");
// What should happen and what did happen with the old VM frontend:
// EXPECT_SUBSTRING("NoSuchMethodError", result);
// EXPECT_SUBSTRING("deleted", result);
}
TEST_CASE(IsolateReload_CallDeleted_TopLevelGetter) {
const char* kScript =
"get deleted { return 'hello'; }\n"
"var retained;\n"
"main() {\n"
" retained = () => deleted;\n"
" return retained();\n"
"}\n";
Dart_Handle lib = TestCase::LoadTestScript(kScript, NULL);
EXPECT_VALID(lib);
EXPECT_STREQ("hello", SimpleInvokeStr(lib, "main"));
const char* kReloadScript =
"var retained;\n"
"main() {\n"
" try {\n"
" return retained();\n"
" } catch (e) {\n"
" return e.toString();\n"
" }\n"
"}\n";
lib = TestCase::ReloadTestScript(kReloadScript);
EXPECT_VALID(lib);
const char* result = SimpleInvokeStr(lib, "main");
EXPECT_SUBSTRING("NoSuchMethodError", result);
EXPECT_SUBSTRING("deleted", result);
}
TEST_CASE(IsolateReload_CallDeleted_TopLevelSetter) {
const char* kScript =
"set deleted(x) {}\n"
"var retained;\n"
"main() {\n"
" retained = () => deleted = 'hello';\n"
" return retained();\n"
"}\n";
Dart_Handle lib = TestCase::LoadTestScript(kScript, NULL);
EXPECT_VALID(lib);
EXPECT_STREQ("hello", SimpleInvokeStr(lib, "main"));
const char* kReloadScript =
"var retained;\n"
"main() {\n"
" try {\n"
" return retained();\n"
" } catch (e) {\n"
" return e.toString();\n"
" }\n"
"}\n";
lib = TestCase::ReloadTestScript(kReloadScript);
EXPECT_VALID(lib);
const char* result = SimpleInvokeStr(lib, "main");
EXPECT_SUBSTRING("NoSuchMethodError", result);
EXPECT_SUBSTRING("deleted", result);
}
TEST_CASE(IsolateReload_CallDeleted_TopLevelSetterEvaluationOrder) {
const char* kScript =
"first(flag) { if (flag) throw 'first!'; return 'hello'; }\n"
"set deleted(x) {}\n"
"var retained;\n"
"main() {\n"
" retained = (bool flag) => deleted = first(flag);\n"
" return retained(false);\n"
"}\n";
Dart_Handle lib = TestCase::LoadTestScript(kScript, NULL);
EXPECT_VALID(lib);
EXPECT_STREQ("hello", SimpleInvokeStr(lib, "main"));
const char* kReloadScript =
"first(flag) { if (flag) throw 'first!'; return 'hello'; }\n"
"var retained;\n"
"main() {\n"
" try {\n"
" return retained(true);\n"
" } catch (e) {\n"
" return e.toString();\n"
" }\n"
"}\n";
lib = TestCase::ReloadTestScript(kReloadScript);
EXPECT_VALID(lib);
const char* result = SimpleInvokeStr(lib, "main");
EXPECT_STREQ("first!", result); // Not NoSuchMethodError
}
TEST_CASE(IsolateReload_CallDeleted_ClassFunction) {
const char* kScript =
"class C { static deleted() { return 'hello'; } }\n"
"var retained;\n"
"main() {\n"
" retained = () => C.deleted();\n"
" return retained();\n"
"}\n";
Dart_Handle lib = TestCase::LoadTestScript(kScript, NULL);
EXPECT_VALID(lib);
EXPECT_STREQ("hello", SimpleInvokeStr(lib, "main"));
const char* kReloadScript =
"var retained;\n"
"main() {\n"
" try {\n"
" return retained();\n"
" } catch (e) {\n"
" return e.toString();\n"
" }\n"
"}\n";
lib = TestCase::ReloadTestScript(kReloadScript);
EXPECT_VALID(lib);
const char* result = SimpleInvokeStr(lib, "main");
EXPECT_SUBSTRING("NoSuchMethodError", result);
EXPECT_SUBSTRING("deleted", result);
}
TEST_CASE(IsolateReload_CallDeleted_ClassFunctionArityChange) {
const char* kScript =
"class C { static deleted() { return 'hello'; } }\n"
"var retained;\n"
"main() {\n"
" retained = () => C.deleted();\n"
" return retained();\n"
"}\n";
Dart_Handle lib = TestCase::LoadTestScript(kScript, NULL);
EXPECT_VALID(lib);
EXPECT_STREQ("hello", SimpleInvokeStr(lib, "main"));
const char* kReloadScript =
"class C { static deleted(newParameter) { return 'hello'; } }\n"
"var retained;\n"
"main() {\n"
" try {\n"
" return retained();\n"
" } catch (e) {\n"
" return e.toString();\n"
" }\n"
"}\n";
lib = TestCase::ReloadTestScript(kReloadScript);
EXPECT_VALID(lib);
const char* result = SimpleInvokeStr(lib, "main");
EXPECT_SUBSTRING("NoSuchMethodError", result);
EXPECT_SUBSTRING("deleted", result);
}
TEST_CASE(IsolateReload_CallDeleted_ClassFunctionEvaluationOrder) {
const char* kScript =
"first(flag) { if (flag) throw 'first!'; }\n"
"class C { static deleted(_) { return 'hello'; } }\n"
"var retained;\n"
"main() {\n"
" retained = (bool flag) => C.deleted(first(flag));\n"
" return retained(false);\n"
"}\n";
Dart_Handle lib = TestCase::LoadTestScript(kScript, NULL);
EXPECT_VALID(lib);
EXPECT_STREQ("hello", SimpleInvokeStr(lib, "main"));
const char* kReloadScript =
"first(flag) { if (flag) throw 'first!'; }\n"
"class C { }\n"
"var retained;\n"
"main() {\n"
" try {\n"
" return retained(true);\n"
" } catch (e) {\n"
" return e.toString();\n"
" }\n"
"}\n";
lib = TestCase::ReloadTestScript(kReloadScript);
EXPECT_VALID(lib);
const char* result = SimpleInvokeStr(lib, "main");
EXPECT_STREQ("first!", result); // Not NoSuchMethodError
}
TEST_CASE(IsolateReload_CallDeleted_ClassGetter) {
const char* kScript =
"class C { static get deleted { return 'hello'; } }\n"
"var retained;\n"
"main() {\n"
" retained = () => C.deleted;\n"
" return retained();\n"
"}\n";
Dart_Handle lib = TestCase::LoadTestScript(kScript, NULL);
EXPECT_VALID(lib);
EXPECT_STREQ("hello", SimpleInvokeStr(lib, "main"));
const char* kReloadScript =
"var retained;\n"
"main() {\n"
" try {\n"
" return retained();\n"
" } catch (e) {\n"
" return e.toString();\n"
" }\n"
"}\n";
lib = TestCase::ReloadTestScript(kReloadScript);
EXPECT_VALID(lib);
const char* result = SimpleInvokeStr(lib, "main");
EXPECT_SUBSTRING("NoSuchMethodError", result);
EXPECT_SUBSTRING("deleted", result);
}
TEST_CASE(IsolateReload_CallDeleted_ClassSetter) {
const char* kScript =
"class C { static set deleted(x) {}}\n"
"var retained;\n"
"main() {\n"
" retained = () => C.deleted = 'hello';\n"
" return retained();\n"
"}\n";
Dart_Handle lib = TestCase::LoadTestScript(kScript, NULL);
EXPECT_VALID(lib);
EXPECT_STREQ("hello", SimpleInvokeStr(lib, "main"));
const char* kReloadScript =
"var retained;\n"
"main() {\n"
" try {\n"
" return retained();\n"
" } catch (e) {\n"
" return e.toString();\n"
" }\n"
"}\n";
lib = TestCase::ReloadTestScript(kReloadScript);
EXPECT_VALID(lib);
const char* result = SimpleInvokeStr(lib, "main");
EXPECT_SUBSTRING("NoSuchMethodError", result);
EXPECT_SUBSTRING("deleted", result);
}
TEST_CASE(IsolateReload_CallDeleted_ClassSetterEvaluationOrder) {
const char* kScript =
"first(flag) { if (flag) throw 'first!'; return 'hello'; }\n"
"class C { static set deleted(x) {}}\n"
"var retained;\n"
"main() {\n"
" retained = (bool flag) => C.deleted = first(flag);\n"
" return retained(false);\n"
"}\n";
Dart_Handle lib = TestCase::LoadTestScript(kScript, NULL);
EXPECT_VALID(lib);
EXPECT_STREQ("hello", SimpleInvokeStr(lib, "main"));
const char* kReloadScript =
"first(flag) { if (flag) throw 'first!'; return 'hello'; }\n"
"var retained;\n"
"main() {\n"
" try {\n"
" return retained(true);\n"
" } catch (e) {\n"
" return e.toString();\n"
" }\n"
"}\n";
lib = TestCase::ReloadTestScript(kReloadScript);
EXPECT_VALID(lib);
const char* result = SimpleInvokeStr(lib, "main");
EXPECT_STREQ("first!", result);
}
TEST_CASE(IsolateReload_CallDeleted_ClassGenerativeConstructor) {
const char* kScript =
"class C { C.deleted(); }\n"
"var retained;\n"
"main() {\n"
" retained = () => C.deleted().toString();\n"
" return retained();\n"
"}\n";
Dart_Handle lib = TestCase::LoadTestScript(kScript, NULL);
EXPECT_VALID(lib);
EXPECT_STREQ("Instance of \'C\'", SimpleInvokeStr(lib, "main"));
const char* kReloadScript =
"class C {}\n"
"var retained;\n"
"main() {\n"
" try {\n"
" return retained();\n"
" } catch (e) {\n"
" return e.toString();\n"
" }\n"
"}\n";
lib = TestCase::ReloadTestScript(kReloadScript);
EXPECT_VALID(lib);
const char* result = SimpleInvokeStr(lib, "main");
EXPECT_SUBSTRING("NoSuchMethodError", result);
EXPECT_SUBSTRING("deleted", result);
}
TEST_CASE(IsolateReload_CallDeleted_ClassGenerativeConstructorArityChange) {
const char* kScript =
"class C { C.deleted(); }\n"
"var retained;\n"
"main() {\n"
" retained = () => C.deleted().toString();\n"
" return retained();\n"
"}\n";
Dart_Handle lib = TestCase::LoadTestScript(kScript, NULL);
EXPECT_VALID(lib);
EXPECT_STREQ("Instance of \'C\'", SimpleInvokeStr(lib, "main"));
const char* kReloadScript =
"class C { C.deleted(newParameter); }\n"
"var retained;\n"
"main() {\n"
" try {\n"
" return retained();\n"
" } catch (e) {\n"
" return e.toString();\n"
" }\n"
"}\n";
lib = TestCase::ReloadTestScript(kReloadScript);
EXPECT_VALID(lib);
const char* result = SimpleInvokeStr(lib, "main");
EXPECT_SUBSTRING("NoSuchMethodError", result);
EXPECT_SUBSTRING("deleted", result);
}
TEST_CASE(IsolateReload_CallDeleted_ClassGenerativeConstructorClassDeleted) {
const char* kScript =
"class C { C.deleted(); }\n"
"var retained;\n"
"main() {\n"
" retained = () => C.deleted().toString();\n"
" return retained();\n"
"}\n";
Dart_Handle lib = TestCase::LoadTestScript(kScript, NULL);
EXPECT_VALID(lib);
EXPECT_STREQ("Instance of \'C\'", SimpleInvokeStr(lib, "main"));
const char* kReloadScript =
"var retained;\n"
"main() {\n"
" try {\n"
" return retained();\n"
" } catch (e) {\n"
" return e.toString();\n"
" }\n"
"}\n";
lib = TestCase::ReloadTestScript(kReloadScript);
EXPECT_VALID(lib);
const char* result = SimpleInvokeStr(lib, "main");
EXPECT_SUBSTRING("NoSuchMethodError", result);
EXPECT_SUBSTRING("deleted", result);
}
TEST_CASE(IsolateReload_CallDeleted_ClassFactoryConstructor) {
const char* kScript =
"class C { factory C.deleted() => new C(); C(); }\n"
"var retained;\n"
"main() {\n"
" retained = () => C.deleted().toString();\n"
" return retained();\n"
"}\n";
Dart_Handle lib = TestCase::LoadTestScript(kScript, NULL);
EXPECT_VALID(lib);
EXPECT_STREQ("Instance of \'C\'", SimpleInvokeStr(lib, "main"));
const char* kReloadScript =
"class C {}\n"
"var retained;\n"
"main() {\n"
" try {\n"
" return retained();\n"
" } catch (e) {\n"
" return e.toString();\n"
" }\n"
"}\n";
lib = TestCase::ReloadTestScript(kReloadScript);
EXPECT_VALID(lib);
const char* result = SimpleInvokeStr(lib, "main");
EXPECT_SUBSTRING("NoSuchMethodError", result);
EXPECT_SUBSTRING("deleted", result);
}
TEST_CASE(IsolateReload_CallDeleted_ClassFactoryConstructorArityChange) {
const char* kScript =
"class C { factory C.deleted() => new C(); C(); }\n"
"var retained;\n"
"main() {\n"
" retained = () => C.deleted().toString();\n"
" return retained();\n"
"}\n";
Dart_Handle lib = TestCase::LoadTestScript(kScript, NULL);
EXPECT_VALID(lib);
EXPECT_STREQ("Instance of \'C\'", SimpleInvokeStr(lib, "main"));
const char* kReloadScript =
"class C { factory C.deleted(newParameter) => new C(); C(); }\n"
"var retained;\n"
"main() {\n"
" try {\n"
" return retained();\n"
" } catch (e) {\n"
" return e.toString();\n"
" }\n"
"}\n";
lib = TestCase::ReloadTestScript(kReloadScript);
EXPECT_VALID(lib);
const char* result = SimpleInvokeStr(lib, "main");
EXPECT_SUBSTRING("NoSuchMethodError", result);
EXPECT_SUBSTRING("deleted", result);
}
TEST_CASE(IsolateReload_CallDeleted_ClassFactoryConstructorClassDeleted) {
const char* kScript =
"class C { factory C.deleted() => new C(); C(); }\n"
"var retained;\n"
"main() {\n"
" retained = () => C.deleted().toString();\n"
" return retained();\n"
"}\n";
Dart_Handle lib = TestCase::LoadTestScript(kScript, NULL);
EXPECT_VALID(lib);
EXPECT_STREQ("Instance of \'C\'", SimpleInvokeStr(lib, "main"));
const char* kReloadScript =
"var retained;\n"
"main() {\n"
" try {\n"
" return retained();\n"
" } catch (e) {\n"
" return e.toString();\n"
" }\n"
"}\n";
lib = TestCase::ReloadTestScript(kReloadScript);
EXPECT_VALID(lib);
const char* result = SimpleInvokeStr(lib, "main");
EXPECT_SUBSTRING("NoSuchMethodError", result);
EXPECT_SUBSTRING("deleted", result);
}
TEST_CASE(IsolateReload_CallDeleted_SuperFunction) {
const char* kScript =
"class C { deleted() { return 'hello'; } }\n"
"class D extends C { curry() => () => super.deleted(); }\n"
"var retained;\n"
"main() {\n"
" retained = new D().curry();\n"
" return retained();\n"
"}\n";
Dart_Handle lib = TestCase::LoadTestScript(kScript, NULL);
EXPECT_VALID(lib);
EXPECT_STREQ("hello", SimpleInvokeStr(lib, "main"));
const char* kReloadScript =
"class C {}\n"